89 lines
3 KiB
Python
89 lines
3 KiB
Python
|
from typing import Generator
|
||
|
|
||
|
|
||
|
class NestedLookup:
|
||
|
@staticmethod
|
||
|
def __new__(cls, document, references, operation):
|
||
|
"""Lookup a key in a nested document, return a list of values
|
||
|
From https://github.com/russellballestrini/nested-lookup/ but in python 3
|
||
|
"""
|
||
|
return list(NestedLookup._nested_lookup(document, references, operation))
|
||
|
|
||
|
@staticmethod
|
||
|
def key_equality_factory(key_to_find):
|
||
|
def key_equality(key, _):
|
||
|
return key == key_to_find
|
||
|
|
||
|
return key_equality
|
||
|
|
||
|
@staticmethod
|
||
|
def is_sub_type_factory(type):
|
||
|
def _is_sub_type(_, value):
|
||
|
return is_sub_type(value, type)
|
||
|
|
||
|
return _is_sub_type
|
||
|
|
||
|
@staticmethod
|
||
|
def key_value_equality_factory(key_to_find, value_to_find):
|
||
|
def key_value_equality(key, value):
|
||
|
return key == key_to_find and value == value_to_find
|
||
|
|
||
|
return key_value_equality
|
||
|
|
||
|
@staticmethod
|
||
|
def key_value_containing_value_factory(key_to_find, value_to_find):
|
||
|
def key_value_containing_value(key, value):
|
||
|
return key == key_to_find and value_to_find in value
|
||
|
|
||
|
return key_value_containing_value
|
||
|
|
||
|
@staticmethod
|
||
|
def _nested_lookup(document, references, operation):
|
||
|
"""Lookup a key in a nested document, yield a value"""
|
||
|
if isinstance(document, list):
|
||
|
for d in document:
|
||
|
for result in NestedLookup._nested_lookup(d, references, operation):
|
||
|
yield result
|
||
|
|
||
|
if isinstance(document, dict):
|
||
|
for k, v in document.items():
|
||
|
if operation(k, v):
|
||
|
references.append((document, k))
|
||
|
yield v
|
||
|
elif isinstance(v, dict):
|
||
|
for result in NestedLookup._nested_lookup(v, references, operation):
|
||
|
yield result
|
||
|
elif isinstance(v, list):
|
||
|
for d in v:
|
||
|
for result in NestedLookup._nested_lookup(
|
||
|
d, references, operation
|
||
|
):
|
||
|
yield result
|
||
|
|
||
|
|
||
|
def is_sub_type(value, resource_type):
|
||
|
try:
|
||
|
return issubclass(value, resource_type)
|
||
|
except TypeError:
|
||
|
return issubclass(value.__class__, resource_type)
|
||
|
|
||
|
|
||
|
def get_nested_dicts_with_key_value(parent_dict: dict, key, value):
|
||
|
"""Return all nested dictionaries that contain a key with a specific value. A sub-case of NestedLookup."""
|
||
|
references = []
|
||
|
NestedLookup(
|
||
|
parent_dict, references, NestedLookup.key_value_equality_factory(key, value)
|
||
|
)
|
||
|
return (document for document, _ in references)
|
||
|
|
||
|
|
||
|
def get_nested_dicts_with_key_containing_value(parent_dict: dict, key, value):
|
||
|
"""Return all nested dictionaries that contain a key with a specific value. A sub-case of NestedLookup."""
|
||
|
references = []
|
||
|
NestedLookup(
|
||
|
parent_dict,
|
||
|
references,
|
||
|
NestedLookup.key_value_containing_value_factory(key, value),
|
||
|
)
|
||
|
return (document for document, _ in references)
|