Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MultiDicts again #389

Closed
ivan-kleshnin opened this issue Jun 14, 2013 · 3 comments
Closed

MultiDicts again #389

ivan-kleshnin opened this issue Jun 14, 2013 · 3 comments

Comments

@ivan-kleshnin
Copy link

I naively thought that all python datastructures should have at least similar behavior :)
Lets look on the tests though:

import webob.multidict             # version of Ian Bicking (the guy who introduced the idea)
import werkzeug.utils              # version or Armin Ronacher 
import django.utils.datastructures # version of Django team

#1. The Beginning
webob_multidict = webob.multidict.MultiDict([('username', 'jack')])
werkzeug_multidict = werkzeug.utils.MultiDict([('username', 'jack')])
django_multidict = django.utils.datastructures.MultiValueDict([('username', 'jack')])

>>> webob_multidict['username']    # ok
'jack'
>>> werkzeug_multidict['username'] # ok
'jack'
>>> django_multidict['username']   # ???
'k'

>>> webob_multidict.getall('username')     # ok
['jack']
>>> werkzeug_multidict.getlist('username') # ok
['jack']
>>> django_multidict.getlist('username')   # ???
'jack'

#2. Different default behavior!
webob_multidict = webob.multidict.MultiDict([('username', 'jack'), ('username', 'gizmo')])
werkzeug_multidict = werkzeug.utils.MultiDict([('username', 'jack'), ('username', 'gizmo')])
django_multidict = django.utils.datastructures.MultiValueDict([('username', 'jack'), ('username', 'gizmo')])

>>> webob_multidict['username']            # ??? why not list
'gizmo'
>>> werkzeug_multidict['username']         # ??? why not list
'jack'
>>> django_multidict['username']           # ???
'o'

>>> webob_multidict.getall('username')     # ok
['jack', 'gizmo']
>>> werkzeug_multidict.getlist('username') # ok
['jack', 'gizmo']
>>> django_multidict.getlist('username')   # ???
'gizmo'

#3. Dancing values
webob_multidict = webob.multidict.MultiDict({'username': ['jack', 'gizmo']})
werkzeug_multidict = werkzeug.utils.MultiDict({'username': ['jack', 'gizmo']})
django_multidict = django.utils.datastructures.MultiValueDict({'username': ['jack', 'gizmo']})

>>> webob_multidict['username']             # ok
['jack', 'gizmo']
>>> werkzeug_multidict['username']          # ???
'jack'
>>> django_multidict['username']            # ???
'gizmo'

>>> webob_multidict.getall('username')      # ???
[['jack', 'gizmo']]
>>> werkzeug_multidict.getlist('username')  # ok
['jack', 'gizmo']
>>> django_multidict.getlist('username')    # ok
['jack', 'gizmo']

#4. Here we go
webob_multidict = webob.multidict.MultiDict({'username': []})
werkzeug_multidict = werkzeug.utils.MultiDict({'username': []})
django_multidict = django.utils.datastructures.MultiValueDict({'username': []})

>>> webob_multidict['username']             # ok
[]
>>> werkzeug_multidict['username']          # ???
IndexError: list index out of range
>>> django_multidict['username']            # ok
[]

>>> webob_multidict.getall('username')      # ???
[[]]
>>> werkzeug_multidict.getlist('username')  # ok
[]
>>> django_multidict.getlist('username')    # ok
[]

Doesn't it convince that something wrong is with the whole concept of MultiDict-s?

@untitaker
Copy link
Contributor

0.) You import MultiDict from werkzeug.utils, which is deprecated.

1.) The Beginning

https://github.com/django/django/blob/master/django/utils/datastructures.py#L264
Django's multidict gets instantiated differently. This gives the expected behavior:

django_multidict = django.utils.datastructures.MultiValueDict([('username', ('jack',))])
print django_multidict['username'] # ok!
>>> 'jack'

2.) Different default behavior

We already had the discussion in #287 why __getitem__ doesn't return a
list of values, but just one value. The different behavior of
django_multidict comes from your incorrect usage of it.

3.) Dancing values

WebOb handles builtin dictionaries the same way as lists of tuples, and
this is a reasonable thing to do. It is just as reasonable to do the
opposite thing, see Werkzeug. After all, the general behavior of a
MultiDict is not that well defined, so it's natural that you end up with
slightly different behavior in each implementation. But that doesn't mean
the concept of MultiDicts is broken.

I think a default implementation in the collections stdlib module might
be good as a guideline and help with unification.

4.) Here we go

As said, nobody said the API of all MultiDict implementations will be the same.

@mitsuhiko
Copy link
Contributor

I don't think the original implementation for a multidict came from paste. The one in Werkzeug is an evolved version of the one in Django with some fixes for instantiation. The fact that you ran into the issue with string slicing in the Django version is the reason why the Werkzeug one automatically ensures that there are always internal lists.

It's way too late to change the implementation of all of those I'm afraid. If you have a particular problem with the API in Werkzeug for those multidicts there are always ways to improve I assume.

The design for the multidict in Werkzeug is that it should work exactly like a dict from the view of the user, not from the view of the creator of the multidict as most multidicts are created internally by the request objects and things of that nature.

@ivan-kleshnin
Copy link
Author

I think a default implementation in the collections stdlib module might
be good as a guideline and help with unification.

Hope we'll get one some day. It influences more thing that one can think of.

As said, nobody said the API of all MultiDict implementations will be the same.

Then all libs, working with HTTP request objects must consider not only this marginal (undocumented) type, but implementation details too. What a pity.

The design for the multidict in Werkzeug is that it should work exactly like a dict from the view of the user, not from the view of the creator of the multidict as most multidicts are created internally by the request objects and things of that nature.

I would say it bitten me often enough to bother. At least I've been glad to know that werkzeug's implementation is kinda like django implementation being fixed. That makes things easier.

Thank you guys for answering.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 13, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants