@@ -17,3 +17,57 @@ def unique_everseen(iterable, key=None):
1717 if k not in seen :
1818 seen_add (k )
1919 yield element
20+
21+
22+ # copied from more_itertools 8.8
23+ def always_iterable (obj , base_type = (str , bytes )):
24+ """If *obj* is iterable, return an iterator over its items::
25+
26+ >>> obj = (1, 2, 3)
27+ >>> list(always_iterable(obj))
28+ [1, 2, 3]
29+
30+ If *obj* is not iterable, return a one-item iterable containing *obj*::
31+
32+ >>> obj = 1
33+ >>> list(always_iterable(obj))
34+ [1]
35+
36+ If *obj* is ``None``, return an empty iterable:
37+
38+ >>> obj = None
39+ >>> list(always_iterable(None))
40+ []
41+
42+ By default, binary and text strings are not considered iterable::
43+
44+ >>> obj = 'foo'
45+ >>> list(always_iterable(obj))
46+ ['foo']
47+
48+ If *base_type* is set, objects for which ``isinstance(obj, base_type)``
49+ returns ``True`` won't be considered iterable.
50+
51+ >>> obj = {'a': 1}
52+ >>> list(always_iterable(obj)) # Iterate over the dict's keys
53+ ['a']
54+ >>> list(always_iterable(obj, base_type=dict)) # Treat dicts as a unit
55+ [{'a': 1}]
56+
57+ Set *base_type* to ``None`` to avoid any special handling and treat objects
58+ Python considers iterable as iterable:
59+
60+ >>> obj = 'foo'
61+ >>> list(always_iterable(obj, base_type=None))
62+ ['f', 'o', 'o']
63+ """
64+ if obj is None :
65+ return iter (())
66+
67+ if (base_type is not None ) and isinstance (obj , base_type ):
68+ return iter ((obj ,))
69+
70+ try :
71+ return iter (obj )
72+ except TypeError :
73+ return iter ((obj ,))
0 commit comments