Repository: pandas-dev/pandas
Pull request: Remove py.path special handling from io.common
- [x] closes #26450 
- [x] tests added / passed
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [ ] whatsnew entry


Problem statement:
Deprecate py.path support
Since our min version is Py35 path lib is guaranteed to be installed. However we have a few functions that accept py.path.LocalPath objects for compatability

Not sure if we need an explicit deprecation cycle or if this is implied with moving minimum support to Py35

Hints from issue discussion:
we should deprecate as have accepted these for a long time and they work py 3
If possible, I'd like to contribute to this. Should I search for functions with LocalPath and deprecate them accordingly?
@nandahkrishna that's great! And yes you've got it right. You might want to check out other PRs labeled Deprecate that have been merged to see how we typically handle as well
> You might want to check out other PRs labeled Deprecate that have been merged to see how we typically handle as well

Sure, I'll do that. Thanks!
I took a look at previous PRs labeled deprecate. I got a fair idea of how it works, but I couldn't seem to find a case that deprecated an external library (might have missed my eye?) so just confirming:
1. Visit functions where py.path.local has been used
2. Add a DeprecateWarning with a suitable message
3. Add tests for the warning
Is this right?
That's right!

Commit message: Corrected import order

Patch to review:
diff --git a/pandas/io/common.py b/pandas/io/common.py
index f9cd1806763e2..89f08628bf246 100644
--- a/pandas/io/common.py
+++ b/pandas/io/common.py
@@ -14,6 +14,7 @@
     urlencode, urljoin, urlparse as parse_url, uses_netloc, uses_params,
     uses_relative)
 from urllib.request import pathname2url, urlopen
+import warnings
 import zipfile
 
 from pandas.errors import (  # noqa
@@ -122,7 +123,7 @@ def _stringify_path(filepath_or_buffer):
         _PATHLIB_INSTALLED = False
 
     try:
-        from py.path import local as LocalPath
+        from py.path import local as LocalPath  # Deprecated - 0.25.0
         _PY_PATH_INSTALLED = True
     except ImportError:
         _PY_PATH_INSTALLED = False
@@ -132,6 +133,8 @@ def _stringify_path(filepath_or_buffer):
     if _PATHLIB_INSTALLED and isinstance(filepath_or_buffer, pathlib.Path):
         return str(filepath_or_buffer)
     if _PY_PATH_INSTALLED and isinstance(filepath_or_buffer, LocalPath):
+        warnings.warn("py.path has been deprecated. Use pathlib instead.",
+                      DeprecationWarning, stacklevel=2)
         return filepath_or_buffer.strpath
     return _expand_user(filepath_or_buffer)
 


Code review comments:
diff_hunk: @@ -132,6 +133,8 @@ def _stringify_path(filepath_or_buffer):
     if _PATHLIB_INSTALLED and isinstance(filepath_or_buffer, pathlib.Path):
         return str(filepath_or_buffer)
     if _PY_PATH_INSTALLED and isinstance(filepath_or_buffer, LocalPath):
path: pandas/io/common.py
text: @user2:
yeah I agree with @user1 here, I think we can blow aways all of these checks (and imports) and just
```
if hasattr(filepath_or_buffer, '__fspath__'):
    return str(filepath_or_buffer)
```
and things should *just* work

@author:
I've removed the imports and checks, only the hasattr check remains.