You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
68 lines
2.2 KiB
68 lines
2.2 KiB
4 years ago
|
# -*- coding: utf-8 -*-
|
||
3 years ago
|
# Copyright 2009-2021 Joshua Bronson. All Rights Reserved.
|
||
4 years ago
|
#
|
||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||
|
|
||
|
|
||
3 years ago
|
"""Functions for iterating over items in a mapping."""
|
||
4 years ago
|
|
||
3 years ago
|
import typing as _t
|
||
|
from collections.abc import Mapping
|
||
|
from itertools import chain
|
||
4 years ago
|
|
||
3 years ago
|
from ._typing import KT, VT, IterItems, MapOrIterItems
|
||
4 years ago
|
|
||
|
|
||
3 years ago
|
_NULL_IT: IterItems = iter(())
|
||
4 years ago
|
|
||
|
|
||
3 years ago
|
def _iteritems_mapping_or_iterable(arg: MapOrIterItems[KT, VT]) -> IterItems[KT, VT]:
|
||
4 years ago
|
"""Yield the items in *arg*.
|
||
|
|
||
|
If *arg* is a :class:`~collections.abc.Mapping`, return an iterator over its items.
|
||
|
Otherwise return an iterator over *arg* itself.
|
||
|
"""
|
||
3 years ago
|
return iter(arg.items() if isinstance(arg, Mapping) else arg)
|
||
4 years ago
|
|
||
|
|
||
3 years ago
|
def _iteritems_args_kw(*args: MapOrIterItems[KT, VT], **kw: VT) -> IterItems[KT, VT]:
|
||
4 years ago
|
"""Yield the items from the positional argument (if given) and then any from *kw*.
|
||
|
|
||
|
:raises TypeError: if more than one positional argument is given.
|
||
|
"""
|
||
|
args_len = len(args)
|
||
|
if args_len > 1:
|
||
3 years ago
|
raise TypeError(f'Expected at most 1 positional argument, got {args_len}')
|
||
|
it: IterItems = ()
|
||
4 years ago
|
if args:
|
||
|
arg = args[0]
|
||
|
if arg:
|
||
3 years ago
|
it = _iteritems_mapping_or_iterable(arg)
|
||
4 years ago
|
if kw:
|
||
3 years ago
|
iterkw = iter(kw.items())
|
||
|
it = chain(it, iterkw) if it else iterkw
|
||
|
return it or _NULL_IT
|
||
4 years ago
|
|
||
|
|
||
3 years ago
|
@_t.overload
|
||
|
def inverted(arg: _t.Mapping[KT, VT]) -> IterItems[VT, KT]: ...
|
||
|
@_t.overload
|
||
|
def inverted(arg: IterItems[KT, VT]) -> IterItems[VT, KT]: ...
|
||
|
def inverted(arg: MapOrIterItems[KT, VT]) -> IterItems[VT, KT]:
|
||
4 years ago
|
"""Yield the inverse items of the provided object.
|
||
|
|
||
|
If *arg* has a :func:`callable` ``__inverted__`` attribute,
|
||
|
return the result of calling it.
|
||
|
|
||
|
Otherwise, return an iterator over the items in `arg`,
|
||
|
inverting each item on the fly.
|
||
|
|
||
|
*See also* :attr:`bidict.BidirectionalMapping.__inverted__`
|
||
|
"""
|
||
|
inv = getattr(arg, '__inverted__', None)
|
||
|
if callable(inv):
|
||
3 years ago
|
return inv() # type: ignore [no-any-return]
|
||
4 years ago
|
return ((val, key) for (key, val) in _iteritems_mapping_or_iterable(arg))
|