1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
from __future__ import annotations
from packaging import version
def find_recursive(list_or_single_dict: list[dict] | dict, wanted: list[dict] | dict) -> bool:
"""
Check if the 'wanted' item(s) sub-dictionary structure is/are present in any of the dictionaries in 'list_or_single_dict'.
'list_or_single_dict' can be either a list of dictionaries or a single dictionary.
"""
def matches_subdict(haystack: dict, needle: dict) -> bool:
"""
Check if all key-value pairs in needle are present in haystack.
This function recursively checks nested dictionaries and lists of dictionaries.
"""
for key, needle_value in needle.items():
if key not in haystack:
return False
haystack_value = haystack[key]
if isinstance(needle_value, dict):
if not isinstance(haystack_value, dict) or not matches_subdict(haystack_value, needle_value):
return False
elif isinstance(needle_value, list):
if not all(
any(matches_subdict(haystack_item, needle_item) for haystack_item in haystack_value)
for needle_item in needle_value
):
return False
else:
if haystack_value != needle_value:
return False
return True
# Turn both args into lists to handle single/multi lookup
if isinstance(list_or_single_dict, dict):
list_or_single_dict = [list_or_single_dict]
if isinstance(wanted, dict):
wanted = [wanted]
return all(any(matches_subdict(item, single_wanted) for item in list_or_single_dict) for single_wanted in wanted)
def should_skip(version_str: str, comparator: str, ref_version_str: str) -> bool:
v = version.parse(version_str)
ref_version = version.parse(ref_version_str)
if (
(comparator == "<=" and v > ref_version) # pylint: disable=too-many-boolean-expressions
or (comparator == ">=" and v < ref_version)
or (comparator == "<" and v >= ref_version)
or (comparator == ">" and v <= ref_version)
):
print(f"Requires version {comparator} {ref_version_str}. Got {v}")
return True
return False
|