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)
SciPy library main repository

SciPy SciPy (pronounced "Sigh Pie") is an open-source software for mathematics, science, and engineering. It includes modules for statistics, optimiza

SciPy 10.7k Jan 09, 2023
Курс про техническое совершенство для нетехнарей

Technical Excellence 101 Курс про техническое совершенство для нетехнарей. Этот курс представлят из себя серию воркшопов, при помощи которых можно объ

Anton Bevzuk 11 Nov 13, 2022
An open-source systems and controls toolbox for Python3

harold A control systems package for Python=3.6. Introduction This package is written with the ambition of providing a full-fledged control systems s

Ilhan Polat 157 Dec 05, 2022
Run unpatched binaries on Nix/NixOS

Run unpatched binaries on Nix/NixOS

Thiago Kenji Okada 160 Jan 08, 2023
A simple flashcard app built as a final project for a databases class.

CS2300 Final Project - Flashcard app 'FlashStudy' Tech stack Backend Python (Language) Django (Web framework) SQLite (Database) Frontend HTML/CSS/Java

Christopher Spencer 2 Feb 03, 2022
A collection of some leetcode challenges in python and JavaScript

Python and Javascript Coding Challenges Some leetcode questions I'm currently working on to open up my mind to better ways of problem solving. Impleme

Ted Ngeene 1 Dec 20, 2021
The dynamic code loading framework used in LocalStack

localstack-plugin-loader localstack-plugin-loader is the dynamic code loading framework used in LocalStack. Install pip install localstack-plugin-load

LocalStack 5 Oct 09, 2022
A python script to get your activity

activities A python script to get your activity Not complete Requirements Python (=3.7) Pip (for python = 3.7) Git Pip packages psutil asyncio aioht

StarNumber 3 Nov 07, 2021
3D Printed Flip Clock Design and Code

Smart Flip Clock 3D printed smart clock that puts a new twist on old technology. Making The Smart Flip Clock The first thing that must be done for thi

Thomas 105 Oct 17, 2022
Python script to combine the statistical results of a TOPAS simulation that was split up into multiple batches.

topas-merge-simulations Python script to combine the statistical results of a TOPAS simulation that was split up into multiple batches At the top of t

Sebastian Schäfer 1 Aug 16, 2022
Simple AoC helper program you can use to develop your own solutions in python.

AoC-Compabion Simple AoC helper program you can use to develop your own solutions in python. Simply install it in your python environment using pip fr

Alexander Vollmer 1 Dec 20, 2021
Awesome & interesting talks about programming

Programming Talks I watch a lot of talks that I love to share with my friends, fellows and coworkers. As I consider all GitHubbers my friends (oh yeah

Veit Heller 7k Dec 26, 2022
Process RunGap output file of a workout and load data into Apple Numbers Spreadsheet and my website with API calls

BSD 3-Clause License Copyright (c) 2020, Mike Bromberek All rights reserved. ProcessWorkout Exercise data is exported in JSON format to iCloud using

Mike Bromberek 1 Jan 03, 2022
Context-free grammar to Sublime-syntax file

Generate a sublime-syntax file from a non-left-recursive, follow-determined, context-free grammar

Haggai Nuchi 8 Nov 17, 2022
Necst-lib - Pure Python tools for NECST

necst-lib Pure Python tools for NECST. Features This library provides: something

NANTEN2 Group 5 Dec 15, 2022
A python package for bitclout.

BitClout.py A python package for bitclout. Developed by ItsAditya Run pip install bitclout to install the module! Examples of How To Use BitClout.py G

ItsAditya 9 Dec 31, 2021
A python script for practicing Toki Pona.

toki.py A python script for practicing Toki Pona. Modified from a hirigana script by ~vilmibm. Example of the script running: $ ./toki.py This script

Dustin 2 Dec 09, 2021
Hashcrack: Hash Bruteforse tool using python

HashCrack Hash Bruteforse tool Usage hashcrack.py -n 6 -c lower -l 5 -a md5 -t 3

Lev 1 May 04, 2022
GitHub saver for stargazers, forks, repos

GitHub backup repositories Save your repos and list of stargazers & list of forks for them. Pure python3 and git with no dependencies to install. GitH

Alexander Kapitanov 23 Aug 21, 2022
万能通用对象池,可以池化任意自定义类型的对象。

pip install universal_object_pool 此包能够将一切任意类型的python对象池化,是万能池,适用范围远大于单一用途的mysql连接池 http连接池等。 框架使用对象池包,自带实现了4个对象池。可以直接开箱用这四个对象池,也可以作为例子学习对象池用法。

12 Dec 15, 2022