Repository: pandas-dev/pandas
Pull request: BUG: type aliasing is not allowed to be compared using isinstance()
- [X] closes #21078
- [ ] tests added / passed
- [X] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [ ] whatsnew entry

As raised in #21078, Python 3.5.4 supports the using `isinstance()` with `typing.re.Pattern` But it does not support the same method in 3.5.2.

``` Python
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import re
>>> import typing
>>> isinstance(re.compile(''), typing.re.Pattern)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.5/typing.py", line 260, in __instancecheck__
    raise TypeError("Type aliases cannot be used with isinstance().")
TypeError: Type aliases cannot be used with isinstance().
```

This Bugfix PR is to revert the `re_type` to be back to what it used to be before the update with the new release.


Problem statement:
.replace() raises when replacing strings
#### Code Sample, a copy-pastable example if possible

```python
pd.Series(['a', 'b', 'c']).replace('a', 'x')
```
#### Problem description

This raises the following error:

> TypeError: Type aliases cannot be used with isinstance().

This behavior is exclusive to the new **version 0.23**. Previous versions work as expected.

Full traceback
```
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-75-761515b509b4> in <module>()
----> 1 pd.Series(['a','b','c']).replace('a', 'x')

~/.virtualenvs/new/lib/python3.5/site-packages/pandas/core/series.py in replace(self, to_replace, value, inplace, limit, regex, method)
   3427         return super(Series, self).replace(to_replace=to_replace, value=value,
   3428                                            inplace=inplace, limit=limit,
-> 3429                                            regex=regex, method=method)
   3430
   3431     @Appender(generic._shared_docs['shift'] % _shared_doc_kwargs)

~/.virtualenvs/new/lib/python3.5/site-packages/pandas/core/generic.py in replace(self, to_replace, value, inplace, limit, regex, method)
   5877                     new_data = self._data.replace(to_replace=to_replace,
   5878                                                   value=value, inplace=inplace,
-> 5879                                                   regex=regex)
   5880                 else:
   5881                     msg = ('Invalid "to_replace" type: '

~/.virtualenvs/new/lib/python3.5/site-packages/pandas/core/internals.py in replace(self, **kwargs)
   3718
   3719     def replace(self, **kwargs):
-> 3720         return self.apply('replace', **kwargs)
   3721
   3722     def replace_list(self, src_list, dest_list, inplace=False, regex=False,

~/.virtualenvs/new/lib/python3.5/site-packages/pandas/core/internals.py in apply(self, f, axes, filter, do_integrity_check, consolidate, **kwargs)
   3579
   3580             kwargs['mgr'] = self
-> 3581             applied = getattr(b, f)(**kwargs)
   3582             result_blocks = _extend_blocks(applied, result_blocks)
   3583

~/.virtualenvs/new/lib/python3.5/site-packages/pandas/core/internals.py in replace(self, to_replace, value, inplace, filter, regex, convert, mgr)
   2430         blocks = [self]
   2431
-> 2432         if not either_list and is_re(to_replace):
   2433             return self._replace_single(to_replace, value, inplace=inplace,
   2434                                         filter=filter, regex=True,

~/.virtualenvs/new/lib/python3.5/site-packages/pandas/core/dtypes/inference.py in is_re(obj)
    217     """
    218
--> 219     return isinstance(obj, re_type)
    220
    221

/usr/lib/python3.5/typing.py in __instancecheck__(self, obj)
    256
    257     def __instancecheck__(self, obj):
--> 258         raise TypeError("Type aliases cannot be used with isinstance().")
    259
    260     def __subclasscheck__(self, cls):

TypeError: Type aliases cannot be used with isinstance().
```

#### Expected Output

```
0    x
1    b
2    c
dtype: object
```

#### Output of ``pd.show_versions()``

<details>

INSTALLED VERSIONS
------------------
commit: None
python: 3.5.1.final.0
python-bits: 64
OS: Linux
OS-release: 4.13.13-5-pve
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: en_US.UTF-8
LANG: en_US.UTF-8
LOCALE: en_US.UTF-8

pandas: 0.23.0
pytest: None
pip: 8.1.1
setuptools: 20.7.0
Cython: None
numpy: 1.14.3
scipy: 1.1.0
pyarrow: None
xarray: None
IPython: 6.4.0
sphinx: None
patsy: None
dateutil: 2.6.1
pytz: 2018.4
blosc: None
bottleneck: None
tables: None
numexpr: None
feather: None
matplotlib: 2.2.2
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: None
html5lib: 0.999
sqlalchemy: None
pymysql: None
psycopg2: None
jinja2: 2.10
s3fs: None
fastparquet: None
pandas_gbq: None
pandas_datareader: None

</details>

Hints from issue discussion:
Hmm I'm not able to reproduce on Python 3.6.

Can you past the full traceback?
I don't understand the bit about "type aliases". Are you overriding a builting with something from the `typing` module?
@TomAugspurger I added the full traceback
Does this raise for you?

```
In [10]: import re

In [11]: import typing

In [12]: isinstance(re.compile(''), typing.re.Pattern)
Out[12]: True
```

If so, can you check the Python issue tracker to see if this has been filed?
That works fine on 3.5.4 for me.

```python
Python 3.5.4 | packaged by conda-forge | (default, Aug 10 2017, 01:41:15)
[GCC 4.2.1 Compatible Apple LLVM 6.1.0 (clang-602.0.53)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import re
>>> import typing
>>> isinstance(re.compile(''), typing.re.Pattern)
True
>>>
```

Can you try upgrading from 3.5.1 to a later point release?
It definitely works with 3.5.4 but doesn't work with 3.5.2 either
OK. See https://github.com/pandas-dev/pandas/pull/20553 for reference.

If you want, you can make a PR using the old way for Python 3.5.2 (or 3) and older... Or upgrade to the latest point release
Will do, thanks!
I had the same issue using the same Python 3.5.2. I just opened up the PR for it to revert it back.
Was that what you mean @TomAugspurger?

Commit message: Adding test for  variable. Changing the Python Version condition to PY36, Added Doc under  section

Patch to review:
diff --git a/doc/source/whatsnew/v0.23.1.txt b/doc/source/whatsnew/v0.23.1.txt
index 35d150dc263b8..2c86ee29632fd 100644
--- a/doc/source/whatsnew/v0.23.1.txt
+++ b/doc/source/whatsnew/v0.23.1.txt
@@ -48,6 +48,11 @@ Groupby/Resample/Rolling
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
 - Bug in :func:`DataFrame.agg` where applying multiple aggregation functions to a :class:`DataFrame` with duplicated column names would cause a stack overflow (:issue:`21063`)
+
+Strings
+^^^^^^^
+
+- Bug in :meth:`Series.str.replace()` where the method throws `TypeError` on Python 3.5.2
 -
 
 Conversion
diff --git a/pandas/compat/__init__.py b/pandas/compat/__init__.py
index 12517372fedd1..5ae22694d0da7 100644
--- a/pandas/compat/__init__.py
+++ b/pandas/compat/__init__.py
@@ -425,7 +425,7 @@ def raise_with_traceback(exc, traceback=Ellipsis):
 
 # In Python 3.7, the private re._pattern_type is removed.
 # Python 3.5+ have typing.re.Pattern
-if PY35:
+if PY36:
     import typing
     re_type = typing.re.Pattern
 else:
diff --git a/pandas/tests/test_compat.py b/pandas/tests/test_compat.py
index ead9ba1e26e2d..11864d92ad580 100644
--- a/pandas/tests/test_compat.py
+++ b/pandas/tests/test_compat.py
@@ -6,7 +6,7 @@
 import pytest
 from pandas.compat import (range, zip, map, filter, lrange, lzip, lmap,
                            lfilter, builtins, iterkeys, itervalues, iteritems,
-                           next, get_range_parameters, PY2)
+                           next, get_range_parameters, PY2, re_type)
 
 
 class TestBuiltinIterators(object):
@@ -89,3 +89,8 @@ def test_get_range_parameters(self, start, stop, step):
         assert start_result == start_expected
         assert stop_result == stop_expected
         assert step_result == step_expected
+
+
+def test_re_type():
+    import re
+    assert isinstance(re.compile(''), re_type)


Code review comments:
diff_hunk: @@ -89,3 +89,8 @@ def test_get_range_parameters(self, start, stop, step):
         assert start_result == start_expected
         assert stop_result == stop_expected
         assert step_result == step_expected
+
+
+def test_re_type():
+    import re
path: pandas/tests/test_compat.py
text: @user1:
can u move the import to the top