Skip to content

Commit

Permalink
Apply always_iterable to .files to ensure iterable even when None.
Browse files Browse the repository at this point in the history
  • Loading branch information
jaraco committed Aug 26, 2021
1 parent f00d5c3 commit fd85222
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 2 deletions.
4 changes: 2 additions & 2 deletions importlib_metadata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
pypy_partial,
)
from ._functools import method_cache
from ._itertools import unique_everseen
from ._itertools import unique_everseen, always_iterable
from ._meta import PackageMetadata, SimplePath

from contextlib import suppress
Expand Down Expand Up @@ -1025,6 +1025,6 @@ def _top_level_declared(dist):
def _top_level_inferred(dist):
return {
f.parts[0] if len(f.parts) > 1 else f.with_suffix('').name
for f in dist.files
for f in always_iterable(dist.files)
if f.suffix == ".py"
}
54 changes: 54 additions & 0 deletions importlib_metadata/_itertools.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,57 @@ def unique_everseen(iterable, key=None):
if k not in seen:
seen_add(k)
yield element


# copied from more_itertools 8.8
def always_iterable(obj, base_type=(str, bytes)):
"""If *obj* is iterable, return an iterator over its items::
>>> obj = (1, 2, 3)
>>> list(always_iterable(obj))
[1, 2, 3]
If *obj* is not iterable, return a one-item iterable containing *obj*::
>>> obj = 1
>>> list(always_iterable(obj))
[1]
If *obj* is ``None``, return an empty iterable:
>>> obj = None
>>> list(always_iterable(None))
[]
By default, binary and text strings are not considered iterable::
>>> obj = 'foo'
>>> list(always_iterable(obj))
['foo']
If *base_type* is set, objects for which ``isinstance(obj, base_type)``
returns ``True`` won't be considered iterable.
>>> obj = {'a': 1}
>>> list(always_iterable(obj)) # Iterate over the dict's keys
['a']
>>> list(always_iterable(obj, base_type=dict)) # Treat dicts as a unit
[{'a': 1}]
Set *base_type* to ``None`` to avoid any special handling and treat objects
Python considers iterable as iterable:
>>> obj = 'foo'
>>> list(always_iterable(obj, base_type=None))
['f', 'o', 'o']
"""
if obj is None:
return iter(())

if (base_type is not None) and isinstance(obj, base_type):
return iter((obj,))

try:
return iter(obj)
except TypeError:
return iter((obj,))

0 comments on commit fd85222

Please sign in to comment.