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)
Annotates sequences with Eggnog-mapper and hhblits against PDB70

Annotating "hypothetical" proteins with the PDB See config/ for configuration information. This workflow takes as input a set of protein sequences. It

1 Apr 05, 2022
Push a record and you will receive a email when that date

Push a record and you will receive a email when that date

5 Nov 28, 2022
Automatically give thanks to Pypi packages you use in your project!

Automatically give thanks to Pypi packages you use in your project!

Ward 25 Dec 20, 2021
An example of Connecting a MySQL Database with Python Code

An example of Connecting a MySQL Database with Python Code And How to install Table of contents General info Technologies Setup General info In this p

Mohammad Hosseinzadeh 1 Nov 23, 2021
Materials for the Introduction in Python , Linux , Git and Github

This repository contains all the materials of the presentation on the introduction of python, linux, git and Github.

AMMI 3 Aug 28, 2022
Wordler - A program to support you to solve the wordle puzzles

solve wordle (https://www.powerlanguage.co.uk/wordle) A program to support you t

Viktor Martinović 2 Jan 17, 2022
LAPS module for CrackMapExec

Crackmapexec-LAPS LAPS module for CrackMapExec Make sure to point to the DC Specify the full domain name Be careful the rid 500 might not be "Administ

28 Oct 05, 2022
Simple tools to make/dump CPC+ CPR cartridge files

Simple tools to make/dump CPC+ CPR cartridge files mkcpr.py: make a CPR file from files (one chunk per file); see notes cprdump.py: dump the chunks of

Juan J. Martínez 3 May 30, 2022
A numbers extract from string python package

Made with Python3 (C) @FayasNoushad Copyright permission under MIT License License - https://github.com/FayasNoushad/Numbers-Extract/blob/main/LICENS

Fayas Noushad 4 Nov 28, 2021
TinyBar - Tiny MacOS menu bar utility to track price dynamics for assets on TinyMan.org

📃 About A simple MacOS menu bar app to display current coins from most popular Liquidity Pools on TinyMan.org

Al 8 Dec 23, 2022
Python flexible slugify function

Python flexible slugify function

Dmitry Voronin 471 Dec 20, 2022
Generalise Prometheus metrics. takes out server specific, replaces variables and such.

Generalise Prometheus metrics. takes out server specific, replaces variables and such. makes it easier to copy from Prometheus console straight to Grafana.

ziv 5 Mar 28, 2022
*考研学习利器,玩电脑控制不住自己时,可以使用该程序定日期锁屏,同时有精美壁纸锁屏显示,也不会枯燥。

LockscreenbyTime_win10 A python program in win10. You can set the time to lock the computer(by setting year, month, day), Fullscreen pictures will sho

PixianDouban 4 Jul 10, 2022
Update your Nintendo Switch cheats with one click, or a bit more~

Interactive-ASM-Cheats-Updater This updater unlocks your ability of updating most of the ASM cheats for Nintendo Switch. Table of Contents Functions Q

zzpong 63 Dec 27, 2022
Render to print for blender 2.9+

render_to_print_blender_addon ** render2print: Blender AddOn for Blender 2.90.0+ ** Calculates camera parameters to allow printing a rendered image to

5 Nov 19, 2021
A Python application that simulates the rolling of a dice, randomly picking one of the 6 faces and then displaying it.

dice-roller-app This is an application developed in Python that shuffles between the 6 faces of a dice, using buttons to shuffle and close the applica

Paddy Costelloe 0 Jul 20, 2021
Korg Volca Sample uploader for linux.

GnuVolca Korg Volca Sample uploader for linux. GnuVolca Usage Installation Via virtualenv Usage Store all the samples you want to upload on an empty d

Gonzalo Rafuls 12 Oct 11, 2022
Ingest openldap data into bloodhound

Bloodhound for Linux Ingest a dumped OpenLDAP ldif into neo4j to be visualized in Bloodhound. Usage: ./ldif_to_neo4j.py ./sample.ldif | cypher-shell -

Guillaume Quéré 71 Nov 09, 2022
validation for pre-commit.ci configuration

pre-commit-ci-config validation for pre-commit.ci configuration installation pip install pre-commit-ci-config api pre_commit_ci_config.SCHEMA a cfgv s

pre-commit.ci 17 Jul 11, 2022
BlackMamba is a multi client C2/post exploitation framework

BlackMamba is a multi client C2/post exploitation framework with some spyware features. Powered by Python 3.8.6 and QT Framework.

Gustavo 873 Dec 29, 2022