Skip to content

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

Merged
merged 3 commits into from
Jul 9, 2018

Conversation

anntzer
Copy link
Contributor

@anntzer anntzer commented Jun 7, 2018

PR Summary

  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.
  4. Simplify caching of directories retrieval.

PR Checklist

  • Has Pytest style unit tests
  • Code is PEP 8 compliant
  • New features are documented, with examples if plot related
  • Documentation is sphinx and numpydoc compliant
  • Added an entry to doc/users/next_whats_new/ if major new feature (follow instructions in README.rst there)
  • Documented in doc/api/api_changes.rst if API changed in a backward-incompatible way

Copy link
Member

@efiring efiring left a 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.

"""
return a callable function that wraps func and reports its
output through logger
def _logged_cached(fmt, func=None):
Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

output through logger
def _logged_cached(fmt, func=None):
if func is None:
return functools.partial(_logged_cached, fmt)
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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).

path = os.path.join(path, '.config')
return path
return (os.environ.get('XDG_CONFIG_HOME')
or (Path(get_home(), ".config")
Copy link
Member

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?

Copy link
Contributor Author

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.

if sys.platform.startswith(('linux', 'freebsd')) and xdg_base
else Path(get_home(), ".matplotlib")
if get_home()
else None)
Copy link
Member

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.

Copy link
Member

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.

Copy link
Contributor Author

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(?)

@@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate import of cbook

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

@anntzer anntzer force-pushed the gethome branch 2 times, most recently from 44aaa1b to 868eeb1 Compare June 24, 2018 22:21
anntzer added 2 commits June 25, 2018 01:03
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.
@anntzer anntzer force-pushed the gethome branch 2 times, most recently from 798f837 to 18da838 Compare June 24, 2018 23:27
@timhoffm timhoffm merged commit 85f0dd6 into matplotlib:master Jul 9, 2018
@QuLogic QuLogic added this to the v3.0 milestone Jul 9, 2018
@anntzer anntzer deleted the gethome branch July 10, 2018 08:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants