The bidirectional mapping library for Python.

Overview

bidict

The bidirectional mapping library for Python.

bidict logo

Status

Latest release Documentation GitHub Actions CI status Test coverage License PyPI Downloads Sponsor through GitHub

bidict:

  • has been used for many years by several teams at Google, Venmo, CERN, Bank of America Merrill Lynch, Bloomberg, Two Sigma, and many others
  • has carefully designed APIs for safety, simplicity, flexibility, and ergonomics
  • is fast, lightweight, and has no runtime dependencies other than Python's standard library
  • integrates natively with Python’s collections.abc interfaces
  • provides type hints for all public APIs
  • is implemented in concise, well-factored, pure (PyPy-compatible) Python code that is optimized for running efficiently as well as for reading and learning [1]
  • has extensive docs and test coverage (including property-based tests and benchmarks) run continuously on all supported Python versions

Installation

pip install bidict

Quick Start

>>> from bidict import bidict
>>> element_by_symbol = bidict({'H': 'hydrogen'})
>>> element_by_symbol['H']
'hydrogen'
>>> element_by_symbol.inverse['hydrogen']
'H'

For more usage documentation, head to the intro [3] and proceed from there.

Enterprise Support

Enterprise-level support for bidict can be obtained via the Tidelift subscription or by contacting me directly.

I have a US-based LLC set up for invoicing, and I have 15+ years of professional experience delivering software and support to companies successfully.

You can also sponsor my work through platforms like GitHub Sponsors. See the Sponsoring section below for details. For rationale and examples of companies doing this, see this post among others.

Voluntary Community Support

Please search through already-asked questions and answers in GitHub Discussions and the issue tracker in case your question has already been addressed.

Otherwise, please feel free to start a new discussion or create a new issue on GitHub, or ask in the bidict chatroom for voluntary community support.

Notice of Usage

If you use bidict, and especially if your usage or your organization is significant in some way, please let me know in any of the following ways:

Changelog

See the changelog [2] for a history of notable changes to bidict.

Release Notifications

Watch releases on GitHub to be notified when new versions of bidict are released.

Learning from bidict

One of the best things about bidict is that it touches a surprising number of interesting Python corners, especially given its small size and scope.

Check out learning-from-bidict [1] if you're interested in learning more.

Contributing

I have been bidict's sole maintainer and active contributor since I started the project almost 15 years ago.

Your help would be most welcome! See the contributors-guide [4] for more information.

Sponsoring

Sponsor through GitHub

Bidict is the product of thousands of hours of my unpaid work over the ~15 years that I've been the sole maintainer.

If bidict has helped you or your company accomplish your work, especially work that you or your company were paid for, please sponsor my work through GitHub, and ask others you know who got value from my work to do the same.

Choose a tier and GitHub handles everything else. Sponsorship just goes on the same bill that GitHub already charges you or your company for automatically, so after the one-time signup, there's nothing extra to do.

You can also sponsor my work through Gumroad or PayPal, or through a support engagement with my LLC. See Enterprise Support above for details.

Finding Documentation

If you're viewing this on https://bidict.readthedocs.io, note that multiple versions of the documentation are available, and you can choose a different version using the popup menu at the bottom-right. Please make sure you're viewing the version of the documentation that corresponds to the version of bidict you'd like to use.

If you're viewing this on GitHub, PyPI, or some other place that can't render and link this documentation properly and are seeing broken links, try these alternate links instead:

[1] (1, 2) docs/learning-from-bidict.rst | https://bidict.readthedocs.io/learning-from-bidict.html
[2] CHANGELOG.rst | https://bidict.readthedocs.io/changelog.html
[3] (1, 2) docs/intro.rst | https://bidict.readthedocs.io/intro.html
[4] docs/contributors-guide.rst | https://bidict.readthedocs.io/contributors-guide.html

Next: intro [3]

Comments
  • Consider removing slice and ~ syntax

    Consider removing slice and ~ syntax

    Some of the syntactic sugar in bidict causes a readability problem for me. Syntactic sugar is always going to be subjective, but I'd like to propose the removal of the overloading of slicing and bitwise negation - because .inv is succinct and covers all these cases without needing the sugar:

    • ~d is clearer written as d.inv
    • d[:key] is clearer written as d.inv[key].

    These don't need to be explained/learned in the same way as they follow from the same clear rule.

    Naturally this would be a big breaking change but if bidict is not yet at a 1.0 release then this could presumably still be considered.

    opened by lordmauve 24
  • global name 'BidirectionalMapping' is not defined

    global name 'BidirectionalMapping' is not defined

    Hi, we are using version bidict==0.18.0 and CPython 2.7.13 and got the following error here:

    bidict/_abc.py in subclasshook at line 90

        def __subclasshook__(cls, C):  # noqa: N803 (argument name should be lowercase)
            """Check if *C* is a :class:`~collections.abc.Mapping`
            that also provides an ``inverse`` attribute,
            thus conforming to the :class:`BidirectionalMapping` interface,
            in which case it will be considered a (virtual) C
            even if it doesn't explicitly extend it.
            """
            that also provides an ``inverse`` attribute,
            thus conforming to the :class:`BidirectionalMapping` interface,
            in which case it will be considered a (virtual) C
            even if it doesn't explicitly extend it.
            """
            if cls is not BidirectionalMapping:  # lgtm [py/comparison-using-is]  # global name 'BidirectionalMapping' is not defined here
                return NotImplemented
            if not Mapping.__subclasshook__(C):
                return NotImplemented
            mro = getattr(C, '__mro__', None)
            if mro is None:  # Python 2 old-style class
            ...
    

    C is a <type 'unicode'> here. So we simply pass unicode string to logger and such error raised. Looks like this happened because of the following line in python2.7/logging/init.py:

    if (args and len(args) == 1 and isinstance(args[0], collections.Mapping)
    

    Could anybody help with this issue? What we are doing wrong? Thanks in advance.

    opened by andreykryazhev 21
  • provide type annotations

    provide type annotations

    Maybe after removing support for older versions of Python.

    Ref:

    • https://docs.python.org/3/library/typing.html
    • https://mypy.readthedocs.io/en/stable/generics.html#defining-sub-classes-of-generic-classes
    • MagicStack/immutables#13
    opened by jab 18
  • bidict should be subclass of dict

    bidict should be subclass of dict

    issubclass(bidict, dict) returns False. We thus cannot pass it to function that test it. If dict were at least at last place of mro it would be settled.

    opened by pacholik 17
  • implement stricter 1-to-1 checking

    implement stricter 1-to-1 checking

    • raise ValueExistsException on insert new key associated with existing value
    • stifled by forceput just like CollapseException was
    • ValueExistsException replaces CollapseException since it's more general
    • rename collapsingbidict loosebidict now that ValueExistsException has replaced CollapseException
    • add forceupdate method for bulk forceput
    • update docs and tests
    opened by jab 12
  • add license title and fix short identifier

    add license title and fix short identifier

    The license title is not strictly required, but it's useful metadata, and part of the recommended license template text:

    • http://choosealicense.com/licenses/isc/
    • https://opensource.org/licenses/isc-license
    • http://spdx.org/licenses/ISC.html#licenseText

    The short identifier has been codified by both SPDX and OSI as "ISC" -- see https://opensource.org/licenses/ISC and http://spdx.org/licenses/ISC.html.

    opened by waldyrious 11
  • New properties

    New properties

    Hi,

    We are working with @hgoldstein95, @bcpierce00, @lemonidas and @seyoungjkim on a mutation testing tool developped as a pytest plugin, called pytest-mutagen. It allows the user to introduce some mutated versions of its functions to check that its test suite catches them.

    It's particularly suited for property-based testing, and that's why we decided to use it on bidict. We found some trivial mutants (like replacing the "clear" or "put" function by just "pass") that were not caught by your test suite, so we added some properties to the existing ones to make sure that they are now caught.

    To witness this you can simply run these commands in the bidict repo (branch new_properties) : python3 -m pip install pytest-mutagen ./run_tests.py --mutate --quick-mut -q

    Therefore we think that these properties could be a relevant addition to yours.

    opened by timpaquatte 10
  • Every bidict creates a reference cycle

    Every bidict creates a reference cycle

    The fact that every bidict creates an holds a reference to its inverse bidict, and each inverse holds a reference to the forward bidict, means that bidicts will create reference cycles.

    This has two implications:

    1. Memory won't be reclaimed immediately if the references are deleted. They will be reclaimed by the garbage collector - but at some later point. Large bidicts could therefore hold memory much longer than a standard dict.
    2. Prior to Python 3.4, any subclasses of bidict that happen to implement __del__() methods won't be garbage collectable at all.

    I'm not sure how important this is, but it's more important the less you know about ways in which bidict is used.

    A workaround might be not to hold a full reference to inv, but to instead hold a weak memoized reference. This would guarantee

    d.inv.inv is d
    

    but would allow immediate reclamation of either side of the bidict pair if no reference to them are held.

    opened by lordmauve 10
  • Missing __all__ in bidict/__init__.py leads to implicit reexport error with mypy in strict mode.

    Missing __all__ in bidict/__init__.py leads to implicit reexport error with mypy in strict mode.

    Hi, Pull request 107 has removed __all__ from bidict/__init__.py.

    This leads to implicit reexports of all the imported classes etc., which generates a error when typechecking with mypy in strict mode (which sets --no-implicit-reexport).

    So for example with test.py...

    from bidict import bidict, BidirectionalMapping
    element_by_symbol: BidirectionalMapping[str, str] = bidict({'H': 'hydrogen'})
    

    ... due to disallowing implicit reexports, the imports will not be found by mypy, while the code obviously works:

    $ mypy --strict .\test.py
    test.py:1: error: Module 'bidict' has no attribute 'bidict'
    test.py:1: error: Module 'bidict' has no attribute 'BidirectionalMapping'; maybe "MutableBidirectionalMapping"?
    Found 2 errors in 1 file (checked 1 source file)
    

    Was there some reasoning behind removing __all__ or could it be re-added? Thanks in advance. :)

    opened by FlorianKoegler 9
  • Add strictbidict that throws exception on any duplicate value assignment

    Add strictbidict that throws exception on any duplicate value assignment

    I see considerable value preventing people accidentally creating mappings that are not invertible. In our codebase, there are several hundred instances of code like

    PRODUCT_REMAP = {... hundreds of lines ...}
    REVERSE_PRODUCT_REMAP = dict((v, k) for k, v in PRODUCT_REMAP.iteritems())
    

    A concern with these is that literals that were accidentally written to include duplicate values would create an incorrect inverse mapping.

    Using bidict does little to improve matters. In code like that below, one of those keys will "win":

    d = bidict({
         'foo': 1,
         ... hundreds of lines ...
         'bar': 1
    })
    

    This has the advantage that the inverse mapping will genuinely reflect the forward mapping, but it carries the disadvantage the mapping for one of the keys is lost. In many cases this is worse - for example, when the forward mapping is fundamental and the inverse mapping is just informational. The only reasonable solution in cases like these is to throw an exception for the programmer to deal with.

    I suggest creating a "strictbidict" in which _put() throws a CollapseException if any value is duplicated, rather than dropping the previous key that maps to that value.

    opened by lordmauve 9
  • Issue #6 multi type hypothesis tests

    Issue #6 multi type hypothesis tests

    opened by tomviner 9
  • Automate upgrading dev dependencies

    Automate upgrading dev dependencies

    Currently, I manually run a script periodically to keep development dependencies up-to-date.

    It looks like https://github.com/marketplace/actions/dependencies-autoupdate could be used to automate this.

    help wanted 
    opened by jab 0
  • logo

    logo

    The old logo is black on a transparent background, and was only designed for use on pages with light backgrounds. The logo is not visible on pages with dark backgrounds, which has become a much more common way for it to be displayed now that GitHub supports dark mode.

    • SVG supports embedded CSS in <style> elements. Can @media (prefers-color-scheme: dark) be used in an SVG to make the same image file look good on both light and dark backgrounds? If so, if we switch the logo from PNGs to SVGs that use this trick, will it work everywhere the logo is displayed?
    • Instead (or in addition), the logo could use other foreground colors that work well on both light and dark backgrounds. Python blue and yellow? (At that point, does it actually need a snake or two? Perhaps encircling a dictionary in a heart shape, or forming { braces around it } (as @lordmauve once mocked up)? A full redesign is not out of scope here :)
    help wanted 
    opened by jab 5
Releases(v0.22.1)
Time tracking program that will format output to be easily put into Gitlab

time_tracker Time tracking program that will format output to be easily put into Gitlab. Feel free to branch and use it yourself! Getting Started Clon

Jake Strasler 2 Oct 13, 2022
Scraper pour les offres de stage Tesla et les notes sur Oasis (Polytech Paris-Saclay) sous forme de bot Discord

Scraper pour les offres de stage Tesla et les notes sur Oasis (Polytech Paris-Saclay) sous forme de bot Discord

Alexandre Malfreyt 1 Jan 21, 2022
Estimate the Market Size for Electic and Plug-In Hybrid Vehicles In Africa

Estimate the Market Size for Electic and Plug-In Hybrid Vehicles In Africa The goal of this repository is to use open data repositories to answer the

Leonce Nshuti 0 Feb 21, 2022
Just imagine normal bancho, but you can have multiple profiles and funorange speed up maps ranked

Local osu! server Just imagine normal bancho, but you can have multiple profiles and funorange speed up maps ranked (coming soon)! Windows Setup Insta

Cover 25 Nov 15, 2022
Data on COVID-19 (coronavirus) cases, deaths, hospitalizations, tests • All countries • Updated daily by Our World in Data

COVID-19 Dataset by Our World in Data Find our data on COVID-19 and its documentation in public/data. Documentation Data: complete COVID-19 dataset Da

Our World in Data 5.5k Jan 03, 2023
A 3-line lisp implementation

Nanolisp The download page of many a language harbors deep senses of forboding, of evil lurking in its native lair. You feel that the language is not

5 Jun 17, 2022
Application to list countries in order of travel from the United States.

Application to list countries in order of travel from the United States.

Broden Wanner 1 Nov 03, 2021
Analysis of ROM image for Norsk Data VDU 301 S

This repository is meant to analyze the ROM images from Norsk Data VDU 301 S as provided at by Torfinn. To combine the two ROM image halves and extrac

Sebastian Rasmussen 1 Oct 21, 2021
Animation picker for Audodesk Maya 2017 (or higher)

Dreamwall Picker Animation picker for Audodesk Maya 2017 (or higher) Authors: Lionel Brouyère, Olivier Evers This tool is a fork of Hotbox Designer (L

DreamWall 93 Dec 21, 2022
ripgrep recursively searches directories for a regex pattern while respecting your gitignore

ripgrep (rg) ripgrep is a line-oriented search tool that recursively searches the current directory for a regex pattern. By default, ripgrep will resp

Andrew Gallant 35k Dec 31, 2022
aaencode for python,把python代码转换为颜文字

py-aaencode aaencode for python,把python代码转换为颜文字 compile.py: 将python编译成颜文字,编译结果有随机性,可以选择BPE词表压缩代码 compile_min.py: 最小化的编译器 compiled_min.txt: 编译得到的最小的com

11 Dec 30, 2021
A script to automatically update bot status at GitHub as well as in Telegram channel.

A simple & short repository to show your bot's status in your GitHub README.md file as well as in you channel.

Jainam Oswal 55 Dec 13, 2022
Python-Kite: Simple python code to make kite pattern

Python-Kite Simple python code to make kite pattern. Getting Started These instr

Anoint 0 Mar 22, 2022
Types for the Rasterio package

types-rasterio Types for the rasterio package A work in progress Install Not yet published to PyPI pip install types-rasterio These type definitions

Kyle Barron 7 Sep 10, 2021
Example platform plugin that fixes fentry calls in Binja

Example Binja Platform Plugin This is an example Binja platform plugin which fixes up linux kernel module calls to __fentry__. __fentry__ is the linux

_yrp 2 Oct 07, 2021
A compiler for ARM, X86, MSP430, xtensa and more implemented in pure Python

A compiler for ARM, X86, MSP430, xtensa and more implemented in pure Python

Windel Bouwman 277 Dec 26, 2022
Battle-Ship - Python-console battle ship

Battle-Ship this SHOULD work in lenux(if i spelled it wrong spam issues till I fix it) the thing that maby wont work is where it clears the screen the

pl608 2 Jan 06, 2022
A Sophisticated And Beautiful Doxing Tool

Garuda V1.1 A Sophisticated And Beautiful Doxing Tool Works on Android[Termux] | Linux | Windows Don't Forget to give it a star ❗ How to use ❓ First o

The Cryptonian 67 Jan 10, 2022
Xoroshiro-cairo - A xoroshiro128** pseudorandom number generator implementation in Cairo

xoroshiro-cairo A xoroshiro128** pseudorandom number generator implementation in

Milan Cermak 26 Oct 05, 2022
Thumbor-bootcamp - learning and contribution experience with ❤️ and 🤗 from the thumbor team

Thumbor-bootcamp - learning and contribution experience with ❤️ and 🤗 from the thumbor team

Thumbor (by @globocom) 9 Jul 11, 2022