bidict v0.22.0 Release Notes
Release Date: 2022-03-23 // over 2 years ago-
⬇️ Drop support for Python 3.6, which reached end of life on 2021-12-23 and is no longer supported by pip as of pip version 22. Take advantage of this to reduce bidict's maintenance costs.
Use mypy-appeasing explicit re-exports in
__init__.py
(e.g.import x as x
) so that mypy no longer gives you an implicit re-export error if you run it with--no-implicit-reexport
(or--strict
) against code that imports from :mod:bidict
.⚡️ Update the implementations and type annotations of :meth:
bidict.BidictBase.keys
and :meth:bidict.BidictBase.values
to make use of the new :class:~bidict.BidictKeysView
type, which works a bit better with type checkers.Inverse bidict instances are now computed lazily the first time the :attr:
~bidict.BidictBase.inverse
attribute is accessed rather than being computed eagerly during initialization. (A bidict's backing, inverse, one-way mapping is still kept in sync eagerly as any mutations are made, to preserve key- and value-uniqueness.)⚡️ Optimize initializing a bidict with another bidict. In a microbenchmark on Python 3.10, this now performs over 2x faster.
⚡️ Optimize updating an empty bidict with another bidict. In a microbenchmark on Python 3.10, this now performs 60-75% faster.
⚡️ Optimize :meth:
~bidict.BidictBase.copy
. In a microbenchmark on Python 3.10, this now performs 10-20x faster.⚡️ Optimize rolling back :ref:
failed updates to a bidict <basic-usage:Updates Fail Clean>
in the case that the number of items passed to the update call can be determined to be larger than the bidict being updated. Previously this rollback was O(n) in the number of items passed. Now it is O(1), i.e. unboundedly faster.Optimize :meth:
bidict.BidictBase.__contains__
(the method called when you runkey in mybidict
). In a microbenchmark on Python 3.10, this now performs over 3-10x faster in the False case, and at least 50% faster in the True case.Optimize :meth:
bidict.BidictBase.__eq__
(the method called when you runmybidict == other
). In a microbenchmark on Python 3.10, this now performs 15-25x faster for ordered bidicts, and 7-12x faster for unordered bidicts.Optimize :meth:
~bidict.BidictBase.equals_order_sensitive
. In a microbenchmark on Python 3.10, this now performs 2x faster for ordered bidicts and 60-90% faster for unordered bidicts.⚡️ Optimize the :class:
~collections.abc.MappingView
objects returned by :meth:bidict.OrderedBidict.keys
, :meth:bidict.OrderedBidict.values
, and :meth:bidict.OrderedBidict.items
to delegate to backingdict_keys
anddict_items
objects if available, which are much faster in CPython. For example, in a microbenchmark on Python 3.10,orderedbi.items() == d.items()
now performs 30-50x faster.🛠 Fix a bug where :meth:
bidict.BidictBase.__eq__
was always returning False rather than :obj:NotImplemented
in the case that the argument was not a :class:~collections.abc.Mapping
, defeating the argument's own__eq__()
if implemented. As a notable example, bidicts now correctly compare equal to :obj:unittest.mock.ANY
.:class:
bidict.BidictBase
now adds a__reversed__
implementation to subclasses that don't have an overridden implementation depending on whether both their backing mappings are :class:~collections.abc.Reversible
. Previously, a__reversed__
implementation was only added to :class:~bidict.BidictBase
whenBidictBase._fwdm_cls
was :class:~collections.abc.Reversible
. So if a :class:~bidict.BidictBase
subclass set its_fwdm_cls
to a non-reversible mutable mapping, it would also have to manually set its__reversed__
attribute to None to override the implementation inherited from :class:~bidict.BidictBase
. This is no longer necessary thanks to bidict's new :meth:object.__init_subclass__
logic.The :class:
~collections.abc.MappingView
objects returned by :meth:bidict.OrderedBidict.keys
, :meth:bidict.OrderedBidict.values
, and :meth:bidict.OrderedBidict.items
are now :class:~collections.abc.Reversible
. (This was already the case for unordered bidicts when running on Python 3.8+.)➕ Add support for Python 3.9-style dict merge operators (
PEP 584 <https://www.python.org/dev/peps/pep-0584/>
__).
See
the tests <https://github.com/jab/bidict/blob/main/tests/>
__ for examples.⚡️ Update docstrings for :meth:
bidict.BidictBase.keys
, :meth:bidict.BidictBase.values
, and :meth:bidict.BidictBase.items
to include more details.:func:
~bidict.namedbidict
now exposes the passed-in keyname and valname in the corresponding properties on the generated class.:func:
~bidict.namedbidict
now requires base_type to be a subclass of :class:~bidict.BidictBase
, but no longer requires base_type to provide an_isinv
attribute, which :class:~bidict.BidictBase
subclasses no longer provide.When attempting to pickle a bidict's inverse whose class was :ref:
dynamically generated <extending:Dynamic Inverse Class Generation>
, and no reference to the dynamically-generated class has been stored anywhere in :data:sys.modules
where :mod:pickle
can find it, the pickle call is now more likely to succeed rather than failing with a :class:~pickle.PicklingError
.✂ Remove the use of slots from (non-ABC) bidict types.
This better matches the mapping implementations in Python's standard library, and significantly reduces code complexity and maintenance burden. The memory savings conferred by using slots are not noticeable unless you're creating millions of bidict instances anyway, which is an extremely unusual usage pattern.
Of course, bidicts can still contain millions (or more) items (which is not an unusual usage pattern) without using any more memory than before these changes. Notably, slots are still used in the internal linked list nodes of ordered bidicts to save memory, since as many node instances are created as there are items inserted.
Previous changes from v0.21.4
-
👍 Explicitly declare support for Python 3.10 as well as some minor internal improvements.