Skip to content

Commit

Permalink
compat with pandas 0.24 (#38)
Browse files Browse the repository at this point in the history
* compat with pandas 0.24

* lint

* lint

* remove old envs
  • Loading branch information
TomAugspurger authored May 17, 2019
1 parent eb6e8c1 commit 0db23fc
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 18 deletions.
2 changes: 0 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ env:
- secure: "RXSmdQ8ordLyB07sgwJ27ojg2bCUbXxp15kEDQRpuCkfZyStmL1Olj4I+7dUkmFiQDkSzY7MGhS2uPQ2mxacKbDfiyrmVK3JBcTacBp4LMVeE0QWvOFs2hp1JQoQVqxx410OJb4itQGo+JzxYXvPGqmhn8of7oM5oA9r8hM0WHKK6IhDm+Vh89VI6qRZL2MXfeM1a8lerw7CL+8ZZTLt8EPjiHE3b2AYalUgtQrP+WbwLFssienXlbvDDLAvukq7Pwm5/g8UU3VaASOnZzxsCq0Oi3MarZJIPe/xf/C825ovbwT3ehD8LZorAvF4WmmwhbTM8hrrtwbQ8UIwlCUfOVIL3NGIPIFO1IUPCSlmz6IAxDnnMfx0dvJnatMn51yfSa2KWdlO6rXveOsnBKnG7vD7HGHK8yfkssx5TxECoX9Pc6GV/hIQwA12TsJEj+303YqIf6kVQc6WtvfZAIlxIFDPWNcApgnB0bZsPKBgRyspDs+NRcXR0wNDtQxcIk2MD2WzZwgKLvjs4XkUfeorYelzn1OY+fOiFZT3hhe0+F3w+hinU9tgjyJ4gLwb4mmK0ZhCsCztygVe4MnW7JILtsw7sMhC/IFzYoLffVTB4jFLWZEjFUC5hscBoV6FDZrrY6Z6YLmY2F9o6IV4k99U4o94RZI5GEoGMxxqNxF5Cds="
matrix:
- PYTHON=3.6 NUMPY=1.11
- PYTHON=3.5 NUMPY=1.9
- PYTHON=2.7 NUMPY=1.9
before_install:
- export PATH="$HOME/miniconda3/bin:$PATH"
install:
Expand Down
3 changes: 0 additions & 3 deletions cyberpandas/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,19 @@ def to_bytes(n, length, byteorder='big'):


def pack(ip):
# type: (int) -> bytes
if six.PY2:
return to_bytes(ip, length=16, byteorder='big')
else:
return ip.to_bytes(16, byteorder='big')


def unpack(ip):
# type: (T.Tuple[int, int]) -> int, int
# Recipe 3.5 from Python Cookbook 3rd ed. (p. 90)
# int.from_bytes(data, 'big') for Py3+
hi, lo = struct.unpack(">QQ", ip)
return hi, lo


def combine(hi, lo):
# type: (int, int) -> int
"""Combine the hi and lo bytes into the final ip address."""
return (hi << 64) + lo
4 changes: 2 additions & 2 deletions cyberpandas/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ def dtype(self):
return self._dtype

@classmethod
def _from_sequence(cls, scalars):
return cls(scalars)
def _from_sequence(cls, scalars, dtype=None, copy=False):
return cls(scalars, dtype=dtype)

@classmethod
def _from_factorized(cls, values, original):
Expand Down
2 changes: 0 additions & 2 deletions cyberpandas/dtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@


def is_ipv4(value):
# type: (Any) -> bool
if isinstance(value, str):
return value.count(".") == 3
elif isinstance(value, bytes):
Expand All @@ -14,6 +13,5 @@ def is_ipv4(value):


def is_ipv6(value):
# type: (Any) -> bool
if isinstance(value, str):
return value.count(":") == 7
25 changes: 20 additions & 5 deletions cyberpandas/ip_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class IPv4v6Base(object):
IPv4v6Base.register(ipaddress.IPv6Address)


@pd.api.extensions.register_extension_dtype
class IPType(ExtensionDtype):
name = 'ip'
type = IPv4v6Base
Expand All @@ -44,6 +45,11 @@ def construct_from_string(cls, string):
raise TypeError("Cannot construct a '{}' from "
"'{}'".format(cls, string))

@classmethod
def construct_array_type(cls):
return IPArray


# -----------------------------------------------------------------------------
# Extension Container
# -----------------------------------------------------------------------------
Expand All @@ -69,15 +75,17 @@ class IPArray(NumPyBackedExtensionArrayMixin):
ndim = 1
can_hold_na = True

def __init__(self, values):
def __init__(self, values, dtype=None, copy=False):
from .parser import _to_ip_array

values = _to_ip_array(values) # TODO: avoid potential copy
# TODO: dtype?
if copy:
values = values.copy()
self.data = values

@classmethod
def from_pyints(cls, values):
# type: (T.Sequence[int]) -> 'IPArray'
"""Construct an IPArray from a sequence of Python integers.
This can be useful for representing IPv6 addresses, which may
Expand All @@ -97,7 +105,7 @@ def from_pyints(cls, values):

@classmethod
def from_bytes(cls, bytestring):
"""Create an IPArray from a bytestring.
r"""Create an IPArray from a bytestring.
Parameters
----------
Expand Down Expand Up @@ -295,7 +303,7 @@ def to_pyints(self):
return [combine(*map(int, x)) for x in self.data]

def to_bytes(self):
"""Serialize the IPArray as a Python bytestring.
r"""Serialize the IPArray as a Python bytestring.
This and :meth:IPArray.from_bytes is the fastest way to roundtrip
serialize and de-serialize an IPArray.
Expand All @@ -312,6 +320,13 @@ def to_bytes(self):
"""
return self.data.tobytes()

def astype(self, dtype, copy=True):
if isinstance(dtype, IPType):
if copy:
self = self.copy()
return self
return super(IPArray, self).astype(dtype)

# ------------------------------------------------------------------------
# Ops
# ------------------------------------------------------------------------
Expand Down Expand Up @@ -449,7 +464,6 @@ def isin(self, other):
return mask

def _isin_network(self, other):
# type: (Union[ipaddress.IPv4Network,ipaddress.IPv6Network]) -> ndarray
"""Check whether an array of addresses is contained in a network."""
# A network is bounded below by 'network_address' and
# above by 'broadcast_address'.
Expand Down Expand Up @@ -649,6 +663,7 @@ def mask(self, mask):
# Accessor
# -----------------------------------------------------------------------------


@pd.api.extensions.register_series_accessor("ip")
class IPAccessor:

Expand Down
1 change: 0 additions & 1 deletion cyberpandas/ip_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@


def _as_int(ip):
# type: (Union[int, str, IPv4Address, IPv6Address]) -> int
if isinstance(ip, six.string_types):
ip = ipaddress.ip_address(ip)
return int(ip)
Expand Down
21 changes: 19 additions & 2 deletions cyberpandas/mac_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import numpy as np
import six

from pandas.api.extensions import ExtensionDtype, take
from pandas.api.extensions import (
ExtensionDtype, take, register_extension_dtype)

from .base import NumPyBackedExtensionArrayMixin


@register_extension_dtype
class MACType(ExtensionDtype):
"""Dtype for MAC Address Data."""
name = 'mac'
Expand All @@ -24,6 +26,10 @@ def construct_from_string(cls, string):
raise TypeError("Cannot construct a '{}' from "
"'{}'".format(cls, string))

@classmethod
def construct_array_type(cls):
return MACArray


class MACArray(NumPyBackedExtensionArrayMixin):
"""Array for MAC Address data.
Expand All @@ -38,9 +44,13 @@ class MACArray(NumPyBackedExtensionArrayMixin):
ndim = 1
can_hold_na = True

def __init__(self, values, copy=True):
def __init__(self, values, copy=True, dtype=None):
# TODO: parse hex / strings
self.data = np.array(values, dtype='uint64', copy=copy)
if isinstance(dtype, str):
MACType.construct_array_type(dtype)
elif dtype:
assert isinstance(dtype, MACType)

@classmethod
def _from_ndarray(cls, data, copy=False):
Expand Down Expand Up @@ -119,6 +129,13 @@ def take_nd(self, indexer, allow_fill=True, fill_value=None):
def copy(self, deep=False):
return type(self)(self.data.copy())

def astype(self, dtype, copy=True):
if isinstance(dtype, type(self.dtype)):
if copy:
self = self.copy()
return self
return super().astype(dtype, copy)


def _format(mac):
# https://stackoverflow.com/a/36883363/1889400
Expand Down
28 changes: 27 additions & 1 deletion tests/ip/test_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ def data_for_grouping():
])


@pytest.fixture
def data_repeated(data):
def gen(count):
for _ in range(count):
yield data
return gen


@pytest.fixture
def na_cmp():
"""Binary operator for comparing NA values.
Expand Down Expand Up @@ -78,7 +86,13 @@ class TestConstructors(base.BaseConstructorsTests):


class TestReshaping(base.BaseReshapingTests):
pass
@pytest.mark.skip("We consider 0 to be NA.")
def test_stack(self):
pass

@pytest.mark.skip("We consider 0 to be NA.")
def test_unstack(self):
pass


class TestGetitem(base.BaseGetitemTests):
Expand All @@ -94,3 +108,15 @@ class TestMethods(base.BaseMethodsTests):
@pytest.mark.xfail(reason='upstream')
def test_value_counts(data, dropna):
pass

@pytest.mark.skip(reason='0 for NA')
def test_combine_le(self, data_repeated):
super().test_combine_le(data_repeated)

@pytest.mark.skip(reason='No __add__')
def test_combine_add(self, data_repeated):
super().test_combine_add(data_repeated)

@pytest.mark.xfail(reason="buggy comparison of v4 and v6")
def test_searchsorted(self, data_for_sorting, as_series):
return super().test_searchsorted(data_for_sorting, as_series)
24 changes: 24 additions & 0 deletions tests/mac/test_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ def data_for_grouping():
])


@pytest.fixture
def data_repeated(data):
def gen(count):
for _ in range(count):
yield data
return gen


@pytest.fixture
def na_cmp():
"""Binary operator for comparing NA values.
Expand Down Expand Up @@ -83,6 +91,14 @@ class TestReshaping(base.BaseReshapingTests):
def test_concat_mixed_dtypes(self):
pass

@pytest.mark.skip(reason="0 for null")
def test_stack(self):
pass

@pytest.mark.skip(reason="0 for null")
def test_unstack(self):
pass


class TestGetitem(base.BaseGetitemTests):
pass
Expand All @@ -96,3 +112,11 @@ class TestMethods(base.BaseMethodsTests):
@pytest.mark.xfail(reason='upstream')
def test_value_counts(data, dropna):
pass

@pytest.mark.skip(reason="buggy comparison")
def test_combine_le(self, data_repeated):
super().test_combine_le(data_repeated)

@pytest.mark.skip(reason="TODO")
def test_hash_pandas_object_works(self):
pass

0 comments on commit 0db23fc

Please sign in to comment.