immutable-views - Immutable views on other collection objects¶
Usage¶
Supported environments¶
The immutable-views package is supported in these environments:
Operating Systems: Linux, macOS / OS-X, native Windows, Linux subsystem in Windows, UNIX-like environments in Windows.
Python: 2.7, 3.4, and higher
Installation¶
The following command installs the immutable-views package and its prerequisite packages into the active Python environment:
$ pip install immutable-views
Overview¶
The immutable-views package provides collection classes that are immutable views on other (mutable) collection objects:
DictView
- immutable view on another mapping (dictionary) object.ListView
- immutable view on another sequence (list) object.SetView
- immutable view on another set object.
An important behavior of views is that they are “live”: Since the view classes delegate to the underlying collection, any modification of the underlying collection object will be visible in the view object.
Creating an immutable view on a collection does not copy the collection and is therefore much faster than creating an immutable copy of the collection.
The memory overhead of using immutable views is very small: An object of any of the view classes in the immutable-views package occupies 40 Bytes (measured in CPython 3.9 on macOS), and because the view object only has a reference to its underlying collection object, that size is independent of the number of items in the collection.
The compute overhead is also very small, it is basically an additional function call to the corresponding function of the underlying collection.
Immutable views are useful if a method or function maintains data in form of a mutable collection and is intended to return that data but users should not be able to modify the data. The underlying collection can be updated by the method or function as needed, but the caller only gets an immutable view on it.
The view classes in the immutable-views package implement the complete behavior of the corresponding Python collection types except for any operations that would modify the underlying collection object.
The view classes delegate all operations to the underlying collection object they are a view of. Therefore, the underlying collection can be any kind of collection implementation (i.e. not just the standard Python collection classes).
Note that the immutability of the view objects only applies to the view object itself and to its underlying collection, but not to the items in the underlying collection. So if the underlying collection contains mutable objects, they will still be mutable when accessed through the view objects.
The standard Python class
types.MappingProxyType
serves the same purpose as the
DictView
class but it does not support pickling or hashing and was added only in
Python 3.3.
The dictproxy
class from the
dictproxyhack
package on Pypi supports Python 2 and Python 3 and uses Python classes where
available (e.g. MappingProxyType
on Python 3.3 and later, and the internal
mappingproxy
class used for __dict__
on CPython) but also does not
support pickling or hashing.
The lack of support for standard dictionary behaviors prevents their use in
cases where the view class is used as a read-only replacement for the standard
dictionary.
Note that there are several packages on Pypi that provide immutable collections, but they all are collections on their own, and not views on other collections. Here is a notable subset of such packages:
Examples¶
Example with dictionaries:
$ python
>>> from immutable_views import DictView
>>> dict1 = {'a': 1, 'b': 2}
>>> dictview1 = DictView(dict1)
# Read-only access to the underlying collection through the view is supported:
>>> dictview1['a']
1
# Modifying the underlying collection through the view is rejected:
>>> dictview1['a'] = 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'DictView' object does not support item assignment
# Modifications of the underlying collection are visible in the view:
>>> dict1['a'] = 2
>>> dictview1['a']
2
Example with lists:
$ python
>>> from immutable_views import ListView
>>> list1 = ['a', 'b']
>>> listview1 = ListView(list1)
# Read-only access to the underlying collection through the view is supported:
>>> listview1[0]
'a'
# Modifying the underlying collection through the view is rejected:
>>> listview1[0] = 'c'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'ListView' object does not support item assignment
# Modifications of the underlying collection are visible in the view:
>>> list1[0] = 'c'
>>> listview1[0]
'c'
Example with sets:
$ python
>>> from immutable_views import SetView
>>> set1 = {'a', 'b'}
>>> setview1 = SetView(set1)
# Read-only access to the underlying collection through the view is supported:
>>> 'a' in setview1
True
# Modifying the underlying collection through the view is rejected:
>>> setview1.add('c')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'SetView' object has no attribute 'add'
# Modifications of the underlying collection are visible in the view:
>>> set1.add('c')
>>> 'c' in setview1
True
Hashing¶
A major motivation for providing immutable collections is the support for hashing.
The immutable view classes provided by the immutable-views package however are only views on the underlying collection. The hashability of the view depends on the hashability of the underlying collection: If the underlying collection is immutable, it is hashable and then the view is also hashable.
The immutable view classes therefore implement a __hash__()
method that
delegates to the hash function of the underlying collection. If a collection
object is hashable, the view object using it will be hashable as well.
Otherwise, TypeError
is raised when the hash()
function is
called on the view object.
Some examples:
View class |
Underlying collection class |
View hashability |
---|---|---|
|
No |
|
|
No |
|
|
Yes |
|
|
No |
|
|
Yes |
API Reference¶
This section describes the Python API of the immutable-views package. The API is kept stable using the compatibility rules defined for semantic versioning. An exception to this rule are fixes for security issues.
Any functions not described in this section are considered internal and may change incompatibly without warning.
DictView class¶
- class immutable_views.DictView(a_dict)[source]¶
An immutable dictionary view.
Derived from
Mapping
.This class provides an immutable view on a possibly mutable mapping object. The mapping object must be an instance of
Mapping
, e.g.dict
, or a user-defined class.This can be used for example when a class maintains a dictionary that should be made available to users of the class without allowing them to modify the dictionary.
In the description of this class, the term ‘view’ always refers to the
DictView
object, and the term ‘dictionary’ or ‘underlying dictionary’ refers to the mapping object the view is based on.The
DictView
class supports the complete behavior of Python classdict
, except for any methods that would modify the dictionary. Note that the non-modifying methods of classdict
are a superset of the methods defined for the abstract classMapping
(the methods are listed in the table at the top of the linked page).The view is “live”: Since the view class delegates all operations to the underlying dictionary, any modification of the underlying dictionary object will be visible in the view object.
Note that only the view object is immutable, not its items. So if the values in the underlying dictionary are mutable objects, they can be modified through the view.
Note that in Python, augmented assignment (e.g.
x += y
) is not guaranteed to modify the left hand object in place, but can result in the left hand name being bound to a new object (like inx = x + y
). For details, see object.__iadd__().For the DictView class, augmented assignment is supported and results in binding the left hand name to a new DictView object.
- Parameters
a_dict (
Mapping
) – The underlying dictionary. If this object is a DictView, its underlying dictionary is used.
Methods:
__contains__
(key)value in self
: Return a boolean indicating whether the dictionary contains an item with a key.__eq__
(other)self == other
: Return a boolean indicating whether the dictionary is equal to the other object.__ge__
(other)self >= other
: Return a boolean indicating whether the dictionary is greater than or equal to the other dictionary.__getitem__
(key)self[key]
: Return the value of the dictionary item with a key.Support for pickling.
__gt__
(other)self > other
: Return a boolean indicating whether the dictionary is greater than the other dictionary.__hash__
()hash(self)
: Return a hash value for the dictionary.__iter__
()Return an iterator through the dictionary keys in iteration order.
__le__
(other)self <= other
: Return a boolean indicating whether the dictionary is less than or equal to the other dictionary.__len__
()len(self)
: Return the number of items in the dictionary.__lt__
(other)self < other
: Return a boolean indicating whether the dictionary is less than the other dictionary.__ne__
(other)self != other
: Return a boolean indicating whether the dictionary is not equal to the other dictionary.__or__
(other)self | other
: Return a new view on the merged dictionary and other dictionary.__repr__
()repr(self)
: Return a string representation of the view suitable for debugging.reversed(self) ...
: Return an iterator through the dictionary keys in reversed iteration order.__ror__
(other)other | self
: Return a new view on the merged dictionary and other dictionary.__setstate__
(a_dict)Support for unpickling.
copy
()Return a new view on a shallow copy of the dictionary.
get
(key[, default])Return the value of the dictionary item with a key or a default value.
has_key
(key)Python 2 only: Return a boolean indicating whether the dictionary contains an item with a key.
items
()Return the dictionary items in iteration order.
Python 2 only: Return an iterator through the dictionary items in iteration order.
iterkeys
()Python 2 only: Return an iterator through the dictionary keys in iteration order.
Python 2 only: Return an iterator through the dictionary values in iteration order.
keys
()Return the dictionary keys in iteration order.
values
()Return the dictionary values in iteration order.
Python 2 only: Return a view on the dictionary items in iteration order.
viewkeys
()Python 2 only: Return a view on the dictionary keys in iteration order.
Python 2 only: Return a view on the dictionary values in iteration order.
Attributes:
The underlying dictionary.
- __contains__(key)[source]¶
value in self
: Return a boolean indicating whether the dictionary contains an item with a key.The return value indicates whether the underlying dictionary contains an item that has the specified key.
- __eq__(other)[source]¶
self == other
: Return a boolean indicating whether the dictionary is equal to the other object.Compared are the underlying dictionary of the left hand view object and the right hand object (or in case of a DictView, its underlying dictionary).
- __ge__(other)[source]¶
self >= other
: Return a boolean indicating whether the dictionary is greater than or equal to the other dictionary.Whether ordering comparison is supported and how ordering is defined depends on the underlying dictionary and the other dictionary. For example, the standard Python
dict
class does not support ordering comparisons on Python 3.
- __getitem__(key)[source]¶
self[key]
: Return the value of the dictionary item with a key.- Raises
KeyError – An item with the key does not exist.
- __gt__(other)[source]¶
self > other
: Return a boolean indicating whether the dictionary is greater than the other dictionary.Whether ordering comparison is supported and how ordering is defined depends on the underlying dictionary and the other dictionary. For example, the standard Python
dict
class does not support ordering comparisons on Python 3.
- __hash__()[source]¶
hash(self)
: Return a hash value for the dictionary.Whether hashing is supported depends on the underlying dictionary. For example, the standard Python
dict
class does not support hashing.- Raises
TypeError – The underlying dictionary does not support hashing.
- __le__(other)[source]¶
self <= other
: Return a boolean indicating whether the dictionary is less than or equal to the other dictionary.Whether ordering comparison is supported and how ordering is defined depends on the underlying dictionary and the other dictionary. For example, the standard Python
dict
class does not support ordering comparisons on Python 3.
- __len__()[source]¶
len(self)
: Return the number of items in the dictionary.The return value is the number of items in the underlying dictionary.
- __lt__(other)[source]¶
self < other
: Return a boolean indicating whether the dictionary is less than the other dictionary.Whether ordering comparison is supported and how ordering is defined depends on the underlying dictionary and the other dictionary. For example, the standard Python
dict
class does not support ordering comparisons on Python 3.
- __ne__(other)[source]¶
self != other
: Return a boolean indicating whether the dictionary is not equal to the other dictionary.Compared are the underlying dictionary of the left hand view object and the right hand object (or in case of a DictView, its underlying dictionary).
- __or__(other)[source]¶
self | other
: Return a new view on the merged dictionary and other dictionary.Added in Python 3.9.
The returned
DictView
object is a view on a new dictionary object of the type of the left hand operand that contains all the items from the underlying dictionary of the left hand operand, updated by the items from the other dictionary (or in case of a DictView, its underlying dictionary).The other object must be a
dict
orDictView
.The dictionary and the other dictionary are not changed.
- Raises
TypeError – The other object is not a dict or DictView.
- __repr__()[source]¶
repr(self)
: Return a string representation of the view suitable for debugging.The underlying dictionary is represented using its
repr()
representation.
- __reversed__()[source]¶
reversed(self) ...
: Return an iterator through the dictionary keys in reversed iteration order.Added in Python 3.8.
The returned iterator yields the keys in the underlying dictionary in reversed iteration order.
- __ror__(other)[source]¶
other | self
: Return a new view on the merged dictionary and other dictionary.Added in Python 3.9.
This method is a fallback and is called only if the left operand does not support the operation.
The returned
DictView
object is a view on a new dictionary object of the type of the right hand operand that contains all the items from the underlying dictionary of the right hand operand, updated by the items from the other dictionary (or in case of a DictView, its underlying dictionary).The other object must be a
dict
orDictView
.The dictionary and the other dictionary are not changed.
- Raises
TypeError – The other object is not a dict or DictView.
- copy()[source]¶
Return a new view on a shallow copy of the dictionary.
The returned
DictView
object is a new view object on a dictionary object of the type of the underlying dictionary.If the dictionary type is immutable, the returned dictionary object may be the underlying dictionary object. If the dictionary type is mutable, the returned dictionary is a new dictionary object that is a shallow copy of the underlying dictionary object.
- property dict¶
The underlying dictionary.
Access to the underlying dictionary is provided for purposes such as conversion to JSON or other cases where the view classes do not work. This access should not be used to modify the underlying dictionary.
- get(key, default=None)[source]¶
Return the value of the dictionary item with a key or a default value.
- has_key(key)[source]¶
Python 2 only: Return a boolean indicating whether the dictionary contains an item with a key.
- Raises
AttributeError – The method does not exist on Python 3.
- items()[source]¶
Return the dictionary items in iteration order.
Each returned item is a tuple of key and value. The items of the underlying dictionary are returned as a view in Python 3 and as a list in Python 2.
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 iteration order.
Each item is a tuple of key and value.
- Raises
AttributeError – The method does not exist on Python 3.
- iterkeys()[source]¶
Python 2 only: Return an iterator through the dictionary keys in 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 iteration order.
- Raises
AttributeError – The method does not exist on Python 3.
- keys()[source]¶
Return the dictionary keys in iteration order.
The keys of the underlying dictionary are returned as a view in Python 3 and as a list in Python 2.
See Dictionary View Objects on Python 3 for details about view objects.
- values()[source]¶
Return the dictionary values in iteration order.
The values of the underlying dictionary are returned as a view in Python 3 and as a list in Python 2.
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 iteration order.
Each returned item is a tuple of key and value. The items of the underlying dictionary are returned as a view.
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 iteration order.
The keys of the underlying dictionary are returned as a view.
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 iteration order.
The values of the underlying dictionary are returned as a view.
See Dictionary View Objects on Python 2 for details about view objects.
- Raises
AttributeError – The method does not exist on Python 3.
ListView class¶
- class immutable_views.ListView(a_list)[source]¶
An immutable list view.
Derived from
Sequence
.This class provides an immutable view on a possibly mutable sequence object. The sequence object must be an instance of
Sequence
, e.g.list
,tuple
,range
, or a user-defined class.This can be used for example when a class maintains a list that should be made available to users of the class without allowing them to modify the list.
In the description of this class, the term ‘view’ always refers to the
ListView
object, and the term ‘list’ or ‘underlying list’ refers to the sequence object the view is based on.The
ListView
class supports the complete behavior of Python classlist
, except for any methods that would modify the list. Note that the non-modifying methods of classlist
are a superset of the methods defined for the abstract classSequence
(the methods are listed in the table at the top of the linked page).The view is “live”: Since the view class delegates all operations to the underlying list, any modification of the underlying list object will be visible in the view object.
Note that only the view object is immutable, not its items. So if the values in the underlying list are mutable objects, they can be modified through the view.
Note that in Python, augmented assignment (e.g.
x += y
) is not guaranteed to modify the left hand object in place, but can result in the left hand name being bound to a new object (like inx = x + y
). For details, see object.__iadd__().For the ListView class, augmented assignment is supported and results in binding the left hand name to a new ListView object.
- Parameters
a_list (
Sequence
) – The underlying list. If this object is a ListView, its underlying list is used.
Methods:
__add__
(other)self + other
: Return a new view on the concatenation of the list and the other list.__contains__
(value)value in self
: Return a boolean indicating whether the list contains a value.__eq__
(other)self == other
: Return a boolean indicating whether the list is equal to the other list.__ge__
(other)self < other
: Return a boolean indicating whether the list is greater than or equal to the other list.__getitem__
(index)self[index]
:Support for pickling.
__gt__
(other)self > other
: Return a boolean indicating whether the list is greater than the other list.__hash__
()hash(self)
: Return a hash value for the list.__iter__
()Return an iterator through the list items.
__le__
(other)self < other
: Return a boolean indicating whether the list is less than or equal to the other list.__len__
()len(self)
: Return the number of items in the list.__lt__
(other)self < other
: Return a boolean indicating whether the list is less than the other list.__mul__
(number)self * number
: Return a new view on the multiplication of the list with a number.__ne__
(other)self != other
: Return a boolean indicating whether the list is not equal to the other list.__repr__
()repr(self)
: Return a string representation of the view suitable for debugging.reversed(self) ...
: Return an iterator through the list in reversed iteration order.__rmul__
(number)number * self
: Return a new view on the multiplication of the list with a number.__setstate__
(a_dict)Support for unpickling.
copy
()Return a new view on a shallow copy of the list.
count
(value)Return the number of times the specified value occurs in the list.
index
(value[, start, stop])Return the index of the first item in the list with the specified value.
Attributes:
The underlying list.
- __add__(other)[source]¶
self + other
: Return a new view on the concatenation of the list and the other list.The returned
ListView
object is a view on a new list object of the type of the left hand operand that contains the items that are in the underlying list of the left hand operand, concatenated with the items in the other list (or in case of a ListView, its underlying list).The other object must be an iterable or
ListView
.The list and the other list are not changed.
- Raises
TypeError – The other object is not an iterable.
- __contains__(value)[source]¶
value in self
: Return a boolean indicating whether the list contains a value.The return value indicates whether the underlying list contains an item that is equal to the value.
- __eq__(other)[source]¶
self == other
: Return a boolean indicating whether the list is equal to the other list.The return value indicates whether the items in the underlying list are equal to the items in the other list (or in case of a ListView, its underlying list).
The other object must be a
list
orListView
.- Raises
TypeError – The other object is not a list or ListView.
- __ge__(other)[source]¶
self < other
: Return a boolean indicating whether the list is greater than or equal to the other list.The return value indicates whether the underlying list is greater than or equal to the other list (or in case of a ListView, its underlying list), based on the lexicographical ordering Python defines for sequence types (see https://docs.python.org/3/tutorial/datastructures.html#comparing-sequences-and-other-types)
The other object must be a
list
orListView
.- Raises
TypeError – The other object is not a list or ListView.
- __getitem__(index)[source]¶
self[index]
:Return the list value at the index position.
- Raises
IndexError – Index out of range.
- __gt__(other)[source]¶
self > other
: Return a boolean indicating whether the list is greater than the other list.The return value indicates whether the underlying list is greater than the other list (or in case of a ListView, its underlying list), based on the lexicographical ordering Python defines for sequence types (see https://docs.python.org/3/tutorial/datastructures.html#comparing-sequences-and-other-types)
The other object must be a
list
orListView
.- Raises
TypeError – The other object is not a list or ListView.
- __hash__()[source]¶
hash(self)
: Return a hash value for the list.Whether hashing is supported depends on the underlying list. For example, the standard Python
list
class does not support hashing, but the standard Pythontuple
class does.- Raises
TypeError – The underlying list does not support hashing.
- __le__(other)[source]¶
self < other
: Return a boolean indicating whether the list is less than or equal to the other list.The return value indicates whether the underlying list is less than or equal to the other list (or in case of a ListView, its underlying list), based on the lexicographical ordering Python defines for sequence types (see https://docs.python.org/3/tutorial/datastructures.html#comparing-sequences-and-other-types)
The other object must be a
list
orListView
.- Raises
TypeError – The other object is not a list or ListView.
- __len__()[source]¶
len(self)
: Return the number of items in the list.The return value is the number of items in the underlying list.
- __lt__(other)[source]¶
self < other
: Return a boolean indicating whether the list is less than the other list.The return value indicates whether the underlying list is less than the other list (or in case of a ListView, its underlying list), based on the lexicographical ordering Python defines for sequence types (see https://docs.python.org/3/tutorial/datastructures.html#comparing-sequences-and-other-types)
The other object must be a
list
orListView
.- Raises
TypeError – The other object is not a list or ListView.
- __mul__(number)[source]¶
self * number
: Return a new view on the multiplication of the list with a number.The returned
ListView
object is a view on a new list object of the type of the left hand operand that contains the items that are in the underlying list of the left hand operand as many times as specified by the right hand operand.A number <= 0 causes the returned list to be empty.
The left hand operand is not changed.
- __ne__(other)[source]¶
self != other
: Return a boolean indicating whether the list is not equal to the other list.The return value indicates whether the items in the underlying list are not equal to the items in the other list (or in case of a ListView, its underlying list).
The other object must be a
list
orListView
.- Raises
TypeError – The other object is not a list or ListView.
- __repr__()[source]¶
repr(self)
: Return a string representation of the view suitable for debugging.The underlying list is represented using its
repr()
representation.
- __reversed__()[source]¶
reversed(self) ...
: Return an iterator through the list in reversed iteration order.The returned iterator yields the items in the underlying list in the reversed iteration order.
- __rmul__(number)[source]¶
number * self
: Return a new view on the multiplication of the list with a number.This method is a fallback and is called only if the left operand does not support the operation.
The returned
ListView
object is a view on a new list object of the type of the right hand operand that contains the items that are in the underlying list of the right hand operand as many times as specified by the left hand operand.A number <= 0 causes the returned list to be empty.
The right hand operand is not changed.
- copy()[source]¶
Return a new view on a shallow copy of the list.
The returned
ListView
object is a new view object on a list object of the type of the underlying list.If the list type is immutable, the returned list object may be the underlying list object. If the list type is mutable, the returned list is a new list object that is a shallow copy of the underlying list object.
- index(value, start=0, stop=9223372036854775807)[source]¶
Return the index of the first item in the list with the specified value.
The search is limited to the index range defined by the specified
start
andstop
parameters, wherebystop
is the index of the first item after the search range.- Raises
ValueError – No such item is found.
- property list¶
The underlying list.
Access to the underlying list is provided for purposes such as conversion to JSON or other cases where the view classes do not work. This access should not be used to modify the underlying list.
SetView class¶
- class immutable_views.SetView(a_set)[source]¶
An immutable set view.
Derived from
Set
.This class provides an immutable view on a possibly mutable set object. The set object must be an instance of
Set
, e.g.set
, or a user-defined class.This can be used for example when a class maintains a set that should be made available to users of the class without allowing them to modify the set.
In the description of this class, the term ‘view’ always refers to the
SetView
object, and the term ‘set’ or ‘underlying set’ refers to the set object the view is based on.The
SetView
class supports the complete behavior of Python classset
, except for any methods that would modify the set. Note that the non-modifying methods of classset
are a superset of the methods defined for the abstract classSet
(the methods are listed in the table at the top of the linked page).The view is “live”: Since the view class delegates all operations to the underlying set, any modification of the underlying set object will be visible in the view object.
Note that only the view object is immutable, not necessarily its items. So if the items in the underlying set are mutable objects, they can be modified through the view.
Note that in Python, augmented assignment (e.g.
x += y
) is not guaranteed to modify the left hand object in place, but can result in the left hand name being bound to a new object (like inx = x + y
). For details, see object.__iadd__().For the SetView class, augmented assignment is supported and results in binding the left hand name to a new SetView object.
- Parameters
a_set (
Set
) – The underlying set. If this object is a SetView, its underlying set is used.
Methods:
__and__
(other)self & other
: Return a new view on the intersection of the set and the other set.__contains__
(value)value in self
: Return a boolean indicating whether the set contains a value.__eq__
(other)self == other
: Return a boolean indicating whether the set is equal to the other set.__ge__
(other)self >= other
: Return a boolean indicating whether the set is an inclusive superset of the other set.Support for pickling.
__gt__
(other)self > other
: Return a boolean indicating whether the set is a proper superset of the other set.__hash__
()hash(self)
: Return a hash value for the set.__iter__
()iter(self) ...
: Return an iterator through the set.__le__
(other)self <= other
: Return a boolean indicating whether the set is an inclusive subset of the other set.__len__
()len(self)
: Return the number of items in the set.__lt__
(other)self < other
: Return a boolean indicating whether the set is a proper subset of the other set.__ne__
(other)self != other
: Return a boolean indicating whether the set is not equal to the other set.__or__
(other)self | other
: Return a new view on the union of the set and the other set.__rand__
(other)other & self
: Return a new view on the intersection of the set and the other set.__repr__
()repr(self)
: Return a string representation of the view suitable for debugging.__ror__
(other)other | self
: Return a new view on the union of the set and the other set.__rsub__
(other)other - self
: Return a new view on the difference of the other set and the set.__rxor__
(other)other ^ self
: Return a new view on the symmetric difference of the set and the other set.__setstate__
(a_dict)Support for unpickling.
__sub__
(other)self - other
: Return a new view on the difference of the set and the other set.__xor__
(other)self ^ other
: Return a new view on the symmetric difference of the set and the other set.copy
()Return a new view on a shallow copy of the set.
difference
(*others)Return a new view on the difference of the set and the other iterables.
intersection
(*others)Return a new view on the intersection of the set and the other iterables.
isdisjoint
(other)Return a boolean indicating whether the set does not intersect with the other iterable.
issubset
(other)Return a boolean indicating whether the set is an inclusive subset of the other iterable.
issuperset
(other)Return a boolean indicating whether the set is an inclusive superset of the other iterable.
symmetric_difference
(other)Return a new view on the symmetric difference of the set and the other iterable.
union
(*others)Return a new view on the union of the set and the other iterables.
Attributes:
The underlying set.
- __and__(other)[source]¶
self & other
: Return a new view on the intersection of the set and the other set.The returned
SetView
object is a view on a new set object of the type of the left hand operand that contains the items that are in the underlying set of the left hand operand and in the other set (or in case of a SetView, its underlying set).The other object must be a
set
orSetView
.The set and the other set are not changed.
- Raises
TypeError – The other object is not a set or SetView.
- __contains__(value)[source]¶
value in self
: Return a boolean indicating whether the set contains a value.The return value indicates whether the underlying set contains an item that is equal to the value.
- __eq__(other)[source]¶
self == other
: Return a boolean indicating whether the set is equal to the other set.The return value indicates whether the items in the underlying set are equal to the items in the other set (or in case of a SetView, its underlying set).
The other object must be a
set
orSetView
.- Raises
TypeError – The other object is not a set or SetView.
- __ge__(other)[source]¶
self >= other
: Return a boolean indicating whether the set is an inclusive superset of the other set.The return value indicates whether every item in the other set (or in case of a SetView, its underlying set) is in the underlying set.
The other object must be a
set
orSetView
.- Raises
TypeError – The other object is not a set or SetView.
- __gt__(other)[source]¶
self > other
: Return a boolean indicating whether the set is a proper superset of the other set.The return value indicates whether the underlying set is a proper superset of the other set (or in case of a SetView, its underlying set).
The other object must be a
set
orSetView
.- Raises
TypeError – The other object is not a set or SetView.
- __hash__()[source]¶
hash(self)
: Return a hash value for the set.Whether hashing is supported depends on the underlying set. For example, the standard Python
set
class does not support hashing, but the standard Pythonfrozenset
class does.- Raises
TypeError – The underlying set does not support hashing.
- __iter__()[source]¶
iter(self) ...
: Return an iterator through the set.The returned iterator yields the items in the underlying set in its iteration order.
- __le__(other)[source]¶
self <= other
: Return a boolean indicating whether the set is an inclusive subset of the other set.The return value indicates whether every item in the underlying set is in the other set (or in case of a SetView, its underlying set).
The other object must be a
set
orSetView
.- Raises
TypeError – The other object is not a set or SetView.
- __len__()[source]¶
len(self)
: Return the number of items in the set.The return value is the number of items in the underlying set.
- __lt__(other)[source]¶
self < other
: Return a boolean indicating whether the set is a proper subset of the other set.The return value indicates whether the underlying set is a proper subset of the other set (or in case of a SetView, its underlying set).
The other object must be a
set
orSetView
.- Raises
TypeError – The other object is not a set or SetView.
- __ne__(other)[source]¶
self != other
: Return a boolean indicating whether the set is not equal to the other set.The return value indicates whether the items in the underlying set are not equal to the items in the other set (or in case of a SetView, its underlying set).
The other object must be a
set
orSetView
.- Raises
TypeError – The other object is not a set or SetView.
- __or__(other)[source]¶
self | other
: Return a new view on the union of the set and the other set.The returned
SetView
object is a view on a new set object of the type of the left hand operand that contains all the (unique) items from the underlying set of the left hand operand and the other set (or in case of a SetView, its underlying set).The other object must be a
set
orSetView
.The set and the other set are not changed.
- Raises
TypeError – The other object is not a set or SetView.
- __rand__(other)[source]¶
other & self
: Return a new view on the intersection of the set and the other set.This method is a fallback and is called only if the left operand does not support the operation.
The returned
SetView
object is a view on a new set object of the type of the right hand operand that contains the items that are in the underlying set of the right hand operand and in the other set (or in case of a SetView, its underlying set).The other object must be a
set
orSetView
.The set and the other set are not changed.
- Raises
TypeError – The other object is not a set or SetView.
- __repr__()[source]¶
repr(self)
: Return a string representation of the view suitable for debugging.The underlying set is represented using its
repr()
representation.
- __ror__(other)[source]¶
other | self
: Return a new view on the union of the set and the other set.This method is a fallback and is called only if the left operand does not support the operation.
The returned
SetView
object is a view on a new set object of the type of the right hand operand that contains all the (unique) items from the underlying set of the right hand operand and the other set (or in case of a SetView, its underlying set).The other object must be a
set
orSetView
.The set and the other set are not changed.
- Raises
TypeError – The other object is not a set or SetView.
- __rsub__(other)[source]¶
other - self
: Return a new view on the difference of the other set and the set.This method is a fallback and is called only if the left operand does not support the operation.
The returned
SetView
object is a view on a new set object of the type of the left hand operand that contains the items that are in the other set (or in case of a SetView, its underlying set) but not in the underlying set of the left hand operand.The other object must be a
set
orSetView
.The set and the other set are not changed.
- Raises
TypeError – The other object is not a set or SetView.
- __rxor__(other)[source]¶
other ^ self
: Return a new view on the symmetric difference of the set and the other set.This method is a fallback and is called only if the left operand does not support the operation.
The returned
SetView
object is a view on a new set object of the type of the right hand operand that contains the items that are in either the underlying set of the right hand operand or in the other set (or in case of a SetView, its underlying set), but not in both.The other object must be a
set
orSetView
.The set and the other set are not changed.
- Raises
TypeError – The other object is not a set or SetView.
- __sub__(other)[source]¶
self - other
: Return a new view on the difference of the set and the other set.The returned
SetView
object is a view on a new set object of the type of the left hand operand that contains the items that are in the underlying set of the left hand operand but not in the other set (or in case of a SetView, its underlying set).The other object must be a
set
orSetView
.The set and the other set are not changed.
- Raises
TypeError – The other object is not a set or SetView.
- __xor__(other)[source]¶
self ^ other
: Return a new view on the symmetric difference of the set and the other set.The returned
SetView
object is a view on a new set object of the type of the left hand operand that contains the items that are in either the underlying set of the left hand operand or in the other set (or in case of a SetView, its underlying set), but not in both.The other object must be a
set
orSetView
.The set and the other set are not changed.
- Raises
TypeError – The other object is not a set or SetView.
- copy()[source]¶
Return a new view on a shallow copy of the set.
The returned
SetView
object is a new view object on a set object of the type of the underlying set.If the set type is immutable, the returned set object may be the underlying set object. If the set type is mutable, the returned set is a new set object that is a shallow copy of the underlying set object.
- difference(*others)[source]¶
Return a new view on the difference of the set and the other iterables.
The returned
SetView
object is a view on a new set object of the type of the underlying set that contains the items that are in the underlying set but not in any of the other iterables (or in case of SetView objects, their underlying sets).The other objects must be iterables.
The set and the other iterables are not changed.
- Raises
TypeError – The other objects are not all iterables.
- intersection(*others)[source]¶
Return a new view on the intersection of the set and the other iterables.
The returned
SetView
object is a view on a new set object of the type of the underlying set that contains the items that are in the underlying set and in the other iterables (or in case of SetView objects, their underlying sets).The other objects must be iterables.
The set and the other iterables are not changed.
- Raises
TypeError – The other objects are not all iterables.
- isdisjoint(other)[source]¶
Return a boolean indicating whether the set does not intersect with the other iterable.
The return value indicates whether the underlying set has no items in common with the other iterable (or in case of a SetView, its underlying set).
The other object must be an iterable.
- Raises
TypeError – The other object is not an iterable.
- issubset(other)[source]¶
Return a boolean indicating whether the set is an inclusive subset of the other iterable.
The return value indicates whether every item in the underlying set is in the other iterable (or in case of a SetView, its underlying set).
The other object must be an iterable.
- Raises
TypeError – The other object is not an iterable.
- issuperset(other)[source]¶
Return a boolean indicating whether the set is an inclusive superset of the other iterable.
The return value indicates whether every item in the other iterable (or in case of a SetView, its underlying set) is in the underlying set.
The other object must be an iterable.
- Raises
TypeError – The other object is not an iterable.
- property set¶
The underlying set.
Access to the underlying set is provided for purposes such as conversion to JSON or other cases where the view classes do not work. This access should not be used to modify the underlying set.
- symmetric_difference(other)[source]¶
Return a new view on the symmetric difference of the set and the other iterable.
The returned
SetView
object is a view on a new set object of the type of the underlying set that contains the items that are in either the underlying set or in the other iterable (or in case of a SetView, its underlying set), but not in both.The other object must be an iterable.
The set and the other iterable are not changed.
- Raises
TypeError – The other object is not an iterable.
- union(*others)[source]¶
Return a new view on the union of the set and the other iterables.
The returned
SetView
object is a view on a new set object of the type of the underlying set that contains all the (unique) items from the underlying set and the other iterables (or in case of SetView objects, their underlying sets).The other objects must be iterables.
The set and the other iterables are not changed.
- Raises
TypeError – The other objects are not all iterables.
Development¶
This section only needs to be read by developers of the immutable-views project, including people who want to make a fix or want to test the project.
Repository¶
The repository for the immutable-views project is on GitHub:
Setting up the development environment¶
If you have write access to the Git repo of this project, clone it using its SSH link, and switch to its working directory:
$ git clone git@github.com:andy-maier/immutable-views.git $ cd immutable-views
If you do not have write access, create a fork on GitHub and clone the fork in the way shown above.
It is recommended that you set up a virtual Python environment. Have the virtual Python environment active for all remaining steps.
Install the project for development. This will install Python packages into the active Python environment, and OS-level packages:
$ make develop
This project uses Make to do things in the currently active Python environment. The command:
$ make
displays a list of valid Make targets and a short description of what each target does.
Building the documentation¶
The ReadTheDocs (RTD) site is used to publish the documentation for the project package at https://immutable-views.readthedocs.io/
This page is automatically updated whenever the Git repo for this package changes the branch from which this documentation is built.
In order to build the documentation locally from the Git work directory, execute:
$ make builddoc
The top-level document to open with a web browser will be
build_doc/html/docs/index.html
.
Testing¶
All of the following make commands run the tests in the currently active Python environment. Depending on how the immutable-views package is installed in that Python environment, either the directories in the main repository directory are used, or the installed package. The test case files and any utility functions they use are always used from the tests directory in the main repository directory.
The tests directory has the following subdirectory structure:
tests
+-- unittest Unit tests
Unit tests
These tests can be run standalone, and the tests validate their results automatically.
They are run by executing:
$ make test
Test execution can be modified by a number of environment variables, as documented in the make help (execute make help).
Contributing¶
Third party contributions to this project are welcome!
In order to contribute, create a Git pull request, considering this:
Test is required.
Each commit should only contain one “logical” change.
A “logical” change should be put into one commit, and not split over multiple commits.
Large new features should be split into stages.
The commit message should not only summarize what you have done, but explain why the change is useful.
What comprises a “logical” change is subject to sound judgement. Sometimes, it makes sense to produce a set of commits for a feature (even if not large). For example, a first commit may introduce a (presumably) compatible API change without exploitation of that feature. With only this commit applied, it should be demonstrable that everything is still working as before. The next commit may be the exploitation of the feature in other components.
For further discussion of good and bad practices regarding commits, see:
Further rules:
The following long-lived branches exist and should be used as targets for pull requests:
master
- for next functional versionstable_$MN
- for fix stream of released version M.N.
We use topic branches for everything!
Based upon the intended long-lived branch, if no dependencies
Based upon an earlier topic branch, in case of dependencies
It is valid to rebase topic branches and force-push them.
We use pull requests to review the branches.
Use the correct long-lived branch (e.g.
master
orstable_0.2
) as a merge target.Review happens as comments on the pull requests.
At least one approval is required for merging.
GitHub meanwhile offers different ways to merge pull requests. We merge pull requests by rebasing the commit from the pull request.
Releasing a version to PyPI¶
This section describes how to release a version of immutable-views to PyPI.
It covers all variants of versions that can be released:
Releasing a new major version (Mnew.0.0) based on the master branch
Releasing a new minor version (M.Nnew.0) based on the master branch
Releasing a new update version (M.N.Unew) based on the stable branch of its minor version
The description assumes that the andy-maier/immutable-views Github repo is cloned locally and its upstream repo is assumed to have the Git remote name origin.
Any commands in the following steps are executed in the main directory of your local clone of the andy-maier/immutable-views Git repo.
Set shell variables for the version that is being released and the branch it is based on:
MNU
- Full version M.N.U that is being releasedMN
- Major and minor version M.N of that full versionBRANCH
- Name of the branch the version that is being released is based on
When releasing a new major version (e.g.
1.0.0
) based on the master branch:MNU=1.0.0 MN=1.0 BRANCH=master
When releasing a new minor version (e.g.
0.9.0
) based on the master branch:MNU=0.9.0 MN=0.9 BRANCH=master
When releasing a new update version (e.g.
0.8.1
) based on the stable branch of its minor version:MNU=0.8.1 MN=0.8 BRANCH=stable_${MN}
Create a topic branch for the version that is being released:
git checkout ${BRANCH} git pull git checkout -b release_${MNU}
Edit the version file:
vi immutable_views/_version.py
and set the
__version__
variable to the version that is being released:__version__ = 'M.N.U'
Edit the change log:
vi docs/changes.rst
and make the following changes in the section of the version that is being released:
Finalize the version.
Change the release date to today’s date.
Make sure that all changes are described.
Make sure the items shown in the change log are relevant for and understandable by users.
In the “Known issues” list item, remove the link to the issue tracker and add text for any known issues you want users to know about.
Remove all empty list items.
When releasing based on the master branch, edit the GitHub workflow file
test.yml
:vi .github/workflows/test.yml
and in the
on
section, increase the version of thestable_*
branch to the new stable branchstable_M.N
created earlier:on: schedule: . . . push: branches: [ master, stable_M.N ] pull_request: branches: [ master, stable_M.N ]
Commit your changes and push the topic branch to the remote repo:
git status # Double check the changed files git commit -asm "Release ${MNU}" git push --set-upstream origin release_${MNU}
On GitHub, create a Pull Request for branch
release_M.N.U
. This will trigger the CI runs.Important: When creating Pull Requests, GitHub by default targets the
master
branch. When releasing based on a stable branch, you need to change the target branch of the Pull Request tostable_M.N
.On GitHub, close milestone
M.N.U
.On GitHub, once the checks for the Pull Request for branch
start_M.N.U
have succeeded, merge the Pull Request (no review is needed). This automatically deletes the branch on GitHub.Add a new tag for the version that is being released and push it to the remote repo. Clean up the local repo:
git checkout ${BRANCH} git pull git tag -f ${MNU} git push -f --tags git branch -d release_${MNU}
When releasing based on the master branch, create and push a new stable branch for the same minor version:
git checkout -b stable_${MN} git push --set-upstream origin stable_${MN} git checkout ${BRANCH}
Note that no GitHub Pull Request is created for any
stable_*
branch.On GitHub, edit the new tag
M.N.U
, and create a release description on it. This will cause it to appear in the Release tab.You can see the tags in GitHub via Code -> Releases -> Tags.
On ReadTheDocs, activate the new version
M.N.U
:Go to https://readthedocs.org/projects/immutable-views/versions/ and log in.
Activate the new version
M.N.U
.This triggers a build of that version. Verify that the build succeeds and that new version is shown in the version selection popup at https://immutable-views.readthedocs.io/
Upload the package to PyPI:
make upload
This will show the package version and will ask for confirmation.
Attention! This only works once for each version. You cannot release the same version twice to PyPI.
Verify that the released version arrived on PyPI at https://pypi.python.org/pypi/immutable-views/
Starting a new version¶
This section shows the steps for starting development of a new version of the immutable-views project in its Git repo.
This section covers all variants of new versions:
Starting a new major version (Mnew.0.0) based on the master branch
Starting a new minor version (M.Nnew.0) based on the master branch
Starting a new update version (M.N.Unew) based on the stable branch of its minor version
The description assumes that the andy-maier/immutable-views Github repo is cloned locally and its upstream repo is assumed to have the Git remote name origin.
Any commands in the following steps are executed in the main directory of your local clone of the andy-maier/immutable-views Git repo.
Set shell variables for the version that is being started and the branch it is based on:
MNU
- Full version M.N.U that is being startedMN
- Major and minor version M.N of that full versionBRANCH
- Name of the branch the version that is being started is based on
When starting a new major version (e.g.
1.0.0
) based on the master branch:MNU=1.0.0 MN=1.0 BRANCH=master
When starting a new minor version (e.g.
0.9.0
) based on the master branch:MNU=0.9.0 MN=0.9 BRANCH=master
When starting a new minor version (e.g.
0.8.1
) based on the stable branch of its minor version:MNU=0.8.1 MN=0.8 BRANCH=stable_${MN}
Create a topic branch for the version that is being started:
git checkout ${BRANCH} git pull git checkout -b start_${MNU}
Edit the version file:
vi immutable_views/_version.py
and update the version to a draft version of the version that is being started:
__version__ = 'M.N.U.dev1'
Edit the change log:
vi docs/changes.rst
and insert the following section before the top-most section:
Version M.N.U.dev1 ------------------ Released: not yet **Incompatible changes:** **Deprecations:** **Bug fixes:** **Enhancements:** **Cleanup:** **Known issues:** * See `list of open issues`_. .. _`list of open issues`: https://github.com/andy-maier/immutable-views/issues
Commit your changes and push them to the remote repo:
git status # Double check the changed files git commit -asm "Start ${MNU}" git push --set-upstream origin start_${MNU}
On GitHub, create a Pull Request for branch
start_M.N.U
.Important: When creating Pull Requests, GitHub by default targets the
master
branch. When starting a version based on a stable branch, you need to change the target branch of the Pull Request tostable_M.N
.On GitHub, create a milestone for the new version
M.N.U
.You can create a milestone in GitHub via Issues -> Milestones -> New Milestone.
On GitHub, go through all open issues and pull requests that still have milestones for previous releases set, and either set them to the new milestone, or to have no milestone.
On GitHub, once the checks for the Pull Request for branch
start_M.N.U
have succeeded, merge the Pull Request (no review is needed). This automatically deletes the branch on GitHub.Update and clean up the local repo:
git checkout ${BRANCH} git pull git branch -d start_${MNU}
Appendix¶
Glossary¶
- string¶
a unicode string or a byte string
- unicode string¶
a Unicode string type (
unicode
in Python 2, andstr
in Python 3)- byte string¶
a byte string type (
str
in Python 2, andbytes
in Python 3). Unless otherwise indicated, byte strings in this project are always UTF-8 encoded.
Change log¶
Version 0.6.1¶
Released: 2021-06-30
Bug fixes:
Fixed new Pylint issue ‘deprecated-class’ that is raised when importing from collections in Python versions that do not support collections.abc yet.
Version 0.6.0¶
Released: 2021-04-14
Bug fixes:
Docs: Fixed description of DictView rich comparison methods. (issue #20)
Docs: Fixed development status of Pypi package to be Beta.
Fixed that there is no ‘__reversed__()’ method on dict before Python 3.8.
Enhancements:
Removed dependency to ‘six’ package.
Stated the memory and compute overhead of using immutable view classes.
Added support for hashing, dependent on the hashability of the underlying collection. (issue #30)
Added OR (|) operator for DictView on Python 3.9. (issue #38)
Added tests for pickling DictView. (issue #47)
Added access to the underlying collections via a property.
The view classes now use slots for the underlying collection. This improves performance and reduces the view object memory size from 48 Bytes to 40 Bytes. (issue #51)
Cleanup:
Docs: Simplified the introduction section.
Docs: Removed INSTALL.md file to avoid duplicate information that can become inconsistent.