Changelog¶
Release Notifications¶
Tip: Subscribe to releases
on GitHub or
libraries.io
to be notified when new versions of bidict are released.
0.21.1 (2020-09-07)¶
This release was yanked and replaced with the 0.21.2 release, which actually provides the intended changes.
0.21.0 (2020-08-22)¶
bidictnow provides type hints! ⌨️ ✅Adding type hints to
bidictposes particularly interesting challenges due to the combination of generic types, dynamically-generated types (such as inverse bidict classes andnamedbidicts), and complicating optimizations such as the use of slots and weakrefs.It didn’t take long to hit bugs and missing features in the state of the art for type hinting in Python today, e.g. missing higher-kinded types support (python/typing#548), too-narrow type hints for
collections.abc.Mapping(python/typeshed#4435), atyping.Genericbug in Python 3.6 (BPO-41451), etc.That said, this release should provide a solid foundation for code using
bidictthat enables static type checking.As always, if you spot any opportunities to improve
bidict(including its new type hints), please don’t hesitate to submit a PR!Add
bidict.MutableBidirectionalMappingABC.The Bidict Types Diagram has been updated accordingly.
Drop support for Python 3.5, which reaches end of life on 2020-09-13, represents a tiny percentage of bidict downloads on PyPI Stats, and lacks support for variable type hint syntax, ordered dicts, and
object.__init_subclass__.Remove the no-longer-needed
bidict.compatmodule.Move inverse bidict class access from a property to an attribute set in
__init_subclass__, to save function call overhead on repeated access.bidict.OrderedBidictBase.__iter__()no longer accepts areversekeyword argument so that it matches the signature ofcontainer.__iter__().Set the
__module__attribute of variousbidicttypes (usingsys._getframe()when necessary) so that private, internal modules are not exposed e.g. in classes’ repr strings.namedbidict()now immediately raisesTypeErrorif the providedbase_typedoes not provide_isinvor__getstate__(), rather than succeeding with a class whose instances may raiseAttributeErrorwhen these attributes are accessed.
0.20.0 (2020-07-23)¶
The following breaking changes are expected to affect few if any users.
Remove APIs deprecated in the previous release:
bidict.OVERWRITEandbidict.IGNORE.The
on_dup_key,on_dup_val, andon_dup_kvarguments ofput()andputall().The
on_dup_key,on_dup_val, andon_dup_kvbidictclass attributes.Remove
bidict.BidirectionalMapping.__subclasshook__()due to lack of use and maintenance cost.Fixes a bug introduced in 0.15.0 that caused any class with an
inverseattribute to be incorrectly considered a subclass ofcollections.abc.Mapping. #111
0.19.0 (2020-01-09)¶
Drop support for Python 2 as promised in v0.18.2.
The
bidict.compatmodule has been pruned accordingly.This makes bidict more efficient on Python 3 and enables further improvement to bidict in the future.
Deprecate
bidict.OVERWRITEandbidict.IGNORE. AUserWarningwill now be emitted if these are used.bidict.DROP_OLDandbidict.DROP_NEWshould be used instead.Rename
DuplicationPolicytoOnDupAction(and implement it via anEnum).An
OnDupActionmay be one ofRAISE,DROP_OLD, orDROP_NEW.Expose the new
OnDupclass to contain the threeOnDupActions that should be taken upon encountering the three kinds of duplication that can occur (key, val, kv).Provide the
ON_DUP_DEFAULT,ON_DUP_RAISE, andON_DUP_DROP_OLDOnDupconvenience instances.Deprecate the
on_dup_key,on_dup_val, andon_dup_kvarguments ofput()andputall(). AUserWarningwill now be emitted if these are used.These have been subsumed by the new on_dup argument, which takes an
OnDupinstance.Use it like this:
bi.put(1, 2, OnDup(key=RAISE, val=...)). Or pass one of the instances already provided, such asON_DUP_DROP_OLD. Or just don’t pass an on_dup argument to use the default value ofON_DUP_RAISE.The Values Must Be Unique docs have been updated accordingly.
Deprecate the
on_dup_key,on_dup_val, andon_dup_kvbidictclass attributes. AUserWarningwill now be emitted if these are used.These have been subsumed by the new
on_dupclass attribute, which takes anOnDupinstance.See the updated Extending bidict docs for example usage.
Improve the more efficient implementations of
keys(),values(), anditems(), and now also provide a more efficient implementation of__iter__()by delegating to backingdicts in the bidict types for which this is possible.Move
bidict.BidictBase.values()tobidict.BidirectionalMapping.values(), since the implementation is generic.No longer use
__all__inbidict’s__init__.py.
0.18.3 (2019-09-22)¶
Improve validation of names passed to
namedbidict(): Usestr.isidentifier()on Python 3, and a better regex on Python 2.On Python 3, set
__qualname__onnamedbidict()classes based on the providedtypenameargument.
0.18.2 (2019-09-08)¶
Warn that Python 2 support will be dropped in a future release when Python 2 is detected.
0.18.1 (2019-09-03)¶
Fix a regression introduced by the memory optimizations added in 0.15.0 which caused
deepcopiedandunpickledbidicts to have their inverses set incorrectly. #94
0.18.0 (2019-02-14)¶
Rename
bidict.BidirectionalMapping.invtoinverseand makebidict.BidictBase.invan alias forinverse. #86bidict.BidirectionalMapping.__subclasshook__()now requires aninverseattribute rather than aninvattribute for a class to qualify as a virtual subclass. This breaking change is expected to affect few if any users.Add Python 2/3-compatible
bidict.compat.collections_abcalias.Stop testing Python 3.4 on CI, and warn when Python 3 < 3.5 is detected rather than Python 3 < 3.3.
Python 3.4 reaches end of life on 2019-03-18. As of January 2019, 3.4 represents only about 3% of bidict downloads on PyPI Stats.
0.17.5 (2018-11-19)¶
Improvements to performance and delegation logic, with minor breaking changes to semi-private APIs.
Remove the
__delegate__instance attribute added in the previous release. It was overly general and not worth the cost.Instead of checking
self.__delegate__and delegating accordingly each time a possibly-delegating method is called, revert back to using “delegated-to-fwdm” mixin classes (now found inbidict._delegating_mixins), and resurrect a mutable bidict parent class that omits the mixins asbidict.MutableBidict.Rename
__repr_delegate__to_repr_delegate.
0.17.4 (2018-11-14)¶
Minor code, interop, and (semi-)private API improvements.
OrderedBidictoptimizations and code improvements.Use
bidicts for the backing_fwdmand_invmmappings, obviating the need to store key and value data in linked list nodes.Refactor proxied- (i.e. delegated-) to-
_fwdmlogic for better composability and interoperability.Drop the
_Proxied*mixin classes and instead move their methods intoBidictBase, which now checks for an object defined by theBidictBase.__delegate__attribute. TheBidictBase.__delegate__object will be delegated to if the method is available on it, otherwise a default implementation (e.g. inherited fromMapping) will be used otherwise. Subclasses may set__delegate__ = Noneto opt out.Consolidate
_MutableBidictintobidict.bidictnow that the dropped mixin classes make it unnecessary.Change
__repr_delegate__to simply take a type likedictorlist.Upgrade to latest major sortedcontainers version (from v1 to v2) for the SortedBidict Recipes.
bidict.compat.{view,iter}{keys,values,items}on Python 2 no longer assumes the target object implements these methods, as they’re not actually part of theMappinginterface, and provides fallback implementations when the methods are unavailable. This allows the SortedBidict Recipes to continue to work with sortedcontainers v2 on Python 2.
0.17.3 (2018-09-18)¶
Improve packaging by adding a pyproject.toml and by including more supporting files in the distribution. #81
Drop pytest-runner and support for running tests via
python setup.py testin preference topytestorpython -m pytest.
0.17.2 (2018-04-30)¶
Memory usage improvements¶
Use less memory in the linked lists that back
OrderedBidicts by storing node data unpacked rather than in (key, value) tuple objects.
0.17.1 (2018-04-28)¶
Bugfix Release¶
Fix a regression in 0.17.0 that could cause erroneous behavior
when updating items of an Orderedbidict’s inverse,
e.g. some_ordered_bidict.inv[foo] = bar.
0.17.0 (2018-04-25)¶
Speedups and memory usage improvements¶
Pass
keys(),values(), anditems()calls (as well as theiriter*andview*counterparts on Python 2) through to the backing_fwdmand_invmdicts so that they run as fast as possible (i.e. at C speed on CPython), rather than using the slower implementations inherited fromcollections.abc.Mapping.Use weakrefs in the linked lists that back
OrderedBidicts to avoid creating strong reference cycles.Memory for an ordered bidict that you create can now be reclaimed in CPython as soon as you no longer hold any references to it, rather than having to wait until the next garbage collection. #71
Misc¶
Add
bidict.__version_info__attribute to complementbidict.__version__.
0.16.0 (2018-04-06)¶
Minor code and efficiency improvements to
inverted() and
_iteritems_args_kw()
(formerly bidict.pairs()).
Minor Breaking API Changes¶
The following breaking changes are expected to affect few if any users.
Rename
bidict.pairs()→bidict._util._iteritems_args_kw.
0.15.0 (2018-03-29)¶
Speedups and memory usage improvements¶
Use slots to speed up bidict attribute access and reduce memory usage. On Python 3, instantiating a large number of bidicts now uses ~57% the amount of memory that it used before, and on Python 2 only ~33% the amount of memory that it used before, in a simple but representative benchmark.
Use weakrefs to refer to a bidict’s inverse internally, no longer creating a strong reference cycle. Memory for a bidict that you create can now be reclaimed in CPython as soon as you no longer hold any references to it, rather than having to wait for the next garbage collection. See the new bidict Avoids Reference Cycles documentation. #24
Make
bidict.BidictBase.__eq__()significantly more speed- and memory-efficient when comparing to a non-dictMapping. (Mapping.__eq__()’s inefficient implementation will now never be used.) The implementation is now more reusable as well.Make
bidict.OrderedBidictBase.__iter__()as well as equality comparison slightly faster for ordered bidicts.
Minor Bugfixes¶
namedbidict()now verifies that the providedkeynameandvalnameare distinct, raisingValueErrorif they are equal.namedbidict()now raisesTypeErrorif the providedbase_typeis not aBidirectionalMapping.If you create a custom bidict subclass whose
_fwdm_clsdiffers from its_invm_cls(as in theFwdKeySortedBidictexample from the SortedBidict Recipes), the inverse bidirectional mapping type (with_fwdm_clsand_invm_clsswapped) is now correctly computed and used automatically for your custom bidict’sinversebidict.
Miscellaneous¶
Classes no longer have to provide an
__inverted__attribute to be considered virtual subclasses ofBidirectionalMapping.If
bidict.inverted()is passed an object with an__inverted__attribute, it now ensures it iscallable()before returning the result of calling it.__repr__()no longer checks for a__reversed__method to determine whether to use an ordered or unordered-style repr. It now calls the new__repr_delegate__instead (which may be overridden if needed), for better composability.
Minor Breaking API Changes¶
The following breaking changes are expected to affect few if any users.
Split back out the
BidictBaseclass fromfrozenbidictandOrderedBidictBasefromFrozenOrderedBidict, reverting the merging of these in 0.14.0. Having e.g.issubclass(bidict, frozenbidict) == Truewas confusing, so this change restoresissubclass(bidict, frozenbidict) == False.See the updated Bidict Types Diagram and Polymorphism documentation.
Rename:
bidict.BidictBase.fwdm→._fwdmbidict.BidictBase.invm→._invmbidict.BidictBase.fwd_cls→._fwdm_clsbidict.BidictBase.inv_cls→._invm_clsbidict.BidictBase.isinv→._isinv
Though overriding
_fwdm_clsand_invm_clsremains supported (see Extending bidict), this is not a common enough use case to warrant public names. Most users do not need to know or care about any of these.The
RAISE,OVERWRITE, andIGNOREduplication policies are no longer available as attributes ofDuplicationPolicy, and can now only be accessed as attributes of thebidictmodule namespace, which was the canonical way to refer to them anyway. It is now no longer possible to create an infinite chain likeDuplicationPolicy.RAISE.RAISE.RAISE...Make
bidict.pairs()andbidict.inverted()no longer importable frombidict.util, and now only importable from the top-levelbidictmodule. (bidict.utilwas renamedbidict._util.)Pickling ordered bidicts now requires at least version 2 of the pickle protocol. If you are using Python 3,
pickle.DEFAULT_PROTOCOLis 3 anyway, so this will not affect you. However if you are using in Python 2,DEFAULT_PROTOCOLis 0, so you must now explicitly specify the version in yourpickle.dumps()calls, e.g.pickle.dumps(ob, 2).
0.14.2 (2017-12-06)¶
Make initializing (or updating an empty bidict) from only another
BidirectionalMappingmore efficient by skipping unnecessary duplication checking.Fix accidental ignoring of specified
base_typeargument when (un)pickling anamedbidict().Fix incorrect inversion of
some_named_bidict.inv.<fwdname>_forandsome_named_bidict.inv.<invname>_for.Only warn when an unsupported Python version is detected (e.g. Python < 2.7) rather than raising
AssertionError.
0.14.1 (2017-11-28)¶
Fix a bug introduced in 0.14.0 where hashing a
frozenbidict’s inverse (e.g.f = frozenbidict(); {f.inv: '...'}) would cause anAttributeError.Fix a bug introduced in 0.14.0 for Python 2 users where attempting to call
viewitems()would cause aTypeError. #48
0.14.0 (2017-11-20)¶
Fix a bug where
bidict’s default on_dup_kv policy was set toRAISE, rather than matching whatever on_dup_val policy was in effect as was documented.Fix a bug that could happen when using Python’s optimization (
-O) flag that could leave an ordered bidict in an inconsistent state when dealing with duplicated, overwritten keys or values. If you do not use optimizations (specifically, skippingassertstatements), this would not have affected you.Fix a bug introduced by the optimizations in 0.13.0 that could cause a frozen bidict that compared equal to another mapping to have a different hash value from the other mapping, violating Python’s object model. This would only have affected you if you were inserting a frozen bidict and some other immutable mapping that it compared equal to into the same set or mapping.
Reduce the memory usage of ordered bidicts.
Make copying of ordered bidicts faster.
Improvements to tests and CI, including:
Test on Windows
Test with PyPy3
Test with CPython 3.7-dev
Test with optimization flags
Require pylint to pass
Breaking API Changes¶
This release includes multiple API simplifications and improvements.
Rename:
orderedbidict→OrderedBidictfrozenorderedbidict→FrozenOrderedBidict
so that these now match the case of
collections.OrderedDict.The names of the
bidict,namedbidict(), andfrozenbidictclasses have been retained as all-lowercase so that they continue to match the case ofdict,namedtuple(), andfrozenset, respectively.The
ON_DUP_VALduplication policy value for on_dup_kv has been removed. UseNoneinstead.Merge
frozenbidictandBidictBasetogether and removeBidictBase.frozenbidictis now the concrete base class that all other bidict types derive from. See the updated Bidict Types Diagram.Merge
frozenbidictandFrozenBidictBasetogether and removeFrozenBidictBase. See the updated Bidict Types Diagram.Merge
frozenorderedbidictandOrderedBidictBasetogether into a singleFrozenOrderedBidictclass and removeOrderedBidictBase.OrderedBidictnow extendsFrozenOrderedBidictto add mutable behavior. See the updated Bidict Types Diagram.Make
__eq__()always perform an order-insensitive equality test, even if the other mapping is ordered.Previously,
__eq__()was only order-sensitive for otherOrderedBidictBasesubclasses, and order-insensitive otherwise.Use the new
equals_order_sensitive()method for order-sensitive equality comparison.orderedbidict._should_compare_order_sensitive()has been removed.frozenorderedbidict._HASH_NITEMS_MAXhas been removed. Since its hash value must be computed from all contained items (so that hash results are consistent with equality comparisons against unordered mappings), the number of items that influence the hash value should not be limitable.frozenbidict._USE_ITEMSVIEW_HASHhas been removed, andfrozenbidict.compute_hash()now usescollections.ItemsView._hash()to compute the hash always, not just when running on PyPy.Override
frozenbidict.compute_hash()to returnhash(frozenset(iteritems(self)))if you prefer the old default behavior on CPython, which takes linear rather than constant space, but which uses thefrozenset_hashroutine (implemented insetobject.c) rather than the pure PythonItemsView._hash()routine.loosebidictandlooseorderedbidicthave been removed. A simple recipe to implement equivalents yourself is now given in Extending bidict.Rename
FrozenBidictBase._compute_hash()→frozenbidict.compute_hash().Rename
DuplicationBehavior→DuplicationPolicy.Rename:
BidictBase._fwd_class→.fwd_clsBidictBase._inv_class→.inv_clsBidictBase._on_dup_key→on_dup_keyBidictBase._on_dup_val→on_dup_valBidictBase._on_dup_kv→on_dup_kv
0.13.1 (2017-03-15)¶
Fix regression introduced by the new
__subclasshook__()functionality in 0.13.0 so thatissubclass(OldStyleClass, BidirectionalMapping)once again works with old-style classes, returningFalserather than raisingAttributeError#41
0.13.0 (2017-01-19)¶
Support Python 3.6.
(Earlier versions of bidict should work fine on 3.6, but it is officially supported starting in this version.)
BidirectionalMappinghas been refactored into an abstract base class, following the waycollections.abc.Mappingworks. The concrete method implementations it used to provide have been moved into a newBidictBasesubclass.BidirectionalMappingnow also implements__subclasshook__(), so any class that provides a conforming set of attributes (enumerated in_subclsattrs) will be considered aBidirectionalMappingsubclass automatically.OrderedBidirectionalMappinghas been renamed toOrderedBidictBase, to better reflect its function. (It is not an ABC.)A new
FrozenBidictBaseclass has been factored out offrozenbidictandfrozenorderedbidict. This implements common behavior such as caching the result of__hash__after the first call.The hash implementations of
frozenbidictandfrozenorderedbidict. have been reworked to improve performance and flexibility.frozenorderedbidict’s hash implementation is now order-sensitive.See
frozenbidict._compute_hash()andfrozenorderedbidict._compute_hashfor more documentation of the changes, including the newfrozenbidict._USE_ITEMSVIEW_HASHandfrozenorderedbidict._HASH_NITEMS_MAXattributes. If you have an interesting use case that requires overriding these, or suggestions for an alternative implementation, please share your feedback.Add
_fwd_classand_inv_classattributes representing the backingMappingtypes used internally to store the forward and inverse dictionaries, respectively.This allows creating custom bidict types with extended functionality simply by overriding these attributes in a subclass.
See the new Extending bidict documentation for examples.
Pass any parameters passed to
popitem()through to_fwd.popitemfor greater extensibility.More concise repr strings for empty bidicts.
e.g.
bidict()rather thanbidict({})andorderedbidict()rather thanorderedbidict([]).Add
bidict.compat.PYPYand remove unusedbidict.compat.izip_longest.
0.12.0 (2016-07-03)¶
New/renamed exceptions:
DuplicationError(base class for the above)
put()now acceptson_dup_key,on_dup_val, andon_dup_kvkeyword args which allow you to override the default policy when the key or value of a given item duplicates any existing item’s. These can take the following values:OVERWRITEIGNORE
on_dup_kvcan also takeON_DUP_VAL.New
putall()method provides a bulkput()API, allowing you to override the default duplication handling policy thatupdate()uses.update()now fails clean, so if anupdate()call raises aDuplicationError, you can now be sure that none of the given items was inserted.Previously, all of the given items that were processed before the one causing the failure would have been inserted, and no facility was provided to recover which items were inserted and which weren’t, nor to revert any changes made by the failed
update()call. The new behavior makes it easier to reason about and control the effects of failedupdate()calls.The new
putall()method also fails clean.Internally, this is implemented by storing a log of changes made while an update is being processed, and rolling back the changes when one of them is found to cause an error. This required reimplementing
orderedbidicton top of two dicts and a linked list, rather than two OrderedDicts, sinceOrderedDictdoes not expose its backing linked list.orderedbidict.move_to_end()now works on Python < 3.2 as a result of the neworderedbidictimplementation.Add
bidict.compat.viewkeysbidict.compat.viewvaluesbidict.compat.iterkeysbidict.compat.itervaluesbidict.compat.izipbidict.compat.izip_longest
to complement the existing
bidict.compat.iteritemsandbidict.compat.viewitemscompatibility helpers.More efficient implementations of
bidict.pairs(),inverted(), andcopy().Implement
__copy__()for use with thecopymodule.Fix issue preventing a client class from inheriting from
loosebidict. #34Add benchmarking to tests.
Drop official support for CPython 3.3. (It may continue to work, but is no longer being tested.)
Breaking API Changes¶
Rename
KeyExistsException→KeyDuplicationErrorandValueExistsException→ValueDuplicationError.When overwriting the key of an existing value in an
orderedbidict, the position of the existing item is now preserved, overwriting the key of the existing item in place, rather than moving the item to the end. This now matches the behavior of overwriting the value of an existing key, which has always preserved the position of the existing item. (If inserting an item whose key duplicates that of one existing item and whose value duplicates that of another, the existing item whose value is duplicated is still dropped, and the existing item whose key is duplicated still gets its value overwritten in place, as before.)For example:
>>> from bidict import orderedbidict >>> o = orderedbidict([(0, 1), (2, 3)]) >>> o.forceput(4, 1)
previously would have resulted in:
>>> o orderedbidict([(2, 3), (4, 1)])
but now results in:
>>> o orderedbidict([(4, 1), (2, 3)])
0.11.0 (2016-02-05)¶
Add
orderedbidict,looseorderedbidict, andfrozenorderedbidict.Add Code of Conduct.
Drop official support for pypy3. (It still may work but is no longer being tested. Support may be added back once pypy3 has made more progress.)
0.10.0.post1 (2015-12-23)¶
Minor documentation fixes and improvements.
0.10.0 (2015-12-23)¶
Remove several features in favor of keeping the API simpler and the code more maintainable.
In the interest of protecting data safety more proactively, by default bidict now raises an error on attempting to insert a non-unique value, rather than allowing its associated key to be silently overwritten. See discussion in #21.
New
forceupdate()method provides a bulkforceput()operation.Fix bugs in
popandsetdefaultwhich could leave a bidict in an inconsistent state.
Breaking API Changes¶
Remove
bidict.__invert__, and with it, support for the~bsyntax. Useinvinstead. #19Remove support for the slice syntax. Use
b.inv[val]rather thanb[:val]. #19Remove
bidict.invert. Useinvrather than inverting a bidict in place. #20Raise
ValueExistsExceptionwhen attempting to insert a mapping with a non-unique key. #21Rename
collapsingbidict→loosebidictnow that it suppressesValueExistsExceptionrather than the less generalCollapseException. #21CollapseExceptionhas been subsumed byValueExistsException. #21put()now raisesKeyExistsExceptionwhen attempting to insert an already-existing key, andValueExistsExceptionwhen attempting to insert an already-existing value.
0.9.0.post1 (2015-06-06)¶
Fix metadata missing in the 0.9.0rc0 release.
0.9.0rc0 (2015-05-30)¶
Add this changelog, Contributors’ Guide, Gitter chat room, and other community-oriented improvements.
Adopt Pytest.
Add property-based tests via hypothesis.
Other code, tests, and docs improvements.
Breaking API Changes¶
Move
bidict.iteritems()andbidict.viewitems()to newbidict.compatmodule.Move
bidict.invertedto newbidict.utilmodule (still available from top-levelbidictmodule as well).Move
bidict.fancy_iteritems()→bidict.util.pairs()(also available from top level asbidict.pairs()).Rename
bidict.namedbidict()’sbidict_typeargument →base_type.