Monday, January 23, 2023

Convert ImmutableMultiDict with duplicate keys to list of lists in Python

 

Using Werkzeug Python

Werkzeug is a WSGI utility library. WSGI is a protocol or convention that assures that your web application can communicate with the webserver and, more crucially, that web apps can collaborate effectively. To convert an ImmutableMultiDict with duplicate keys to a list of lists, we’ll use one of its function to create ImmutableMultiDict.

We can use the pip command to install the werkzeug library by opening a command line and typing the following command –

pip install werkzeug

Examples 1:

So, initially, we’ll create an immutableMultiDict with duplicate keys using the werkzeug library’s datastructures class, followed by the ImmutableMultiDict() function. After building ImmutableMultiDict, we’ll utilize one of its methods, lists(), to return a generator object, which we’ll convert to a list using the list function.

Python3

from werkzeug.datastructures import ImmutableMultiDict

d = ImmutableMultiDict([('Subject', 'Chemistry'),

                        ('Period', '1st'),

                        ('Period', '4th')])

print(list(d.lists()))

Output:

[('Subject', ['Chemistry']), ('Period', ['1st', '4th'])]

Example 2:

Python3

from werkzeug.datastructures import ImmutableMultiDict

d = ImmutableMultiDict([('Gadget', 'DSLR'),

                        ('Accessories','Lens 18-105mm'), 

                        ('Accessories', 'Lens 70-200mm'), 

                        ('Accessories', 'Tripod stand')])

list(d.lists())

Output:

[(‘Gadget’, [‘DSLR’]), (‘Accessories’, [‘Lens 18-105mm’, ‘Lens 70-200mm’, ‘Tripod stand’])]

  • So, in the first line, we import the ImmutableMultiDict class from the werkzeug module, and we can create ImmutableMultiDict directly using this class. Remember that, unlike standard Dictionaries, MultiDict is a subclass of Dictionary that can have several values for the same key. 
  • We create ImmutableMultiDict and store it in variable ‘d’ in the second line of code. 
  • We’re passing two keys with the same name, ‘Period,’ and if it were a normal dictionary, the one that came later would have overwritten the value, and only one could have been stored, not both separate values of the same key name. 
  • We can now print this ImmutableMultiDict directly, but our goal is to convert it to a list of lists, so we utilize one of its class’s functions .lists() to change the values associated with a single key from tuples to lists. If we want to double-check it, we may use a for loop to print it.
  • Finally, we wrapped it in a list function, which stores it in a list, and then we print it.

Source: www.geeksforgeeks.org

From Werkzeug docs:

class werkzeug.datastructures.TypeConversionDict

Works like a regular dict but the get() method can perform type conversions. MultiDict and CombinedMultiDict are subclasses of this class and provide the same feature.

Changelog
get(key, default=None, type=None)

Return the default value if the requested data doesn’t exist. If type is provided and is a callable it should convert the value, return it or raise a ValueError if that is not possible. In this case the function will return the default as if the value was not found:

d = TypeConversionDict(foo='42', bar='blub')
d.get('foo', type=int)
42
d.get('bar', -1, type=int)
-1
Parameters:
  • key – The key to be looked up.

  • default – The default value to be returned if the key can’t be looked up. If not further specified None is returned.

  • type – A callable that is used to cast the value in the MultiDict. If a ValueError is raised by this callable the default value is returned.

class werkzeug.datastructures.ImmutableTypeConversionDict

Works like a TypeConversionDict but does not support modifications.

Changelog
copy()

Return a shallow mutable copy of this object. Keep in mind that the standard library’s copy() function is a no-op for this class like for any other python immutable type (eg: tuple).

class werkzeug.datastructures.MultiDict(mapping=None)

A MultiDict is a dictionary subclass customized to deal with multiple values for the same key which is for example used by the parsing functions in the wrappers. This is necessary because some HTML form elements pass multiple values for the same key.

MultiDict implements all standard dictionary methods. Internally, it saves all values for a key as a list, but the standard dict access methods will only return the first value for a key. If you want to gain access to the other values, too, you have to use the list methods as explained below.

Basic Usage:

d = MultiDict([('a', 'b'), ('a', 'c')])
d
MultiDict([('a', 'b'), ('a', 'c')])
d['a']
'b'
d.getlist('a')
['b', 'c']
'a' in d
True

It behaves like a normal dict thus all dict functions will only return the first value when multiple values for one key are found.

From Werkzeug 0.3 onwards, the KeyError raised by this class is also a subclass of the BadRequest HTTP exception and will render a page for a 400 BAD REQUEST if caught in a catch-all for HTTP exceptions.

A MultiDict can be constructed from an iterable of (key, value) tuples, a dict, a MultiDict or from Werkzeug 0.2 onwards some keyword parameters.

Parameters:

mapping – the initial value for the MultiDict. Either a regular dict, an iterable of (key, value) tuples or None.

add(key, value)

Adds a new value for the key.

Changelog
Parameters:
  • key – the key for the value.

  • value – the value to add.

clear() None.  Remove all items from D.

copy()

Return a shallow copy of this object.

deepcopy(memo=None)

Return a deep copy of this object.

fromkeys(value=None, /)

Create a new dictionary with keys from iterable and values set to value.

get(key, default=None, type=None)

Return the default value if the requested data doesn’t exist. If type is provided and is a callable it should convert the value, return it or raise a ValueError if that is not possible. In this case the function will return the default as if the value was not found:

d = TypeConversionDict(foo='42', bar='blub')
d.get('foo', type=int)
42
d.get('bar', -1, type=int)
-1
Parameters:
  • key – The key to be looked up.

  • default – The default value to be returned if the key can’t be looked up. If not further specified None is returned.

  • type – A callable that is used to cast the value in the MultiDict. If a ValueError is raised by this callable the default value is returned.

getlist(key, type=None)

Return the list of items for a given key. If that key is not in the MultiDict, the return value will be an empty list. Just like get, getlist accepts a type parameter. All items will be converted with the callable defined there.

Parameters:
  • key – The key to be looked up.

  • type – A callable that is used to cast the value in the MultiDict. If a ValueError is raised by this callable the value will be removed from the list.

Returns:

a list of all the values for the key.

items(multi=False)

Return an iterator of (key, value) pairs.

Parameters:

multi – If set to True the iterator returned will have a pair for each value of each key. Otherwise it will only contain pairs for the first value of each key.

keys() a set-like object providing a view on D's keys

lists()

Return a iterator of (key, values) pairs, where values is the list of all values associated with the key.

listvalues()

Return an iterator of all values associated with a key. Zipping keys() and this is the same as calling lists():

d = MultiDict({"foo": [1, 2, 3]})
zip(d.keys(), d.listvalues()) == d.lists()
True
pop(key, default=no value)

Pop the first item for a list on the dict. Afterwards the key is removed from the dict, so additional values are discarded:

d = MultiDict({"foo": [1, 2, 3]})
d.pop("foo")
1
"foo" in d
False
Parameters:
  • key – the key to pop.

  • default – if provided the value to return if the key was not in the dictionary.

popitem()

Pop an item from the dict.

popitemlist()

Pop a (key, list) tuple from the dict.

poplist(key)

Pop the list for a key from the dict. If the key is not in the dict an empty list is returned.

Changelog
setdefault(key, default=None)

Returns the value for the key if it is in the dict, otherwise it returns default and sets that value for key.

Parameters:
  • key – The key to be looked up.

  • default – The default value to be returned if the key is not in the dict. If not further specified it’s None.

setlist(key, new_list)

Remove the old values for a key and add new ones. Note that the list you pass the values in will be shallow-copied before it is inserted in the dictionary.

d = MultiDict()
d.setlist('foo', ['1', '2'])
d['foo']
'1'
d.getlist('foo')
['1', '2']
Parameters:
  • key – The key for which the values are set.

  • new_list – An iterable with the new values for the key. Old values are removed first.

setlistdefault(key, default_list=None)

Like setdefault but sets multiple values. The list returned is not a copy, but the list that is actually used internally. This means that you can put new values into the dict by appending items to the list:

d = MultiDict({"foo": 1})
d.setlistdefault("foo").extend([2, 3])
d.getlist("foo")
[1, 2, 3]
Parameters:
  • key – The key to be looked up.

  • default_list – An iterable of default values. It is either copied (in case it was a list) or converted into a list before returned.

Returns:

a list

to_dict(flat=True)

Return the contents as regular dict. If flat is True the returned dict will only have the first item present, if flat is False all values will be returned as lists.

Parameters:

flat – If set to False the dict returned will have lists with all the values in it. Otherwise it will only contain the first value for each key.

Returns:

a dict

update(mapping)

update() extends rather than replaces existing key lists:

a = MultiDict({'x': 1})
b = MultiDict({'x': 2, 'y': 3})
a.update(b)
a
MultiDict([('y', 3), ('x', 1), ('x', 2)])

If the value list for a key in other_dict is empty, no new values will be added to the dict and the key will not be created:

x = {'empty_list': []}
y = MultiDict()
y.update(x)
y
MultiDict([])
values()

Returns an iterator of the first value on every key’s value list.

class werkzeug.datastructures.OrderedMultiDict(mapping=None)

Works like a regular MultiDict but preserves the order of the fields. To convert the ordered multi dict into a list you can use the items() method and pass it multi=True.

In general an OrderedMultiDict is an order of magnitude slower than a MultiDict.

note

Due to a limitation in Python you cannot convert an ordered multi dict into a regular dict by using dict(multidict). Instead you have to use the to_dict() method, otherwise the internal bucket objects are exposed.

class werkzeug.datastructures.ImmutableMultiDict(mapping=None)

An immutable MultiDict.

Changelog
copy()

Return a shallow mutable copy of this object. Keep in mind that the standard library’s copy() function is a no-op for this class like for any other python immutable type (eg: tuple).

class werkzeug.datastructures.ImmutableOrderedMultiDict(mapping=None)

An immutable OrderedMultiDict.

Changelog
copy()

Return a shallow mutable copy of this object. Keep in mind that the standard library’s copy() function is a no-op for this class like for any other python immutable type (eg: tuple).

class werkzeug.datastructures.CombinedMultiDict(dicts=None)

A read only MultiDict that you can pass multiple MultiDict instances as sequence and it will combine the return values of all wrapped dicts:

from werkzeug.datastructures import CombinedMultiDict, MultiDict
post = MultiDict([('foo', 'bar')])
get = MultiDict([('blub', 'blah')])
combined = CombinedMultiDict([get, post])
combined['foo']
'bar'
combined['blub']
'blah'

This works for all read operations and will raise a TypeError for methods that usually change data which isn’t possible.

From Werkzeug 0.3 onwards, the KeyError raised by this class is also a subclass of the BadRequest HTTP exception and will render a page for a 400 BAD REQUEST if caught in a catch-all for HTTP exceptions.

class werkzeug.datastructures.ImmutableDict

An immutable dict.

Changelog
copy()

Return a shallow mutable copy of this object. Keep in mind that the standard library’s copy() function is a no-op for this class like for any other python immutable type (eg: tuple).

class werkzeug.datastructures.ImmutableList(iterable=(), /)

An immutable list.

Changelog
Private:


class werkzeug.datastructures.FileMultiDict(mapping=None)

A special MultiDict that has convenience methods to add files to it. This is used for EnvironBuilder and generally useful for unittesting.

Changelog
add_file(name, file, filename=None, content_type=None)

Adds a new file to the dict. file can be a file name or a file-like or a FileStorage object.

Parameters:
  • name – the name of the field.

  • file – a filename or file-like object

  • filename – an optional filename

  • content_type – an optional content type