Source code for woob.browser.filters.json

# Copyright(C) 2014-2021 Romain Bignon
#
# This file is part of woob.
#
# woob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# woob is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with woob. If not, see <http://www.gnu.org/licenses/>.

from __future__ import annotations

from typing import Callable, Any

from .base import _Filter, _NO_DEFAULT, Filter, debug, ItemNotFound


__all__ = ['Dict']


class NotFound:
    def __repr__(self):
        return 'NOT_FOUND'

_NOT_FOUND = NotFound()


[docs]class Dict(Filter): """Filter to find elements in a dictionary or list. Note that a selector defined as None or an empty string will be equivalent to selecting the root of the provided document, as for None. :param selector: Input selector to use on the object. :param default: Default value is an element of the chain is not found, or if a type mismatch occurs. >>> d = {'a': {'b': 'c', 'd': None}} >>> Dict('')(d) {'a': {'b': 'c', 'd': None}} >>> Dict()(d) {'a': {'b': 'c', 'd': None}} >>> Dict('a/b')(d) 'c' >>> Dict('a')(d) {'b': 'c', 'd': None} >>> Dict('notfound')(d) Traceback (most recent call last): ... woob.browser.filters.base.ItemNotFound: Element ['notfound'] not found >>> Dict('notfound', default=None)(d) >>> """ def __init__(self, selector: str | _Filter | Callable | Any | None = None, default: Any = _NO_DEFAULT): super().__init__(default=default) if selector is None or selector == '': self.selector = [] elif isinstance(selector, str): self.selector = selector.split('/') elif callable(selector): self.selector = [selector] else: self.selector = selector def __getitem__(self, name): self.selector.append(name) return self
[docs] @debug() def filter(self, value): if value is _NOT_FOUND: return self.default_or_raise(ItemNotFound(f'Element {self.selector!r} not found' % self.selector)) return value
[docs] @classmethod def select(cls, selector, item, obj=None, key=None): if isinstance(item, (dict, list)): content = item else: content = item.el for el in selector: if isinstance(content, list): el = int(el) elif isinstance(el, _Filter): el._key = key el._obj = obj el = el(item) elif callable(el): el = el(item) try: content = content[el] except (KeyError, IndexError, TypeError): return _NOT_FOUND return content