-
Notifications
You must be signed in to change notification settings - Fork 284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Grib1unit10 additional #184
Conversation
There is still plenty of work to do making the grib tests quicker and more focussed. Hopefully the 'Mock' approach can be extended to assist this. |
Implement only a few methods, just enough to allow GribWrapper creation. | ||
""" | ||
|
||
class GribInternalError(Exception): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume we can't just use the actual class from the grib api instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could, I hadn't thought of that.
However, it will introduce an extra "knowledge dependency", as we need to (know how to) make one so we can raise it in the faking code (below).
No actual behaviour seems to be used, though, so it is terribly easy to 'fake'
-- and then that is also a statement of precisely how much interface we think is required (!), which I quite like.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point regarding dependency.
Seems desirable to be completely independent of the real grib api.
Good job. Made some comments. |
|
||
|
||
@contextmanager | ||
def Fakeup_Gribapi_Context(fake_gribapi_class=Fake_GribApi): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still having doubts about the worth of this, in place of a simple "try.. finally" block.
@rhattersley put me up to this, but having done it, I'm worried it adds very little in this case, and is considerably less transparent.
It doesn't even simplify the usage code that much : Compare
with Fakeup_Gribapi_Context():
<stuff>...
with
try:
orig_gribapi_module = iris.fileformats.grib.gribapi
iris.fileformats.grib.gribapi = Fake_GribApi()
<stuff>...
finally:
iris.fileformats.grib.gribapi = orig_gribapi_module
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like it. It's safe and neat.
In fact, I wrote a praising comment but didn't post it.
I'd like to see this become the standard for module mocking in Iris.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Continuing the great tradition of turning nouns into verbs... could we PEP8 the names please. I'm looking at you "Fake_GribApi", and you "Fakeup_Gribapi_Context"!
(While you're at it, the use of the word "context" doesn't really add much and is a bit reverse-Polish.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correction - please could you convert to using http://pypi.python.org/pypi/mock
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An example of mocking can be found here: #229
Re: your various "remove / unnecessary" comments.
|
@bblay : thanks for comments. |
I think the only thing to do is:
I think the grib1 key in the grib2 dict is harmless. The rest is fine as it is:
|
Changes to cover the issues previously raised. |
@@ -30,10 +34,49 @@ | |||
import iris.util | |||
import iris.tests.stock | |||
|
|||
import mock | |||
|
|||
import gribapi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be in the 3rd-party section alongside matplotlib.pyplot
. Similarly for mock
and numpy
.
The datetime
and contextlib
imports should be moved to sit with os
and warnings
.
The mock module is just there as a tool to help with writing focussed tests. In this case the With hindsight, I suspect we would have been better served by first making a PR which removed the code in the |
return self._time_unit_stringandsecs()[0] | ||
|
||
def _time_unit_as_seconds(self): | ||
return self._time_unit_stringandsecs()[1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The inter-relationships between _time_unit_as_string
, _time_unit_as_seconds
, and _time_unit_stringandsecs
are overly complex. Wouldn't it'd be simpler and more transparent just to have:
_time_unit_as_string
: the code from the first half of_time_unit_stringandsecs
_time_unit_as_seconds
: calls_time_unit_as_string
to get the string, then decodes it using the code from the second half of_time_unit_stringandsecs
Having done that, it seems pretty odd to convert the GRIB values into a string just to decode the string into numbers again. How about something vaguely (please don't take it too literally) like:
class GribWrapper:
edition_1 = {13: ('15 minutes', 15 * 60), 14: ('30 minutes', 30 * 60)}
edition_2 = {13: ...}
edition_any = {0: ('minutes', 60), ...}
def _time_unit(self):
if edition == 1:
answer = self.edition_1.get(timeunit_num) or self.edition_any(timeunit_num)
return answer
def _time_unit_as_string(self):
return self._time_unit()[0]
def _time_unit_as_seconds(self):
return self._time_unit()[1]
Oddly, the three-part solution is back again!
There are lots of PEP8 issues which could do with ironing out. You may well find the |
#182 would probably do away with this. Much of the grib wrapper code is just there to support the rules system (the "extra keys"). |
Hopefully now have covered the following points...
Outstanding work stil to come:
|
def _time_unit_stringandsecs(self): | ||
""" | ||
Interpret message time unit as udunits-string, and float(seconds). | ||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a multi-line docstring there should be a blank line before the closing quotes.
Rather extensively refactored : Probably overkill, but I hope it addresses the outstanding issues. Anyway, I certainly learnt a few things. Please review. |
Qué? Python 2.7.2 (default, Oct 1 2012, 15:56:20)
[GCC 4.4.6 20110731 (Red Hat 4.4.6-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo(dict):
... def __getitem__(self, key):
... return 'wibble'
...
>>> Foo()['thing']
'wibble' |
u_secs = int(u_num) * u_basesecs | ||
if not (u_secs > 0.0): | ||
raise Exception( | ||
'Unexpected time unit string : "{0}"'.format(units_string) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't matter in this instance, but in general for quoting a string you're better off using {!r}
to get the repr
version - it automatically handles the different kinds of quotes and any necessary escaping (plus it's shorter and less "noisy"). i.e. 'Unexpected time unit string : {!r}'.format(units_string)
Sorry, it seems I was just out-of-date on this. Ok, I've just done it now |
Thanks @rhattersley. If you think so... |
You've done it already - so if you want to include it in the PR then feel free. |
Personally, I think they're better as a module constant, rather than a local variable. They are constant after all. And it avoids Python having to make a fresh dict each time. (Yes - I know there's no such thing as a true constant in Python!) |
Applied patches : fake-message-objects and alternate-string/seconds |
Thanks for the re-base - looks good now. I think it would benefit from a squash though, if you're happy to give that a go...? |
I can compress the log to just one entry "Support extra GRIB timeunit codes". |
I wouldn't hurt to have an extra line or two in the commit message. But I'm not that bothered either way. You choose 😉 |
- also small tweak to GribWrapper __init__, to prevent possible infinite loops
Additional GRIB time units
Phew! Thanks for hanging in there @pp-mo! 😄 |
Added additional GRIB1 and GRIB2 time units support.
Also enhanced test_grib_load, with (beginnings of) improved Mock-style testing methods, as suggested by @rhattersley in ##171 (and private discussions)