From 6bf9b6aca8a7ded219b54bfa60c4e7dccac05efb Mon Sep 17 00:00:00 2001 From: Martin Wendt Date: Sun, 8 Sep 2024 18:25:13 +0200 Subject: [PATCH 01/11] Add Tree.build_random_tree() --- CHANGELOG.md | 3 +- nutree/test_tree_generator.py | 49 ++++ nutree/tree.py | 7 + nutree/tree_generator.py | 475 ++++++++++++++++++++++++++++++++++ nutree/typed_tree.py | 6 + 5 files changed, 539 insertions(+), 1 deletion(-) create mode 100644 nutree/test_tree_generator.py create mode 100644 nutree/tree_generator.py diff --git a/CHANGELOG.md b/CHANGELOG.md index b44449e..5613e2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # Changelog -## 0.8.1 (unreleased) +## 0.9.0 (unreleased) +- Add TypedTree.build_random_tree() - Fixed #7 Tree.from_dict failing to recreate an arbitrary object tree with a mapper. ## 0.8.0 (2024-03-29) diff --git a/nutree/test_tree_generator.py b/nutree/test_tree_generator.py new file mode 100644 index 0000000..270b9ec --- /dev/null +++ b/nutree/test_tree_generator.py @@ -0,0 +1,49 @@ +""" +Generic tree generator for test data. +""" + +from tree_generator import RangeRandomizer, TextRandomizer, build_random_tree + + +structure_definition = { + "name": "fmea", + #: Types define the default properties of the nodes + "types": { + #: Default properties for all node types + # "*": {":factory": WbNode}, + #: Specific default properties for each node type + "function": {"icon": "bi bi-gear"}, + "failure": {"icon": "bi bi-exclamation-triangle"}, + "cause": {"icon": "bi bi-tools"}, + "effect": {"icon": "bi bi-lightning"}, + }, + #: Relations define the possible parent / child relationships between + #: node types and optionally override the default properties. + "relations": { + "__root__": { + "function": { + ":count": 10, + "title": TextRandomizer(("{i}: Provide $(Noun:plural)",)), + "expanded": True, + }, + }, + "function": { + "failure": { + ":count": RangeRandomizer(1, 3), + "title": TextRandomizer("$(Noun:plural) not provided"), + }, + }, + "failure": { + "cause": { + ":count": RangeRandomizer(1, 3), + "title": TextRandomizer("$(Noun:plural) not provided"), + }, + "effect": { + ":count": RangeRandomizer(1, 3), + "title": TextRandomizer("$(Noun:plural) not provided"), + }, + }, + }, +} +tree = build_random_tree(structure_definition) +tree.print() diff --git a/nutree/tree.py b/nutree/tree.py index 67f96c6..2b24075 100644 --- a/nutree/tree.py +++ b/nutree/tree.py @@ -18,6 +18,7 @@ MermaidFormatType, MermaidNodeMapperCallbackType, ) +from nutree.tree_generator import build_random_tree from .common import ( FILE_FORMAT_VERSION, @@ -842,6 +843,12 @@ def _self_check(self) -> True: assert clone_count == len(node_list) return True + @classmethod + def build_random_tree(cls, structure_def: dict) -> Tree: + """Build a random tree for testing.""" + tt = build_random_tree(cls, structure_def) + return tt + # ------------------------------------------------------------------------------ # - _SystemRootNode diff --git a/nutree/tree_generator.py b/nutree/tree_generator.py new file mode 100644 index 0000000..9928627 --- /dev/null +++ b/nutree/tree_generator.py @@ -0,0 +1,475 @@ +""" +Implements a generator that creates a random tree structure from a specification. + +Returns a nutree.TypedTree with random data from a specification. + +Example: + +```py +from tree_generator import RangeRandomizer, TextRandomizer, generate_tree + + +structure_definition = { + "name": "fmea", + #: Types define the default properties of the nodes + "types": { + #: Default properties for all node types + # "*": {":factory": WbNode}, + #: Specific default properties for each node type + "function": {"icon": "bi bi-gear"}, + "failure": {"icon": "bi bi-exclamation-triangle"}, + "cause": {"icon": "bi bi-tools"}, + "effect": {"icon": "bi bi-lightning"}, + }, + #: Relations define the possible parent / child relationships between + #: node types and optionally override the default properties. + "relations": { + "__root__": { + "function": { + ":count": 10, + "title": TextRandomizer(("{i}: Provide $(Noun:plural)",)), + "expanded": True, + }, + }, + "function": { + "failure": { + ":count": RangeRandomizer(1, 3), + "title": TextRandomizer("$(Noun:plural) not provided"), + }, + }, + "failure": { + "cause": { + ":count": RangeRandomizer(1, 3), + "title": TextRandomizer("$(Noun:plural) not provided"), + }, + "effect": { + ":count": RangeRandomizer(1, 3), + "title": TextRandomizer("$(Noun:plural) not provided"), + }, + }, + }, +} +tree = generate_tree(structure_definition) +tree.print() +``` +""" + +from abc import ABC, abstractmethod + +from datetime import date, datetime, timedelta, timezone +import random +from typing import Any, Sequence, Union + +try: + from fabulist import Fabulist # type: ignore + fab = Fabulist() +except ImportError: + Fabulist = None + fab = None + +from nutree.typed_tree import TypedTree, TypedNode + + +# fab = Fabulist() + + +# ------------------------------------------------------------------------------ +# Generic data object to be used when nutree.Node instances +# ------------------------------------------------------------------------------ + + +class GenericNodeData: + """Used as `node.data` instance in nutree. + + Initialized with a dictionary of values. The values can be accessed + via the `node.data` attribute like `node.data["KEY"]`. + If the Tree is initialized with `shadow_attrs=True`, the values are also + available as attributes of the node like `node.KEY`. + + If the tree is serialized, the values are copied to the serialized data. + + Examples: + + ```py + node = TypedNode(DictNodeData(a=1, b=2)) + tree.add_child(node) + + print(node.a) # 1 + print(node.data["b"]) # 2 + ``` + + Alternatively, the data can be initialized with a dictionary like this: + ```py + d = {"a": 1, "b": 2} + node = TypedNode(DictNodeData(**d)) + ``` + + See https://github.com/mar10/nutree + """ + + def __init__(self, **values) -> None: + self.values: dict = values + + def __repr__(self): + return f"{self.__class__.__name__}<{self.values}>" + + def __getitem__(self, key): + return self.values[key] + + @staticmethod + def serialize_mapper(nutree_node, data): + return nutree_node.data.values.copy() + + +# ------------------------------------------------------------------------------ +# Randomizers +# ------------------------------------------------------------------------------ +class Randomizer(ABC): + """ + Abstract base class for randomizers. + Args: + probability (float, optional): The probability of using the randomizer. + Must be in the range [0.0, 1.0]. Defaults to 1.0. + Attributes: + probability (float): The probability of using the randomizer. + """ + + def __init__(self, *, probability: float = 1.0) -> None: + assert ( + probability is None or 0.0 <= probability <= 1.0 + ), f"probality must be in the range [0.0 .. 1.0]: {probability}" + self.probability = probability + + def _skip_value(self) -> bool: + use = self.probability == 1.0 or random.random() <= self.probability + return not use + + @abstractmethod + def generate(self) -> Any: ... + + +class RangeRandomizer(Randomizer): + """ + A randomizer class that generates random values within a specified range. + + Args: + min_val (Union[float, int]): The minimum value of the range. + max_val (Union[float, int]): The maximum value of the range. + probability (float, optional): The probability of generating a value. Defaults to 1.0. + none_value (Any, optional): The value to return when skipping generation. Defaults to None. + + Returns: + Union[float, int, None]: The generated random value, or none_value if generation is skipped. + """ + + """""" + + def __init__( + self, + min_val: Union[float, int], + max_val: Union[float, int], + *, + probability: float = 1.0, + none_value: Any = None, + ) -> None: + super().__init__(probability=probability) + assert type(min_val) is type(max_val) + self.is_float = type(min_val) is float + self.min = min_val + self.max = max_val + self.none_value = none_value + assert self.max > self.min + + def generate(self) -> Union[float, int, None]: + if self._skip_value(): + return self.none_value + if self.is_float: + return random.uniform(self.min, self.max) + return random.randrange(self.min, self.max) + + +class DateRangeRandomizer(Randomizer): + """ + A randomizer class that generates random dates within a specified range. + + Args: + min_dt (date): The minimum date of the range. + max_dt (Union[date, int]): The maximum date of the range. Pass an integer to specify the number of days from min_dt. + as_js_stamp (bool, optional): If True, return the date as a JavaScript timestamp. Defaults to True. + probability (float, optional): The probability of generating a value. Defaults to 1.0. + """ + + def __init__( + self, + min_dt: date, + max_dt: Union[date, int], + *, + as_js_stamp=True, + probability: float = 1.0, + ) -> None: + super().__init__(probability=probability) + if type(max_dt) in (int, float): + self.delta_days = max_dt + max_dt = min_dt + self.delta_days + else: + self.delta_days = (max_dt - min_dt).days + assert max_dt > min_dt + self.min = min_dt + self.max = max_dt + self.as_js_stamp = as_js_stamp + + def generate(self) -> Union[date, None]: + # print(self.min, self.max, self.delta_days, self.probability) + if self._skip_value(): + # print("SKIP") + return + res = self.min + timedelta(days=random.randrange(self.delta_days)) + # print(res) + if self.as_js_stamp: + ONE_DAY_SEC = 24 * 60 * 60 + dt = datetime(res.year, res.month, res.day) + # print(f"{dt=}") + # print(f"{dt=}, {dt.timestamp()=}") + dt_utc = dt.replace(tzinfo=timezone.utc) + stamp_ms = (dt_utc.timestamp() + ONE_DAY_SEC) * 1000.0 + # print(self.min, self.max, self.delta_days, res, stamp_ms) + res = stamp_ms + return res + + +class ValueRandomizer(Randomizer): + """ + A randomizer class that generates a fixed value with a given probability. + + Args: + value (Any): The value to generate. + probability (float): The probability of generating a value [0.0 .. 1.0]. + """ + + def __init__(self, value: Any, *, probability: float) -> None: + super().__init__(probability=probability) + self.value = value + + def generate(self) -> Any: + if self._skip_value(): + return + return self.value + + +class SparseBoolRandomizer(ValueRandomizer): + """ + A randomizer class that generates a boolean value with a given probability. + If the value is False, it is returned as None. + """ + + def __init__(self, *, probability: float) -> None: + super().__init__(True, probability=probability) + + +class SampleRandomizer(Randomizer): + """ + A randomizer class that generates a random value from a sample list. + """ + + def __init__( + self, sample_list: Sequence, *, counts=None, probability: float = 1.0 + ) -> None: + super().__init__(probability=probability) + self.sample_list = sample_list + self.counts = counts + + def generate(self) -> Any: + if self._skip_value(): + return + return random.sample(self.sample_list, 1, counts=self.counts)[0] + + +# class BoolRandomizer(SampleRandomizer): +# def __init__(self, *, allow_none: bool = False) -> None: +# if allow_none: +# super().__init__((True, False, None)) +# else: +# super().__init__((True, False)) + + +class TextRandomizer(Randomizer): + """ + A randomizer class that generates a random string value from a Fabulist template. + + Uses the [`fabulist`](https://github.com/mar10/fabulist/) library to generate + text values. + + Args: + template (str | list): A template string or list of strings. + probability (float, optional): The probability of generating a value. Defaults to 1.0. + """ + + def __init__(self, template: str | list, *, probability: float = 1.0) -> None: + super().__init__(probability=probability) + if not fab: + raise RuntimeError("Need fabulist installed to generate random text.") + self.template = template + + def generate(self) -> Any: + if self._skip_value(): + return + return fab.get_quote(self.template) + + +class BlindTextRandomizer(Randomizer): + """ + A randomizer class that generates a random lorem ipsum text value from a template. + + Uses the [`fabulist`](https://github.com/mar10/fabulist/) library to generate + text values. + + Args: + sentence_count (int | tuple, optional): The number of sentences to generate. Defaults to (2, 6). + dialect (str, optional): The dialect of the text. Defaults to "ipsum". + entropy (int, optional): The entropy of the text. Defaults to 2. + keep_first (bool, optional): If True, keep the first sentence. Defaults to False. + words_per_sentence (int | tuple, optional): The number of words per sentence. Defaults to (3, 15). + probability (float, optional): The probability of generating a value. Defaults to 1.0. + """ + + def __init__( + self, + *, + sentence_count: int | tuple = (2, 6), + dialect: str = "ipsum", + entropy: int = 2, + keep_first: bool = False, + words_per_sentence: int | tuple = (3, 15), + probability: float = 1.0, + ) -> None: + super().__init__(probability=probability) + if not fab: + raise RuntimeError("Need fabulist installed to generate random text.") + + self.sentence_count = sentence_count + self.dialect = dialect + self.entropy = entropy + self.keep_first = keep_first + self.words_per_sentence = words_per_sentence + + def generate(self) -> Any: + if self._skip_value(): + return + return fab.get_lorem_paragraph( + sentence_count=self.sentence_count, + dialect=self.dialect, + entropy=self.entropy, + keep_first=self.keep_first, + words_per_sentence=self.words_per_sentence, + ) + + +def _resolve_random(val: Any) -> Any: + if isinstance(val, Randomizer): + return val.generate() + return val + + +def _resolve_random_dict(d: dict, *, macros: dict = None) -> None: + remove = [] + for key in d.keys(): + val = d[key] + + if isinstance(val, Randomizer): + val = val.generate() + if val is None: # Skip due to probability + remove.append(key) + else: + d[key] = val + + if macros and isinstance(val, str): + d[key] = val.format(**macros) + + for key in remove: + d.pop(key) + return + + +# ------------------------------------------------------------------------------ +# Tree Builder +# ------------------------------------------------------------------------------ + + +def _merge_specs(node_type: str, spec: dict, types: dict) -> dict: + res = types.get("*", {}).copy() + res.update(types.get(node_type, {})) + res.update(spec) + return res + + +def _make_tree( + *, + parent_node: TypedNode, + parent_type: str, + types: dict, + relations: dict, + prefix: str, +): + child_specs = relations[parent_type] + + for node_type, spec in child_specs.items(): + spec = _merge_specs(node_type, spec, types) + count = spec.pop(":count", 1) + count = _resolve_random(count) or 0 + callback = spec.pop(":callback", None) + factory = spec.pop(":factory", GenericNodeData) + + for i in range(count): + i += 1 # 1-based + p = f"{prefix}.{i}" if prefix else f"{i}" + + # Resolve `Randomizer` values and resolve `{prefix}` and `{i}` macros + data = spec.copy() + + _resolve_random_dict(data, macros={"i": i, "prefix": p}) + + if callback: + callback(data) + + node_data = factory(**data) + + if isinstance(parent_node, TypedNode): + node = parent_node.add_child(node_data, kind=node_type) + else: + node = parent_node.add_child(node_data) + + # Generate child relations + if node_type in relations: + _make_tree( + parent_node=node, + parent_type=node_type, + types=types, + relations=relations, + prefix=p, + ) + + return + + +def build_random_tree(*, tree_class, structure_def: dict) -> TypedTree: + """ + Return a nutree.TypedTree with random data from a specification. + """ + name = structure_def.pop("name", None) + + tree = tree_class(name=name, shadow_attrs=True) + + types = structure_def.pop("types", {}) + relations = structure_def.pop("relations") + assert not structure_def, f"found extra data: {structure_def}" + assert "__root__" in relations, "missing '__root__' relation" + + _make_tree( + parent_node=tree.system_root, + parent_type="__root__", + types=types, + relations=relations, + prefix="", + ) + + return tree diff --git a/nutree/typed_tree.py b/nutree/typed_tree.py index f1841ca..71164c3 100644 --- a/nutree/typed_tree.py +++ b/nutree/typed_tree.py @@ -23,6 +23,7 @@ ValueMapType, call_mapper, ) +from nutree.tree_generator import build_random_tree from .node import Node from .tree import Tree @@ -778,6 +779,11 @@ def load( """ return super().load(target, mapper=mapper, file_meta=file_meta) + @classmethod + def build_random_tree(cls, structure_def: dict) -> TypedTree: + """Build a random tree for testing.""" + tt = build_random_tree(cls, structure_def) + return tt # ------------------------------------------------------------------------------ # - _SystemRootTypedNode From dad5e89b0f253cc518b819879f59e99d9caee0de Mon Sep 17 00:00:00 2001 From: Martin Wendt Date: Mon, 9 Sep 2024 16:21:48 +0200 Subject: [PATCH 02/11] Fix tests and format --- CHANGELOG.md | 3 +- Pipfile | 7 +- Pipfile.lock | 1629 +++++++++++++++++---------------- docs/sphinx/ug_objects.rst | 111 ++- nutree/common.py | 57 +- nutree/test_tree_generator.py | 49 - nutree/tree.py | 22 +- nutree/tree_generator.py | 152 ++- nutree/typed_tree.py | 15 +- tests/test_tree_generator.py | 128 +++ tox.ini | 35 +- 11 files changed, 1251 insertions(+), 957 deletions(-) delete mode 100644 nutree/test_tree_generator.py create mode 100644 tests/test_tree_generator.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 5613e2d..8d28461 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ ## 0.9.0 (unreleased) -- Add TypedTree.build_random_tree() +- Add `Tree.build_random_tree()` +- Add `GenericNodeData` - Fixed #7 Tree.from_dict failing to recreate an arbitrary object tree with a mapper. ## 0.8.0 (2024-03-29) diff --git a/Pipfile b/Pipfile index 8c15a74..b205c36 100644 --- a/Pipfile +++ b/Pipfile @@ -5,10 +5,8 @@ name = "pypi" [dev-packages] black = { version = "~=24.3", extras = ["jupyter"] } +fabulist="*" isort = "*" -# pylint = "*" -# TODO: remove this line: -# pytest-html = "!=3.2.0" # wait for https://github.com/pytest-dev/pytest-html/pull/583 pytest = "*" pytest-cov = "*" PyYAML = "*" @@ -22,9 +20,9 @@ tox = "*" twine = "*" wheel = "*" yabs = "*" -nutree = {path = ".",editable = true} ipykernel = "*" notebook = "*" +nutree = {path = ".",editable = true} [packages] @@ -32,4 +30,3 @@ notebook = "*" python_version = "3.12" [pipenv] -# allow_prereleases = true diff --git a/Pipfile.lock b/Pipfile.lock index c9de180..566da6e 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "5935bcfa3efbb2476994643f35d2c509acabbabe36499683b590fdca3a093dd2" + "sha256": "98a0bcd048aa6b4870c6737ccc39368c1df70ce8bad22db187a05d49b0855bae" }, "pipfile-spec": 6, "requires": { @@ -27,19 +27,11 @@ }, "anyio": { "hashes": [ - "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8", - "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6" + "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94", + "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7" ], "markers": "python_version >= '3.8'", - "version": "==4.3.0" - }, - "appnope": { - "hashes": [ - "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", - "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c" - ], - "markers": "platform_system == 'Darwin'", - "version": "==0.1.4" + "version": "==4.4.0" }, "argon2-cffi": { "hashes": [ @@ -84,14 +76,6 @@ "markers": "python_version >= '3.8'", "version": "==1.3.0" }, - "astroid": { - "hashes": [ - "sha256:951798f922990137ac090c53af473db7ab4e70c770e6d7fae0cec59f74411819", - "sha256:ac248253bfa4bd924a0de213707e7ebeeb3138abeb48d798784ead1e56d419d4" - ], - "markers": "python_full_version >= '3.8.0'", - "version": "==3.1.0" - }, "asttokens": { "hashes": [ "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24", @@ -109,19 +93,19 @@ }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "babel": { "hashes": [ - "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363", - "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287" + "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b", + "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316" ], - "markers": "python_version >= '3.7'", - "version": "==2.14.0" + "markers": "python_version >= '3.8'", + "version": "==2.16.0" }, "beautifulsoup4": { "hashes": [ @@ -136,31 +120,31 @@ "jupyter" ], "hashes": [ - "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f", - "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93", - "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11", - "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0", - "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9", - "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5", - "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213", - "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d", - "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7", - "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837", - "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f", - "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395", - "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995", - "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f", - "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597", - "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959", - "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5", - "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb", - "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4", - "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7", - "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd", - "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7" - ], - "markers": "python_version >= '3.8'", - "version": "==24.3.0" + "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6", + "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e", + "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f", + "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018", + "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e", + "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd", + "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4", + "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed", + "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2", + "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42", + "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af", + "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb", + "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368", + "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb", + "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af", + "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed", + "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47", + "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2", + "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a", + "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c", + "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920", + "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1" + ], + "markers": "python_version >= '3.8'", + "version": "==24.8.0" }, "bleach": { "hashes": [ @@ -172,77 +156,92 @@ }, "cachetools": { "hashes": [ - "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945", - "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105" + "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292", + "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a" ], "markers": "python_version >= '3.7'", - "version": "==5.3.3" + "version": "==5.5.0" }, "certifi": { "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "markers": "python_version >= '3.6'", - "version": "==2024.2.2" + "version": "==2024.8.30" }, "cffi": { "hashes": [ - "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", - "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", - "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", - "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", - "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", - "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", - "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", - "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", - "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", - "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", - "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", - "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", - "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", - "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", - "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", - "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", - "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", - "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", - "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", - "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", - "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", - "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", - "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", - "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", - "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", - "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", - "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", - "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", - "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", - "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", - "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", - "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", - "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", - "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", - "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", - "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", - "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", - "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", - "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", - "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", - "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", - "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", - "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", - "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", - "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", - "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", - "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", - "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", - "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", - "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", - "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", - "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" + "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", + "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", + "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", + "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", + "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", + "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", + "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", + "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", + "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", + "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", + "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", + "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", + "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", + "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", + "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", + "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", + "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", + "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", + "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", + "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", + "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", + "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", + "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", + "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", + "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", + "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", + "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", + "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", + "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", + "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", + "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", + "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", + "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", + "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", + "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", + "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", + "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", + "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", + "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", + "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", + "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", + "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", + "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", + "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", + "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", + "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", + "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", + "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", + "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", + "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", + "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", + "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", + "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", + "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", + "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", + "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", + "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", + "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", + "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", + "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", + "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", + "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", + "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", + "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", + "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", + "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", + "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" ], "markers": "python_version >= '3.8'", - "version": "==1.16.0" + "version": "==1.17.1" }, "chardet": { "hashes": [ @@ -361,7 +360,7 @@ "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", + "markers": "sys_platform == 'win32'", "version": "==0.4.6" }, "comm": { @@ -384,126 +383,141 @@ "toml" ], "hashes": [ - "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c", - "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63", - "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7", - "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f", - "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8", - "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf", - "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0", - "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384", - "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76", - "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7", - "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d", - "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70", - "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f", - "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818", - "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b", - "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d", - "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec", - "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083", - "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2", - "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9", - "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd", - "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade", - "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e", - "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a", - "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227", - "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87", - "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c", - "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e", - "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c", - "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e", - "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd", - "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec", - "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562", - "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8", - "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677", - "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357", - "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c", - "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd", - "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49", - "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286", - "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1", - "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf", - "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51", - "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409", - "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384", - "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e", - "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978", - "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57", - "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e", - "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2", - "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48", - "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4" - ], - "markers": "python_version >= '3.8'", - "version": "==7.4.4" + "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca", + "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d", + "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6", + "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989", + "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c", + "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b", + "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223", + "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f", + "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56", + "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3", + "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8", + "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb", + "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388", + "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0", + "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a", + "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8", + "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f", + "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a", + "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962", + "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8", + "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391", + "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc", + "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2", + "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155", + "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb", + "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0", + "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c", + "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a", + "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004", + "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060", + "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232", + "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93", + "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129", + "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163", + "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de", + "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6", + "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23", + "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569", + "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d", + "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778", + "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d", + "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36", + "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a", + "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6", + "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34", + "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704", + "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106", + "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9", + "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862", + "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b", + "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255", + "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16", + "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3", + "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133", + "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb", + "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657", + "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d", + "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca", + "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36", + "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c", + "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e", + "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff", + "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7", + "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5", + "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02", + "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c", + "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df", + "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3", + "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a", + "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959", + "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234", + "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc" + ], + "markers": "python_version >= '3.8'", + "version": "==7.6.1" }, "cryptography": { "hashes": [ - "sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee", - "sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576", - "sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d", - "sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30", - "sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413", - "sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb", - "sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da", - "sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4", - "sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd", - "sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc", - "sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8", - "sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1", - "sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc", - "sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e", - "sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8", - "sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940", - "sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400", - "sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7", - "sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16", - "sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278", - "sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74", - "sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec", - "sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1", - "sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2", - "sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c", - "sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922", - "sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a", - "sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6", - "sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1", - "sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e", - "sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac", - "sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7" - ], - "version": "==42.0.5" + "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494", + "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806", + "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d", + "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062", + "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2", + "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4", + "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1", + "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85", + "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84", + "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042", + "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d", + "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962", + "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2", + "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa", + "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d", + "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365", + "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96", + "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47", + "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d", + "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d", + "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c", + "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb", + "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277", + "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172", + "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034", + "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a", + "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289" + ], + "version": "==43.0.1" }, "debugpy": { "hashes": [ - "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb", - "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146", - "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8", - "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242", - "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0", - "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741", - "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539", - "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23", - "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3", - "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39", - "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd", - "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9", - "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace", - "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42", - "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0", - "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7", - "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e", - "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234", - "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98", - "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703", - "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42", - "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099" - ], - "markers": "python_version >= '3.8'", - "version": "==1.8.1" + "sha256:0a1029a2869d01cb777216af8c53cda0476875ef02a2b6ff8b2f2c9a4b04176c", + "sha256:1cd04a73eb2769eb0bfe43f5bfde1215c5923d6924b9b90f94d15f207a402226", + "sha256:28ced650c974aaf179231668a293ecd5c63c0a671ae6d56b8795ecc5d2f48d3c", + "sha256:345d6a0206e81eb68b1493ce2fbffd57c3088e2ce4b46592077a943d2b968ca3", + "sha256:3df6692351172a42af7558daa5019651f898fc67450bf091335aa8a18fbf6f3a", + "sha256:4413b7a3ede757dc33a273a17d685ea2b0c09dbd312cc03f5534a0fd4d40750a", + "sha256:4fbb3b39ae1aa3e5ad578f37a48a7a303dad9a3d018d369bc9ec629c1cfa7408", + "sha256:55919dce65b471eff25901acf82d328bbd5b833526b6c1364bd5133754777a44", + "sha256:5b5c770977c8ec6c40c60d6f58cacc7f7fe5a45960363d6974ddb9b62dbee156", + "sha256:606bccba19f7188b6ea9579c8a4f5a5364ecd0bf5a0659c8a5d0e10dcee3032a", + "sha256:7b0fe36ed9d26cb6836b0a51453653f8f2e347ba7348f2bbfe76bfeb670bfb1c", + "sha256:7e4d594367d6407a120b76bdaa03886e9eb652c05ba7f87e37418426ad2079f7", + "sha256:8f913ee8e9fcf9d38a751f56e6de12a297ae7832749d35de26d960f14280750a", + "sha256:a697beca97dad3780b89a7fb525d5e79f33821a8bc0c06faf1f1289e549743cf", + "sha256:ad84b7cde7fd96cf6eea34ff6c4a1b7887e0fe2ea46e099e53234856f9d99a34", + "sha256:b2112cfeb34b4507399d298fe7023a16656fc553ed5246536060ca7bd0e668d0", + "sha256:b78c1250441ce893cb5035dd6f5fc12db968cc07f91cc06996b2087f7cefdd8e", + "sha256:c0a65b00b7cdd2ee0c2cf4c7335fef31e15f1b7056c7fdbce9e90193e1a8c8cb", + "sha256:c9f7c15ea1da18d2fcc2709e9f3d6de98b69a5b0fff1807fb80bc55f906691f7", + "sha256:db9fb642938a7a609a6c865c32ecd0d795d56c1aaa7a7a5722d77855d5e77f2b", + "sha256:dd3811bd63632bb25eda6bd73bea8e0521794cda02be41fa3160eb26fc29e7ed", + "sha256:e84c276489e141ed0b93b0af648eef891546143d6a48f610945416453a8ad406" + ], + "markers": "python_version >= '3.8'", + "version": "==1.8.5" }, "decorator": { "hashes": [ @@ -529,14 +543,6 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.2.14" }, - "dill": { - "hashes": [ - "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca", - "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7" - ], - "markers": "python_version >= '3.11'", - "version": "==0.3.8" - }, "distlib": { "hashes": [ "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784", @@ -554,26 +560,34 @@ }, "executing": { "hashes": [ - "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147", - "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc" + "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf", + "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab" ], - "markers": "python_version >= '3.5'", - "version": "==2.0.1" + "markers": "python_version >= '3.8'", + "version": "==2.1.0" + }, + "fabulist": { + "hashes": [ + "sha256:6306d25164faafd2663a3c2cea4b95e73d8c51bba568fa340ce21fceb2862806", + "sha256:638f1456aa5ec97753db23abf9408fb56c6c78dbe4625a1e487013fceed1bf51" + ], + "index": "pypi", + "version": "==1.2.0" }, "fastjsonschema": { "hashes": [ - "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0", - "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d" + "sha256:3d48fc5300ee96f5d116f10fe6f28d938e6008f59a6a025c2649475b87f76a23", + "sha256:5875f0b0fa7a0043a91e93a9b8f793bcbbba9691e7fd83dca95c28ba26d21f0a" ], - "version": "==2.19.1" + "version": "==2.20.0" }, "filelock": { "hashes": [ - "sha256:5ffa845303983e7a0b7ae17636509bc97997d58afeafa72fb141a17b152284cb", - "sha256:a79895a25bbefdf55d1a2a0a80968f7dbb28edcd6d4234a0afb3f37ecde4b546" + "sha256:81de9eb8453c769b63369f87f11131a7ab04e367f8d97ad39dc230daa07e3bec", + "sha256:f6ed4c963184f4c84dd5557ce8fece759a3724b37b80c6c4f20a2f63a4dc6609" ], "markers": "python_version >= '3.8'", - "version": "==3.13.3" + "version": "==3.16.0" }, "fqdn": { "hashes": [ @@ -592,11 +606,11 @@ }, "gitpython": { "hashes": [ - "sha256:1bf9cd7c9e7255f77778ea54359e54ac22a72a5b51288c457c881057b7bb9ecd", - "sha256:2d99869e0fef71a73cbd242528105af1d6c1b108c60dfabd994bf292f76c3ceb" + "sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c", + "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff" ], "markers": "python_version >= '3.7'", - "version": "==3.1.42" + "version": "==3.1.43" }, "h11": { "hashes": [ @@ -616,19 +630,19 @@ }, "httpx": { "hashes": [ - "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5", - "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5" + "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", + "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2" ], "markers": "python_version >= '3.8'", - "version": "==0.27.0" + "version": "==0.27.2" }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac", + "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603" ], - "markers": "python_version >= '3.5'", - "version": "==3.6" + "markers": "python_version >= '3.6'", + "version": "==3.8" }, "imagesize": { "hashes": [ @@ -640,11 +654,11 @@ }, "importlib-metadata": { "hashes": [ - "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570", - "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2" + "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1", + "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5" ], "markers": "python_version >= '3.8'", - "version": "==7.1.0" + "version": "==8.4.0" }, "iniconfig": { "hashes": [ @@ -656,20 +670,20 @@ }, "ipykernel": { "hashes": [ - "sha256:1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da", - "sha256:3d44070060f9475ac2092b760123fadf105d2e2493c24848b6691a7c4f42af5c" + "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5", + "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==6.29.4" + "version": "==6.29.5" }, "ipython": { "hashes": [ - "sha256:2dcaad9049f9056f1fef63514f176c7d41f930daa78d05b82a176202818f2c14", - "sha256:3c86f284c8f3d8f2b6c662f885c4889a91df7cd52056fd02b7d8d6195d7f56e9" + "sha256:0b99a2dc9f15fd68692e898e5568725c6d49c527d36a9fb5960ffbdeaa82ff7e", + "sha256:f68b3cb8bde357a5d7adc9598d57e22a45dfbea19eb6b98286fa3b288c9cd55c" ], "markers": "python_version >= '3.10'", - "version": "==8.22.2" + "version": "==8.27.0" }, "isodate": { "hashes": [ @@ -696,27 +710,27 @@ }, "jaraco.classes": { "hashes": [ - "sha256:86b534de565381f6b3c1c830d13f931d7be1a75f0081c57dff615578676e2206", - "sha256:cb28a5ebda8bc47d8c8015307d93163464f9f2b91ab4006e09ff0ce07e8bfb30" + "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", + "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790" ], "markers": "python_version >= '3.8'", - "version": "==3.3.1" + "version": "==3.4.0" }, "jaraco.context": { "hashes": [ - "sha256:4dad2404540b936a20acedec53355bdaea223acb88fd329fa6de9261c941566e", - "sha256:5d9e95ca0faa78943ed66f6bc658dd637430f16125d86988e77844c741ff2f11" + "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", + "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4" ], - "markers": "python_version >= '3.7'", - "version": "==4.3.0" + "markers": "python_version >= '3.8'", + "version": "==6.0.1" }, "jaraco.functools": { "hashes": [ - "sha256:c279cb24c93d694ef7270f970d499cab4d3813f4e08273f95398651a634f0925", - "sha256:daf276ddf234bea897ef14f43c4e1bf9eefeac7b7a82a4dd69228ac20acff68d" + "sha256:3460c74cd0d32bf82b9576bbb3527c4364d5b27a21f5158a62aed6c4b42e23f5", + "sha256:c9d16a3ed4ccb5a889ad8e0b7a343401ee5b2a71cee6ed192d3f68bc351e94e3" ], "markers": "python_version >= '3.8'", - "version": "==4.0.0" + "version": "==4.0.2" }, "jedi": { "hashes": [ @@ -728,37 +742,37 @@ }, "jinja2": { "hashes": [ - "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa", - "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90" + "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", + "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d" ], "markers": "python_version >= '3.7'", - "version": "==3.1.3" + "version": "==3.1.4" }, "json5": { "hashes": [ - "sha256:0c638399421da959a20952782800e5c1a78c14e08e1dc9738fa10d8ec14d58c8", - "sha256:4ca101fd5c7cb47960c055ef8f4d0e31e15a7c6c48c3b6f1473fc83b6c462a13" + "sha256:34ed7d834b1341a86987ed52f3f76cd8ee184394906b6e22a1e0deb9ab294e8f", + "sha256:548e41b9be043f9426776f05df8635a00fe06104ea51ed24b67f908856e151ae" ], "markers": "python_version >= '3.8'", - "version": "==0.9.24" + "version": "==0.9.25" }, "jsonpointer": { "hashes": [ - "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a", - "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88" + "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", + "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef" ], - "version": "==2.4" + "version": "==3.0.0" }, "jsonschema": { "extras": [ "format-nongpl" ], "hashes": [ - "sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f", - "sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5" + "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", + "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566" ], "markers": "python_version >= '3.8'", - "version": "==4.21.1" + "version": "==4.23.0" }, "jsonschema-specifications": { "hashes": [ @@ -770,11 +784,11 @@ }, "jupyter-client": { "hashes": [ - "sha256:3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f", - "sha256:e842515e2bab8e19186d89fdfea7abd15e39dd581f94e399f00e2af5a1652d3f" + "sha256:2bda14d55ee5ba58552a8c53ae43d215ad9868853489213f37da060ced54d8df", + "sha256:50cbc5c66fd1b8f65ecb66bc490ab73217993632809b6e505687de18e9dea39f" ], "markers": "python_version >= '3.8'", - "version": "==8.6.1" + "version": "==8.6.2" }, "jupyter-core": { "hashes": [ @@ -794,19 +808,19 @@ }, "jupyter-lsp": { "hashes": [ - "sha256:5e50033149344065348e688608f3c6d654ef06d9856b67655bd7b6bac9ee2d59", - "sha256:da61cb63a16b6dff5eac55c2699cc36eac975645adee02c41bdfc03bf4802e77" + "sha256:45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da", + "sha256:793147a05ad446f809fd53ef1cd19a9f5256fd0a2d6b7ce943a982cb4f545001" ], "markers": "python_version >= '3.8'", - "version": "==2.2.4" + "version": "==2.2.5" }, "jupyter-server": { "hashes": [ - "sha256:77b2b49c3831fbbfbdb5048cef4350d12946191f833a24e5f83e5f8f4803e97b", - "sha256:c80bfb049ea20053c3d9641c2add4848b38073bf79f1729cea1faed32fc1c78e" + "sha256:47ff506127c2f7851a17bf4713434208fc490955d0e8632e95014a9a9afbeefd", + "sha256:66095021aa9638ced276c248b1d81862e4c50f292d575920bbe960de1c56b12b" ], "markers": "python_version >= '3.8'", - "version": "==2.13.0" + "version": "==2.14.2" }, "jupyter-server-terminals": { "hashes": [ @@ -818,11 +832,11 @@ }, "jupyterlab": { "hashes": [ - "sha256:3bc843382a25e1ab7bc31d9e39295a9f0463626692b7995597709c0ab236ab2c", - "sha256:c9ad75290cb10bfaff3624bf3fbb852319b4cce4c456613f8ebbaa98d03524db" + "sha256:73b6e0775d41a9fee7ee756c80f58a6bed4040869ccc21411dc559818874d321", + "sha256:ae7f3a1b8cb88b4f55009ce79fa7c06f99d70cd63601ee4aa91815d054f46f75" ], "markers": "python_version >= '3.8'", - "version": "==4.1.5" + "version": "==4.2.5" }, "jupyterlab-pygments": { "hashes": [ @@ -834,19 +848,19 @@ }, "jupyterlab-server": { "hashes": [ - "sha256:2098198e1e82e0db982440f9b5136175d73bea2cd42a6480aa6fd502cb23c4f9", - "sha256:eb645ecc8f9b24bac5decc7803b6d5363250e16ec5af814e516bc2c54dd88081" + "sha256:e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4", + "sha256:eb36caca59e74471988f0ae25c77945610b887f777255aa21f8065def9e51ed4" ], "markers": "python_version >= '3.8'", - "version": "==2.25.4" + "version": "==2.27.3" }, "keyring": { "hashes": [ - "sha256:9a15cd280338920388e8c1787cb8792b9755dabb3e7c61af5ac1f8cd437cefde", - "sha256:fc024ed53c7ea090e30723e6bd82f58a39dc25d9a6797d866203ecd0ee6306cb" + "sha256:8d85a1ea5d6db8515b59e1c5d1d1678b03cf7fc8b8dcfb1651e8c4a524eb42ef", + "sha256:8d963da00ccdf06e356acd9bf3b743208878751032d8599c6cc89eb51310ffae" ], "markers": "python_version >= '3.8'", - "version": "==25.0.0" + "version": "==25.3.0" }, "markdown-it-py": { "hashes": [ @@ -924,19 +938,11 @@ }, "matplotlib-inline": { "hashes": [ - "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311", - "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304" - ], - "markers": "python_version >= '3.5'", - "version": "==0.1.6" - }, - "mccabe": { - "hashes": [ - "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", - "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" + "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", + "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca" ], - "markers": "python_version >= '3.6'", - "version": "==0.7.0" + "markers": "python_version >= '3.8'", + "version": "==0.1.7" }, "mdurl": { "hashes": [ @@ -956,11 +962,11 @@ }, "more-itertools": { "hashes": [ - "sha256:686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684", - "sha256:8fccb480c43d3e99a00087634c06dd02b0d50fbf088b380de5a41a015ec239e1" + "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", + "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6" ], "markers": "python_version >= '3.8'", - "version": "==10.2.0" + "version": "==10.5.0" }, "mypy-extensions": { "hashes": [ @@ -980,19 +986,19 @@ }, "nbconvert": { "hashes": [ - "sha256:a6733b78ce3d47c3f85e504998495b07e6ea9cf9bf6ec1c98dda63ec6ad19142", - "sha256:ddeff14beeeedf3dd0bc506623e41e4507e551736de59df69a91f86700292b3b" + "sha256:05873c620fe520b6322bf8a5ad562692343fe3452abda5765c7a34b7d1aa3eb3", + "sha256:86ca91ba266b0a448dc96fa6c5b9d98affabde2867b363258703536807f9f7f4" ], "markers": "python_version >= '3.8'", - "version": "==7.16.3" + "version": "==7.16.4" }, "nbformat": { "hashes": [ - "sha256:60ed5e910ef7c6264b87d644f276b1b49e24011930deef54605188ddeb211685", - "sha256:d9476ca28676799af85385f409b49d95e199951477a159a576ef2a675151e5e8" + "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", + "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b" ], "markers": "python_version >= '3.8'", - "version": "==5.10.3" + "version": "==5.10.4" }, "nest-asyncio": { "hashes": [ @@ -1004,33 +1010,33 @@ }, "nh3": { "hashes": [ - "sha256:0316c25b76289cf23be6b66c77d3608a4fdf537b35426280032f432f14291b9a", - "sha256:1a814dd7bba1cb0aba5bcb9bebcc88fd801b63e21e2450ae6c52d3b3336bc911", - "sha256:1aa52a7def528297f256de0844e8dd680ee279e79583c76d6fa73a978186ddfb", - "sha256:22c26e20acbb253a5bdd33d432a326d18508a910e4dcf9a3316179860d53345a", - "sha256:40015514022af31975c0b3bca4014634fa13cb5dc4dbcbc00570acc781316dcc", - "sha256:40d0741a19c3d645e54efba71cb0d8c475b59135c1e3c580f879ad5514cbf028", - "sha256:551672fd71d06cd828e282abdb810d1be24e1abb7ae2543a8fa36a71c1006fe9", - "sha256:66f17d78826096291bd264f260213d2b3905e3c7fae6dfc5337d49429f1dc9f3", - "sha256:85cdbcca8ef10733bd31f931956f7fbb85145a4d11ab9e6742bbf44d88b7e351", - "sha256:a3f55fabe29164ba6026b5ad5c3151c314d136fd67415a17660b4aaddacf1b10", - "sha256:b4427ef0d2dfdec10b641ed0bdaf17957eb625b2ec0ea9329b3d28806c153d71", - "sha256:ba73a2f8d3a1b966e9cdba7b211779ad8a2561d2dba9674b8a19ed817923f65f", - "sha256:c21bac1a7245cbd88c0b0e4a420221b7bfa838a2814ee5bb924e9c2f10a1120b", - "sha256:c551eb2a3876e8ff2ac63dff1585236ed5dfec5ffd82216a7a174f7c5082a78a", - "sha256:c790769152308421283679a142dbdb3d1c46c79c823008ecea8e8141db1a2062", - "sha256:d7a25fd8c86657f5d9d576268e3b3767c5cd4f42867c9383618be8517f0f022a" - ], - "version": "==0.2.17" + "sha256:0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164", + "sha256:14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86", + "sha256:19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b", + "sha256:34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad", + "sha256:36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204", + "sha256:3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a", + "sha256:42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200", + "sha256:5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189", + "sha256:6955369e4d9f48f41e3f238a9e60f9410645db7e07435e62c6a9ea6135a4907f", + "sha256:7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811", + "sha256:8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844", + "sha256:94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4", + "sha256:a7f1b5b2c15866f2db413a3649a8fe4fd7b428ae58be2c0f6bca5eefd53ca2be", + "sha256:c8b3a1cebcba9b3669ed1a84cc65bf005728d2f0bc1ed2a6594a992e817f3a50", + "sha256:de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307", + "sha256:f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe" + ], + "version": "==0.2.18" }, "notebook": { "hashes": [ - "sha256:efc2c80043909e0faa17fce9e9b37c059c03af0ec99a4d4db84cb21d9d2e936a", - "sha256:fc6c24b9aef18d0cd57157c9c47e95833b9b0bdc599652639acf0bdb61dc7d5f" + "sha256:2ef07d4220421623ad3fe88118d687bc0450055570cdd160814a59cf3a1c516e", + "sha256:c89264081f671bc02eec0ed470a627ed791b9156cad9285226b31611d3e9fe1c" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==7.1.2" + "version": "==7.2.2" }, "notebook-shim": { "hashes": [ @@ -1054,11 +1060,11 @@ }, "packaging": { "hashes": [ - "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", - "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" + "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", + "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" ], - "markers": "python_version >= '3.7'", - "version": "==24.0" + "markers": "python_version >= '3.8'", + "version": "==24.1" }, "pandocfilters": { "hashes": [ @@ -1070,11 +1076,11 @@ }, "parso": { "hashes": [ - "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0", - "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75" + "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", + "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d" ], "markers": "python_version >= '3.6'", - "version": "==0.8.3" + "version": "==0.8.4" }, "pathspec": { "hashes": [ @@ -1084,14 +1090,6 @@ "markers": "python_version >= '3.8'", "version": "==0.12.1" }, - "pexpect": { - "hashes": [ - "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", - "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f" - ], - "markers": "sys_platform != 'win32' and sys_platform != 'emscripten'", - "version": "==4.9.0" - }, "pkginfo": { "hashes": [ "sha256:5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297", @@ -1102,19 +1100,19 @@ }, "platformdirs": { "hashes": [ - "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", - "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768" + "sha256:9e5e27a08aa095dd127b9f2e764d74254f482fef22b0970773bfba79d091ab8c", + "sha256:eb1c8582560b34ed4ba105009a4badf7f6f85768b30126f351328507b2beb617" ], "markers": "python_version >= '3.8'", - "version": "==4.2.0" + "version": "==4.3.2" }, "pluggy": { "hashes": [ - "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981", - "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be" + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" ], "markers": "python_version >= '3.8'", - "version": "==1.4.0" + "version": "==1.5.0" }, "prometheus-client": { "hashes": [ @@ -1126,90 +1124,76 @@ }, "prompt-toolkit": { "hashes": [ - "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d", - "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6" + "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10", + "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360" ], "markers": "python_full_version >= '3.7.0'", - "version": "==3.0.43" + "version": "==3.0.47" }, "psutil": { "hashes": [ - "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d", - "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73", - "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8", - "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2", - "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e", - "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36", - "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7", - "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c", - "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee", - "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421", - "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf", - "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81", - "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0", - "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631", - "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4", - "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8" + "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35", + "sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0", + "sha256:1e7c870afcb7d91fdea2b37c24aeb08f98b6d67257a5cb0a8bc3ac68d0f1a68c", + "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1", + "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3", + "sha256:34859b8d8f423b86e4385ff3665d3f4d94be3cdf48221fbe476e883514fdb71c", + "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd", + "sha256:6ec7588fb3ddaec7344a825afe298db83fe01bfaaab39155fa84cf1c0d6b13c3", + "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0", + "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2", + "sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6", + "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d", + "sha256:a9a3dbfb4de4f18174528d87cc352d1f788b7496991cca33c6996f40c9e3c92c", + "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0", + "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132", + "sha256:fc8c9510cde0146432bbdb433322861ee8c3efbf8589865c8bf8d21cb30c4d14", + "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==5.9.8" - }, - "ptyprocess": { - "hashes": [ - "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", - "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220" - ], - "version": "==0.7.0" + "version": "==6.0.0" }, "pure-eval": { "hashes": [ - "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350", - "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3" + "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", + "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42" ], - "version": "==0.2.2" + "version": "==0.2.3" }, "pycparser": { "hashes": [ - "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", - "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" + "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", + "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc" ], - "version": "==2.21" + "markers": "python_version >= '3.8'", + "version": "==2.22" }, "pygithub": { "hashes": [ - "sha256:0148d7347a1cdeed99af905077010aef81a4dad988b0ba51d4108bf66b443f7e", - "sha256:65b499728be3ce7b0cd2cd760da3b32f0f4d7bc55e5e0677617f90f6564e793e" + "sha256:6601e22627e87bac192f1e2e39c6e6f69a43152cfb8f307cee575879320b3051", + "sha256:81935aa4bdc939fba98fee1cb47422c09157c56a27966476ff92775602b9ee24" ], - "markers": "python_version >= '3.7'", - "version": "==2.3.0" + "markers": "python_version >= '3.8'", + "version": "==2.4.0" }, "pygments": { "hashes": [ - "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c", - "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367" + "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", + "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a" ], - "markers": "python_version >= '3.7'", - "version": "==2.17.2" + "markers": "python_version >= '3.8'", + "version": "==2.18.0" }, "pyjwt": { "extras": [ "crypto" ], "hashes": [ - "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de", - "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320" + "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850", + "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c" ], - "markers": "python_version >= '3.7'", - "version": "==2.8.0" - }, - "pylint": { - "hashes": [ - "sha256:507a5b60953874766d8a366e8e8c7af63e058b26345cfcb5f91f89d987fd6b74", - "sha256:6a69beb4a6f63debebaab0a3477ecd0f559aa726af4954fc948c51f7a2549e23" - ], - "index": "pypi", - "markers": "python_full_version >= '3.8.0'", - "version": "==3.1.0" + "markers": "python_version >= '3.8'", + "version": "==2.9.0" }, "pynacl": { "hashes": [ @@ -1229,28 +1213,28 @@ }, "pyparsing": { "hashes": [ - "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad", - "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742" + "sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c", + "sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032" ], "markers": "python_full_version >= '3.6.8'", - "version": "==3.1.2" + "version": "==3.1.4" }, "pyproject-api": { "hashes": [ - "sha256:1817dc018adc0d1ff9ca1ed8c60e1623d5aaca40814b953af14a9cf9a5cae538", - "sha256:4c0116d60476b0786c88692cf4e325a9814965e2469c5998b830bba16b183675" + "sha256:2dc1654062c2b27733d8fd4cdda672b22fe8741ef1dde8e3a998a9547b071eeb", + "sha256:7ebc6cd10710f89f4cf2a2731710a98abce37ebff19427116ff2174c9236a827" ], "markers": "python_version >= '3.8'", - "version": "==1.6.1" + "version": "==1.7.1" }, "pytest": { "hashes": [ - "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7", - "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044" + "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5", + "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==8.1.1" + "version": "==8.3.2" }, "pytest-cov": { "hashes": [ @@ -1277,161 +1261,219 @@ "markers": "python_version >= '3.6'", "version": "==2.0.7" }, + "pywin32": { + "hashes": [ + "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d", + "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65", + "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e", + "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b", + "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4", + "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040", + "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a", + "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36", + "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8", + "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e", + "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802", + "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a", + "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407", + "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0" + ], + "markers": "sys_platform == 'win32' and platform_python_implementation != 'PyPy'", + "version": "==306" + }, + "pywin32-ctypes": { + "hashes": [ + "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", + "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755" + ], + "markers": "sys_platform == 'win32'", + "version": "==0.2.3" + }, + "pywinpty": { + "hashes": [ + "sha256:2fd876b82ca750bb1333236ce98488c1be96b08f4f7647cfdf4129dfad83c2d4", + "sha256:61d420c2116c0212808d31625611b51caf621fe67f8a6377e2e8b617ea1c1f7d", + "sha256:697bff211fb5a6508fee2dc6ff174ce03f34a9a233df9d8b5fe9c8ce4d5eaf56", + "sha256:71cb613a9ee24174730ac7ae439fd179ca34ccb8c5349e8d7b72ab5dea2c6f4b", + "sha256:b96fb14698db1284db84ca38c79f15b4cfdc3172065b5137383910567591fa99", + "sha256:c34e32351a3313ddd0d7da23d27f835c860d32fe4ac814d372a3ea9594f41dde" + ], + "markers": "os_name == 'nt'", + "version": "==2.0.13" + }, "pyyaml": { "hashes": [ - "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", - "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", - "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", - "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", - "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", - "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", - "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", - "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", - "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", - "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", - "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", - "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", - "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", - "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", - "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", - "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", - "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", - "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", - "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", - "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", - "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", - "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", - "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", - "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", - "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", - "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", - "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", - "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", - "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", - "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", - "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", - "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", - "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", - "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", - "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", - "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", - "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", - "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", - "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", - "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", - "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", - "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", - "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", - "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", - "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", - "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", - "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", - "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", - "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", - "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", - "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" ], - "markers": "python_version >= '3.6'", - "version": "==6.0.1" + "markers": "python_version >= '3.8'", + "version": "==6.0.2" }, "pyzmq": { "hashes": [ - "sha256:004ff469d21e86f0ef0369717351073e0e577428e514c47c8480770d5e24a565", - "sha256:00a06faa7165634f0cac1abb27e54d7a0b3b44eb9994530b8ec73cf52e15353b", - "sha256:00c48ae2fd81e2a50c3485de1b9d5c7c57cd85dc8ec55683eac16846e57ac979", - "sha256:01171fc48542348cd1a360a4b6c3e7d8f46cdcf53a8d40f84db6707a6768acc1", - "sha256:019744b99da30330798bb37df33549d59d380c78e516e3bab9c9b84f87a9592f", - "sha256:02bbc1a87b76e04fd780b45e7f695471ae6de747769e540da909173d50ff8e2d", - "sha256:02c9087b109070c5ab0b383079fa1b5f797f8d43e9a66c07a4b8b8bdecfd88ee", - "sha256:07cd61a20a535524906595e09344505a9bd46f1da7a07e504b315d41cd42eb07", - "sha256:0806175f2ae5ad4b835ecd87f5f85583316b69f17e97786f7443baaf54b9bb98", - "sha256:09dfe949e83087da88c4a76767df04b22304a682d6154de2c572625c62ad6886", - "sha256:0dabfb10ef897f3b7e101cacba1437bd3a5032ee667b7ead32bbcdd1a8422fe7", - "sha256:0ddd6d71d4ef17ba5a87becf7ddf01b371eaba553c603477679ae817a8d84d75", - "sha256:0f513130c4c361201da9bc69df25a086487250e16b5571ead521b31ff6b02220", - "sha256:0f97bc2f1f13cb16905a5f3e1fbdf100e712d841482b2237484360f8bc4cb3d7", - "sha256:11e70516688190e9c2db14fcf93c04192b02d457b582a1f6190b154691b4c93a", - "sha256:146b9b1f29ead41255387fb07be56dc29639262c0f7344f570eecdcd8d683314", - "sha256:16b726c1f6c2e7625706549f9dbe9b06004dfbec30dbed4bf50cbdfc73e5b32a", - "sha256:1b3cbba2f47062b85fe0ef9de5b987612140a9ba3a9c6d2543c6dec9f7c2ab27", - "sha256:1b9b1f2ad6498445a941d9a4fee096d387fee436e45cc660e72e768d3d8ee611", - "sha256:1ec23bd7b3a893ae676d0e54ad47d18064e6c5ae1fadc2f195143fb27373f7f6", - "sha256:246747b88917e4867e2367b005fc8eefbb4a54b7db363d6c92f89d69abfff4b6", - "sha256:25c2dbb97d38b5ac9fd15586e048ec5eb1e38f3d47fe7d92167b0c77bb3584e9", - "sha256:2c6441e0398c2baacfe5ba30c937d274cfc2dc5b55e82e3749e333aabffde561", - "sha256:2c9a79f1d2495b167119d02be7448bfba57fad2a4207c4f68abc0bab4b92925b", - "sha256:2e2713ef44be5d52dd8b8e2023d706bf66cb22072e97fc71b168e01d25192755", - "sha256:313c3794d650d1fccaaab2df942af9f2c01d6217c846177cfcbc693c7410839e", - "sha256:3516e0b6224cf6e43e341d56da15fd33bdc37fa0c06af4f029f7d7dfceceabbc", - "sha256:359f7f74b5d3c65dae137f33eb2bcfa7ad9ebefd1cab85c935f063f1dbb245cc", - "sha256:39b1067f13aba39d794a24761e385e2eddc26295826530a8c7b6c6c341584289", - "sha256:3c00c9b7d1ca8165c610437ca0c92e7b5607b2f9076f4eb4b095c85d6e680a1d", - "sha256:3c53687dde4d9d473c587ae80cc328e5b102b517447456184b485587ebd18b62", - "sha256:3e124e6b1dd3dfbeb695435dff0e383256655bb18082e094a8dd1f6293114642", - "sha256:4345c9a27f4310afbb9c01750e9461ff33d6fb74cd2456b107525bbeebcb5be3", - "sha256:45999e7f7ed5c390f2e87ece7f6c56bf979fb213550229e711e45ecc7d42ccb8", - "sha256:49151b0efece79f6a79d41a461d78535356136ee70084a1c22532fc6383f4ad0", - "sha256:4cb8fc1f8d69b411b8ec0b5f1ffbcaf14c1db95b6bccea21d83610987435f1a4", - "sha256:4e5837af3e5aaa99a091302df5ee001149baff06ad22b722d34e30df5f0d9097", - "sha256:4e6f689880d5ad87918430957297c975203a082d9a036cc426648fcbedae769b", - "sha256:5074adeacede5f810b7ef39607ee59d94e948b4fd954495bdb072f8c54558181", - "sha256:518efd91c3d8ac9f9b4f7dd0e2b7b8bf1a4fe82a308009016b07eaa48681af82", - "sha256:55875492f820d0eb3417b51d96fea549cde77893ae3790fd25491c5754ea2f68", - "sha256:5a68d491fc20762b630e5db2191dd07ff89834086740f70e978bb2ef2668be08", - "sha256:5dde6751e857910c1339890f3524de74007958557593b9e7e8c5f01cd919f8a7", - "sha256:5e319ed7d6b8f5fad9b76daa0a68497bc6f129858ad956331a5835785761e003", - "sha256:5edac3f57c7ddaacdb4d40f6ef2f9e299471fc38d112f4bc6d60ab9365445fb0", - "sha256:6cc0020b74b2e410287e5942e1e10886ff81ac77789eb20bec13f7ae681f0fdd", - "sha256:6dd0d50bbf9dca1d0bdea219ae6b40f713a3fb477c06ca3714f208fd69e16fd8", - "sha256:7598d2ba821caa37a0f9d54c25164a4fa351ce019d64d0b44b45540950458840", - "sha256:759cfd391a0996345ba94b6a5110fca9c557ad4166d86a6e81ea526c376a01e8", - "sha256:7ae8f354b895cbd85212da245f1a5ad8159e7840e37d78b476bb4f4c3f32a9fe", - "sha256:7b6d09a8962a91151f0976008eb7b29b433a560fde056ec7a3db9ec8f1075438", - "sha256:7c61e346ac34b74028ede1c6b4bcecf649d69b707b3ff9dc0fab453821b04d1e", - "sha256:7f51a7b4ead28d3fca8dda53216314a553b0f7a91ee8fc46a72b402a78c3e43d", - "sha256:82544e0e2d0c1811482d37eef297020a040c32e0687c1f6fc23a75b75db8062c", - "sha256:8807c87fa893527ae8a524c15fc505d9950d5e856f03dae5921b5e9aa3b8783b", - "sha256:889370d5174a741a62566c003ee8ddba4b04c3f09a97b8000092b7ca83ec9c49", - "sha256:8b14c75979ce932c53b79976a395cb2a8cd3aaf14aef75e8c2cb55a330b9b49d", - "sha256:8c5f80e578427d4695adac6fdf4370c14a2feafdc8cb35549c219b90652536ae", - "sha256:8e9f3fabc445d0ce320ea2c59a75fe3ea591fdbdeebec5db6de530dd4b09412e", - "sha256:93f1aa311e8bb912e34f004cf186407a4e90eec4f0ecc0efd26056bf7eda0226", - "sha256:94504ff66f278ab4b7e03e4cba7e7e400cb73bfa9d3d71f58d8972a8dc67e7a6", - "sha256:967668420f36878a3c9ecb5ab33c9d0ff8d054f9c0233d995a6d25b0e95e1b6b", - "sha256:9880078f683466b7f567b8624bfc16cad65077be046b6e8abb53bed4eeb82dd3", - "sha256:99a6b36f95c98839ad98f8c553d8507644c880cf1e0a57fe5e3a3f3969040882", - "sha256:9a18fff090441a40ffda8a7f4f18f03dc56ae73f148f1832e109f9bffa85df15", - "sha256:9add2e5b33d2cd765ad96d5eb734a5e795a0755f7fc49aa04f76d7ddda73fd70", - "sha256:a793ac733e3d895d96f865f1806f160696422554e46d30105807fdc9841b9f7d", - "sha256:a86c2dd76ef71a773e70551a07318b8e52379f58dafa7ae1e0a4be78efd1ff16", - "sha256:a8c1d566344aee826b74e472e16edae0a02e2a044f14f7c24e123002dcff1c05", - "sha256:ac170e9e048b40c605358667aca3d94e98f604a18c44bdb4c102e67070f3ac9b", - "sha256:b264bf2cc96b5bc43ce0e852be995e400376bd87ceb363822e2cb1964fcdc737", - "sha256:b8c8a419dfb02e91b453615c69568442e897aaf77561ee0064d789705ff37a92", - "sha256:bc69c96735ab501419c432110016329bf0dea8898ce16fab97c6d9106dc0b348", - "sha256:bef02cfcbded83473bdd86dd8d3729cd82b2e569b75844fb4ea08fee3c26ae41", - "sha256:c0b5ca88a8928147b7b1e2dfa09f3b6c256bc1135a1338536cbc9ea13d3b7add", - "sha256:cc69949484171cc961e6ecd4a8911b9ce7a0d1f738fcae717177c231bf77437b", - "sha256:ced111c2e81506abd1dc142e6cd7b68dd53747b3b7ae5edbea4578c5eeff96b7", - "sha256:d1299d7e964c13607efd148ca1f07dcbf27c3ab9e125d1d0ae1d580a1682399d", - "sha256:d1b604734bec94f05f81b360a272fc824334267426ae9905ff32dc2be433ab96", - "sha256:d9a5f194cf730f2b24d6af1f833c14c10f41023da46a7f736f48b6d35061e76e", - "sha256:db36c27baed588a5a8346b971477b718fdc66cf5b80cbfbd914b4d6d355e44e2", - "sha256:df0c7a16ebb94452d2909b9a7b3337940e9a87a824c4fc1c7c36bb4404cb0cde", - "sha256:e10a4b5a4b1192d74853cc71a5e9fd022594573926c2a3a4802020360aa719d8", - "sha256:e624c789359f1a16f83f35e2c705d07663ff2b4d4479bad35621178d8f0f6ea4", - "sha256:e690145a8c0c273c28d3b89d6fb32c45e0d9605b2293c10e650265bf5c11cfec", - "sha256:ea1608dd169da230a0ad602d5b1ebd39807ac96cae1845c3ceed39af08a5c6df", - "sha256:ea253b368eb41116011add00f8d5726762320b1bda892f744c91997b65754d73", - "sha256:eb7e49a17fb8c77d3119d41a4523e432eb0c6932187c37deb6fbb00cc3028088", - "sha256:ef12e259e7bc317c7597d4f6ef59b97b913e162d83b421dd0db3d6410f17a244", - "sha256:f8429b17cbb746c3e043cb986328da023657e79d5ed258b711c06a70c2ea7537", - "sha256:fa99973d2ed20417744fca0073390ad65ce225b546febb0580358e36aa90dba6", - "sha256:faf79a302f834d9e8304fafdc11d0d042266667ac45209afa57e5efc998e3872", - "sha256:fc31baa0c32a2ca660784d5af3b9487e13b61b3032cb01a115fce6588e1bed30" + "sha256:007137c9ac9ad5ea21e6ad97d3489af654381324d5d3ba614c323f60dab8fae6", + "sha256:034da5fc55d9f8da09015d368f519478a52675e558c989bfcb5cf6d4e16a7d2a", + "sha256:05590cdbc6b902101d0e65d6a4780af14dc22914cc6ab995d99b85af45362cc9", + "sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f", + "sha256:0aca98bc423eb7d153214b2df397c6421ba6373d3397b26c057af3c904452e37", + "sha256:0bed0e799e6120b9c32756203fb9dfe8ca2fb8467fed830c34c877e25638c3fc", + "sha256:0d987a3ae5a71c6226b203cfd298720e0086c7fe7c74f35fa8edddfbd6597eed", + "sha256:0eaa83fc4c1e271c24eaf8fb083cbccef8fde77ec8cd45f3c35a9a123e6da097", + "sha256:160c7e0a5eb178011e72892f99f918c04a131f36056d10d9c1afb223fc952c2d", + "sha256:17bf5a931c7f6618023cdacc7081f3f266aecb68ca692adac015c383a134ca52", + "sha256:17c412bad2eb9468e876f556eb4ee910e62d721d2c7a53c7fa31e643d35352e6", + "sha256:18c8dc3b7468d8b4bdf60ce9d7141897da103c7a4690157b32b60acb45e333e6", + "sha256:1a534f43bc738181aa7cbbaf48e3eca62c76453a40a746ab95d4b27b1111a7d2", + "sha256:1c17211bc037c7d88e85ed8b7d8f7e52db6dc8eca5590d162717c654550f7282", + "sha256:1f3496d76b89d9429a656293744ceca4d2ac2a10ae59b84c1da9b5165f429ad3", + "sha256:1fcc03fa4997c447dce58264e93b5aa2d57714fbe0f06c07b7785ae131512732", + "sha256:226af7dcb51fdb0109f0016449b357e182ea0ceb6b47dfb5999d569e5db161d5", + "sha256:23f4aad749d13698f3f7b64aad34f5fc02d6f20f05999eebc96b89b01262fb18", + "sha256:25bf2374a2a8433633c65ccb9553350d5e17e60c8eb4de4d92cc6bd60f01d306", + "sha256:28ad5233e9c3b52d76196c696e362508959741e1a005fb8fa03b51aea156088f", + "sha256:28c812d9757fe8acecc910c9ac9dafd2ce968c00f9e619db09e9f8f54c3a68a3", + "sha256:29c6a4635eef69d68a00321e12a7d2559fe2dfccfa8efae3ffb8e91cd0b36a8b", + "sha256:29c7947c594e105cb9e6c466bace8532dc1ca02d498684128b339799f5248277", + "sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a", + "sha256:2ae90ff9dad33a1cfe947d2c40cb9cb5e600d759ac4f0fd22616ce6540f72797", + "sha256:2c4a71d5d6e7b28a47a394c0471b7e77a0661e2d651e7ae91e0cab0a587859ca", + "sha256:2ea4ad4e6a12e454de05f2949d4beddb52460f3de7c8b9d5c46fbb7d7222e02c", + "sha256:2eb7735ee73ca1b0d71e0e67c3739c689067f055c764f73aac4cc8ecf958ee3f", + "sha256:31507f7b47cc1ead1f6e86927f8ebb196a0bab043f6345ce070f412a59bf87b5", + "sha256:35cffef589bcdc587d06f9149f8d5e9e8859920a071df5a2671de2213bef592a", + "sha256:367b4f689786fca726ef7a6c5ba606958b145b9340a5e4808132cc65759abd44", + "sha256:39887ac397ff35b7b775db7201095fc6310a35fdbae85bac4523f7eb3b840e20", + "sha256:3a495b30fc91db2db25120df5847d9833af237546fd59170701acd816ccc01c4", + "sha256:3b55a4229ce5da9497dd0452b914556ae58e96a4381bb6f59f1305dfd7e53fc8", + "sha256:402b190912935d3db15b03e8f7485812db350d271b284ded2b80d2e5704be780", + "sha256:43a47408ac52647dfabbc66a25b05b6a61700b5165807e3fbd40063fcaf46386", + "sha256:4661c88db4a9e0f958c8abc2b97472e23061f0bc737f6f6179d7a27024e1faa5", + "sha256:46a446c212e58456b23af260f3d9fb785054f3e3653dbf7279d8f2b5546b21c2", + "sha256:470d4a4f6d48fb34e92d768b4e8a5cc3780db0d69107abf1cd7ff734b9766eb0", + "sha256:49d34ab71db5a9c292a7644ce74190b1dd5a3475612eefb1f8be1d6961441971", + "sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b", + "sha256:4d80b1dd99c1942f74ed608ddb38b181b87476c6a966a88a950c7dee118fdf50", + "sha256:4da04c48873a6abdd71811c5e163bd656ee1b957971db7f35140a2d573f6949c", + "sha256:4f78c88905461a9203eac9faac157a2a0dbba84a0fd09fd29315db27be40af9f", + "sha256:4ff9dc6bc1664bb9eec25cd17506ef6672d506115095411e237d571e92a58231", + "sha256:5506f06d7dc6ecf1efacb4a013b1f05071bb24b76350832c96449f4a2d95091c", + "sha256:55cf66647e49d4621a7e20c8d13511ef1fe1efbbccf670811864452487007e08", + "sha256:5a509df7d0a83a4b178d0f937ef14286659225ef4e8812e05580776c70e155d5", + "sha256:5c2b3bfd4b9689919db068ac6c9911f3fcb231c39f7dd30e3138be94896d18e6", + "sha256:6835dd60355593de10350394242b5757fbbd88b25287314316f266e24c61d073", + "sha256:689c5d781014956a4a6de61d74ba97b23547e431e9e7d64f27d4922ba96e9d6e", + "sha256:6a96179a24b14fa6428cbfc08641c779a53f8fcec43644030328f44034c7f1f4", + "sha256:6ace4f71f1900a548f48407fc9be59c6ba9d9aaf658c2eea6cf2779e72f9f317", + "sha256:6b274e0762c33c7471f1a7471d1a2085b1a35eba5cdc48d2ae319f28b6fc4de3", + "sha256:706e794564bec25819d21a41c31d4df2d48e1cc4b061e8d345d7fb4dd3e94072", + "sha256:70fc7fcf0410d16ebdda9b26cbd8bf8d803d220a7f3522e060a69a9c87bf7bad", + "sha256:7133d0a1677aec369d67dd78520d3fa96dd7f3dcec99d66c1762870e5ea1a50a", + "sha256:7445be39143a8aa4faec43b076e06944b8f9d0701b669df4af200531b21e40bb", + "sha256:76589c020680778f06b7e0b193f4b6dd66d470234a16e1df90329f5e14a171cd", + "sha256:76589f2cd6b77b5bdea4fca5992dc1c23389d68b18ccc26a53680ba2dc80ff2f", + "sha256:77eb0968da535cba0470a5165468b2cac7772cfb569977cff92e240f57e31bef", + "sha256:794a4562dcb374f7dbbfb3f51d28fb40123b5a2abadee7b4091f93054909add5", + "sha256:7ad1bc8d1b7a18497dda9600b12dc193c577beb391beae5cd2349184db40f187", + "sha256:7f98f6dfa8b8ccaf39163ce872bddacca38f6a67289116c8937a02e30bbe9711", + "sha256:8423c1877d72c041f2c263b1ec6e34360448decfb323fa8b94e85883043ef988", + "sha256:8685fa9c25ff00f550c1fec650430c4b71e4e48e8d852f7ddcf2e48308038640", + "sha256:878206a45202247781472a2d99df12a176fef806ca175799e1c6ad263510d57c", + "sha256:89289a5ee32ef6c439086184529ae060c741334b8970a6855ec0b6ad3ff28764", + "sha256:8ab5cad923cc95c87bffee098a27856c859bd5d0af31bd346035aa816b081fe1", + "sha256:8b435f2753621cd36e7c1762156815e21c985c72b19135dac43a7f4f31d28dd1", + "sha256:8be4700cd8bb02cc454f630dcdf7cfa99de96788b80c51b60fe2fe1dac480289", + "sha256:8c997098cc65e3208eca09303630e84d42718620e83b733d0fd69543a9cab9cb", + "sha256:8ea039387c10202ce304af74def5021e9adc6297067f3441d348d2b633e8166a", + "sha256:8f7e66c7113c684c2b3f1c83cdd3376103ee0ce4c49ff80a648643e57fb22218", + "sha256:90412f2db8c02a3864cbfc67db0e3dcdbda336acf1c469526d3e869394fe001c", + "sha256:92a78853d7280bffb93df0a4a6a2498cba10ee793cc8076ef797ef2f74d107cf", + "sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7", + "sha256:9cb3a6460cdea8fe8194a76de8895707e61ded10ad0be97188cc8463ffa7e3a8", + "sha256:9dd8cd1aeb00775f527ec60022004d030ddc51d783d056e3e23e74e623e33726", + "sha256:9ed69074a610fad1c2fda66180e7b2edd4d31c53f2d1872bc2d1211563904cd9", + "sha256:9edda2df81daa129b25a39b86cb57dfdfe16f7ec15b42b19bfac503360d27a93", + "sha256:a2224fa4a4c2ee872886ed00a571f5e967c85e078e8e8c2530a2fb01b3309b88", + "sha256:a4f96f0d88accc3dbe4a9025f785ba830f968e21e3e2c6321ccdfc9aef755115", + "sha256:aedd5dd8692635813368e558a05266b995d3d020b23e49581ddd5bbe197a8ab6", + "sha256:aee22939bb6075e7afededabad1a56a905da0b3c4e3e0c45e75810ebe3a52672", + "sha256:b1d464cb8d72bfc1a3adc53305a63a8e0cac6bc8c5a07e8ca190ab8d3faa43c2", + "sha256:b8f86dd868d41bea9a5f873ee13bf5551c94cf6bc51baebc6f85075971fe6eea", + "sha256:bc6bee759a6bddea5db78d7dcd609397449cb2d2d6587f48f3ca613b19410cfc", + "sha256:bea2acdd8ea4275e1278350ced63da0b166421928276c7c8e3f9729d7402a57b", + "sha256:bfa832bfa540e5b5c27dcf5de5d82ebc431b82c453a43d141afb1e5d2de025fa", + "sha256:c0e6091b157d48cbe37bd67233318dbb53e1e6327d6fc3bb284afd585d141003", + "sha256:c3789bd5768ab5618ebf09cef6ec2b35fed88709b104351748a63045f0ff9797", + "sha256:c530e1eecd036ecc83c3407f77bb86feb79916d4a33d11394b8234f3bd35b940", + "sha256:c811cfcd6a9bf680236c40c6f617187515269ab2912f3d7e8c0174898e2519db", + "sha256:c92d73464b886931308ccc45b2744e5968cbaade0b1d6aeb40d8ab537765f5bc", + "sha256:cccba051221b916a4f5e538997c45d7d136a5646442b1231b916d0164067ea27", + "sha256:cdeabcff45d1c219636ee2e54d852262e5c2e085d6cb476d938aee8d921356b3", + "sha256:ced65e5a985398827cc9276b93ef6dfabe0273c23de8c7931339d7e141c2818e", + "sha256:d049df610ac811dcffdc147153b414147428567fbbc8be43bb8885f04db39d98", + "sha256:dacd995031a01d16eec825bf30802fceb2c3791ef24bcce48fa98ce40918c27b", + "sha256:ddf33d97d2f52d89f6e6e7ae66ee35a4d9ca6f36eda89c24591b0c40205a3629", + "sha256:ded0fc7d90fe93ae0b18059930086c51e640cdd3baebdc783a695c77f123dcd9", + "sha256:e3e0210287329272539eea617830a6a28161fbbd8a3271bf4150ae3e58c5d0e6", + "sha256:e6fa2e3e683f34aea77de8112f6483803c96a44fd726d7358b9888ae5bb394ec", + "sha256:ea0eb6af8a17fa272f7b98d7bebfab7836a0d62738e16ba380f440fceca2d951", + "sha256:ea7f69de383cb47522c9c208aec6dd17697db7875a4674c4af3f8cfdac0bdeae", + "sha256:eac5174677da084abf378739dbf4ad245661635f1600edd1221f150b165343f4", + "sha256:fc4f7a173a5609631bb0c42c23d12c49df3966f89f496a51d3eb0ec81f4519d6", + "sha256:fdb5b3e311d4d4b0eb8b3e8b4d1b0a512713ad7e6a68791d0923d1aec433d919" ], - "markers": "python_version >= '3.6'", - "version": "==25.1.2" + "markers": "python_version >= '3.7'", + "version": "==26.2.0" }, "rdflib": { "hashes": [ @@ -1460,19 +1502,19 @@ }, "referencing": { "hashes": [ - "sha256:5773bd84ef41799a5a8ca72dc34590c041eb01bf9aa02632b4a973fb0181a844", - "sha256:d53ae300ceddd3169f1ffa9caf2cb7b769e92657e4fafb23d34b93679116dfd4" + "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", + "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de" ], "markers": "python_version >= '3.8'", - "version": "==0.34.0" + "version": "==0.35.1" }, "requests": { "hashes": [ - "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", - "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], - "markers": "python_version >= '3.7'", - "version": "==2.31.0" + "markers": "python_version >= '3.8'", + "version": "==2.32.3" }, "requests-toolbelt": { "hashes": [ @@ -1508,140 +1550,145 @@ }, "rich": { "hashes": [ - "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222", - "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432" + "sha256:2e85306a063b9492dffc86278197a60cbece75bcb766022f3436f567cae11bdc", + "sha256:a5ac1f1cd448ade0d59cc3356f7db7a7ccda2c8cbae9c7a90c28ff463d3e91f4" ], "markers": "python_full_version >= '3.7.0'", - "version": "==13.7.1" + "version": "==13.8.0" }, "rpds-py": { "hashes": [ - "sha256:01e36a39af54a30f28b73096dd39b6802eddd04c90dbe161c1b8dbe22353189f", - "sha256:044a3e61a7c2dafacae99d1e722cc2d4c05280790ec5a05031b3876809d89a5c", - "sha256:08231ac30a842bd04daabc4d71fddd7e6d26189406d5a69535638e4dcb88fe76", - "sha256:08f9ad53c3f31dfb4baa00da22f1e862900f45908383c062c27628754af2e88e", - "sha256:0ab39c1ba9023914297dd88ec3b3b3c3f33671baeb6acf82ad7ce883f6e8e157", - "sha256:0af039631b6de0397ab2ba16eaf2872e9f8fca391b44d3d8cac317860a700a3f", - "sha256:0b8612cd233543a3781bc659c731b9d607de65890085098986dfd573fc2befe5", - "sha256:11a8c85ef4a07a7638180bf04fe189d12757c696eb41f310d2426895356dcf05", - "sha256:1374f4129f9bcca53a1bba0bb86bf78325a0374577cf7e9e4cd046b1e6f20e24", - "sha256:1d4acf42190d449d5e89654d5c1ed3a4f17925eec71f05e2a41414689cda02d1", - "sha256:1d9a5be316c15ffb2b3c405c4ff14448c36b4435be062a7f578ccd8b01f0c4d8", - "sha256:1df3659d26f539ac74fb3b0c481cdf9d725386e3552c6fa2974f4d33d78e544b", - "sha256:22806714311a69fd0af9b35b7be97c18a0fc2826e6827dbb3a8c94eac6cf7eeb", - "sha256:2644e47de560eb7bd55c20fc59f6daa04682655c58d08185a9b95c1970fa1e07", - "sha256:2e6d75ab12b0bbab7215e5d40f1e5b738aa539598db27ef83b2ec46747df90e1", - "sha256:30f43887bbae0d49113cbaab729a112251a940e9b274536613097ab8b4899cf6", - "sha256:34b18ba135c687f4dac449aa5157d36e2cbb7c03cbea4ddbd88604e076aa836e", - "sha256:36b3ee798c58ace201289024b52788161e1ea133e4ac93fba7d49da5fec0ef9e", - "sha256:39514da80f971362f9267c600b6d459bfbbc549cffc2cef8e47474fddc9b45b1", - "sha256:39f5441553f1c2aed4de4377178ad8ff8f9d733723d6c66d983d75341de265ab", - "sha256:3a96e0c6a41dcdba3a0a581bbf6c44bb863f27c541547fb4b9711fd8cf0ffad4", - "sha256:3f26b5bd1079acdb0c7a5645e350fe54d16b17bfc5e71f371c449383d3342e17", - "sha256:41ef53e7c58aa4ef281da975f62c258950f54b76ec8e45941e93a3d1d8580594", - "sha256:42821446ee7a76f5d9f71f9e33a4fb2ffd724bb3e7f93386150b61a43115788d", - "sha256:43fbac5f22e25bee1d482c97474f930a353542855f05c1161fd804c9dc74a09d", - "sha256:4457a94da0d5c53dc4b3e4de1158bdab077db23c53232f37a3cb7afdb053a4e3", - "sha256:465a3eb5659338cf2a9243e50ad9b2296fa15061736d6e26240e713522b6235c", - "sha256:482103aed1dfe2f3b71a58eff35ba105289b8d862551ea576bd15479aba01f66", - "sha256:4832d7d380477521a8c1644bbab6588dfedea5e30a7d967b5fb75977c45fd77f", - "sha256:4901165d170a5fde6f589acb90a6b33629ad1ec976d4529e769c6f3d885e3e80", - "sha256:5307def11a35f5ae4581a0b658b0af8178c65c530e94893345bebf41cc139d33", - "sha256:5417558f6887e9b6b65b4527232553c139b57ec42c64570569b155262ac0754f", - "sha256:56a737287efecafc16f6d067c2ea0117abadcd078d58721f967952db329a3e5c", - "sha256:586f8204935b9ec884500498ccc91aa869fc652c40c093bd9e1471fbcc25c022", - "sha256:5b4e7d8d6c9b2e8ee2d55c90b59c707ca59bc30058269b3db7b1f8df5763557e", - "sha256:5ddcba87675b6d509139d1b521e0c8250e967e63b5909a7e8f8944d0f90ff36f", - "sha256:618a3d6cae6ef8ec88bb76dd80b83cfe415ad4f1d942ca2a903bf6b6ff97a2da", - "sha256:635dc434ff724b178cb192c70016cc0ad25a275228f749ee0daf0eddbc8183b1", - "sha256:661d25cbffaf8cc42e971dd570d87cb29a665f49f4abe1f9e76be9a5182c4688", - "sha256:66e6a3af5a75363d2c9a48b07cb27c4ea542938b1a2e93b15a503cdfa8490795", - "sha256:67071a6171e92b6da534b8ae326505f7c18022c6f19072a81dcf40db2638767c", - "sha256:685537e07897f173abcf67258bee3c05c374fa6fff89d4c7e42fb391b0605e98", - "sha256:69e64831e22a6b377772e7fb337533c365085b31619005802a79242fee620bc1", - "sha256:6b0817e34942b2ca527b0e9298373e7cc75f429e8da2055607f4931fded23e20", - "sha256:6c81e5f372cd0dc5dc4809553d34f832f60a46034a5f187756d9b90586c2c307", - "sha256:6d7faa6f14017c0b1e69f5e2c357b998731ea75a442ab3841c0dbbbfe902d2c4", - "sha256:6ef0befbb5d79cf32d0266f5cff01545602344eda89480e1dd88aca964260b18", - "sha256:6ef687afab047554a2d366e112dd187b62d261d49eb79b77e386f94644363294", - "sha256:7223a2a5fe0d217e60a60cdae28d6949140dde9c3bcc714063c5b463065e3d66", - "sha256:77f195baa60a54ef9d2de16fbbfd3ff8b04edc0c0140a761b56c267ac11aa467", - "sha256:793968759cd0d96cac1e367afd70c235867831983f876a53389ad869b043c948", - "sha256:7bd339195d84439cbe5771546fe8a4e8a7a045417d8f9de9a368c434e42a721e", - "sha256:7cd863afe7336c62ec78d7d1349a2f34c007a3cc6c2369d667c65aeec412a5b1", - "sha256:7f2facbd386dd60cbbf1a794181e6aa0bd429bd78bfdf775436020172e2a23f0", - "sha256:84ffab12db93b5f6bad84c712c92060a2d321b35c3c9960b43d08d0f639d60d7", - "sha256:8c8370641f1a7f0e0669ddccca22f1da893cef7628396431eb445d46d893e5cd", - "sha256:8db715ebe3bb7d86d77ac1826f7d67ec11a70dbd2376b7cc214199360517b641", - "sha256:8e8916ae4c720529e18afa0b879473049e95949bf97042e938530e072fde061d", - "sha256:8f03bccbd8586e9dd37219bce4d4e0d3ab492e6b3b533e973fa08a112cb2ffc9", - "sha256:8f2fc11e8fe034ee3c34d316d0ad8808f45bc3b9ce5857ff29d513f3ff2923a1", - "sha256:923d39efa3cfb7279a0327e337a7958bff00cc447fd07a25cddb0a1cc9a6d2da", - "sha256:93df1de2f7f7239dc9cc5a4a12408ee1598725036bd2dedadc14d94525192fc3", - "sha256:998e33ad22dc7ec7e030b3df701c43630b5bc0d8fbc2267653577e3fec279afa", - "sha256:99f70b740dc04d09e6b2699b675874367885217a2e9f782bdf5395632ac663b7", - "sha256:9a00312dea9310d4cb7dbd7787e722d2e86a95c2db92fbd7d0155f97127bcb40", - "sha256:9d54553c1136b50fd12cc17e5b11ad07374c316df307e4cfd6441bea5fb68496", - "sha256:9dbbeb27f4e70bfd9eec1be5477517365afe05a9b2c441a0b21929ee61048124", - "sha256:a1ce3ba137ed54f83e56fb983a5859a27d43a40188ba798993812fed73c70836", - "sha256:a34d557a42aa28bd5c48a023c570219ba2593bcbbb8dc1b98d8cf5d529ab1434", - "sha256:a5f446dd5055667aabaee78487f2b5ab72e244f9bc0b2ffebfeec79051679984", - "sha256:ad36cfb355e24f1bd37cac88c112cd7730873f20fb0bdaf8ba59eedf8216079f", - "sha256:aec493917dd45e3c69d00a8874e7cbed844efd935595ef78a0f25f14312e33c6", - "sha256:b316144e85316da2723f9d8dc75bada12fa58489a527091fa1d5a612643d1a0e", - "sha256:b34ae4636dfc4e76a438ab826a0d1eed2589ca7d9a1b2d5bb546978ac6485461", - "sha256:b34b7aa8b261c1dbf7720b5d6f01f38243e9b9daf7e6b8bc1fd4657000062f2c", - "sha256:bc362ee4e314870a70f4ae88772d72d877246537d9f8cb8f7eacf10884862432", - "sha256:bed88b9a458e354014d662d47e7a5baafd7ff81c780fd91584a10d6ec842cb73", - "sha256:c0013fe6b46aa496a6749c77e00a3eb07952832ad6166bd481c74bda0dcb6d58", - "sha256:c0b5dcf9193625afd8ecc92312d6ed78781c46ecbf39af9ad4681fc9f464af88", - "sha256:c4325ff0442a12113a6379af66978c3fe562f846763287ef66bdc1d57925d337", - "sha256:c463ed05f9dfb9baebef68048aed8dcdc94411e4bf3d33a39ba97e271624f8f7", - "sha256:c8362467a0fdeccd47935f22c256bec5e6abe543bf0d66e3d3d57a8fb5731863", - "sha256:cd5bf1af8efe569654bbef5a3e0a56eca45f87cfcffab31dd8dde70da5982475", - "sha256:cf1ea2e34868f6fbf070e1af291c8180480310173de0b0c43fc38a02929fc0e3", - "sha256:d62dec4976954a23d7f91f2f4530852b0c7608116c257833922a896101336c51", - "sha256:d68c93e381010662ab873fea609bf6c0f428b6d0bb00f2c6939782e0818d37bf", - "sha256:d7c36232a90d4755b720fbd76739d8891732b18cf240a9c645d75f00639a9024", - "sha256:dd18772815d5f008fa03d2b9a681ae38d5ae9f0e599f7dda233c439fcaa00d40", - "sha256:ddc2f4dfd396c7bfa18e6ce371cba60e4cf9d2e5cdb71376aa2da264605b60b9", - "sha256:e003b002ec72c8d5a3e3da2989c7d6065b47d9eaa70cd8808b5384fbb970f4ec", - "sha256:e32a92116d4f2a80b629778280103d2a510a5b3f6314ceccd6e38006b5e92dcb", - "sha256:e4461d0f003a0aa9be2bdd1b798a041f177189c1a0f7619fe8c95ad08d9a45d7", - "sha256:e541ec6f2ec456934fd279a3120f856cd0aedd209fc3852eca563f81738f6861", - "sha256:e546e768d08ad55b20b11dbb78a745151acbd938f8f00d0cfbabe8b0199b9880", - "sha256:ea7d4a99f3b38c37eac212dbd6ec42b7a5ec51e2c74b5d3223e43c811609e65f", - "sha256:ed4eb745efbff0a8e9587d22a84be94a5eb7d2d99c02dacf7bd0911713ed14dd", - "sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca", - "sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58", - "sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e" - ], - "markers": "python_version >= '3.8'", - "version": "==0.18.0" + "sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c", + "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585", + "sha256:11ef6ce74616342888b69878d45e9f779b95d4bd48b382a229fe624a409b72c5", + "sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6", + "sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef", + "sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2", + "sha256:1e5f3cd7397c8f86c8cc72d5a791071431c108edd79872cdd96e00abd8497d29", + "sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318", + "sha256:22e6c9976e38f4d8c4a63bd8a8edac5307dffd3ee7e6026d97f3cc3a2dc02a0b", + "sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399", + "sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739", + "sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee", + "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174", + "sha256:338ca4539aad4ce70a656e5187a3a31c5204f261aef9f6ab50e50bcdffaf050a", + "sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344", + "sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2", + "sha256:3d2b1ad682a3dfda2a4e8ad8572f3100f95fad98cb99faf37ff0ddfe9cbf9d03", + "sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5", + "sha256:3fde368e9140312b6e8b6c09fb9f8c8c2f00999d1823403ae90cc00480221b22", + "sha256:40ce74fc86ee4645d0a225498d091d8bc61f39b709ebef8204cb8b5a464d3c0e", + "sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96", + "sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91", + "sha256:4b16aa0107ecb512b568244ef461f27697164d9a68d8b35090e9b0c1c8b27752", + "sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075", + "sha256:4fe84294c7019456e56d93e8ababdad5a329cd25975be749c3f5f558abb48253", + "sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee", + "sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad", + "sha256:54b43a2b07db18314669092bb2de584524d1ef414588780261e31e85846c26a5", + "sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce", + "sha256:569b3ea770c2717b730b61998b6c54996adee3cef69fc28d444f3e7920313cf7", + "sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b", + "sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8", + "sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57", + "sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3", + "sha256:5b4f105deeffa28bbcdff6c49b34e74903139afa690e35d2d9e3c2c2fba18cec", + "sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209", + "sha256:614fdafe9f5f19c63ea02817fa4861c606a59a604a77c8cdef5aa01d28b97921", + "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045", + "sha256:65794e4048ee837494aea3c21a28ad5fc080994dfba5b036cf84de37f7ad5074", + "sha256:6632f2d04f15d1bd6fe0eedd3b86d9061b836ddca4c03d5cf5c7e9e6b7c14580", + "sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7", + "sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5", + "sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3", + "sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0", + "sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24", + "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139", + "sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db", + "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc", + "sha256:9824fb430c9cf9af743cf7aaf6707bf14323fb51ee74425c380f4c846ea70789", + "sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f", + "sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2", + "sha256:9d35cef91e59ebbeaa45214861874bc6f19eb35de96db73e467a8358d701a96c", + "sha256:a1862d2d7ce1674cffa6d186d53ca95c6e17ed2b06b3f4c476173565c862d232", + "sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6", + "sha256:aa7f429242aae2947246587d2964fad750b79e8c233a2367f71b554e9447949c", + "sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29", + "sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489", + "sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94", + "sha256:af0fc424a5842a11e28956e69395fbbeab2c97c42253169d87e90aac2886d751", + "sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2", + "sha256:b4c29cbbba378759ac5786730d1c3cb4ec6f8ababf5c42a9ce303dc4b3d08cda", + "sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9", + "sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51", + "sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c", + "sha256:b8c00a3b1e70c1d3891f0db1b05292747f0dbcfb49c43f9244d04c70fbc40eb8", + "sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989", + "sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511", + "sha256:c3e130fd0ec56cb76eb49ef52faead8ff09d13f4527e9b0c400307ff72b408e1", + "sha256:c52d3f2f82b763a24ef52f5d24358553e8403ce05f893b5347098014f2d9eff2", + "sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150", + "sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c", + "sha256:ce9845054c13696f7af7f2b353e6b4f676dab1b4b215d7fe5e05c6f8bb06f965", + "sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f", + "sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58", + "sha256:d0b67d87bb45ed1cd020e8fbf2307d449b68abc45402fe1a4ac9e46c3c8b192b", + "sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f", + "sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d", + "sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821", + "sha256:d72278a30111e5b5525c1dd96120d9e958464316f55adb030433ea905866f4de", + "sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121", + "sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855", + "sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272", + "sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60", + "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02", + "sha256:def7400461c3a3f26e49078302e1c1b38f6752342c77e3cf72ce91ca69fb1bc1", + "sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140", + "sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879", + "sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940", + "sha256:e6900ecdd50ce0facf703f7a00df12374b74bbc8ad9fe0f6559947fb20f82364", + "sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4", + "sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e", + "sha256:ec31a99ca63bf3cd7f1a5ac9fe95c5e2d060d3c768a09bc1d16e235840861420", + "sha256:f0475242f447cc6cb8a9dd486d68b2ef7fbee84427124c232bff5f63b1fe11e5", + "sha256:f2fbf7db2012d4876fb0d66b5b9ba6591197b0f165db8d99371d976546472a24", + "sha256:f60012a73aa396be721558caa3a6fd49b3dd0033d1675c6d59c4502e870fcf0c", + "sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf", + "sha256:f90a4cd061914a60bd51c68bcb4357086991bd0bb93d8aa66a6da7701370708f", + "sha256:f918a1a130a6dfe1d7fe0f105064141342e7dd1611f2e6a21cd2f5c8cb1cfb3e", + "sha256:fa518bcd7600c584bf42e6617ee8132869e877db2f76bcdc281ec6a4113a53ab", + "sha256:faefcc78f53a88f3076b7f8be0a8f8d35133a3ecf7f3770895c25f8813460f08", + "sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92", + "sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a", + "sha256:fdfc3a892927458d98f3d55428ae46b921d1f7543b89382fdb483f5640daaec8" + ], + "markers": "python_version >= '3.8'", + "version": "==0.20.0" }, "ruff": { "hashes": [ - "sha256:3f3860057590e810c7ffea75669bdc6927bfd91e29b4baa9258fd48b540a4365", - "sha256:519cf6a0ebed244dce1dc8aecd3dc99add7a2ee15bb68cf19588bb5bf58e0488", - "sha256:60c870a7d46efcbc8385d27ec07fe534ac32f3b251e4fc44b3cbfd9e09609ef4", - "sha256:64abeed785dad51801b423fa51840b1764b35d6c461ea8caef9cf9e5e5ab34d9", - "sha256:6810563cc08ad0096b57c717bd78aeac888a1bfd38654d9113cb3dc4d3f74232", - "sha256:6fc14fa742e1d8f24910e1fff0bd5e26d395b0e0e04cc1b15c7c5e5fe5b4af91", - "sha256:986f2377f7cf12efac1f515fc1a5b753c000ed1e0a6de96747cdf2da20a1b369", - "sha256:98e98300056445ba2cc27d0b325fd044dc17fcc38e4e4d2c7711585bd0a958ed", - "sha256:af27ac187c0a331e8ef91d84bf1c3c6a5dea97e912a7560ac0cef25c526a4102", - "sha256:bb0acfb921030d00070539c038cd24bb1df73a2981e9f55942514af8b17be94e", - "sha256:c4fd98e85869603e65f554fdc5cddf0712e352fe6e61d29d5a6fe087ec82b76c", - "sha256:cf133dd744f2470b347f602452a88e70dadfbe0fcfb5fd46e093d55da65f82f7", - "sha256:cf187a7e7098233d0d0c71175375c5162f880126c4c716fa28a8ac418dcf3378", - "sha256:d3ee7880f653cc03749a3bfea720cf2a192e4f884925b0cf7eecce82f0ce5854", - "sha256:de0d5069b165e5a32b3c6ffbb81c350b1e3d3483347196ffdf86dc0ef9e37dd6", - "sha256:df52972138318bc7546d92348a1ee58449bc3f9eaf0db278906eb511889c4b50", - "sha256:f0f4484c6541a99862b693e13a151435a279b271cff20e37101116a21e2a1ad1" + "sha256:0308610470fcc82969082fc83c76c0d362f562e2f0cdab0586516f03a4e06ec6", + "sha256:0b52387d3289ccd227b62102c24714ed75fbba0b16ecc69a923a37e3b5e0aaaa", + "sha256:0ea086601b22dc5e7693a78f3fcfc460cceabfdf3bdc36dc898792aba48fbad6", + "sha256:34d5efad480193c046c86608dbba2bccdc1c5fd11950fb271f8086e0c763a5d1", + "sha256:50e30b437cebef547bd5c3edf9ce81343e5dd7c737cb36ccb4fe83573f3d392e", + "sha256:549daccee5227282289390b0222d0fbee0275d1db6d514550d65420053021a58", + "sha256:66dbfea86b663baab8fcae56c59f190caba9398df1488164e2df53e216248baa", + "sha256:7862f42fc1a4aca1ea3ffe8a11f67819d183a5693b228f0bb3a531f5e40336fc", + "sha256:803b96dea21795a6c9d5bfa9e96127cc9c31a1987802ca68f35e5c95aed3fc0d", + "sha256:932063a03bac394866683e15710c25b8690ccdca1cf192b9a98260332ca93408", + "sha256:ac3b5bfbee99973f80aa1b7cbd1c9cbce200883bdd067300c22a6cc1c7fba212", + "sha256:ac4b75e898ed189b3708c9ab3fc70b79a433219e1e87193b4f2b77251d058d14", + "sha256:bedff9e4f004dad5f7f76a9d39c4ca98af526c9b1695068198b3bda8c085ef60", + "sha256:c44536df7b93a587de690e124b89bd47306fddd59398a0fb12afd6133c7b3818", + "sha256:c4b153fc152af51855458e79e835fb6b933032921756cec9af7d0ba2aa01a258", + "sha256:d02a4127a86de23002e694d7ff19f905c51e338c72d8e09b56bfb60e1681724f", + "sha256:eebe4ff1967c838a1a9618a5a59a3b0a00406f8d7eefee97c70411fefc353617", + "sha256:f0f8968feea5ce3777c0d8365653d5e91c40c31a81d95824ba61d871a11b8523" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==0.3.4" + "version": "==0.6.4" }, "semantic-version": { "hashes": [ @@ -1653,20 +1700,20 @@ }, "send2trash": { "hashes": [ - "sha256:a384719d99c07ce1eefd6905d2decb6f8b7ed054025bb0e618919f945de4f679", - "sha256:c132d59fa44b9ca2b1699af5c86f57ce9f4c5eb56629d5d55fbb7a35f84e2312" + "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9", + "sha256:b18e7a3966d99871aefeb00cfbcfdced55ce4871194810fc71f4aa484b953abf" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.8.2" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", + "version": "==1.8.3" }, "setuptools": { "hashes": [ - "sha256:0ff4183f8f42cd8fa3acea16c45205521a4ef28f73c6391d8a25e92893134f2e", - "sha256:c21c49fb1042386df081cb5d86759792ab89efca84cf114889191cd09aacc80c" + "sha256:5f4c08aa4d3ebcb57a50c33b1b07e94315d7fc7230f7115e47fc99776c8ce308", + "sha256:95b40ed940a1c67eb70fc099094bd6e99c6ee7c23aa2306f4d2697ba7916f9c6" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==69.2.0" + "version": "==74.1.2" }, "six": { "hashes": [ @@ -1708,19 +1755,19 @@ }, "soupsieve": { "hashes": [ - "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690", - "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7" + "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", + "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9" ], "markers": "python_version >= '3.8'", - "version": "==2.5" + "version": "==2.6" }, "sphinx": { "hashes": [ - "sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560", - "sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5" + "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe", + "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239" ], "markers": "python_version >= '3.9'", - "version": "==7.2.6" + "version": "==7.4.7" }, "sphinx-rtd-theme": { "hashes": [ @@ -1732,27 +1779,27 @@ }, "sphinxcontrib-applehelp": { "hashes": [ - "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619", - "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4" + "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", + "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5" ], "markers": "python_version >= '3.9'", - "version": "==1.0.8" + "version": "==2.0.0" }, "sphinxcontrib-devhelp": { "hashes": [ - "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f", - "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3" + "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", + "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2" ], "markers": "python_version >= '3.9'", - "version": "==1.0.6" + "version": "==2.0.0" }, "sphinxcontrib-htmlhelp": { "hashes": [ - "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015", - "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04" + "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", + "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9" ], "markers": "python_version >= '3.9'", - "version": "==2.0.5" + "version": "==2.1.0" }, "sphinxcontrib-jquery": { "hashes": [ @@ -1772,19 +1819,19 @@ }, "sphinxcontrib-qthelp": { "hashes": [ - "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6", - "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182" + "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", + "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb" ], "markers": "python_version >= '3.9'", - "version": "==1.0.7" + "version": "==2.0.0" }, "sphinxcontrib-serializinghtml": { "hashes": [ - "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7", - "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f" + "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", + "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d" ], "markers": "python_version >= '3.9'", - "version": "==1.1.10" + "version": "==2.0.0" }, "stack-data": { "hashes": [ @@ -1803,18 +1850,18 @@ }, "tinycss2": { "hashes": [ - "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847", - "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627" + "sha256:152f9acabd296a8375fbca5b84c961ff95971fcfc32e79550c8df8e29118c54d", + "sha256:54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7" ], - "markers": "python_version >= '3.7'", - "version": "==1.2.1" + "markers": "python_version >= '3.8'", + "version": "==1.3.0" }, "tokenize-rt": { "hashes": [ - "sha256:9fe80f8a5c1edad2d3ede0f37481cc0cc1538a2f442c9c2f9e4feacd2792d054", - "sha256:b79d41a65cfec71285433511b50271b05da3584a1da144a0752e9c621a285289" + "sha256:b9711bdfc51210211137499b5e355d3de5ec88a85d2025c520cbb921b5194367", + "sha256:d4ff7ded2873512938b4f8cbb98c9b07118f01d30ac585a30d7a88353ca36d22" ], - "version": "==5.2.0" + "version": "==6.0.0" }, "toml": { "hashes": [ @@ -1824,72 +1871,64 @@ "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==0.10.2" }, - "tomlkit": { - "hashes": [ - "sha256:5cd82d48a3dd89dee1f9d64420aa20ae65cfbd00668d6f094d7578a78efbb77b", - "sha256:7ca1cfc12232806517a8515047ba66a19369e71edf2439d0f5824f91032b6cc3" - ], - "markers": "python_version >= '3.7'", - "version": "==0.12.4" - }, "tornado": { "hashes": [ - "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0", - "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63", - "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263", - "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052", - "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f", - "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee", - "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78", - "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579", - "sha256:f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212", - "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e", - "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2" + "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8", + "sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f", + "sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4", + "sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3", + "sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14", + "sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842", + "sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9", + "sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698", + "sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7", + "sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d", + "sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4" ], "markers": "python_version >= '3.8'", - "version": "==6.4" + "version": "==6.4.1" }, "tox": { "hashes": [ - "sha256:0defb44f6dafd911b61788325741cc6b2e12ea71f987ac025ad4d649f1f1a104", - "sha256:2900c4eb7b716af4a928a7fdc2ed248ad6575294ed7cfae2ea41203937422847" + "sha256:35d472032ee1f73fe20c3e0e73d7073a4e85075c86ff02c576f9fc7c6a15a578", + "sha256:3c0c96bc3a568a5c7e66387a4cfcf8c875b52e09f4d47c9f7a277ec82f1a0b11" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.14.2" + "version": "==4.18.1" }, "traitlets": { "hashes": [ - "sha256:8cdd83c040dab7d1dee822678e5f5d100b514f7b72b01615b26fc5718916fdf9", - "sha256:fcdf85684a772ddeba87db2f398ce00b40ff550d1528c03c14dbf6a02003cd80" + "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", + "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f" ], "markers": "python_version >= '3.8'", - "version": "==5.14.2" + "version": "==5.14.3" }, "twine": { "hashes": [ - "sha256:89b0cc7d370a4b66421cc6102f269aa910fe0f1861c124f573cf2ddedbc10cf4", - "sha256:a262933de0b484c53408f9edae2e7821c1c45a3314ff2df9bdd343aa7ab8edc0" + "sha256:215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997", + "sha256:9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==5.0.0" + "version": "==5.1.1" }, "types-python-dateutil": { "hashes": [ - "sha256:5d2f2e240b86905e40944dd787db6da9263f0deabef1076ddaed797351ec0202", - "sha256:6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b" + "sha256:27c8cc2d058ccb14946eebcaaa503088f4f6dbc4fb6093d3d456a49aef2753f6", + "sha256:9706c3b68284c25adffc47319ecc7947e5bb86b3773f843c73906fd598bc176e" ], "markers": "python_version >= '3.8'", - "version": "==2.9.0.20240316" + "version": "==2.9.0.20240906" }, "typing-extensions": { "hashes": [ - "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", - "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], "markers": "python_version >= '3.8'", - "version": "==4.10.0" + "version": "==4.12.2" }, "uri-template": { "hashes": [ @@ -1900,19 +1939,19 @@ }, "urllib3": { "hashes": [ - "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", - "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" + "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472", + "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168" ], "markers": "python_version >= '3.8'", - "version": "==2.2.1" + "version": "==2.2.2" }, "virtualenv": { "hashes": [ - "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a", - "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197" + "sha256:48f2695d9809277003f30776d155615ffc11328e6a0a8c1f0ec80188d7874a55", + "sha256:c17f4e0f3e6036e9f26700446f85c76ab11df65ff6d8a9cbfad9f71aabfcf23c" ], "markers": "python_version >= '3.7'", - "version": "==20.25.1" + "version": "==20.26.4" }, "wcwidth": { "hashes": [ @@ -1923,10 +1962,10 @@ }, "webcolors": { "hashes": [ - "sha256:29bc7e8752c0a1bd4a1f03c14d6e6a72e93d82193738fa860cbff59d0fcc11bf", - "sha256:c225b674c83fa923be93d235330ce0300373d02885cef23238813b0d5668304a" + "sha256:08b07af286a01bcd30d583a7acadf629583d1f79bfef27dd2c2c5c263817277d", + "sha256:fc4c3b59358ada164552084a8ebee637c221e4059267d0f8325b3b560f6c7f0a" ], - "version": "==1.13" + "version": "==24.8.0" }, "webencodings": { "hashes": [ @@ -1937,20 +1976,20 @@ }, "websocket-client": { "hashes": [ - "sha256:10e511ea3a8c744631d3bd77e61eb17ed09304c413ad42cf6ddfa4c7787e8fe6", - "sha256:f4c3d22fec12a2461427a29957ff07d35098ee2d976d3ba244e688b8b4057588" + "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", + "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da" ], "markers": "python_version >= '3.8'", - "version": "==1.7.0" + "version": "==1.8.0" }, "wheel": { "hashes": [ - "sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85", - "sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81" + "sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f", + "sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==0.43.0" + "version": "==0.44.0" }, "wrapt": { "hashes": [ @@ -2038,11 +2077,11 @@ }, "zipp": { "hashes": [ - "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b", - "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715" + "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064", + "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b" ], "markers": "python_version >= '3.8'", - "version": "==3.18.1" + "version": "==3.20.1" } } } diff --git a/docs/sphinx/ug_objects.rst b/docs/sphinx/ug_objects.rst index 1ec4ec7..9ac2e4c 100644 --- a/docs/sphinx/ug_objects.rst +++ b/docs/sphinx/ug_objects.rst @@ -79,7 +79,7 @@ Shadow Attributes (Attribute Aliasing) When storing arbitrary objects within a tree node, all its attributes must be accessed through the ``node.data`` attribute. |br| -This can be simplified by using the ``shadow_attrs`` argument, which allow to +This can be simplified by using the ``shadow_attrs`` argument, which allows to access ``node.data.age`` as ``node.age`` for example:: tree = Tree("Persons", shadow_attrs=True) @@ -114,3 +114,112 @@ access ``node.data.age`` as ``node.age`` for example:: Note also that shadow attributes are readonly. +.. _generic-node-data: + +Generic Node Data +----------------- + + +.. _random-trees: + +Generate Random Trees +--------------------- + +Example:: + + structure_def = { + #: Name of the new tree (str, optiona) + "name": "fmea", + #: Types define the default properties of the nodes + "types": { + #: Default properties for all node types + "*": { ... }, + #: Specific default properties for each node type (optional) + "TYPE_1": { ... }, + "TYPE_2": { ... }, + ... + }, + #: Relations define the possible parent / child relationships between + #: node types and optionally override the default properties. + "relations": { + "__root__": { + "TYPE_1": { + ":count": 10, + "ATTR_1": "Function {hier_idx}", + "expanded": True, + }, + }, + "function": { + "failure": { + ":count": RangeRandomizer(1, 3), + "title": "Failure {hier_idx}", + }, + }, + "failure": { + "cause": { + ":count": RangeRandomizer(1, 3), + "title": "Cause {hier_idx}", + }, + "effect": { + ":count": RangeRandomizer(1, 3), + "title": "Effect {hier_idx}", + }, + }, + }, + } + tree = Tree.build_random_tree(structure_def) + tree.print() + assert type(tree) is Tree + assert tree.calc_height() == 3 + +Example:: + + structure_def = { + "name": "fmea", + #: Types define the default properties of the nodes + "types": { + #: Default properties for all node types + "*": {":factory": GenericNodeData}, + #: Specific default properties for each node type + "function": {"icon": "bi bi-gear"}, + "failure": {"icon": "bi bi-exclamation-triangle"}, + "cause": {"icon": "bi bi-tools"}, + "effect": {"icon": "bi bi-lightning"}, + }, + #: Relations define the possible parent / child relationships between + #: node types and optionally override the default properties. + "relations": { + "__root__": { + "function": { + ":count": 10, + "title": "Function {hier_idx}", + "expanded": True, + }, + }, + "function": { + "failure": { + ":count": RangeRandomizer(1, 3), + "title": "Failure {hier_idx}", + }, + }, + "failure": { + "cause": { + ":count": RangeRandomizer(1, 3), + "title": "Cause {hier_idx}", + }, + "effect": { + ":count": RangeRandomizer(1, 3), + "title": "Effect {hier_idx}", + }, + }, + }, + } + tree = Tree.build_random_tree(structure_def) + tree.print() + assert type(tree) is Tree + assert tree.calc_height() == 3 + + tree2 = TypedTree.build_random_tree(structure_def) + tree2.print() + assert type(tree2) is TypedTree + assert tree2.calc_height() == 3 diff --git a/nutree/common.py b/nutree/common.py index 10dae41..9cca817 100644 --- a/nutree/common.py +++ b/nutree/common.py @@ -13,12 +13,14 @@ from contextlib import contextmanager from enum import Enum from pathlib import Path -from typing import IO, TYPE_CHECKING, Any, Callable, Dict, List, Type, Union +from typing import IO, TYPE_CHECKING, Any, Callable, Dict, List, Type, TypeVar, Union if TYPE_CHECKING: # Imported by type checkers, but prevent circular includes from .node import Node from .tree import Tree + TTree = TypeVar("TTree", bound=Tree) + #: Used as ID for the system root node ROOT_ID: str = "__root__" @@ -158,6 +160,55 @@ def __init__(self, value=None): "round43c": (" ", "│ ", "╰── ", "├── ", "╰─┬ ", "├─┬ "), } +# ------------------------------------------------------------------------------ +# Generic data object to be used when nutree.Node instances +# ------------------------------------------------------------------------------ + + +class GenericNodeData: + """Can be used as `node.data` instance for dict-like data. + + Initialized with a dictionary of values. The values can be accessed + via the `node.data` attribute like `node.data["KEY"]`. + If the Tree is initialized with `shadow_attrs=True`, the values are also + available as attributes of the node like `node.KEY`. + + If the tree is serialized, the values are copied to the serialized data. + + Examples: + + ```py + tree = Tree(shadow_attrs=True) + node = Node(GenericNodeData(a=1, b=2)) + tree.add_child(node) + + print(node.a) # 1 + print(node.data["b"]) # 2 + ``` + + Alternatively, the data can be initialized with a dictionary like this: + + ```py + d = {"a": 1, "b": 2} + node = Node(GenericNodeData(**d)) + ``` + + See :ref:`generic-node-data` for details. + """ + + def __init__(self, **values) -> None: + self.values: dict = values + + def __repr__(self): + return f"{self.__class__.__name__}<{self.values}>" + + def __getitem__(self, key): + return self.values[key] + + @staticmethod + def serialize_mapper(nutree_node, data): + return nutree_node.data.values.copy() + def get_version() -> str: from nutree import __version__ @@ -263,7 +314,7 @@ def open_as_uncompressed_input_stream( *, encoding: str = "utf8", auto_uncompress: bool = True, -) -> IO[str]: +) -> IO[str]: # type: ignore """Open a file for reading, decompressing if necessary. Decompression is done by checking for the magic header (independent of the @@ -296,7 +347,7 @@ def open_as_compressed_output_stream( *, compression: bool | int = True, encoding: str = "utf8", -) -> IO[str]: +) -> IO[str]: # type: ignore """Open a file for writing, ZIP-compressing if requested. Example:: diff --git a/nutree/test_tree_generator.py b/nutree/test_tree_generator.py deleted file mode 100644 index 270b9ec..0000000 --- a/nutree/test_tree_generator.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -Generic tree generator for test data. -""" - -from tree_generator import RangeRandomizer, TextRandomizer, build_random_tree - - -structure_definition = { - "name": "fmea", - #: Types define the default properties of the nodes - "types": { - #: Default properties for all node types - # "*": {":factory": WbNode}, - #: Specific default properties for each node type - "function": {"icon": "bi bi-gear"}, - "failure": {"icon": "bi bi-exclamation-triangle"}, - "cause": {"icon": "bi bi-tools"}, - "effect": {"icon": "bi bi-lightning"}, - }, - #: Relations define the possible parent / child relationships between - #: node types and optionally override the default properties. - "relations": { - "__root__": { - "function": { - ":count": 10, - "title": TextRandomizer(("{i}: Provide $(Noun:plural)",)), - "expanded": True, - }, - }, - "function": { - "failure": { - ":count": RangeRandomizer(1, 3), - "title": TextRandomizer("$(Noun:plural) not provided"), - }, - }, - "failure": { - "cause": { - ":count": RangeRandomizer(1, 3), - "title": TextRandomizer("$(Noun:plural) not provided"), - }, - "effect": { - ":count": RangeRandomizer(1, 3), - "title": TextRandomizer("$(Noun:plural) not provided"), - }, - }, - }, -} -tree = build_random_tree(structure_definition) -tree.print() diff --git a/nutree/tree.py b/nutree/tree.py index 2b24075..41d382d 100644 --- a/nutree/tree.py +++ b/nutree/tree.py @@ -9,7 +9,7 @@ import random import threading from pathlib import Path -from typing import IO, Any, Iterable, Iterator +from typing import IO, TYPE_CHECKING, Any, Iterable, Iterator, Type from nutree.diff import diff_tree from nutree.mermaid import ( @@ -18,7 +18,6 @@ MermaidFormatType, MermaidNodeMapperCallbackType, ) -from nutree.tree_generator import build_random_tree from .common import ( FILE_FORMAT_VERSION, @@ -44,6 +43,9 @@ from .node import Node from .rdf import tree_to_rdf +if TYPE_CHECKING: # Imported by type checkers, but prevent circular includes + from nutree.common import TTree + _DELETED_TAG = "" #: Minimal Python version that is supported by WsgiDAV @@ -844,9 +846,19 @@ def _self_check(self) -> True: return True @classmethod - def build_random_tree(cls, structure_def: dict) -> Tree: - """Build a random tree for testing.""" - tt = build_random_tree(cls, structure_def) + def build_random_tree(cls: Type[TTree], structure_def: dict) -> TTree: + """Build a random tree for . + + Returns a new :class:`Tree` instance with random nodes, as defined by + structure_def. + If called like ``TypedTree.build_random_tree(structure_def)``, this + method will return a :class:`~nutree.typed_tree.TypedTree` instance. + + See :ref:`random-trees` for details. + """ + from nutree.tree_generator import build_random_tree + + tt = build_random_tree(tree_class=cls, structure_def=structure_def) return tt diff --git a/nutree/tree_generator.py b/nutree/tree_generator.py index 9928627..7d77dba 100644 --- a/nutree/tree_generator.py +++ b/nutree/tree_generator.py @@ -54,71 +54,27 @@ ``` """ +import random +import sys from abc import ABC, abstractmethod - from datetime import date, datetime, timedelta, timezone -import random -from typing import Any, Sequence, Union +from typing import TYPE_CHECKING, Any, Sequence, Type, Union + +from nutree.common import GenericNodeData +from nutree.node import Node +from nutree.typed_tree import TypedNode try: from fabulist import Fabulist # type: ignore + fab = Fabulist() except ImportError: + # We run without fabulist (with reduced functionality in this case) Fabulist = None fab = None -from nutree.typed_tree import TypedTree, TypedNode - - -# fab = Fabulist() - - -# ------------------------------------------------------------------------------ -# Generic data object to be used when nutree.Node instances -# ------------------------------------------------------------------------------ - - -class GenericNodeData: - """Used as `node.data` instance in nutree. - - Initialized with a dictionary of values. The values can be accessed - via the `node.data` attribute like `node.data["KEY"]`. - If the Tree is initialized with `shadow_attrs=True`, the values are also - available as attributes of the node like `node.KEY`. - - If the tree is serialized, the values are copied to the serialized data. - - Examples: - - ```py - node = TypedNode(DictNodeData(a=1, b=2)) - tree.add_child(node) - - print(node.a) # 1 - print(node.data["b"]) # 2 - ``` - - Alternatively, the data can be initialized with a dictionary like this: - ```py - d = {"a": 1, "b": 2} - node = TypedNode(DictNodeData(**d)) - ``` - - See https://github.com/mar10/nutree - """ - - def __init__(self, **values) -> None: - self.values: dict = values - - def __repr__(self): - return f"{self.__class__.__name__}<{self.values}>" - - def __getitem__(self, key): - return self.values[key] - - @staticmethod - def serialize_mapper(nutree_node, data): - return nutree_node.data.values.copy() +if TYPE_CHECKING: # Imported by type checkers, but prevent circular includes + from nutree.common import TTree # ------------------------------------------------------------------------------ @@ -136,7 +92,7 @@ class Randomizer(ABC): def __init__(self, *, probability: float = 1.0) -> None: assert ( - probability is None or 0.0 <= probability <= 1.0 + type(probability) is float and 0.0 <= probability <= 1.0 ), f"probality must be in the range [0.0 .. 1.0]: {probability}" self.probability = probability @@ -155,11 +111,14 @@ class RangeRandomizer(Randomizer): Args: min_val (Union[float, int]): The minimum value of the range. max_val (Union[float, int]): The maximum value of the range. - probability (float, optional): The probability of generating a value. Defaults to 1.0. - none_value (Any, optional): The value to return when skipping generation. Defaults to None. + probability (float, optional): The probability of generating a value. + Defaults to 1.0. + none_value (Any, optional): The value to return when skipping generation. + Defaults to None. Returns: - Union[float, int, None]: The generated random value, or none_value if generation is skipped. + Union[float, int, None]: The generated random value, or none_value + if generation is skipped. """ """""" @@ -173,7 +132,9 @@ def __init__( none_value: Any = None, ) -> None: super().__init__(probability=probability) - assert type(min_val) is type(max_val) + assert type(min_val) is type( + max_val + ), f"min_val and max_val must be of the same type: {min_val}, {max_val}" self.is_float = type(min_val) is float self.min = min_val self.max = max_val @@ -194,9 +155,16 @@ class DateRangeRandomizer(Randomizer): Args: min_dt (date): The minimum date of the range. - max_dt (Union[date, int]): The maximum date of the range. Pass an integer to specify the number of days from min_dt. - as_js_stamp (bool, optional): If True, return the date as a JavaScript timestamp. Defaults to True. - probability (float, optional): The probability of generating a value. Defaults to 1.0. + max_dt (Union[date, int]): The maximum date of the range. + Pass an integer to specify the number of days from min_dt. + as_js_stamp (bool, optional): If True, return the date as a JavaScript + timestamp. Defaults to True. + probability (float, optional): The probability of generating a value. + Defaults to 1.0. + Examples: + >>> DateRangeRandomizer(date(2020, 1, 1), date(2020, 12, 31)).generate() + datetime.date(2020, 3, 7) + >>> DateRangeRandomizer(date(2020, 1, 1), 365).generate() """ def __init__( @@ -208,12 +176,19 @@ def __init__( probability: float = 1.0, ) -> None: super().__init__(probability=probability) - if type(max_dt) in (int, float): + assert type(min_dt) is date, f"min_dt must be a date: {min_dt}" + assert type(max_dt) in (date, int), f"max_dt must be a date or int: {max_dt}" + + if type(max_dt) is int: self.delta_days = max_dt - max_dt = min_dt + self.delta_days + max_dt = min_dt + timedelta(days=self.delta_days) else: self.delta_days = (max_dt - min_dt).days - assert max_dt > min_dt + + assert ( + max_dt > min_dt + ), f"max_dt must be greater than min_dt: {min_dt}, {max_dt}" + self.min = min_dt self.max = max_dt self.as_js_stamp = as_js_stamp @@ -276,11 +251,18 @@ def __init__( ) -> None: super().__init__(probability=probability) self.sample_list = sample_list + # TODO: remove this when support for Python 3.8 is removed + if sys.version_info < (3, 9) and counts: + raise RuntimeError("counts argument requires Python 3.9 or later.") + self.counts = counts def generate(self) -> Any: if self._skip_value(): return + # TODO: remove this when support for Python 3.8 is removed + if sys.version_info < (3, 9) and not self.counts: + return random.sample(self.sample_list, 1)[0] return random.sample(self.sample_list, 1, counts=self.counts)[0] @@ -301,10 +283,11 @@ class TextRandomizer(Randomizer): Args: template (str | list): A template string or list of strings. - probability (float, optional): The probability of generating a value. Defaults to 1.0. + probability (float, optional): The probability of generating a value. + Defaults to 1.0. """ - def __init__(self, template: str | list, *, probability: float = 1.0) -> None: + def __init__(self, template: Union[str, list], *, probability: float = 1.0) -> None: super().__init__(probability=probability) if not fab: raise RuntimeError("Need fabulist installed to generate random text.") @@ -324,22 +307,26 @@ class BlindTextRandomizer(Randomizer): text values. Args: - sentence_count (int | tuple, optional): The number of sentences to generate. Defaults to (2, 6). + sentence_count (int | tuple, optional): The number of sentences to generate. + Defaults to (2, 6). dialect (str, optional): The dialect of the text. Defaults to "ipsum". entropy (int, optional): The entropy of the text. Defaults to 2. - keep_first (bool, optional): If True, keep the first sentence. Defaults to False. - words_per_sentence (int | tuple, optional): The number of words per sentence. Defaults to (3, 15). - probability (float, optional): The probability of generating a value. Defaults to 1.0. + keep_first (bool, optional): If True, keep the first sentence. + Defaults to False. + words_per_sentence (int | tuple, optional): The number of words per sentence. + Defaults to (3, 15). + probability (float, optional): The probability of generating a value. + Defaults to 1.0. """ def __init__( self, *, - sentence_count: int | tuple = (2, 6), + sentence_count: Union[int, tuple] = (2, 6), dialect: str = "ipsum", entropy: int = 2, keep_first: bool = False, - words_per_sentence: int | tuple = (3, 15), + words_per_sentence: Union[int, tuple] = (3, 15), probability: float = 1.0, ) -> None: super().__init__(probability=probability) @@ -404,7 +391,7 @@ def _merge_specs(node_type: str, spec: dict, types: dict) -> dict: def _make_tree( *, - parent_node: TypedNode, + parent_node: Node, parent_type: str, types: dict, relations: dict, @@ -423,10 +410,10 @@ def _make_tree( i += 1 # 1-based p = f"{prefix}.{i}" if prefix else f"{i}" - # Resolve `Randomizer` values and resolve `{prefix}` and `{i}` macros + # Resolve `Randomizer` values and expand `{idx}` and `{hier_idx}` macros data = spec.copy() - _resolve_random_dict(data, macros={"i": i, "prefix": p}) + _resolve_random_dict(data, macros={"idx": i, "hier_idx": p}) if callback: callback(data) @@ -451,19 +438,20 @@ def _make_tree( return -def build_random_tree(*, tree_class, structure_def: dict) -> TypedTree: +def build_random_tree(*, tree_class: Type["TTree"], structure_def: dict) -> "TTree": """ Return a nutree.TypedTree with random data from a specification. """ - name = structure_def.pop("name", None) - - tree = tree_class(name=name, shadow_attrs=True) + structure_def = structure_def.copy() + name = structure_def.pop("name", None) types = structure_def.pop("types", {}) - relations = structure_def.pop("relations") + relations = structure_def.pop("relations") # mandatory assert not structure_def, f"found extra data: {structure_def}" assert "__root__" in relations, "missing '__root__' relation" + tree: TTree = tree_class(name=name, shadow_attrs=True) + _make_tree( parent_node=tree.system_root, parent_type="__root__", diff --git a/nutree/typed_tree.py b/nutree/typed_tree.py index 71164c3..8cfe2ec 100644 --- a/nutree/typed_tree.py +++ b/nutree/typed_tree.py @@ -9,7 +9,7 @@ from pathlib import Path from typing import IO, Any, Iterator -from nutree.common import ( +from .common import ( ROOT_ID, CalcIdCallbackType, DeserializeMapperType, @@ -23,8 +23,6 @@ ValueMapType, call_mapper, ) -from nutree.tree_generator import build_random_tree - from .node import Node from .tree import Tree @@ -779,11 +777,12 @@ def load( """ return super().load(target, mapper=mapper, file_meta=file_meta) - @classmethod - def build_random_tree(cls, structure_def: dict) -> TypedTree: - """Build a random tree for testing.""" - tt = build_random_tree(cls, structure_def) - return tt + # @classmethod + # def build_random_tree(cls, structure_def: dict) -> TypedTree: + # """Build a random tree for testing.""" + # tt = build_random_tree(cls, structure_def) + # return tt + # ------------------------------------------------------------------------------ # - _SystemRootTypedNode diff --git a/tests/test_tree_generator.py b/tests/test_tree_generator.py new file mode 100644 index 0000000..aaf8192 --- /dev/null +++ b/tests/test_tree_generator.py @@ -0,0 +1,128 @@ +""" +Generic tree generator for test data. +""" + +import datetime + +import pytest + +from nutree.common import GenericNodeData +from nutree.tree import Tree +from nutree.tree_generator import ( + BlindTextRandomizer, + DateRangeRandomizer, + RangeRandomizer, + SampleRandomizer, + SparseBoolRandomizer, + TextRandomizer, + ValueRandomizer, +) +from nutree.typed_tree import TypedTree + + +def test_simple(): + structure_def = { + "name": "fmea", + #: Types define the default properties of the nodes + "types": { + #: Default properties for all node types + "*": {":factory": GenericNodeData}, + #: Specific default properties for each node type + "function": {"icon": "bi bi-gear"}, + "failure": {"icon": "bi bi-exclamation-triangle"}, + "cause": {"icon": "bi bi-tools"}, + "effect": {"icon": "bi bi-lightning"}, + }, + #: Relations define the possible parent / child relationships between + #: node types and optionally override the default properties. + "relations": { + "__root__": { + "function": { + ":count": 3, + "title": "Function {hier_idx}", + "date": DateRangeRandomizer( + datetime.date(2020, 1, 1), datetime.date(2020, 12, 31) + ), + "date2": DateRangeRandomizer(datetime.date(2020, 1, 1), 365), + "value": ValueRandomizer("foo", probability=0.5), + "expanded": SparseBoolRandomizer(probability=0.5), + "state": SampleRandomizer(["open", "closed"]), + }, + }, + "function": { + "failure": { + ":count": RangeRandomizer(1, 3), + "title": "Failure {hier_idx}", + }, + }, + "failure": { + "cause": { + ":count": RangeRandomizer(1, 3), + "title": "Cause {hier_idx}", + }, + "effect": { + ":count": RangeRandomizer(1, 3), + "title": "Effect {hier_idx}", + }, + }, + }, + } + tree = Tree.build_random_tree(structure_def) + tree.print() + assert type(tree) is Tree + assert tree.calc_height() == 3 + + tree2 = TypedTree.build_random_tree(structure_def) + tree2.print() + assert type(tree2) is TypedTree + assert tree2.calc_height() == 3 + + +@pytest.mark.xfail(reason="fabulist may not be installed") +def test_fabulist(): + + structure_def = { + "name": "fmea", + #: Types define the default properties of the nodes + "types": { + #: Default properties for all node types (optional, default + #: is GenericNodeData) + "*": {":factory": GenericNodeData}, + #: Specific default properties for each node type + "function": {"icon": "bi bi-gear"}, + "failure": {"icon": "bi bi-exclamation-triangle"}, + "cause": {"icon": "bi bi-tools"}, + "effect": {"icon": "bi bi-lightning"}, + }, + #: Relations define the possible parent / child relationships between + #: node types and optionally override the default properties. + "relations": { + "__root__": { + "function": { + ":count": 3, + "title": TextRandomizer(("{idx}: Provide $(Noun:plural)",)), + "details": BlindTextRandomizer(dialect="lorem"), + "expanded": True, + }, + }, + "function": { + "failure": { + ":count": RangeRandomizer(1, 3), + "title": TextRandomizer("$(Noun:plural) not provided"), + }, + }, + "failure": { + "cause": { + ":count": RangeRandomizer(1, 3), + "title": TextRandomizer("$(Noun:plural) not provided"), + }, + "effect": { + ":count": RangeRandomizer(1, 3), + "title": TextRandomizer("$(Noun:plural) not provided"), + }, + }, + }, + } + tree = TypedTree.build_random_tree(structure_def) + tree.print() + assert type(tree) is TypedTree diff --git a/tox.ini b/tox.ini index 9d327e6..0833798 100644 --- a/tox.ini +++ b/tox.ini @@ -1,13 +1,14 @@ [tox] basepython = python3.12 envlist = - check, - py312, - py311, - py310, - py39, - py38, - ; py37, + check + ; py313 # EoL: 2029-10 + py312 # EoL: 2028-10 + py311 # EoL: 2027-10 + py310 # EoL: 2026-10 + py39 # EoL: 2025-10 + py38 # EoL: 2024-10 + ; py37 # Eol: 2023-06-27 coverage, skip_missing_interpreters = true @@ -24,6 +25,7 @@ setenv = COVERAGE_FILE=.coverage.{envname} # Note: also honors .coveragerc: deps = + fabulist pydot pytest pytest-cov @@ -73,7 +75,7 @@ commands = [testenv:format] -description = Reformat python code using Black and isort +description = Reformat python code using Black, ruff, isort, and pyupgrade # skip_install = true deps = {[testenv:check]deps} @@ -89,6 +91,23 @@ commands = black nutree tests setup.py {[testenv:lint]commands} +[testenv:format-no-pyupgrade] +description = Same a `format` but without pyupgrade, so it runs on windows +# skip_install = true +deps = + {[testenv:check]deps} + pyupgrade +allowlist_externals: + bash +changedir = {toxinidir} +commands = + ; bash -ec 'pyupgrade --py38-plus --exit-zero-even-if-changed nutree/*.py tests/*.py setup.py' + ruff check --fix nutree tests setup.py + ; ruff format nutree tests setup.py + isort --profile black nutree tests setup.py {posargs} + black nutree tests setup.py + {[testenv:lint]commands} + [testenv:docs] description = Build Sphinx documentation (output directory: docs/sphinx-build) From ea326f1c465b8a77bc83db6362adb568e145ed96 Mon Sep 17 00:00:00 2001 From: Martin Wendt Date: Tue, 10 Sep 2024 20:41:31 +0200 Subject: [PATCH 03/11] wip --- README.md | 1 + docs/sphinx/conf.py | 22 +++-- docs/sphinx/index.rst | 3 +- docs/sphinx/reference_guide.rst | 10 +- docs/sphinx/ug_objects.rst | 103 -------------------- docs/sphinx/ug_randomize.rst | 162 ++++++++++++++++++++++++++++++++ docs/sphinx/user_guide.rst | 1 + nutree/tree.py | 2 +- nutree/tree_generator.py | 3 + tests/test_serialize.py | 4 +- tests/test_tree_generator.py | 15 ++- 11 files changed, 206 insertions(+), 120 deletions(-) create mode 100644 docs/sphinx/ug_randomize.rst diff --git a/README.md b/README.md index fae11d7..5971d33 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Nodes can be plain strings or objects
(De)Serialize to (compressed) JSON
Save as Mermaid flow diagram
Different traversal methods
+Generate random trees
Fully type annotated
Convert to RDF graph
Typed child nodes
diff --git a/docs/sphinx/conf.py b/docs/sphinx/conf.py index e5fa685..4345f99 100644 --- a/docs/sphinx/conf.py +++ b/docs/sphinx/conf.py @@ -130,19 +130,25 @@ #version = '1.0' # The full version, including alpha/beta/rc tags. #release = '1.0' -import pkg_resources +import importlib try: - release = pkg_resources.get_distribution('nutree').version - # print( "release", release) - del pkg_resources -except pkg_resources.DistributionNotFound: - print('To build the documentation, The distribution information') - print('Has to be available. Either install the package into your') + # release = pkg_resources.get_distribution("nutree").version + release = importlib.metadata.version("nutree") +except importlib.metadata.PackageNotFoundError: + print("To build the documentation, The distribution information") + print("has to be available. Either install the package into your") print('development environment or run "setup.py develop" to setup the') - print('metadata. A virtualenv is recommended!') + print("metadata. A virtualenv is recommended!") + + print(f"sys.path: {sys.path}") + print(f"package_root: {package_root}") + for fn in os.listdir(package_root): + print("-", fn) sys.exit(1) +del importlib.metadata + version = '.'.join(release.split('.')[:2]) # The language for content autogenerated by Sphinx. Refer to documentation diff --git a/docs/sphinx/index.rst b/docs/sphinx/index.rst index 3ed7931..351651f 100644 --- a/docs/sphinx/index.rst +++ b/docs/sphinx/index.rst @@ -96,8 +96,9 @@ Nutree Facts * :ref:`(De)Serialize to (compressed) JSON ` * :ref:`Save as Mermaid flow diagram ` * :ref:`Different traversal methods ` - * :ref:`Fully type annotated ` + * :ref:`Generate random trees ` * :ref:`Convert to RDF graph ` + * :ref:`Fully type annotated ` * :ref:`Typed child nodes ` * :ref:`Pretty print ` * :ref:`Navigation ` diff --git a/docs/sphinx/reference_guide.rst b/docs/sphinx/reference_guide.rst index a8e263f..669d589 100644 --- a/docs/sphinx/reference_guide.rst +++ b/docs/sphinx/reference_guide.rst @@ -5,10 +5,18 @@ Reference Guide Class Overview ============== +nutree classes +-------------- + .. inheritance-diagram:: nutree.tree nutree.node nutree.typed_tree nutree.common :parts: 2 :private-bases: - :caption: nutree classes + +Random tree generator +--------------------- + +.. inheritance-diagram:: nutree.tree_generator + :parts: 2 .. API diff --git a/docs/sphinx/ug_objects.rst b/docs/sphinx/ug_objects.rst index 9ac2e4c..1e026ef 100644 --- a/docs/sphinx/ug_objects.rst +++ b/docs/sphinx/ug_objects.rst @@ -120,106 +120,3 @@ Generic Node Data ----------------- -.. _random-trees: - -Generate Random Trees ---------------------- - -Example:: - - structure_def = { - #: Name of the new tree (str, optiona) - "name": "fmea", - #: Types define the default properties of the nodes - "types": { - #: Default properties for all node types - "*": { ... }, - #: Specific default properties for each node type (optional) - "TYPE_1": { ... }, - "TYPE_2": { ... }, - ... - }, - #: Relations define the possible parent / child relationships between - #: node types and optionally override the default properties. - "relations": { - "__root__": { - "TYPE_1": { - ":count": 10, - "ATTR_1": "Function {hier_idx}", - "expanded": True, - }, - }, - "function": { - "failure": { - ":count": RangeRandomizer(1, 3), - "title": "Failure {hier_idx}", - }, - }, - "failure": { - "cause": { - ":count": RangeRandomizer(1, 3), - "title": "Cause {hier_idx}", - }, - "effect": { - ":count": RangeRandomizer(1, 3), - "title": "Effect {hier_idx}", - }, - }, - }, - } - tree = Tree.build_random_tree(structure_def) - tree.print() - assert type(tree) is Tree - assert tree.calc_height() == 3 - -Example:: - - structure_def = { - "name": "fmea", - #: Types define the default properties of the nodes - "types": { - #: Default properties for all node types - "*": {":factory": GenericNodeData}, - #: Specific default properties for each node type - "function": {"icon": "bi bi-gear"}, - "failure": {"icon": "bi bi-exclamation-triangle"}, - "cause": {"icon": "bi bi-tools"}, - "effect": {"icon": "bi bi-lightning"}, - }, - #: Relations define the possible parent / child relationships between - #: node types and optionally override the default properties. - "relations": { - "__root__": { - "function": { - ":count": 10, - "title": "Function {hier_idx}", - "expanded": True, - }, - }, - "function": { - "failure": { - ":count": RangeRandomizer(1, 3), - "title": "Failure {hier_idx}", - }, - }, - "failure": { - "cause": { - ":count": RangeRandomizer(1, 3), - "title": "Cause {hier_idx}", - }, - "effect": { - ":count": RangeRandomizer(1, 3), - "title": "Effect {hier_idx}", - }, - }, - }, - } - tree = Tree.build_random_tree(structure_def) - tree.print() - assert type(tree) is Tree - assert tree.calc_height() == 3 - - tree2 = TypedTree.build_random_tree(structure_def) - tree2.print() - assert type(tree2) is TypedTree - assert tree2.calc_height() == 3 diff --git a/docs/sphinx/ug_randomize.rst b/docs/sphinx/ug_randomize.rst new file mode 100644 index 0000000..beaabe4 --- /dev/null +++ b/docs/sphinx/ug_randomize.rst @@ -0,0 +1,162 @@ +.. _randomize: + +--------------------- +Generate Random Trees +--------------------- + +.. py:currentmodule:: nutree + +Nutree can generate random tree structures from a structure definition. +This can be used to create hierarchical data for test, demo, or benchmarking of +*nutree* itself. + +The result can also be used as a source for creating fixtures for other targets +in a following next step. |br| +See `Wundebaum demo `_ and the +`fixture generator `_ +for an example. + +The structure is defined as Python dictionary that describes the +parent-child relationships to be created. +This definition is then passed to :meth:`tree.Tree.build_random_tree`:: + + structure_def = { + ... + # Relations define the possible parent / child relationships between + # node types and optionally override the default properties. + "relations": { + "__root__": { # System root, i.e. we define the top nodes here + "TYPE_1": { + # How many instances to create: + ":count": 10, + # Attribute names and values for every instance: + "ATTR_1": "This is a top node", + "ATTR_2": True, + "ATTR_3": 42, + }, + }, + "TYPE_1": { # Potential child nodes of TYPE_1 + "TYPE_2": { + ":count": 3, + "title": "This is a child node of TYPE_1", + }, + }, + "TYPE_2": { # Potential child nodes of TYPE_2 + "TYPE_3": { + ":count": 3, + "title": "This is a child node of TYPE_2", + }, + "TYPE_4": { + ":count": 3, + "title": "This is a also child node of TYPE_2", + }, + }, + }, + } + tree = Tree.build_random_tree(structure_def) + tree.print() + assert type(tree) is Tree + assert tree.calc_height() == 3 + +Example:: + + structure_def = { + #: Name of the new tree (str, optiona) + "name": "fmea", + #: Types define the default properties of the nodes + "types": { + #: Default properties for all node types + "*": { ... }, + #: Specific default properties for each node type (optional) + "TYPE_1": { ... }, + "TYPE_2": { ... }, + ... + }, + #: Relations define the possible parent / child relationships between + #: node types and optionally override the default properties. + "relations": { + "__root__": { + "TYPE_1": { + ":count": 10, + "ATTR_1": "Function {hier_idx}", + "expanded": True, + }, + }, + "function": { + "failure": { + ":count": RangeRandomizer(1, 3), + "title": "Failure {hier_idx}", + }, + }, + "failure": { + "cause": { + ":count": RangeRandomizer(1, 3), + "title": "Cause {hier_idx}", + }, + "effect": { + ":count": RangeRandomizer(1, 3), + "title": "Effect {hier_idx}", + }, + }, + }, + } + tree = Tree.build_random_tree(structure_def) + tree.print() + assert type(tree) is Tree + assert tree.calc_height() == 3 + +Example:: + + structure_def = { + "name": "fmea", + #: Types define the default properties of the nodes + "types": { + #: Default properties for all node types + "*": {":factory": GenericNodeData}, + #: Specific default properties for each node type + "function": {"icon": "bi bi-gear"}, + "failure": {"icon": "bi bi-exclamation-triangle"}, + "cause": {"icon": "bi bi-tools"}, + "effect": {"icon": "bi bi-lightning"}, + }, + #: Relations define the possible parent / child relationships between + #: node types and optionally override the default properties. + "relations": { + "__root__": { + "function": { + ":count": 10, + "title": "Function {hier_idx}", + "expanded": True, + }, + }, + "function": { + "failure": { + ":count": RangeRandomizer(1, 3), + "title": "Failure {hier_idx}", + }, + }, + "failure": { + "cause": { + ":count": RangeRandomizer(1, 3), + "title": "Cause {hier_idx}", + }, + "effect": { + ":count": RangeRandomizer(1, 3), + "title": "Effect {hier_idx}", + }, + }, + }, + } + tree = Tree.build_random_tree(structure_def) + tree.print() + assert type(tree) is Tree + assert tree.calc_height() == 3 + + tree2 = TypedTree.build_random_tree(structure_def) + tree2.print() + assert type(tree2) is TypedTree + assert tree2.calc_height() == 3 + +.. note: + + The diff --git a/docs/sphinx/user_guide.rst b/docs/sphinx/user_guide.rst index f3ac240..88ecfea 100644 --- a/docs/sphinx/user_guide.rst +++ b/docs/sphinx/user_guide.rst @@ -108,4 +108,5 @@ kind (str, readonly): ug_serialize ug_diff ug_graphs + ug_randomize ug_advanced diff --git a/nutree/tree.py b/nutree/tree.py index 41d382d..4f6e8d3 100644 --- a/nutree/tree.py +++ b/nutree/tree.py @@ -854,7 +854,7 @@ def build_random_tree(cls: Type[TTree], structure_def: dict) -> TTree: If called like ``TypedTree.build_random_tree(structure_def)``, this method will return a :class:`~nutree.typed_tree.TypedTree` instance. - See :ref:`random-trees` for details. + See :ref:`randomize` for details. """ from nutree.tree_generator import build_random_tree diff --git a/nutree/tree_generator.py b/nutree/tree_generator.py index 7d77dba..1fdb6fe 100644 --- a/nutree/tree_generator.py +++ b/nutree/tree_generator.py @@ -3,6 +3,8 @@ Returns a nutree.TypedTree with random data from a specification. +See :ref:`randomize` for details. + Example: ```py @@ -441,6 +443,7 @@ def _make_tree( def build_random_tree(*, tree_class: Type["TTree"], structure_def: dict) -> "TTree": """ Return a nutree.TypedTree with random data from a specification. + See :ref:`randomize` for details. """ structure_def = structure_def.copy() diff --git a/tests/test_serialize.py b/tests/test_serialize.py index 649ff80..678ab57 100644 --- a/tests/test_serialize.py +++ b/tests/test_serialize.py @@ -829,9 +829,11 @@ def test_serialize_mermaid_typed(self): Path(__file__).parent / "temp/test_serialize_2.md", ) - @pytest.mark.xfail(reason="mmdc may not be installed") + # @pytest.mark.xfail(reason="mmdc may not be installed") def test_serialize_mermaid_svg(self): """Save/load as typed object tree with clones.""" + if not shutil.which("mmdc"): + raise pytest.skip("mmdc not installed") KEEP_FILES = not fixture.is_running_on_ci() and False tree = fixture.create_typed_tree(style="simple", clones=True, name="Root") diff --git a/tests/test_tree_generator.py b/tests/test_tree_generator.py index aaf8192..bfc6711 100644 --- a/tests/test_tree_generator.py +++ b/tests/test_tree_generator.py @@ -16,6 +16,7 @@ SparseBoolRandomizer, TextRandomizer, ValueRandomizer, + fab, ) from nutree.typed_tree import TypedTree @@ -43,10 +44,12 @@ def test_simple(): "date": DateRangeRandomizer( datetime.date(2020, 1, 1), datetime.date(2020, 12, 31) ), - "date2": DateRangeRandomizer(datetime.date(2020, 1, 1), 365), + "date2": DateRangeRandomizer( + datetime.date(2020, 1, 1), 365, probability=0.99 + ), "value": ValueRandomizer("foo", probability=0.5), "expanded": SparseBoolRandomizer(probability=0.5), - "state": SampleRandomizer(["open", "closed"]), + "state": SampleRandomizer(["open", "closed"], probability=0.99), }, }, "function": { @@ -57,7 +60,7 @@ def test_simple(): }, "failure": { "cause": { - ":count": RangeRandomizer(1, 3), + ":count": RangeRandomizer(1, 3, probability=0.99), "title": "Cause {hier_idx}", }, "effect": { @@ -78,9 +81,11 @@ def test_simple(): assert tree2.calc_height() == 3 -@pytest.mark.xfail(reason="fabulist may not be installed") def test_fabulist(): + if not fab: + pytest.skip("fabulist not installed") + structure_def = { "name": "fmea", #: Types define the default properties of the nodes @@ -101,7 +106,7 @@ def test_fabulist(): "function": { ":count": 3, "title": TextRandomizer(("{idx}: Provide $(Noun:plural)",)), - "details": BlindTextRandomizer(dialect="lorem"), + "details": BlindTextRandomizer(dialect="ipsum"), "expanded": True, }, }, From bc318c4ed65ea32623ca0a1bf505ad90dda55d88 Mon Sep 17 00:00:00 2001 From: Martin Wendt Date: Wed, 11 Sep 2024 22:38:22 +0200 Subject: [PATCH 04/11] Update docs --- Pipfile | 1 + Pipfile.lock | 80 ++++++-------- docs/sphinx/ug_basics.rst | 10 +- docs/sphinx/ug_clones.rst | 4 + docs/sphinx/ug_diff.rst | 4 + docs/sphinx/ug_graphs.rst | 9 ++ docs/sphinx/ug_mutation.rst | 6 ++ docs/sphinx/ug_objects.rst | 140 ++++++++++++++++++++++-- docs/sphinx/ug_pretty_print.rst | 6 ++ docs/sphinx/ug_randomize.rst | 7 +- docs/sphinx/ug_search_and_navigate.rst | 6 +- docs/sphinx/ug_serialize.rst | 5 + nutree/__init__.py | 2 + nutree/common.py | 79 ++++++++++---- nutree/node.py | 2 +- nutree/tree.py | 4 +- nutree/tree_generator.py | 5 +- pyproject.toml | 30 ++++++ setup.cfg | 46 ++++---- tests/pytest.ini | 3 + tests/test_objects.py | 141 +++++++++++++++++++++++++ 21 files changed, 482 insertions(+), 108 deletions(-) diff --git a/Pipfile b/Pipfile index b205c36..608e3b7 100644 --- a/Pipfile +++ b/Pipfile @@ -5,6 +5,7 @@ name = "pypi" [dev-packages] black = { version = "~=24.3", extras = ["jupyter"] } +# coverage = "*" fabulist="*" isort = "*" pytest = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 566da6e..78c5940 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -33,6 +33,14 @@ "markers": "python_version >= '3.8'", "version": "==4.4.0" }, + "appnope": { + "hashes": [ + "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", + "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c" + ], + "markers": "platform_system == 'Darwin'", + "version": "==0.1.4" + }, "argon2-cffi": { "hashes": [ "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08", @@ -360,7 +368,7 @@ "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" ], - "markers": "sys_platform == 'win32'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", "version": "==0.4.6" }, "comm": { @@ -1090,6 +1098,14 @@ "markers": "python_version >= '3.8'", "version": "==0.12.1" }, + "pexpect": { + "hashes": [ + "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", + "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f" + ], + "markers": "sys_platform != 'win32' and sys_platform != 'emscripten'", + "version": "==4.9.0" + }, "pkginfo": { "hashes": [ "sha256:5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297", @@ -1153,6 +1169,13 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "version": "==6.0.0" }, + "ptyprocess": { + "hashes": [ + "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", + "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220" + ], + "version": "==0.7.0" + }, "pure-eval": { "hashes": [ "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", @@ -1229,12 +1252,12 @@ }, "pytest": { "hashes": [ - "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5", - "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce" + "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", + "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==8.3.2" + "version": "==8.3.3" }, "pytest-cov": { "hashes": [ @@ -1261,46 +1284,6 @@ "markers": "python_version >= '3.6'", "version": "==2.0.7" }, - "pywin32": { - "hashes": [ - "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d", - "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65", - "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e", - "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b", - "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4", - "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040", - "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a", - "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36", - "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8", - "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e", - "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802", - "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a", - "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407", - "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0" - ], - "markers": "sys_platform == 'win32' and platform_python_implementation != 'PyPy'", - "version": "==306" - }, - "pywin32-ctypes": { - "hashes": [ - "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", - "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755" - ], - "markers": "sys_platform == 'win32'", - "version": "==0.2.3" - }, - "pywinpty": { - "hashes": [ - "sha256:2fd876b82ca750bb1333236ce98488c1be96b08f4f7647cfdf4129dfad83c2d4", - "sha256:61d420c2116c0212808d31625611b51caf621fe67f8a6377e2e8b617ea1c1f7d", - "sha256:697bff211fb5a6508fee2dc6ff174ce03f34a9a233df9d8b5fe9c8ce4d5eaf56", - "sha256:71cb613a9ee24174730ac7ae439fd179ca34ccb8c5349e8d7b72ab5dea2c6f4b", - "sha256:b96fb14698db1284db84ca38c79f15b4cfdc3172065b5137383910567591fa99", - "sha256:c34e32351a3313ddd0d7da23d27f835c860d32fe4ac814d372a3ea9594f41dde" - ], - "markers": "os_name == 'nt'", - "version": "==2.0.13" - }, "pyyaml": { "hashes": [ "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", @@ -1357,6 +1340,7 @@ "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" ], + "index": "pypi", "markers": "python_version >= '3.8'", "version": "==6.0.2" }, @@ -1550,11 +1534,11 @@ }, "rich": { "hashes": [ - "sha256:2e85306a063b9492dffc86278197a60cbece75bcb766022f3436f567cae11bdc", - "sha256:a5ac1f1cd448ade0d59cc3356f7db7a7ccda2c8cbae9c7a90c28ff463d3e91f4" + "sha256:1760a3c0848469b97b558fc61c85233e3dafb69c7a071b4d60c38099d3cd4c06", + "sha256:8260cda28e3db6bf04d2d1ef4dbc03ba80a824c88b0e7668a0f23126a424844a" ], "markers": "python_full_version >= '3.7.0'", - "version": "==13.8.0" + "version": "==13.8.1" }, "rpds-py": { "hashes": [ @@ -1766,6 +1750,7 @@ "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe", "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239" ], + "index": "pypi", "markers": "python_version >= '3.9'", "version": "==7.4.7" }, @@ -1774,6 +1759,7 @@ "sha256:bd5d7b80622406762073a04ef8fadc5f9151261563d47027de09910ce03afe6b", "sha256:ec93d0856dc280cf3aee9a4c9807c60e027c7f7b461b77aeffed682e68f0e586" ], + "index": "pypi", "markers": "python_version >= '3.6'", "version": "==2.0.0" }, diff --git a/docs/sphinx/ug_basics.rst b/docs/sphinx/ug_basics.rst index 0915e05..f55315b 100644 --- a/docs/sphinx/ug_basics.rst +++ b/docs/sphinx/ug_basics.rst @@ -4,6 +4,12 @@ Basics .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree is a Python library for managing hierarchical data structures. + It stores arbitrary data objects in nodes and provides methods for + navigation, searching, and iteration. + Adding Nodes ------------ @@ -35,8 +41,8 @@ Nodes are usually created by adding a new data instance to a parent:: .. seealso:: - See :doc:`ug_objects` for details on how to manage arbitrary objects instead - of plain strings. + See :doc:`ug_objects` for details on how to manage arbitrary objects, dicts, + etc. instead of plain strings. Info and Navigation diff --git a/docs/sphinx/ug_clones.rst b/docs/sphinx/ug_clones.rst index a879b2e..4336f9f 100644 --- a/docs/sphinx/ug_clones.rst +++ b/docs/sphinx/ug_clones.rst @@ -6,6 +6,10 @@ Multiple Instances ('Clones') .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree allows to store multiple references to the same data object in a tree. + Every :class:`~nutree.node.Node` instance is unique within the tree and also has a unique `node.node_id` value. diff --git a/docs/sphinx/ug_diff.rst b/docs/sphinx/ug_diff.rst index 543c5e2..0ad30a9 100644 --- a/docs/sphinx/ug_diff.rst +++ b/docs/sphinx/ug_diff.rst @@ -6,6 +6,10 @@ Diff and Merge .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree provides a `diff` method to compare two trees and calculate the differences. + The :meth:`~nutree.tree.Tree.diff` method compares a tree (`T0`) against another one (`T1`) and returns a merged, annotated copy. diff --git a/docs/sphinx/ug_graphs.rst b/docs/sphinx/ug_graphs.rst index 4a1b862..2330b76 100644 --- a/docs/sphinx/ug_graphs.rst +++ b/docs/sphinx/ug_graphs.rst @@ -6,6 +6,15 @@ Graphs .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree implements conversion to `DOT `_ + and `Mermaid `_ formats. |br| + This allows to visualize trees as graphs in various formats like `png`, `svg`, etc. |br| + The :class:`~nutree.typed_tree.TypedTree` class introduces the concept of + `typed nodes`, which allows to generate labelled edges in the graph representation. + + .. note:: :class:`~nutree.tree.Tree` (and :class:`~nutree.typed_tree.TypedTree` even more so) has features that make mapping to a graph easy. diff --git a/docs/sphinx/ug_mutation.rst b/docs/sphinx/ug_mutation.rst index 115c32b..d5ccd9d 100644 --- a/docs/sphinx/ug_mutation.rst +++ b/docs/sphinx/ug_mutation.rst @@ -6,6 +6,12 @@ Mutation .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree provides methods to modify the tree structure in-place. |br| + This includes adding, moving, and deleting nodes, as well as filtering and sorting. + + Some in-place modifications are available:: # Tree diff --git a/docs/sphinx/ug_objects.rst b/docs/sphinx/ug_objects.rst index 1e026ef..a9ad9a7 100644 --- a/docs/sphinx/ug_objects.rst +++ b/docs/sphinx/ug_objects.rst @@ -6,6 +6,14 @@ Working with Objects .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree allows to store arbitrary objects in its nodes without the + need to modify them or derive from a common base class. |br| + It also supports shadow attributes for direct access to object attributes. |br| + Some objects like *dicts* or *dataclasses* are unhashable and require special + handling. + The previous examples used plain strings as data objects. However, any Python object can be stored, as long as it is `hashable`. @@ -37,7 +45,7 @@ We can add instances of these classes to our tree:: ... For bookkeeping, lookups, and serialization, every data object needs a `data_id`. -This value defaults to ``hash(data)``, which is good enough in many cases. :: +This value defaults to ``hash(data)``, which is good enough in many cases:: assert tree[alice].data_id == hash(alice) @@ -46,7 +54,7 @@ to be useful for persistence. In our example, we already have object GUIDs, whic we want to use instead. This can be achieved by passing a callback to the tree:: def _calc_id(tree, data): - if isinstance(data, fixture.Person): + if isinstance(data, Person): return data.guid return hash(data) @@ -83,9 +91,8 @@ This can be simplified by using the ``shadow_attrs`` argument, which allows to access ``node.data.age`` as ``node.age`` for example:: tree = Tree("Persons", shadow_attrs=True) - dev = tree.add(Department("Development")) alice = Person("Alice", age=23, guid="{123-456}") - alice_node = dev.add(alice) + alice_node = tree.add(alice) # Standard access using `node.data`: assert alice_node.data is alice @@ -96,15 +103,17 @@ access ``node.data.age`` as ``node.age`` for example:: assert alice_node.guid == "{123-456}" assert alice_node.age == 23 + # Note also: shadow attributes are readonly: + alice_node.age = 24 # ERROR: raises AttributeError + + # But we can still modify the data object directly: + alice_node.data.age = 24 # OK! + # Note caveat: `node.name` is not shadowed, but a native property: assert alice.data.name == "Alice" assert alice.name == "Person" - # Note also: shadow attributes are readonly: - alice.age = 24 # ERROR: raises AttributeError - alice.data.age = 24 # OK! - -.. note:: +.. warning:: Aliasing only works for attribute names that are **not** part of the native :class:`~nutree.node.Node` data model. So these attributes will always return @@ -114,9 +123,118 @@ access ``node.data.age`` as ``node.age`` for example:: Note also that shadow attributes are readonly. + .. _generic-node-data: -Generic Node Data ------------------ +Dictionaries (GenericNodeData) +------------------------------ + +Python +`dictionaries `_ +are unhashable and cannot be used as node data objects. |br| +We can handle this in different ways: + +1. Explicitly set the `data_id` when adding the dict: |br| + ``tree.add({"name": "Alice", "age": 23, "guid": "{123-456}"}, data_id="{123-456}")`` +2. Use a custom `calc_data_id` callback function that returns a unique key for + the data object (see example above). +3. Wrap the dict in :class:`~nutree.common.GenericNodeData`. + +The :class:`~nutree.common.GenericNodeData` class is a simple wrapper around a +dictionary that + +- is hashable, so it can be used added to the tree as ``node.data`` +- stores a reference to the original dict internally as ``node.data._dict`` +- allows readonly access to dict keys as shadow attributes, i.e. + ``node.data._dict["name"]`` can be accessed as ``node.data.name``. |br| + If ``shadow_attrs=True`` is passed to the tree constructor, it can also be + accessed as ``node.name``. |br| + Note that shadow attributes are readonly. +- allows access to dict keys by index, i.e. ``node.data["name"]`` + +Examples :: + + from nutree import Tree, GenericNodeData + + tree = Tree(shadow_attrs=True) + + d = {"a": 1, "b": 2} + obj = GenericNodeData(d) + +We can now add the wrapped `dict` to the tree:: + + node = tree.add_child(obj) + + assert node.data._dict is d, "stored as reference" + assert node.data._dict["a"] == 1 + + assert node.data.a == 1, "accessible as data attribute" + assert node.data["a"] == 1, "accessible by index" + + # Since we enabled shadow_attrs, this is also possible: + assert node.a == 1, "accessible as node attribute" + + # Note: shadow attributes are readonly: + node.a = 99 # ERROR: raises AttributeError + node.data["a"] = 99 # ERROR: raises TypeError + + # We need to access the dict directly to modify it + node.data._dict["a"] = 99 + assert node.a == 99, "should reflect changes in dict" +GenericNodeData can also be initialized with keyword args like this:: + + obj = GenericNodeData(a=1, b=2) + + +Dataclasses +----------- + +`Dataclasses `_ are a great way +to define simple classes that hold data. However, they are not hashable by default. |br| +We can handle this in different ways:: + + from dataclasses import dataclass + + @dataclass + class Person: + name: str + age: int + guid: str = None + + alice = Person("Alice", age=23, guid="{123-456}") + +.. 1. Explicitly set the `data_id` when adding the dataclass instance. +.. ``tree.add(, data_id="{123-456}")`` +.. 2. Use a custom `calc_data_id` function that returns a unique key for the data object. +.. 3. Make the dataclass hashable by adding a `__hash__` method. +.. 4. Make the dataclass ``frozen=True`` (or ``unsafe_hash=True``). + +Example: Explicitly set the `data_id` when adding the dataclass instance:: + + tree.add(alice, data_id=alice.guid) + +Example: make the dataclass hashable by adding a `__hash__` method:: + + @dataclass + class Person: + name: str + age: int + guid: str = None + + def __hash__(self): + return hash(self.guid) + + alice = Person("Alice", age=23, guid="{123-456}") + + tree.add(alice) + +Example: Use a frozen dataclass instead, which is immutable and hashable by default:: + + @dataclass(frozen=True) + class Person: + name: str + age: int + guid: str = None + diff --git a/docs/sphinx/ug_pretty_print.rst b/docs/sphinx/ug_pretty_print.rst index 4eb1463..9b8695d 100644 --- a/docs/sphinx/ug_pretty_print.rst +++ b/docs/sphinx/ug_pretty_print.rst @@ -6,6 +6,12 @@ Pretty Print .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree provides a `format` method to generate a pretty printed string + representation of the tree structure. + + :meth:`~nutree.tree.Tree.format` produces a pretty formatted string representation:: diff --git a/docs/sphinx/ug_randomize.rst b/docs/sphinx/ug_randomize.rst index beaabe4..4eb2081 100644 --- a/docs/sphinx/ug_randomize.rst +++ b/docs/sphinx/ug_randomize.rst @@ -6,6 +6,10 @@ Generate Random Trees .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree can generate random tree structures from a structure definition. + Nutree can generate random tree structures from a structure definition. This can be used to create hierarchical data for test, demo, or benchmarking of *nutree* itself. @@ -54,9 +58,6 @@ This definition is then passed to :meth:`tree.Tree.build_random_tree`:: }, } tree = Tree.build_random_tree(structure_def) - tree.print() - assert type(tree) is Tree - assert tree.calc_height() == 3 Example:: diff --git a/docs/sphinx/ug_search_and_navigate.rst b/docs/sphinx/ug_search_and_navigate.rst index d8714f8..f8d3962 100644 --- a/docs/sphinx/ug_search_and_navigate.rst +++ b/docs/sphinx/ug_search_and_navigate.rst @@ -4,6 +4,10 @@ Search and Navigate .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree provides methods to search, navigate, and iterate tree structures. + .. _navigate: Assuming we have a tree like this:: @@ -101,7 +105,7 @@ Examples:: tree.add("A", data_id="123") assert tree.find("A") is None # not found assert tree.find("123") is None # not found - assert tree.find(data_id="123") is not None # works + assert tree.find(data_id="123") is not None # FOUND! .. _traversal: diff --git a/docs/sphinx/ug_serialize.rst b/docs/sphinx/ug_serialize.rst index 5a2a093..16acad3 100644 --- a/docs/sphinx/ug_serialize.rst +++ b/docs/sphinx/ug_serialize.rst @@ -6,6 +6,11 @@ .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree provides methods to serialize and deserialize tree structures as JSON. + Arbitrary objects can be stored and restored by implementing mappers. |br| + The native format supports compact formatting and optional zipping. Native Format ------------- diff --git a/nutree/__init__.py b/nutree/__init__.py index 822ae4a..013e163 100644 --- a/nutree/__init__.py +++ b/nutree/__init__.py @@ -20,6 +20,7 @@ from .common import ( AmbiguousMatchError, + GenericNodeData, IterMethod, SelectBranch, SkipBranch, @@ -39,6 +40,7 @@ AmbiguousMatchError, diff_node_formatter, DiffClassification, + GenericNodeData, IterMethod, load_tree_from_fs, SelectBranch, diff --git a/nutree/common.py b/nutree/common.py index 9cca817..627b2c0 100644 --- a/nutree/common.py +++ b/nutree/common.py @@ -175,39 +175,82 @@ class GenericNodeData: If the tree is serialized, the values are copied to the serialized data. - Examples: + Examples:: - ```py - tree = Tree(shadow_attrs=True) - node = Node(GenericNodeData(a=1, b=2)) - tree.add_child(node) + tree = Tree(shadow_attrs=True) - print(node.a) # 1 - print(node.data["b"]) # 2 - ``` + d = {"a": 1, "b": 2} + obj = GenericNodeData(d) + node = tree.add_child(obj) - Alternatively, the data can be initialized with a dictionary like this: + assert node.data.values is d, "stored as reference" + assert node.data.values["a"] == 1 - ```py - d = {"a": 1, "b": 2} - node = Node(GenericNodeData(**d)) - ``` + assert node.data.a == 1, "accessible as data attribute" + assert node.data["a"] == 1, "accessible by index" + + # Since we enabled shadow_attrs, this is also possible: + assert node.a == 1, "accessible as node attribute" + + + Alternatively, the data can be initialized with keyword args like this:: + + obj = GenericNodeData(a=1, b=2) + + or with a dictionary like this. Note that in this case we unpack the dictionary + which creates a copy:: + + d = {"a": 1, "b": 2} + obj = GenericNodeData(**d) See :ref:`generic-node-data` for details. """ - def __init__(self, **values) -> None: - self.values: dict = values + __slots__ = ("_dict",) + + def __init__(self, dict_inst: dict | None = None, **values) -> None: + if dict_inst is not None: + # A dictionary was passed: store a reference to that instance + if not isinstance(dict_inst, dict): + self._dict = None + raise TypeError("dict_inst must be a dictionary or None") + if values: + self._dict = None + raise ValueError("Cannot pass both dict_inst and **values") + self._dict: dict = dict_inst + else: + # Single keyword arguments are passed (probably from unpacked dict): + # store them in a new dictionary + self._dict: dict = values def __repr__(self): - return f"{self.__class__.__name__}<{self.values}>" + return f"{self.__class__.__name__}<{self._dict}>" def __getitem__(self, key): - return self.values[key] + return self._dict[key] + + def __getattr__(self, name: str) -> Any: + """Allow to access values as attributes. + + Assuming the GenericNodeData instance is stored in a Node.data instance, + this allows to access the values like this:: + + node.data.NAME + + If shadow_attrs is enabled, this also allows to access the values like this:: + + node.NAME + + See :ref:`generic-node-data`. + """ + try: + return self._dict[name] + except KeyError: + raise AttributeError(name) from None @staticmethod def serialize_mapper(nutree_node, data): - return nutree_node.data.values.copy() + return nutree_node.data._dict.copy() def get_version() -> str: diff --git a/nutree/node.py b/nutree/node.py index 41f2698..e0159ce 100644 --- a/nutree/node.py +++ b/nutree/node.py @@ -150,7 +150,7 @@ def __getattr__(self, name: str) -> Any: See :ref:`shadow-attributes`. """ if self._tree._shadow_attrs: - return getattr(self.data, name) + return getattr(self._data, name) raise AttributeError # def __iadd__(self, other) -> None: diff --git a/nutree/tree.py b/nutree/tree.py index 4f6e8d3..0938c1e 100644 --- a/nutree/tree.py +++ b/nutree/tree.py @@ -9,7 +9,7 @@ import random import threading from pathlib import Path -from typing import IO, TYPE_CHECKING, Any, Iterable, Iterator, Type +from typing import IO, TYPE_CHECKING, Any, Iterable, Iterator from nutree.diff import diff_tree from nutree.mermaid import ( @@ -846,7 +846,7 @@ def _self_check(self) -> True: return True @classmethod - def build_random_tree(cls: Type[TTree], structure_def: dict) -> TTree: + def build_random_tree(cls: type[TTree], structure_def: dict) -> TTree: """Build a random tree for . Returns a new :class:`Tree` instance with random nodes, as defined by diff --git a/nutree/tree_generator.py b/nutree/tree_generator.py index 1fdb6fe..c81a02a 100644 --- a/nutree/tree_generator.py +++ b/nutree/tree_generator.py @@ -453,7 +453,10 @@ def build_random_tree(*, tree_class: Type["TTree"], structure_def: dict) -> "TTr assert not structure_def, f"found extra data: {structure_def}" assert "__root__" in relations, "missing '__root__' relation" - tree: TTree = tree_class(name=name, shadow_attrs=True) + tree: TTree = tree_class( + name=name, + shadow_attrs=True, + ) _make_tree( parent_node=tree.system_root, diff --git a/pyproject.toml b/pyproject.toml index b6dd178..8c5823f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,3 +50,33 @@ ignore = [ # [tool.ruff.pydocstyle] # convention = "google" + +# --- Coverage Settings -------------------------------------------------------- +[tool.pytest.ini_options] +# addopts = "-ra -q --cov=nutree --cov-report=html" +addopts = "-ra -q --cov=nutree" +# addopts = "--cov=nutree --cov-report=html --cov-report=term-missing" + +[tool.coverage.run] +# branch = true +omit = [ + "tests/*", + # nutree/leaves_cli.py + # nutree/cli_common.py + # nutree/monitor/* +] + +[tool.coverage.report] +precision = 1 +# show_missing = true +sort = "Name" +exclude_lines = [ + "pragma: no cover", + "raise NotImplementedError", + "if __name__ == .__main__.:", + "if TYPE_CHECKING:", +] + +[tool.coverage.html] +directory = "build/coverage" + diff --git a/setup.cfg b/setup.cfg index fbae0ea..44abd57 100644 --- a/setup.cfg +++ b/setup.cfg @@ -74,6 +74,8 @@ install_requires = graph = pydot; rdflib; graphviz # pdf = ReportLab>=1.2; RXP # rest = docutils>=0.3; pack ==1.1, ==1.3 +random = fabulist +all = pydot; rdflib; graphviz; fabulist [options.packages.find] where = . @@ -101,26 +103,26 @@ universal = false # docs/sphinx-build # docs/sphinx-build/* -# --- Coverage Settings -------------------------------------------------------- - -[coverage:run] -# branch = True -omit = - tests/* - # nutree/leaves_cli.py - # nutree/cli_common.py - # nutree/monitor/* - -[coverage:report] -precision = 1 -# show_missing = True -sort = Name -exclude_lines = - pragma: no cover - raise NotImplementedError - if __name__ == .__main__.: - if TYPE_CHECKING: - -[coverage:html] -directory = build/coverage +# # --- Coverage Settings -------------------------------------------------------- + +# [coverage:run] +# # branch = True +# omit = +# tests/* +# # nutree/leaves_cli.py +# # nutree/cli_common.py +# # nutree/monitor/* + +# [coverage:report] +# precision = 1 +# # show_missing = True +# sort = Name +# exclude_lines = +# pragma: no cover +# raise NotImplementedError +# if __name__ == .__main__.: +# if TYPE_CHECKING: + +# [coverage:html] +# directory = build/coverage diff --git a/tests/pytest.ini b/tests/pytest.ini index 09a19bc..aa0702b 100644 --- a/tests/pytest.ini +++ b/tests/pytest.ini @@ -1,6 +1,9 @@ [pytest] # Silence `PytestDeprecationWarning` junit_family = legacy + +# See also pyproject.toml + ; testpaths = ; tests ; src diff --git a/tests/test_objects.py b/tests/test_objects.py index fda1788..afe45c4 100644 --- a/tests/test_objects.py +++ b/tests/test_objects.py @@ -7,6 +7,7 @@ import pytest from nutree import Tree +from nutree.common import GenericNodeData class Item: @@ -114,3 +115,143 @@ def test_shadow_attrs_true(self): # Shadow attributes are readonly with pytest.raises(AttributeError): let_it_be_node.price = 9.99 + + +class TestGenericNodeData: + def setup_method(self): + self.tree = Tree("fixture") + + def teardown_method(self): + self.tree = None + + def test_constructor(self): + d: dict = {"a": 1, "b": 2} + + with pytest.raises(TypeError, match="dict_inst must be a dictionary"): + _ = GenericNodeData("foo") + + with pytest.raises(TypeError): + _ = GenericNodeData("foo", **d) + + with pytest.raises(TypeError): + _ = GenericNodeData("foo", d) + + with pytest.raises(ValueError): + _ = GenericNodeData(d, foo="bar") + + gnd = GenericNodeData(d) + assert gnd._dict is d, "dict should be stored as reference" + + assert gnd.a == 1, "GenericNodeData should support attribute access" + with pytest.raises(AttributeError): + _ = gnd.foo + + assert gnd["a"] == 1, "GenericNodeData should support item access" + with pytest.raises(KeyError): + _ = gnd["foo"] + + gnd = GenericNodeData(**d) + assert gnd._dict is not d, "unpacked dict should be stored as copy" + + def test_dict(self): + tree = Tree(shadow_attrs=True) + + d: dict = {"a": 1, "b": 2} + + # We cannot simply add a dict, because it is unhashable + with pytest.raises(TypeError, match="unhashable type: 'dict'"): + _ = tree.add(d) + + # But we can wrap it in a GenericNodeData instance + node = tree.add(GenericNodeData(d)) + + # The dict is stored as reference + + assert isinstance(node.data, GenericNodeData) + assert node.data._dict is d, "dict should be stored as reference" + assert node.a == 1, "should support attribute access via shadowing" + + with pytest.raises(AttributeError): + # should not allow access to non-existing attributes + _ = node.foo + + with pytest.raises(TypeError, match="'Node' object is not subscriptable"): + # should NOT support item access via indexing + _ = node["a"] + + assert node.data.a == 1, "should support attribute access via data" + + with pytest.raises(AttributeError): + # should not allow access to non-existing attributes + _ = node.data.foo + + assert node.data["a"] == 1, "should support item access via data" + + with pytest.raises(AttributeError, match="object has no attribute 'a'"): + # Shadowing is read-only + _ = node.data.a = 99 + + with pytest.raises( + TypeError, match="'GenericNodeData' object does not support item assignment" + ): + # Index access is read-only + _ = node.data["a"] = 99 + + with pytest.raises( + TypeError, match="'GenericNodeData' object does not support item assignment" + ): + _ = node.data["foo"] = 99 + + # We need to access the dict directly to modify it + node.data._dict["a"] = 99 + assert node.a == 99, "should reflect changes in dict" + + def test_generic_node_data_unpacked(self): + tree = Tree(shadow_attrs=True) + + d: dict = {"a": 1, "b": 2} + + # We can also unpack the dict + node = tree.add(GenericNodeData(**d)) + + assert node.data._dict is not d, "unpacked dict should be stored as copy" + assert node.data._dict == {"a": 1, "b": 2} + assert node.a == 1, "GenericNodeData should support attribute access" + + def test_dataclass(self): + + from dataclasses import FrozenInstanceError, dataclass + + @dataclass + class Item: + name: str + price: float + count: int + + @dataclass(frozen=True) + class FrozenItem: + name: str + price: float + count: int + + tree = Tree(shadow_attrs=True) + + # We cannot simply add a dataclass, because it is mutable and unhashable + with pytest.raises(TypeError, match="unhashable type: 'Item'"): + _ = tree.add(Item("Let It Be", 12.34, 17)) + + # But we can add frozen dataclasses + item = FrozenItem("Let It Be", 12.34, 17) + dict_node = tree.add(item) + + # Frozen dataclasses are immutable + with pytest.raises(FrozenInstanceError): + item.count += 1 + + tree.print() + + assert isinstance(dict_node.data, FrozenItem) + assert dict_node.data is item, "dataclass should be stored as reference" + assert dict_node.price == 12.34, "should support attribute access via shadowing" + with pytest.raises(AttributeError): + _ = dict_node.foo From 3f27caa19a5abb5e1094169b19e75165e6f0c8d1 Mon Sep 17 00:00:00 2001 From: Martin Wendt Date: Wed, 11 Sep 2024 22:44:48 +0200 Subject: [PATCH 05/11] 2024 --- docs/sphinx/conf.py | 2 +- docs/sphinx/ug_randomize.rst | 16 +++------------- nutree/common.py | 2 +- nutree/diff.py | 2 +- nutree/dot.py | 2 +- nutree/fs.py | 2 +- nutree/mermaid.py | 2 +- nutree/node.py | 2 +- nutree/rdf.py | 2 +- nutree/tree.py | 2 +- nutree/typed_tree.py | 2 +- tests/fixture.py | 2 +- tests/test_bench.py | 2 +- tests/test_clones.py | 2 +- tests/test_core.py | 2 +- tests/test_diff.py | 2 +- tests/test_objects.py | 2 +- tests/test_serialize.py | 2 +- tests/test_typed_tree.py | 2 +- tests/test_typing_concept.py | 2 +- tests/tutorial_script.py | 2 +- 21 files changed, 23 insertions(+), 33 deletions(-) diff --git a/docs/sphinx/conf.py b/docs/sphinx/conf.py index 4345f99..0b08295 100644 --- a/docs/sphinx/conf.py +++ b/docs/sphinx/conf.py @@ -119,7 +119,7 @@ # General information about the project. project = u'nutree' -copyright = u'2021-2023, Martin Wendt' +copyright = u'2021-2024, Martin Wendt' author = u'Martin Wendt' # The version info for the project you're documenting, acts as replacement for diff --git a/docs/sphinx/ug_randomize.rst b/docs/sphinx/ug_randomize.rst index 4eb2081..b5edaa9 100644 --- a/docs/sphinx/ug_randomize.rst +++ b/docs/sphinx/ug_randomize.rst @@ -41,22 +41,15 @@ This definition is then passed to :meth:`tree.Tree.build_random_tree`:: }, "TYPE_1": { # Potential child nodes of TYPE_1 "TYPE_2": { + # How many instances to create: ":count": 3, + # Attribute names and values for every instance: "title": "This is a child node of TYPE_1", }, }, - "TYPE_2": { # Potential child nodes of TYPE_2 - "TYPE_3": { - ":count": 3, - "title": "This is a child node of TYPE_2", - }, - "TYPE_4": { - ":count": 3, - "title": "This is a also child node of TYPE_2", - }, - }, }, } + tree = Tree.build_random_tree(structure_def) Example:: @@ -158,6 +151,3 @@ Example:: assert type(tree2) is TypedTree assert tree2.calc_height() == 3 -.. note: - - The diff --git a/nutree/common.py b/nutree/common.py index 627b2c0..792107d 100644 --- a/nutree/common.py +++ b/nutree/common.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Functions and declarations used by the :mod:`nutree.tree` and :mod:`nutree.node` diff --git a/nutree/diff.py b/nutree/diff.py index d825a40..31864e0 100644 --- a/nutree/diff.py +++ b/nutree/diff.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt and contributors; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt and contributors; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Implement diff/merge algorithms. diff --git a/nutree/dot.py b/nutree/dot.py index c1fbdfe..b23fdbe 100644 --- a/nutree/dot.py +++ b/nutree/dot.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Functions and declarations to support diff --git a/nutree/fs.py b/nutree/fs.py index 949423e..b4a093c 100644 --- a/nutree/fs.py +++ b/nutree/fs.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Methods and classes to support file system related functionality. diff --git a/nutree/mermaid.py b/nutree/mermaid.py index e0b907a..ce51dde 100644 --- a/nutree/mermaid.py +++ b/nutree/mermaid.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Functions and declarations to support diff --git a/nutree/node.py b/nutree/node.py index e0159ce..2da16cf 100644 --- a/nutree/node.py +++ b/nutree/node.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Declare the :class:`~nutree.node.Node` class. diff --git a/nutree/rdf.py b/nutree/rdf.py index 67db673..c4f2be2 100644 --- a/nutree/rdf.py +++ b/nutree/rdf.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Functions and declarations to implement `rdflib `_. diff --git a/nutree/tree.py b/nutree/tree.py index 0938c1e..3e6751d 100644 --- a/nutree/tree.py +++ b/nutree/tree.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Declare the :class:`~nutree.tree.Tree` class. diff --git a/nutree/typed_tree.py b/nutree/typed_tree.py index 8cfe2ec..38f7bfc 100644 --- a/nutree/typed_tree.py +++ b/nutree/typed_tree.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Declare the :class:`~nutree.tree.TypedTree` class. diff --git a/tests/fixture.py b/tests/fixture.py index 63ea796..e8b93ec 100644 --- a/tests/fixture.py +++ b/tests/fixture.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Test helpers. diff --git a/tests/test_bench.py b/tests/test_bench.py index 0e46c07..f2f6d00 100644 --- a/tests/test_bench.py +++ b/tests/test_bench.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ diff --git a/tests/test_clones.py b/tests/test_clones.py index c5e8700..094c936 100644 --- a/tests/test_clones.py +++ b/tests/test_clones.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ diff --git a/tests/test_core.py b/tests/test_core.py index 54da45a..f97c84c 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ diff --git a/tests/test_diff.py b/tests/test_diff.py index dcedb9f..fde3edb 100644 --- a/tests/test_diff.py +++ b/tests/test_diff.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ diff --git a/tests/test_objects.py b/tests/test_objects.py index afe45c4..0dc221c 100644 --- a/tests/test_objects.py +++ b/tests/test_objects.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ diff --git a/tests/test_serialize.py b/tests/test_serialize.py index 678ab57..b57c3c7 100644 --- a/tests/test_serialize.py +++ b/tests/test_serialize.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ diff --git a/tests/test_typed_tree.py b/tests/test_typed_tree.py index 65eed6e..4eb1a4d 100644 --- a/tests/test_typed_tree.py +++ b/tests/test_typed_tree.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ diff --git a/tests/test_typing_concept.py b/tests/test_typing_concept.py index ba9649b..4efe686 100644 --- a/tests/test_typing_concept.py +++ b/tests/test_typing_concept.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ diff --git a/tests/tutorial_script.py b/tests/tutorial_script.py index f12b01c..623bdd8 100644 --- a/tests/tutorial_script.py +++ b/tests/tutorial_script.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ From 4fd579a8da702fb64d86d496fee920c08bd5ba92 Mon Sep 17 00:00:00 2001 From: Martin Wendt Date: Thu, 12 Sep 2024 13:12:09 +0200 Subject: [PATCH 06/11] Add Tree.build_random_tree() (#9) * Add Tree.build_random_tree() * Fix tests and format * wip * Update docs * 2024 --- CHANGELOG.md | 4 +- Pipfile | 8 +- Pipfile.lock | 1567 ++++++++++++------------ README.md | 1 + docs/sphinx/conf.py | 24 +- docs/sphinx/index.rst | 3 +- docs/sphinx/reference_guide.rst | 10 +- docs/sphinx/ug_basics.rst | 10 +- docs/sphinx/ug_clones.rst | 4 + docs/sphinx/ug_diff.rst | 4 + docs/sphinx/ug_graphs.rst | 9 + docs/sphinx/ug_mutation.rst | 6 + docs/sphinx/ug_objects.rst | 144 ++- docs/sphinx/ug_pretty_print.rst | 6 + docs/sphinx/ug_randomize.rst | 153 +++ docs/sphinx/ug_search_and_navigate.rst | 6 +- docs/sphinx/ug_serialize.rst | 5 + docs/sphinx/user_guide.rst | 1 + nutree/__init__.py | 2 + nutree/common.py | 102 +- nutree/diff.py | 2 +- nutree/dot.py | 2 +- nutree/fs.py | 2 +- nutree/mermaid.py | 2 +- nutree/node.py | 4 +- nutree/rdf.py | 2 +- nutree/tree.py | 23 +- nutree/tree_generator.py | 469 +++++++ nutree/typed_tree.py | 11 +- pyproject.toml | 30 + setup.cfg | 46 +- tests/fixture.py | 2 +- tests/pytest.ini | 3 + tests/test_bench.py | 2 +- tests/test_clones.py | 2 +- tests/test_core.py | 2 +- tests/test_diff.py | 2 +- tests/test_objects.py | 143 ++- tests/test_serialize.py | 6 +- tests/test_tree_generator.py | 133 ++ tests/test_typed_tree.py | 2 +- tests/test_typing_concept.py | 2 +- tests/tutorial_script.py | 2 +- tox.ini | 35 +- 44 files changed, 2140 insertions(+), 858 deletions(-) create mode 100644 docs/sphinx/ug_randomize.rst create mode 100644 nutree/tree_generator.py create mode 100644 tests/test_tree_generator.py diff --git a/CHANGELOG.md b/CHANGELOG.md index b44449e..8d28461 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ # Changelog -## 0.8.1 (unreleased) +## 0.9.0 (unreleased) +- Add `Tree.build_random_tree()` +- Add `GenericNodeData` - Fixed #7 Tree.from_dict failing to recreate an arbitrary object tree with a mapper. ## 0.8.0 (2024-03-29) diff --git a/Pipfile b/Pipfile index 8c15a74..608e3b7 100644 --- a/Pipfile +++ b/Pipfile @@ -5,10 +5,9 @@ name = "pypi" [dev-packages] black = { version = "~=24.3", extras = ["jupyter"] } +# coverage = "*" +fabulist="*" isort = "*" -# pylint = "*" -# TODO: remove this line: -# pytest-html = "!=3.2.0" # wait for https://github.com/pytest-dev/pytest-html/pull/583 pytest = "*" pytest-cov = "*" PyYAML = "*" @@ -22,9 +21,9 @@ tox = "*" twine = "*" wheel = "*" yabs = "*" -nutree = {path = ".",editable = true} ipykernel = "*" notebook = "*" +nutree = {path = ".",editable = true} [packages] @@ -32,4 +31,3 @@ notebook = "*" python_version = "3.12" [pipenv] -# allow_prereleases = true diff --git a/Pipfile.lock b/Pipfile.lock index c9de180..78c5940 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "5935bcfa3efbb2476994643f35d2c509acabbabe36499683b590fdca3a093dd2" + "sha256": "98a0bcd048aa6b4870c6737ccc39368c1df70ce8bad22db187a05d49b0855bae" }, "pipfile-spec": 6, "requires": { @@ -27,11 +27,11 @@ }, "anyio": { "hashes": [ - "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8", - "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6" + "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94", + "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7" ], "markers": "python_version >= '3.8'", - "version": "==4.3.0" + "version": "==4.4.0" }, "appnope": { "hashes": [ @@ -84,14 +84,6 @@ "markers": "python_version >= '3.8'", "version": "==1.3.0" }, - "astroid": { - "hashes": [ - "sha256:951798f922990137ac090c53af473db7ab4e70c770e6d7fae0cec59f74411819", - "sha256:ac248253bfa4bd924a0de213707e7ebeeb3138abeb48d798784ead1e56d419d4" - ], - "markers": "python_full_version >= '3.8.0'", - "version": "==3.1.0" - }, "asttokens": { "hashes": [ "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24", @@ -109,19 +101,19 @@ }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "babel": { "hashes": [ - "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363", - "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287" + "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b", + "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316" ], - "markers": "python_version >= '3.7'", - "version": "==2.14.0" + "markers": "python_version >= '3.8'", + "version": "==2.16.0" }, "beautifulsoup4": { "hashes": [ @@ -136,31 +128,31 @@ "jupyter" ], "hashes": [ - "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f", - "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93", - "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11", - "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0", - "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9", - "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5", - "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213", - "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d", - "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7", - "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837", - "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f", - "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395", - "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995", - "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f", - "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597", - "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959", - "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5", - "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb", - "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4", - "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7", - "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd", - "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7" - ], - "markers": "python_version >= '3.8'", - "version": "==24.3.0" + "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6", + "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e", + "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f", + "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018", + "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e", + "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd", + "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4", + "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed", + "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2", + "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42", + "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af", + "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb", + "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368", + "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb", + "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af", + "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed", + "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47", + "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2", + "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a", + "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c", + "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920", + "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1" + ], + "markers": "python_version >= '3.8'", + "version": "==24.8.0" }, "bleach": { "hashes": [ @@ -172,77 +164,92 @@ }, "cachetools": { "hashes": [ - "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945", - "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105" + "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292", + "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a" ], "markers": "python_version >= '3.7'", - "version": "==5.3.3" + "version": "==5.5.0" }, "certifi": { "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "markers": "python_version >= '3.6'", - "version": "==2024.2.2" + "version": "==2024.8.30" }, "cffi": { "hashes": [ - "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", - "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", - "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", - "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", - "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", - "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", - "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", - "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", - "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", - "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", - "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", - "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", - "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", - "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", - "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", - "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", - "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", - "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", - "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", - "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", - "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", - "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", - "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", - "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", - "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", - "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", - "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", - "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", - "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", - "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", - "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", - "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", - "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", - "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", - "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", - "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", - "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", - "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", - "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", - "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", - "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", - "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", - "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", - "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", - "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", - "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", - "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", - "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", - "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", - "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", - "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", - "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" + "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", + "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", + "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", + "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", + "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", + "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", + "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", + "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", + "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", + "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", + "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", + "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", + "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", + "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", + "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", + "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", + "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", + "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", + "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", + "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", + "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", + "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", + "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", + "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", + "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", + "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", + "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", + "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", + "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", + "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", + "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", + "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", + "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", + "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", + "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", + "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", + "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", + "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", + "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", + "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", + "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", + "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", + "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", + "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", + "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", + "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", + "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", + "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", + "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", + "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", + "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", + "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", + "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", + "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", + "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", + "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", + "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", + "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", + "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", + "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", + "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", + "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", + "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", + "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", + "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", + "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", + "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" ], "markers": "python_version >= '3.8'", - "version": "==1.16.0" + "version": "==1.17.1" }, "chardet": { "hashes": [ @@ -384,126 +391,141 @@ "toml" ], "hashes": [ - "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c", - "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63", - "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7", - "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f", - "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8", - "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf", - "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0", - "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384", - "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76", - "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7", - "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d", - "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70", - "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f", - "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818", - "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b", - "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d", - "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec", - "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083", - "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2", - "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9", - "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd", - "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade", - "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e", - "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a", - "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227", - "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87", - "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c", - "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e", - "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c", - "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e", - "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd", - "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec", - "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562", - "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8", - "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677", - "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357", - "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c", - "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd", - "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49", - "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286", - "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1", - "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf", - "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51", - "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409", - "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384", - "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e", - "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978", - "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57", - "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e", - "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2", - "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48", - "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4" - ], - "markers": "python_version >= '3.8'", - "version": "==7.4.4" + "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca", + "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d", + "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6", + "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989", + "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c", + "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b", + "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223", + "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f", + "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56", + "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3", + "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8", + "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb", + "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388", + "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0", + "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a", + "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8", + "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f", + "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a", + "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962", + "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8", + "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391", + "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc", + "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2", + "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155", + "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb", + "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0", + "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c", + "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a", + "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004", + "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060", + "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232", + "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93", + "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129", + "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163", + "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de", + "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6", + "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23", + "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569", + "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d", + "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778", + "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d", + "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36", + "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a", + "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6", + "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34", + "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704", + "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106", + "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9", + "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862", + "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b", + "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255", + "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16", + "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3", + "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133", + "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb", + "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657", + "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d", + "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca", + "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36", + "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c", + "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e", + "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff", + "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7", + "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5", + "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02", + "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c", + "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df", + "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3", + "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a", + "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959", + "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234", + "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc" + ], + "markers": "python_version >= '3.8'", + "version": "==7.6.1" }, "cryptography": { "hashes": [ - "sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee", - "sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576", - "sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d", - "sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30", - "sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413", - "sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb", - "sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da", - "sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4", - "sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd", - "sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc", - "sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8", - "sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1", - "sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc", - "sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e", - "sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8", - "sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940", - "sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400", - "sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7", - "sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16", - "sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278", - "sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74", - "sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec", - "sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1", - "sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2", - "sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c", - "sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922", - "sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a", - "sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6", - "sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1", - "sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e", - "sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac", - "sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7" - ], - "version": "==42.0.5" + "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494", + "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806", + "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d", + "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062", + "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2", + "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4", + "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1", + "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85", + "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84", + "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042", + "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d", + "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962", + "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2", + "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa", + "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d", + "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365", + "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96", + "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47", + "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d", + "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d", + "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c", + "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb", + "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277", + "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172", + "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034", + "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a", + "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289" + ], + "version": "==43.0.1" }, "debugpy": { "hashes": [ - "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb", - "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146", - "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8", - "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242", - "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0", - "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741", - "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539", - "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23", - "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3", - "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39", - "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd", - "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9", - "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace", - "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42", - "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0", - "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7", - "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e", - "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234", - "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98", - "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703", - "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42", - "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099" - ], - "markers": "python_version >= '3.8'", - "version": "==1.8.1" + "sha256:0a1029a2869d01cb777216af8c53cda0476875ef02a2b6ff8b2f2c9a4b04176c", + "sha256:1cd04a73eb2769eb0bfe43f5bfde1215c5923d6924b9b90f94d15f207a402226", + "sha256:28ced650c974aaf179231668a293ecd5c63c0a671ae6d56b8795ecc5d2f48d3c", + "sha256:345d6a0206e81eb68b1493ce2fbffd57c3088e2ce4b46592077a943d2b968ca3", + "sha256:3df6692351172a42af7558daa5019651f898fc67450bf091335aa8a18fbf6f3a", + "sha256:4413b7a3ede757dc33a273a17d685ea2b0c09dbd312cc03f5534a0fd4d40750a", + "sha256:4fbb3b39ae1aa3e5ad578f37a48a7a303dad9a3d018d369bc9ec629c1cfa7408", + "sha256:55919dce65b471eff25901acf82d328bbd5b833526b6c1364bd5133754777a44", + "sha256:5b5c770977c8ec6c40c60d6f58cacc7f7fe5a45960363d6974ddb9b62dbee156", + "sha256:606bccba19f7188b6ea9579c8a4f5a5364ecd0bf5a0659c8a5d0e10dcee3032a", + "sha256:7b0fe36ed9d26cb6836b0a51453653f8f2e347ba7348f2bbfe76bfeb670bfb1c", + "sha256:7e4d594367d6407a120b76bdaa03886e9eb652c05ba7f87e37418426ad2079f7", + "sha256:8f913ee8e9fcf9d38a751f56e6de12a297ae7832749d35de26d960f14280750a", + "sha256:a697beca97dad3780b89a7fb525d5e79f33821a8bc0c06faf1f1289e549743cf", + "sha256:ad84b7cde7fd96cf6eea34ff6c4a1b7887e0fe2ea46e099e53234856f9d99a34", + "sha256:b2112cfeb34b4507399d298fe7023a16656fc553ed5246536060ca7bd0e668d0", + "sha256:b78c1250441ce893cb5035dd6f5fc12db968cc07f91cc06996b2087f7cefdd8e", + "sha256:c0a65b00b7cdd2ee0c2cf4c7335fef31e15f1b7056c7fdbce9e90193e1a8c8cb", + "sha256:c9f7c15ea1da18d2fcc2709e9f3d6de98b69a5b0fff1807fb80bc55f906691f7", + "sha256:db9fb642938a7a609a6c865c32ecd0d795d56c1aaa7a7a5722d77855d5e77f2b", + "sha256:dd3811bd63632bb25eda6bd73bea8e0521794cda02be41fa3160eb26fc29e7ed", + "sha256:e84c276489e141ed0b93b0af648eef891546143d6a48f610945416453a8ad406" + ], + "markers": "python_version >= '3.8'", + "version": "==1.8.5" }, "decorator": { "hashes": [ @@ -529,14 +551,6 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.2.14" }, - "dill": { - "hashes": [ - "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca", - "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7" - ], - "markers": "python_version >= '3.11'", - "version": "==0.3.8" - }, "distlib": { "hashes": [ "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784", @@ -554,26 +568,34 @@ }, "executing": { "hashes": [ - "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147", - "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc" + "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf", + "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab" ], - "markers": "python_version >= '3.5'", - "version": "==2.0.1" + "markers": "python_version >= '3.8'", + "version": "==2.1.0" + }, + "fabulist": { + "hashes": [ + "sha256:6306d25164faafd2663a3c2cea4b95e73d8c51bba568fa340ce21fceb2862806", + "sha256:638f1456aa5ec97753db23abf9408fb56c6c78dbe4625a1e487013fceed1bf51" + ], + "index": "pypi", + "version": "==1.2.0" }, "fastjsonschema": { "hashes": [ - "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0", - "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d" + "sha256:3d48fc5300ee96f5d116f10fe6f28d938e6008f59a6a025c2649475b87f76a23", + "sha256:5875f0b0fa7a0043a91e93a9b8f793bcbbba9691e7fd83dca95c28ba26d21f0a" ], - "version": "==2.19.1" + "version": "==2.20.0" }, "filelock": { "hashes": [ - "sha256:5ffa845303983e7a0b7ae17636509bc97997d58afeafa72fb141a17b152284cb", - "sha256:a79895a25bbefdf55d1a2a0a80968f7dbb28edcd6d4234a0afb3f37ecde4b546" + "sha256:81de9eb8453c769b63369f87f11131a7ab04e367f8d97ad39dc230daa07e3bec", + "sha256:f6ed4c963184f4c84dd5557ce8fece759a3724b37b80c6c4f20a2f63a4dc6609" ], "markers": "python_version >= '3.8'", - "version": "==3.13.3" + "version": "==3.16.0" }, "fqdn": { "hashes": [ @@ -592,11 +614,11 @@ }, "gitpython": { "hashes": [ - "sha256:1bf9cd7c9e7255f77778ea54359e54ac22a72a5b51288c457c881057b7bb9ecd", - "sha256:2d99869e0fef71a73cbd242528105af1d6c1b108c60dfabd994bf292f76c3ceb" + "sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c", + "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff" ], "markers": "python_version >= '3.7'", - "version": "==3.1.42" + "version": "==3.1.43" }, "h11": { "hashes": [ @@ -616,19 +638,19 @@ }, "httpx": { "hashes": [ - "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5", - "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5" + "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", + "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2" ], "markers": "python_version >= '3.8'", - "version": "==0.27.0" + "version": "==0.27.2" }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac", + "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603" ], - "markers": "python_version >= '3.5'", - "version": "==3.6" + "markers": "python_version >= '3.6'", + "version": "==3.8" }, "imagesize": { "hashes": [ @@ -640,11 +662,11 @@ }, "importlib-metadata": { "hashes": [ - "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570", - "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2" + "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1", + "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5" ], "markers": "python_version >= '3.8'", - "version": "==7.1.0" + "version": "==8.4.0" }, "iniconfig": { "hashes": [ @@ -656,20 +678,20 @@ }, "ipykernel": { "hashes": [ - "sha256:1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da", - "sha256:3d44070060f9475ac2092b760123fadf105d2e2493c24848b6691a7c4f42af5c" + "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5", + "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==6.29.4" + "version": "==6.29.5" }, "ipython": { "hashes": [ - "sha256:2dcaad9049f9056f1fef63514f176c7d41f930daa78d05b82a176202818f2c14", - "sha256:3c86f284c8f3d8f2b6c662f885c4889a91df7cd52056fd02b7d8d6195d7f56e9" + "sha256:0b99a2dc9f15fd68692e898e5568725c6d49c527d36a9fb5960ffbdeaa82ff7e", + "sha256:f68b3cb8bde357a5d7adc9598d57e22a45dfbea19eb6b98286fa3b288c9cd55c" ], "markers": "python_version >= '3.10'", - "version": "==8.22.2" + "version": "==8.27.0" }, "isodate": { "hashes": [ @@ -696,27 +718,27 @@ }, "jaraco.classes": { "hashes": [ - "sha256:86b534de565381f6b3c1c830d13f931d7be1a75f0081c57dff615578676e2206", - "sha256:cb28a5ebda8bc47d8c8015307d93163464f9f2b91ab4006e09ff0ce07e8bfb30" + "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", + "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790" ], "markers": "python_version >= '3.8'", - "version": "==3.3.1" + "version": "==3.4.0" }, "jaraco.context": { "hashes": [ - "sha256:4dad2404540b936a20acedec53355bdaea223acb88fd329fa6de9261c941566e", - "sha256:5d9e95ca0faa78943ed66f6bc658dd637430f16125d86988e77844c741ff2f11" + "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", + "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4" ], - "markers": "python_version >= '3.7'", - "version": "==4.3.0" + "markers": "python_version >= '3.8'", + "version": "==6.0.1" }, "jaraco.functools": { "hashes": [ - "sha256:c279cb24c93d694ef7270f970d499cab4d3813f4e08273f95398651a634f0925", - "sha256:daf276ddf234bea897ef14f43c4e1bf9eefeac7b7a82a4dd69228ac20acff68d" + "sha256:3460c74cd0d32bf82b9576bbb3527c4364d5b27a21f5158a62aed6c4b42e23f5", + "sha256:c9d16a3ed4ccb5a889ad8e0b7a343401ee5b2a71cee6ed192d3f68bc351e94e3" ], "markers": "python_version >= '3.8'", - "version": "==4.0.0" + "version": "==4.0.2" }, "jedi": { "hashes": [ @@ -728,37 +750,37 @@ }, "jinja2": { "hashes": [ - "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa", - "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90" + "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", + "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d" ], "markers": "python_version >= '3.7'", - "version": "==3.1.3" + "version": "==3.1.4" }, "json5": { "hashes": [ - "sha256:0c638399421da959a20952782800e5c1a78c14e08e1dc9738fa10d8ec14d58c8", - "sha256:4ca101fd5c7cb47960c055ef8f4d0e31e15a7c6c48c3b6f1473fc83b6c462a13" + "sha256:34ed7d834b1341a86987ed52f3f76cd8ee184394906b6e22a1e0deb9ab294e8f", + "sha256:548e41b9be043f9426776f05df8635a00fe06104ea51ed24b67f908856e151ae" ], "markers": "python_version >= '3.8'", - "version": "==0.9.24" + "version": "==0.9.25" }, "jsonpointer": { "hashes": [ - "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a", - "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88" + "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", + "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef" ], - "version": "==2.4" + "version": "==3.0.0" }, "jsonschema": { "extras": [ "format-nongpl" ], "hashes": [ - "sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f", - "sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5" + "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", + "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566" ], "markers": "python_version >= '3.8'", - "version": "==4.21.1" + "version": "==4.23.0" }, "jsonschema-specifications": { "hashes": [ @@ -770,11 +792,11 @@ }, "jupyter-client": { "hashes": [ - "sha256:3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f", - "sha256:e842515e2bab8e19186d89fdfea7abd15e39dd581f94e399f00e2af5a1652d3f" + "sha256:2bda14d55ee5ba58552a8c53ae43d215ad9868853489213f37da060ced54d8df", + "sha256:50cbc5c66fd1b8f65ecb66bc490ab73217993632809b6e505687de18e9dea39f" ], "markers": "python_version >= '3.8'", - "version": "==8.6.1" + "version": "==8.6.2" }, "jupyter-core": { "hashes": [ @@ -794,19 +816,19 @@ }, "jupyter-lsp": { "hashes": [ - "sha256:5e50033149344065348e688608f3c6d654ef06d9856b67655bd7b6bac9ee2d59", - "sha256:da61cb63a16b6dff5eac55c2699cc36eac975645adee02c41bdfc03bf4802e77" + "sha256:45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da", + "sha256:793147a05ad446f809fd53ef1cd19a9f5256fd0a2d6b7ce943a982cb4f545001" ], "markers": "python_version >= '3.8'", - "version": "==2.2.4" + "version": "==2.2.5" }, "jupyter-server": { "hashes": [ - "sha256:77b2b49c3831fbbfbdb5048cef4350d12946191f833a24e5f83e5f8f4803e97b", - "sha256:c80bfb049ea20053c3d9641c2add4848b38073bf79f1729cea1faed32fc1c78e" + "sha256:47ff506127c2f7851a17bf4713434208fc490955d0e8632e95014a9a9afbeefd", + "sha256:66095021aa9638ced276c248b1d81862e4c50f292d575920bbe960de1c56b12b" ], "markers": "python_version >= '3.8'", - "version": "==2.13.0" + "version": "==2.14.2" }, "jupyter-server-terminals": { "hashes": [ @@ -818,11 +840,11 @@ }, "jupyterlab": { "hashes": [ - "sha256:3bc843382a25e1ab7bc31d9e39295a9f0463626692b7995597709c0ab236ab2c", - "sha256:c9ad75290cb10bfaff3624bf3fbb852319b4cce4c456613f8ebbaa98d03524db" + "sha256:73b6e0775d41a9fee7ee756c80f58a6bed4040869ccc21411dc559818874d321", + "sha256:ae7f3a1b8cb88b4f55009ce79fa7c06f99d70cd63601ee4aa91815d054f46f75" ], "markers": "python_version >= '3.8'", - "version": "==4.1.5" + "version": "==4.2.5" }, "jupyterlab-pygments": { "hashes": [ @@ -834,19 +856,19 @@ }, "jupyterlab-server": { "hashes": [ - "sha256:2098198e1e82e0db982440f9b5136175d73bea2cd42a6480aa6fd502cb23c4f9", - "sha256:eb645ecc8f9b24bac5decc7803b6d5363250e16ec5af814e516bc2c54dd88081" + "sha256:e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4", + "sha256:eb36caca59e74471988f0ae25c77945610b887f777255aa21f8065def9e51ed4" ], "markers": "python_version >= '3.8'", - "version": "==2.25.4" + "version": "==2.27.3" }, "keyring": { "hashes": [ - "sha256:9a15cd280338920388e8c1787cb8792b9755dabb3e7c61af5ac1f8cd437cefde", - "sha256:fc024ed53c7ea090e30723e6bd82f58a39dc25d9a6797d866203ecd0ee6306cb" + "sha256:8d85a1ea5d6db8515b59e1c5d1d1678b03cf7fc8b8dcfb1651e8c4a524eb42ef", + "sha256:8d963da00ccdf06e356acd9bf3b743208878751032d8599c6cc89eb51310ffae" ], "markers": "python_version >= '3.8'", - "version": "==25.0.0" + "version": "==25.3.0" }, "markdown-it-py": { "hashes": [ @@ -924,19 +946,11 @@ }, "matplotlib-inline": { "hashes": [ - "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311", - "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304" - ], - "markers": "python_version >= '3.5'", - "version": "==0.1.6" - }, - "mccabe": { - "hashes": [ - "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", - "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" + "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", + "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca" ], - "markers": "python_version >= '3.6'", - "version": "==0.7.0" + "markers": "python_version >= '3.8'", + "version": "==0.1.7" }, "mdurl": { "hashes": [ @@ -956,11 +970,11 @@ }, "more-itertools": { "hashes": [ - "sha256:686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684", - "sha256:8fccb480c43d3e99a00087634c06dd02b0d50fbf088b380de5a41a015ec239e1" + "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", + "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6" ], "markers": "python_version >= '3.8'", - "version": "==10.2.0" + "version": "==10.5.0" }, "mypy-extensions": { "hashes": [ @@ -980,19 +994,19 @@ }, "nbconvert": { "hashes": [ - "sha256:a6733b78ce3d47c3f85e504998495b07e6ea9cf9bf6ec1c98dda63ec6ad19142", - "sha256:ddeff14beeeedf3dd0bc506623e41e4507e551736de59df69a91f86700292b3b" + "sha256:05873c620fe520b6322bf8a5ad562692343fe3452abda5765c7a34b7d1aa3eb3", + "sha256:86ca91ba266b0a448dc96fa6c5b9d98affabde2867b363258703536807f9f7f4" ], "markers": "python_version >= '3.8'", - "version": "==7.16.3" + "version": "==7.16.4" }, "nbformat": { "hashes": [ - "sha256:60ed5e910ef7c6264b87d644f276b1b49e24011930deef54605188ddeb211685", - "sha256:d9476ca28676799af85385f409b49d95e199951477a159a576ef2a675151e5e8" + "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", + "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b" ], "markers": "python_version >= '3.8'", - "version": "==5.10.3" + "version": "==5.10.4" }, "nest-asyncio": { "hashes": [ @@ -1004,33 +1018,33 @@ }, "nh3": { "hashes": [ - "sha256:0316c25b76289cf23be6b66c77d3608a4fdf537b35426280032f432f14291b9a", - "sha256:1a814dd7bba1cb0aba5bcb9bebcc88fd801b63e21e2450ae6c52d3b3336bc911", - "sha256:1aa52a7def528297f256de0844e8dd680ee279e79583c76d6fa73a978186ddfb", - "sha256:22c26e20acbb253a5bdd33d432a326d18508a910e4dcf9a3316179860d53345a", - "sha256:40015514022af31975c0b3bca4014634fa13cb5dc4dbcbc00570acc781316dcc", - "sha256:40d0741a19c3d645e54efba71cb0d8c475b59135c1e3c580f879ad5514cbf028", - "sha256:551672fd71d06cd828e282abdb810d1be24e1abb7ae2543a8fa36a71c1006fe9", - "sha256:66f17d78826096291bd264f260213d2b3905e3c7fae6dfc5337d49429f1dc9f3", - "sha256:85cdbcca8ef10733bd31f931956f7fbb85145a4d11ab9e6742bbf44d88b7e351", - "sha256:a3f55fabe29164ba6026b5ad5c3151c314d136fd67415a17660b4aaddacf1b10", - "sha256:b4427ef0d2dfdec10b641ed0bdaf17957eb625b2ec0ea9329b3d28806c153d71", - "sha256:ba73a2f8d3a1b966e9cdba7b211779ad8a2561d2dba9674b8a19ed817923f65f", - "sha256:c21bac1a7245cbd88c0b0e4a420221b7bfa838a2814ee5bb924e9c2f10a1120b", - "sha256:c551eb2a3876e8ff2ac63dff1585236ed5dfec5ffd82216a7a174f7c5082a78a", - "sha256:c790769152308421283679a142dbdb3d1c46c79c823008ecea8e8141db1a2062", - "sha256:d7a25fd8c86657f5d9d576268e3b3767c5cd4f42867c9383618be8517f0f022a" - ], - "version": "==0.2.17" + "sha256:0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164", + "sha256:14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86", + "sha256:19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b", + "sha256:34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad", + "sha256:36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204", + "sha256:3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a", + "sha256:42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200", + "sha256:5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189", + "sha256:6955369e4d9f48f41e3f238a9e60f9410645db7e07435e62c6a9ea6135a4907f", + "sha256:7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811", + "sha256:8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844", + "sha256:94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4", + "sha256:a7f1b5b2c15866f2db413a3649a8fe4fd7b428ae58be2c0f6bca5eefd53ca2be", + "sha256:c8b3a1cebcba9b3669ed1a84cc65bf005728d2f0bc1ed2a6594a992e817f3a50", + "sha256:de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307", + "sha256:f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe" + ], + "version": "==0.2.18" }, "notebook": { "hashes": [ - "sha256:efc2c80043909e0faa17fce9e9b37c059c03af0ec99a4d4db84cb21d9d2e936a", - "sha256:fc6c24b9aef18d0cd57157c9c47e95833b9b0bdc599652639acf0bdb61dc7d5f" + "sha256:2ef07d4220421623ad3fe88118d687bc0450055570cdd160814a59cf3a1c516e", + "sha256:c89264081f671bc02eec0ed470a627ed791b9156cad9285226b31611d3e9fe1c" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==7.1.2" + "version": "==7.2.2" }, "notebook-shim": { "hashes": [ @@ -1054,11 +1068,11 @@ }, "packaging": { "hashes": [ - "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", - "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" + "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", + "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" ], - "markers": "python_version >= '3.7'", - "version": "==24.0" + "markers": "python_version >= '3.8'", + "version": "==24.1" }, "pandocfilters": { "hashes": [ @@ -1070,11 +1084,11 @@ }, "parso": { "hashes": [ - "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0", - "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75" + "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", + "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d" ], "markers": "python_version >= '3.6'", - "version": "==0.8.3" + "version": "==0.8.4" }, "pathspec": { "hashes": [ @@ -1102,19 +1116,19 @@ }, "platformdirs": { "hashes": [ - "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", - "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768" + "sha256:9e5e27a08aa095dd127b9f2e764d74254f482fef22b0970773bfba79d091ab8c", + "sha256:eb1c8582560b34ed4ba105009a4badf7f6f85768b30126f351328507b2beb617" ], "markers": "python_version >= '3.8'", - "version": "==4.2.0" + "version": "==4.3.2" }, "pluggy": { "hashes": [ - "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981", - "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be" + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" ], "markers": "python_version >= '3.8'", - "version": "==1.4.0" + "version": "==1.5.0" }, "prometheus-client": { "hashes": [ @@ -1126,33 +1140,34 @@ }, "prompt-toolkit": { "hashes": [ - "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d", - "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6" + "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10", + "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360" ], "markers": "python_full_version >= '3.7.0'", - "version": "==3.0.43" + "version": "==3.0.47" }, "psutil": { "hashes": [ - "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d", - "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73", - "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8", - "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2", - "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e", - "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36", - "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7", - "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c", - "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee", - "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421", - "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf", - "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81", - "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0", - "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631", - "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4", - "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8" + "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35", + "sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0", + "sha256:1e7c870afcb7d91fdea2b37c24aeb08f98b6d67257a5cb0a8bc3ac68d0f1a68c", + "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1", + "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3", + "sha256:34859b8d8f423b86e4385ff3665d3f4d94be3cdf48221fbe476e883514fdb71c", + "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd", + "sha256:6ec7588fb3ddaec7344a825afe298db83fe01bfaaab39155fa84cf1c0d6b13c3", + "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0", + "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2", + "sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6", + "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d", + "sha256:a9a3dbfb4de4f18174528d87cc352d1f788b7496991cca33c6996f40c9e3c92c", + "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0", + "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132", + "sha256:fc8c9510cde0146432bbdb433322861ee8c3efbf8589865c8bf8d21cb30c4d14", + "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==5.9.8" + "version": "==6.0.0" }, "ptyprocess": { "hashes": [ @@ -1163,53 +1178,45 @@ }, "pure-eval": { "hashes": [ - "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350", - "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3" + "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", + "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42" ], - "version": "==0.2.2" + "version": "==0.2.3" }, "pycparser": { "hashes": [ - "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", - "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" + "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", + "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc" ], - "version": "==2.21" + "markers": "python_version >= '3.8'", + "version": "==2.22" }, "pygithub": { "hashes": [ - "sha256:0148d7347a1cdeed99af905077010aef81a4dad988b0ba51d4108bf66b443f7e", - "sha256:65b499728be3ce7b0cd2cd760da3b32f0f4d7bc55e5e0677617f90f6564e793e" + "sha256:6601e22627e87bac192f1e2e39c6e6f69a43152cfb8f307cee575879320b3051", + "sha256:81935aa4bdc939fba98fee1cb47422c09157c56a27966476ff92775602b9ee24" ], - "markers": "python_version >= '3.7'", - "version": "==2.3.0" + "markers": "python_version >= '3.8'", + "version": "==2.4.0" }, "pygments": { "hashes": [ - "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c", - "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367" + "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", + "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a" ], - "markers": "python_version >= '3.7'", - "version": "==2.17.2" + "markers": "python_version >= '3.8'", + "version": "==2.18.0" }, "pyjwt": { "extras": [ "crypto" ], "hashes": [ - "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de", - "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320" - ], - "markers": "python_version >= '3.7'", - "version": "==2.8.0" - }, - "pylint": { - "hashes": [ - "sha256:507a5b60953874766d8a366e8e8c7af63e058b26345cfcb5f91f89d987fd6b74", - "sha256:6a69beb4a6f63debebaab0a3477ecd0f559aa726af4954fc948c51f7a2549e23" + "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850", + "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c" ], - "index": "pypi", - "markers": "python_full_version >= '3.8.0'", - "version": "==3.1.0" + "markers": "python_version >= '3.8'", + "version": "==2.9.0" }, "pynacl": { "hashes": [ @@ -1229,28 +1236,28 @@ }, "pyparsing": { "hashes": [ - "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad", - "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742" + "sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c", + "sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032" ], "markers": "python_full_version >= '3.6.8'", - "version": "==3.1.2" + "version": "==3.1.4" }, "pyproject-api": { "hashes": [ - "sha256:1817dc018adc0d1ff9ca1ed8c60e1623d5aaca40814b953af14a9cf9a5cae538", - "sha256:4c0116d60476b0786c88692cf4e325a9814965e2469c5998b830bba16b183675" + "sha256:2dc1654062c2b27733d8fd4cdda672b22fe8741ef1dde8e3a998a9547b071eeb", + "sha256:7ebc6cd10710f89f4cf2a2731710a98abce37ebff19427116ff2174c9236a827" ], "markers": "python_version >= '3.8'", - "version": "==1.6.1" + "version": "==1.7.1" }, "pytest": { "hashes": [ - "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7", - "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044" + "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", + "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==8.1.1" + "version": "==8.3.3" }, "pytest-cov": { "hashes": [ @@ -1279,159 +1286,178 @@ }, "pyyaml": { "hashes": [ - "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", - "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", - "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", - "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", - "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", - "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", - "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", - "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", - "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", - "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", - "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", - "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", - "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", - "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", - "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", - "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", - "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", - "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", - "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", - "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", - "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", - "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", - "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", - "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", - "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", - "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", - "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", - "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", - "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", - "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", - "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", - "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", - "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", - "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", - "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", - "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", - "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", - "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", - "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", - "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", - "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", - "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", - "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", - "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", - "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", - "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", - "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", - "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", - "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", - "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", - "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" ], - "markers": "python_version >= '3.6'", - "version": "==6.0.1" + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==6.0.2" }, "pyzmq": { "hashes": [ - "sha256:004ff469d21e86f0ef0369717351073e0e577428e514c47c8480770d5e24a565", - "sha256:00a06faa7165634f0cac1abb27e54d7a0b3b44eb9994530b8ec73cf52e15353b", - "sha256:00c48ae2fd81e2a50c3485de1b9d5c7c57cd85dc8ec55683eac16846e57ac979", - "sha256:01171fc48542348cd1a360a4b6c3e7d8f46cdcf53a8d40f84db6707a6768acc1", - "sha256:019744b99da30330798bb37df33549d59d380c78e516e3bab9c9b84f87a9592f", - "sha256:02bbc1a87b76e04fd780b45e7f695471ae6de747769e540da909173d50ff8e2d", - "sha256:02c9087b109070c5ab0b383079fa1b5f797f8d43e9a66c07a4b8b8bdecfd88ee", - "sha256:07cd61a20a535524906595e09344505a9bd46f1da7a07e504b315d41cd42eb07", - "sha256:0806175f2ae5ad4b835ecd87f5f85583316b69f17e97786f7443baaf54b9bb98", - "sha256:09dfe949e83087da88c4a76767df04b22304a682d6154de2c572625c62ad6886", - "sha256:0dabfb10ef897f3b7e101cacba1437bd3a5032ee667b7ead32bbcdd1a8422fe7", - "sha256:0ddd6d71d4ef17ba5a87becf7ddf01b371eaba553c603477679ae817a8d84d75", - "sha256:0f513130c4c361201da9bc69df25a086487250e16b5571ead521b31ff6b02220", - "sha256:0f97bc2f1f13cb16905a5f3e1fbdf100e712d841482b2237484360f8bc4cb3d7", - "sha256:11e70516688190e9c2db14fcf93c04192b02d457b582a1f6190b154691b4c93a", - "sha256:146b9b1f29ead41255387fb07be56dc29639262c0f7344f570eecdcd8d683314", - "sha256:16b726c1f6c2e7625706549f9dbe9b06004dfbec30dbed4bf50cbdfc73e5b32a", - "sha256:1b3cbba2f47062b85fe0ef9de5b987612140a9ba3a9c6d2543c6dec9f7c2ab27", - "sha256:1b9b1f2ad6498445a941d9a4fee096d387fee436e45cc660e72e768d3d8ee611", - "sha256:1ec23bd7b3a893ae676d0e54ad47d18064e6c5ae1fadc2f195143fb27373f7f6", - "sha256:246747b88917e4867e2367b005fc8eefbb4a54b7db363d6c92f89d69abfff4b6", - "sha256:25c2dbb97d38b5ac9fd15586e048ec5eb1e38f3d47fe7d92167b0c77bb3584e9", - "sha256:2c6441e0398c2baacfe5ba30c937d274cfc2dc5b55e82e3749e333aabffde561", - "sha256:2c9a79f1d2495b167119d02be7448bfba57fad2a4207c4f68abc0bab4b92925b", - "sha256:2e2713ef44be5d52dd8b8e2023d706bf66cb22072e97fc71b168e01d25192755", - "sha256:313c3794d650d1fccaaab2df942af9f2c01d6217c846177cfcbc693c7410839e", - "sha256:3516e0b6224cf6e43e341d56da15fd33bdc37fa0c06af4f029f7d7dfceceabbc", - "sha256:359f7f74b5d3c65dae137f33eb2bcfa7ad9ebefd1cab85c935f063f1dbb245cc", - "sha256:39b1067f13aba39d794a24761e385e2eddc26295826530a8c7b6c6c341584289", - "sha256:3c00c9b7d1ca8165c610437ca0c92e7b5607b2f9076f4eb4b095c85d6e680a1d", - "sha256:3c53687dde4d9d473c587ae80cc328e5b102b517447456184b485587ebd18b62", - "sha256:3e124e6b1dd3dfbeb695435dff0e383256655bb18082e094a8dd1f6293114642", - "sha256:4345c9a27f4310afbb9c01750e9461ff33d6fb74cd2456b107525bbeebcb5be3", - "sha256:45999e7f7ed5c390f2e87ece7f6c56bf979fb213550229e711e45ecc7d42ccb8", - "sha256:49151b0efece79f6a79d41a461d78535356136ee70084a1c22532fc6383f4ad0", - "sha256:4cb8fc1f8d69b411b8ec0b5f1ffbcaf14c1db95b6bccea21d83610987435f1a4", - "sha256:4e5837af3e5aaa99a091302df5ee001149baff06ad22b722d34e30df5f0d9097", - "sha256:4e6f689880d5ad87918430957297c975203a082d9a036cc426648fcbedae769b", - "sha256:5074adeacede5f810b7ef39607ee59d94e948b4fd954495bdb072f8c54558181", - "sha256:518efd91c3d8ac9f9b4f7dd0e2b7b8bf1a4fe82a308009016b07eaa48681af82", - "sha256:55875492f820d0eb3417b51d96fea549cde77893ae3790fd25491c5754ea2f68", - "sha256:5a68d491fc20762b630e5db2191dd07ff89834086740f70e978bb2ef2668be08", - "sha256:5dde6751e857910c1339890f3524de74007958557593b9e7e8c5f01cd919f8a7", - "sha256:5e319ed7d6b8f5fad9b76daa0a68497bc6f129858ad956331a5835785761e003", - "sha256:5edac3f57c7ddaacdb4d40f6ef2f9e299471fc38d112f4bc6d60ab9365445fb0", - "sha256:6cc0020b74b2e410287e5942e1e10886ff81ac77789eb20bec13f7ae681f0fdd", - "sha256:6dd0d50bbf9dca1d0bdea219ae6b40f713a3fb477c06ca3714f208fd69e16fd8", - "sha256:7598d2ba821caa37a0f9d54c25164a4fa351ce019d64d0b44b45540950458840", - "sha256:759cfd391a0996345ba94b6a5110fca9c557ad4166d86a6e81ea526c376a01e8", - "sha256:7ae8f354b895cbd85212da245f1a5ad8159e7840e37d78b476bb4f4c3f32a9fe", - "sha256:7b6d09a8962a91151f0976008eb7b29b433a560fde056ec7a3db9ec8f1075438", - "sha256:7c61e346ac34b74028ede1c6b4bcecf649d69b707b3ff9dc0fab453821b04d1e", - "sha256:7f51a7b4ead28d3fca8dda53216314a553b0f7a91ee8fc46a72b402a78c3e43d", - "sha256:82544e0e2d0c1811482d37eef297020a040c32e0687c1f6fc23a75b75db8062c", - "sha256:8807c87fa893527ae8a524c15fc505d9950d5e856f03dae5921b5e9aa3b8783b", - "sha256:889370d5174a741a62566c003ee8ddba4b04c3f09a97b8000092b7ca83ec9c49", - "sha256:8b14c75979ce932c53b79976a395cb2a8cd3aaf14aef75e8c2cb55a330b9b49d", - "sha256:8c5f80e578427d4695adac6fdf4370c14a2feafdc8cb35549c219b90652536ae", - "sha256:8e9f3fabc445d0ce320ea2c59a75fe3ea591fdbdeebec5db6de530dd4b09412e", - "sha256:93f1aa311e8bb912e34f004cf186407a4e90eec4f0ecc0efd26056bf7eda0226", - "sha256:94504ff66f278ab4b7e03e4cba7e7e400cb73bfa9d3d71f58d8972a8dc67e7a6", - "sha256:967668420f36878a3c9ecb5ab33c9d0ff8d054f9c0233d995a6d25b0e95e1b6b", - "sha256:9880078f683466b7f567b8624bfc16cad65077be046b6e8abb53bed4eeb82dd3", - "sha256:99a6b36f95c98839ad98f8c553d8507644c880cf1e0a57fe5e3a3f3969040882", - "sha256:9a18fff090441a40ffda8a7f4f18f03dc56ae73f148f1832e109f9bffa85df15", - "sha256:9add2e5b33d2cd765ad96d5eb734a5e795a0755f7fc49aa04f76d7ddda73fd70", - "sha256:a793ac733e3d895d96f865f1806f160696422554e46d30105807fdc9841b9f7d", - "sha256:a86c2dd76ef71a773e70551a07318b8e52379f58dafa7ae1e0a4be78efd1ff16", - "sha256:a8c1d566344aee826b74e472e16edae0a02e2a044f14f7c24e123002dcff1c05", - "sha256:ac170e9e048b40c605358667aca3d94e98f604a18c44bdb4c102e67070f3ac9b", - "sha256:b264bf2cc96b5bc43ce0e852be995e400376bd87ceb363822e2cb1964fcdc737", - "sha256:b8c8a419dfb02e91b453615c69568442e897aaf77561ee0064d789705ff37a92", - "sha256:bc69c96735ab501419c432110016329bf0dea8898ce16fab97c6d9106dc0b348", - "sha256:bef02cfcbded83473bdd86dd8d3729cd82b2e569b75844fb4ea08fee3c26ae41", - "sha256:c0b5ca88a8928147b7b1e2dfa09f3b6c256bc1135a1338536cbc9ea13d3b7add", - "sha256:cc69949484171cc961e6ecd4a8911b9ce7a0d1f738fcae717177c231bf77437b", - "sha256:ced111c2e81506abd1dc142e6cd7b68dd53747b3b7ae5edbea4578c5eeff96b7", - "sha256:d1299d7e964c13607efd148ca1f07dcbf27c3ab9e125d1d0ae1d580a1682399d", - "sha256:d1b604734bec94f05f81b360a272fc824334267426ae9905ff32dc2be433ab96", - "sha256:d9a5f194cf730f2b24d6af1f833c14c10f41023da46a7f736f48b6d35061e76e", - "sha256:db36c27baed588a5a8346b971477b718fdc66cf5b80cbfbd914b4d6d355e44e2", - "sha256:df0c7a16ebb94452d2909b9a7b3337940e9a87a824c4fc1c7c36bb4404cb0cde", - "sha256:e10a4b5a4b1192d74853cc71a5e9fd022594573926c2a3a4802020360aa719d8", - "sha256:e624c789359f1a16f83f35e2c705d07663ff2b4d4479bad35621178d8f0f6ea4", - "sha256:e690145a8c0c273c28d3b89d6fb32c45e0d9605b2293c10e650265bf5c11cfec", - "sha256:ea1608dd169da230a0ad602d5b1ebd39807ac96cae1845c3ceed39af08a5c6df", - "sha256:ea253b368eb41116011add00f8d5726762320b1bda892f744c91997b65754d73", - "sha256:eb7e49a17fb8c77d3119d41a4523e432eb0c6932187c37deb6fbb00cc3028088", - "sha256:ef12e259e7bc317c7597d4f6ef59b97b913e162d83b421dd0db3d6410f17a244", - "sha256:f8429b17cbb746c3e043cb986328da023657e79d5ed258b711c06a70c2ea7537", - "sha256:fa99973d2ed20417744fca0073390ad65ce225b546febb0580358e36aa90dba6", - "sha256:faf79a302f834d9e8304fafdc11d0d042266667ac45209afa57e5efc998e3872", - "sha256:fc31baa0c32a2ca660784d5af3b9487e13b61b3032cb01a115fce6588e1bed30" + "sha256:007137c9ac9ad5ea21e6ad97d3489af654381324d5d3ba614c323f60dab8fae6", + "sha256:034da5fc55d9f8da09015d368f519478a52675e558c989bfcb5cf6d4e16a7d2a", + "sha256:05590cdbc6b902101d0e65d6a4780af14dc22914cc6ab995d99b85af45362cc9", + "sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f", + "sha256:0aca98bc423eb7d153214b2df397c6421ba6373d3397b26c057af3c904452e37", + "sha256:0bed0e799e6120b9c32756203fb9dfe8ca2fb8467fed830c34c877e25638c3fc", + "sha256:0d987a3ae5a71c6226b203cfd298720e0086c7fe7c74f35fa8edddfbd6597eed", + "sha256:0eaa83fc4c1e271c24eaf8fb083cbccef8fde77ec8cd45f3c35a9a123e6da097", + "sha256:160c7e0a5eb178011e72892f99f918c04a131f36056d10d9c1afb223fc952c2d", + "sha256:17bf5a931c7f6618023cdacc7081f3f266aecb68ca692adac015c383a134ca52", + "sha256:17c412bad2eb9468e876f556eb4ee910e62d721d2c7a53c7fa31e643d35352e6", + "sha256:18c8dc3b7468d8b4bdf60ce9d7141897da103c7a4690157b32b60acb45e333e6", + "sha256:1a534f43bc738181aa7cbbaf48e3eca62c76453a40a746ab95d4b27b1111a7d2", + "sha256:1c17211bc037c7d88e85ed8b7d8f7e52db6dc8eca5590d162717c654550f7282", + "sha256:1f3496d76b89d9429a656293744ceca4d2ac2a10ae59b84c1da9b5165f429ad3", + "sha256:1fcc03fa4997c447dce58264e93b5aa2d57714fbe0f06c07b7785ae131512732", + "sha256:226af7dcb51fdb0109f0016449b357e182ea0ceb6b47dfb5999d569e5db161d5", + "sha256:23f4aad749d13698f3f7b64aad34f5fc02d6f20f05999eebc96b89b01262fb18", + "sha256:25bf2374a2a8433633c65ccb9553350d5e17e60c8eb4de4d92cc6bd60f01d306", + "sha256:28ad5233e9c3b52d76196c696e362508959741e1a005fb8fa03b51aea156088f", + "sha256:28c812d9757fe8acecc910c9ac9dafd2ce968c00f9e619db09e9f8f54c3a68a3", + "sha256:29c6a4635eef69d68a00321e12a7d2559fe2dfccfa8efae3ffb8e91cd0b36a8b", + "sha256:29c7947c594e105cb9e6c466bace8532dc1ca02d498684128b339799f5248277", + "sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a", + "sha256:2ae90ff9dad33a1cfe947d2c40cb9cb5e600d759ac4f0fd22616ce6540f72797", + "sha256:2c4a71d5d6e7b28a47a394c0471b7e77a0661e2d651e7ae91e0cab0a587859ca", + "sha256:2ea4ad4e6a12e454de05f2949d4beddb52460f3de7c8b9d5c46fbb7d7222e02c", + "sha256:2eb7735ee73ca1b0d71e0e67c3739c689067f055c764f73aac4cc8ecf958ee3f", + "sha256:31507f7b47cc1ead1f6e86927f8ebb196a0bab043f6345ce070f412a59bf87b5", + "sha256:35cffef589bcdc587d06f9149f8d5e9e8859920a071df5a2671de2213bef592a", + "sha256:367b4f689786fca726ef7a6c5ba606958b145b9340a5e4808132cc65759abd44", + "sha256:39887ac397ff35b7b775db7201095fc6310a35fdbae85bac4523f7eb3b840e20", + "sha256:3a495b30fc91db2db25120df5847d9833af237546fd59170701acd816ccc01c4", + "sha256:3b55a4229ce5da9497dd0452b914556ae58e96a4381bb6f59f1305dfd7e53fc8", + "sha256:402b190912935d3db15b03e8f7485812db350d271b284ded2b80d2e5704be780", + "sha256:43a47408ac52647dfabbc66a25b05b6a61700b5165807e3fbd40063fcaf46386", + "sha256:4661c88db4a9e0f958c8abc2b97472e23061f0bc737f6f6179d7a27024e1faa5", + "sha256:46a446c212e58456b23af260f3d9fb785054f3e3653dbf7279d8f2b5546b21c2", + "sha256:470d4a4f6d48fb34e92d768b4e8a5cc3780db0d69107abf1cd7ff734b9766eb0", + "sha256:49d34ab71db5a9c292a7644ce74190b1dd5a3475612eefb1f8be1d6961441971", + "sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b", + "sha256:4d80b1dd99c1942f74ed608ddb38b181b87476c6a966a88a950c7dee118fdf50", + "sha256:4da04c48873a6abdd71811c5e163bd656ee1b957971db7f35140a2d573f6949c", + "sha256:4f78c88905461a9203eac9faac157a2a0dbba84a0fd09fd29315db27be40af9f", + "sha256:4ff9dc6bc1664bb9eec25cd17506ef6672d506115095411e237d571e92a58231", + "sha256:5506f06d7dc6ecf1efacb4a013b1f05071bb24b76350832c96449f4a2d95091c", + "sha256:55cf66647e49d4621a7e20c8d13511ef1fe1efbbccf670811864452487007e08", + "sha256:5a509df7d0a83a4b178d0f937ef14286659225ef4e8812e05580776c70e155d5", + "sha256:5c2b3bfd4b9689919db068ac6c9911f3fcb231c39f7dd30e3138be94896d18e6", + "sha256:6835dd60355593de10350394242b5757fbbd88b25287314316f266e24c61d073", + "sha256:689c5d781014956a4a6de61d74ba97b23547e431e9e7d64f27d4922ba96e9d6e", + "sha256:6a96179a24b14fa6428cbfc08641c779a53f8fcec43644030328f44034c7f1f4", + "sha256:6ace4f71f1900a548f48407fc9be59c6ba9d9aaf658c2eea6cf2779e72f9f317", + "sha256:6b274e0762c33c7471f1a7471d1a2085b1a35eba5cdc48d2ae319f28b6fc4de3", + "sha256:706e794564bec25819d21a41c31d4df2d48e1cc4b061e8d345d7fb4dd3e94072", + "sha256:70fc7fcf0410d16ebdda9b26cbd8bf8d803d220a7f3522e060a69a9c87bf7bad", + "sha256:7133d0a1677aec369d67dd78520d3fa96dd7f3dcec99d66c1762870e5ea1a50a", + "sha256:7445be39143a8aa4faec43b076e06944b8f9d0701b669df4af200531b21e40bb", + "sha256:76589c020680778f06b7e0b193f4b6dd66d470234a16e1df90329f5e14a171cd", + "sha256:76589f2cd6b77b5bdea4fca5992dc1c23389d68b18ccc26a53680ba2dc80ff2f", + "sha256:77eb0968da535cba0470a5165468b2cac7772cfb569977cff92e240f57e31bef", + "sha256:794a4562dcb374f7dbbfb3f51d28fb40123b5a2abadee7b4091f93054909add5", + "sha256:7ad1bc8d1b7a18497dda9600b12dc193c577beb391beae5cd2349184db40f187", + "sha256:7f98f6dfa8b8ccaf39163ce872bddacca38f6a67289116c8937a02e30bbe9711", + "sha256:8423c1877d72c041f2c263b1ec6e34360448decfb323fa8b94e85883043ef988", + "sha256:8685fa9c25ff00f550c1fec650430c4b71e4e48e8d852f7ddcf2e48308038640", + "sha256:878206a45202247781472a2d99df12a176fef806ca175799e1c6ad263510d57c", + "sha256:89289a5ee32ef6c439086184529ae060c741334b8970a6855ec0b6ad3ff28764", + "sha256:8ab5cad923cc95c87bffee098a27856c859bd5d0af31bd346035aa816b081fe1", + "sha256:8b435f2753621cd36e7c1762156815e21c985c72b19135dac43a7f4f31d28dd1", + "sha256:8be4700cd8bb02cc454f630dcdf7cfa99de96788b80c51b60fe2fe1dac480289", + "sha256:8c997098cc65e3208eca09303630e84d42718620e83b733d0fd69543a9cab9cb", + "sha256:8ea039387c10202ce304af74def5021e9adc6297067f3441d348d2b633e8166a", + "sha256:8f7e66c7113c684c2b3f1c83cdd3376103ee0ce4c49ff80a648643e57fb22218", + "sha256:90412f2db8c02a3864cbfc67db0e3dcdbda336acf1c469526d3e869394fe001c", + "sha256:92a78853d7280bffb93df0a4a6a2498cba10ee793cc8076ef797ef2f74d107cf", + "sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7", + "sha256:9cb3a6460cdea8fe8194a76de8895707e61ded10ad0be97188cc8463ffa7e3a8", + "sha256:9dd8cd1aeb00775f527ec60022004d030ddc51d783d056e3e23e74e623e33726", + "sha256:9ed69074a610fad1c2fda66180e7b2edd4d31c53f2d1872bc2d1211563904cd9", + "sha256:9edda2df81daa129b25a39b86cb57dfdfe16f7ec15b42b19bfac503360d27a93", + "sha256:a2224fa4a4c2ee872886ed00a571f5e967c85e078e8e8c2530a2fb01b3309b88", + "sha256:a4f96f0d88accc3dbe4a9025f785ba830f968e21e3e2c6321ccdfc9aef755115", + "sha256:aedd5dd8692635813368e558a05266b995d3d020b23e49581ddd5bbe197a8ab6", + "sha256:aee22939bb6075e7afededabad1a56a905da0b3c4e3e0c45e75810ebe3a52672", + "sha256:b1d464cb8d72bfc1a3adc53305a63a8e0cac6bc8c5a07e8ca190ab8d3faa43c2", + "sha256:b8f86dd868d41bea9a5f873ee13bf5551c94cf6bc51baebc6f85075971fe6eea", + "sha256:bc6bee759a6bddea5db78d7dcd609397449cb2d2d6587f48f3ca613b19410cfc", + "sha256:bea2acdd8ea4275e1278350ced63da0b166421928276c7c8e3f9729d7402a57b", + "sha256:bfa832bfa540e5b5c27dcf5de5d82ebc431b82c453a43d141afb1e5d2de025fa", + "sha256:c0e6091b157d48cbe37bd67233318dbb53e1e6327d6fc3bb284afd585d141003", + "sha256:c3789bd5768ab5618ebf09cef6ec2b35fed88709b104351748a63045f0ff9797", + "sha256:c530e1eecd036ecc83c3407f77bb86feb79916d4a33d11394b8234f3bd35b940", + "sha256:c811cfcd6a9bf680236c40c6f617187515269ab2912f3d7e8c0174898e2519db", + "sha256:c92d73464b886931308ccc45b2744e5968cbaade0b1d6aeb40d8ab537765f5bc", + "sha256:cccba051221b916a4f5e538997c45d7d136a5646442b1231b916d0164067ea27", + "sha256:cdeabcff45d1c219636ee2e54d852262e5c2e085d6cb476d938aee8d921356b3", + "sha256:ced65e5a985398827cc9276b93ef6dfabe0273c23de8c7931339d7e141c2818e", + "sha256:d049df610ac811dcffdc147153b414147428567fbbc8be43bb8885f04db39d98", + "sha256:dacd995031a01d16eec825bf30802fceb2c3791ef24bcce48fa98ce40918c27b", + "sha256:ddf33d97d2f52d89f6e6e7ae66ee35a4d9ca6f36eda89c24591b0c40205a3629", + "sha256:ded0fc7d90fe93ae0b18059930086c51e640cdd3baebdc783a695c77f123dcd9", + "sha256:e3e0210287329272539eea617830a6a28161fbbd8a3271bf4150ae3e58c5d0e6", + "sha256:e6fa2e3e683f34aea77de8112f6483803c96a44fd726d7358b9888ae5bb394ec", + "sha256:ea0eb6af8a17fa272f7b98d7bebfab7836a0d62738e16ba380f440fceca2d951", + "sha256:ea7f69de383cb47522c9c208aec6dd17697db7875a4674c4af3f8cfdac0bdeae", + "sha256:eac5174677da084abf378739dbf4ad245661635f1600edd1221f150b165343f4", + "sha256:fc4f7a173a5609631bb0c42c23d12c49df3966f89f496a51d3eb0ec81f4519d6", + "sha256:fdb5b3e311d4d4b0eb8b3e8b4d1b0a512713ad7e6a68791d0923d1aec433d919" ], - "markers": "python_version >= '3.6'", - "version": "==25.1.2" + "markers": "python_version >= '3.7'", + "version": "==26.2.0" }, "rdflib": { "hashes": [ @@ -1460,19 +1486,19 @@ }, "referencing": { "hashes": [ - "sha256:5773bd84ef41799a5a8ca72dc34590c041eb01bf9aa02632b4a973fb0181a844", - "sha256:d53ae300ceddd3169f1ffa9caf2cb7b769e92657e4fafb23d34b93679116dfd4" + "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", + "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de" ], "markers": "python_version >= '3.8'", - "version": "==0.34.0" + "version": "==0.35.1" }, "requests": { "hashes": [ - "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", - "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], - "markers": "python_version >= '3.7'", - "version": "==2.31.0" + "markers": "python_version >= '3.8'", + "version": "==2.32.3" }, "requests-toolbelt": { "hashes": [ @@ -1508,140 +1534,145 @@ }, "rich": { "hashes": [ - "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222", - "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432" + "sha256:1760a3c0848469b97b558fc61c85233e3dafb69c7a071b4d60c38099d3cd4c06", + "sha256:8260cda28e3db6bf04d2d1ef4dbc03ba80a824c88b0e7668a0f23126a424844a" ], "markers": "python_full_version >= '3.7.0'", - "version": "==13.7.1" + "version": "==13.8.1" }, "rpds-py": { "hashes": [ - "sha256:01e36a39af54a30f28b73096dd39b6802eddd04c90dbe161c1b8dbe22353189f", - "sha256:044a3e61a7c2dafacae99d1e722cc2d4c05280790ec5a05031b3876809d89a5c", - "sha256:08231ac30a842bd04daabc4d71fddd7e6d26189406d5a69535638e4dcb88fe76", - "sha256:08f9ad53c3f31dfb4baa00da22f1e862900f45908383c062c27628754af2e88e", - "sha256:0ab39c1ba9023914297dd88ec3b3b3c3f33671baeb6acf82ad7ce883f6e8e157", - "sha256:0af039631b6de0397ab2ba16eaf2872e9f8fca391b44d3d8cac317860a700a3f", - "sha256:0b8612cd233543a3781bc659c731b9d607de65890085098986dfd573fc2befe5", - "sha256:11a8c85ef4a07a7638180bf04fe189d12757c696eb41f310d2426895356dcf05", - "sha256:1374f4129f9bcca53a1bba0bb86bf78325a0374577cf7e9e4cd046b1e6f20e24", - "sha256:1d4acf42190d449d5e89654d5c1ed3a4f17925eec71f05e2a41414689cda02d1", - "sha256:1d9a5be316c15ffb2b3c405c4ff14448c36b4435be062a7f578ccd8b01f0c4d8", - "sha256:1df3659d26f539ac74fb3b0c481cdf9d725386e3552c6fa2974f4d33d78e544b", - "sha256:22806714311a69fd0af9b35b7be97c18a0fc2826e6827dbb3a8c94eac6cf7eeb", - "sha256:2644e47de560eb7bd55c20fc59f6daa04682655c58d08185a9b95c1970fa1e07", - "sha256:2e6d75ab12b0bbab7215e5d40f1e5b738aa539598db27ef83b2ec46747df90e1", - "sha256:30f43887bbae0d49113cbaab729a112251a940e9b274536613097ab8b4899cf6", - "sha256:34b18ba135c687f4dac449aa5157d36e2cbb7c03cbea4ddbd88604e076aa836e", - "sha256:36b3ee798c58ace201289024b52788161e1ea133e4ac93fba7d49da5fec0ef9e", - "sha256:39514da80f971362f9267c600b6d459bfbbc549cffc2cef8e47474fddc9b45b1", - "sha256:39f5441553f1c2aed4de4377178ad8ff8f9d733723d6c66d983d75341de265ab", - "sha256:3a96e0c6a41dcdba3a0a581bbf6c44bb863f27c541547fb4b9711fd8cf0ffad4", - "sha256:3f26b5bd1079acdb0c7a5645e350fe54d16b17bfc5e71f371c449383d3342e17", - "sha256:41ef53e7c58aa4ef281da975f62c258950f54b76ec8e45941e93a3d1d8580594", - "sha256:42821446ee7a76f5d9f71f9e33a4fb2ffd724bb3e7f93386150b61a43115788d", - "sha256:43fbac5f22e25bee1d482c97474f930a353542855f05c1161fd804c9dc74a09d", - "sha256:4457a94da0d5c53dc4b3e4de1158bdab077db23c53232f37a3cb7afdb053a4e3", - "sha256:465a3eb5659338cf2a9243e50ad9b2296fa15061736d6e26240e713522b6235c", - "sha256:482103aed1dfe2f3b71a58eff35ba105289b8d862551ea576bd15479aba01f66", - "sha256:4832d7d380477521a8c1644bbab6588dfedea5e30a7d967b5fb75977c45fd77f", - "sha256:4901165d170a5fde6f589acb90a6b33629ad1ec976d4529e769c6f3d885e3e80", - "sha256:5307def11a35f5ae4581a0b658b0af8178c65c530e94893345bebf41cc139d33", - "sha256:5417558f6887e9b6b65b4527232553c139b57ec42c64570569b155262ac0754f", - "sha256:56a737287efecafc16f6d067c2ea0117abadcd078d58721f967952db329a3e5c", - "sha256:586f8204935b9ec884500498ccc91aa869fc652c40c093bd9e1471fbcc25c022", - "sha256:5b4e7d8d6c9b2e8ee2d55c90b59c707ca59bc30058269b3db7b1f8df5763557e", - "sha256:5ddcba87675b6d509139d1b521e0c8250e967e63b5909a7e8f8944d0f90ff36f", - "sha256:618a3d6cae6ef8ec88bb76dd80b83cfe415ad4f1d942ca2a903bf6b6ff97a2da", - "sha256:635dc434ff724b178cb192c70016cc0ad25a275228f749ee0daf0eddbc8183b1", - "sha256:661d25cbffaf8cc42e971dd570d87cb29a665f49f4abe1f9e76be9a5182c4688", - "sha256:66e6a3af5a75363d2c9a48b07cb27c4ea542938b1a2e93b15a503cdfa8490795", - "sha256:67071a6171e92b6da534b8ae326505f7c18022c6f19072a81dcf40db2638767c", - "sha256:685537e07897f173abcf67258bee3c05c374fa6fff89d4c7e42fb391b0605e98", - "sha256:69e64831e22a6b377772e7fb337533c365085b31619005802a79242fee620bc1", - "sha256:6b0817e34942b2ca527b0e9298373e7cc75f429e8da2055607f4931fded23e20", - "sha256:6c81e5f372cd0dc5dc4809553d34f832f60a46034a5f187756d9b90586c2c307", - "sha256:6d7faa6f14017c0b1e69f5e2c357b998731ea75a442ab3841c0dbbbfe902d2c4", - "sha256:6ef0befbb5d79cf32d0266f5cff01545602344eda89480e1dd88aca964260b18", - "sha256:6ef687afab047554a2d366e112dd187b62d261d49eb79b77e386f94644363294", - "sha256:7223a2a5fe0d217e60a60cdae28d6949140dde9c3bcc714063c5b463065e3d66", - "sha256:77f195baa60a54ef9d2de16fbbfd3ff8b04edc0c0140a761b56c267ac11aa467", - "sha256:793968759cd0d96cac1e367afd70c235867831983f876a53389ad869b043c948", - "sha256:7bd339195d84439cbe5771546fe8a4e8a7a045417d8f9de9a368c434e42a721e", - "sha256:7cd863afe7336c62ec78d7d1349a2f34c007a3cc6c2369d667c65aeec412a5b1", - "sha256:7f2facbd386dd60cbbf1a794181e6aa0bd429bd78bfdf775436020172e2a23f0", - "sha256:84ffab12db93b5f6bad84c712c92060a2d321b35c3c9960b43d08d0f639d60d7", - "sha256:8c8370641f1a7f0e0669ddccca22f1da893cef7628396431eb445d46d893e5cd", - "sha256:8db715ebe3bb7d86d77ac1826f7d67ec11a70dbd2376b7cc214199360517b641", - "sha256:8e8916ae4c720529e18afa0b879473049e95949bf97042e938530e072fde061d", - "sha256:8f03bccbd8586e9dd37219bce4d4e0d3ab492e6b3b533e973fa08a112cb2ffc9", - "sha256:8f2fc11e8fe034ee3c34d316d0ad8808f45bc3b9ce5857ff29d513f3ff2923a1", - "sha256:923d39efa3cfb7279a0327e337a7958bff00cc447fd07a25cddb0a1cc9a6d2da", - "sha256:93df1de2f7f7239dc9cc5a4a12408ee1598725036bd2dedadc14d94525192fc3", - "sha256:998e33ad22dc7ec7e030b3df701c43630b5bc0d8fbc2267653577e3fec279afa", - "sha256:99f70b740dc04d09e6b2699b675874367885217a2e9f782bdf5395632ac663b7", - "sha256:9a00312dea9310d4cb7dbd7787e722d2e86a95c2db92fbd7d0155f97127bcb40", - "sha256:9d54553c1136b50fd12cc17e5b11ad07374c316df307e4cfd6441bea5fb68496", - "sha256:9dbbeb27f4e70bfd9eec1be5477517365afe05a9b2c441a0b21929ee61048124", - "sha256:a1ce3ba137ed54f83e56fb983a5859a27d43a40188ba798993812fed73c70836", - "sha256:a34d557a42aa28bd5c48a023c570219ba2593bcbbb8dc1b98d8cf5d529ab1434", - "sha256:a5f446dd5055667aabaee78487f2b5ab72e244f9bc0b2ffebfeec79051679984", - "sha256:ad36cfb355e24f1bd37cac88c112cd7730873f20fb0bdaf8ba59eedf8216079f", - "sha256:aec493917dd45e3c69d00a8874e7cbed844efd935595ef78a0f25f14312e33c6", - "sha256:b316144e85316da2723f9d8dc75bada12fa58489a527091fa1d5a612643d1a0e", - "sha256:b34ae4636dfc4e76a438ab826a0d1eed2589ca7d9a1b2d5bb546978ac6485461", - "sha256:b34b7aa8b261c1dbf7720b5d6f01f38243e9b9daf7e6b8bc1fd4657000062f2c", - "sha256:bc362ee4e314870a70f4ae88772d72d877246537d9f8cb8f7eacf10884862432", - "sha256:bed88b9a458e354014d662d47e7a5baafd7ff81c780fd91584a10d6ec842cb73", - "sha256:c0013fe6b46aa496a6749c77e00a3eb07952832ad6166bd481c74bda0dcb6d58", - "sha256:c0b5dcf9193625afd8ecc92312d6ed78781c46ecbf39af9ad4681fc9f464af88", - "sha256:c4325ff0442a12113a6379af66978c3fe562f846763287ef66bdc1d57925d337", - "sha256:c463ed05f9dfb9baebef68048aed8dcdc94411e4bf3d33a39ba97e271624f8f7", - "sha256:c8362467a0fdeccd47935f22c256bec5e6abe543bf0d66e3d3d57a8fb5731863", - "sha256:cd5bf1af8efe569654bbef5a3e0a56eca45f87cfcffab31dd8dde70da5982475", - "sha256:cf1ea2e34868f6fbf070e1af291c8180480310173de0b0c43fc38a02929fc0e3", - "sha256:d62dec4976954a23d7f91f2f4530852b0c7608116c257833922a896101336c51", - "sha256:d68c93e381010662ab873fea609bf6c0f428b6d0bb00f2c6939782e0818d37bf", - "sha256:d7c36232a90d4755b720fbd76739d8891732b18cf240a9c645d75f00639a9024", - "sha256:dd18772815d5f008fa03d2b9a681ae38d5ae9f0e599f7dda233c439fcaa00d40", - "sha256:ddc2f4dfd396c7bfa18e6ce371cba60e4cf9d2e5cdb71376aa2da264605b60b9", - "sha256:e003b002ec72c8d5a3e3da2989c7d6065b47d9eaa70cd8808b5384fbb970f4ec", - "sha256:e32a92116d4f2a80b629778280103d2a510a5b3f6314ceccd6e38006b5e92dcb", - "sha256:e4461d0f003a0aa9be2bdd1b798a041f177189c1a0f7619fe8c95ad08d9a45d7", - "sha256:e541ec6f2ec456934fd279a3120f856cd0aedd209fc3852eca563f81738f6861", - "sha256:e546e768d08ad55b20b11dbb78a745151acbd938f8f00d0cfbabe8b0199b9880", - "sha256:ea7d4a99f3b38c37eac212dbd6ec42b7a5ec51e2c74b5d3223e43c811609e65f", - "sha256:ed4eb745efbff0a8e9587d22a84be94a5eb7d2d99c02dacf7bd0911713ed14dd", - "sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca", - "sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58", - "sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e" - ], - "markers": "python_version >= '3.8'", - "version": "==0.18.0" + "sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c", + "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585", + "sha256:11ef6ce74616342888b69878d45e9f779b95d4bd48b382a229fe624a409b72c5", + "sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6", + "sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef", + "sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2", + "sha256:1e5f3cd7397c8f86c8cc72d5a791071431c108edd79872cdd96e00abd8497d29", + "sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318", + "sha256:22e6c9976e38f4d8c4a63bd8a8edac5307dffd3ee7e6026d97f3cc3a2dc02a0b", + "sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399", + "sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739", + "sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee", + "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174", + "sha256:338ca4539aad4ce70a656e5187a3a31c5204f261aef9f6ab50e50bcdffaf050a", + "sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344", + "sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2", + "sha256:3d2b1ad682a3dfda2a4e8ad8572f3100f95fad98cb99faf37ff0ddfe9cbf9d03", + "sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5", + "sha256:3fde368e9140312b6e8b6c09fb9f8c8c2f00999d1823403ae90cc00480221b22", + "sha256:40ce74fc86ee4645d0a225498d091d8bc61f39b709ebef8204cb8b5a464d3c0e", + "sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96", + "sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91", + "sha256:4b16aa0107ecb512b568244ef461f27697164d9a68d8b35090e9b0c1c8b27752", + "sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075", + "sha256:4fe84294c7019456e56d93e8ababdad5a329cd25975be749c3f5f558abb48253", + "sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee", + "sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad", + "sha256:54b43a2b07db18314669092bb2de584524d1ef414588780261e31e85846c26a5", + "sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce", + "sha256:569b3ea770c2717b730b61998b6c54996adee3cef69fc28d444f3e7920313cf7", + "sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b", + "sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8", + "sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57", + "sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3", + "sha256:5b4f105deeffa28bbcdff6c49b34e74903139afa690e35d2d9e3c2c2fba18cec", + "sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209", + "sha256:614fdafe9f5f19c63ea02817fa4861c606a59a604a77c8cdef5aa01d28b97921", + "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045", + "sha256:65794e4048ee837494aea3c21a28ad5fc080994dfba5b036cf84de37f7ad5074", + "sha256:6632f2d04f15d1bd6fe0eedd3b86d9061b836ddca4c03d5cf5c7e9e6b7c14580", + "sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7", + "sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5", + "sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3", + "sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0", + "sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24", + "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139", + "sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db", + "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc", + "sha256:9824fb430c9cf9af743cf7aaf6707bf14323fb51ee74425c380f4c846ea70789", + "sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f", + "sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2", + "sha256:9d35cef91e59ebbeaa45214861874bc6f19eb35de96db73e467a8358d701a96c", + "sha256:a1862d2d7ce1674cffa6d186d53ca95c6e17ed2b06b3f4c476173565c862d232", + "sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6", + "sha256:aa7f429242aae2947246587d2964fad750b79e8c233a2367f71b554e9447949c", + "sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29", + "sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489", + "sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94", + "sha256:af0fc424a5842a11e28956e69395fbbeab2c97c42253169d87e90aac2886d751", + "sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2", + "sha256:b4c29cbbba378759ac5786730d1c3cb4ec6f8ababf5c42a9ce303dc4b3d08cda", + "sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9", + "sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51", + "sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c", + "sha256:b8c00a3b1e70c1d3891f0db1b05292747f0dbcfb49c43f9244d04c70fbc40eb8", + "sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989", + "sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511", + "sha256:c3e130fd0ec56cb76eb49ef52faead8ff09d13f4527e9b0c400307ff72b408e1", + "sha256:c52d3f2f82b763a24ef52f5d24358553e8403ce05f893b5347098014f2d9eff2", + "sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150", + "sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c", + "sha256:ce9845054c13696f7af7f2b353e6b4f676dab1b4b215d7fe5e05c6f8bb06f965", + "sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f", + "sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58", + "sha256:d0b67d87bb45ed1cd020e8fbf2307d449b68abc45402fe1a4ac9e46c3c8b192b", + "sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f", + "sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d", + "sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821", + "sha256:d72278a30111e5b5525c1dd96120d9e958464316f55adb030433ea905866f4de", + "sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121", + "sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855", + "sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272", + "sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60", + "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02", + "sha256:def7400461c3a3f26e49078302e1c1b38f6752342c77e3cf72ce91ca69fb1bc1", + "sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140", + "sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879", + "sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940", + "sha256:e6900ecdd50ce0facf703f7a00df12374b74bbc8ad9fe0f6559947fb20f82364", + "sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4", + "sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e", + "sha256:ec31a99ca63bf3cd7f1a5ac9fe95c5e2d060d3c768a09bc1d16e235840861420", + "sha256:f0475242f447cc6cb8a9dd486d68b2ef7fbee84427124c232bff5f63b1fe11e5", + "sha256:f2fbf7db2012d4876fb0d66b5b9ba6591197b0f165db8d99371d976546472a24", + "sha256:f60012a73aa396be721558caa3a6fd49b3dd0033d1675c6d59c4502e870fcf0c", + "sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf", + "sha256:f90a4cd061914a60bd51c68bcb4357086991bd0bb93d8aa66a6da7701370708f", + "sha256:f918a1a130a6dfe1d7fe0f105064141342e7dd1611f2e6a21cd2f5c8cb1cfb3e", + "sha256:fa518bcd7600c584bf42e6617ee8132869e877db2f76bcdc281ec6a4113a53ab", + "sha256:faefcc78f53a88f3076b7f8be0a8f8d35133a3ecf7f3770895c25f8813460f08", + "sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92", + "sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a", + "sha256:fdfc3a892927458d98f3d55428ae46b921d1f7543b89382fdb483f5640daaec8" + ], + "markers": "python_version >= '3.8'", + "version": "==0.20.0" }, "ruff": { "hashes": [ - "sha256:3f3860057590e810c7ffea75669bdc6927bfd91e29b4baa9258fd48b540a4365", - "sha256:519cf6a0ebed244dce1dc8aecd3dc99add7a2ee15bb68cf19588bb5bf58e0488", - "sha256:60c870a7d46efcbc8385d27ec07fe534ac32f3b251e4fc44b3cbfd9e09609ef4", - "sha256:64abeed785dad51801b423fa51840b1764b35d6c461ea8caef9cf9e5e5ab34d9", - "sha256:6810563cc08ad0096b57c717bd78aeac888a1bfd38654d9113cb3dc4d3f74232", - "sha256:6fc14fa742e1d8f24910e1fff0bd5e26d395b0e0e04cc1b15c7c5e5fe5b4af91", - "sha256:986f2377f7cf12efac1f515fc1a5b753c000ed1e0a6de96747cdf2da20a1b369", - "sha256:98e98300056445ba2cc27d0b325fd044dc17fcc38e4e4d2c7711585bd0a958ed", - "sha256:af27ac187c0a331e8ef91d84bf1c3c6a5dea97e912a7560ac0cef25c526a4102", - "sha256:bb0acfb921030d00070539c038cd24bb1df73a2981e9f55942514af8b17be94e", - "sha256:c4fd98e85869603e65f554fdc5cddf0712e352fe6e61d29d5a6fe087ec82b76c", - "sha256:cf133dd744f2470b347f602452a88e70dadfbe0fcfb5fd46e093d55da65f82f7", - "sha256:cf187a7e7098233d0d0c71175375c5162f880126c4c716fa28a8ac418dcf3378", - "sha256:d3ee7880f653cc03749a3bfea720cf2a192e4f884925b0cf7eecce82f0ce5854", - "sha256:de0d5069b165e5a32b3c6ffbb81c350b1e3d3483347196ffdf86dc0ef9e37dd6", - "sha256:df52972138318bc7546d92348a1ee58449bc3f9eaf0db278906eb511889c4b50", - "sha256:f0f4484c6541a99862b693e13a151435a279b271cff20e37101116a21e2a1ad1" + "sha256:0308610470fcc82969082fc83c76c0d362f562e2f0cdab0586516f03a4e06ec6", + "sha256:0b52387d3289ccd227b62102c24714ed75fbba0b16ecc69a923a37e3b5e0aaaa", + "sha256:0ea086601b22dc5e7693a78f3fcfc460cceabfdf3bdc36dc898792aba48fbad6", + "sha256:34d5efad480193c046c86608dbba2bccdc1c5fd11950fb271f8086e0c763a5d1", + "sha256:50e30b437cebef547bd5c3edf9ce81343e5dd7c737cb36ccb4fe83573f3d392e", + "sha256:549daccee5227282289390b0222d0fbee0275d1db6d514550d65420053021a58", + "sha256:66dbfea86b663baab8fcae56c59f190caba9398df1488164e2df53e216248baa", + "sha256:7862f42fc1a4aca1ea3ffe8a11f67819d183a5693b228f0bb3a531f5e40336fc", + "sha256:803b96dea21795a6c9d5bfa9e96127cc9c31a1987802ca68f35e5c95aed3fc0d", + "sha256:932063a03bac394866683e15710c25b8690ccdca1cf192b9a98260332ca93408", + "sha256:ac3b5bfbee99973f80aa1b7cbd1c9cbce200883bdd067300c22a6cc1c7fba212", + "sha256:ac4b75e898ed189b3708c9ab3fc70b79a433219e1e87193b4f2b77251d058d14", + "sha256:bedff9e4f004dad5f7f76a9d39c4ca98af526c9b1695068198b3bda8c085ef60", + "sha256:c44536df7b93a587de690e124b89bd47306fddd59398a0fb12afd6133c7b3818", + "sha256:c4b153fc152af51855458e79e835fb6b933032921756cec9af7d0ba2aa01a258", + "sha256:d02a4127a86de23002e694d7ff19f905c51e338c72d8e09b56bfb60e1681724f", + "sha256:eebe4ff1967c838a1a9618a5a59a3b0a00406f8d7eefee97c70411fefc353617", + "sha256:f0f8968feea5ce3777c0d8365653d5e91c40c31a81d95824ba61d871a11b8523" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==0.3.4" + "version": "==0.6.4" }, "semantic-version": { "hashes": [ @@ -1653,20 +1684,20 @@ }, "send2trash": { "hashes": [ - "sha256:a384719d99c07ce1eefd6905d2decb6f8b7ed054025bb0e618919f945de4f679", - "sha256:c132d59fa44b9ca2b1699af5c86f57ce9f4c5eb56629d5d55fbb7a35f84e2312" + "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9", + "sha256:b18e7a3966d99871aefeb00cfbcfdced55ce4871194810fc71f4aa484b953abf" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.8.2" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", + "version": "==1.8.3" }, "setuptools": { "hashes": [ - "sha256:0ff4183f8f42cd8fa3acea16c45205521a4ef28f73c6391d8a25e92893134f2e", - "sha256:c21c49fb1042386df081cb5d86759792ab89efca84cf114889191cd09aacc80c" + "sha256:5f4c08aa4d3ebcb57a50c33b1b07e94315d7fc7230f7115e47fc99776c8ce308", + "sha256:95b40ed940a1c67eb70fc099094bd6e99c6ee7c23aa2306f4d2697ba7916f9c6" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==69.2.0" + "version": "==74.1.2" }, "six": { "hashes": [ @@ -1708,51 +1739,53 @@ }, "soupsieve": { "hashes": [ - "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690", - "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7" + "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", + "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9" ], "markers": "python_version >= '3.8'", - "version": "==2.5" + "version": "==2.6" }, "sphinx": { "hashes": [ - "sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560", - "sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5" + "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe", + "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239" ], + "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==7.2.6" + "version": "==7.4.7" }, "sphinx-rtd-theme": { "hashes": [ "sha256:bd5d7b80622406762073a04ef8fadc5f9151261563d47027de09910ce03afe6b", "sha256:ec93d0856dc280cf3aee9a4c9807c60e027c7f7b461b77aeffed682e68f0e586" ], + "index": "pypi", "markers": "python_version >= '3.6'", "version": "==2.0.0" }, "sphinxcontrib-applehelp": { "hashes": [ - "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619", - "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4" + "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", + "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5" ], "markers": "python_version >= '3.9'", - "version": "==1.0.8" + "version": "==2.0.0" }, "sphinxcontrib-devhelp": { "hashes": [ - "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f", - "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3" + "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", + "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2" ], "markers": "python_version >= '3.9'", - "version": "==1.0.6" + "version": "==2.0.0" }, "sphinxcontrib-htmlhelp": { "hashes": [ - "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015", - "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04" + "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", + "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9" ], "markers": "python_version >= '3.9'", - "version": "==2.0.5" + "version": "==2.1.0" }, "sphinxcontrib-jquery": { "hashes": [ @@ -1772,19 +1805,19 @@ }, "sphinxcontrib-qthelp": { "hashes": [ - "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6", - "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182" + "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", + "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb" ], "markers": "python_version >= '3.9'", - "version": "==1.0.7" + "version": "==2.0.0" }, "sphinxcontrib-serializinghtml": { "hashes": [ - "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7", - "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f" + "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", + "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d" ], "markers": "python_version >= '3.9'", - "version": "==1.1.10" + "version": "==2.0.0" }, "stack-data": { "hashes": [ @@ -1803,18 +1836,18 @@ }, "tinycss2": { "hashes": [ - "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847", - "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627" + "sha256:152f9acabd296a8375fbca5b84c961ff95971fcfc32e79550c8df8e29118c54d", + "sha256:54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7" ], - "markers": "python_version >= '3.7'", - "version": "==1.2.1" + "markers": "python_version >= '3.8'", + "version": "==1.3.0" }, "tokenize-rt": { "hashes": [ - "sha256:9fe80f8a5c1edad2d3ede0f37481cc0cc1538a2f442c9c2f9e4feacd2792d054", - "sha256:b79d41a65cfec71285433511b50271b05da3584a1da144a0752e9c621a285289" + "sha256:b9711bdfc51210211137499b5e355d3de5ec88a85d2025c520cbb921b5194367", + "sha256:d4ff7ded2873512938b4f8cbb98c9b07118f01d30ac585a30d7a88353ca36d22" ], - "version": "==5.2.0" + "version": "==6.0.0" }, "toml": { "hashes": [ @@ -1824,72 +1857,64 @@ "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==0.10.2" }, - "tomlkit": { - "hashes": [ - "sha256:5cd82d48a3dd89dee1f9d64420aa20ae65cfbd00668d6f094d7578a78efbb77b", - "sha256:7ca1cfc12232806517a8515047ba66a19369e71edf2439d0f5824f91032b6cc3" - ], - "markers": "python_version >= '3.7'", - "version": "==0.12.4" - }, "tornado": { "hashes": [ - "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0", - "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63", - "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263", - "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052", - "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f", - "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee", - "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78", - "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579", - "sha256:f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212", - "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e", - "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2" + "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8", + "sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f", + "sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4", + "sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3", + "sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14", + "sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842", + "sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9", + "sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698", + "sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7", + "sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d", + "sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4" ], "markers": "python_version >= '3.8'", - "version": "==6.4" + "version": "==6.4.1" }, "tox": { "hashes": [ - "sha256:0defb44f6dafd911b61788325741cc6b2e12ea71f987ac025ad4d649f1f1a104", - "sha256:2900c4eb7b716af4a928a7fdc2ed248ad6575294ed7cfae2ea41203937422847" + "sha256:35d472032ee1f73fe20c3e0e73d7073a4e85075c86ff02c576f9fc7c6a15a578", + "sha256:3c0c96bc3a568a5c7e66387a4cfcf8c875b52e09f4d47c9f7a277ec82f1a0b11" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.14.2" + "version": "==4.18.1" }, "traitlets": { "hashes": [ - "sha256:8cdd83c040dab7d1dee822678e5f5d100b514f7b72b01615b26fc5718916fdf9", - "sha256:fcdf85684a772ddeba87db2f398ce00b40ff550d1528c03c14dbf6a02003cd80" + "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", + "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f" ], "markers": "python_version >= '3.8'", - "version": "==5.14.2" + "version": "==5.14.3" }, "twine": { "hashes": [ - "sha256:89b0cc7d370a4b66421cc6102f269aa910fe0f1861c124f573cf2ddedbc10cf4", - "sha256:a262933de0b484c53408f9edae2e7821c1c45a3314ff2df9bdd343aa7ab8edc0" + "sha256:215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997", + "sha256:9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==5.0.0" + "version": "==5.1.1" }, "types-python-dateutil": { "hashes": [ - "sha256:5d2f2e240b86905e40944dd787db6da9263f0deabef1076ddaed797351ec0202", - "sha256:6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b" + "sha256:27c8cc2d058ccb14946eebcaaa503088f4f6dbc4fb6093d3d456a49aef2753f6", + "sha256:9706c3b68284c25adffc47319ecc7947e5bb86b3773f843c73906fd598bc176e" ], "markers": "python_version >= '3.8'", - "version": "==2.9.0.20240316" + "version": "==2.9.0.20240906" }, "typing-extensions": { "hashes": [ - "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", - "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], "markers": "python_version >= '3.8'", - "version": "==4.10.0" + "version": "==4.12.2" }, "uri-template": { "hashes": [ @@ -1900,19 +1925,19 @@ }, "urllib3": { "hashes": [ - "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", - "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" + "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472", + "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168" ], "markers": "python_version >= '3.8'", - "version": "==2.2.1" + "version": "==2.2.2" }, "virtualenv": { "hashes": [ - "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a", - "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197" + "sha256:48f2695d9809277003f30776d155615ffc11328e6a0a8c1f0ec80188d7874a55", + "sha256:c17f4e0f3e6036e9f26700446f85c76ab11df65ff6d8a9cbfad9f71aabfcf23c" ], "markers": "python_version >= '3.7'", - "version": "==20.25.1" + "version": "==20.26.4" }, "wcwidth": { "hashes": [ @@ -1923,10 +1948,10 @@ }, "webcolors": { "hashes": [ - "sha256:29bc7e8752c0a1bd4a1f03c14d6e6a72e93d82193738fa860cbff59d0fcc11bf", - "sha256:c225b674c83fa923be93d235330ce0300373d02885cef23238813b0d5668304a" + "sha256:08b07af286a01bcd30d583a7acadf629583d1f79bfef27dd2c2c5c263817277d", + "sha256:fc4c3b59358ada164552084a8ebee637c221e4059267d0f8325b3b560f6c7f0a" ], - "version": "==1.13" + "version": "==24.8.0" }, "webencodings": { "hashes": [ @@ -1937,20 +1962,20 @@ }, "websocket-client": { "hashes": [ - "sha256:10e511ea3a8c744631d3bd77e61eb17ed09304c413ad42cf6ddfa4c7787e8fe6", - "sha256:f4c3d22fec12a2461427a29957ff07d35098ee2d976d3ba244e688b8b4057588" + "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", + "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da" ], "markers": "python_version >= '3.8'", - "version": "==1.7.0" + "version": "==1.8.0" }, "wheel": { "hashes": [ - "sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85", - "sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81" + "sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f", + "sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==0.43.0" + "version": "==0.44.0" }, "wrapt": { "hashes": [ @@ -2038,11 +2063,11 @@ }, "zipp": { "hashes": [ - "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b", - "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715" + "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064", + "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b" ], "markers": "python_version >= '3.8'", - "version": "==3.18.1" + "version": "==3.20.1" } } } diff --git a/README.md b/README.md index fae11d7..5971d33 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Nodes can be plain strings or objects
(De)Serialize to (compressed) JSON
Save as Mermaid flow diagram
Different traversal methods
+Generate random trees
Fully type annotated
Convert to RDF graph
Typed child nodes
diff --git a/docs/sphinx/conf.py b/docs/sphinx/conf.py index e5fa685..0b08295 100644 --- a/docs/sphinx/conf.py +++ b/docs/sphinx/conf.py @@ -119,7 +119,7 @@ # General information about the project. project = u'nutree' -copyright = u'2021-2023, Martin Wendt' +copyright = u'2021-2024, Martin Wendt' author = u'Martin Wendt' # The version info for the project you're documenting, acts as replacement for @@ -130,19 +130,25 @@ #version = '1.0' # The full version, including alpha/beta/rc tags. #release = '1.0' -import pkg_resources +import importlib try: - release = pkg_resources.get_distribution('nutree').version - # print( "release", release) - del pkg_resources -except pkg_resources.DistributionNotFound: - print('To build the documentation, The distribution information') - print('Has to be available. Either install the package into your') + # release = pkg_resources.get_distribution("nutree").version + release = importlib.metadata.version("nutree") +except importlib.metadata.PackageNotFoundError: + print("To build the documentation, The distribution information") + print("has to be available. Either install the package into your") print('development environment or run "setup.py develop" to setup the') - print('metadata. A virtualenv is recommended!') + print("metadata. A virtualenv is recommended!") + + print(f"sys.path: {sys.path}") + print(f"package_root: {package_root}") + for fn in os.listdir(package_root): + print("-", fn) sys.exit(1) +del importlib.metadata + version = '.'.join(release.split('.')[:2]) # The language for content autogenerated by Sphinx. Refer to documentation diff --git a/docs/sphinx/index.rst b/docs/sphinx/index.rst index 3ed7931..351651f 100644 --- a/docs/sphinx/index.rst +++ b/docs/sphinx/index.rst @@ -96,8 +96,9 @@ Nutree Facts * :ref:`(De)Serialize to (compressed) JSON ` * :ref:`Save as Mermaid flow diagram ` * :ref:`Different traversal methods ` - * :ref:`Fully type annotated ` + * :ref:`Generate random trees ` * :ref:`Convert to RDF graph ` + * :ref:`Fully type annotated ` * :ref:`Typed child nodes ` * :ref:`Pretty print ` * :ref:`Navigation ` diff --git a/docs/sphinx/reference_guide.rst b/docs/sphinx/reference_guide.rst index a8e263f..669d589 100644 --- a/docs/sphinx/reference_guide.rst +++ b/docs/sphinx/reference_guide.rst @@ -5,10 +5,18 @@ Reference Guide Class Overview ============== +nutree classes +-------------- + .. inheritance-diagram:: nutree.tree nutree.node nutree.typed_tree nutree.common :parts: 2 :private-bases: - :caption: nutree classes + +Random tree generator +--------------------- + +.. inheritance-diagram:: nutree.tree_generator + :parts: 2 .. API diff --git a/docs/sphinx/ug_basics.rst b/docs/sphinx/ug_basics.rst index 0915e05..f55315b 100644 --- a/docs/sphinx/ug_basics.rst +++ b/docs/sphinx/ug_basics.rst @@ -4,6 +4,12 @@ Basics .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree is a Python library for managing hierarchical data structures. + It stores arbitrary data objects in nodes and provides methods for + navigation, searching, and iteration. + Adding Nodes ------------ @@ -35,8 +41,8 @@ Nodes are usually created by adding a new data instance to a parent:: .. seealso:: - See :doc:`ug_objects` for details on how to manage arbitrary objects instead - of plain strings. + See :doc:`ug_objects` for details on how to manage arbitrary objects, dicts, + etc. instead of plain strings. Info and Navigation diff --git a/docs/sphinx/ug_clones.rst b/docs/sphinx/ug_clones.rst index a879b2e..4336f9f 100644 --- a/docs/sphinx/ug_clones.rst +++ b/docs/sphinx/ug_clones.rst @@ -6,6 +6,10 @@ Multiple Instances ('Clones') .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree allows to store multiple references to the same data object in a tree. + Every :class:`~nutree.node.Node` instance is unique within the tree and also has a unique `node.node_id` value. diff --git a/docs/sphinx/ug_diff.rst b/docs/sphinx/ug_diff.rst index 543c5e2..0ad30a9 100644 --- a/docs/sphinx/ug_diff.rst +++ b/docs/sphinx/ug_diff.rst @@ -6,6 +6,10 @@ Diff and Merge .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree provides a `diff` method to compare two trees and calculate the differences. + The :meth:`~nutree.tree.Tree.diff` method compares a tree (`T0`) against another one (`T1`) and returns a merged, annotated copy. diff --git a/docs/sphinx/ug_graphs.rst b/docs/sphinx/ug_graphs.rst index 4a1b862..2330b76 100644 --- a/docs/sphinx/ug_graphs.rst +++ b/docs/sphinx/ug_graphs.rst @@ -6,6 +6,15 @@ Graphs .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree implements conversion to `DOT `_ + and `Mermaid `_ formats. |br| + This allows to visualize trees as graphs in various formats like `png`, `svg`, etc. |br| + The :class:`~nutree.typed_tree.TypedTree` class introduces the concept of + `typed nodes`, which allows to generate labelled edges in the graph representation. + + .. note:: :class:`~nutree.tree.Tree` (and :class:`~nutree.typed_tree.TypedTree` even more so) has features that make mapping to a graph easy. diff --git a/docs/sphinx/ug_mutation.rst b/docs/sphinx/ug_mutation.rst index 115c32b..d5ccd9d 100644 --- a/docs/sphinx/ug_mutation.rst +++ b/docs/sphinx/ug_mutation.rst @@ -6,6 +6,12 @@ Mutation .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree provides methods to modify the tree structure in-place. |br| + This includes adding, moving, and deleting nodes, as well as filtering and sorting. + + Some in-place modifications are available:: # Tree diff --git a/docs/sphinx/ug_objects.rst b/docs/sphinx/ug_objects.rst index 1ec4ec7..a9ad9a7 100644 --- a/docs/sphinx/ug_objects.rst +++ b/docs/sphinx/ug_objects.rst @@ -6,6 +6,14 @@ Working with Objects .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree allows to store arbitrary objects in its nodes without the + need to modify them or derive from a common base class. |br| + It also supports shadow attributes for direct access to object attributes. |br| + Some objects like *dicts* or *dataclasses* are unhashable and require special + handling. + The previous examples used plain strings as data objects. However, any Python object can be stored, as long as it is `hashable`. @@ -37,7 +45,7 @@ We can add instances of these classes to our tree:: ... For bookkeeping, lookups, and serialization, every data object needs a `data_id`. -This value defaults to ``hash(data)``, which is good enough in many cases. :: +This value defaults to ``hash(data)``, which is good enough in many cases:: assert tree[alice].data_id == hash(alice) @@ -46,7 +54,7 @@ to be useful for persistence. In our example, we already have object GUIDs, whic we want to use instead. This can be achieved by passing a callback to the tree:: def _calc_id(tree, data): - if isinstance(data, fixture.Person): + if isinstance(data, Person): return data.guid return hash(data) @@ -79,13 +87,12 @@ Shadow Attributes (Attribute Aliasing) When storing arbitrary objects within a tree node, all its attributes must be accessed through the ``node.data`` attribute. |br| -This can be simplified by using the ``shadow_attrs`` argument, which allow to +This can be simplified by using the ``shadow_attrs`` argument, which allows to access ``node.data.age`` as ``node.age`` for example:: tree = Tree("Persons", shadow_attrs=True) - dev = tree.add(Department("Development")) alice = Person("Alice", age=23, guid="{123-456}") - alice_node = dev.add(alice) + alice_node = tree.add(alice) # Standard access using `node.data`: assert alice_node.data is alice @@ -96,15 +103,17 @@ access ``node.data.age`` as ``node.age`` for example:: assert alice_node.guid == "{123-456}" assert alice_node.age == 23 + # Note also: shadow attributes are readonly: + alice_node.age = 24 # ERROR: raises AttributeError + + # But we can still modify the data object directly: + alice_node.data.age = 24 # OK! + # Note caveat: `node.name` is not shadowed, but a native property: assert alice.data.name == "Alice" assert alice.name == "Person" - # Note also: shadow attributes are readonly: - alice.age = 24 # ERROR: raises AttributeError - alice.data.age = 24 # OK! - -.. note:: +.. warning:: Aliasing only works for attribute names that are **not** part of the native :class:`~nutree.node.Node` data model. So these attributes will always return @@ -114,3 +123,118 @@ access ``node.data.age`` as ``node.age`` for example:: Note also that shadow attributes are readonly. + +.. _generic-node-data: + +Dictionaries (GenericNodeData) +------------------------------ + +Python +`dictionaries `_ +are unhashable and cannot be used as node data objects. |br| +We can handle this in different ways: + +1. Explicitly set the `data_id` when adding the dict: |br| + ``tree.add({"name": "Alice", "age": 23, "guid": "{123-456}"}, data_id="{123-456}")`` +2. Use a custom `calc_data_id` callback function that returns a unique key for + the data object (see example above). +3. Wrap the dict in :class:`~nutree.common.GenericNodeData`. + +The :class:`~nutree.common.GenericNodeData` class is a simple wrapper around a +dictionary that + +- is hashable, so it can be used added to the tree as ``node.data`` +- stores a reference to the original dict internally as ``node.data._dict`` +- allows readonly access to dict keys as shadow attributes, i.e. + ``node.data._dict["name"]`` can be accessed as ``node.data.name``. |br| + If ``shadow_attrs=True`` is passed to the tree constructor, it can also be + accessed as ``node.name``. |br| + Note that shadow attributes are readonly. +- allows access to dict keys by index, i.e. ``node.data["name"]`` + +Examples :: + + from nutree import Tree, GenericNodeData + + tree = Tree(shadow_attrs=True) + + d = {"a": 1, "b": 2} + obj = GenericNodeData(d) + +We can now add the wrapped `dict` to the tree:: + + node = tree.add_child(obj) + + assert node.data._dict is d, "stored as reference" + assert node.data._dict["a"] == 1 + + assert node.data.a == 1, "accessible as data attribute" + assert node.data["a"] == 1, "accessible by index" + + # Since we enabled shadow_attrs, this is also possible: + assert node.a == 1, "accessible as node attribute" + + # Note: shadow attributes are readonly: + node.a = 99 # ERROR: raises AttributeError + node.data["a"] = 99 # ERROR: raises TypeError + + # We need to access the dict directly to modify it + node.data._dict["a"] = 99 + assert node.a == 99, "should reflect changes in dict" + + +GenericNodeData can also be initialized with keyword args like this:: + + obj = GenericNodeData(a=1, b=2) + + +Dataclasses +----------- + +`Dataclasses `_ are a great way +to define simple classes that hold data. However, they are not hashable by default. |br| +We can handle this in different ways:: + + from dataclasses import dataclass + + @dataclass + class Person: + name: str + age: int + guid: str = None + + alice = Person("Alice", age=23, guid="{123-456}") + +.. 1. Explicitly set the `data_id` when adding the dataclass instance. +.. ``tree.add(, data_id="{123-456}")`` +.. 2. Use a custom `calc_data_id` function that returns a unique key for the data object. +.. 3. Make the dataclass hashable by adding a `__hash__` method. +.. 4. Make the dataclass ``frozen=True`` (or ``unsafe_hash=True``). + +Example: Explicitly set the `data_id` when adding the dataclass instance:: + + tree.add(alice, data_id=alice.guid) + +Example: make the dataclass hashable by adding a `__hash__` method:: + + @dataclass + class Person: + name: str + age: int + guid: str = None + + def __hash__(self): + return hash(self.guid) + + alice = Person("Alice", age=23, guid="{123-456}") + + tree.add(alice) + +Example: Use a frozen dataclass instead, which is immutable and hashable by default:: + + @dataclass(frozen=True) + class Person: + name: str + age: int + guid: str = None + diff --git a/docs/sphinx/ug_pretty_print.rst b/docs/sphinx/ug_pretty_print.rst index 4eb1463..9b8695d 100644 --- a/docs/sphinx/ug_pretty_print.rst +++ b/docs/sphinx/ug_pretty_print.rst @@ -6,6 +6,12 @@ Pretty Print .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree provides a `format` method to generate a pretty printed string + representation of the tree structure. + + :meth:`~nutree.tree.Tree.format` produces a pretty formatted string representation:: diff --git a/docs/sphinx/ug_randomize.rst b/docs/sphinx/ug_randomize.rst new file mode 100644 index 0000000..b5edaa9 --- /dev/null +++ b/docs/sphinx/ug_randomize.rst @@ -0,0 +1,153 @@ +.. _randomize: + +--------------------- +Generate Random Trees +--------------------- + +.. py:currentmodule:: nutree + +.. admonition:: TL;DR + + Nutree can generate random tree structures from a structure definition. + +Nutree can generate random tree structures from a structure definition. +This can be used to create hierarchical data for test, demo, or benchmarking of +*nutree* itself. + +The result can also be used as a source for creating fixtures for other targets +in a following next step. |br| +See `Wundebaum demo `_ and the +`fixture generator `_ +for an example. + +The structure is defined as Python dictionary that describes the +parent-child relationships to be created. +This definition is then passed to :meth:`tree.Tree.build_random_tree`:: + + structure_def = { + ... + # Relations define the possible parent / child relationships between + # node types and optionally override the default properties. + "relations": { + "__root__": { # System root, i.e. we define the top nodes here + "TYPE_1": { + # How many instances to create: + ":count": 10, + # Attribute names and values for every instance: + "ATTR_1": "This is a top node", + "ATTR_2": True, + "ATTR_3": 42, + }, + }, + "TYPE_1": { # Potential child nodes of TYPE_1 + "TYPE_2": { + # How many instances to create: + ":count": 3, + # Attribute names and values for every instance: + "title": "This is a child node of TYPE_1", + }, + }, + }, + } + + tree = Tree.build_random_tree(structure_def) + +Example:: + + structure_def = { + #: Name of the new tree (str, optiona) + "name": "fmea", + #: Types define the default properties of the nodes + "types": { + #: Default properties for all node types + "*": { ... }, + #: Specific default properties for each node type (optional) + "TYPE_1": { ... }, + "TYPE_2": { ... }, + ... + }, + #: Relations define the possible parent / child relationships between + #: node types and optionally override the default properties. + "relations": { + "__root__": { + "TYPE_1": { + ":count": 10, + "ATTR_1": "Function {hier_idx}", + "expanded": True, + }, + }, + "function": { + "failure": { + ":count": RangeRandomizer(1, 3), + "title": "Failure {hier_idx}", + }, + }, + "failure": { + "cause": { + ":count": RangeRandomizer(1, 3), + "title": "Cause {hier_idx}", + }, + "effect": { + ":count": RangeRandomizer(1, 3), + "title": "Effect {hier_idx}", + }, + }, + }, + } + tree = Tree.build_random_tree(structure_def) + tree.print() + assert type(tree) is Tree + assert tree.calc_height() == 3 + +Example:: + + structure_def = { + "name": "fmea", + #: Types define the default properties of the nodes + "types": { + #: Default properties for all node types + "*": {":factory": GenericNodeData}, + #: Specific default properties for each node type + "function": {"icon": "bi bi-gear"}, + "failure": {"icon": "bi bi-exclamation-triangle"}, + "cause": {"icon": "bi bi-tools"}, + "effect": {"icon": "bi bi-lightning"}, + }, + #: Relations define the possible parent / child relationships between + #: node types and optionally override the default properties. + "relations": { + "__root__": { + "function": { + ":count": 10, + "title": "Function {hier_idx}", + "expanded": True, + }, + }, + "function": { + "failure": { + ":count": RangeRandomizer(1, 3), + "title": "Failure {hier_idx}", + }, + }, + "failure": { + "cause": { + ":count": RangeRandomizer(1, 3), + "title": "Cause {hier_idx}", + }, + "effect": { + ":count": RangeRandomizer(1, 3), + "title": "Effect {hier_idx}", + }, + }, + }, + } + tree = Tree.build_random_tree(structure_def) + tree.print() + assert type(tree) is Tree + assert tree.calc_height() == 3 + + tree2 = TypedTree.build_random_tree(structure_def) + tree2.print() + assert type(tree2) is TypedTree + assert tree2.calc_height() == 3 + diff --git a/docs/sphinx/ug_search_and_navigate.rst b/docs/sphinx/ug_search_and_navigate.rst index d8714f8..f8d3962 100644 --- a/docs/sphinx/ug_search_and_navigate.rst +++ b/docs/sphinx/ug_search_and_navigate.rst @@ -4,6 +4,10 @@ Search and Navigate .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree provides methods to search, navigate, and iterate tree structures. + .. _navigate: Assuming we have a tree like this:: @@ -101,7 +105,7 @@ Examples:: tree.add("A", data_id="123") assert tree.find("A") is None # not found assert tree.find("123") is None # not found - assert tree.find(data_id="123") is not None # works + assert tree.find(data_id="123") is not None # FOUND! .. _traversal: diff --git a/docs/sphinx/ug_serialize.rst b/docs/sphinx/ug_serialize.rst index 5a2a093..16acad3 100644 --- a/docs/sphinx/ug_serialize.rst +++ b/docs/sphinx/ug_serialize.rst @@ -6,6 +6,11 @@ .. py:currentmodule:: nutree +.. admonition:: TL;DR + + Nutree provides methods to serialize and deserialize tree structures as JSON. + Arbitrary objects can be stored and restored by implementing mappers. |br| + The native format supports compact formatting and optional zipping. Native Format ------------- diff --git a/docs/sphinx/user_guide.rst b/docs/sphinx/user_guide.rst index f3ac240..88ecfea 100644 --- a/docs/sphinx/user_guide.rst +++ b/docs/sphinx/user_guide.rst @@ -108,4 +108,5 @@ kind (str, readonly): ug_serialize ug_diff ug_graphs + ug_randomize ug_advanced diff --git a/nutree/__init__.py b/nutree/__init__.py index 822ae4a..013e163 100644 --- a/nutree/__init__.py +++ b/nutree/__init__.py @@ -20,6 +20,7 @@ from .common import ( AmbiguousMatchError, + GenericNodeData, IterMethod, SelectBranch, SkipBranch, @@ -39,6 +40,7 @@ AmbiguousMatchError, diff_node_formatter, DiffClassification, + GenericNodeData, IterMethod, load_tree_from_fs, SelectBranch, diff --git a/nutree/common.py b/nutree/common.py index 10dae41..792107d 100644 --- a/nutree/common.py +++ b/nutree/common.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Functions and declarations used by the :mod:`nutree.tree` and :mod:`nutree.node` @@ -13,12 +13,14 @@ from contextlib import contextmanager from enum import Enum from pathlib import Path -from typing import IO, TYPE_CHECKING, Any, Callable, Dict, List, Type, Union +from typing import IO, TYPE_CHECKING, Any, Callable, Dict, List, Type, TypeVar, Union if TYPE_CHECKING: # Imported by type checkers, but prevent circular includes from .node import Node from .tree import Tree + TTree = TypeVar("TTree", bound=Tree) + #: Used as ID for the system root node ROOT_ID: str = "__root__" @@ -158,6 +160,98 @@ def __init__(self, value=None): "round43c": (" ", "│ ", "╰── ", "├── ", "╰─┬ ", "├─┬ "), } +# ------------------------------------------------------------------------------ +# Generic data object to be used when nutree.Node instances +# ------------------------------------------------------------------------------ + + +class GenericNodeData: + """Can be used as `node.data` instance for dict-like data. + + Initialized with a dictionary of values. The values can be accessed + via the `node.data` attribute like `node.data["KEY"]`. + If the Tree is initialized with `shadow_attrs=True`, the values are also + available as attributes of the node like `node.KEY`. + + If the tree is serialized, the values are copied to the serialized data. + + Examples:: + + tree = Tree(shadow_attrs=True) + + d = {"a": 1, "b": 2} + obj = GenericNodeData(d) + node = tree.add_child(obj) + + assert node.data.values is d, "stored as reference" + assert node.data.values["a"] == 1 + + assert node.data.a == 1, "accessible as data attribute" + assert node.data["a"] == 1, "accessible by index" + + # Since we enabled shadow_attrs, this is also possible: + assert node.a == 1, "accessible as node attribute" + + + Alternatively, the data can be initialized with keyword args like this:: + + obj = GenericNodeData(a=1, b=2) + + or with a dictionary like this. Note that in this case we unpack the dictionary + which creates a copy:: + + d = {"a": 1, "b": 2} + obj = GenericNodeData(**d) + + See :ref:`generic-node-data` for details. + """ + + __slots__ = ("_dict",) + + def __init__(self, dict_inst: dict | None = None, **values) -> None: + if dict_inst is not None: + # A dictionary was passed: store a reference to that instance + if not isinstance(dict_inst, dict): + self._dict = None + raise TypeError("dict_inst must be a dictionary or None") + if values: + self._dict = None + raise ValueError("Cannot pass both dict_inst and **values") + self._dict: dict = dict_inst + else: + # Single keyword arguments are passed (probably from unpacked dict): + # store them in a new dictionary + self._dict: dict = values + + def __repr__(self): + return f"{self.__class__.__name__}<{self._dict}>" + + def __getitem__(self, key): + return self._dict[key] + + def __getattr__(self, name: str) -> Any: + """Allow to access values as attributes. + + Assuming the GenericNodeData instance is stored in a Node.data instance, + this allows to access the values like this:: + + node.data.NAME + + If shadow_attrs is enabled, this also allows to access the values like this:: + + node.NAME + + See :ref:`generic-node-data`. + """ + try: + return self._dict[name] + except KeyError: + raise AttributeError(name) from None + + @staticmethod + def serialize_mapper(nutree_node, data): + return nutree_node.data._dict.copy() + def get_version() -> str: from nutree import __version__ @@ -263,7 +357,7 @@ def open_as_uncompressed_input_stream( *, encoding: str = "utf8", auto_uncompress: bool = True, -) -> IO[str]: +) -> IO[str]: # type: ignore """Open a file for reading, decompressing if necessary. Decompression is done by checking for the magic header (independent of the @@ -296,7 +390,7 @@ def open_as_compressed_output_stream( *, compression: bool | int = True, encoding: str = "utf8", -) -> IO[str]: +) -> IO[str]: # type: ignore """Open a file for writing, ZIP-compressing if requested. Example:: diff --git a/nutree/diff.py b/nutree/diff.py index d825a40..31864e0 100644 --- a/nutree/diff.py +++ b/nutree/diff.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt and contributors; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt and contributors; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Implement diff/merge algorithms. diff --git a/nutree/dot.py b/nutree/dot.py index c1fbdfe..b23fdbe 100644 --- a/nutree/dot.py +++ b/nutree/dot.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Functions and declarations to support diff --git a/nutree/fs.py b/nutree/fs.py index 949423e..b4a093c 100644 --- a/nutree/fs.py +++ b/nutree/fs.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Methods and classes to support file system related functionality. diff --git a/nutree/mermaid.py b/nutree/mermaid.py index e0b907a..ce51dde 100644 --- a/nutree/mermaid.py +++ b/nutree/mermaid.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Functions and declarations to support diff --git a/nutree/node.py b/nutree/node.py index 41f2698..2da16cf 100644 --- a/nutree/node.py +++ b/nutree/node.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Declare the :class:`~nutree.node.Node` class. @@ -150,7 +150,7 @@ def __getattr__(self, name: str) -> Any: See :ref:`shadow-attributes`. """ if self._tree._shadow_attrs: - return getattr(self.data, name) + return getattr(self._data, name) raise AttributeError # def __iadd__(self, other) -> None: diff --git a/nutree/rdf.py b/nutree/rdf.py index 67db673..c4f2be2 100644 --- a/nutree/rdf.py +++ b/nutree/rdf.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Functions and declarations to implement `rdflib `_. diff --git a/nutree/tree.py b/nutree/tree.py index 67f96c6..3e6751d 100644 --- a/nutree/tree.py +++ b/nutree/tree.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Declare the :class:`~nutree.tree.Tree` class. @@ -9,7 +9,7 @@ import random import threading from pathlib import Path -from typing import IO, Any, Iterable, Iterator +from typing import IO, TYPE_CHECKING, Any, Iterable, Iterator from nutree.diff import diff_tree from nutree.mermaid import ( @@ -43,6 +43,9 @@ from .node import Node from .rdf import tree_to_rdf +if TYPE_CHECKING: # Imported by type checkers, but prevent circular includes + from nutree.common import TTree + _DELETED_TAG = "" #: Minimal Python version that is supported by WsgiDAV @@ -842,6 +845,22 @@ def _self_check(self) -> True: assert clone_count == len(node_list) return True + @classmethod + def build_random_tree(cls: type[TTree], structure_def: dict) -> TTree: + """Build a random tree for . + + Returns a new :class:`Tree` instance with random nodes, as defined by + structure_def. + If called like ``TypedTree.build_random_tree(structure_def)``, this + method will return a :class:`~nutree.typed_tree.TypedTree` instance. + + See :ref:`randomize` for details. + """ + from nutree.tree_generator import build_random_tree + + tt = build_random_tree(tree_class=cls, structure_def=structure_def) + return tt + # ------------------------------------------------------------------------------ # - _SystemRootNode diff --git a/nutree/tree_generator.py b/nutree/tree_generator.py new file mode 100644 index 0000000..c81a02a --- /dev/null +++ b/nutree/tree_generator.py @@ -0,0 +1,469 @@ +""" +Implements a generator that creates a random tree structure from a specification. + +Returns a nutree.TypedTree with random data from a specification. + +See :ref:`randomize` for details. + +Example: + +```py +from tree_generator import RangeRandomizer, TextRandomizer, generate_tree + + +structure_definition = { + "name": "fmea", + #: Types define the default properties of the nodes + "types": { + #: Default properties for all node types + # "*": {":factory": WbNode}, + #: Specific default properties for each node type + "function": {"icon": "bi bi-gear"}, + "failure": {"icon": "bi bi-exclamation-triangle"}, + "cause": {"icon": "bi bi-tools"}, + "effect": {"icon": "bi bi-lightning"}, + }, + #: Relations define the possible parent / child relationships between + #: node types and optionally override the default properties. + "relations": { + "__root__": { + "function": { + ":count": 10, + "title": TextRandomizer(("{i}: Provide $(Noun:plural)",)), + "expanded": True, + }, + }, + "function": { + "failure": { + ":count": RangeRandomizer(1, 3), + "title": TextRandomizer("$(Noun:plural) not provided"), + }, + }, + "failure": { + "cause": { + ":count": RangeRandomizer(1, 3), + "title": TextRandomizer("$(Noun:plural) not provided"), + }, + "effect": { + ":count": RangeRandomizer(1, 3), + "title": TextRandomizer("$(Noun:plural) not provided"), + }, + }, + }, +} +tree = generate_tree(structure_definition) +tree.print() +``` +""" + +import random +import sys +from abc import ABC, abstractmethod +from datetime import date, datetime, timedelta, timezone +from typing import TYPE_CHECKING, Any, Sequence, Type, Union + +from nutree.common import GenericNodeData +from nutree.node import Node +from nutree.typed_tree import TypedNode + +try: + from fabulist import Fabulist # type: ignore + + fab = Fabulist() +except ImportError: + # We run without fabulist (with reduced functionality in this case) + Fabulist = None + fab = None + +if TYPE_CHECKING: # Imported by type checkers, but prevent circular includes + from nutree.common import TTree + + +# ------------------------------------------------------------------------------ +# Randomizers +# ------------------------------------------------------------------------------ +class Randomizer(ABC): + """ + Abstract base class for randomizers. + Args: + probability (float, optional): The probability of using the randomizer. + Must be in the range [0.0, 1.0]. Defaults to 1.0. + Attributes: + probability (float): The probability of using the randomizer. + """ + + def __init__(self, *, probability: float = 1.0) -> None: + assert ( + type(probability) is float and 0.0 <= probability <= 1.0 + ), f"probality must be in the range [0.0 .. 1.0]: {probability}" + self.probability = probability + + def _skip_value(self) -> bool: + use = self.probability == 1.0 or random.random() <= self.probability + return not use + + @abstractmethod + def generate(self) -> Any: ... + + +class RangeRandomizer(Randomizer): + """ + A randomizer class that generates random values within a specified range. + + Args: + min_val (Union[float, int]): The minimum value of the range. + max_val (Union[float, int]): The maximum value of the range. + probability (float, optional): The probability of generating a value. + Defaults to 1.0. + none_value (Any, optional): The value to return when skipping generation. + Defaults to None. + + Returns: + Union[float, int, None]: The generated random value, or none_value + if generation is skipped. + """ + + """""" + + def __init__( + self, + min_val: Union[float, int], + max_val: Union[float, int], + *, + probability: float = 1.0, + none_value: Any = None, + ) -> None: + super().__init__(probability=probability) + assert type(min_val) is type( + max_val + ), f"min_val and max_val must be of the same type: {min_val}, {max_val}" + self.is_float = type(min_val) is float + self.min = min_val + self.max = max_val + self.none_value = none_value + assert self.max > self.min + + def generate(self) -> Union[float, int, None]: + if self._skip_value(): + return self.none_value + if self.is_float: + return random.uniform(self.min, self.max) + return random.randrange(self.min, self.max) + + +class DateRangeRandomizer(Randomizer): + """ + A randomizer class that generates random dates within a specified range. + + Args: + min_dt (date): The minimum date of the range. + max_dt (Union[date, int]): The maximum date of the range. + Pass an integer to specify the number of days from min_dt. + as_js_stamp (bool, optional): If True, return the date as a JavaScript + timestamp. Defaults to True. + probability (float, optional): The probability of generating a value. + Defaults to 1.0. + Examples: + >>> DateRangeRandomizer(date(2020, 1, 1), date(2020, 12, 31)).generate() + datetime.date(2020, 3, 7) + >>> DateRangeRandomizer(date(2020, 1, 1), 365).generate() + """ + + def __init__( + self, + min_dt: date, + max_dt: Union[date, int], + *, + as_js_stamp=True, + probability: float = 1.0, + ) -> None: + super().__init__(probability=probability) + assert type(min_dt) is date, f"min_dt must be a date: {min_dt}" + assert type(max_dt) in (date, int), f"max_dt must be a date or int: {max_dt}" + + if type(max_dt) is int: + self.delta_days = max_dt + max_dt = min_dt + timedelta(days=self.delta_days) + else: + self.delta_days = (max_dt - min_dt).days + + assert ( + max_dt > min_dt + ), f"max_dt must be greater than min_dt: {min_dt}, {max_dt}" + + self.min = min_dt + self.max = max_dt + self.as_js_stamp = as_js_stamp + + def generate(self) -> Union[date, None]: + # print(self.min, self.max, self.delta_days, self.probability) + if self._skip_value(): + # print("SKIP") + return + res = self.min + timedelta(days=random.randrange(self.delta_days)) + # print(res) + if self.as_js_stamp: + ONE_DAY_SEC = 24 * 60 * 60 + dt = datetime(res.year, res.month, res.day) + # print(f"{dt=}") + # print(f"{dt=}, {dt.timestamp()=}") + dt_utc = dt.replace(tzinfo=timezone.utc) + stamp_ms = (dt_utc.timestamp() + ONE_DAY_SEC) * 1000.0 + # print(self.min, self.max, self.delta_days, res, stamp_ms) + res = stamp_ms + return res + + +class ValueRandomizer(Randomizer): + """ + A randomizer class that generates a fixed value with a given probability. + + Args: + value (Any): The value to generate. + probability (float): The probability of generating a value [0.0 .. 1.0]. + """ + + def __init__(self, value: Any, *, probability: float) -> None: + super().__init__(probability=probability) + self.value = value + + def generate(self) -> Any: + if self._skip_value(): + return + return self.value + + +class SparseBoolRandomizer(ValueRandomizer): + """ + A randomizer class that generates a boolean value with a given probability. + If the value is False, it is returned as None. + """ + + def __init__(self, *, probability: float) -> None: + super().__init__(True, probability=probability) + + +class SampleRandomizer(Randomizer): + """ + A randomizer class that generates a random value from a sample list. + """ + + def __init__( + self, sample_list: Sequence, *, counts=None, probability: float = 1.0 + ) -> None: + super().__init__(probability=probability) + self.sample_list = sample_list + # TODO: remove this when support for Python 3.8 is removed + if sys.version_info < (3, 9) and counts: + raise RuntimeError("counts argument requires Python 3.9 or later.") + + self.counts = counts + + def generate(self) -> Any: + if self._skip_value(): + return + # TODO: remove this when support for Python 3.8 is removed + if sys.version_info < (3, 9) and not self.counts: + return random.sample(self.sample_list, 1)[0] + return random.sample(self.sample_list, 1, counts=self.counts)[0] + + +# class BoolRandomizer(SampleRandomizer): +# def __init__(self, *, allow_none: bool = False) -> None: +# if allow_none: +# super().__init__((True, False, None)) +# else: +# super().__init__((True, False)) + + +class TextRandomizer(Randomizer): + """ + A randomizer class that generates a random string value from a Fabulist template. + + Uses the [`fabulist`](https://github.com/mar10/fabulist/) library to generate + text values. + + Args: + template (str | list): A template string or list of strings. + probability (float, optional): The probability of generating a value. + Defaults to 1.0. + """ + + def __init__(self, template: Union[str, list], *, probability: float = 1.0) -> None: + super().__init__(probability=probability) + if not fab: + raise RuntimeError("Need fabulist installed to generate random text.") + self.template = template + + def generate(self) -> Any: + if self._skip_value(): + return + return fab.get_quote(self.template) + + +class BlindTextRandomizer(Randomizer): + """ + A randomizer class that generates a random lorem ipsum text value from a template. + + Uses the [`fabulist`](https://github.com/mar10/fabulist/) library to generate + text values. + + Args: + sentence_count (int | tuple, optional): The number of sentences to generate. + Defaults to (2, 6). + dialect (str, optional): The dialect of the text. Defaults to "ipsum". + entropy (int, optional): The entropy of the text. Defaults to 2. + keep_first (bool, optional): If True, keep the first sentence. + Defaults to False. + words_per_sentence (int | tuple, optional): The number of words per sentence. + Defaults to (3, 15). + probability (float, optional): The probability of generating a value. + Defaults to 1.0. + """ + + def __init__( + self, + *, + sentence_count: Union[int, tuple] = (2, 6), + dialect: str = "ipsum", + entropy: int = 2, + keep_first: bool = False, + words_per_sentence: Union[int, tuple] = (3, 15), + probability: float = 1.0, + ) -> None: + super().__init__(probability=probability) + if not fab: + raise RuntimeError("Need fabulist installed to generate random text.") + + self.sentence_count = sentence_count + self.dialect = dialect + self.entropy = entropy + self.keep_first = keep_first + self.words_per_sentence = words_per_sentence + + def generate(self) -> Any: + if self._skip_value(): + return + return fab.get_lorem_paragraph( + sentence_count=self.sentence_count, + dialect=self.dialect, + entropy=self.entropy, + keep_first=self.keep_first, + words_per_sentence=self.words_per_sentence, + ) + + +def _resolve_random(val: Any) -> Any: + if isinstance(val, Randomizer): + return val.generate() + return val + + +def _resolve_random_dict(d: dict, *, macros: dict = None) -> None: + remove = [] + for key in d.keys(): + val = d[key] + + if isinstance(val, Randomizer): + val = val.generate() + if val is None: # Skip due to probability + remove.append(key) + else: + d[key] = val + + if macros and isinstance(val, str): + d[key] = val.format(**macros) + + for key in remove: + d.pop(key) + return + + +# ------------------------------------------------------------------------------ +# Tree Builder +# ------------------------------------------------------------------------------ + + +def _merge_specs(node_type: str, spec: dict, types: dict) -> dict: + res = types.get("*", {}).copy() + res.update(types.get(node_type, {})) + res.update(spec) + return res + + +def _make_tree( + *, + parent_node: Node, + parent_type: str, + types: dict, + relations: dict, + prefix: str, +): + child_specs = relations[parent_type] + + for node_type, spec in child_specs.items(): + spec = _merge_specs(node_type, spec, types) + count = spec.pop(":count", 1) + count = _resolve_random(count) or 0 + callback = spec.pop(":callback", None) + factory = spec.pop(":factory", GenericNodeData) + + for i in range(count): + i += 1 # 1-based + p = f"{prefix}.{i}" if prefix else f"{i}" + + # Resolve `Randomizer` values and expand `{idx}` and `{hier_idx}` macros + data = spec.copy() + + _resolve_random_dict(data, macros={"idx": i, "hier_idx": p}) + + if callback: + callback(data) + + node_data = factory(**data) + + if isinstance(parent_node, TypedNode): + node = parent_node.add_child(node_data, kind=node_type) + else: + node = parent_node.add_child(node_data) + + # Generate child relations + if node_type in relations: + _make_tree( + parent_node=node, + parent_type=node_type, + types=types, + relations=relations, + prefix=p, + ) + + return + + +def build_random_tree(*, tree_class: Type["TTree"], structure_def: dict) -> "TTree": + """ + Return a nutree.TypedTree with random data from a specification. + See :ref:`randomize` for details. + """ + structure_def = structure_def.copy() + + name = structure_def.pop("name", None) + types = structure_def.pop("types", {}) + relations = structure_def.pop("relations") # mandatory + assert not structure_def, f"found extra data: {structure_def}" + assert "__root__" in relations, "missing '__root__' relation" + + tree: TTree = tree_class( + name=name, + shadow_attrs=True, + ) + + _make_tree( + parent_node=tree.system_root, + parent_type="__root__", + types=types, + relations=relations, + prefix="", + ) + + return tree diff --git a/nutree/typed_tree.py b/nutree/typed_tree.py index f1841ca..38f7bfc 100644 --- a/nutree/typed_tree.py +++ b/nutree/typed_tree.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Declare the :class:`~nutree.tree.TypedTree` class. @@ -9,7 +9,7 @@ from pathlib import Path from typing import IO, Any, Iterator -from nutree.common import ( +from .common import ( ROOT_ID, CalcIdCallbackType, DeserializeMapperType, @@ -23,7 +23,6 @@ ValueMapType, call_mapper, ) - from .node import Node from .tree import Tree @@ -778,6 +777,12 @@ def load( """ return super().load(target, mapper=mapper, file_meta=file_meta) + # @classmethod + # def build_random_tree(cls, structure_def: dict) -> TypedTree: + # """Build a random tree for testing.""" + # tt = build_random_tree(cls, structure_def) + # return tt + # ------------------------------------------------------------------------------ # - _SystemRootTypedNode diff --git a/pyproject.toml b/pyproject.toml index b6dd178..8c5823f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,3 +50,33 @@ ignore = [ # [tool.ruff.pydocstyle] # convention = "google" + +# --- Coverage Settings -------------------------------------------------------- +[tool.pytest.ini_options] +# addopts = "-ra -q --cov=nutree --cov-report=html" +addopts = "-ra -q --cov=nutree" +# addopts = "--cov=nutree --cov-report=html --cov-report=term-missing" + +[tool.coverage.run] +# branch = true +omit = [ + "tests/*", + # nutree/leaves_cli.py + # nutree/cli_common.py + # nutree/monitor/* +] + +[tool.coverage.report] +precision = 1 +# show_missing = true +sort = "Name" +exclude_lines = [ + "pragma: no cover", + "raise NotImplementedError", + "if __name__ == .__main__.:", + "if TYPE_CHECKING:", +] + +[tool.coverage.html] +directory = "build/coverage" + diff --git a/setup.cfg b/setup.cfg index fbae0ea..44abd57 100644 --- a/setup.cfg +++ b/setup.cfg @@ -74,6 +74,8 @@ install_requires = graph = pydot; rdflib; graphviz # pdf = ReportLab>=1.2; RXP # rest = docutils>=0.3; pack ==1.1, ==1.3 +random = fabulist +all = pydot; rdflib; graphviz; fabulist [options.packages.find] where = . @@ -101,26 +103,26 @@ universal = false # docs/sphinx-build # docs/sphinx-build/* -# --- Coverage Settings -------------------------------------------------------- - -[coverage:run] -# branch = True -omit = - tests/* - # nutree/leaves_cli.py - # nutree/cli_common.py - # nutree/monitor/* - -[coverage:report] -precision = 1 -# show_missing = True -sort = Name -exclude_lines = - pragma: no cover - raise NotImplementedError - if __name__ == .__main__.: - if TYPE_CHECKING: - -[coverage:html] -directory = build/coverage +# # --- Coverage Settings -------------------------------------------------------- + +# [coverage:run] +# # branch = True +# omit = +# tests/* +# # nutree/leaves_cli.py +# # nutree/cli_common.py +# # nutree/monitor/* + +# [coverage:report] +# precision = 1 +# # show_missing = True +# sort = Name +# exclude_lines = +# pragma: no cover +# raise NotImplementedError +# if __name__ == .__main__.: +# if TYPE_CHECKING: + +# [coverage:html] +# directory = build/coverage diff --git a/tests/fixture.py b/tests/fixture.py index 63ea796..e8b93ec 100644 --- a/tests/fixture.py +++ b/tests/fixture.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ Test helpers. diff --git a/tests/pytest.ini b/tests/pytest.ini index 09a19bc..aa0702b 100644 --- a/tests/pytest.ini +++ b/tests/pytest.ini @@ -1,6 +1,9 @@ [pytest] # Silence `PytestDeprecationWarning` junit_family = legacy + +# See also pyproject.toml + ; testpaths = ; tests ; src diff --git a/tests/test_bench.py b/tests/test_bench.py index 0e46c07..f2f6d00 100644 --- a/tests/test_bench.py +++ b/tests/test_bench.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ diff --git a/tests/test_clones.py b/tests/test_clones.py index c5e8700..094c936 100644 --- a/tests/test_clones.py +++ b/tests/test_clones.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ diff --git a/tests/test_core.py b/tests/test_core.py index 54da45a..f97c84c 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ diff --git a/tests/test_diff.py b/tests/test_diff.py index dcedb9f..fde3edb 100644 --- a/tests/test_diff.py +++ b/tests/test_diff.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ diff --git a/tests/test_objects.py b/tests/test_objects.py index fda1788..0dc221c 100644 --- a/tests/test_objects.py +++ b/tests/test_objects.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ @@ -7,6 +7,7 @@ import pytest from nutree import Tree +from nutree.common import GenericNodeData class Item: @@ -114,3 +115,143 @@ def test_shadow_attrs_true(self): # Shadow attributes are readonly with pytest.raises(AttributeError): let_it_be_node.price = 9.99 + + +class TestGenericNodeData: + def setup_method(self): + self.tree = Tree("fixture") + + def teardown_method(self): + self.tree = None + + def test_constructor(self): + d: dict = {"a": 1, "b": 2} + + with pytest.raises(TypeError, match="dict_inst must be a dictionary"): + _ = GenericNodeData("foo") + + with pytest.raises(TypeError): + _ = GenericNodeData("foo", **d) + + with pytest.raises(TypeError): + _ = GenericNodeData("foo", d) + + with pytest.raises(ValueError): + _ = GenericNodeData(d, foo="bar") + + gnd = GenericNodeData(d) + assert gnd._dict is d, "dict should be stored as reference" + + assert gnd.a == 1, "GenericNodeData should support attribute access" + with pytest.raises(AttributeError): + _ = gnd.foo + + assert gnd["a"] == 1, "GenericNodeData should support item access" + with pytest.raises(KeyError): + _ = gnd["foo"] + + gnd = GenericNodeData(**d) + assert gnd._dict is not d, "unpacked dict should be stored as copy" + + def test_dict(self): + tree = Tree(shadow_attrs=True) + + d: dict = {"a": 1, "b": 2} + + # We cannot simply add a dict, because it is unhashable + with pytest.raises(TypeError, match="unhashable type: 'dict'"): + _ = tree.add(d) + + # But we can wrap it in a GenericNodeData instance + node = tree.add(GenericNodeData(d)) + + # The dict is stored as reference + + assert isinstance(node.data, GenericNodeData) + assert node.data._dict is d, "dict should be stored as reference" + assert node.a == 1, "should support attribute access via shadowing" + + with pytest.raises(AttributeError): + # should not allow access to non-existing attributes + _ = node.foo + + with pytest.raises(TypeError, match="'Node' object is not subscriptable"): + # should NOT support item access via indexing + _ = node["a"] + + assert node.data.a == 1, "should support attribute access via data" + + with pytest.raises(AttributeError): + # should not allow access to non-existing attributes + _ = node.data.foo + + assert node.data["a"] == 1, "should support item access via data" + + with pytest.raises(AttributeError, match="object has no attribute 'a'"): + # Shadowing is read-only + _ = node.data.a = 99 + + with pytest.raises( + TypeError, match="'GenericNodeData' object does not support item assignment" + ): + # Index access is read-only + _ = node.data["a"] = 99 + + with pytest.raises( + TypeError, match="'GenericNodeData' object does not support item assignment" + ): + _ = node.data["foo"] = 99 + + # We need to access the dict directly to modify it + node.data._dict["a"] = 99 + assert node.a == 99, "should reflect changes in dict" + + def test_generic_node_data_unpacked(self): + tree = Tree(shadow_attrs=True) + + d: dict = {"a": 1, "b": 2} + + # We can also unpack the dict + node = tree.add(GenericNodeData(**d)) + + assert node.data._dict is not d, "unpacked dict should be stored as copy" + assert node.data._dict == {"a": 1, "b": 2} + assert node.a == 1, "GenericNodeData should support attribute access" + + def test_dataclass(self): + + from dataclasses import FrozenInstanceError, dataclass + + @dataclass + class Item: + name: str + price: float + count: int + + @dataclass(frozen=True) + class FrozenItem: + name: str + price: float + count: int + + tree = Tree(shadow_attrs=True) + + # We cannot simply add a dataclass, because it is mutable and unhashable + with pytest.raises(TypeError, match="unhashable type: 'Item'"): + _ = tree.add(Item("Let It Be", 12.34, 17)) + + # But we can add frozen dataclasses + item = FrozenItem("Let It Be", 12.34, 17) + dict_node = tree.add(item) + + # Frozen dataclasses are immutable + with pytest.raises(FrozenInstanceError): + item.count += 1 + + tree.print() + + assert isinstance(dict_node.data, FrozenItem) + assert dict_node.data is item, "dataclass should be stored as reference" + assert dict_node.price == 12.34, "should support attribute access via shadowing" + with pytest.raises(AttributeError): + _ = dict_node.foo diff --git a/tests/test_serialize.py b/tests/test_serialize.py index 649ff80..b57c3c7 100644 --- a/tests/test_serialize.py +++ b/tests/test_serialize.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ @@ -829,9 +829,11 @@ def test_serialize_mermaid_typed(self): Path(__file__).parent / "temp/test_serialize_2.md", ) - @pytest.mark.xfail(reason="mmdc may not be installed") + # @pytest.mark.xfail(reason="mmdc may not be installed") def test_serialize_mermaid_svg(self): """Save/load as typed object tree with clones.""" + if not shutil.which("mmdc"): + raise pytest.skip("mmdc not installed") KEEP_FILES = not fixture.is_running_on_ci() and False tree = fixture.create_typed_tree(style="simple", clones=True, name="Root") diff --git a/tests/test_tree_generator.py b/tests/test_tree_generator.py new file mode 100644 index 0000000..bfc6711 --- /dev/null +++ b/tests/test_tree_generator.py @@ -0,0 +1,133 @@ +""" +Generic tree generator for test data. +""" + +import datetime + +import pytest + +from nutree.common import GenericNodeData +from nutree.tree import Tree +from nutree.tree_generator import ( + BlindTextRandomizer, + DateRangeRandomizer, + RangeRandomizer, + SampleRandomizer, + SparseBoolRandomizer, + TextRandomizer, + ValueRandomizer, + fab, +) +from nutree.typed_tree import TypedTree + + +def test_simple(): + structure_def = { + "name": "fmea", + #: Types define the default properties of the nodes + "types": { + #: Default properties for all node types + "*": {":factory": GenericNodeData}, + #: Specific default properties for each node type + "function": {"icon": "bi bi-gear"}, + "failure": {"icon": "bi bi-exclamation-triangle"}, + "cause": {"icon": "bi bi-tools"}, + "effect": {"icon": "bi bi-lightning"}, + }, + #: Relations define the possible parent / child relationships between + #: node types and optionally override the default properties. + "relations": { + "__root__": { + "function": { + ":count": 3, + "title": "Function {hier_idx}", + "date": DateRangeRandomizer( + datetime.date(2020, 1, 1), datetime.date(2020, 12, 31) + ), + "date2": DateRangeRandomizer( + datetime.date(2020, 1, 1), 365, probability=0.99 + ), + "value": ValueRandomizer("foo", probability=0.5), + "expanded": SparseBoolRandomizer(probability=0.5), + "state": SampleRandomizer(["open", "closed"], probability=0.99), + }, + }, + "function": { + "failure": { + ":count": RangeRandomizer(1, 3), + "title": "Failure {hier_idx}", + }, + }, + "failure": { + "cause": { + ":count": RangeRandomizer(1, 3, probability=0.99), + "title": "Cause {hier_idx}", + }, + "effect": { + ":count": RangeRandomizer(1, 3), + "title": "Effect {hier_idx}", + }, + }, + }, + } + tree = Tree.build_random_tree(structure_def) + tree.print() + assert type(tree) is Tree + assert tree.calc_height() == 3 + + tree2 = TypedTree.build_random_tree(structure_def) + tree2.print() + assert type(tree2) is TypedTree + assert tree2.calc_height() == 3 + + +def test_fabulist(): + + if not fab: + pytest.skip("fabulist not installed") + + structure_def = { + "name": "fmea", + #: Types define the default properties of the nodes + "types": { + #: Default properties for all node types (optional, default + #: is GenericNodeData) + "*": {":factory": GenericNodeData}, + #: Specific default properties for each node type + "function": {"icon": "bi bi-gear"}, + "failure": {"icon": "bi bi-exclamation-triangle"}, + "cause": {"icon": "bi bi-tools"}, + "effect": {"icon": "bi bi-lightning"}, + }, + #: Relations define the possible parent / child relationships between + #: node types and optionally override the default properties. + "relations": { + "__root__": { + "function": { + ":count": 3, + "title": TextRandomizer(("{idx}: Provide $(Noun:plural)",)), + "details": BlindTextRandomizer(dialect="ipsum"), + "expanded": True, + }, + }, + "function": { + "failure": { + ":count": RangeRandomizer(1, 3), + "title": TextRandomizer("$(Noun:plural) not provided"), + }, + }, + "failure": { + "cause": { + ":count": RangeRandomizer(1, 3), + "title": TextRandomizer("$(Noun:plural) not provided"), + }, + "effect": { + ":count": RangeRandomizer(1, 3), + "title": TextRandomizer("$(Noun:plural) not provided"), + }, + }, + }, + } + tree = TypedTree.build_random_tree(structure_def) + tree.print() + assert type(tree) is TypedTree diff --git a/tests/test_typed_tree.py b/tests/test_typed_tree.py index 65eed6e..4eb1a4d 100644 --- a/tests/test_typed_tree.py +++ b/tests/test_typed_tree.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ diff --git a/tests/test_typing_concept.py b/tests/test_typing_concept.py index ba9649b..4efe686 100644 --- a/tests/test_typing_concept.py +++ b/tests/test_typing_concept.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ diff --git a/tests/tutorial_script.py b/tests/tutorial_script.py index f12b01c..623bdd8 100644 --- a/tests/tutorial_script.py +++ b/tests/tutorial_script.py @@ -1,4 +1,4 @@ -# (c) 2021-2023 Martin Wendt; see https://github.com/mar10/nutree +# (c) 2021-2024 Martin Wendt; see https://github.com/mar10/nutree # Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php """ """ diff --git a/tox.ini b/tox.ini index 9d327e6..0833798 100644 --- a/tox.ini +++ b/tox.ini @@ -1,13 +1,14 @@ [tox] basepython = python3.12 envlist = - check, - py312, - py311, - py310, - py39, - py38, - ; py37, + check + ; py313 # EoL: 2029-10 + py312 # EoL: 2028-10 + py311 # EoL: 2027-10 + py310 # EoL: 2026-10 + py39 # EoL: 2025-10 + py38 # EoL: 2024-10 + ; py37 # Eol: 2023-06-27 coverage, skip_missing_interpreters = true @@ -24,6 +25,7 @@ setenv = COVERAGE_FILE=.coverage.{envname} # Note: also honors .coveragerc: deps = + fabulist pydot pytest pytest-cov @@ -73,7 +75,7 @@ commands = [testenv:format] -description = Reformat python code using Black and isort +description = Reformat python code using Black, ruff, isort, and pyupgrade # skip_install = true deps = {[testenv:check]deps} @@ -89,6 +91,23 @@ commands = black nutree tests setup.py {[testenv:lint]commands} +[testenv:format-no-pyupgrade] +description = Same a `format` but without pyupgrade, so it runs on windows +# skip_install = true +deps = + {[testenv:check]deps} + pyupgrade +allowlist_externals: + bash +changedir = {toxinidir} +commands = + ; bash -ec 'pyupgrade --py38-plus --exit-zero-even-if-changed nutree/*.py tests/*.py setup.py' + ruff check --fix nutree tests setup.py + ; ruff format nutree tests setup.py + isort --profile black nutree tests setup.py {posargs} + black nutree tests setup.py + {[testenv:lint]commands} + [testenv:docs] description = Build Sphinx documentation (output directory: docs/sphinx-build) From 4ccd6319996e5049c0c60c34c83ff880f3622043 Mon Sep 17 00:00:00 2001 From: Martin Wendt Date: Thu, 12 Sep 2024 13:15:43 +0200 Subject: [PATCH 07/11] Reapply last changes --- CHANGELOG.md | 7 +- docs/sphinx/reference_guide.rst | 4 +- docs/sphinx/rg_modules.rst | 9 ++ docs/sphinx/ug_objects.rst | 94 +++++++++++-------- docs/sphinx/ug_randomize.rst | 155 ++++++++++++++++++-------------- nutree/common.py | 34 +------ nutree/tree_generator.py | 55 +----------- tests/test_objects.py | 33 +++++++ tests/test_tree_generator.py | 1 + tox.ini | 1 + 10 files changed, 199 insertions(+), 194 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d28461..a875f04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,8 @@ ## 0.9.0 (unreleased) -- Add `Tree.build_random_tree()` -- Add `GenericNodeData` +- Add `Tree.build_random_tree()` (experimental). +- Add `GenericNodeData` as wrapper for `dict` data. - Fixed #7 Tree.from_dict failing to recreate an arbitrary object tree with a mapper. ## 0.8.0 (2024-03-29) @@ -11,9 +11,8 @@ - BREAKING: Drop Python 3.7 support (EoL 2023-06-27). - `Tree.save()` accepts a `compression` argument that will enable compression. `Tree.load()` can detect if the input file has a compression header and will - decompress automatically. -- New traversal methods `LEVEL_ORDER`, `LEVEL_ORDER_RTL`, `ZIGZAG`, `ZIGZAG_RTL`. decompress transparently. +- New traversal methods `LEVEL_ORDER`, `LEVEL_ORDER_RTL`, `ZIGZAG`, `ZIGZAG_RTL`. - New compact connector styles `'lines32c'`, `'round43c'`, ... - Save as mermaid flow diagram. diff --git a/docs/sphinx/reference_guide.rst b/docs/sphinx/reference_guide.rst index 669d589..54d0c3e 100644 --- a/docs/sphinx/reference_guide.rst +++ b/docs/sphinx/reference_guide.rst @@ -5,14 +5,14 @@ Reference Guide Class Overview ============== -nutree classes +Nutree Classes -------------- .. inheritance-diagram:: nutree.tree nutree.node nutree.typed_tree nutree.common :parts: 2 :private-bases: -Random tree generator +Random Tree Generator --------------------- .. inheritance-diagram:: nutree.tree_generator diff --git a/docs/sphinx/rg_modules.rst b/docs/sphinx/rg_modules.rst index 3340b4a..2d619ab 100644 --- a/docs/sphinx/rg_modules.rst +++ b/docs/sphinx/rg_modules.rst @@ -42,3 +42,12 @@ nutree.common module :show-inheritance: :inherited-members: +nutree.tree_generator module +---------------------------- + +.. automodule:: nutree.tree_generator + :members: + :undoc-members: + :show-inheritance: + :inherited-members: + diff --git a/docs/sphinx/ug_objects.rst b/docs/sphinx/ug_objects.rst index a9ad9a7..9e5b831 100644 --- a/docs/sphinx/ug_objects.rst +++ b/docs/sphinx/ug_objects.rst @@ -131,26 +131,47 @@ Dictionaries (GenericNodeData) Python `dictionaries `_ -are unhashable and cannot be used as node data objects. |br| -We can handle this in different ways: +are unhashable and cannot be used as node data objects:: -1. Explicitly set the `data_id` when adding the dict: |br| - ``tree.add({"name": "Alice", "age": 23, "guid": "{123-456}"}, data_id="{123-456}")`` -2. Use a custom `calc_data_id` callback function that returns a unique key for - the data object (see example above). -3. Wrap the dict in :class:`~nutree.common.GenericNodeData`. + d = {"a": 1, "b": 2} + tree.add(d) # ERROR: raises `TypeError: unhashable type: 'dict'` + +Adding Native Dictionaries +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We can handle this by explicitly setting the `data_id` when adding the dict:: + + node = tree.add({d, data_id="{123-456}") -The :class:`~nutree.common.GenericNodeData` class is a simple wrapper around a -dictionary that + assert node.data is d + assert node.data["a"] == 1 + +Alternatively, we can implement a custom `calc_data_id` callback function that +returns a unique key for the data object:: + + def _calc_id(tree, data): + if isinstance(data, dict): + return hash(data["guid"]) + return hash(data) -- is hashable, so it can be used added to the tree as ``node.data`` + tree = Tree(calc_data_id=_calc_id) + + d = {"a": 1, "b": 2, "guid": "{123-456}"} + tree.add(d) + +Wrapping Dictionaries +~~~~~~~~~~~~~~~~~~~~~ + +Finally, we can use the :class:`~nutree.common.GenericNodeData` which is a simple +wrapper around a dictionary that + +- is hashable, so it can be added to the tree as ``node.data`` - stores a reference to the original dict internally as ``node.data._dict`` - allows readonly access to dict keys as shadow attributes, i.e. ``node.data._dict["name"]`` can be accessed as ``node.data.name``. |br| If ``shadow_attrs=True`` is passed to the tree constructor, it can also be - accessed as ``node.name``. |br| - Note that shadow attributes are readonly. -- allows access to dict keys by index, i.e. ``node.data["name"]`` + accessed as ``node.name`` +- allows readonly access to dict keys by index, i.e. ``node.data["name"]`` Examples :: @@ -160,11 +181,10 @@ Examples :: d = {"a": 1, "b": 2} obj = GenericNodeData(d) - -We can now add the wrapped `dict` to the tree:: - node = tree.add_child(obj) +We can now access the dict keys as attributes:: + assert node.data._dict is d, "stored as reference" assert node.data._dict["a"] == 1 @@ -187,13 +207,22 @@ GenericNodeData can also be initialized with keyword args like this:: obj = GenericNodeData(a=1, b=2) +.. warning:: + The :class:`~nutree.common.GenericNodeData` provides a hash value because + any class that is hashable, so it can be used as a data object. However, the + hash value is NOT based on the internal dict but on the object itself. |br| + This means that two instances of GenericNodeData with the same dict content + will have different hash values. + +.. warning:: + The `shadow_attrs` feature is readonly, so you cannot modify the dict + through the shadow attributes. You need to access the dict directly for that. Dataclasses ----------- `Dataclasses `_ are a great way -to define simple classes that hold data. However, they are not hashable by default. |br| -We can handle this in different ways:: +to define simple classes that hold data. However, they are not hashable by default:: from dataclasses import dataclass @@ -205,32 +234,27 @@ We can handle this in different ways:: alice = Person("Alice", age=23, guid="{123-456}") -.. 1. Explicitly set the `data_id` when adding the dataclass instance. -.. ``tree.add(, data_id="{123-456}")`` -.. 2. Use a custom `calc_data_id` function that returns a unique key for the data object. -.. 3. Make the dataclass hashable by adding a `__hash__` method. -.. 4. Make the dataclass ``frozen=True`` (or ``unsafe_hash=True``). + tree.add(alice) # ERROR: raises `TypeError: unhashable type: 'dict'` -Example: Explicitly set the `data_id` when adding the dataclass instance:: +We can handle this in different ways byexplicitly set the `data_id` when adding +the dataclass instance:: tree.add(alice, data_id=alice.guid) -Example: make the dataclass hashable by adding a `__hash__` method:: - - @dataclass - class Person: - name: str - age: int - guid: str = None +Alternatively, we can implement a custom `calc_data_id` callback function that +returns a unique key for the data object:: - def __hash__(self): - return hash(self.guid) + def _calc_id(tree, data): + if hasattr(data, "guid"): + return hash(data.guid) + return hash(data) - alice = Person("Alice", age=23, guid="{123-456}") + tree = Tree(calc_data_id=_calc_id) tree.add(alice) -Example: Use a frozen dataclass instead, which is immutable and hashable by default:: +Finally, we can use a frozen dataclass instead, which is immutable and hashable by +default (or pass ``unsafe_hash=True``):: @dataclass(frozen=True) class Person: diff --git a/docs/sphinx/ug_randomize.rst b/docs/sphinx/ug_randomize.rst index b5edaa9..d0d6260 100644 --- a/docs/sphinx/ug_randomize.rst +++ b/docs/sphinx/ug_randomize.rst @@ -10,6 +10,10 @@ Generate Random Trees Nutree can generate random tree structures from a structure definition. +.. warning:: + + This feature is experimental and may change in future versions. + Nutree can generate random tree structures from a structure definition. This can be used to create hierarchical data for test, demo, or benchmarking of *nutree* itself. @@ -55,99 +59,114 @@ This definition is then passed to :meth:`tree.Tree.build_random_tree`:: Example:: structure_def = { - #: Name of the new tree (str, optiona) + # Name of the generated tree (optional) "name": "fmea", - #: Types define the default properties of the nodes + # Types define the default properties of the gernated nodes "types": { - #: Default properties for all node types - "*": { ... }, - #: Specific default properties for each node type (optional) - "TYPE_1": { ... }, - "TYPE_2": { ... }, - ... - }, - #: Relations define the possible parent / child relationships between - #: node types and optionally override the default properties. - "relations": { - "__root__": { - "TYPE_1": { - ":count": 10, - "ATTR_1": "Function {hier_idx}", - "expanded": True, - }, - }, - "function": { - "failure": { - ":count": RangeRandomizer(1, 3), - "title": "Failure {hier_idx}", - }, - }, - "failure": { - "cause": { - ":count": RangeRandomizer(1, 3), - "title": "Cause {hier_idx}", - }, - "effect": { - ":count": RangeRandomizer(1, 3), - "title": "Effect {hier_idx}", - }, + # '*' Defines default properties for all node types (optional) + "*": { + ":factory": GenericNodeData, # Default node class (optional) }, + # Specific default properties for each node type + "function": {"icon": "gear"}, + "failure": {"icon": "exclamation"}, + "cause": {"icon": "tools"}, + "effect": {"icon": "lightning"}, }, - } - tree = Tree.build_random_tree(structure_def) - tree.print() - assert type(tree) is Tree - assert tree.calc_height() == 3 - -Example:: - - structure_def = { - "name": "fmea", - #: Types define the default properties of the nodes - "types": { - #: Default properties for all node types - "*": {":factory": GenericNodeData}, - #: Specific default properties for each node type - "function": {"icon": "bi bi-gear"}, - "failure": {"icon": "bi bi-exclamation-triangle"}, - "cause": {"icon": "bi bi-tools"}, - "effect": {"icon": "bi bi-lightning"}, - }, - #: Relations define the possible parent / child relationships between - #: node types and optionally override the default properties. + # Relations define the possible parent / child relationships between + # node types and optionally override the default properties. "relations": { "__root__": { "function": { - ":count": 10, - "title": "Function {hier_idx}", + ":count": 3, + "title": TextRandomizer(("{idx}: Provide $(Noun:plural)",)), + "details": BlindTextRandomizer(dialect="ipsum"), "expanded": True, }, }, "function": { "failure": { ":count": RangeRandomizer(1, 3), - "title": "Failure {hier_idx}", + "title": TextRandomizer("$(Noun:plural) not provided"), }, }, "failure": { "cause": { ":count": RangeRandomizer(1, 3), - "title": "Cause {hier_idx}", + "title": TextRandomizer("$(Noun:plural) not provided"), }, "effect": { ":count": RangeRandomizer(1, 3), - "title": "Effect {hier_idx}", + "title": TextRandomizer("$(Noun:plural) not provided"), }, }, }, } - tree = Tree.build_random_tree(structure_def) - tree.print() - assert type(tree) is Tree + + tree = TypedTree.build_random_tree(structure_def) + + assert type(tree) is TypedTree assert tree.calc_height() == 3 + + tree.print() + +May produce:: + + TypedTree<'fmea'> + ├── function → GenericNodeData<{'icon': 'gear', 'title': '1: Provide Seniors', 'details': 'Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.', 'expanded': True}> + │ ├── failure → GenericNodeData<{'icon': 'exclamation', 'title': 'Streets not provided'}> + │ │ ├── cause → GenericNodeData<{'icon': 'tools', 'title': 'Decisions not provided'}> + │ │ ├── effect → GenericNodeData<{'icon': 'lightning', 'title': 'Spaces not provided'}> + │ │ ╰── effect → GenericNodeData<{'icon': 'lightning', 'title': 'Kings not provided'}> + │ ╰── failure → GenericNodeData<{'icon': 'exclamation', 'title': 'Entertainments not provided'}> + │ ├── cause → GenericNodeData<{'icon': 'tools', 'title': 'Programs not provided'}> + │ ├── effect → GenericNodeData<{'icon': 'lightning', 'title': 'Dirts not provided'}> + │ ╰── effect → GenericNodeData<{'icon': 'lightning', 'title': 'Dimensions not provided'}> + ├── function → GenericNodeData<{'icon': 'gear', 'title': '2: Provide Shots', 'details': 'Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum.', 'expanded': True}> + │ ├── failure → GenericNodeData<{'icon': 'exclamation', 'title': 'Trainers not provided'}> + │ │ ├── cause → GenericNodeData<{'icon': 'tools', 'title': 'Girlfriends not provided'}> + │ │ ├── cause → GenericNodeData<{'icon': 'tools', 'title': 'Noses not provided'}> + │ │ ├── effect → GenericNodeData<{'icon': 'lightning', 'title': 'Closets not provided'}> + │ │ ╰── effect → GenericNodeData<{'icon': 'lightning', 'title': 'Potentials not provided'}> + │ ╰── failure → GenericNodeData<{'icon': 'exclamation', 'title': 'Punches not provided'}> + │ ├── cause → GenericNodeData<{'icon': 'tools', 'title': 'Inevitables not provided'}> + │ ├── cause → GenericNodeData<{'icon': 'tools', 'title': 'Fronts not provided'}> + │ ╰── effect → GenericNodeData<{'icon': 'lightning', 'title': 'Worths not provided'}> + ╰── function → GenericNodeData<{'icon': 'gear', 'title': '3: Provide Shots', 'details': 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.', 'expanded': True}> + ╰── failure → GenericNodeData<{'icon': 'exclamation', 'title': 'Recovers not provided'}> + ├── cause → GenericNodeData<{'icon': 'tools', 'title': 'Viruses not provided'}> + ├── effect → GenericNodeData<{'icon': 'lightning', 'title': 'Dirts not provided'}> + ╰── effect → GenericNodeData<{'icon': 'lightning', 'title': 'Readings not provided'}> + + +**A few things to note** + +- The generated tree contains nodes :class:`~common.GenericNodeData` as ``node.data`` + value.. + +- Every ``node.data`` contains items from the structure definition except for + the ones starting with a colon, for example ``":count"``. |br| + The node items are merged with the default properties defined in the `types` + section. + +- Randomizers are used to generate random data for each instance. + They derive from the :class:`~tree_generator.Randomizer` base class. + +- The :class:`~tree_generator.TextRandomizer` and + :class:`~tree_generator.BlindTextRandomizer` classes are used to generate + random text using the `Fabulist `_ library. + +- :meth:`tree.Tree.build_random_tree` creates instances of :class:`~tree.Tree`, while + :meth:`typed_tree.TypedTree.build_random_tree` creates instances of + :class:`~typed_tree.TypedTree`. + +- The generated tree contains instances of the :class:`~common.GenericNodeData` + class by default, but can be overridden for each node type by adding a + ``":factory": CLASS`` entry. - tree2 = TypedTree.build_random_tree(structure_def) - tree2.print() - assert type(tree2) is TypedTree - assert tree2.calc_height() == 3 +.. note:: + The random text generator is based on the `Fabulist `_ + library and can use any of its providers to generate random data. |br| + Make sure to install the `fabulist` package to use the text randomizers + :class:`~tree_generator.TextRandomizer` and :class:`~tree_generator.BlindTextRandomizer`. diff --git a/nutree/common.py b/nutree/common.py index 792107d..cb3c425 100644 --- a/nutree/common.py +++ b/nutree/common.py @@ -166,43 +166,15 @@ def __init__(self, value=None): class GenericNodeData: - """Can be used as `node.data` instance for dict-like data. + """Wrap a Python dict so it can be added to the tree. + + Makes the hashable and exposes the dict values as attributes. Initialized with a dictionary of values. The values can be accessed via the `node.data` attribute like `node.data["KEY"]`. If the Tree is initialized with `shadow_attrs=True`, the values are also available as attributes of the node like `node.KEY`. - If the tree is serialized, the values are copied to the serialized data. - - Examples:: - - tree = Tree(shadow_attrs=True) - - d = {"a": 1, "b": 2} - obj = GenericNodeData(d) - node = tree.add_child(obj) - - assert node.data.values is d, "stored as reference" - assert node.data.values["a"] == 1 - - assert node.data.a == 1, "accessible as data attribute" - assert node.data["a"] == 1, "accessible by index" - - # Since we enabled shadow_attrs, this is also possible: - assert node.a == 1, "accessible as node attribute" - - - Alternatively, the data can be initialized with keyword args like this:: - - obj = GenericNodeData(a=1, b=2) - - or with a dictionary like this. Note that in this case we unpack the dictionary - which creates a copy:: - - d = {"a": 1, "b": 2} - obj = GenericNodeData(**d) - See :ref:`generic-node-data` for details. """ diff --git a/nutree/tree_generator.py b/nutree/tree_generator.py index c81a02a..d90ecf4 100644 --- a/nutree/tree_generator.py +++ b/nutree/tree_generator.py @@ -1,59 +1,7 @@ """ Implements a generator that creates a random tree structure from a specification. -Returns a nutree.TypedTree with random data from a specification. - See :ref:`randomize` for details. - -Example: - -```py -from tree_generator import RangeRandomizer, TextRandomizer, generate_tree - - -structure_definition = { - "name": "fmea", - #: Types define the default properties of the nodes - "types": { - #: Default properties for all node types - # "*": {":factory": WbNode}, - #: Specific default properties for each node type - "function": {"icon": "bi bi-gear"}, - "failure": {"icon": "bi bi-exclamation-triangle"}, - "cause": {"icon": "bi bi-tools"}, - "effect": {"icon": "bi bi-lightning"}, - }, - #: Relations define the possible parent / child relationships between - #: node types and optionally override the default properties. - "relations": { - "__root__": { - "function": { - ":count": 10, - "title": TextRandomizer(("{i}: Provide $(Noun:plural)",)), - "expanded": True, - }, - }, - "function": { - "failure": { - ":count": RangeRandomizer(1, 3), - "title": TextRandomizer("$(Noun:plural) not provided"), - }, - }, - "failure": { - "cause": { - ":count": RangeRandomizer(1, 3), - "title": TextRandomizer("$(Noun:plural) not provided"), - }, - "effect": { - ":count": RangeRandomizer(1, 3), - "title": TextRandomizer("$(Noun:plural) not provided"), - }, - }, - }, -} -tree = generate_tree(structure_definition) -tree.print() -``` """ import random @@ -85,11 +33,10 @@ class Randomizer(ABC): """ Abstract base class for randomizers. + Args: probability (float, optional): The probability of using the randomizer. Must be in the range [0.0, 1.0]. Defaults to 1.0. - Attributes: - probability (float): The probability of using the randomizer. """ def __init__(self, *, probability: float = 1.0) -> None: diff --git a/tests/test_objects.py b/tests/test_objects.py index 0dc221c..9ffd622 100644 --- a/tests/test_objects.py +++ b/tests/test_objects.py @@ -248,6 +248,9 @@ class FrozenItem: with pytest.raises(FrozenInstanceError): item.count += 1 + # We can also add by passing the data_id as keyword argument: + _ = tree.add(item, data_id="123-456") + tree.print() assert isinstance(dict_node.data, FrozenItem) @@ -255,3 +258,33 @@ class FrozenItem: assert dict_node.price == 12.34, "should support attribute access via shadowing" with pytest.raises(AttributeError): _ = dict_node.foo + + def test_callback(self): + from dataclasses import dataclass + + d: dict = {"a": 1, "guid": "123-456"} + + @dataclass + class Item: + a: int + guid: str + + dc = Item(2, "234-567") + + def _calc_id(tree, data): + if isinstance(data, Item): + return hash(data.guid) + elif isinstance(data, dict): + return hash(data["guid"]) + return hash(data) + + tree = Tree(calc_data_id=_calc_id, shadow_attrs=True) + + n1 = tree.add(d) + n2 = tree.add(dc) + + assert n1.data is d + assert n1.data["a"] == 1 + + assert n2.data is dc + assert n2.a == 2 diff --git a/tests/test_tree_generator.py b/tests/test_tree_generator.py index bfc6711..803fe43 100644 --- a/tests/test_tree_generator.py +++ b/tests/test_tree_generator.py @@ -131,3 +131,4 @@ def test_fabulist(): tree = TypedTree.build_random_tree(structure_def) tree.print() assert type(tree) is TypedTree + # assert 0 diff --git a/tox.ini b/tox.ini index 0833798..470402e 100644 --- a/tox.ini +++ b/tox.ini @@ -116,6 +116,7 @@ deps = ; python-dateutil ; lxml furo + fabulist pydot rdflib recommonmark From 477a22f89774156d19ce261d5c367f4621f3e711 Mon Sep 17 00:00:00 2001 From: Martin Wendt Date: Thu, 12 Sep 2024 13:31:40 +0200 Subject: [PATCH 08/11] Update CHANGELOG.md --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a875f04..1758ae0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog -## 0.9.0 (unreleased) +## 0.9.1 (unreleased) + +## 0.9.0 (2024-09-12) - Add `Tree.build_random_tree()` (experimental). - Add `GenericNodeData` as wrapper for `dict` data. From 4576296a5f917e354e5cd97df8124dbb9b8cc5f9 Mon Sep 17 00:00:00 2001 From: Martin Wendt Date: Thu, 12 Sep 2024 13:32:12 +0200 Subject: [PATCH 09/11] Bump version to 0.9.0 --- nutree/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nutree/__init__.py b/nutree/__init__.py index 013e163..4c6f2d2 100644 --- a/nutree/__init__.py +++ b/nutree/__init__.py @@ -16,7 +16,7 @@ """ # flake8: noqa -__version__ = "0.8.1-a1" +__version__ = "0.9.0" from .common import ( AmbiguousMatchError, From a98fd14b04d1cee57c22ff6874c2bd57bb3fc4e0 Mon Sep 17 00:00:00 2001 From: Martin Wendt Date: Thu, 12 Sep 2024 13:32:25 +0200 Subject: [PATCH 10/11] Bump prerelease (0.9.1-a1) [ci skip] --- nutree/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nutree/__init__.py b/nutree/__init__.py index 4c6f2d2..18a4318 100644 --- a/nutree/__init__.py +++ b/nutree/__init__.py @@ -16,7 +16,7 @@ """ # flake8: noqa -__version__ = "0.9.0" +__version__ = "0.9.1-a1" from .common import ( AmbiguousMatchError, From 0a293067c9bb8e6cf1386ec71935db520faaabf8 Mon Sep 17 00:00:00 2001 From: Martin Wendt Date: Thu, 12 Sep 2024 14:07:06 +0200 Subject: [PATCH 11/11] Update installation docs --- docs/sphinx/index.rst | 4 ++-- docs/sphinx/installation.rst | 4 ++-- docs/sphinx/ug_graphs.rst | 6 +++--- docs/sphinx/ug_randomize.rst | 2 ++ setup.cfg | 24 ------------------------ 5 files changed, 9 insertions(+), 31 deletions(-) diff --git a/docs/sphinx/index.rst b/docs/sphinx/index.rst index 351651f..e73b854 100644 --- a/docs/sphinx/index.rst +++ b/docs/sphinx/index.rst @@ -28,8 +28,8 @@ nutree $ pip install nutree -**Note:** Run ``pip install nutree[graph]`` instead, in order to install -additional graph support. +**Note:** Run ``pip install "nutree[graph]"`` or ``pip install "nutree[all]"`` +instead, in order to install additional graph support. :: diff --git a/docs/sphinx/installation.rst b/docs/sphinx/installation.rst index 61d0120..b37cd23 100644 --- a/docs/sphinx/installation.rst +++ b/docs/sphinx/installation.rst @@ -5,8 +5,8 @@ Installation is straightforward:: $ pip install nutree -**Note:** Run ``pip install nutree[graph]`` instead, in order to install -additional graph support. +**Note:** Run ``pip install "nutree[graph]"`` or ``pip install "nutree[all]"`` +instead, in order to install additional graph support. Installing `nutree` and its dependencies into a 'sandbox' will help to keep your system Python clean, but requires to activate the virtual environment:: diff --git a/docs/sphinx/ug_graphs.rst b/docs/sphinx/ug_graphs.rst index 2330b76..27fbd7d 100644 --- a/docs/sphinx/ug_graphs.rst +++ b/docs/sphinx/ug_graphs.rst @@ -175,7 +175,7 @@ Let's visualize the result of the :ref:`diff-and-merge` example:: of `pydot `_ and `Graphwiz `_. |br| Either install them separately or install nutree with extras: - ``pip install nutree[graph]``. + ``pip install "nutree[graph]"`` or ``pip install "nutree[all]"``. .. _save-mermaid: @@ -461,5 +461,5 @@ This would be the 'turtle' formatted serialization:: .. note:: Converting to RDF requires an installation of `rdflib `_ |br| - Either install it separately or install nutree with extras: - ``pip install nutree[graph]``. + Either install them separately or install nutree with extras: + ``pip install "nutree[graph]"`` or ``pip install "nutree[all]"``. diff --git a/docs/sphinx/ug_randomize.rst b/docs/sphinx/ug_randomize.rst index d0d6260..e52daf2 100644 --- a/docs/sphinx/ug_randomize.rst +++ b/docs/sphinx/ug_randomize.rst @@ -170,3 +170,5 @@ May produce:: library and can use any of its providers to generate random data. |br| Make sure to install the `fabulist` package to use the text randomizers :class:`~tree_generator.TextRandomizer` and :class:`~tree_generator.BlindTextRandomizer`. + Either install `fabulist` separately or install nutree with extras: + ``pip install "nutree[random]"`` or ``pip install "nutree[all]"``. diff --git a/setup.cfg b/setup.cfg index 44abd57..664ebe8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -102,27 +102,3 @@ universal = false # ignore = # docs/sphinx-build # docs/sphinx-build/* - -# # --- Coverage Settings -------------------------------------------------------- - -# [coverage:run] -# # branch = True -# omit = -# tests/* -# # nutree/leaves_cli.py -# # nutree/cli_common.py -# # nutree/monitor/* - -# [coverage:report] -# precision = 1 -# # show_missing = True -# sort = Name -# exclude_lines = -# pragma: no cover -# raise NotImplementedError -# if __name__ == .__main__.: -# if TYPE_CHECKING: - -# [coverage:html] -# directory = build/coverage -