-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Simplify retrieval of cache and config directories #11398
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
Conversation
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 haven't actually tested all this for functionality, but it looks plausible, and the reduction in LOC is nice. Readability needs improvement, even though it will require a few lines of comment and docstring.
lib/matplotlib/__init__.py
Outdated
""" | ||
return a callable function that wraps func and reports its | ||
output through logger | ||
def _logged_cached(fmt, func=None): |
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 needs a docstring to explain what it does.
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.
Added.
lib/matplotlib/__init__.py
Outdated
output through logger | ||
def _logged_cached(fmt, func=None): | ||
if func is None: | ||
return functools.partial(_logged_cached, fmt) |
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 think this needs a comment to explain what it is doing, and how. I read the functools.partial doc, but I'm still completely baffled by these lines. I dimly recollect that you already explained something like this somewhere else, but if so, it didn't stick in my brain.
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.
Would lambda func: _logged_cached(fmt, func)
look better for you? That's basically the same thing.
Or I can even implement the decorator using more nested functions, but I think the flatter pattern is usually preferred.
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's probably fine the way it is; I'm just looking for a hopefully short comment that will explain it. I suspect the conceptual difficulty comes from the fact that the simpler and more common use of decorators is without arguments. What your usage is doing is first executing the _logged_cashed(fmt)
to yield the real decorator function object that gets applied to the func
that follows it. That real decorator remembers and can use fmt
, and is a function that takes only one argument, which is now 'func', as expected for a decorator. A key point is that the initial function execution to yield the real decorator occurs before the application by the @
.
Maybe insert a comment:
if func is None:
# Return the decorator function object.
....
Or maybe that is overkill. I think I understand it now, and will probably recognize it in the future; I actually like it. It's just a question of whether a short comment will save someone else some time in understanding how this works. I'm not sure.
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.
Added a short comment (and at another place where I used the same pattern: cbook._define_aliases).
lib/matplotlib/__init__.py
Outdated
path = os.path.join(path, '.config') | ||
return path | ||
return (os.environ.get('XDG_CONFIG_HOME') | ||
or (Path(get_home(), ".config") |
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.
Is there a reason for returning a string in the first case and a Path object in the second? Or is it just that for the way the output is used it doesn't matter, and you like using pathlib
instead of os.path
?
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's true that it doesn't matter, but I changed it to return str every time -- there's no reason to be inconsistent.
lib/matplotlib/__init__.py
Outdated
if sys.platform.startswith(('linux', 'freebsd')) and xdg_base | ||
else Path(get_home(), ".matplotlib") | ||
if get_home() | ||
else None) |
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.
These chained "one-line" ternaries take a little getting used to... but maybe they are OK in the end.
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 find this particularly easy to read either, and I'm not sure what the advantage is other than saving a couple of lines of 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.
Flattened this one. Left the one for _get_xdg_foo_dir as I think they're still more readable(?)
lib/matplotlib/testing/compare.py
Outdated
@@ -18,8 +18,7 @@ | |||
|
|||
import matplotlib | |||
from matplotlib.testing.exceptions import ImageComparisonFailure | |||
from matplotlib import _png | |||
from matplotlib import _get_cachedir | |||
from matplotlib import _png, cbook |
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.
Duplicate import of cbook
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.
removed
44aaa1b
to
868eeb1
Compare
1. In get_home, we shouldn't check for $TMP, but instead let this case fall through to _create_config_or_cache_dir. 2. When checking for $XDG_{CONFIG,CACHE}_HOME and $MPLCONFIGDIR, consider empty strings as equivalent to unset (which is standard behavior, e.g. one could write `XDG_CONFIG_HOME= python ...` and expect things to behave as if `XDG_CONFIG_HOME` was indeed unset). 3. The logic in _get_config_or_cache_dir can greatly simplified: try to create a candidate, generating it on the way if necessary; if it cannot be created or is not writable, fallback to a temporary directory.
798f837
to
18da838
Compare
PR Summary
fall through to _create_config_or_cache_dir.
consider empty strings as equivalent to unset (which is standard
behavior, e.g. one could write
XDG_CONFIG_HOME= python ...
andexpect things to behave as if
XDG_CONFIG_HOME
was indeed unset).create a candidate, generating it on the way if necessary; if it
cannot be created or is not writable, fallback to a temporary
directory.
PR Checklist