Skip to content

CLN: Misc PY2/3 compat functions #26008

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 10 commits into from
Apr 9, 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
55 changes: 3 additions & 52 deletions pandas/compat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
* lists: lrange(), lmap(), lzip(), lfilter()
* iterable method compatibility: iteritems, iterkeys, itervalues
* Uses the original method if available, otherwise uses items, keys, values.
* bind_method: binds functions to classes
* add_metaclass(metaclass) - class decorator that recreates class with with the
given metaclass instead (and avoids intermediary class creation)

Expand All @@ -22,7 +21,6 @@
from distutils.version import LooseVersion
import sys
import platform
import types
import struct

PY2 = sys.version_info[0] == 2
Expand All @@ -32,8 +30,6 @@
PY37 = sys.version_info >= (3, 7)
PYPY = platform.python_implementation() == 'PyPy'

from pandas.compat.chainmap import DeepChainMap


# list-producing versions of the major Python iterating functions
def lrange(*args, **kwargs):
Expand All @@ -52,29 +48,6 @@ def lfilter(*args, **kwargs):
return list(filter(*args, **kwargs))


if PY3:
def isidentifier(s):
return s.isidentifier()

def str_to_bytes(s, encoding=None):
return s.encode(encoding or 'ascii')

def bytes_to_str(b, encoding=None):
return b.decode(encoding or 'utf-8')

else:
# Python 2
_name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")

def isidentifier(s, dotted=False):
return bool(_name_re.match(s))

def str_to_bytes(s, encoding='ascii'):
return s

def bytes_to_str(b, encoding='ascii'):
return b

if PY2:
def iteritems(obj, **kw):
return obj.iteritems(**kw)
Expand All @@ -95,30 +68,6 @@ def iterkeys(obj, **kw):
def itervalues(obj, **kw):
return iter(obj.values(**kw))


def bind_method(cls, name, func):
"""Bind a method to class, python 2 and python 3 compatible.

Parameters
----------

cls : type
class to receive bound method
name : basestring
name of method on class instance
func : function
function to be bound as method


Returns
-------
None
"""
# only python 2 has bound/unbound method issue
if not PY3:
setattr(cls, name, types.MethodType(func, None, cls))
else:
setattr(cls, name, func)
# ----------------------------------------------------------------------------
# functions largely based / taken from the six module

Expand All @@ -133,7 +82,7 @@ def to_str(s):
Convert bytes and non-string into Python 3 str
"""
if isinstance(s, bytes):
s = bytes_to_str(s)
s = s.decode('utf-8')
elif not isinstance(s, str):
s = str(s)
return s
Expand Down Expand Up @@ -172,6 +121,7 @@ def wrapper(cls):
return metaclass(cls.__name__, cls.__bases__, orig_vars)
return wrapper


if PY3:
def raise_with_traceback(exc, traceback=Ellipsis):
if traceback == Ellipsis:
Expand Down Expand Up @@ -207,6 +157,7 @@ def raise_with_traceback(exc, traceback=Ellipsis):
else:
re_type = type(re.compile(''))


# https://github.com/pandas-dev/pandas/pull/9123
def is_platform_little_endian():
""" am I little endian """
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/computation/pytables.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import numpy as np

from pandas._libs.tslibs import Timedelta, Timestamp
from pandas.compat import DeepChainMap
from pandas.compat.chainmap import DeepChainMap

from pandas.core.dtypes.common import is_list_like

Expand Down
2 changes: 1 addition & 1 deletion pandas/core/computation/scope.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import numpy as np

from pandas._libs.tslibs import Timestamp
from pandas.compat import DeepChainMap
from pandas.compat.chainmap import DeepChainMap

from pandas.core.base import StringMixin
import pandas.core.computation as compu
Expand Down
4 changes: 2 additions & 2 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

from pandas._libs import Timestamp, iNaT, properties
import pandas.compat as compat
from pandas.compat import isidentifier, lrange, lzip, set_function_name, to_str
from pandas.compat import lrange, lzip, set_function_name, to_str
from pandas.compat.numpy import function as nv
from pandas.errors import AbstractMethodError
from pandas.util._decorators import (
Expand Down Expand Up @@ -5150,7 +5150,7 @@ def _dir_additions(self):
If info_axis is a MultiIndex, it's first level values are used.
"""
additions = {c for c in self._info_axis.unique(level=0)[:100]
if isinstance(c, str) and isidentifier(c)}
if isinstance(c, str) and c.isidentifier()}
return super(NDFrame, self)._dir_additions().union(additions)

# ----------------------------------------------------------------------
Expand Down
3 changes: 1 addition & 2 deletions pandas/core/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

from pandas._libs import algos as libalgos, lib, ops as libops
import pandas.compat as compat
from pandas.compat import bind_method
from pandas.errors import NullFrequencyError
from pandas.util._decorators import Appender

Expand Down Expand Up @@ -1545,7 +1544,7 @@ def add_methods(cls, new_methods):
force = not (issubclass(cls, ABCSparseArray) and
name.startswith('__i'))
if force or name not in cls.__dict__:
bind_method(cls, name, method)
setattr(cls, name, method)


# ----------------------------------------------------------------------
Expand Down
8 changes: 2 additions & 6 deletions pandas/io/clipboards.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
from io import StringIO
import warnings

import pandas.compat as compat

from pandas.core.dtypes.generic import ABCDataFrame

from pandas import get_option, option_context
Expand Down Expand Up @@ -38,10 +36,8 @@ def read_clipboard(sep=r'\s+', **kwargs): # pragma: no cover

# Try to decode (if needed, as "text" might already be a string here).
try:
text = compat.bytes_to_str(
text, encoding=(kwargs.get('encoding') or
get_option('display.encoding'))
)
text = text.decode(kwargs.get('encoding')
or get_option('display.encoding'))
except AttributeError:
Copy link
Member

@jbrockmendel jbrockmendel Apr 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe take the getoption outside of the try/except?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm...that encoding logic is specific to the try-except block. I'm not sure we should be putting it outside.

In addition, since this is supposed to be pure removal, I'm uneasy about making other changes beyond the stated purpose of removing PY2 / 3 things.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine by me. Moved back in the try except.

pass

Expand Down
3 changes: 1 addition & 2 deletions pandas/io/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from urllib.request import pathname2url, urlopen
import zipfile

import pandas.compat as compat
from pandas.errors import ( # noqa
AbstractMethodError, DtypeWarning, EmptyDataError, ParserError,
ParserWarning)
Expand Down Expand Up @@ -460,7 +459,7 @@ def __next__(self):

# readline returns bytes, not str, but Python's CSV reader
# expects str, so convert the output to str before continuing
newline = compat.bytes_to_str(newline)
newline = newline.decode('utf-8')

# mmap doesn't raise if reading past the allocated
# data but instead returns an empty string, so raise
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/io/formats/test_printing.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import pandas._config.config as cf

import pandas as pd
from pandas import compat

import pandas.io.formats.format as fmt
import pandas.io.formats.printing as printing
Expand All @@ -27,7 +26,7 @@ def test_repr_binary_type():
raw = bytes(letters, encoding=cf.get_option('display.encoding'))
except TypeError:
raw = bytes(letters)
b = str(compat.bytes_to_str(raw))
b = str(raw.decode('utf-8'))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a big deal, but is the str still necessary?

Copy link
Member

@gfyoung gfyoung Apr 8, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not...should test in a separate commit nonetheless.

res = printing.pprint_thing(b, quote_strings=True)
assert res == repr(b)
res = printing.pprint_thing(b, quote_strings=False)
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/io/json/test_ujson.py
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ def test_decode_big_escape(self):
# Make sure no Exception is raised.
for _ in range(10):
base = '\u00e5'.encode("utf-8")
quote = compat.str_to_bytes("\"")
quote = b'"'

escape_input = quote + (base * 1024 * 1024 * 2) + quote
ujson.decode(escape_input)
Expand Down
4 changes: 2 additions & 2 deletions pandas/tests/series/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import pytest

import pandas.compat as compat
from pandas.compat import isidentifier, lzip
from pandas.compat import lzip

import pandas as pd
from pandas import (
Expand Down Expand Up @@ -282,7 +282,7 @@ def test_index_tab_completion(self, index):
for i, x in enumerate(s.index.unique(level=0)):
if i < 100:
assert (not isinstance(x, str) or
not isidentifier(x) or x in dir_s)
not x.isidentifier() or x in dir_s)
else:
assert x not in dir_s

Expand Down