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)
YunoHost is an operating system aiming to simplify as much as possible the administration of a server.

YunoHost is an operating system aiming to simplify as much as possible the administration of a server. This repository corresponds to the core code, written mostly in Python and Bash.

YunoHost 1.5k Jan 09, 2023
Streamlit apps done following data professor's course on YouTube

streamlit-twelve-apps Streamlit apps done following data professor's course on YouTube Español Curso de apps de data science hecho por Data Professor

Federico Bravin 1 Jan 10, 2022
Hydralit package is a wrapping and template project to combine multiple independant Streamlit applications into a multi-page application.

Hydralit The Hydralit package is a wrapping and template project to combine multiple independant (or somewhat dependant) Streamlit applications into a

Jackson Storm 108 Jan 08, 2023
🟥This is an overview of how to set up and use DataStore3 in your Roblox experiences

Welcome to DataStore3 👋 This is an overview of how to set up and use DataStore3 in your Roblox experiences What is it? 🤔 DataStore3 is a service tha

Reece Harris 7 Aug 19, 2022
EFB Docker image with efb-telegram-master and efb-wechat-slave

efb-wechat-docker EFB Docker image with efb-telegram-master and efb-wechat-slave Features Container run by non-root user. Support add environment vari

Haukeng 1 Nov 10, 2022
Request ID propagation for ASGI apps

ASGI Correlation ID middleware Middleware for loading and receiving correlation IDs from request HTTP headers, and making them available in applicatio

snok 170 Jan 02, 2023
App and Python library for parsing, writing, and validation of the STAND013 file format.

python-stand013 python-stand013 is a Python app and library for parsing, writing, and validation of the STAND013 file format. Features The following i

Oda 3 Nov 09, 2022
An early stage integration of Hotwire Turbo with Django

Note: This is not ready for production. APIs likely to change dramatically. Please drop by our Slack channel to discuss!

Hotwire for Django 352 Jan 06, 2023
Python library for ODE integration via Taylor's method and LLVM

heyoka.py Modern Taylor's method via just-in-time compilation Explore the docs » Report bug · Request feature · Discuss The heyókȟa [...] is a kind of

Francesco Biscani 45 Dec 21, 2022
Easy way to build a SaaS application using Python and Dash

EasySaaS This project will be attempt to make a great starting point for your next big business as easy and efficent as possible. This project will cr

xianhu 3 Nov 17, 2022
Python bindings for the Plex API.

Python-PlexAPI Overview Unofficial Python bindings for the Plex API. Our goal is to match all capabilities of the official Plex Web Client. A few of t

Michael Shepanski 931 Jan 07, 2023
An interactive tool with which to explore the possible imaging performance of candidate ngEHT architectures.

ngEHTexplorer An interactive tool with which to explore the possible imaging performance of candidate ngEHT architectures. Welcome! ngEHTexplorer is a

Avery Broderick 7 Jan 28, 2022
"Cambio de monedas" Change-making problem with Python, dynamic programming best solutions,

Change-making-problem / Cambio de monedas Entendiendo el problema Dada una cantidad de dinero y una lista de denominaciones de monedas, encontrar el n

Juan Antonio Ayola Cortes 1 Dec 08, 2021
Medical appointments No-Show classifier

Medical Appointments No-shows Why do 20% of patients miss their scheduled appointments? A person makes a doctor appointment, receives all the instruct

4 Apr 20, 2022
A competition for forecasting electricity demand at the country-level using a standard backtesting framework

A competition for forecasting electricity demand at the country-level using a standard backtesting framework

5 Jul 12, 2022
An easy FASTA object handler, reader, writer and translator for small to medium size projects without dependencies.

miniFASTA An easy FASTA object handler, reader, writer and translator for small to medium size projects without dependencies. Installation Using pip /

Jules Kreuer 3 Jun 30, 2022
Install Firefox from Mozilla.org easily, complete with .desktop file creation.

firefox-installer Install Firefox from Mozilla.org easily, complete with .desktop file creation. Dependencies Python 3 Python LXML Debian/Ubuntu: sudo

rany 7 Nov 04, 2022
This repo is for scripts to run various clients at the merge f2f

merge-f2f This repo is for scripts to run various clients at the merge f2f. Tested with Lighthouse! Tested with Geth! General dependecies sudo apt-get

Parithosh Jayanthi 2 Apr 03, 2022
This is the key combo trainer for League of Legends and Dota 2 players.

This is the key combo trainer for League of Legends and Dota 2 players. Place the mouse cursor on the blue point and press the key combo from the upper-left side of the screen.

Ilya Shpigor 1 Jan 31, 2022
Find virtual hosts (vhosts) from IP addresses and hostnames

Features Enumerate vhosts from a list of IP addresses and domain names. Virtual Hosts are enumerated using the following process: Supplied domains are

3 Jul 09, 2022