Repository: matplotlib/matplotlib
Pull request: pyplot.style.use() to accept pathlib.Path objects as arguments
## PR Summary
Currently the pyplot.style.use() supports strings, list, and dic as function arguments where string can be  a library style or path/URL to style file. Added the code to leverage the function to use pathlib.Path object as an argument.   
Fixes #15138 
## PR Checklist

- [X] Has Pytest style unit tests
- [X] Code is [Flake 8](http://flake8.pycqa.org/en/latest/) compliant
- [X] New features are documented, with examples if plot related
- [X] 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

<!--
Thank you so much for your PR!  To help us review your contribution, please
consider the following points:

- A development guide is available at https://matplotlib.org/devdocs/devel/index.html.

- Help with git and github is available at
  https://matplotlib.org/devel/gitwash/development_workflow.html.

- Do not create the PR out of master, but out of a separate branch.

- The PR title should summarize the changes, for example "Raise ValueError on
  non-numeric input to set_xlim".  Avoid non-descriptive titles such as
  "Addresses issue #8576".

- The summary should provide at least 1-2 sentences describing the pull request
  in detail (Why is this change required?  What problem does it solve?) and
  link to any relevant issues.

- If you are contributing fixes to docstrings, please pay attention to
  http://matplotlib.org/devel/documenting_mpl.html#formatting.  In particular,
  note the difference between using single backquotes, double backquotes, and
  asterisks in the markup.

We understand that PRs can sometimes be overwhelming, especially as the
reviews start coming in.  Please let us know if the reviews are unclear or
the recommended next step seems overly demanding, if you would like help in
addressing a reviewer's comments, or if you have been waiting too long to hear
back on your PR.
-->


Problem statement:
Make plt.style.use accept path-like objects in addition to string
`plt.style.use(style)` accepts a `str`, `dict`, or `list`. The `str `can be either the name of a style or a path/URL to a style file. I propose that this also accept a pathlike object (`pathlib.Path`) so that it is unneccesary to cast it like `plt.style.use(str(my_path))`, but accept it like this `plt.style.use(my_path)`.

There may be other places in the code that accepts file paths as strings.

Hints from issue discussion:
This should be a fairly straightforward enhancement, changing a few `isinstance`s and perhaps adding a cast to `str` internally (if necessary).
Hi @QuLogic,

If no one is working on this problem than I would like to give it a shot. Also can you please guide me from where should I start?

Thank You!
Om.
You will need to change the code in the function `use()`  at `matplotlib/style/core.py`.
Hi @timhoffm,

Thanks for the guidance and I have started working on this enhancement. Can you please tell me where to go if I need any help?

Thank you!
Om.
You can ask on the [gitter channel](https://gitter.im/matplotlib/matplotlib) or post questions alongside your PR.

Commit message: Update lib/matplotlib/tests/test_style.py

Co-Authored-By: Elliott Sales de Andrade <quantum.analyst@gmail.com>

Patch to review:
diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py
index b7cac2a11fa1..d268f67f0359 100644
--- a/lib/matplotlib/__init__.py
+++ b/lib/matplotlib/__init__.py
@@ -948,7 +948,7 @@ def rc_params_from_file(fname, fail_on_error=False, use_default_template=True):
 
     Parameters
     ----------
-    fname : str
+    fname : str, path-like
         Name of file parsed for Matplotlib settings.
     fail_on_error : bool
         If True, raise an error when the parser fails to convert a parameter.
diff --git a/lib/matplotlib/style/core.py b/lib/matplotlib/style/core.py
index e151b27b8181..577c9f51e7a5 100644
--- a/lib/matplotlib/style/core.py
+++ b/lib/matplotlib/style/core.py
@@ -72,7 +72,7 @@ def use(style):
 
     Parameters
     ----------
-    style : str, dict, or list
+    style : str, dict, Path or list
         A style specification. Valid options are:
 
         +------+-------------------------------------------------------------+
@@ -82,14 +82,17 @@ def use(style):
         | dict | Dictionary with valid key/value pairs for                   |
         |      | `matplotlib.rcParams`.                                      |
         +------+-------------------------------------------------------------+
-        | list | A list of style specifiers (str or dict) applied from first |
-        |      | to last in the list.                                        |
+        | Path | A path-like object which is a path to a style file.         |
         +------+-------------------------------------------------------------+
+        | list | A list of style specifiers (str, Path or dict) applied from |
+        |      | first to last in the list.                                  |
+        +------+-------------------------------------------------------------+
+
     """
     style_alias = {'mpl20': 'default',
                    'mpl15': 'classic'}
-    if isinstance(style, str) or hasattr(style, 'keys'):
-        # If name is a single str or dict, make it a single element list.
+    if isinstance(style, (str, Path)) or hasattr(style, 'keys'):
+        # If name is a single str, Path or dict, make it a single element list.
         styles = [style]
     else:
         styles = style
@@ -97,7 +100,7 @@ def use(style):
     styles = (style_alias.get(s, s) if isinstance(s, str) else s
               for s in styles)
     for style in styles:
-        if not isinstance(style, str):
+        if not isinstance(style, (str, Path)):
             _apply_style(style)
         elif style == 'default':
             # Deprecation warnings were already handled when creating
@@ -123,7 +126,7 @@ def context(style, after_reset=False):
 
     Parameters
     ----------
-    style : str, dict, or list
+    style : str, dict, Path or list
         A style specification. Valid options are:
 
         +------+-------------------------------------------------------------+
@@ -133,8 +136,10 @@ def context(style, after_reset=False):
         | dict | Dictionary with valid key/value pairs for                   |
         |      | `matplotlib.rcParams`.                                      |
         +------+-------------------------------------------------------------+
-        | list | A list of style specifiers (str or dict) applied from first |
-        |      | to last in the list.                                        |
+        | Path | A path-like object which is a path to a style file.         |
+        +------+-------------------------------------------------------------+
+        | list | A list of style specifiers (str, Path or dict) applied from |
+        |      | first to last in the list.                                  |
         +------+-------------------------------------------------------------+
 
     after_reset : bool
diff --git a/lib/matplotlib/tests/test_style.py b/lib/matplotlib/tests/test_style.py
index 552b87e4aa14..0accfa005f5f 100644
--- a/lib/matplotlib/tests/test_style.py
+++ b/lib/matplotlib/tests/test_style.py
@@ -68,6 +68,16 @@ def test_use_url(tmpdir):
             assert mpl.rcParams['axes.facecolor'] == "#adeade"
 
 
+def test_single_path(tmpdir):
+    mpl.rcParams[PARAM] = 'gray'
+    temp_file = f'text.{STYLE_EXTENSION}'
+    path = Path(tmpdir, temp_file)
+    path.write_text(f'{PARAM} : {VALUE}')
+    with style.context(path):
+        assert mpl.rcParams[PARAM] == VALUE
+    assert mpl.rcParams[PARAM] == 'gray'
+
+
 def test_context():
     mpl.rcParams[PARAM] = 'gray'
     with temp_style('test', DUMMY_SETTINGS):


Code review comments:
diff_hunk: @@ -948,7 +948,7 @@ def rc_params_from_file(fname, fail_on_error=False, use_default_template=True):
 
     Parameters
     ----------
-    fname : str
+    fname : str, path-like
path: lib/matplotlib/__init__.py
text: @user1:
```suggestion
    fname : str or path-like
```

@user1:
According to [numpydoc](https://numpydoc.readthedocs.io/en/latest/format.html#sections), which we follow, all types are separated by `or` not commas (also multiple ones `A or B or C`).