Skip to content

Commit 7ab3d87

Browse files
ENH: Apply masks (#36)
1 parent e342e1c commit 7ab3d87

File tree

4 files changed

+60
-1
lines changed

4 files changed

+60
-1
lines changed

cyberpandas/ip_array.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@ def _from_ndarray(cls, data, copy=False):
148148
new.data = data
149149
return new
150150

151+
@property
152+
def _as_u8(self):
153+
"""A 2-D view on our underlying data, for bit-level manipulation."""
154+
return self.data.view("<u8").reshape(-1, 1)
155+
151156
# -------------------------------------------------------------------------
152157
# Properties
153158
# -------------------------------------------------------------------------
@@ -607,6 +612,38 @@ def hostmask(self, v4_prefixlen=32, v6_prefixlen=128):
607612
"""
608613
return self._apply_mask('hostmask', v4_prefixlen, v6_prefixlen)
609614

615+
def mask(self, mask):
616+
"""Apply a host or subnet mask.
617+
618+
Parameters
619+
----------
620+
mask : IPArray
621+
The host or subnet mask to be applied
622+
623+
Returns
624+
-------
625+
masked : IPArray
626+
627+
See Also
628+
--------
629+
netmask
630+
hostmask
631+
632+
Examples
633+
--------
634+
>>> arr = IPArray(['216.003.128.12', '192.168.100.1'])
635+
>>> mask = arr.netmask(v4_prefixlen=24)
636+
>>> mask
637+
IPArray(['255.255.255.0', '255.255.255.0'])
638+
>>> arr.mask(mask)
639+
IPArray(['216.3.128.0', '192.168.100.0'])
640+
"""
641+
mask = type(self)(mask)
642+
a = self._as_u8
643+
b = mask._as_u8
644+
masked = np.bitwise_and(a, b).ravel().view(self.dtype._record_type)
645+
return type(self)(masked)
646+
610647

611648
# -----------------------------------------------------------------------------
612649
# Accessor
@@ -653,6 +690,10 @@ def hostmask(self, v4_prefixlen=32, v6_prefixlen=128):
653690
return delegated_method(self._data.hostmask, self._index,
654691
self._name, v4_prefixlen, v6_prefixlen)
655692

693+
def mask(self, other):
694+
return delegated_method(self._data.mask, self._index, self._name,
695+
other)
696+
656697

657698
def is_ipaddress_type(obj):
658699
t = getattr(obj, 'dtype', obj)

docs/source/api.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ an IPArray, calling the Series method will dispatch to these methods.
4343
.. automethod:: IPArray.unique
4444
.. automethod:: IPArray.isin
4545
.. automethod:: IPArray.isna
46-
.. autoattribute:: IPArray.netmask
4746

4847
IP Address Attributes
4948
"""""""""""""""""""""
@@ -62,6 +61,7 @@ IP addresss-specific attributes.
6261
.. autoattribute:: IPArray.is_link_local
6362
.. automethod:: IPArray.netmask
6463
.. automethod:: IPArray.hostmask
64+
.. automethod:: IPArray.mask
6565

6666

6767

docs/source/changelog.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
Changelog
33
#########
44

5+
*************
6+
Version 1.1.1
7+
*************
8+
9+
- Added :meth:`IPArray.mask` to apply net and host masks to an array of IP addresses (:issue:`36`).
10+
511
*************
612
Version 1.1.0
713
*************

tests/ip/test_ip.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,3 +382,15 @@ def test_hostmask_basic():
382382
v6_prefixlen=32)
383383
assert result.name == 'foo'
384384
assert result.values.equals(expected)
385+
386+
387+
def test_apply_mask():
388+
arr = ip.IPArray([u'216.3.128.0', u'192.168.100.0', u'1::1:12'])
389+
mask = arr.netmask(v4_prefixlen=24, v6_prefixlen=112)
390+
result = arr.mask(mask)
391+
expected = ip.IPArray([u'216.3.128.0', u'192.168.100.0', u'1::1:0'])
392+
assert result.equals(expected)
393+
394+
result = pd.Series(arr, name='test').ip.mask(mask)
395+
expected = pd.Series(expected, name='test')
396+
tm.assert_series_equal(result, expected)

0 commit comments

Comments
 (0)