Skip to content

ENH: Apply masks #36

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
Jun 12, 2018
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
41 changes: 41 additions & 0 deletions cyberpandas/ip_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ def _from_ndarray(cls, data, copy=False):
new.data = data
return new

@property
def _as_u8(self):
"""A 2-D view on our underlying data, for bit-level manipulation."""
return self.data.view("<u8").reshape(-1, 1)

# -------------------------------------------------------------------------
# Properties
# -------------------------------------------------------------------------
Expand Down Expand Up @@ -607,6 +612,38 @@ def hostmask(self, v4_prefixlen=32, v6_prefixlen=128):
"""
return self._apply_mask('hostmask', v4_prefixlen, v6_prefixlen)

def mask(self, mask):
"""Apply a host or subnet mask.

Parameters
----------
mask : IPArray
The host or subnet mask to be applied

Returns
-------
masked : IPArray

See Also
--------
netmask
hostmask

Examples
--------
>>> arr = IPArray(['216.003.128.12', '192.168.100.1'])
>>> mask = arr.netmask(v4_prefixlen=24)
>>> mask
IPArray(['255.255.255.0', '255.255.255.0'])
>>> arr.mask(mask)
IPArray(['216.3.128.0', '192.168.100.0'])
"""
mask = type(self)(mask)
a = self._as_u8
b = mask._as_u8
masked = np.bitwise_and(a, b).ravel().view(self.dtype._record_type)
return type(self)(masked)


# -----------------------------------------------------------------------------
# Accessor
Expand Down Expand Up @@ -653,6 +690,10 @@ def hostmask(self, v4_prefixlen=32, v6_prefixlen=128):
return delegated_method(self._data.hostmask, self._index,
self._name, v4_prefixlen, v6_prefixlen)

def mask(self, other):
return delegated_method(self._data.mask, self._index, self._name,
other)


def is_ipaddress_type(obj):
t = getattr(obj, 'dtype', obj)
Expand Down
2 changes: 1 addition & 1 deletion docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ an IPArray, calling the Series method will dispatch to these methods.
.. automethod:: IPArray.unique
.. automethod:: IPArray.isin
.. automethod:: IPArray.isna
.. autoattribute:: IPArray.netmask

IP Address Attributes
"""""""""""""""""""""
Expand All @@ -62,6 +61,7 @@ IP addresss-specific attributes.
.. autoattribute:: IPArray.is_link_local
.. automethod:: IPArray.netmask
.. automethod:: IPArray.hostmask
.. automethod:: IPArray.mask



Expand Down
6 changes: 6 additions & 0 deletions docs/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
Changelog
#########

*************
Version 1.1.1
*************

- Added :meth:`IPArray.mask` to apply net and host masks to an array of IP addresses (:issue:`36`).

*************
Version 1.1.0
*************
Expand Down
12 changes: 12 additions & 0 deletions tests/ip/test_ip.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,3 +382,15 @@ def test_hostmask_basic():
v6_prefixlen=32)
assert result.name == 'foo'
assert result.values.equals(expected)


def test_apply_mask():
arr = ip.IPArray([u'216.3.128.0', u'192.168.100.0', u'1::1:12'])
mask = arr.netmask(v4_prefixlen=24, v6_prefixlen=112)
result = arr.mask(mask)
expected = ip.IPArray([u'216.3.128.0', u'192.168.100.0', u'1::1:0'])
assert result.equals(expected)

result = pd.Series(arr, name='test').ip.mask(mask)
expected = pd.Series(expected, name='test')
tm.assert_series_equal(result, expected)