Giter VIP home page Giter VIP logo

bidict's Introduction

bidict's People

Contributors

dependabot[bot] avatar gaborbernat avatar github-actions[bot] avatar harrysky avatar jab avatar jbaum98 avatar jmoraleda avatar knaperek avatar leifwalsh avatar leonidgman avatar synapticarbors avatar thetriplev avatar timgates42 avatar tomviner avatar waldyrious avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bidict's Issues

TypeError: unhashable type: 'slice'

Hi Jab, thank you for this great package.

I recently upgraded my bidict to version 11.0 from an older version (bidict==0.9.0.post1), and all of my tests broke.

It seems like the syntax bd[:some_key] is not working anymore.

>>> import bidict
>>> bd = bidict.bidict()
>>> bd["hello"] = "world"
>>> bd[:"world"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/real/.virtualenvs/wchat/lib/python3.4/site-packages/bidict/_common.py", line 57, in __getitem__
    return self._fwd[key]
TypeError: unhashable type: 'slice'

Is this behaviour intentional? I just checked at the docs and it seems like any mention of this syntax is gone.

Not installable from GitHub release tarball

Using the source tarball from releases doesn't allow an installation.

$ tar -xzf bidict-0.21.2.tar.gz 
$ cd bidict-0.21.2/
$ python3 -m venv .
$ source bin/activate
$ python3 setup.py develop
Traceback (most recent call last):
  File "setup.py", line 94, in <module>
    setup(
  File "/home/bidict-0.21.2/lib64/python3.8/site-packages/setuptools/__init__.py", line 145, in setup
    return distutils.core.setup(**attrs)
  File "/usr/lib64/python3.8/distutils/core.py", line 108, in setup
    _setup_distribution = dist = klass(attrs)
  File "/home/bidict-0.21.2/lib64/python3.8/site-packages/setuptools/dist.py", line 446, in __init__
    _Distribution.__init__(self, {
  File "/usr/lib64/python3.8/distutils/dist.py", line 292, in __init__
    self.finalize_options()
  File "/home/bidict-0.21.2/lib64/python3.8/site-packages/setuptools/dist.py", line 735, in finalize_options
    ep.load()(self, ep.name, value)
  File "/home/bidict-0.21.2/.eggs/setuptools_scm-4.1.2-py3.8.egg/setuptools_scm/integration.py", line 17, in version_keyword
    dist.metadata.version = _get_version(config)
  File "/home/bidict-0.21.2/.eggs/setuptools_scm-4.1.2-py3.8.egg/setuptools_scm/__init__.py", line 148, in _get_version
    parsed_version = _do_parse(config)
  File "/home/bidict-0.21.2/.eggs/setuptools_scm-4.1.2-py3.8.egg/setuptools_scm/__init__.py", line 110, in _do_parse
    raise LookupError(
LookupError: setuptools-scm was unable to detect version for '/home/bidict-0.21.2'.

Make sure you're either building from a fully intact git repository or PyPI tarballs. Most other sources (such as GitHub's tarballs, a git checkout without the .git folder) don't contain the necessary metadata and will not work.

For example, if you're using pip, instead of https://github.com/user/proj/archive/master.zip use git+https://github.com/user/proj.git#egg=proj

The tarball seems to be incomplete for the usage with setuptools-scm.

Quick Usage Notice

To quickly provide me with notice of your usage of bidict, please add a reaction to this issue. Hearing that people are using bidict is a powerful antidote to the loneliness of maintaining an open-source project by myself. 😅

Alternatively, you can create a dedicated issue if you'd like to tell me more about how you're using bidict and how it's treating you. I'd love to hear about your use case and if or how bidict could better support it.

Thanks for stopping by. 😊

❤️❤️❤️

Alias `inverse` for `inv` please?

I think exposing inverse in addition to inv would have two benefits:

  1. It would allow code to be written in a way that is more intuitive and self-explanatory.
  2. It would help with discoverability - only a little, but enough to be worthwhile.

1. Intuition and Self-Explanation

I think it's important to remember that there is a big difference between reading .inv when:

  1. You have the word "inverse" or the concept of inversion already in mind.
  2. You don't have the word "inverse" or the concept of inversion in mind.
  3. You couldn't even say when you last used or read the word "inverse".
  4. You don't know the word "inverse".

.inv is really great in the first case, and is decently suggestive in the second case, and it's definitely easier to type, so I like it and think it's good to have it. But I think .inv can be needlessly hard in the third and fourth case.

Because inverse is not a "casual" word - it's easy to forget when we've internalized it and work with inverses of things regularly, but most people first explicitly learn it in technical contexts, like in math or formal logic or computer science.

For many practicing software developers the word itself doesn't come up that often, because when the concept does come up, it can be easier to find more common words to express it.

Relatedly, more and more software developers, both professionally and in open source communities, have English as their second language, or have picked up software as a practical tool without the more formal background.

I think when people are trying to understand some code, whether because they're new to it or haven't worked with it in a long time, having .inverse reduces the amount of mental work they have to use just to idea-fit what the intent is, relative to .inv, especially if they're not yet familiar with bidict as a package.

TL;DR: I love .inv for interactive use and quick work, but I'd like to have the option to write .inverse when it helps people read and understand my code in the long term.

2. Discoverability

I recently tried using bidict for the first time after not thinking about it for maybe four or six months, and I couldn't for the life of me remember off the top of my head how to get the inverse view.

Naturally, because Python is so helpfully discoverable, I did dir(my_bydict_instance) and scanned the output (line-wrapped like it was on my 80-characters-wide terminal):

>>> dir(bd)
['_MutableMapping__marker', '_ON_DUP_OVERWRITE', '__abstractmethods__', '__class
__', '__contains__', '__copy__', '__delattr__', '__delitem__', '__dir__', '__doc
__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__get
state__', '__gt__', '__hash__', '__init__', '__inverted__', '__iter__', '__le__'
, '__len__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduc
e_ex__', '__repr__', '__setattr__', '__setitem__', '__setstate__', '__sizeof__',
 '__slots__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_
negative_cache', '_abc_negative_cache_version', '_abc_registry', '_dedup_item', 
'_fwdm', '_fwdm_cls', '_get_on_dup', '_hash', '_init_inv', '_inv', '_inv_cls', '
_invm', '_invm_cls', '_invweak', '_isdupitem', '_isinv', '_pop', '_put', '_repr_
delegate', '_undo_write', '_update', '_update_with_rollback', '_write_item', 'cl
ear', 'copy', 'forceput', 'forceupdate', 'get', 'inv', 'items', 'keys', 'on_dup_
key', 'on_dup_kv', 'on_dup_val', 'pop', 'popitem', 'put', 'putall', 'setdefault'
, 'update', 'values']

For me, inv just blended in with the other smaller default attributes, and more importantly, it didn't visually pattern-match for the kind of word I most readily thought of while trying to articulate in my head what I wanted.

Consider the appearance if we add an inverse alias in there:

>>> dir(bd)
['_MutableMapping__marker', '_ON_DUP_OVERWRITE', '__abstractmethods__', '__class
__', '__contains__', '__copy__', '__delattr__', '__delitem__', '__dir__', '__doc
__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__get
state__', '__gt__', '__hash__', '__init__', '__inverted__', '__iter__', '__le__'
, '__len__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduc
e_ex__', '__repr__', '__setattr__', '__setitem__', '__setstate__', '__sizeof__',
 '__slots__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_
negative_cache', '_abc_negative_cache_version', '_abc_registry', '_dedup_item', 
'_fwdm', '_fwdm_cls', '_get_on_dup', '_hash', '_init_inv', '_inv', '_inv_cls', '
_invm', '_invm_cls', '_invweak', '_isdupitem', '_isinv', '_pop', '_put', '_repr_
delegate', '_undo_write', '_update', '_update_with_rollback', '_write_item', 'cl
ear', 'copy', 'forceput', 'forceupdate', 'get', 'inv', 'inverse', 'items', 'keys
', 'on_dup_key', 'on_dup_kv', 'on_dup_val', 'pop', 'popitem', 'put', 'putall', '
setdefault', 'update', 'values']

The difference is slight and subtle, but I think it really helps, because if you don't know what word to look for, the word "inverse" jumps out more, and is more likely to visually pattern-match for a brain thinking of other related words like "reverse".

To be clear on that last bit, I fully agree that "inverse" is the more technically correct word than "reverse", and with the reasoning expressed in the Terminology addendum of the docs - that's not what I'm talking about. I'm just saying that we know some people think of "reverse" intuitively when thinking about a bijected mapping, and so having something that visually strongly pattern-matches it is a bonus to discoverability.

TL;DR: I think inverse is more likely to more quickly jump out to a person unless they already know to look for inv, especially if they have the word or similar words in mind already.

Aside on using dir as example to discoverability:

Someone will probably want to reply that I could've just looked up the documentation for bidict on the web instead, or that this would not be an issue on a modern IDE, or that doing help(my_bidict_instance) would've made it easier, so I'm just going to preemptively address those now:

  1. Web searches relative to dir is like the human equivalent of a CPU getting data from disk instead of from L1 cache: it's must more out-of-band and requires orders of magnitude more mental, physical, and temporal overhead, as well as additional external conditions. It's easy to tune it out if you're already used to doing that, because human brains are good at that, but it's really noticeable when you're used to not having to do it.

  2. IDEs and IPython and so on reduce the information-to-noise ratio vs. dir, and can sometimes intelligently display type hints/inferences - still, as I'm sitting here looking at the auto-complete for my_bidict_instance. in a couple of them, in moments when I manage to clear my mind of expectations, inv doesn't really stand out prominently either. It's a lot easier to find, but the discoverability inefficiency isn't so much removed, as "dimmed". (Plus we don't always have access to such conveniences, depending on the systems or situations we're dealing with.)

  3. help provides a completely different kind of discoverability than dir provides: help gives you far more information to wade through, and all that extra information relative to dir is about how the interfaces work, and is useless for the goal of remembering what a specific interface you already have in mind is called. It reduces information-to-noise ratio to use dir instead of help in such cases.

In short, my habit of calling dir first developed because it gets me the right information faster most of the time, despite the unpleasantness and overhead of visually parsing the attribute names from the forest of single-quotes.

But even if dir still doesn't feel like a good example, the overall discoverability point still applies, and even if the discoverability gain doesn't seem worth it, I think the intuition-and-reading-guiding obviousness of the full word is the main argument.

[Doc] subclass of object are hashable by default in python 3.7.1

using ipython with python 3.7.1, I found that

In [95]: class Temp(object):
    ...:     pass
    ...:

In [96]: a = Temp()

In [97]: hash(a)
Out[97]: -9223372036574570836

contradict with the descrpition

This is consistent with the fact that object implements hash(), but subclasses of object are not hashable by default.

in learn from bidict
Do i make this right because the behaviour of hash in new version of python differs
or just I misunderstand sth?

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. :)

Why it returns None when I use bidict?

I have some data of coordinates stored in a bidict,debug info is like this:

(124.60132961215734, 43.75520239658435): (124.6013296121573, 43.7437499999993), (124.47646235458595, 43.762063234912446): (124.4770833333322, 43.756249999999305), (124.591724438498, 43.707862612120465): (124.58541666666568, 43.70208333333264),

Now I want to get key of (124.4770833333322, 43.756249999999305) which in values of the bidict,so I input the code:

source_coord = source_target_dict.get(coord) #coord = (124.4770833333322, 43.756249999999305)

And then debug info told me source coord is None,what happened and how should I solve it?

v0.14.0 breaks viewitems() with Python2.7

viewitems() is no longer working

from bidict import bidict
d = bidict(a="b")
d.viewitems()

Now returns an error:
TypeError: init() takes exactly 2 arguments (1 given)

Looks like this is the cause 033083ca

Thanks,

consider removing namedbidict

To enable me to focus better on more core functionality, I'm considering removing namedbidict. The value it has provided doesn't seem worth the maintenance burden.

Here is a sample of people/orgs whose code would break if this happens:

Everyone please give feedback here, and please spread the word to other bidict users. I'm leaning toward going through with this, but if users' feedback trumps the rationale above, I won't.

github git tags out of sync since 0.18.4

Hi,

I would like to kindly ask if you can push all missing git tags to the corresponding pypi releases to github and also keep git tags in sync in the future?
This would really make it easier to map specific pypi releases to exact commits in the git tree in an easy and convenient way.
Also it would aid in subscribing to github release watch notifications etc.

cheers 🐱

Bug in BidirectionalMapping.__subclasshook__(): Any class with an inverse attribute is considered a collections.abc.Mapping

Importing bidict causes the tfp.sts.Autoregressive class to not work at all. Simplest code to reproduce the problem is as follows
Not sure if the issue is with tfp or bidict.

    import bidict  
    import tensorflow_probability as tfp  
    a=tfp.sts.Autoregressive(order=2)  
AttributeError: 'LinearOperatorDiag' object has not attribute 'keys'

bidict :0.19.0
tf : 2.2.0
tfp:0.10.0
see tensorflow/probability#1016

add performance tests

...to verify that bidict performance is comparable to manually managing two dicts and catch any performance regressions.

Dependency Dashboard

This issue provides visibility into Renovate updates and their statuses. Learn more

Awaiting Schedule

These updates are awaiting their schedule. Click on a checkbox to get an update now.

  • Refresh pip-compile outputs

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.


  • Check this box to trigger a request for Renovate to run again on this repository

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.

is there any simple way to run tests on windows?

I want to check whether your project is compatible with python 3.3. Your classifier only list 3.4 and 3.5.

I've installed py.test - no luck to run tests:

D:\work\OpenSource\bidict.git>py.test tests
usage: py.test [options] [file_or_dir] [file_or_dir] [...]
py.test: error: unrecognized arguments: --benchmark-save-data --benchmark-autosave --benchmark-group-by=name --benchmark-compare
  inifile: D:\work\OpenSource\bidict.git\pytest.ini
  rootdir: D:\work\OpenSource\bidict.git

I've tried python setup.py tests - that commands downloads half of pypi, and then said:

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

I've installed tox because that's what your contributing guide seems to suggest me. It said:

OSError: [WinError 193] %1 is not Win32 application

(that tried to run test.sh under the hood).

What I should try next?

use weakref?

Currently a bidict and its inverse maintain strong references to one another and one another's _fwd and _bwd dicts. Use weakref?

refactor tests

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.

Type hints for Bidict type

Hello,

I am creating a Python package that uses bidict. I'm wondering what type hinting I should assign to this data.

b: bidict[str, str] = bidict(
  {
    "H": "hydrogen",
    "C": "carbon"
  }
)

Is the bidict[str, str] accurate? Thank you.

Thoughts: More than bidirectional functionality?

Hi All,

I came across bidict while searching for a more general application of the functionality in this helpful repo. I was wondering if anyone here can point me towards the data structure I'm looking for or help me expand on bidict to build it.

The data structure I'm looking for can, in O(1) time, go from an element of a collection to getting the rest of the elements in that collection. If the collections are of size 2, this boils down to what bidict does now. In the case where they're not, like

collection = [
    [1, 'hola', 'hello'],
    [2, 'audios', 'goodbye'],
]

I'm hoping to index like collection['goodbye'] and get [2, 'audios', 'goodbye']. The inclusion of the key used to index in the return structure doesn't matter to me.

Questions:

  1. Has anyone else had the need for this type of in memory data structure? Was the O(1) indexing constraint relevent?
  2. Can bidict be easily expanded to do this?

Solutions:

  1. It would be easy to filter the collection for the subcollection of interest, but that's an O(n) process.
  2. As long as all the values are unique across sub collections, I was thinking I could keep a large dictionary of elements in the sub collections to that sub collection. This approach would be close to what bidict does, but with the added constraint that all the elements are unique. My understanding is that bidict currently only requires that all the keys are unique and that all the values are unique. Can someone validate this? If true, is that why bidict doesn't currently take this approach?

Use Case
The real world use case is to avoid making a database call to get simple, unchanging information out of a relational database table. For example, we might store permission levels in an application DB as integers but refer to them in API responses and errors different strings. All elements of the collection relate to the same idea, they're just different representations. One alternative to having a structure like this is to have lots of translation functions. Ex: def db_int_to_API_representation(db_int):. However, as the number of entries in the collections grows, the number of functions needed could grow as its factorial. A more realistic example collection is:

permissions = [
    [1, 'readOnly', 'read_only', 'READ'],
    [2, 'writeOnly', 'write_only', 'WRITE'],
    [3, 'readWrite', 'read_write', 'READWRITE'],
]

List comprehension issue possibly Windows related

Performing a list comp with a bidict results in a 'not defined' error on Windows. Ive tried the same code on OSX 10.10 and it works fine.

In [1]: import bidict

In [2]: bd = bidict.bidict({1: 'a', 2: 'b', 3 : 'c'})

In [3]: bd[:'a']
Out[3]: 1

In [4]: names = [ 'a', 'b', 'c']

In [5]: names = ['a', 'b']

In [6]: keys = [ bd[:x] for x in names ]

NameError Traceback (most recent call last)
----> 1 keys = [ bd[:x] for x in names ]

NameError: name 'bd' is not defined

Code reviewer signup

If you are interested in reviewing changes to bidict, please 👍 (or better yet, comment, so I get an email) on this issue.

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.

Cannot inherit loosebidict

import bidict
class Sub(bidict.loosebidict):
     pass
b = Sub()
b['a'] = 1
....
RecursionError: maximum recursion depth exceeded while calling a Python object

This is because you are calling super(self.__class__, self) instead of super()

consider (k, v) containment check via b[x:y]

Currently if you want to check whether a bidict contains the mapping (k, v), you have to write b.get(k) == v (or b.get(k, sentinel) == v when v is None).

Terry Reedy proposes also allowing b[k:v] to return True or False to perform this check.

bidict imcompatible with deepcopy and pickle

import copy
from bidict import bidict
d = bidict({0: 1, 2: 3})
d2 = copy.deepcopy(d)
x = d2.inv.inv

This raises:

~/Library/...
    169     def inv(self):
    170         """Alias for :attr:`inverse`."""
--> 171         return self.inverse
    172 
    173     def __getstate__(self):

~/Library/...
    159             return self._inv
    160         # Otherwise a weakref is stored in self._invweak. Try to get a strong ref from it.
--> 161         inv = self._invweak()
    162         if inv is not None:
    163             return inv

AttributeError: _invweak

In addition, this also raises the same error:

import pickle
from bidict import bidict
d = bidict({0: 1, 2: 3})
pickle.loads(pickle.dumps(d)).inv.inv

bidict won't pip uninstall from virtualenv

Under python2.7 (at least) on Linux(Ubuntu14.10), pip uninstall from a virtualenv with bidict installed via pip install (using pip v1.5.6) says:
Can't uninstall 'bidict'. No files were found to uninstall.

Yet, at the python prompt:
>>> import bidict
>>> bidict.BidirectionalMapping({"a":1})
BidirectionalMapping({'a': 1})
>>>

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 :)

Remove bidict.invert()

The undocumented bidict.invert() appears to perform an "invert-in-place". This seems superfluous given .inv; but naive use of this method could cause significant confusion about what state a bidict is in at what point in a program (consider beginners in particular). Without this there's no risk of holding a reference to a bidict that flip-flops in semantics.

A more expert programmer who wanted to do an in-place replacement of values, could use the same kind of approach as to mutate a normal dict in-place, eg:

vals = list(d.items())    
d.clear()
d.inv.update(vals)

(Background: I work on a very large project (thousands of developers) where we see every type of mistake under the sun, and I can imagine this accidentally/foolishly being used to mutate global "constant" state causing hard-to-diagnose problems.)

pip install bidicty failure

caffe@CVML:~$ sudo pip install bidict
[sudo] password for caffe:
The directory '/home/caffe/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
The directory '/home/caffe/.cache/pip' or its parent directory is not owned by the current user and caching wheels has been disabled. check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Looking in indexes: http://mirrors.aliyun.com/pypi/simple/
Collecting bidict
Downloading http://mirrors.aliyun.com/pypi/packages/79/a8/83a52f422b1c041758fcfa3ac4438fc92a14e3cbe2b36f97282d973aff55/bidict-0.17.2.tar.gz (266kB)
100% |████████████████████████████████| 276kB 3.9MB/s
Stucked at installing bidict. Anyone offer a solution?

document non-atomicity

Since dict's mutating methods aren't atomic (e.g. d[k] += 1, which is d[k] = d[k] + 1, which presents a race condition such that two threads running it at the same time may each see the same value for d[k], and it ends up set to d[k] + 1 rather than d[k] + 2), bidict's mutating methods aren't atomic either. Worth documenting?

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.

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.