2. API Reference

2.1. Class NocaseDict

class nocasedict.NocaseDict(*args, **kwargs)[source]

A case-insensitive and case-preserving ordered dictionary.

The dictionary is case-insensitive: When items of the dictionary are looked up by key or keys are compared by the dictionary, that is done case-insensitively. The case-insensitivity is defined by performing the lookup or comparison on the result of the lower() method on the key value. Therefore, objects used as keys must support the lower() method. If a key object does not do that, AttributeError is raised.

The dictionary is case-preserving: When keys are returned, they have the lexical case that was originally specified when adding or updating the item.

The dictionary is ordered: The dictionary maintains the order in which items were added for all Python versions supported by this package. This is consistent with the ordering behavior of the built-in dict class starting with Python 3.7.

The NocaseDict class is derived from the abstract base class collections.abc.MutableMapping and not from the dict class, because of the unique implementation of NocaseDict, which maintains a single dictionary with the lower-cased keys, and values that are tuples (original key, value). This supports key based lookup with a single dictionary lookup. Users that need to test whether an object is a dictionary should do that with isinstance(obj, Mapping) or isinstance(obj, MutableMapping).

The provided key and value objects will be referenced from the dictionary without being copied, consistent with the built-in dict class.

Except for the case-insensitivity of its keys, the NocaseDict class behaves like the built-in dict class starting with Python 3.7 (where it is guaranteed to be ordered), so its documentation applies completely.

The NocaseDict class itself provides no added functionality compared to the built-in dict class. This package provides mixin classes for adding functionality:

  • HashableMixin mixin class: Adds case-insensitive hashability.
  • KeyableByMixin() mixin generator function: Adds ability to get the key from an attribute of the value object.

Example of usage:

from nocasedict import NocaseDict

dict1 = NocaseDict({'Alpha': 1, 'Beta': 2})

print(dict1['ALPHA'])  # Lookup by key is case-insensitive
# 1

print(dict1)  # Access of keys is case-preserving
# NocaseDict({'Alpha': 1, 'Beta': 2})
Parameters:
  • *args

    An optional single positional argument representing key-value pairs to initialize the dictionary from, in iteration order of the specified object. The argument must be one of:

    • a dictionary object, or more specifically an object that has a method keys() providing iteration through the keys and that supports subscription by key (e.g. ncd[key]) for accessing the values.
    • an iterable. If a key occurs more than once (case-insensitively), the last item for that key becomes the corresponding item in the dictionary. Each item in the iterable must be one of:
      • an iterable with exactly two items. The first item is used as the key, and the second item as the value.
      • an object with a key attribute, if the KeyableByMixin() mixin generator function is used. The value of the key attribute is used as the key, and the object itself as the value.
  • **kwargs

    Optional keyword arguments representing key-value pairs to add to the dictionary after being initialized from the positional argument.

    If a key being added is already present (case-insensitively) from the positional argument, key and value will be updated from the keyword argument.

    Before Python 3.7, the order of keyword arguments as specified in the call to the method was not guaranteed to be preserved for the method implementation, so passing more than one keyword argument may have resulted in arbitrary order of items in the dictionary.

To summarize, only the following types of init arguments are guaranteed to preserve the order of provided items after having been added to the new dictionary, across all Python versions supported by this package:

  • Passing an iterable as a single positional argument, and passing at most one keyword argument.
  • Passing an ordered dictionary/mapping as a single positional argument, and passing at most one keyword argument.

A UserWarning will be issued if the order of provided items in the arguments is not guaranteed to be preserved.

Examples for initializing:

from nocasedict import NocaseDict

dict1 = NocaseDict({'Alpha': 1, 'Beta': 2})
dict2 = NocaseDict(dict1)
dict3 = NocaseDict([('Alpha', 1), ('Beta', 2)])
dict4 = NocaseDict((('Alpha', 1), ('Beta', 2)))
dict5 = NocaseDict(Alpha=1, Beta=2)
dict6 = NocaseDict(dict1, BETA=3)
Raises:
  • AttributeError – Key does not have a lower() method.
  • TypeError – Expected at most 1 positional argument, got {n}.
  • ValueError – Cannot unpack positional argument item #{i}.

Methods

clear Remove all items from the dictionary.
copy Return a copy of the dictionary.
fromkeys Return a new NocaseDict object with keys from the specified iterable of keys, and values all set to the specified value.
get Return the value of the item with an existing key (looked up case-insensitively), or if the key does not exist, a default value.
has_key Python 2 only: Return a boolean indicating whether the dictionary contains an item with the key (looked up case-insensitively).
items Return a view on (in Python 3) or a list of (in Python 2) the dictionary items in dictionary iteration order, where each item is a tuple of its key (in the original lexical case) and its value.
iteritems Python 2 only: Return an iterator through the dictionary items in dictionary iteration order, where each item is a tuple of its key (in the original lexical case) and its value.
iterkeys Python 2 only: Return an iterator through the dictionary keys (in the original lexical case) in dictionary iteration order.
itervalues Python 2 only: Return an iterator through the dictionary values in dictionary iteration order.
keys Return a view on (in Python 3) or a list of (in Python 2) the dictionary keys (in the original lexical case) in dictionary iteration order.
keys_nocase Return a view on (in Python 3) or a list of (in Python 2) the lower-cased dictionary keys in dictionary iteration order.
pop Remove the item with the specified key if it exists (looked up case-insensitively), and return its value.
popitem Remove the last dictionary item (in iteration order) and return it as a tuple (key, value).
setdefault If an item with the key (looked up case-insensitively) does not exist, add an item with that key and the specified default value, and return the value of the item with the key.
update Update the dictionary from key/value pairs.
values Return a view on (in Python 3) or a list of (in Python 2) the dictionary values in dictionary iteration order.
viewitems Python 2 only: Return a view on the dictionary items in dictionary order, where each item is a tuple of its key (in the original lexical case) and its value.
viewkeys Python 2 only: Return a view on the dictionary keys (in the original lexical case) in dictionary iteration order.
viewvalues Python 2 only: Return a view on the dictionary values in dictionary order.

Attributes

Details

__contains__(key)[source]

Return a boolean indicating whether the dictionary contains an item with the key (looked up case-insensitively).

Invoked when using: key in ncd

Raises:AttributeError – Key does not have a lower() method.
__delitem__(key)[source]

Delete the item with an existing key (looked up case-insensitively).

Invoked when using: del ncd[key]

Raises:
  • AttributeError – Key does not have a lower() method.
  • KeyError – Key does not exist (case-insensitively).
__eq__(other)[source]

Return a boolean indicating whether the dictionary and the other dictionary are equal, by matching items (case-insensitively) based on their keys, and then comparing the values of matching items for equality.

The other dictionary may be a NocaseDict object or any other mapping. In all cases, the matching of keys takes place case-insensitively.

Invoked when using e.g.: ncd == other

Raises:AttributeError – Key does not have a lower() method.
__getitem__(key)[source]

Return the value of the item with an existing key (looked up case-insensitively).

Invoked when using e.g.: value = ncd[key]

Raises:
  • AttributeError – Key does not have a lower() method.
  • KeyError – Key does not exist (case-insensitively).
__iter__()[source]

Return an iterator through the dictionary keys (in the original lexical case) in dictionary iteration order.

Invoked when using: for key in ncd

__len__()[source]

Return the number of items in the dictionary.

Invoked when using: len(ncd)

__ne__(other)[source]

Return a boolean indicating whether the dictionary and the other dictionary are not equal, by negating the equality test.

The other dictionary may be a NocaseDict object or any other mapping. In all cases, the matching of keys takes place case-insensitively.

Invoked when using e.g.: ncd != other

Raises:AttributeError – Key does not have a lower() method.
__repr__()[source]

Return a string representation of the dictionary that is suitable for debugging.

The order of items is in dictionary iteration order, and the keys are in the original lexical case.

Invoked when using e.g.: repr(ncd)

__reversed__()[source]

Return an iterator for the reversed iteration order of the dictionary.

Invoked when using: reversed[ncd]

__setitem__(key, value)[source]

Update the value of the item with an existing key (looked up case-insensitively), or if an item with the key does not exist, add an item with the specified key and value.

Invoked when using e.g.: ncd[key] = value

Raises:AttributeError – Key does not have a lower() method.
clear()[source]

Remove all items from the dictionary.

copy()[source]

Return a copy of the dictionary.

This is a middle-deep copy; the copy is independent of the original in all attributes that have mutable types except for:

  • The values in the dictionary

Note that the Python functions copy.copy() and copy.deepcopy() can be used to create completely shallow or completely deep copies of objects of this class.

classmethod fromkeys(iterable, value=None)[source]

Return a new NocaseDict object with keys from the specified iterable of keys, and values all set to the specified value.

Raises:AttributeError – Key does not have a lower() method.
get(key, default=None)[source]

Return the value of the item with an existing key (looked up case-insensitively), or if the key does not exist, a default value.

Raises:AttributeError – Key does not have a lower() method.
has_key(key)[source]

Python 2 only: Return a boolean indicating whether the dictionary contains an item with the key (looked up case-insensitively).

Raises:
items()[source]

Return a view on (in Python 3) or a list of (in Python 2) the dictionary items in dictionary iteration order, where each item is a tuple of its key (in the original lexical case) and its value.

See Dictionary View Objects on Python 3 for details about view objects.

iteritems()[source]

Python 2 only: Return an iterator through the dictionary items in dictionary iteration order, where each item is a tuple of its key (in the original lexical case) and its value.

Raises:AttributeError – The method does not exist on Python 3.
iterkeys()[source]

Python 2 only: Return an iterator through the dictionary keys (in the original lexical case) in dictionary iteration order.

Raises:AttributeError – The method does not exist on Python 3.
itervalues()[source]

Python 2 only: Return an iterator through the dictionary values in dictionary iteration order.

Raises:AttributeError – The method does not exist on Python 3.
keys()[source]

Return a view on (in Python 3) or a list of (in Python 2) the dictionary keys (in the original lexical case) in dictionary iteration order.

See Dictionary View Objects on Python 3 for details about view objects.

keys_nocase()[source]

Return a view on (in Python 3) or a list of (in Python 2) the lower-cased dictionary keys in dictionary iteration order.

See Dictionary View Objects on Python 3 for details about view objects.

pop(key, default=<object object>)[source]

Remove the item with the specified key if it exists (looked up case-insensitively), and return its value.

If an item with the key does not exist, the default value is returned if specified, otherwise KeyError is raised.

Raises:KeyError – Key does not exist (case-insensitively) and no default was specified.
popitem()[source]

Remove the last dictionary item (in iteration order) and return it as a tuple (key, value).

The last item in iteration order is the last item that was added to the dictionary.

Raises:KeyError – Dictionary is empty.
setdefault(key, default=None)[source]

If an item with the key (looked up case-insensitively) does not exist, add an item with that key and the specified default value, and return the value of the item with the key.

Raises:AttributeError – Key does not have a lower() method.
update(*args, **kwargs)[source]

Update the dictionary from key/value pairs.

If a key is already present in the dictionary (looked up case-insensitively), its key and value is updated (without affecting its position in the dictionary iteration order). Otherwise, an item with the key and value is added to the dictionary.

The provided key and value objects will be referenced from the dictionary without being copied, consistent with the built-in dict class.

Parameters:
  • *args

    An optional single positional argument representing key-value pairs to update the dictionary from, in iteration order of the specified object. The argument must be one of:

    • a dictionary object, or more specifically an object that has a method keys() providing iteration through the keys and that supports subscription by key for accessing the values.
    • an iterable. If a key occurs more than once (case-insensitively), the last item for that key becomes the corresponding item in the dictionary. Each item in the iterable must be one of:
      • an iterable with exactly two items. The first item is used as the key, and the second item as the value.
      • an object with a key attribute, if the KeyableByMixin() mixin generator function is used. The value of the key attribute is used as the key, and the object itself as the value.
  • **kwargs

    Optional keyword arguments representing key-value pairs to update the dictionary from, after having processed the positional argument.

    Before Python 3.7, the order of keyword arguments as specified in the call to the method was not guaranteed to be preserved for the method implementation, so passing more than one keyword argument may have resulted in arbitrary order of items in the dictionary.

Raises:
  • AttributeError – Key does not have a lower() method.
  • TypeError – Expected at most 1 positional argument, got {n}.
  • ValueError – Cannot unpack positional argument item #{i}.
values()[source]

Return a view on (in Python 3) or a list of (in Python 2) the dictionary values in dictionary iteration order.

See Dictionary View Objects on Python 3 for details about view objects.

viewitems()[source]

Python 2 only: Return a view on the dictionary items in dictionary order, where each item is a tuple of its key (in the original lexical case) and its value.

See Dictionary View Objects on Python 2 for details about view objects.

Raises:AttributeError – The method does not exist on Python 3.
viewkeys()[source]

Python 2 only: Return a view on the dictionary keys (in the original lexical case) in dictionary iteration order.

See Dictionary View Objects on Python 2 for details about view objects.

Raises:AttributeError – The method does not exist on Python 3.
viewvalues()[source]

Python 2 only: Return a view on the dictionary values in dictionary order.

See Dictionary View Objects on Python 2 for details about view objects.

Raises:AttributeError – The method does not exist on Python 3.

2.2. Mixin class HashableMixin

class nocasedict.HashableMixin[source]

A mixin class that adds case-insensitive hashability to nocasedict.NocaseDict.

The derived class inheriting from HashableMixin must (directly or indirectly) inherit from NocaseDict.

Hashability allows objects of the derived class to be used as keys of dict and members of set, because these data structures use the hash values internally.

The hash value calculated by this mixin class uses the hash values of the keys and values of the dictionary in such a way that the hash value of the key is case-insensitive (i.e. it does not change for different lexical cases of a key), and the hash value of the dictionary is order-insensitive (i.e. it does not change for a different order of items).

Since NocaseDict objects are mutable, reliable use of the hash value requires that no items in the dictionary are added, removed or updated, while the dictionary object is used as a key (in another dictionary) or as a set member.

See hashable for more details.

Example:

from nocasedict import NocaseDict, HashableMixin

class MyDict(HashableMixin, NocaseDict):
    pass

mykey1 = MyDict(a=1, b=2)
mykey2 = MyDict(B=2, A=1)  # case- and order-insensitively equal

dict1 = {mykey1: 'foo'}  # Add item using first key

print(dict1[mykey2])  # Access item using second key
# 'foo'

Methods

Attributes

Details

__hash__()[source]

Return a case-insensitive and order-insensitive hash value for the dictionary.

2.3. Mixin generator function KeyableByMixin()

nocasedict.KeyableByMixin(key_attr)[source]

A generator function returning a mixin class that adds the ability to the nocasedict.NocaseDict class to initialize or update the dictionary from an iterable of objects, whereby a particular attribute of each object is used as the key.

This simplifies the initialization of dictionaries because simple lists or tuples of such objects can be provided.

The derived class inheriting from the returned mixin class must (directly or indirectly) inherit from NocaseDict.

Example:

from nocasedict import NocaseDict, KeyableByMixin

class MyDict(KeyableByMixin('name'), NocaseDict):
    pass

class Obj(object):
    def __init__(self, name, thing):
        self.name = name  # Will be used as the key
        self.thing = thing

md = MyDict([Obj('A', 1), Obj('B', 2)])

print(md)
# MyDict({'A': <__main__.Obj object at 0x10bc3d820>,
#         'B': <__main__.Obj object at 0x10bc89af0>})