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
Enable showing DeprecationWarning in debug_on and add unit test #1554
Conversation
Add a unit test for debug_on, including the new functionality to add deprecation warnings.
Linter says docstring should be on one line. Let it be so.
Congratulations 🎉. DeepCode analyzed your code in 2.471 seconds and we found no issues. Enjoy a moment of no bugs ☀️. 👉 View analysis in DeepCode’s Dashboard | Configure the bot |
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.
LGTM, thanks for taking the time. Some tests are failing though.
Hmm, I thought the tests were passing when I ran them locally :-/ I well check this. |
Add a debug_off function that switches debugging off. Use this function when testing debug_on so it doesn't affect the behaviour of other unit tests. The GAC reader ones are still failing for reasons I don't understand yet.
I am deeply confused how this PR can cause the GACLAC reader tests to fail in the way they do. |
I have no clue why, but with this PR, these import statements all return in mocks, causing a test failure: satpy/satpy/tests/reader_tests/test_avhrr_l1b_gaclac.py Lines 140 to 147 in d556c80
Any clue why that would happen with my PR, which is just doing stuff with warning filters and loggers? |
Codecov Report
@@ Coverage Diff @@
## master #1554 +/- ##
==========================================
+ Coverage 92.54% 92.58% +0.03%
==========================================
Files 251 251
Lines 36761 36828 +67
==========================================
+ Hits 34022 34097 +75
+ Misses 2739 2731 -8
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
The only failing build seems to be, as far as I know, the unstable build that uses bleeding edge versions from dask, xarray, etc. |
These failures happen on my local machine if and only if local pygac is installed, and I run the new tests:
|
I think this deserves it's own issue. Creating now. |
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.
Just a few comments for clarity, otherwise it looks good.
satpy/utils.py
Outdated
_warning_manager = _WarningManager() | ||
|
||
|
||
def dep_warnings_on(): |
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.
dep
can be missleading (I was thinking dependency, as in warnings from other libraries), maybe just rename to deprecation_warnings_on
for clarity?
satpy/utils.py
Outdated
_warning_manager.filt = warnings.filters[0] | ||
|
||
|
||
def dep_warnings_off(): |
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.
Here too.
class _WarningManager: | ||
"""Class to handle switching warnings on and off.""" | ||
|
||
filt = None | ||
|
||
|
||
_warning_manager = _WarningManager() |
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.
do we really need a class here? would it work with just a module variable, eg _warning_filter
?
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.
That would have to be a global variable. I personally hate global variables. I find them confusing, error-prone, and hard to test.
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.
In a way, isn't _warning_manager
also a global variable? Yes, it's a class instance, but everything in Python is a class instance.
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.
In a way yes, and in a way no. There is no global keyword, and I'm not changing somebody else's namespace; rather, I'm just changing the state of a mutable object that happens to be in the module namespace. The difference is subtle and in this case largely semantic, but if somebody did have the idea to use their own reference to _warning_manager
(hopefully for testing purposes) it would be affected by changes, unlike a global variable which would be a name bound to a new object.
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.
ok, I get your point.
Now, looking at the bigger picture, why use a class at all and not just a constant?
When doing warnings.filterwarnings("default", category=DeprecationWarning)
, the last filter becomes in principle ('default', None, DeprecationWarning, None, 0)
(I say in principle because there could be a race condition, or are warning filters thread-safe?).
So we could have _deprecation_warning_filter = ('default', None, DeprecationWarning, None, 0)
at the module level and use that in deprecation_warnings_off
.
Or are you worried that the filter syntax will change in certain circumstances?
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 don't believe it's thread safe, let's just hope people don't rely on debug_on()...debug_off()
to work reliably in threaded code.
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.
about thread-safety:
The catch_warnings manager works by replacing and then later restoring the module’s showwarning() function and internal list of filter specifications. This means the context manager is modifying global state and therefore is not thread-safe.
(last lines in https://docs.python.org/3/library/warnings.html)
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.
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.
No further comments from me 👍
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 not thrilled with the Python 'warnings' module, so there is no solution that I would be thrilled with.
satpy/utils.py
Outdated
@contextlib.contextmanager | ||
def debug(dep_warnings=True): | ||
"""Context manager to temporarily set debugging on. | ||
|
||
Example:: | ||
|
||
>>> with satpy.utils.debug(): | ||
... code_here() | ||
|
||
Args: | ||
dep_warnings (Optional[bool]): Switch on deprecation warnings. | ||
Defaults to True. | ||
""" | ||
debug_on() | ||
yield | ||
debug_off() |
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.
That's really nice, great addition!
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.
Maybe rename dep_warnings
to deprecation_warnings
?
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 renamed it throughout now (and passed the relevant parameter in line 93...).
Extend the functionality of
debug_on
to switch on the visibility ofDeprecationWarning
using thedefault
filter (as opposed to only showing them in__main__
, which is the default Python behaviour in current and recent Python versions). Also add a unit test fordebug_on
.