+import http.cookies
import re
import xml.etree.ElementTree
'Function in set should be a transformation'
assert traverse_obj(_TEST_DATA, (..., {str})) == ['str'], \
'Type in set should be a type filter'
+ assert traverse_obj(_TEST_DATA, (..., {str, int})) == [100, 'str'], \
+ 'Multiple types in set should be a type filter'
assert traverse_obj(_TEST_DATA, {dict}) == _TEST_DATA, \
'A single set should be wrapped into a path'
assert traverse_obj(_TEST_DATA, (..., {str.upper})) == ['STR'], \
'Function in set should be a transformation'
assert traverse_obj(_TEST_DATA, ('fail', {lambda _: 'const'})) == 'const', \
'Function in set should always be called'
- # Sets with length != 1 should raise in debug
+ # Sets with length < 1 or > 1 not including only types should raise
with pytest.raises(Exception):
traverse_obj(_TEST_DATA, set())
with pytest.raises(Exception):
'special transformations should act on current element'
assert traverse_obj(etree, ('country', 0, ..., 'text()', {int_or_none})) == [1, 2008, 141100], \
'special transformations should act on current element'
+
+ def test_traversal_unbranching(self):
+ assert traverse_obj(_TEST_DATA, [(100, 1.2), all]) == [100, 1.2], \
+ '`all` should give all results as list'
+ assert traverse_obj(_TEST_DATA, [(100, 1.2), any]) == 100, \
+ '`any` should give the first result'
+ assert traverse_obj(_TEST_DATA, [100, all]) == [100], \
+ '`all` should give list if non branching'
+ assert traverse_obj(_TEST_DATA, [100, any]) == 100, \
+ '`any` should give single item if non branching'
+ assert traverse_obj(_TEST_DATA, [('dict', 'None', 100), all]) == [100], \
+ '`all` should filter `None` and empty dict'
+ assert traverse_obj(_TEST_DATA, [('dict', 'None', 100), any]) == 100, \
+ '`any` should filter `None` and empty dict'
+ assert traverse_obj(_TEST_DATA, [{
+ 'all': [('dict', 'None', 100, 1.2), all],
+ 'any': [('dict', 'None', 100, 1.2), any],
+ }]) == {'all': [100, 1.2], 'any': 100}, \
+ '`all`/`any` should apply to each dict path separately'
+ assert traverse_obj(_TEST_DATA, [{
+ 'all': [('dict', 'None', 100, 1.2), all],
+ 'any': [('dict', 'None', 100, 1.2), any],
+ }], get_all=False) == {'all': [100, 1.2], 'any': 100}, \
+ '`all`/`any` should apply to dict regardless of `get_all`'
+ assert traverse_obj(_TEST_DATA, [('dict', 'None', 100, 1.2), all, {float}]) is None, \
+ '`all` should reset branching status'
+ assert traverse_obj(_TEST_DATA, [('dict', 'None', 100, 1.2), any, {float}]) is None, \
+ '`any` should reset branching status'
+ assert traverse_obj(_TEST_DATA, [('dict', 'None', 100, 1.2), all, ..., {float}]) == [1.2], \
+ '`all` should allow further branching'
+ assert traverse_obj(_TEST_DATA, [('dict', 'None', 'urls', 'data'), any, ..., 'index']) == [0, 1], \
+ '`any` should allow further branching'
+
+ def test_traversal_morsel(self):
+ values = {
+ 'expires': 'a',
+ 'path': 'b',
+ 'comment': 'c',
+ 'domain': 'd',
+ 'max-age': 'e',
+ 'secure': 'f',
+ 'httponly': 'g',
+ 'version': 'h',
+ 'samesite': 'i',
+ }
+ morsel = http.cookies.Morsel()
+ morsel.set('item_key', 'item_value', 'coded_value')
+ morsel.update(values)
+ values['key'] = 'item_key'
+ values['value'] = 'item_value'
+
+ for key, value in values.items():
+ assert traverse_obj(morsel, key) == value, \
+ 'Morsel should provide access to all values'
+ assert traverse_obj(morsel, ...) == list(values.values()), \
+ '`...` should yield all values'
+ assert traverse_obj(morsel, lambda k, v: True) == list(values.values()), \
+ 'function key should yield all values'
+ assert traverse_obj(morsel, [(None,), any]) == morsel, \
+ 'Morsel should not be implicitly changed to dict on usage'