Skip to content

CLN: Remove PY2/PY3 flags from pandas.compat #26047

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
Apr 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions pandas/_libs/tslibs/parsing.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ from cpython.datetime cimport datetime

import numpy as np

import six

# dateutil compat
from dateutil.tz import (tzoffset,
tzlocal as _dateutil_tzlocal,
Expand Down Expand Up @@ -526,14 +524,8 @@ def try_parse_datetime_components(object[:] years,
# Copyright (c) 2017 - dateutil contributors
class _timelex(object):
def __init__(self, instream):
if six.PY2:
# In Python 2, we can't duck type properly because unicode has
# a 'decode' function, and we'd be double-decoding
if isinstance(instream, (bytes, bytearray)):
instream = instream.decode()
else:
if getattr(instream, 'decode', None) is not None:
instream = instream.decode()
if getattr(instream, 'decode', None) is not None:
instream = instream.decode()

if isinstance(instream, str):
self.stream = instream
Expand Down
6 changes: 1 addition & 5 deletions pandas/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
import sys
from typing import Callable, Dict

from pandas.compat import PY3


def get_keywords():
# these strings will be replaced by git during git-archive.
Expand Down Expand Up @@ -84,9 +82,7 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
if verbose:
print("unable to find command, tried %s" % (commands,))
return None
stdout = p.communicate()[0].strip()
if PY3:
stdout = stdout.decode()
stdout = p.communicate()[0].strip().decode()
if p.returncode != 0:
if verbose:
print("unable to run {dispcmd} (error)".format(dispcmd=dispcmd))
Expand Down
100 changes: 36 additions & 64 deletions pandas/compat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
compat
======

Cross-compatible functions for Python 2 and 3.
Cross-compatible functions for different versions of Python.

Key items to import for 2/3 compatible code:
Key items to import for compatible code:
* lists: lrange(), lmap(), lzip(), lfilter()
* iterable method compatibility: iteritems, iterkeys, itervalues
* Uses the original method if available, otherwise uses items, keys, values.
Expand All @@ -23,8 +23,6 @@
import platform
import struct

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


if PY2:
def iteritems(obj, **kw):
return obj.iteritems(**kw)
def iteritems(obj, **kw):
return iter(obj.items(**kw))

def iterkeys(obj, **kw):
return obj.iterkeys(**kw)

def itervalues(obj, **kw):
return obj.itervalues(**kw)
def iterkeys(obj, **kw):
return iter(obj.keys(**kw))

else:
def iteritems(obj, **kw):
return iter(obj.items(**kw))

def iterkeys(obj, **kw):
return iter(obj.keys(**kw))

def itervalues(obj, **kw):
return iter(obj.values(**kw))
def itervalues(obj, **kw):
return iter(obj.values(**kw))

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


if PY3:
def to_str(s):
"""
Convert bytes and non-string into Python 3 str
"""
if isinstance(s, bytes):
s = s.decode('utf-8')
elif not isinstance(s, str):
s = str(s)
return s

def set_function_name(f, name, cls):
""" Bind the name/qualname attributes of the function """
f.__name__ = name
f.__qualname__ = '{klass}.{name}'.format(
klass=cls.__name__,
name=name)
f.__module__ = cls.__module__
return f
else:
def to_str(s):
"""
Convert unicode and non-string into Python 2 str
"""
if not isinstance(s, basestring):
s = str(s)
return s
def to_str(s):
"""
Convert bytes and non-string into Python 3 str
"""
if isinstance(s, bytes):
s = s.decode('utf-8')
elif not isinstance(s, str):
s = str(s)
return s

def set_function_name(f, name, cls):
""" Bind the name attributes of the function """
f.__name__ = name
return f

def set_function_name(f, name, cls):
"""
Bind the name/qualname attributes of the function
"""
f.__name__ = name
f.__qualname__ = '{klass}.{name}'.format(
klass=cls.__name__,
name=name)
f.__module__ = cls.__module__
return f


def add_metaclass(metaclass):
"""Class decorator for creating a class with a metaclass."""
"""
Class decorator for creating a class with a metaclass.
"""
def wrapper(cls):
orig_vars = cls.__dict__.copy()
orig_vars.pop('__dict__', None)
Expand All @@ -121,22 +101,14 @@ def wrapper(cls):
return wrapper


if PY3:
def raise_with_traceback(exc, traceback=Ellipsis):
if traceback == Ellipsis:
_, _, traceback = sys.exc_info()
raise exc.with_traceback(traceback)
else:
# this version of raise is a syntax error in Python 3
exec("""
def raise_with_traceback(exc, traceback=Ellipsis):
"""
Raise exception with existing traceback.
If traceback is not passed, uses sys.exc_info() to get traceback.
"""
if traceback == Ellipsis:
_, _, traceback = sys.exc_info()
raise exc, None, traceback
""")

raise_with_traceback.__doc__ = """Raise exception with existing traceback.
If traceback is not passed, uses sys.exc_info() to get traceback."""
raise exc.with_traceback(traceback)


# dateutil minimum version
Expand Down
22 changes: 6 additions & 16 deletions pandas/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import pytest
from pytz import FixedOffset, utc

from pandas.compat import PY3
import pandas.util._test_decorators as td

import pandas as pd
Expand Down Expand Up @@ -134,8 +133,6 @@ def observed(request):
'__truediv__', '__rtruediv__',
'__pow__', '__rpow__',
'__mod__', '__rmod__']
if not PY3:
_all_arithmetic_operators.extend(['__div__', '__rdiv__'])


@pytest.fixture(params=_all_arithmetic_operators)
Expand Down Expand Up @@ -248,12 +245,7 @@ def datetime_tz_utc():
return timezone.utc


utc_objs = ['utc', 'dateutil/UTC', utc, tzutc()]
if PY3:
utc_objs.append(timezone.utc)


@pytest.fixture(params=utc_objs)
@pytest.fixture(params=['utc', 'dateutil/UTC', utc, tzutc(), timezone.utc])
def utc_fixture(request):
"""
Fixture to provide variants of UTC timezone strings and tzinfo objects
Expand Down Expand Up @@ -406,9 +398,9 @@ def tz_aware_fixture(request):
OBJECT_DTYPES = [object, 'object']

ALL_REAL_DTYPES = FLOAT_DTYPES + ALL_INT_DTYPES
ALL_NUMPY_DTYPES = (ALL_REAL_DTYPES + COMPLEX_DTYPES + STRING_DTYPES
+ DATETIME_DTYPES + TIMEDELTA_DTYPES + BOOL_DTYPES
+ OBJECT_DTYPES + BYTES_DTYPES * PY3) # bytes only for PY3
ALL_NUMPY_DTYPES = (ALL_REAL_DTYPES + COMPLEX_DTYPES + STRING_DTYPES +
DATETIME_DTYPES + TIMEDELTA_DTYPES + BOOL_DTYPES +
OBJECT_DTYPES + BYTES_DTYPES)


@pytest.fixture(params=STRING_DTYPES)
Expand Down Expand Up @@ -559,8 +551,7 @@ def any_numpy_dtype(request):
# categoricals are handled separately
_any_skipna_inferred_dtype = [
('string', ['a', np.nan, 'c']),
('unicode' if not PY3 else 'string', ['a', np.nan, 'c']),
('bytes' if PY3 else 'string', [b'a', np.nan, b'c']),
('bytes', [b'a', np.nan, b'c']),
('empty', [np.nan, np.nan, np.nan]),
('empty', []),
('mixed-integer', ['a', np.nan, 2]),
Expand Down Expand Up @@ -592,9 +583,8 @@ def any_skipna_inferred_dtype(request):

The covered (inferred) types are:
* 'string'
* 'unicode' (if PY2)
* 'empty'
* 'bytes' (if PY3)
* 'bytes'
* 'mixed'
* 'mixed-integer'
* 'mixed-integer-float'
Expand Down
6 changes: 1 addition & 5 deletions pandas/core/arrays/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import numpy as np

from pandas.compat import PY3, set_function_name
from pandas.compat import set_function_name
from pandas.compat.numpy import function as nv
from pandas.errors import AbstractMethodError
from pandas.util._decorators import Appender, Substitution
Expand Down Expand Up @@ -991,10 +991,6 @@ def _add_arithmetic_ops(cls):
cls.__rfloordiv__ = cls._create_arithmetic_method(ops.rfloordiv)
cls.__truediv__ = cls._create_arithmetic_method(operator.truediv)
cls.__rtruediv__ = cls._create_arithmetic_method(ops.rtruediv)
if not PY3:
cls.__div__ = cls._create_arithmetic_method(operator.div)
cls.__rdiv__ = cls._create_arithmetic_method(ops.rdiv)

cls.__divmod__ = cls._create_arithmetic_method(divmod)
cls.__rdivmod__ = cls._create_arithmetic_method(ops.rdivmod)

Expand Down
2 changes: 0 additions & 2 deletions pandas/core/arrays/sparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -1593,8 +1593,6 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):

special = {'add', 'sub', 'mul', 'pow', 'mod', 'floordiv', 'truediv',
'divmod', 'eq', 'ne', 'lt', 'gt', 'le', 'ge', 'remainder'}
if compat.PY2:
special.add('div')
aliases = {
'subtract': 'sub',
'multiply': 'mul',
Expand Down
4 changes: 0 additions & 4 deletions pandas/core/arrays/timedeltas.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,10 +566,6 @@ def __rtruediv__(self, other):
.format(dtype=other.dtype,
cls=type(self).__name__))

if compat.PY2:
__div__ = __truediv__
__rdiv__ = __rtruediv__

def __floordiv__(self, other):
if isinstance(other, (ABCSeries, ABCDataFrame, ABCIndexClass)):
return NotImplemented
Expand Down
22 changes: 3 additions & 19 deletions pandas/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,8 @@


class StringMixin(object):
"""implements string methods so long as object defines a `__unicode__`
method.

Handles Python2/3 compatibility transparently.
"""
Implements string methods so long as object defines a `__unicode__` method.
"""
# side note - this could be made into a metaclass if more than one
# object needs
Expand All @@ -51,21 +49,12 @@ def __unicode__(self):
def __str__(self):
"""
Return a string representation for a particular Object

Invoked by str(df) in both py2/py3.
Yields Bytestring in Py2, Unicode String in py3.
"""

if compat.PY3:
return self.__unicode__()
return self.__bytes__()
return self.__unicode__()

def __bytes__(self):
"""
Return a string representation for a particular object.

Invoked by bytes(obj) in py3 only.
Yields a bytestring in both py2/py3.
"""
from pandas._config import get_option

Expand All @@ -75,8 +64,6 @@ def __bytes__(self):
def __repr__(self):
"""
Return a string representation for a particular object.

Yields Bytestring in Py2, Unicode String in py3.
"""
return str(self)

Expand All @@ -93,9 +80,6 @@ def _constructor(self):
def __unicode__(self):
"""
Return a string representation for a particular object.

Invoked by unicode(obj) in py2 only. Yields a Unicode String in both
py2/py3.
"""
# Should be overwritten by base classes
return object.__repr__(self)
Expand Down
12 changes: 5 additions & 7 deletions pandas/core/computation/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import numpy as np

from pandas._libs.tslibs import Timestamp
from pandas.compat import PY3

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

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

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

_special_case_arith_ops_syms = '**', '//', '%'
Expand Down Expand Up @@ -471,10 +470,9 @@ def __init__(self, lhs, rhs, truediv, *args, **kwargs):
lhs.return_type,
rhs.return_type))

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


_unary_ops_syms = '+', '-', '~', 'not'
Expand Down
Loading