Skip to content

Commit

Permalink
safe deletion for ordered maps
Browse files Browse the repository at this point in the history
  • Loading branch information
vreuter committed May 14, 2019
1 parent fc61270 commit b21067b
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 2 deletions.
4 changes: 2 additions & 2 deletions attmap/attmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
else:
from collections.abc import Mapping

from .helpers import copy, get_logger
from .helpers import copy, get_logger, safedel_message
from ._att_map_like import AttMapLike


Expand All @@ -26,7 +26,7 @@ def __delitem__(self, key):
try:
del self.__dict__[key]
except KeyError:
_LOGGER.debug("No key {} to delete".format(key))
_LOGGER.debug(safedel_message(key))

def __getitem__(self, item):
return self.__dict__[item]
Expand Down
10 changes: 10 additions & 0 deletions attmap/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,13 @@ def is_custom_map(obj):
:return bool: whether the object is a Mapping other than dict
"""
return isinstance(obj, Mapping) and type(obj) is not dict


def safedel_message(key):
"""
Create safe deletion log message.
:param hashable key: unmapped key for which deletion/removal was tried
:return str: message to log unmapped key deletion attempt.
"""
return "No key {} to delete".format(key)
11 changes: 11 additions & 0 deletions attmap/ordattmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

from collections import OrderedDict
from .attmap import AttMap
from .helpers import get_logger, safedel_message

__author__ = "Vince Reuter"
__email__ = "vreuter@virginia.edu"

__all__ = ["OrdAttMap"]


_LOGGER = get_logger(__name__)


class OrdAttMap(OrderedDict, AttMap):
""" Insertion-ordered mapping with dot notation access """

Expand All @@ -18,6 +22,13 @@ def __init__(self, entries=None):
def __setitem__(self, key, value):
super(OrdAttMap, self).__setitem__(key, self._finalize_value(value))

def __delitem__(self, key):
""" Make unmapped key deletion unexceptional. """
try:
super(OrdAttMap, self).__delitem__(key)
except KeyError:
_LOGGER.debug(safedel_message(key))

def __eq__(self, other):
return AttMap.__eq__(self, other) and list(self.keys()) == list(other.keys())

Expand Down
12 changes: 12 additions & 0 deletions tests/test_basic_ops_dynamic.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ def test_add_pandas_series(series, attmap_type):
assert raw_data == {k: m[k] for k in raw_data}


@pytest.mark.parametrize("seed_data", [{}, {"a": 1}, {"b": 2, "c": 3}])
@pytest.mark.parametrize("delkey", ["d", "e"])
def test_del_unmapped_key(attmap_type, seed_data, delkey):
""" Attempt to remove unmapped key should not fail. """
m = get_att_map(attmap_type, entries=seed_data)
assert delkey not in m
try:
del m[delkey]
except KeyError as e:
pytest.fail("Attempt to remove unmapped key hit exception: {}".format(e))


@pytest.mark.parametrize("f_extra_checks_pair",
[(repr, []), (str, [lambda s, dt: s.startswith(dt.__name__)])])
def test_text(attmap_type, entries, f_extra_checks_pair):
Expand Down

0 comments on commit b21067b

Please sign in to comment.