Skip to content

Commit 190a69e

Browse files
jschendelmroeschke
authored andcommitted
CLN: Remove PY2/PY3 flags from pandas.compat (#26047)
* CLN: Remove PY2/PY3 flags from pandas.compat * lint * no longer mention py2
1 parent 5a15069 commit 190a69e

20 files changed

+72
-215
lines changed

pandas/_libs/tslibs/parsing.pyx

+2-10
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ from cpython.datetime cimport datetime
1111

1212
import numpy as np
1313

14-
import six
15-
1614
# dateutil compat
1715
from dateutil.tz import (tzoffset,
1816
tzlocal as _dateutil_tzlocal,
@@ -526,14 +524,8 @@ def try_parse_datetime_components(object[:] years,
526524
# Copyright (c) 2017 - dateutil contributors
527525
class _timelex(object):
528526
def __init__(self, instream):
529-
if six.PY2:
530-
# In Python 2, we can't duck type properly because unicode has
531-
# a 'decode' function, and we'd be double-decoding
532-
if isinstance(instream, (bytes, bytearray)):
533-
instream = instream.decode()
534-
else:
535-
if getattr(instream, 'decode', None) is not None:
536-
instream = instream.decode()
527+
if getattr(instream, 'decode', None) is not None:
528+
instream = instream.decode()
537529

538530
if isinstance(instream, str):
539531
self.stream = instream

pandas/_version.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
import sys
1515
from typing import Callable, Dict
1616

17-
from pandas.compat import PY3
18-
1917

2018
def get_keywords():
2119
# these strings will be replaced by git during git-archive.
@@ -84,9 +82,7 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
8482
if verbose:
8583
print("unable to find command, tried %s" % (commands,))
8684
return None
87-
stdout = p.communicate()[0].strip()
88-
if PY3:
89-
stdout = stdout.decode()
85+
stdout = p.communicate()[0].strip().decode()
9086
if p.returncode != 0:
9187
if verbose:
9288
print("unable to run {dispcmd} (error)".format(dispcmd=dispcmd))

pandas/compat/__init__.py

+36-64
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
compat
33
======
44
5-
Cross-compatible functions for Python 2 and 3.
5+
Cross-compatible functions for different versions of Python.
66
7-
Key items to import for 2/3 compatible code:
7+
Key items to import for compatible code:
88
* lists: lrange(), lmap(), lzip(), lfilter()
99
* iterable method compatibility: iteritems, iterkeys, itervalues
1010
* Uses the original method if available, otherwise uses items, keys, values.
@@ -23,8 +23,6 @@
2323
import platform
2424
import struct
2525

26-
PY2 = sys.version_info[0] == 2
27-
PY3 = sys.version_info[0] >= 3
2826
PY36 = sys.version_info >= (3, 6)
2927
PY37 = sys.version_info >= (3, 7)
3028
PYPY = platform.python_implementation() == 'PyPy'
@@ -47,25 +45,16 @@ def lfilter(*args, **kwargs):
4745
return list(filter(*args, **kwargs))
4846

4947

50-
if PY2:
51-
def iteritems(obj, **kw):
52-
return obj.iteritems(**kw)
48+
def iteritems(obj, **kw):
49+
return iter(obj.items(**kw))
5350

54-
def iterkeys(obj, **kw):
55-
return obj.iterkeys(**kw)
5651

57-
def itervalues(obj, **kw):
58-
return obj.itervalues(**kw)
52+
def iterkeys(obj, **kw):
53+
return iter(obj.keys(**kw))
5954

60-
else:
61-
def iteritems(obj, **kw):
62-
return iter(obj.items(**kw))
63-
64-
def iterkeys(obj, **kw):
65-
return iter(obj.keys(**kw))
6655

67-
def itervalues(obj, **kw):
68-
return iter(obj.values(**kw))
56+
def itervalues(obj, **kw):
57+
return iter(obj.values(**kw))
6958

7059
# ----------------------------------------------------------------------------
7160
# functions largely based / taken from the six module
@@ -75,42 +64,33 @@ def itervalues(obj, **kw):
7564
# found at https://bitbucket.org/gutworth/six
7665

7766

78-
if PY3:
79-
def to_str(s):
80-
"""
81-
Convert bytes and non-string into Python 3 str
82-
"""
83-
if isinstance(s, bytes):
84-
s = s.decode('utf-8')
85-
elif not isinstance(s, str):
86-
s = str(s)
87-
return s
88-
89-
def set_function_name(f, name, cls):
90-
""" Bind the name/qualname attributes of the function """
91-
f.__name__ = name
92-
f.__qualname__ = '{klass}.{name}'.format(
93-
klass=cls.__name__,
94-
name=name)
95-
f.__module__ = cls.__module__
96-
return f
97-
else:
98-
def to_str(s):
99-
"""
100-
Convert unicode and non-string into Python 2 str
101-
"""
102-
if not isinstance(s, basestring):
103-
s = str(s)
104-
return s
67+
def to_str(s):
68+
"""
69+
Convert bytes and non-string into Python 3 str
70+
"""
71+
if isinstance(s, bytes):
72+
s = s.decode('utf-8')
73+
elif not isinstance(s, str):
74+
s = str(s)
75+
return s
10576

106-
def set_function_name(f, name, cls):
107-
""" Bind the name attributes of the function """
108-
f.__name__ = name
109-
return f
77+
78+
def set_function_name(f, name, cls):
79+
"""
80+
Bind the name/qualname attributes of the function
81+
"""
82+
f.__name__ = name
83+
f.__qualname__ = '{klass}.{name}'.format(
84+
klass=cls.__name__,
85+
name=name)
86+
f.__module__ = cls.__module__
87+
return f
11088

11189

11290
def add_metaclass(metaclass):
113-
"""Class decorator for creating a class with a metaclass."""
91+
"""
92+
Class decorator for creating a class with a metaclass.
93+
"""
11494
def wrapper(cls):
11595
orig_vars = cls.__dict__.copy()
11696
orig_vars.pop('__dict__', None)
@@ -121,22 +101,14 @@ def wrapper(cls):
121101
return wrapper
122102

123103

124-
if PY3:
125-
def raise_with_traceback(exc, traceback=Ellipsis):
126-
if traceback == Ellipsis:
127-
_, _, traceback = sys.exc_info()
128-
raise exc.with_traceback(traceback)
129-
else:
130-
# this version of raise is a syntax error in Python 3
131-
exec("""
132104
def raise_with_traceback(exc, traceback=Ellipsis):
105+
"""
106+
Raise exception with existing traceback.
107+
If traceback is not passed, uses sys.exc_info() to get traceback.
108+
"""
133109
if traceback == Ellipsis:
134110
_, _, traceback = sys.exc_info()
135-
raise exc, None, traceback
136-
""")
137-
138-
raise_with_traceback.__doc__ = """Raise exception with existing traceback.
139-
If traceback is not passed, uses sys.exc_info() to get traceback."""
111+
raise exc.with_traceback(traceback)
140112

141113
# In Python 3.7, the private re._pattern_type is removed.
142114
# Python 3.5+ have typing.re.Pattern

pandas/conftest.py

+6-16
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import pytest
1010
from pytz import FixedOffset, utc
1111

12-
from pandas.compat import PY3
1312
import pandas.util._test_decorators as td
1413

1514
import pandas as pd
@@ -134,8 +133,6 @@ def observed(request):
134133
'__truediv__', '__rtruediv__',
135134
'__pow__', '__rpow__',
136135
'__mod__', '__rmod__']
137-
if not PY3:
138-
_all_arithmetic_operators.extend(['__div__', '__rdiv__'])
139136

140137

141138
@pytest.fixture(params=_all_arithmetic_operators)
@@ -248,12 +245,7 @@ def datetime_tz_utc():
248245
return timezone.utc
249246

250247

251-
utc_objs = ['utc', 'dateutil/UTC', utc, tzutc()]
252-
if PY3:
253-
utc_objs.append(timezone.utc)
254-
255-
256-
@pytest.fixture(params=utc_objs)
248+
@pytest.fixture(params=['utc', 'dateutil/UTC', utc, tzutc(), timezone.utc])
257249
def utc_fixture(request):
258250
"""
259251
Fixture to provide variants of UTC timezone strings and tzinfo objects
@@ -406,9 +398,9 @@ def tz_aware_fixture(request):
406398
OBJECT_DTYPES = [object, 'object']
407399

408400
ALL_REAL_DTYPES = FLOAT_DTYPES + ALL_INT_DTYPES
409-
ALL_NUMPY_DTYPES = (ALL_REAL_DTYPES + COMPLEX_DTYPES + STRING_DTYPES
410-
+ DATETIME_DTYPES + TIMEDELTA_DTYPES + BOOL_DTYPES
411-
+ OBJECT_DTYPES + BYTES_DTYPES * PY3) # bytes only for PY3
401+
ALL_NUMPY_DTYPES = (ALL_REAL_DTYPES + COMPLEX_DTYPES + STRING_DTYPES +
402+
DATETIME_DTYPES + TIMEDELTA_DTYPES + BOOL_DTYPES +
403+
OBJECT_DTYPES + BYTES_DTYPES)
412404

413405

414406
@pytest.fixture(params=STRING_DTYPES)
@@ -559,8 +551,7 @@ def any_numpy_dtype(request):
559551
# categoricals are handled separately
560552
_any_skipna_inferred_dtype = [
561553
('string', ['a', np.nan, 'c']),
562-
('unicode' if not PY3 else 'string', ['a', np.nan, 'c']),
563-
('bytes' if PY3 else 'string', [b'a', np.nan, b'c']),
554+
('bytes', [b'a', np.nan, b'c']),
564555
('empty', [np.nan, np.nan, np.nan]),
565556
('empty', []),
566557
('mixed-integer', ['a', np.nan, 2]),
@@ -592,9 +583,8 @@ def any_skipna_inferred_dtype(request):
592583
593584
The covered (inferred) types are:
594585
* 'string'
595-
* 'unicode' (if PY2)
596586
* 'empty'
597-
* 'bytes' (if PY3)
587+
* 'bytes'
598588
* 'mixed'
599589
* 'mixed-integer'
600590
* 'mixed-integer-float'

pandas/core/arrays/base.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
import numpy as np
1212

13-
from pandas.compat import PY3, set_function_name
13+
from pandas.compat import set_function_name
1414
from pandas.compat.numpy import function as nv
1515
from pandas.errors import AbstractMethodError
1616
from pandas.util._decorators import Appender, Substitution
@@ -991,10 +991,6 @@ def _add_arithmetic_ops(cls):
991991
cls.__rfloordiv__ = cls._create_arithmetic_method(ops.rfloordiv)
992992
cls.__truediv__ = cls._create_arithmetic_method(operator.truediv)
993993
cls.__rtruediv__ = cls._create_arithmetic_method(ops.rtruediv)
994-
if not PY3:
995-
cls.__div__ = cls._create_arithmetic_method(operator.div)
996-
cls.__rdiv__ = cls._create_arithmetic_method(ops.rdiv)
997-
998994
cls.__divmod__ = cls._create_arithmetic_method(divmod)
999995
cls.__rdivmod__ = cls._create_arithmetic_method(ops.rdivmod)
1000996

pandas/core/arrays/sparse.py

-2
Original file line numberDiff line numberDiff line change
@@ -1593,8 +1593,6 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
15931593

15941594
special = {'add', 'sub', 'mul', 'pow', 'mod', 'floordiv', 'truediv',
15951595
'divmod', 'eq', 'ne', 'lt', 'gt', 'le', 'ge', 'remainder'}
1596-
if compat.PY2:
1597-
special.add('div')
15981596
aliases = {
15991597
'subtract': 'sub',
16001598
'multiply': 'mul',

pandas/core/arrays/timedeltas.py

-4
Original file line numberDiff line numberDiff line change
@@ -566,10 +566,6 @@ def __rtruediv__(self, other):
566566
.format(dtype=other.dtype,
567567
cls=type(self).__name__))
568568

569-
if compat.PY2:
570-
__div__ = __truediv__
571-
__rdiv__ = __rtruediv__
572-
573569
def __floordiv__(self, other):
574570
if isinstance(other, (ABCSeries, ABCDataFrame, ABCIndexClass)):
575571
return NotImplemented

pandas/core/base.py

+3-19
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,8 @@
3434

3535

3636
class StringMixin(object):
37-
"""implements string methods so long as object defines a `__unicode__`
38-
method.
39-
40-
Handles Python2/3 compatibility transparently.
37+
"""
38+
Implements string methods so long as object defines a `__unicode__` method.
4139
"""
4240
# side note - this could be made into a metaclass if more than one
4341
# object needs
@@ -51,21 +49,12 @@ def __unicode__(self):
5149
def __str__(self):
5250
"""
5351
Return a string representation for a particular Object
54-
55-
Invoked by str(df) in both py2/py3.
56-
Yields Bytestring in Py2, Unicode String in py3.
5752
"""
58-
59-
if compat.PY3:
60-
return self.__unicode__()
61-
return self.__bytes__()
53+
return self.__unicode__()
6254

6355
def __bytes__(self):
6456
"""
6557
Return a string representation for a particular object.
66-
67-
Invoked by bytes(obj) in py3 only.
68-
Yields a bytestring in both py2/py3.
6958
"""
7059
from pandas._config import get_option
7160

@@ -75,8 +64,6 @@ def __bytes__(self):
7564
def __repr__(self):
7665
"""
7766
Return a string representation for a particular object.
78-
79-
Yields Bytestring in Py2, Unicode String in py3.
8067
"""
8168
return str(self)
8269

@@ -93,9 +80,6 @@ def _constructor(self):
9380
def __unicode__(self):
9481
"""
9582
Return a string representation for a particular object.
96-
97-
Invoked by unicode(obj) in py2 only. Yields a Unicode String in both
98-
py2/py3.
9983
"""
10084
# Should be overwritten by base classes
10185
return object.__repr__(self)

pandas/core/computation/ops.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import numpy as np
1010

1111
from pandas._libs.tslibs import Timestamp
12-
from pandas.compat import PY3
1312

1413
from pandas.core.dtypes.common import is_list_like, is_scalar
1514

@@ -272,8 +271,8 @@ def _not_in(x, y):
272271
_bool_ops_dict = dict(zip(_bool_ops_syms, _bool_ops_funcs))
273272

274273
_arith_ops_syms = '+', '-', '*', '/', '**', '//', '%'
275-
_arith_ops_funcs = (op.add, op.sub, op.mul, op.truediv if PY3 else op.div,
276-
op.pow, op.floordiv, op.mod)
274+
_arith_ops_funcs = (op.add, op.sub, op.mul, op.truediv, op.pow, op.floordiv,
275+
op.mod)
277276
_arith_ops_dict = dict(zip(_arith_ops_syms, _arith_ops_funcs))
278277

279278
_special_case_arith_ops_syms = '**', '//', '%'
@@ -471,10 +470,9 @@ def __init__(self, lhs, rhs, truediv, *args, **kwargs):
471470
lhs.return_type,
472471
rhs.return_type))
473472

474-
if truediv or PY3:
475-
# do not upcast float32s to float64 un-necessarily
476-
acceptable_dtypes = [np.float32, np.float_]
477-
_cast_inplace(com.flatten(self), acceptable_dtypes, np.float_)
473+
# do not upcast float32s to float64 un-necessarily
474+
acceptable_dtypes = [np.float32, np.float_]
475+
_cast_inplace(com.flatten(self), acceptable_dtypes, np.float_)
478476

479477

480478
_unary_ops_syms = '+', '-', '~', 'not'

0 commit comments

Comments
 (0)