-------------------
- 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 run ``key 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 run ``mybidict == 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 <bidict.BidictBase.values>`, and
:meth:`bidict.OrderedBidict.items`
to delegate to backing ``dict_keys`` and ``dict_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` when ``BidictBase._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 <bidict.BidictBase.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.
- ``namedbidict`` now
exposes the passed-in *keyname* and *valname*
in the corresponding properties on the generated class.
- ``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.