@@ -29,6 +29,7 @@ class IPv4v6Base(object):
2929IPv4v6Base .register (ipaddress .IPv6Address )
3030
3131
32+ @pd .api .extensions .register_extension_dtype
3233class IPType (ExtensionDtype ):
3334 name = 'ip'
3435 type = IPv4v6Base
@@ -44,6 +45,11 @@ def construct_from_string(cls, string):
4445 raise TypeError ("Cannot construct a '{}' from "
4546 "'{}'" .format (cls , string ))
4647
48+ @classmethod
49+ def construct_array_type (cls ):
50+ return IPArray
51+
52+
4753# -----------------------------------------------------------------------------
4854# Extension Container
4955# -----------------------------------------------------------------------------
@@ -69,15 +75,17 @@ class IPArray(NumPyBackedExtensionArrayMixin):
6975 ndim = 1
7076 can_hold_na = True
7177
72- def __init__ (self , values ):
78+ def __init__ (self , values , dtype = None , copy = False ):
7379 from .parser import _to_ip_array
7480
7581 values = _to_ip_array (values ) # TODO: avoid potential copy
82+ # TODO: dtype?
83+ if copy :
84+ values = values .copy ()
7685 self .data = values
7786
7887 @classmethod
7988 def from_pyints (cls , values ):
80- # type: (T.Sequence[int]) -> 'IPArray'
8189 """Construct an IPArray from a sequence of Python integers.
8290
8391 This can be useful for representing IPv6 addresses, which may
@@ -97,7 +105,7 @@ def from_pyints(cls, values):
97105
98106 @classmethod
99107 def from_bytes (cls , bytestring ):
100- """Create an IPArray from a bytestring.
108+ r """Create an IPArray from a bytestring.
101109
102110 Parameters
103111 ----------
@@ -295,7 +303,7 @@ def to_pyints(self):
295303 return [combine (* map (int , x )) for x in self .data ]
296304
297305 def to_bytes (self ):
298- """Serialize the IPArray as a Python bytestring.
306+ r """Serialize the IPArray as a Python bytestring.
299307
300308 This and :meth:IPArray.from_bytes is the fastest way to roundtrip
301309 serialize and de-serialize an IPArray.
@@ -312,6 +320,13 @@ def to_bytes(self):
312320 """
313321 return self .data .tobytes ()
314322
323+ def astype (self , dtype , copy = True ):
324+ if isinstance (dtype , IPType ):
325+ if copy :
326+ self = self .copy ()
327+ return self
328+ return super (IPArray , self ).astype (dtype )
329+
315330 # ------------------------------------------------------------------------
316331 # Ops
317332 # ------------------------------------------------------------------------
@@ -449,7 +464,6 @@ def isin(self, other):
449464 return mask
450465
451466 def _isin_network (self , other ):
452- # type: (Union[ipaddress.IPv4Network,ipaddress.IPv6Network]) -> ndarray
453467 """Check whether an array of addresses is contained in a network."""
454468 # A network is bounded below by 'network_address' and
455469 # above by 'broadcast_address'.
@@ -649,6 +663,7 @@ def mask(self, mask):
649663# Accessor
650664# -----------------------------------------------------------------------------
651665
666+
652667@pd .api .extensions .register_series_accessor ("ip" )
653668class IPAccessor :
654669
0 commit comments