From a76884d288016f98be6bfea1fa399170874d05f3 Mon Sep 17 00:00:00 2001 From: Roman Zlobin Date: Tue, 12 Mar 2024 13:30:47 +0300 Subject: [PATCH 01/31] fix tutorial --- tutorials/pipeline/4_groups_and_conditions_full.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tutorials/pipeline/4_groups_and_conditions_full.py b/tutorials/pipeline/4_groups_and_conditions_full.py index 312b9d999..f899b47af 100644 --- a/tutorials/pipeline/4_groups_and_conditions_full.py +++ b/tutorials/pipeline/4_groups_and_conditions_full.py @@ -156,7 +156,7 @@ def never_running_service(_, __, info: ServiceRuntimeInfo): def runtime_info_printing_service(_, __, info: ServiceRuntimeInfo): logger.info( f"Service '{info.name}' runtime execution info:" - f"{info.model_dump_json(indent=4, default=str)}" + f"{info.model_dump_json(indent=4)}" ) @@ -209,6 +209,8 @@ def runtime_info_printing_service(_, __, info: ServiceRuntimeInfo): pipeline = Pipeline.from_dict(pipeline_dict) if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + check_happy_path(pipeline, HAPPY_PATH) if is_interactive_mode(): logger.info(f"Pipeline structure:\n{pipeline.pretty_format()}") From 9e62a8449b3db47d8858a46789806f9d200e8534 Mon Sep 17 00:00:00 2001 From: ZergLev <64711614+ZergLev@users.noreply.github.com> Date: Fri, 15 Mar 2024 16:33:28 +0300 Subject: [PATCH 02/31] Add condition asserting str is in Message.text (#335) # Description - Function has_text() added. Checks the 'text' field of last_request(), if specified text within 'text' field, returns true. For such a task it's quicker than regexp condition and has less syntax bloat than exact_match() would have. This also makes checking telegram callback data easier since it is saved in the 'text' field: has_text(callback_data). - All relevant API reference / tutorials / guides updated. By that I mean all 'exact_match(Message("Some message"))' was changed into 'has_text("Some message")'. - All relevant references in the codebase updated. - Tests added, but I'm not sure I did it right. I changed some exact_match() uses to has_text() there. Well, vim did it, and now I'm thinking it's maybe preferable, actually. # Checklist - [x] I have performed a self-review of the changes - [x] Check if tests are done right (poetry has no issues, I mean if exact_match() should return instead of has_text()) # To Consider - Consider if exact_match() could somehow be used in tandem with has_text() in the tutorials. It's a part of functionality that new users can't really see now, since it's rarely used (mostly in telegram tutorials). --------- Co-authored-by: Roman Zlobin --- dff/script/conditions/__init__.py | 1 + dff/script/conditions/std_conditions.py | 16 ++++++++++++++++ tests/script/conditions/test_conditions.py | 5 +++++ 3 files changed, 22 insertions(+) diff --git a/dff/script/conditions/__init__.py b/dff/script/conditions/__init__.py index 49f17e8c3..06bebb91a 100644 --- a/dff/script/conditions/__init__.py +++ b/dff/script/conditions/__init__.py @@ -2,6 +2,7 @@ from .std_conditions import ( exact_match, + has_text, regexp, check_cond_seq, aggregate, diff --git a/dff/script/conditions/std_conditions.py b/dff/script/conditions/std_conditions.py index 8ffd1088c..3959a1e71 100644 --- a/dff/script/conditions/std_conditions.py +++ b/dff/script/conditions/std_conditions.py @@ -50,6 +50,22 @@ def exact_match_condition_handler(ctx: Context, pipeline: Pipeline) -> bool: return exact_match_condition_handler +@validate_call +def has_text(text: str) -> Callable[[Context, Pipeline], bool]: + """ + Return function handler. This handler returns `True` only if the last user phrase + contains the phrase specified in :py:param:`text`. + + :param text: A `str` variable to look for within the user request. + """ + + def has_text_condition_handler(ctx: Context, pipeline: Pipeline) -> bool: + request = ctx.last_request + return text in request.text + + return has_text_condition_handler + + @validate_call def regexp(pattern: Union[str, Pattern], flags: Union[int, re.RegexFlag] = 0) -> Callable[[Context, Pipeline], bool]: """ diff --git a/tests/script/conditions/test_conditions.py b/tests/script/conditions/test_conditions.py index c56e4aa39..ab85df16a 100644 --- a/tests/script/conditions/test_conditions.py +++ b/tests/script/conditions/test_conditions.py @@ -21,6 +21,11 @@ def test_conditions(): assert cnd.exact_match(Message())(ctx, pipeline) assert not cnd.exact_match(Message(), skip_none=False)(ctx, pipeline) + assert cnd.has_text("text")(ctx, pipeline) + assert cnd.has_text("te")(ctx, pipeline) + assert not cnd.has_text("text1")(ctx, pipeline) + assert cnd.has_text("")(ctx, pipeline) + assert cnd.regexp("t.*t")(ctx, pipeline) assert not cnd.regexp("t.*t1")(ctx, pipeline) assert not cnd.regexp("t.*t1")(failed_ctx, pipeline) From 4d46718ea9b1da06c14f657c34bdfc72063bb1f5 Mon Sep 17 00:00:00 2001 From: Roman Zlobin Date: Mon, 18 Mar 2024 14:10:52 +0300 Subject: [PATCH 03/31] skip tests on empty string tg credentials --- tests/messengers/telegram/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/messengers/telegram/conftest.py b/tests/messengers/telegram/conftest.py index d3436410a..60c3e801d 100644 --- a/tests/messengers/telegram/conftest.py +++ b/tests/messengers/telegram/conftest.py @@ -42,7 +42,7 @@ def env_vars(): for arg in env_variables: env_variables[arg] = os.getenv(arg) - if env_variables[arg] is None: + if not env_variables[arg]: pytest.skip(f"`{arg}` is not set", allow_module_level=True) yield env_variables From cda79843d29521c3fd3946e6a2a3c04aa440c798 Mon Sep 17 00:00:00 2001 From: Roman Zlobin Date: Mon, 18 Mar 2024 14:11:27 +0300 Subject: [PATCH 04/31] fix condition docstrings --- dff/script/conditions/std_conditions.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dff/script/conditions/std_conditions.py b/dff/script/conditions/std_conditions.py index 3959a1e71..d2d23f4e8 100644 --- a/dff/script/conditions/std_conditions.py +++ b/dff/script/conditions/std_conditions.py @@ -25,8 +25,8 @@ def exact_match(match: Message, skip_none: bool = True) -> Callable[[Context, Pipeline], bool]: """ Return function handler. This handler returns `True` only if the last user phrase - is the same Message as the :py:const:`match`. - If :py:const:`skip_none` the handler will not compare `None` fields of :py:const:`match`. + is the same Message as the `match`. + If `skip_none` the handler will not compare `None` fields of `match`. :param match: A Message variable to compare user request with. :param skip_none: Whether fields should be compared if they are `None` in :py:const:`match`. @@ -54,7 +54,7 @@ def exact_match_condition_handler(ctx: Context, pipeline: Pipeline) -> bool: def has_text(text: str) -> Callable[[Context, Pipeline], bool]: """ Return function handler. This handler returns `True` only if the last user phrase - contains the phrase specified in :py:param:`text`. + contains the phrase specified in `text`. :param text: A `str` variable to look for within the user request. """ @@ -70,7 +70,7 @@ def has_text_condition_handler(ctx: Context, pipeline: Pipeline) -> bool: def regexp(pattern: Union[str, Pattern], flags: Union[int, re.RegexFlag] = 0) -> Callable[[Context, Pipeline], bool]: """ Return function handler. This handler returns `True` only if the last user phrase contains - :py:const:`pattern ` with :py:const:`flags `. + `pattern` with `flags`. :param pattern: The `RegExp` pattern. :param flags: Flags for this pattern. Defaults to 0. @@ -187,9 +187,9 @@ def has_last_labels( ) -> Callable[[Context, Pipeline], bool]: """ Return condition handler. This handler returns `True` if any label from - last :py:const:`last_n_indices` context labels is in - the :py:const:`flow_labels` list or in - the :py:const:`~dff.script.NodeLabel2Type` list. + last `last_n_indices` context labels is in + the `flow_labels` list or in + the `~dff.script.NodeLabel2Type` list. :param flow_labels: List of labels to check. Every label has type `str`. Empty if not set. :param labels: List of labels corresponding to the nodes. Empty if not set. From 32ce6fe3ab564c70601eeb54a71dbc0dc38e8db6 Mon Sep 17 00:00:00 2001 From: ZergLev <64711614+ZergLev@users.noreply.github.com> Date: Mon, 18 Mar 2024 14:58:29 +0300 Subject: [PATCH 05/31] Minor fix in CONTRIBUTING.md (#339) - Removed a duplicate paragraph in CONTRIBUTING.md --- CONTRIBUTING.md | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9939a5dc8..5c7c72707 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -78,26 +78,6 @@ They can help shorten the comments and avoid boilerplate code. The documentation links generated by the directives are always relative to the local documentation and verified during build. -- `%pip install {args}` - This directive generates dependency installation cell, adds a comment and sets up "quiet" flag. - - It should be used in tutorials, like this: `# %pip install dff[...]`. -- `%doclink({args})` - This directive generates a documentation link. It supports 2 or three arguments and the generated link will look like: `ARG1/ARG2#ARG3`. - - The first argument can be either `api` for DFF codebase, `tutorial` for tutorials or `guide` for user guides. -- `%mddoclink({args})` - This directive is a shortcut for `%doclink` that generates a markdown format link instead. - - The generated link will be either `[ARG2](%doclink(ARG1,ARG2))` or `[ARG3](%doclink(ARG1,ARG2,ARG3))`. - -#### Documentation links - -In your tutorials, you can use special expanding directives in markdown cells. -They can help shorten the comments and avoid boilerplate code. -The documentation links generated by the directives are always relative -to the local documentation and verified during build. - - `%pip install {args}` This directive generates dependency installation cell, adds a comment and sets up "quiet" flag. From 957fb013d3d06f394d79aae9addd841d32d718a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 16:16:27 +0000 Subject: [PATCH 06/31] build(deps-dev): bump the deps group with 7 updates (#338) Bumps the deps group with 7 updates: | Package | From | To | | --- | --- | --- | | [black](https://github.com/psf/black) | `24.2.0` | `24.3.0` | | [mypy](https://github.com/python/mypy) | `1.8.0` | `1.9.0` | | [pytest](https://github.com/pytest-dev/pytest) | `8.0.2` | `8.1.1` | | [python-on-whales](https://github.com/gabrieldemarmiesse/python-on-whales) | `0.69.0` | `0.70.0` | | [uvicorn](https://github.com/encode/uvicorn) | `0.27.1` | `0.28.0` | | [locust](https://github.com/locustio/locust) | `2.23.1` | `2.24.0` | | [streamlit](https://github.com/streamlit/streamlit) | `1.31.1` | `1.32.2` | Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 214 ++++++++++++++++++---------------------------------- 1 file changed, 72 insertions(+), 142 deletions(-) diff --git a/poetry.lock b/poetry.lock index 343d984ba..bc3f448a8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -570,34 +570,6 @@ files = [ {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, ] -[[package]] -name = "backports-zoneinfo" -version = "0.2.1" -description = "Backport of the standard library zoneinfo module" -optional = false -python-versions = ">=3.6" -files = [ - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"}, - {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, -] - -[package.extras] -tzdata = ["tzdata"] - [[package]] name = "beautifulsoup4" version = "4.12.3" @@ -621,33 +593,33 @@ lxml = ["lxml"] [[package]] name = "black" -version = "24.2.0" +version = "24.3.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-24.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6981eae48b3b33399c8757036c7f5d48a535b962a7c2310d19361edeef64ce29"}, - {file = "black-24.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d533d5e3259720fdbc1b37444491b024003e012c5173f7d06825a77508085430"}, - {file = "black-24.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61a0391772490ddfb8a693c067df1ef5227257e72b0e4108482b8d41b5aee13f"}, - {file = "black-24.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:992e451b04667116680cb88f63449267c13e1ad134f30087dec8527242e9862a"}, - {file = "black-24.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:163baf4ef40e6897a2a9b83890e59141cc8c2a98f2dda5080dc15c00ee1e62cd"}, - {file = "black-24.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e37c99f89929af50ffaf912454b3e3b47fd64109659026b678c091a4cd450fb2"}, - {file = "black-24.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9de21bafcba9683853f6c96c2d515e364aee631b178eaa5145fc1c61a3cc92"}, - {file = "black-24.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:9db528bccb9e8e20c08e716b3b09c6bdd64da0dd129b11e160bf082d4642ac23"}, - {file = "black-24.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d84f29eb3ee44859052073b7636533ec995bd0f64e2fb43aeceefc70090e752b"}, - {file = "black-24.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e08fb9a15c914b81dd734ddd7fb10513016e5ce7e6704bdd5e1251ceee51ac9"}, - {file = "black-24.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:810d445ae6069ce64030c78ff6127cd9cd178a9ac3361435708b907d8a04c693"}, - {file = "black-24.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ba15742a13de85e9b8f3239c8f807723991fbfae24bad92d34a2b12e81904982"}, - {file = "black-24.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7e53a8c630f71db01b28cd9602a1ada68c937cbf2c333e6ed041390d6968faf4"}, - {file = "black-24.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93601c2deb321b4bad8f95df408e3fb3943d85012dddb6121336b8e24a0d1218"}, - {file = "black-24.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0057f800de6acc4407fe75bb147b0c2b5cbb7c3ed110d3e5999cd01184d53b0"}, - {file = "black-24.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:faf2ee02e6612577ba0181f4347bcbcf591eb122f7841ae5ba233d12c39dcb4d"}, - {file = "black-24.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:057c3dc602eaa6fdc451069bd027a1b2635028b575a6c3acfd63193ced20d9c8"}, - {file = "black-24.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:08654d0797e65f2423f850fc8e16a0ce50925f9337fb4a4a176a7aa4026e63f8"}, - {file = "black-24.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca610d29415ee1a30a3f30fab7a8f4144e9d34c89a235d81292a1edb2b55f540"}, - {file = "black-24.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:4dd76e9468d5536abd40ffbc7a247f83b2324f0c050556d9c371c2b9a9a95e31"}, - {file = "black-24.2.0-py3-none-any.whl", hash = "sha256:e8a6ae970537e67830776488bca52000eaa37fa63b9988e8c487458d9cd5ace6"}, - {file = "black-24.2.0.tar.gz", hash = "sha256:bce4f25c27c3435e4dace4815bcb2008b87e167e3bf4ee47ccdc5ce906eb4894"}, + {file = "black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395"}, + {file = "black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995"}, + {file = "black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7"}, + {file = "black-24.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0"}, + {file = "black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9"}, + {file = "black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597"}, + {file = "black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d"}, + {file = "black-24.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5"}, + {file = "black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f"}, + {file = "black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11"}, + {file = "black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4"}, + {file = "black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5"}, + {file = "black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837"}, + {file = "black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd"}, + {file = "black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213"}, + {file = "black-24.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959"}, + {file = "black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb"}, + {file = "black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7"}, + {file = "black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7"}, + {file = "black-24.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f"}, + {file = "black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93"}, + {file = "black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f"}, ] [package.dependencies] @@ -2803,13 +2775,13 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-ena [[package]] name = "locust" -version = "2.23.1" +version = "2.24.0" description = "Developer friendly load testing framework" optional = false python-versions = ">=3.8" files = [ - {file = "locust-2.23.1-py3-none-any.whl", hash = "sha256:96013a460a4b4d6d4fd46c70e6ff1fd2b6e03b48ddb1b48d1513d3134ba2cecf"}, - {file = "locust-2.23.1.tar.gz", hash = "sha256:6cc729729e5ebf5852fc9d845302cfcf0ab0132f198e68b3eb0c88b438b6a863"}, + {file = "locust-2.24.0-py3-none-any.whl", hash = "sha256:1b6b878b4fd0108fec956120815e69775d2616c8f4d1e9f365c222a7a5c17d9a"}, + {file = "locust-2.24.0.tar.gz", hash = "sha256:6cffa378d995244a7472af6be1d6139331f19aee44e907deee73e0281252804d"}, ] [package.dependencies] @@ -2825,6 +2797,7 @@ pywin32 = {version = "*", markers = "platform_system == \"Windows\""} pyzmq = ">=25.0.0" requests = ">=2.26.0" roundrobin = ">=0.0.2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} Werkzeug = ">=2.0.0" [[package]] @@ -3203,38 +3176,38 @@ files = [ [[package]] name = "mypy" -version = "1.8.0" +version = "1.9.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, - {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, - {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, - {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, - {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, - {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, - {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, - {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, - {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, - {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, - {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, - {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, - {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, - {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, - {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, - {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, - {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, - {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, - {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, + {file = "mypy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8a67616990062232ee4c3952f41c779afac41405806042a8126fe96e098419f"}, + {file = "mypy-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d357423fa57a489e8c47b7c85dfb96698caba13d66e086b412298a1a0ea3b0ed"}, + {file = "mypy-1.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49c87c15aed320de9b438ae7b00c1ac91cd393c1b854c2ce538e2a72d55df150"}, + {file = "mypy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:48533cdd345c3c2e5ef48ba3b0d3880b257b423e7995dada04248725c6f77374"}, + {file = "mypy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:4d3dbd346cfec7cb98e6cbb6e0f3c23618af826316188d587d1c1bc34f0ede03"}, + {file = "mypy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:653265f9a2784db65bfca694d1edd23093ce49740b2244cde583aeb134c008f3"}, + {file = "mypy-1.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a3c007ff3ee90f69cf0a15cbcdf0995749569b86b6d2f327af01fd1b8aee9dc"}, + {file = "mypy-1.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2418488264eb41f69cc64a69a745fad4a8f86649af4b1041a4c64ee61fc61129"}, + {file = "mypy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:68edad3dc7d70f2f17ae4c6c1b9471a56138ca22722487eebacfd1eb5321d612"}, + {file = "mypy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:85ca5fcc24f0b4aeedc1d02f93707bccc04733f21d41c88334c5482219b1ccb3"}, + {file = "mypy-1.9.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aceb1db093b04db5cd390821464504111b8ec3e351eb85afd1433490163d60cd"}, + {file = "mypy-1.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0235391f1c6f6ce487b23b9dbd1327b4ec33bb93934aa986efe8a9563d9349e6"}, + {file = "mypy-1.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4d5ddc13421ba3e2e082a6c2d74c2ddb3979c39b582dacd53dd5d9431237185"}, + {file = "mypy-1.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:190da1ee69b427d7efa8aa0d5e5ccd67a4fb04038c380237a0d96829cb157913"}, + {file = "mypy-1.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:fe28657de3bfec596bbeef01cb219833ad9d38dd5393fc649f4b366840baefe6"}, + {file = "mypy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e54396d70be04b34f31d2edf3362c1edd023246c82f1730bbf8768c28db5361b"}, + {file = "mypy-1.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5e6061f44f2313b94f920e91b204ec600982961e07a17e0f6cd83371cb23f5c2"}, + {file = "mypy-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a10926e5473c5fc3da8abb04119a1f5811a236dc3a38d92015cb1e6ba4cb9e"}, + {file = "mypy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b685154e22e4e9199fc95f298661deea28aaede5ae16ccc8cbb1045e716b3e04"}, + {file = "mypy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:5d741d3fc7c4da608764073089e5f58ef6352bedc223ff58f2f038c2c4698a89"}, + {file = "mypy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:587ce887f75dd9700252a3abbc9c97bbe165a4a630597845c61279cf32dfbf02"}, + {file = "mypy-1.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f88566144752999351725ac623471661c9d1cd8caa0134ff98cceeea181789f4"}, + {file = "mypy-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61758fabd58ce4b0720ae1e2fea5cfd4431591d6d590b197775329264f86311d"}, + {file = "mypy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e49499be624dead83927e70c756970a0bc8240e9f769389cdf5714b0784ca6bf"}, + {file = "mypy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:571741dc4194b4f82d344b15e8837e8c5fcc462d66d076748142327626a1b6e9"}, + {file = "mypy-1.9.0-py3-none-any.whl", hash = "sha256:a260627a570559181a9ea5de61ac6297aa5af202f06fd7ab093ce74e7181e43e"}, + {file = "mypy-1.9.0.tar.gz", hash = "sha256:3cc5da0127e6a478cddd906068496a97a7618a21ce9b54bde5bf7e539c7af974"}, ] [package.dependencies] @@ -3668,8 +3641,8 @@ files = [ [package.dependencies] numpy = [ {version = ">=1.20.3", markers = "python_version < \"3.10\""}, - {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -4567,13 +4540,13 @@ watchdog = ["watchdog"] [[package]] name = "pytest" -version = "8.0.2" +version = "8.1.1" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.0.2-py3-none-any.whl", hash = "sha256:edfaaef32ce5172d5466b5127b42e0d6d35ebbe4453f0e3505d96afd93f6b096"}, - {file = "pytest-8.0.2.tar.gz", hash = "sha256:d4051d623a2e0b7e51960ba963193b09ce6daeb9759a451844a21e4ddedfc1bd"}, + {file = "pytest-8.1.1-py3-none-any.whl", hash = "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7"}, + {file = "pytest-8.1.1.tar.gz", hash = "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044"}, ] [package.dependencies] @@ -4581,11 +4554,11 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=1.3.0,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +pluggy = ">=1.4,<2.0" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" @@ -4724,13 +4697,13 @@ files = [ [[package]] name = "python-on-whales" -version = "0.69.0" +version = "0.70.0" description = "A Docker client for Python, designed to be fun and intuitive!" optional = false python-versions = "<4,>=3.8" files = [ - {file = "python-on-whales-0.69.0.tar.gz", hash = "sha256:86bef044568e6abd381e63731e03a6536709be129c5934020da403b99f489b5e"}, - {file = "python_on_whales-0.69.0-py3-none-any.whl", hash = "sha256:73cf63377fbcbfee1f4a5e58148a1a0293f2ba153c2b862b830d0d9fedd5e223"}, + {file = "python-on-whales-0.70.0.tar.gz", hash = "sha256:bb89e91c86e049f9c04e2636f2d40faa000ff5b17d54f71e68581201e449eda5"}, + {file = "python_on_whales-0.70.0-py3-none-any.whl", hash = "sha256:492325387d7686adc6669e911820bd4da1cd672bc5a7fb6d54c32ee849bfe7e6"}, ] [package.dependencies] @@ -4828,6 +4801,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -5855,13 +5829,13 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7 [[package]] name = "streamlit" -version = "1.31.1" +version = "1.32.2" description = "A faster way to build and share data apps" optional = false python-versions = ">=3.8, !=3.9.7" files = [ - {file = "streamlit-1.31.1-py2.py3-none-any.whl", hash = "sha256:a1a84249f7a9b854fe356db06c85dc03c3f9da4df06a33aa5a922647b955e8c8"}, - {file = "streamlit-1.31.1.tar.gz", hash = "sha256:dfc43ca85b4b4c31d097c27b983b8ccc960222ad907862b2b2fb4ddf04c50fdc"}, + {file = "streamlit-1.32.2-py2.py3-none-any.whl", hash = "sha256:a0b8044e76fec364b07be145f8b40dbd8d083e20ebbb189ceb1fa9423f3dedea"}, + {file = "streamlit-1.32.2.tar.gz", hash = "sha256:1258b9cbc3ff957bf7d09b1bfc85cedc308f1065b30748545295a9af8d5577ab"}, ] [package.dependencies] @@ -5870,7 +5844,6 @@ blinker = ">=1.0.0,<2" cachetools = ">=4.0,<6" click = ">=7.0,<9" gitpython = ">=3.0.7,<3.1.19 || >3.1.19,<4" -importlib-metadata = ">=1.4,<8" numpy = ">=1.19.3,<2" packaging = ">=16.8,<24" pandas = ">=1.3.0,<3" @@ -5878,15 +5851,12 @@ pillow = ">=7.1.0,<11" protobuf = ">=3.20,<5" pyarrow = ">=7.0" pydeck = ">=0.8.0b4,<1" -python-dateutil = ">=2.7.3,<3" requests = ">=2.27,<3" rich = ">=10.14.0,<14" tenacity = ">=8.1.0,<9" toml = ">=0.10.1,<2" tornado = ">=6.0.3,<7" typing-extensions = ">=4.3.0,<5" -tzlocal = ">=1.1,<6" -validators = ">=0.2,<1" watchdog = {version = ">=2.1.5", markers = "platform_system != \"Darwin\""} [package.extras] @@ -6154,24 +6124,6 @@ files = [ {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] -[[package]] -name = "tzlocal" -version = "5.2" -description = "tzinfo object for the local timezone" -optional = false -python-versions = ">=3.8" -files = [ - {file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"}, - {file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"}, -] - -[package.dependencies] -"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} -tzdata = {version = "*", markers = "platform_system == \"Windows\""} - -[package.extras] -devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"] - [[package]] name = "uri-template" version = "1.3.0" @@ -6204,13 +6156,13 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "uvicorn" -version = "0.27.1" +version = "0.28.0" description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.8" files = [ - {file = "uvicorn-0.27.1-py3-none-any.whl", hash = "sha256:5c89da2f3895767472a35556e539fd59f7edbe9b1e9c0e1c99eebeadc61838e4"}, - {file = "uvicorn-0.27.1.tar.gz", hash = "sha256:3d9a267296243532db80c83a959a3400502165ade2c1338dea4e67915fd4745a"}, + {file = "uvicorn-0.28.0-py3-none-any.whl", hash = "sha256:6623abbbe6176204a4226e67607b4d52cc60ff62cda0ff177613645cefa2ece1"}, + {file = "uvicorn-0.28.0.tar.gz", hash = "sha256:cab4473b5d1eaeb5a0f6375ac4bc85007ffc75c3cc1768816d9e5d589857b067"}, ] [package.dependencies] @@ -6221,28 +6173,6 @@ typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} [package.extras] standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] -[[package]] -name = "validators" -version = "0.22.0" -description = "Python Data Validation for Humans™" -optional = false -python-versions = ">=3.8" -files = [ - {file = "validators-0.22.0-py3-none-any.whl", hash = "sha256:61cf7d4a62bbae559f2e54aed3b000cea9ff3e2fdbe463f51179b92c58c9585a"}, - {file = "validators-0.22.0.tar.gz", hash = "sha256:77b2689b172eeeb600d9605ab86194641670cdb73b60afd577142a9397873370"}, -] - -[package.extras] -docs-offline = ["myst-parser (>=2.0.0)", "pypandoc-binary (>=1.11)", "sphinx (>=7.1.1)"] -docs-online = ["mkdocs (>=1.5.2)", "mkdocs-git-revision-date-localized-plugin (>=1.2.0)", "mkdocs-material (>=9.2.6)", "mkdocstrings[python] (>=0.22.0)", "pyaml (>=23.7.0)"] -hooks = ["pre-commit (>=3.3.3)"] -package = ["build (>=1.0.0)", "twine (>=4.0.2)"] -runner = ["tox (>=4.11.1)"] -sast = ["bandit[toml] (>=1.7.5)"] -testing = ["pytest (>=7.4.0)"] -tooling = ["black (>=23.7.0)", "pyright (>=1.1.325)", "ruff (>=0.0.287)"] -tooling-extras = ["pyaml (>=23.7.0)", "pypandoc-binary (>=1.11)", "pytest (>=7.4.0)"] - [[package]] name = "virtualenv" version = "20.25.1" From 1dd073590c6a01c0be8bc6336554da872897f8d8 Mon Sep 17 00:00:00 2001 From: Roman Zlobin Date: Wed, 20 Mar 2024 11:18:31 +0000 Subject: [PATCH 07/31] mention pandoc in CONTRIBUTING.md --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5c7c72707..85e0c7110 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,6 +69,8 @@ by activating the virtual environment and then running poetry run poe docs ``` +Note that you'll need `pandoc` installed on your system in order to build docs. + After that `docs/build` dir will be created and you can open index file `docs/build/index.html` in your browser of choice. #### Documentation links From 0e39538916eef962221ddf9476a82b8d61f3a7cf Mon Sep 17 00:00:00 2001 From: Roman Zlobin Date: Fri, 22 Mar 2024 15:03:50 +0300 Subject: [PATCH 08/31] Revert "remove pre_response and pre_transition processing tutorials" This reverts commit 08672c0f8f72d99205ac42a030a38389fdf762ed. --- .../script/core/7_pre_response_processing.py | 132 ++++++++++++++++++ .../script/core/{7_misc.py => 8_misc.py} | 0 .../core/9_pre_transitions_processing.py | 99 +++++++++++++ 3 files changed, 231 insertions(+) create mode 100644 tutorials/script/core/7_pre_response_processing.py rename tutorials/script/core/{7_misc.py => 8_misc.py} (100%) create mode 100644 tutorials/script/core/9_pre_transitions_processing.py diff --git a/tutorials/script/core/7_pre_response_processing.py b/tutorials/script/core/7_pre_response_processing.py new file mode 100644 index 000000000..9697b8675 --- /dev/null +++ b/tutorials/script/core/7_pre_response_processing.py @@ -0,0 +1,132 @@ +# %% [markdown] +""" +# Core: 7. Pre-response processing + +This tutorial shows pre-response processing feature. + +Here, %mddoclink(api,script.core.keywords,Keywords.PRE_RESPONSE_PROCESSING) +is demonstrated which can be used for +additional context processing before response handlers. + +There are also some other %mddoclink(api,script.core.keywords,Keywords) +worth attention used in this tutorial. + +First of all, let's do all the necessary imports from DFF. +""" + +# %pip install dff + +# %% +from dff.script import ( + GLOBAL, + LOCAL, + RESPONSE, + TRANSITIONS, + PRE_RESPONSE_PROCESSING, + Context, + Message, +) +import dff.script.labels as lbl +import dff.script.conditions as cnd + +from dff.pipeline import Pipeline +from dff.utils.testing.common import ( + check_happy_path, + is_interactive_mode, + run_interactive_mode, +) + + +# %% +def add_prefix(prefix): + def add_prefix_processing(ctx: Context, _: Pipeline): + processed_node = ctx.current_node + processed_node.response = Message( + text=f"{prefix}: {processed_node.response.text}" + ) + + return add_prefix_processing + + +# %% [markdown] +""" +`PRE_RESPONSE_PROCESSING` is a keyword that +can be used in `GLOBAL`, `LOCAL` or nodes. +""" + + +# %% +toy_script = { + "root": { + "start": { + RESPONSE: Message(), + TRANSITIONS: {("flow", "step_0"): cnd.true()}, + }, + "fallback": {RESPONSE: Message("the end")}, + }, + GLOBAL: { + PRE_RESPONSE_PROCESSING: { + "proc_name_1": add_prefix("l1_global"), + "proc_name_2": add_prefix("l2_global"), + } + }, + "flow": { + LOCAL: { + PRE_RESPONSE_PROCESSING: { + "proc_name_2": add_prefix("l2_local"), + "proc_name_3": add_prefix("l3_local"), + } + }, + "step_0": { + RESPONSE: Message("first"), + TRANSITIONS: {lbl.forward(): cnd.true()}, + }, + "step_1": { + PRE_RESPONSE_PROCESSING: {"proc_name_1": add_prefix("l1_step_1")}, + RESPONSE: Message("second"), + TRANSITIONS: {lbl.forward(): cnd.true()}, + }, + "step_2": { + PRE_RESPONSE_PROCESSING: {"proc_name_2": add_prefix("l2_step_2")}, + RESPONSE: Message("third"), + TRANSITIONS: {lbl.forward(): cnd.true()}, + }, + "step_3": { + PRE_RESPONSE_PROCESSING: {"proc_name_3": add_prefix("l3_step_3")}, + RESPONSE: Message("fourth"), + TRANSITIONS: {lbl.forward(): cnd.true()}, + }, + "step_4": { + PRE_RESPONSE_PROCESSING: {"proc_name_4": add_prefix("l4_step_4")}, + RESPONSE: Message("fifth"), + TRANSITIONS: {"step_0": cnd.true()}, + }, + }, +} + + +# testing +happy_path = ( + (Message(), Message("l3_local: l2_local: l1_global: first")), + (Message(), Message("l3_local: l2_local: l1_step_1: second")), + (Message(), Message("l3_local: l2_step_2: l1_global: third")), + (Message(), Message("l3_step_3: l2_local: l1_global: fourth")), + ( + Message(), + Message("l4_step_4: l3_local: l2_local: l1_global: fifth"), + ), + (Message(), Message("l3_local: l2_local: l1_global: first")), +) + + +# %% +pipeline = Pipeline.from_script( + toy_script, + start_label=("root", "start"), + fallback_label=("root", "fallback"), +) + +if __name__ == "__main__": + check_happy_path(pipeline, happy_path) + if is_interactive_mode(): + run_interactive_mode(pipeline) diff --git a/tutorials/script/core/7_misc.py b/tutorials/script/core/8_misc.py similarity index 100% rename from tutorials/script/core/7_misc.py rename to tutorials/script/core/8_misc.py diff --git a/tutorials/script/core/9_pre_transitions_processing.py b/tutorials/script/core/9_pre_transitions_processing.py new file mode 100644 index 000000000..9f2eddc01 --- /dev/null +++ b/tutorials/script/core/9_pre_transitions_processing.py @@ -0,0 +1,99 @@ +# %% [markdown] +""" +# Core: 9. Pre-transitions processing + +This tutorial shows pre-transitions processing feature. + +Here, %mddoclink(api,script.core.keywords,Keywords.PRE_TRANSITIONS_PROCESSING) +is demonstrated which can be used for additional context +processing before transitioning to the next step. + +First of all, let's do all the necessary imports from DFF. +""" + +# %pip install dff + +# %% +from dff.script import ( + GLOBAL, + RESPONSE, + TRANSITIONS, + PRE_RESPONSE_PROCESSING, + PRE_TRANSITIONS_PROCESSING, + Context, + Message, +) +import dff.script.labels as lbl +import dff.script.conditions as cnd +from dff.pipeline import Pipeline +from dff.utils.testing.common import ( + check_happy_path, + is_interactive_mode, + run_interactive_mode, +) + + +# %% +def save_previous_node_response(ctx: Context, _: Pipeline): + processed_node = ctx.current_node + ctx.misc["previous_node_response"] = processed_node.response + + +def prepend_previous_node_response(ctx: Context, _: Pipeline): + processed_node = ctx.current_node + processed_node.response = Message( + text=f"previous={ctx.misc['previous_node_response'].text}:" + f" current={processed_node.response.text}" + ) + + +# %% +# a dialog script +toy_script = { + "root": { + "start": { + RESPONSE: Message(), + TRANSITIONS: {("flow", "step_0"): cnd.true()}, + }, + "fallback": {RESPONSE: Message("the end")}, + }, + GLOBAL: { + PRE_RESPONSE_PROCESSING: { + "proc_name_1": prepend_previous_node_response + }, + PRE_TRANSITIONS_PROCESSING: { + "proc_name_1": save_previous_node_response + }, + TRANSITIONS: {lbl.forward(0.1): cnd.true()}, + }, + "flow": { + "step_0": {RESPONSE: Message("first")}, + "step_1": {RESPONSE: Message("second")}, + "step_2": {RESPONSE: Message("third")}, + "step_3": {RESPONSE: Message("fourth")}, + "step_4": {RESPONSE: Message("fifth")}, + }, +} + + +# testing +happy_path = ( + (Message("1"), Message("previous=None: current=first")), + (Message("2"), Message("previous=first: current=second")), + (Message("3"), Message("previous=second: current=third")), + (Message("4"), Message("previous=third: current=fourth")), + (Message("5"), Message("previous=fourth: current=fifth")), +) + + +# %% +pipeline = Pipeline.from_script( + toy_script, + start_label=("root", "start"), + fallback_label=("root", "fallback"), +) + +if __name__ == "__main__": + check_happy_path(pipeline, happy_path) + if is_interactive_mode(): + run_interactive_mode(pipeline) From cb7474185761db03ae3e6d650d8c47fb680bfcb6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 17:29:05 +0000 Subject: [PATCH 09/31] build(deps-dev): bump the deps group with 2 updates (#343) Bumps the deps group with 2 updates: [pytest-cov](https://github.com/pytest-dev/pytest-cov) and [uvicorn](https://github.com/encode/uvicorn). Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/poetry.lock b/poetry.lock index bc3f448a8..cb8ba42a1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4580,13 +4580,13 @@ testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] [[package]] name = "pytest-cov" -version = "4.1.0" +version = "5.0.0" description = "Pytest plugin for measuring coverage." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, - {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, + {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, + {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, ] [package.dependencies] @@ -4594,7 +4594,7 @@ coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" [package.extras] -testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] [[package]] name = "pytest-fixture-config" @@ -6156,13 +6156,13 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "uvicorn" -version = "0.28.0" +version = "0.29.0" description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.8" files = [ - {file = "uvicorn-0.28.0-py3-none-any.whl", hash = "sha256:6623abbbe6176204a4226e67607b4d52cc60ff62cda0ff177613645cefa2ece1"}, - {file = "uvicorn-0.28.0.tar.gz", hash = "sha256:cab4473b5d1eaeb5a0f6375ac4bc85007ffc75c3cc1768816d9e5d589857b067"}, + {file = "uvicorn-0.29.0-py3-none-any.whl", hash = "sha256:2c2aac7ff4f4365c206fd773a39bf4ebd1047c238f8b8268ad996829323473de"}, + {file = "uvicorn-0.29.0.tar.gz", hash = "sha256:6a69214c0b6a087462412670b3ef21224fa48cae0e452b5883e8e8bdfdd11dd0"}, ] [package.dependencies] From fbfc084378544ffdbf8b9c14a06fac8bf38dea24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 08:48:48 +0000 Subject: [PATCH 10/31] build(deps-dev): bump black from 24.2.0 to 24.3.0 (#340) Bumps [black](https://github.com/psf/black) from 24.2.0 to 24.3.0. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 5ccead1a55e287cc744f2ad5297ffa2665fa7f5f Mon Sep 17 00:00:00 2001 From: Alexander Sergeev <22302418+pseusys@users.noreply.github.com> Date: Tue, 16 Apr 2024 01:00:50 +0200 Subject: [PATCH 11/31] Actor revalidation (#289) # Description Actor validation made required and also improved. --------- Co-authored-by: Roman Zlobin --- dff/messengers/telegram/messenger.py | 2 +- dff/pipeline/pipeline/actor.py | 50 +----- dff/pipeline/pipeline/pipeline.py | 32 +--- dff/pipeline/types.py | 2 - dff/script/__init__.py | 3 +- dff/script/conditions/std_conditions.py | 3 +- dff/script/core/context.py | 10 +- dff/script/core/normalization.py | 15 +- dff/script/core/script.py | 179 +++++++++++++++++++- dff/script/core/types.py | 9 +- dff/script/labels/std_labels.py | 48 +++--- tests/pipeline/test_pipeline.py | 4 +- tests/script/core/test_actor.py | 16 +- tests/script/core/test_normalization.py | 6 +- tests/script/core/test_script.py | 42 ++--- tests/script/core/test_validation.py | 215 ++++++++++++++++++++++++ tests/stats/test_defaults.py | 4 +- tutorials/script/core/4_transitions.py | 43 +++-- tutorials/script/core/8_misc.py | 5 +- tutorials/utils/1_cache.py | 4 +- tutorials/utils/2_lru_cache.py | 4 +- 21 files changed, 501 insertions(+), 195 deletions(-) create mode 100644 tests/script/core/test_validation.py diff --git a/dff/messengers/telegram/messenger.py b/dff/messengers/telegram/messenger.py index 15cbfc4e6..b88d149f9 100644 --- a/dff/messengers/telegram/messenger.py +++ b/dff/messengers/telegram/messenger.py @@ -232,7 +232,7 @@ def telegram_condition( **kwargs, ) - def condition(ctx: Context, _: Pipeline, *__, **___): # pragma: no cover + def condition(ctx: Context, _: Pipeline) -> bool: # pragma: no cover last_request = ctx.last_request if last_request is None: return False diff --git a/dff/pipeline/pipeline/actor.py b/dff/pipeline/pipeline/actor.py index 9613562f3..3bac71feb 100644 --- a/dff/pipeline/pipeline/actor.py +++ b/dff/pipeline/pipeline/actor.py @@ -45,22 +45,6 @@ from dff.pipeline.pipeline.pipeline import Pipeline -def error_handler(error_msgs: list, msg: str, exception: Optional[Exception] = None, logging_flag: bool = True): - """ - This function handles errors during :py:class:`~dff.script.Script` validation. - - :param error_msgs: List that contains error messages. :py:func:`~dff.script.error_handler` - adds every next error message to that list. - :param msg: Error message which is to be added into `error_msgs`. - :param exception: Invoked exception. If it has been set, it is used to obtain logging traceback. - Defaults to `None`. - :param logging_flag: The flag which defines whether logging is necessary. Defaults to `True`. - """ - error_msgs.append(msg) - if logging_flag: - logger.error(msg, exc_info=exception) - - class Actor: """ The class which is used to process :py:class:`~dff.script.Context` @@ -73,7 +57,7 @@ class Actor: Dialog comes into that label if all other transitions failed, or there was an error while executing the scenario. Defaults to `None`. - :param label_priority: Default priority value for all :py:const:`labels ` + :param label_priority: Default priority value for all :py:const:`labels ` where there is no priority. Defaults to `1.0`. :param condition_handler: Handler that processes a call of condition functions. Defaults to `None`. :param handlers: This variable is responsible for the usage of external handlers on @@ -92,11 +76,9 @@ def __init__( condition_handler: Optional[Callable] = None, handlers: Optional[Dict[ActorStage, List[Callable]]] = None, ): - # script validation self.script = script if isinstance(script, Script) else Script(script=script) self.label_priority = label_priority - # node labels validation self.start_label = normalize_label(start_label) if self.script.get(self.start_label[0], {}).get(self.start_label[1]) is None: raise ValueError(f"Unknown start_label={self.start_label}") @@ -389,36 +371,6 @@ def _choose_label( chosen_label = self.fallback_label return chosen_label - def validate_script(self, pipeline: Pipeline, verbose: bool = True): - # TODO: script has to not contain priority == -inf, because it uses for miss values - flow_labels = [] - node_labels = [] - labels = [] - conditions = [] - for flow_name, flow in self.script.items(): - for node_name, node in flow.items(): - flow_labels += [flow_name] * len(node.transitions) - node_labels += [node_name] * len(node.transitions) - labels += list(node.transitions.keys()) - conditions += list(node.transitions.values()) - - error_msgs = [] - for flow_label, node_label, label, condition in zip(flow_labels, node_labels, labels, conditions): - if not callable(label): - label = normalize_label(label, flow_label) - - # validate labeling - try: - node = self.script[label[0]][label[1]] - except Exception as exc: - msg = ( - f"Could not find node with label={label}, " - f"error was found in (flow_label, node_label)={(flow_label, node_label)}" - ) - error_handler(error_msgs, msg, exc, verbose) - break - return error_msgs - async def default_condition_handler( condition: Callable, ctx: Context, pipeline: Pipeline diff --git a/dff/pipeline/pipeline/pipeline.py b/dff/pipeline/pipeline/pipeline.py index 94eb52a57..d901a3ebf 100644 --- a/dff/pipeline/pipeline/pipeline.py +++ b/dff/pipeline/pipeline/pipeline.py @@ -50,12 +50,9 @@ class Pipeline: :param script: (required) A :py:class:`~.Script` instance (object or dict). :param start_label: (required) Actor start label. :param fallback_label: Actor fallback label. - :param label_priority: Default priority value for all actor :py:const:`labels ` + :param label_priority: Default priority value for all actor :py:const:`labels ` where there is no priority. Defaults to `1.0`. - :param validation_stage: This flag sets whether the validation stage is executed after actor creation. - It is executed by default. Defaults to `None`. :param condition_handler: Handler that processes a call of actor condition functions. Defaults to `None`. - :param verbose: If it is `True`, logging is used in actor. Defaults to `True`. :param handlers: This variable is responsible for the usage of external handlers on the certain stages of work of :py:class:`~dff.script.Actor`. @@ -88,9 +85,7 @@ def __init__( start_label: NodeLabel2Type, fallback_label: Optional[NodeLabel2Type] = None, label_priority: float = 1.0, - validation_stage: Optional[bool] = None, condition_handler: Optional[Callable] = None, - verbose: bool = True, handlers: Optional[Dict[ActorStage, List[Callable]]] = None, messenger_interface: Optional[MessengerInterface] = None, context_storage: Optional[Union[DBContextStorage, Dict]] = None, @@ -121,9 +116,7 @@ def __init__( start_label, fallback_label, label_priority, - validation_stage, condition_handler, - verbose, handlers, ) if self.actor is None: @@ -211,9 +204,7 @@ def from_script( start_label: NodeLabel2Type, fallback_label: Optional[NodeLabel2Type] = None, label_priority: float = 1.0, - validation_stage: Optional[bool] = None, condition_handler: Optional[Callable] = None, - verbose: bool = True, parallelize_processing: bool = False, handlers: Optional[Dict[ActorStage, List[Callable]]] = None, context_storage: Optional[Union[DBContextStorage, Dict]] = None, @@ -232,12 +223,9 @@ def from_script( :param script: (required) A :py:class:`~.Script` instance (object or dict). :param start_label: (required) Actor start label. :param fallback_label: Actor fallback label. - :param label_priority: Default priority value for all actor :py:const:`labels ` + :param label_priority: Default priority value for all actor :py:const:`labels ` where there is no priority. Defaults to `1.0`. - :param validation_stage: This flag sets whether the validation stage is executed after actor creation. - It is executed by default. Defaults to `None`. :param condition_handler: Handler that processes a call of actor condition functions. Defaults to `None`. - :param verbose: If it is `True`, logging is used in actor. Defaults to `True`. :param parallelize_processing: This flag determines whether or not the functions defined in the ``PRE_RESPONSE_PROCESSING`` and ``PRE_TRANSITIONS_PROCESSING`` sections of the script should be parallelized over respective groups. @@ -265,9 +253,7 @@ def from_script( start_label=start_label, fallback_label=fallback_label, label_priority=label_priority, - validation_stage=validation_stage, condition_handler=condition_handler, - verbose=verbose, parallelize_processing=parallelize_processing, handlers=handlers, messenger_interface=messenger_interface, @@ -281,9 +267,7 @@ def set_actor( start_label: NodeLabel2Type, fallback_label: Optional[NodeLabel2Type] = None, label_priority: float = 1.0, - validation_stage: Optional[bool] = None, condition_handler: Optional[Callable] = None, - verbose: bool = True, handlers: Optional[Dict[ActorStage, List[Callable]]] = None, ): """ @@ -296,26 +280,16 @@ def set_actor( :param fallback_label: Actor fallback label. The label of :py:class:`~dff.script.Script`. Dialog comes into that label if all other transitions failed, or there was an error while executing the scenario. - :param label_priority: Default priority value for all actor :py:const:`labels ` + :param label_priority: Default priority value for all actor :py:const:`labels ` where there is no priority. Defaults to `1.0`. - :param validation_stage: This flag sets whether the validation stage is executed in actor. - It is executed by default. Defaults to `None`. :param condition_handler: Handler that processes a call of actor condition functions. Defaults to `None`. - :param verbose: If it is `True`, logging is used in actor. Defaults to `True`. :param handlers: This variable is responsible for the usage of external handlers on the certain stages of work of :py:class:`~dff.script.Actor`. - key :py:class:`~dff.script.ActorStage` - Stage in which the handler is called. - value List[Callable] - The list of called handlers for each stage. Defaults to an empty `dict`. """ - old_actor = self.actor self.actor = Actor(script, start_label, fallback_label, label_priority, condition_handler, handlers) - errors = self.actor.validate_script(self, verbose) if validation_stage is not False else [] - if errors: - self.actor = old_actor - raise ValueError( - f"Found {len(errors)} errors: " + " ".join([f"{i}) {er}" for i, er in enumerate(errors, 1)]) - ) @classmethod def from_dict(cls, dictionary: PipelineBuilder) -> "Pipeline": diff --git a/dff/pipeline/types.py b/dff/pipeline/types.py index b8c782471..c26525972 100644 --- a/dff/pipeline/types.py +++ b/dff/pipeline/types.py @@ -263,9 +263,7 @@ class ExtraHandlerRuntimeInfo(BaseModel): "start_label": NodeLabel2Type, "fallback_label": NotRequired[Optional[NodeLabel2Type]], "label_priority": NotRequired[float], - "validation_stage": NotRequired[Optional[bool]], "condition_handler": NotRequired[Optional[Callable]], - "verbose": NotRequired[bool], "handlers": NotRequired[Optional[Dict[ActorStage, List[Callable]]]], }, ) diff --git a/dff/script/__init__.py b/dff/script/__init__.py index 577266bc9..9ac057b45 100644 --- a/dff/script/__init__.py +++ b/dff/script/__init__.py @@ -18,7 +18,8 @@ NodeLabel2Type, NodeLabel3Type, NodeLabelTupledType, - NodeLabelType, + ConstLabel, + Label, ConditionType, ModuleName, ActorStage, diff --git a/dff/script/conditions/std_conditions.py b/dff/script/conditions/std_conditions.py index d2d23f4e8..88c086ab4 100644 --- a/dff/script/conditions/std_conditions.py +++ b/dff/script/conditions/std_conditions.py @@ -189,12 +189,13 @@ def has_last_labels( Return condition handler. This handler returns `True` if any label from last `last_n_indices` context labels is in the `flow_labels` list or in - the `~dff.script.NodeLabel2Type` list. + the `labels` list. :param flow_labels: List of labels to check. Every label has type `str`. Empty if not set. :param labels: List of labels corresponding to the nodes. Empty if not set. :param last_n_indices: Number of last utterances to check. """ + # todo: rewrite docs & function itself flow_labels = [] if flow_labels is None else flow_labels labels = [] if labels is None else labels diff --git a/dff/script/core/context.py b/dff/script/core/context.py index e174ecb7a..4b223eef5 100644 --- a/dff/script/core/context.py +++ b/dff/script/core/context.py @@ -88,14 +88,6 @@ class Context(BaseModel): - key - Arbitrary data name. - value - Arbitrary data. """ - validation: bool = False - """ - `validation` is a flag that signals that :py:class:`~dff.pipeline.pipeline.pipeline.Pipeline`, - while being initialized, checks the :py:class:`~dff.script.core.script.Script`. - The functions that can give not valid data - while being validated must use this flag to take the validation mode into account. - Otherwise the validation will not be passed. - """ framework_states: Dict[ModuleName, Dict[str, Any]] = {} """ `framework_states` is used for addons states or for @@ -142,7 +134,7 @@ def cast(cls, ctx: Optional[Union[Context, dict, str]] = None, *args, **kwargs) ctx = Context.model_validate(ctx) elif isinstance(ctx, str): ctx = Context.model_validate_json(ctx) - elif not issubclass(type(ctx), Context): + elif not isinstance(ctx, Context): raise ValueError( f"Context expected to be an instance of the Context class " f"or an instance of the dict/str(json) type. Got: {type(ctx)}" diff --git a/dff/script/core/normalization.py b/dff/script/core/normalization.py index 6ad57144f..e6926227d 100644 --- a/dff/script/core/normalization.py +++ b/dff/script/core/normalization.py @@ -12,7 +12,7 @@ from .keywords import Keywords from .context import Context -from .types import NodeLabel3Type, NodeLabelType, ConditionType, LabelType +from .types import ConstLabel, ConditionType, Label, LabelType from .message import Message if TYPE_CHECKING: @@ -21,22 +21,19 @@ logger = logging.getLogger(__name__) -def normalize_label( - label: NodeLabelType, default_flow_label: LabelType = "" -) -> Union[Callable[[Context, Pipeline], NodeLabel3Type], NodeLabel3Type]: +def normalize_label(label: Label, default_flow_label: LabelType = "") -> Label: """ The function that is used for normalization of - :py:const:`default_flow_label `. + :py:const:`label `. :param label: If label is Callable the function is wrapped into try/except and normalization is used on the result of the function call with the name label. :param default_flow_label: flow_label is used if label does not contain flow_label. - :return: Result of the label normalization, - if Callable is returned, the normalized result is returned. + :return: Result of the label normalization """ if callable(label): - def get_label_handler(ctx: Context, pipeline: Pipeline) -> NodeLabel3Type: + def get_label_handler(ctx: Context, pipeline: Pipeline) -> ConstLabel: try: new_label = label(ctx, pipeline) new_label = normalize_label(new_label, default_flow_label) @@ -62,6 +59,8 @@ def get_label_handler(ctx: Context, pipeline: Pipeline) -> NodeLabel3Type: elif isinstance(label, tuple) and len(label) == 3: flow_label = label[0] or default_flow_label return (flow_label, label[1], label[2]) + else: + raise TypeError(f"Label '{label!r}' is of incorrect type. It has to follow the `Label`:\n" f"{Label!r}") def normalize_condition(condition: ConditionType) -> Callable[[Context, Pipeline], bool]: diff --git a/dff/script/core/script.py b/dff/script/core/script.py index c5c65b83a..3c7fde9b5 100644 --- a/dff/script/core/script.py +++ b/dff/script/core/script.py @@ -8,12 +8,14 @@ # %% from __future__ import annotations +from enum import Enum +import inspect import logging -from typing import Callable, Optional, Any, Dict, Union, TYPE_CHECKING +from typing import Callable, List, Optional, Any, Dict, Tuple, Union, TYPE_CHECKING from pydantic import BaseModel, field_validator, validate_call -from .types import LabelType, NodeLabelType, ConditionType, NodeLabel3Type +from .types import Label, LabelType, ConditionType, ConstLabel # noqa: F401 from .message import Message from .keywords import Keywords from .normalization import normalize_condition, normalize_label @@ -25,12 +27,89 @@ logger = logging.getLogger(__name__) +class UserFunctionType(str, Enum): + LABEL = "label" + RESPONSE = "response" + CONDITION = "condition" + TRANSITION_PROCESSING = "pre_transitions_processing" + RESPONSE_PROCESSING = "pre_response_processing" + + +USER_FUNCTION_TYPES: Dict[UserFunctionType, Tuple[Tuple[str, ...], str]] = { + UserFunctionType.LABEL: (("Context", "Pipeline"), "ConstLabel"), + UserFunctionType.RESPONSE: (("Context", "Pipeline"), "Message"), + UserFunctionType.CONDITION: (("Context", "Pipeline"), "bool"), + UserFunctionType.RESPONSE_PROCESSING: (("Context", "Pipeline"), "None"), + UserFunctionType.TRANSITION_PROCESSING: (("Context", "Pipeline"), "None"), +} + + +def _types_equal(signature_type: Any, expected_type: str) -> bool: + """ + This function checks equality of signature type with expected type. + Three cases are handled. If no signature is present, it is presumed that types are equal. + If signature is a type, it is compared with expected type as is. + If signature is a string, it is compared with expected type name. + + :param signature_type: type received from function signature. + :param expected_type: expected type - a class. + :return: true if types are equal, false otherwise. + """ + signature_str = signature_type.__name__ if hasattr(signature_type, "__name__") else str(signature_type) + signature_empty = signature_type == inspect.Parameter.empty + expected_string = signature_str == expected_type + expected_global = str(signature_type) == str(globals().get(expected_type)) + return signature_empty or expected_string or expected_global + + +def _validate_callable(callable: Callable, func_type: UserFunctionType, flow_label: str, node_label: str) -> List: + """ + This function validates a function during :py:class:`~dff.script.Script` validation. + It checks parameter number (unconditionally), parameter types (if specified) and return type (if specified). + + :param callable: Function to validate. + :param func_type: Type of the function (label, condition, response, etc.). + :param flow_label: Flow label this function is related to (used for error localization only). + :param node_label: Node label this function is related to (used for error localization only). + :return: list of produced error messages. + """ + + error_msgs = list() + signature = inspect.signature(callable) + arguments_type, return_type = USER_FUNCTION_TYPES[func_type] + params = list(signature.parameters.values()) + if len(params) != len(arguments_type): + msg = ( + f"Incorrect parameter number for {callable.__name__!r}: " + f"should be {len(arguments_type)}, not {len(params)}. " + f"Error found at {(flow_label, node_label)!r}." + ) + error_msgs.append(msg) + for idx, param in enumerate(params): + if not _types_equal(param.annotation, arguments_type[idx]): + msg = ( + f"Incorrect parameter annotation for parameter #{idx + 1} " + f" of {callable.__name__!r}: " + f"should be {arguments_type[idx]}, not {param.annotation}. " + f"Error found at {(flow_label, node_label)!r}." + ) + error_msgs.append(msg) + if not _types_equal(signature.return_annotation, return_type): + msg = ( + f"Incorrect return type annotation of {callable.__name__!r}: " + f"should be {return_type!r}, not {signature.return_annotation}. " + f"Error found at {(flow_label, node_label)!r}." + ) + error_msgs.append(msg) + return error_msgs + + class Node(BaseModel, extra="forbid", validate_assignment=True): """ The class for the `Node` object. """ - transitions: Dict[NodeLabelType, ConditionType] = {} + transitions: Dict[Label, ConditionType] = {} response: Optional[Union[Message, Callable[[Context, Pipeline], Message]]] = None pre_transitions_processing: Dict[Any, Callable] = {} pre_response_processing: Dict[Any, Callable] = {} @@ -39,9 +118,7 @@ class Node(BaseModel, extra="forbid", validate_assignment=True): @field_validator("transitions", mode="before") @classmethod @validate_call - def normalize_transitions( - cls, transitions: Dict[NodeLabelType, ConditionType] - ) -> Dict[Union[Callable, NodeLabel3Type], Callable]: + def normalize_transitions(cls, transitions: Dict[Label, ConditionType]) -> Dict[Label, Callable]: """ The function which is used to normalize transitions and returns normalized dict. @@ -81,6 +158,96 @@ def normalize_script(cls, script: Dict[LabelType, Any]) -> Dict[LabelType, Dict[ script[Keywords.GLOBAL] = {Keywords.GLOBAL: script[Keywords.GLOBAL]} return script + @field_validator("script", mode="before") + @classmethod + @validate_call + def validate_script_before(cls, script: Dict[LabelType, Any]) -> Dict[LabelType, Dict[LabelType, Dict[str, Any]]]: + error_msgs = [] + for flow_name, flow in script.items(): + for node_name, node in flow.items(): + # validate labeling + transitions = node.get("transitions", dict()) + for label in transitions.keys(): + if callable(label): + error_msgs += _validate_callable(label, UserFunctionType.LABEL, flow_name, node_name) + + # validate responses + response = node.get("response", None) + if callable(response): + error_msgs += _validate_callable( + response, + UserFunctionType.RESPONSE, + flow_name, + node_name, + ) + + # validate conditions + for label, condition in transitions.items(): + if callable(condition): + error_msgs += _validate_callable( + condition, + UserFunctionType.CONDITION, + flow_name, + node_name, + ) + + # validate pre_transitions- and pre_response_processing + pre_transitions_processing = node.get("pre_transitions_processing", dict()) + pre_response_processing = node.get("pre_response_processing", dict()) + for place, functions in zip( + (UserFunctionType.TRANSITION_PROCESSING, UserFunctionType.RESPONSE_PROCESSING), + (pre_transitions_processing, pre_response_processing), + ): + for function in functions.values(): + if callable(function): + error_msgs += _validate_callable( + function, + place, + flow_name, + node_name, + ) + if error_msgs: + error_number_string = "1 error" if len(error_msgs) == 1 else f"{len(error_msgs)} errors" + raise ValueError( + f"Found {error_number_string}:\n" + "\n".join([f"{i}) {er}" for i, er in enumerate(error_msgs, 1)]) + ) + else: + return script + + @field_validator("script", mode="after") + @classmethod + @validate_call + def validate_script_after(cls, script: Dict[LabelType, Any]) -> Dict[LabelType, Dict[LabelType, Dict[str, Any]]]: + error_msgs = [] + for flow_name, flow in script.items(): + for node_name, node in flow.items(): + # validate labeling + for label in node.transitions.keys(): + if not callable(label): + norm_flow_label, norm_node_label, _ = normalize_label(label, flow_name) + if norm_flow_label not in script.keys(): + msg = ( + f"Flow {norm_flow_label!r} cannot be found for label={label}. " + f"Error found at {(flow_name, node_name)!r}." + ) + elif norm_node_label not in script[norm_flow_label].keys(): + msg = ( + f"Node {norm_node_label!r} cannot be found for label={label}. " + f"Error found at {(flow_name, node_name)!r}." + ) + else: + msg = None + if msg is not None: + error_msgs.append(msg) + + if error_msgs: + error_number_string = "1 error" if len(error_msgs) == 1 else f"{len(error_msgs)} errors" + raise ValueError( + f"Found {error_number_string}:\n" + "\n".join([f"{i}) {er}" for i, er in enumerate(error_msgs, 1)]) + ) + else: + return script + def __getitem__(self, key): return self.script[key] diff --git a/dff/script/core/types.py b/dff/script/core/types.py index a4f088dec..69b8aafd2 100644 --- a/dff/script/core/types.py +++ b/dff/script/core/types.py @@ -15,6 +15,7 @@ LabelType: TypeAlias = Union[str, Keywords] """Label can be a casual string or :py:class:`~dff.script.Keywords`.""" +# todo: rename these to identifiers NodeLabel1Type: TypeAlias = Tuple[str, float] """Label type for transitions can be `[node_name, transition_priority]`.""" @@ -27,9 +28,13 @@ NodeLabelTupledType: TypeAlias = Union[NodeLabel1Type, NodeLabel2Type, NodeLabel3Type] """Label type for transitions can be one of three different types.""" +# todo: group all these types into a class -NodeLabelType: TypeAlias = Union[Callable, NodeLabelTupledType, str] -"""Label type for transitions can be one of three different types.""" +ConstLabel: TypeAlias = Union[NodeLabelTupledType, str] +"""Label functions should be annotated with this type only.""" + +Label: TypeAlias = Union[ConstLabel, Callable] +"""Label type for transitions should be of this type only.""" ConditionType: TypeAlias = Callable """Condition type can be only `Callable`.""" diff --git a/dff/script/labels/std_labels.py b/dff/script/labels/std_labels.py index 663c89461..6f58c4411 100644 --- a/dff/script/labels/std_labels.py +++ b/dff/script/labels/std_labels.py @@ -1,36 +1,36 @@ """ Labels ------ -:py:const:`Labels ` are one of the important components of the dialog graph, +:py:const:`Labels ` are one of the important components of the dialog graph, which determine the targeted node name of the transition. They are used to identify the next step in the conversation. Labels can also be used in combination with other conditions, such as the current context or user data, to create more complex and dynamic conversations. -This module contains a standard set of scripting :py:const:`labels ` that +This module contains a standard set of scripting :py:const:`labels ` that can be used by developers to define the conversation flow. """ from __future__ import annotations from typing import Optional, Callable, TYPE_CHECKING -from dff.script import Context, NodeLabel3Type +from dff.script import Context, ConstLabel if TYPE_CHECKING: from dff.pipeline.pipeline.pipeline import Pipeline -def repeat(priority: Optional[float] = None) -> Callable: +def repeat(priority: Optional[float] = None) -> Callable[[Context, Pipeline], ConstLabel]: """ Returns transition handler that takes :py:class:`.Context`, :py:class:`~dff.pipeline.Pipeline` and :py:const:`priority `. - This handler returns a :py:const:`label ` + This handler returns a :py:const:`label ` to the last node with a given :py:const:`priority `. If the priority is not given, `Pipeline.actor.label_priority` is used as default. :param priority: Priority of transition. Uses `Pipeline.actor.label_priority` if priority not defined. """ - def repeat_transition_handler(ctx: Context, pipeline: Pipeline) -> NodeLabel3Type: + def repeat_transition_handler(ctx: Context, pipeline: Pipeline) -> ConstLabel: current_priority = pipeline.actor.label_priority if priority is None else priority if len(ctx.labels) >= 1: flow_label, label = list(ctx.labels.values())[-1] @@ -41,11 +41,11 @@ def repeat_transition_handler(ctx: Context, pipeline: Pipeline) -> NodeLabel3Typ return repeat_transition_handler -def previous(priority: Optional[float] = None) -> Callable: +def previous(priority: Optional[float] = None) -> Callable[[Context, Pipeline], ConstLabel]: """ Returns transition handler that takes :py:class:`~dff.script.Context`, :py:class:`~dff.pipeline.Pipeline` and :py:const:`priority `. - This handler returns a :py:const:`label ` + This handler returns a :py:const:`label ` to the previous node with a given :py:const:`priority `. If the priority is not given, `Pipeline.actor.label_priority` is used as default. If the current node is the start node, fallback is returned. @@ -53,7 +53,7 @@ def previous(priority: Optional[float] = None) -> Callable: :param priority: Priority of transition. Uses `Pipeline.actor.label_priority` if priority not defined. """ - def previous_transition_handler(ctx: Context, pipeline: Pipeline) -> NodeLabel3Type: + def previous_transition_handler(ctx: Context, pipeline: Pipeline) -> ConstLabel: current_priority = pipeline.actor.label_priority if priority is None else priority if len(ctx.labels) >= 2: flow_label, label = list(ctx.labels.values())[-2] @@ -66,36 +66,36 @@ def previous_transition_handler(ctx: Context, pipeline: Pipeline) -> NodeLabel3T return previous_transition_handler -def to_start(priority: Optional[float] = None) -> Callable: +def to_start(priority: Optional[float] = None) -> Callable[[Context, Pipeline], ConstLabel]: """ Returns transition handler that takes :py:class:`~dff.script.Context`, :py:class:`~dff.pipeline.Pipeline` and :py:const:`priority `. - This handler returns a :py:const:`label ` + This handler returns a :py:const:`label ` to the start node with a given :py:const:`priority `. If the priority is not given, `Pipeline.actor.label_priority` is used as default. :param priority: Priority of transition. Uses `Pipeline.actor.label_priority` if priority not defined. """ - def to_start_transition_handler(ctx: Context, pipeline: Pipeline) -> NodeLabel3Type: + def to_start_transition_handler(ctx: Context, pipeline: Pipeline) -> ConstLabel: current_priority = pipeline.actor.label_priority if priority is None else priority return (*pipeline.actor.start_label[:2], current_priority) return to_start_transition_handler -def to_fallback(priority: Optional[float] = None) -> Callable: +def to_fallback(priority: Optional[float] = None) -> Callable[[Context, Pipeline], ConstLabel]: """ Returns transition handler that takes :py:class:`~dff.script.Context`, :py:class:`~dff.pipeline.Pipeline` and :py:const:`priority `. - This handler returns a :py:const:`label ` + This handler returns a :py:const:`label ` to the fallback node with a given :py:const:`priority `. If the priority is not given, `Pipeline.actor.label_priority` is used as default. :param priority: Priority of transition. Uses `Pipeline.actor.label_priority` if priority not defined. """ - def to_fallback_transition_handler(ctx: Context, pipeline: Pipeline) -> NodeLabel3Type: + def to_fallback_transition_handler(ctx: Context, pipeline: Pipeline) -> ConstLabel: current_priority = pipeline.actor.label_priority if priority is None else priority return (*pipeline.actor.fallback_label[:2], current_priority) @@ -108,7 +108,7 @@ def _get_label_by_index_shifting( priority: Optional[float] = None, increment_flag: bool = True, cyclicality_flag: bool = True, -) -> NodeLabel3Type: +) -> ConstLabel: """ Function that returns node label from the context and pipeline after shifting the index. @@ -137,11 +137,13 @@ def _get_label_by_index_shifting( return (flow_label, labels[label_index], current_priority) -def forward(priority: Optional[float] = None, cyclicality_flag: bool = True) -> Callable: +def forward( + priority: Optional[float] = None, cyclicality_flag: bool = True +) -> Callable[[Context, Pipeline], ConstLabel]: """ Returns transition handler that takes :py:class:`~dff.script.Context`, :py:class:`~dff.pipeline.Pipeline` and :py:const:`priority `. - This handler returns a :py:const:`label ` + This handler returns a :py:const:`label ` to the forward node with a given :py:const:`priority ` and :py:const:`cyclicality_flag `. If the priority is not given, `Pipeline.actor.label_priority` is used as default. @@ -150,7 +152,7 @@ def forward(priority: Optional[float] = None, cyclicality_flag: bool = True) -> (e.g the element with `index = len(labels)` has `index = 0`). Defaults to `True`. """ - def forward_transition_handler(ctx: Context, pipeline: Pipeline) -> NodeLabel3Type: + def forward_transition_handler(ctx: Context, pipeline: Pipeline) -> ConstLabel: return _get_label_by_index_shifting( ctx, pipeline, priority, increment_flag=True, cyclicality_flag=cyclicality_flag ) @@ -158,11 +160,13 @@ def forward_transition_handler(ctx: Context, pipeline: Pipeline) -> NodeLabel3Ty return forward_transition_handler -def backward(priority: Optional[float] = None, cyclicality_flag: bool = True) -> Callable: +def backward( + priority: Optional[float] = None, cyclicality_flag: bool = True +) -> Callable[[Context, Pipeline], ConstLabel]: """ Returns transition handler that takes :py:class:`~dff.script.Context`, :py:class:`~dff.pipeline.Pipeline` and :py:const:`priority `. - This handler returns a :py:const:`label ` + This handler returns a :py:const:`label ` to the backward node with a given :py:const:`priority ` and :py:const:`cyclicality_flag `. If the priority is not given, `Pipeline.actor.label_priority` is used as default. @@ -171,7 +175,7 @@ def backward(priority: Optional[float] = None, cyclicality_flag: bool = True) -> (e.g the element with `index = len(labels)` has `index = 0`). Defaults to `True`. """ - def back_transition_handler(ctx: Context, pipeline: Pipeline) -> NodeLabel3Type: + def back_transition_handler(ctx: Context, pipeline: Pipeline) -> ConstLabel: return _get_label_by_index_shifting( ctx, pipeline, priority, increment_flag=False, cyclicality_flag=cyclicality_flag ) diff --git a/tests/pipeline/test_pipeline.py b/tests/pipeline/test_pipeline.py index 97f2f7f61..8cf96f551 100644 --- a/tests/pipeline/test_pipeline.py +++ b/tests/pipeline/test_pipeline.py @@ -16,9 +16,9 @@ def test_pretty_format(): def test_script_getting_and_setting(): - script = {"old_flow": {"": {RESPONSE: lambda c, p: Message(), TRANSITIONS: {"": cnd.true()}}}} + script = {"old_flow": {"": {RESPONSE: lambda _, __: Message(), TRANSITIONS: {"": cnd.true()}}}} pipeline = Pipeline.from_script(script=script, start_label=("old_flow", "")) - new_script = {"new_flow": {"": {RESPONSE: lambda c, p: Message(), TRANSITIONS: {"": cnd.false()}}}} + new_script = {"new_flow": {"": {RESPONSE: lambda _, __: Message(), TRANSITIONS: {"": cnd.false()}}}} pipeline.set_actor(script=new_script, start_label=("new_flow", "")) assert list(pipeline.script.script.keys())[0] == list(new_script.keys())[0] diff --git a/tests/script/core/test_actor.py b/tests/script/core/test_actor.py index 99dfcbd00..5a9fa6a04 100644 --- a/tests/script/core/test_actor.py +++ b/tests/script/core/test_actor.py @@ -12,6 +12,7 @@ Message, ) from dff.script.conditions import true +from dff.script.labels import repeat def positive_test(samples, custom_class): @@ -39,8 +40,6 @@ def std_func(ctx, pipeline): def fake_label(ctx: Context, pipeline): - if not ctx.validation: - return ("123", "123", 0) return ("flow", "node1", 1) @@ -68,6 +67,17 @@ async def test_actor(): raise Exception("can not be passed: fail of missing node") except ValueError: pass + try: + # fail of response returned Callable + pipeline = Pipeline.from_script( + {"flow": {"node1": {RESPONSE: lambda c, a: lambda x: 1, TRANSITIONS: {repeat(): true()}}}}, + start_label=("flow", "node1"), + ) + ctx = Context() + await pipeline.actor(pipeline, ctx) + raise Exception("can not be passed: fail of response returned Callable") + except ValueError: + pass # empty ctx stability pipeline = Pipeline.from_script( @@ -185,7 +195,7 @@ async def test_call_limit(): }, } # script = {"flow": {"node1": {TRANSITIONS: {"node1": true()}}}} - pipeline = Pipeline.from_script(script=script, start_label=("flow1", "node1"), validation_stage=False) + pipeline = Pipeline.from_script(script=script, start_label=("flow1", "node1")) for i in range(4): await pipeline._run_pipeline(Message("req1"), 0) if limit_errors: diff --git a/tests/script/core/test_normalization.py b/tests/script/core/test_normalization.py index fc871b889..66852b222 100644 --- a/tests/script/core/test_normalization.py +++ b/tests/script/core/test_normalization.py @@ -12,7 +12,7 @@ Context, Script, Node, - NodeLabel3Type, + ConstLabel, Message, ) from dff.script.labels import repeat @@ -36,10 +36,10 @@ def create_env() -> Tuple[Context, Pipeline]: def test_normalize_label(): ctx, actor = create_env() - def true_label_func(ctx: Context, pipeline: Pipeline) -> NodeLabel3Type: + def true_label_func(ctx: Context, pipeline: Pipeline) -> ConstLabel: return ("flow", "node1", 1) - def false_label_func(ctx: Context, pipeline: Pipeline) -> NodeLabel3Type: + def false_label_func(ctx: Context, pipeline: Pipeline) -> ConstLabel: return ("flow", "node2", 1) n_f = normalize_label(true_label_func) diff --git a/tests/script/core/test_script.py b/tests/script/core/test_script.py index 72f6a0175..b4f5dd371 100644 --- a/tests/script/core/test_script.py +++ b/tests/script/core/test_script.py @@ -1,8 +1,9 @@ # %% import itertools +import pytest + from dff.script import ( - GLOBAL, TRANSITIONS, RESPONSE, MISC, @@ -12,6 +13,7 @@ Node, Message, ) +from dff.utils.testing.toy_script import TOY_SCRIPT, MULTIFLOW_SCRIPT def positive_test(samples, custom_class): @@ -97,16 +99,6 @@ def node_test(node: Node): def test_node_exec(): - # node = Node( - # **{ - # TRANSITIONS.name.lower(): {"node": std_func}, - # RESPONSE.name.lower(): "text", - # PROCESSING.name.lower(): {1: std_func}, - # PRE_TRANSITIONS_PROCESSING.name.lower(): {1: std_func}, - # MISC.name.lower(): {"key": "val"}, - # } - # ) - # node_test(node) node = Node( **{ TRANSITIONS.name.lower(): {"node": std_func}, @@ -119,22 +111,12 @@ def test_node_exec(): node_test(node) -def test_script(): - script_test(PRE_RESPONSE_PROCESSING) - - -def script_test(pre_response_proc): - node_template = { - TRANSITIONS: {"node": std_func}, - RESPONSE: Message("text"), - pre_response_proc: {1: std_func}, - PRE_TRANSITIONS_PROCESSING: {1: std_func}, - MISC: {"key": "val"}, - } - script = Script(script={GLOBAL: node_template.copy(), "flow": {"node": node_template.copy()}}) - node_test(script[GLOBAL][GLOBAL]) - node_test(script["flow"]["node"]) - assert list(script.keys()) == [GLOBAL, "flow"] - assert len(script.values()) == 2 - assert list(script) == [GLOBAL, "flow"] - assert len(list(script.items())) == 2 +@pytest.mark.parametrize( + ["script"], + [ + (TOY_SCRIPT,), + (MULTIFLOW_SCRIPT,), + ], +) +def test_script(script): + Script(script=script) diff --git a/tests/script/core/test_validation.py b/tests/script/core/test_validation.py new file mode 100644 index 000000000..13941ec4a --- /dev/null +++ b/tests/script/core/test_validation.py @@ -0,0 +1,215 @@ +from pydantic import ValidationError +import pytest + +from dff.pipeline import Pipeline +from dff.script import ( + PRE_RESPONSE_PROCESSING, + PRE_TRANSITIONS_PROCESSING, + RESPONSE, + TRANSITIONS, + Context, + Message, + Script, + ConstLabel, +) +from dff.script.conditions import exact_match + + +class UserFunctionSamples: + """ + This class contains various examples of user functions along with their signatures. + """ + + @staticmethod + def wrong_param_number(number: int) -> float: + return 8.0 + number + + @staticmethod + def wrong_param_types(number: int, flag: bool) -> float: + return 8.0 + number if flag else 42.1 + + @staticmethod + def wrong_return_type(_: Context, __: Pipeline) -> float: + return 1.0 + + @staticmethod + def correct_label(_: Context, __: Pipeline) -> ConstLabel: + return ("root", "start", 1) + + @staticmethod + def correct_response(_: Context, __: Pipeline) -> Message: + return Message("hi") + + @staticmethod + def correct_condition(_: Context, __: Pipeline) -> bool: + return True + + @staticmethod + def correct_pre_response_processor(_: Context, __: Pipeline) -> None: + pass + + @staticmethod + def correct_pre_transition_processor(_: Context, __: Pipeline) -> None: + pass + + +class TestLabelValidation: + def test_param_number(self): + with pytest.raises(ValidationError, match=r"Found 3 errors:[\w\W]*Incorrect parameter number") as e: + Script( + script={ + "root": { + "start": {TRANSITIONS: {UserFunctionSamples.wrong_param_number: exact_match(Message("hi"))}} + } + } + ) + assert e + + def test_param_types(self): + with pytest.raises(ValidationError, match=r"Found 3 errors:[\w\W]*Incorrect parameter annotation") as e: + Script( + script={ + "root": { + "start": {TRANSITIONS: {UserFunctionSamples.wrong_param_types: exact_match(Message("hi"))}} + } + } + ) + assert e + + def test_return_type(self): + with pytest.raises(ValidationError, match=r"Found 1 error:[\w\W]*Incorrect return type annotation") as e: + Script( + script={ + "root": { + "start": {TRANSITIONS: {UserFunctionSamples.wrong_return_type: exact_match(Message("hi"))}} + } + } + ) + assert e + + def test_flow_name(self): + with pytest.raises(ValidationError, match=r"Found 1 error:[\w\W]*Flow '\w*' cannot be found for label") as e: + Script(script={"root": {"start": {TRANSITIONS: {("other", "start", 1): exact_match(Message("hi"))}}}}) + assert e + + def test_node_name(self): + with pytest.raises(ValidationError, match=r"Found 1 error:[\w\W]*Node '\w*' cannot be found for label") as e: + Script(script={"root": {"start": {TRANSITIONS: {("root", "other", 1): exact_match(Message("hi"))}}}}) + assert e + + def test_correct_script(self): + Script( + script={"root": {"start": {TRANSITIONS: {UserFunctionSamples.correct_label: exact_match(Message("hi"))}}}} + ) + + +class TestResponseValidation: + def test_param_number(self): + with pytest.raises(ValidationError, match=r"Found 3 errors:[\w\W]*Incorrect parameter number") as e: + Script(script={"root": {"start": {RESPONSE: UserFunctionSamples.wrong_param_number}}}) + assert e + + def test_param_types(self): + with pytest.raises(ValidationError, match=r"Found 3 errors:[\w\W]*Incorrect parameter annotation") as e: + Script(script={"root": {"start": {RESPONSE: UserFunctionSamples.wrong_param_types}}}) + assert e + + def test_return_type(self): + with pytest.raises(ValidationError, match=r"Found 1 error:[\w\W]*Incorrect return type annotation") as e: + Script(script={"root": {"start": {RESPONSE: UserFunctionSamples.wrong_return_type}}}) + assert e + + def test_correct_script(self): + Script(script={"root": {"start": {RESPONSE: UserFunctionSamples.correct_response}}}) + + +class TestConditionValidation: + def test_param_number(self): + with pytest.raises(ValidationError, match=r"Found 3 errors:[\w\W]*Incorrect parameter number") as e: + Script( + script={ + "root": {"start": {TRANSITIONS: {("root", "start", 1): UserFunctionSamples.wrong_param_number}}} + } + ) + assert e + + def test_param_types(self): + with pytest.raises(ValidationError, match=r"Found 3 errors:[\w\W]*Incorrect parameter annotation") as e: + Script( + script={"root": {"start": {TRANSITIONS: {("root", "start", 1): UserFunctionSamples.wrong_param_types}}}} + ) + assert e + + def test_return_type(self): + with pytest.raises(ValidationError, match=r"Found 1 error:[\w\W]*Incorrect return type annotation") as e: + Script( + script={"root": {"start": {TRANSITIONS: {("root", "start", 1): UserFunctionSamples.wrong_return_type}}}} + ) + assert e + + def test_correct_script(self): + Script(script={"root": {"start": {TRANSITIONS: {("root", "start", 1): UserFunctionSamples.correct_condition}}}}) + + +class TestProcessingValidation: + def test_response_param_number(self): + with pytest.raises(ValidationError, match=r"Found 3 errors:[\w\W]*Incorrect parameter number") as e: + Script( + script={"root": {"start": {PRE_RESPONSE_PROCESSING: {"PRP": UserFunctionSamples.wrong_param_number}}}} + ) + assert e + + def test_response_param_types(self): + with pytest.raises(ValidationError, match=r"Found 3 errors:[\w\W]*Incorrect parameter annotation") as e: + Script( + script={"root": {"start": {PRE_RESPONSE_PROCESSING: {"PRP": UserFunctionSamples.wrong_param_types}}}} + ) + assert e + + def test_response_return_type(self): + with pytest.raises(ValidationError, match=r"Found 1 error:[\w\W]*Incorrect return type annotation") as e: + Script( + script={"root": {"start": {PRE_RESPONSE_PROCESSING: {"PRP": UserFunctionSamples.wrong_return_type}}}} + ) + assert e + + def test_response_correct_script(self): + Script( + script={ + "root": { + "start": {PRE_RESPONSE_PROCESSING: {"PRP": UserFunctionSamples.correct_pre_response_processor}} + } + } + ) + + def test_transition_param_number(self): + with pytest.raises(ValidationError, match=r"Found 3 errors:[\w\W]*Incorrect parameter number") as e: + Script( + script={ + "root": {"start": {PRE_TRANSITIONS_PROCESSING: {"PTP": UserFunctionSamples.wrong_param_number}}} + } + ) + assert e + + def test_transition_param_types(self): + with pytest.raises(ValidationError, match=r"Found 3 errors:[\w\W]*Incorrect parameter annotation") as e: + Script( + script={"root": {"start": {PRE_TRANSITIONS_PROCESSING: {"PTP": UserFunctionSamples.wrong_param_types}}}} + ) + assert e + + def test_transition_return_type(self): + with pytest.raises(ValidationError, match=r"Found 1 error:[\w\W]*Incorrect return type annotation") as e: + Script( + script={"root": {"start": {PRE_TRANSITIONS_PROCESSING: {"PTP": UserFunctionSamples.wrong_return_type}}}} + ) + assert e + + def test_transition_correct_script(self): + Script( + script={ + "root": { + "start": {PRE_TRANSITIONS_PROCESSING: {"PTP": UserFunctionSamples.correct_pre_transition_processor}} + } + } + ) diff --git a/tests/stats/test_defaults.py b/tests/stats/test_defaults.py index bd4982eaf..ff2e0265b 100644 --- a/tests/stats/test_defaults.py +++ b/tests/stats/test_defaults.py @@ -21,9 +21,7 @@ ], ) async def test_get_current_label(context: Context, expected: set): - pipeline = Pipeline.from_script( - {"greeting_flow": {"start_node": {}}}, ("greeting_flow", "start_node"), validation_stage=False - ) + pipeline = Pipeline.from_script({"greeting_flow": {"start_node": {}}}, ("greeting_flow", "start_node")) runtime_info = ExtraHandlerRuntimeInfo( func=lambda x: x, stage="BEFORE", diff --git a/tutorials/script/core/4_transitions.py b/tutorials/script/core/4_transitions.py index 123d226da..250cd0d23 100644 --- a/tutorials/script/core/4_transitions.py +++ b/tutorials/script/core/4_transitions.py @@ -19,7 +19,7 @@ # %% import re -from dff.script import TRANSITIONS, RESPONSE, Context, NodeLabel3Type, Message +from dff.script import TRANSITIONS, RESPONSE, Context, ConstLabel, Message import dff.script.conditions as cnd import dff.script.labels as lbl from dff.pipeline import Pipeline @@ -33,21 +33,34 @@ """ Let's define the functions with a special type of return value: - NodeLabel3Type == tuple[str, str, float] + ConstLabel == Flow Name; Node Name; Priority -which means that transition returns a `tuple` -with flow name, node name and priority. +These functions return Labels that +determine destination and priority of a specific transition. + +Labels consist of: + +1. Flow name of the destination node + (optional; defaults to flow name of the current node). +2. Node name of the destination node + (required). +3. Priority of the transition (more on that later) + (optional; defaults to pipeline's + [label_priority](%doclink(api,pipeline.pipeline.pipeline))). + +An example of omitting optional arguments is shown in the body of the +`greeting_flow_n2_transition` function: """ # %% -def greeting_flow_n2_transition(_: Context, __: Pipeline) -> NodeLabel3Type: - return ("greeting_flow", "node2", 1.0) +def greeting_flow_n2_transition(_: Context, __: Pipeline) -> ConstLabel: + return "greeting_flow", "node2" -def high_priority_node_transition(flow_label, label): - def transition(_: Context, __: Pipeline) -> NodeLabel3Type: - return (flow_label, label, 2.0) +def high_priority_node_transition(flow_name, node_name): + def transition(_: Context, __: Pipeline) -> ConstLabel: + return flow_name, node_name, 2.0 return transition @@ -66,22 +79,22 @@ def transition(_: Context, __: Pipeline) -> NodeLabel3Type: offers the following methods: * `lbl.repeat()` returns transition handler - which returns `NodeLabelType` to the last node, + which returns `ConstLabel` to the last node, * `lbl.previous()` returns transition handler - which returns `NodeLabelType` to the previous node, + which returns `ConstLabel` to the previous node, * `lbl.to_start()` returns transition handler - which returns `NodeLabelType` to the start node, + which returns `ConstLabel` to the start node, * `lbl.to_fallback()` returns transition - handler which returns `NodeLabelType` to the fallback node, + handler which returns `ConstLabel` to the fallback node, * `lbl.forward()` returns transition handler - which returns `NodeLabelType` to the forward node, + which returns `ConstLabel` to the forward node, * `lbl.backward()` returns transition handler - which returns `NodeLabelType` to the backward node. + which returns `ConstLabel` to the backward node. There are three flows here: `global_flow`, `greeting_flow`, `music_flow`. """ diff --git a/tutorials/script/core/8_misc.py b/tutorials/script/core/8_misc.py index c0ec7310f..6379fede4 100644 --- a/tutorials/script/core/8_misc.py +++ b/tutorials/script/core/8_misc.py @@ -34,12 +34,11 @@ # %% def custom_response(ctx: Context, _: Pipeline) -> Message: - if ctx.validation: - return Message() current_node = ctx.current_node + current_misc = current_node.misc if current_node is not None else None return Message( text=f"ctx.last_label={ctx.last_label}: " - f"current_node.misc={current_node.misc}" + f"current_node.misc={current_misc}" ) diff --git a/tutorials/utils/1_cache.py b/tutorials/utils/1_cache.py index 871c9a939..bf1142a9f 100644 --- a/tutorials/utils/1_cache.py +++ b/tutorials/utils/1_cache.py @@ -47,9 +47,7 @@ def cached_response(_): return external_data["counter"] -def response(ctx: Context, _, *__, **___) -> Message: - if ctx.validation: - return Message() +def response(_: Context, __: Pipeline) -> Message: return Message( text=f"{cached_response(1)}-{cached_response(2)}-" f"{cached_response(1)}-{cached_response(2)}" diff --git a/tutorials/utils/2_lru_cache.py b/tutorials/utils/2_lru_cache.py index 40e59715f..faca106d7 100644 --- a/tutorials/utils/2_lru_cache.py +++ b/tutorials/utils/2_lru_cache.py @@ -46,9 +46,7 @@ def cached_response(_): return external_data["counter"] -def response(ctx: Context, _, *__, **___) -> Message: - if ctx.validation: - return Message() +def response(_: Context, __: Pipeline) -> Message: return Message( text=f"{cached_response(1)}-{cached_response(2)}-{cached_response(3)}-" f"{cached_response(2)}-{cached_response(1)}" From 7d4056576f4771b6fd75175ae86c37fdd6036019 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 23:03:09 +0000 Subject: [PATCH 12/31] build(deps): bump the deps group with 12 updates (#350) --- poetry.lock | 361 ++++++++++++++++++++++++++-------------------------- 1 file changed, 179 insertions(+), 182 deletions(-) diff --git a/poetry.lock b/poetry.lock index cb8ba42a1..9a336e4ea 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "accessible-pygments" @@ -185,13 +185,13 @@ files = [ [[package]] name = "altair" -version = "5.2.0" +version = "5.3.0" description = "Vega-Altair: A declarative statistical visualization library for Python." optional = false python-versions = ">=3.8" files = [ - {file = "altair-5.2.0-py3-none-any.whl", hash = "sha256:8c4888ad11db7c39f3f17aa7f4ea985775da389d79ac30a6c22856ab238df399"}, - {file = "altair-5.2.0.tar.gz", hash = "sha256:2ad7f0c8010ebbc46319cc30febfb8e59ccf84969a201541c207bc3a4fa6cf81"}, + {file = "altair-5.3.0-py3-none-any.whl", hash = "sha256:7084a1dab4d83c5e7e5246b92dc1b4451a6c68fd057f3716ee9d315c8980e59a"}, + {file = "altair-5.3.0.tar.gz", hash = "sha256:5a268b1a0983b23d8f9129f819f956174aa7aea2719ed55a52eba9979b9f6675"}, ] [package.dependencies] @@ -204,7 +204,8 @@ toolz = "*" typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] -dev = ["anywidget", "geopandas", "hatch", "ipython", "m2r", "mypy", "pandas-stubs", "pyarrow (>=11)", "pytest", "pytest-cov", "ruff (>=0.1.3)", "types-jsonschema", "types-setuptools", "vega-datasets", "vegafusion[embed] (>=1.4.0)", "vl-convert-python (>=1.1.0)"] +all = ["altair-tiles (>=0.3.0)", "anywidget (>=0.9.0)", "pyarrow (>=11)", "vega-datasets (>=0.9.0)", "vegafusion[embed] (>=1.6.6)", "vl-convert-python (>=1.3.0)"] +dev = ["geopandas", "hatch", "ipython", "m2r", "mypy", "pandas-stubs", "pytest", "pytest-cov", "ruff (>=0.3.0)", "types-jsonschema", "types-setuptools"] doc = ["docutils", "jinja2", "myst-parser", "numpydoc", "pillow (>=9,<10)", "pydata-sphinx-theme (>=0.14.1)", "scipy", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinxext-altair"] [[package]] @@ -593,33 +594,33 @@ lxml = ["lxml"] [[package]] name = "black" -version = "24.3.0" +version = "24.4.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395"}, - {file = "black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995"}, - {file = "black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7"}, - {file = "black-24.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0"}, - {file = "black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9"}, - {file = "black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597"}, - {file = "black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d"}, - {file = "black-24.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5"}, - {file = "black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f"}, - {file = "black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11"}, - {file = "black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4"}, - {file = "black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5"}, - {file = "black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837"}, - {file = "black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd"}, - {file = "black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213"}, - {file = "black-24.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959"}, - {file = "black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb"}, - {file = "black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7"}, - {file = "black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7"}, - {file = "black-24.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f"}, - {file = "black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93"}, - {file = "black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f"}, + {file = "black-24.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6ad001a9ddd9b8dfd1b434d566be39b1cd502802c8d38bbb1ba612afda2ef436"}, + {file = "black-24.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3a3a092b8b756c643fe45f4624dbd5a389f770a4ac294cf4d0fce6af86addaf"}, + {file = "black-24.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dae79397f367ac8d7adb6c779813328f6d690943f64b32983e896bcccd18cbad"}, + {file = "black-24.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:71d998b73c957444fb7c52096c3843875f4b6b47a54972598741fe9a7f737fcb"}, + {file = "black-24.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8e5537f456a22cf5cfcb2707803431d2feeb82ab3748ade280d6ccd0b40ed2e8"}, + {file = "black-24.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64e60a7edd71fd542a10a9643bf369bfd2644de95ec71e86790b063aa02ff745"}, + {file = "black-24.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cd5b4f76056cecce3e69b0d4c228326d2595f506797f40b9233424e2524c070"}, + {file = "black-24.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:64578cf99b6b46a6301bc28bdb89f9d6f9b592b1c5837818a177c98525dbe397"}, + {file = "black-24.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f95cece33329dc4aa3b0e1a771c41075812e46cf3d6e3f1dfe3d91ff09826ed2"}, + {file = "black-24.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4396ca365a4310beef84d446ca5016f671b10f07abdba3e4e4304218d2c71d33"}, + {file = "black-24.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44d99dfdf37a2a00a6f7a8dcbd19edf361d056ee51093b2445de7ca09adac965"}, + {file = "black-24.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:21f9407063ec71c5580b8ad975653c66508d6a9f57bd008bb8691d273705adcd"}, + {file = "black-24.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:652e55bb722ca026299eb74e53880ee2315b181dfdd44dca98e43448620ddec1"}, + {file = "black-24.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7f2966b9b2b3b7104fca9d75b2ee856fe3fdd7ed9e47c753a4bb1a675f2caab8"}, + {file = "black-24.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bb9ca06e556a09f7f7177bc7cb604e5ed2d2df1e9119e4f7d2f1f7071c32e5d"}, + {file = "black-24.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4e71cdebdc8efeb6deaf5f2deb28325f8614d48426bed118ecc2dcaefb9ebf3"}, + {file = "black-24.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6644f97a7ef6f401a150cca551a1ff97e03c25d8519ee0bbc9b0058772882665"}, + {file = "black-24.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:75a2d0b4f5eb81f7eebc31f788f9830a6ce10a68c91fbe0fade34fff7a2836e6"}, + {file = "black-24.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb949f56a63c5e134dfdca12091e98ffb5fd446293ebae123d10fc1abad00b9e"}, + {file = "black-24.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:7852b05d02b5b9a8c893ab95863ef8986e4dda29af80bbbda94d7aee1abf8702"}, + {file = "black-24.4.0-py3-none-any.whl", hash = "sha256:74eb9b5420e26b42c00a3ff470dc0cd144b80a766128b1771d07643165e08d0e"}, + {file = "black-24.4.0.tar.gz", hash = "sha256:f07b69fda20578367eaebbd670ff8fc653ab181e1ff95d84497f9fa20e7d0641"}, ] [package.dependencies] @@ -2105,13 +2106,13 @@ tests = ["freezegun", "pytest", "pytest-cov"] [[package]] name = "idna" -version = "3.6" +version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] @@ -2775,13 +2776,13 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-ena [[package]] name = "locust" -version = "2.24.0" +version = "2.25.0" description = "Developer friendly load testing framework" optional = false python-versions = ">=3.8" files = [ - {file = "locust-2.24.0-py3-none-any.whl", hash = "sha256:1b6b878b4fd0108fec956120815e69775d2616c8f4d1e9f365c222a7a5c17d9a"}, - {file = "locust-2.24.0.tar.gz", hash = "sha256:6cffa378d995244a7472af6be1d6139331f19aee44e907deee73e0281252804d"}, + {file = "locust-2.25.0-py3-none-any.whl", hash = "sha256:35ee14d0a2b91d0d644150d0b628ce4569b0e1fec1c33c55040fa26cc693d085"}, + {file = "locust-2.25.0.tar.gz", hash = "sha256:45bc88b3097f0346a46514f99ebf8d8a86f07325366da0b9dc2c3f207499dbc6"}, ] [package.dependencies] @@ -2988,13 +2989,13 @@ files = [ [[package]] name = "motor" -version = "3.3.2" +version = "3.4.0" description = "Non-blocking MongoDB driver for Tornado or asyncio" optional = true python-versions = ">=3.7" files = [ - {file = "motor-3.3.2-py3-none-any.whl", hash = "sha256:6fe7e6f0c4f430b9e030b9d22549b732f7c2226af3ab71ecc309e4a1b7d19953"}, - {file = "motor-3.3.2.tar.gz", hash = "sha256:d2fc38de15f1c8058f389c1a44a4d4105c0405c48c061cd492a654496f7bc26a"}, + {file = "motor-3.4.0-py3-none-any.whl", hash = "sha256:4b1e1a0cc5116ff73be2c080a72da078f2bb719b53bc7a6bb9e9a2f7dcd421ed"}, + {file = "motor-3.4.0.tar.gz", hash = "sha256:c89b4e4eb2e711345e91c7c9b122cb68cce0e5e869ed0387dd0acb10775e3131"}, ] [package.dependencies] @@ -3007,7 +3008,7 @@ gssapi = ["pymongo[gssapi] (>=4.5,<5)"] ocsp = ["pymongo[ocsp] (>=4.5,<5)"] snappy = ["pymongo[snappy] (>=4.5,<5)"] srv = ["pymongo[srv] (>=4.5,<5)"] -test = ["aiohttp (<3.8.6)", "mockupdb", "motor[encryption]", "pytest (>=7)", "tornado (>=5)"] +test = ["aiohttp (!=3.8.6)", "mockupdb", "motor[encryption]", "pytest (>=7)", "tornado (>=5)"] zstd = ["pymongo[zstd] (>=4.5,<5)"] [[package]] @@ -3437,57 +3438,57 @@ PyYAML = ">=5.1.0" [[package]] name = "opentelemetry-api" -version = "1.23.0" +version = "1.24.0" description = "OpenTelemetry Python API" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_api-1.23.0-py3-none-any.whl", hash = "sha256:cc03ea4025353048aadb9c64919099663664672ea1c6be6ddd8fee8e4cd5e774"}, - {file = "opentelemetry_api-1.23.0.tar.gz", hash = "sha256:14a766548c8dd2eb4dfc349739eb4c3893712a0daa996e5dbf945f9da665da9d"}, + {file = "opentelemetry_api-1.24.0-py3-none-any.whl", hash = "sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2"}, + {file = "opentelemetry_api-1.24.0.tar.gz", hash = "sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<7.0" +importlib-metadata = ">=6.0,<=7.0" [[package]] name = "opentelemetry-exporter-otlp" -version = "1.23.0" +version = "1.24.0" description = "OpenTelemetry Collector Exporters" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp-1.23.0-py3-none-any.whl", hash = "sha256:92371fdc8d7803465a45801fe30cd8c522ef355a385b0a1d5346d32f77511ea2"}, - {file = "opentelemetry_exporter_otlp-1.23.0.tar.gz", hash = "sha256:4af8798f9bc3bddb92fcbb5b4aa9d0e955d962aa1d9bceaab08891c355a9f907"}, + {file = "opentelemetry_exporter_otlp-1.24.0-py3-none-any.whl", hash = "sha256:1dfe2e4befe1f0efc193a896837740407669b2929233b406ac0a813151200cac"}, + {file = "opentelemetry_exporter_otlp-1.24.0.tar.gz", hash = "sha256:649c6e249e55cbdebe99ba2846e3851c04c9f328570328c35b3af9c094314b55"}, ] [package.dependencies] -opentelemetry-exporter-otlp-proto-grpc = "1.23.0" -opentelemetry-exporter-otlp-proto-http = "1.23.0" +opentelemetry-exporter-otlp-proto-grpc = "1.24.0" +opentelemetry-exporter-otlp-proto-http = "1.24.0" [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.23.0" +version = "1.24.0" description = "OpenTelemetry Protobuf encoding" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_common-1.23.0-py3-none-any.whl", hash = "sha256:2a9e7e9d5a8b026b572684b6b24dcdefcaa58613d5ce3d644130b0c373c056c1"}, - {file = "opentelemetry_exporter_otlp_proto_common-1.23.0.tar.gz", hash = "sha256:35e4ea909e7a0b24235bd0aaf17fba49676527feb1823b46565ff246d5a1ab18"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.24.0-py3-none-any.whl", hash = "sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.24.0.tar.gz", hash = "sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461"}, ] [package.dependencies] -opentelemetry-proto = "1.23.0" +opentelemetry-proto = "1.24.0" [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.23.0" +version = "1.24.0" description = "OpenTelemetry Collector Protobuf over gRPC Exporter" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_grpc-1.23.0-py3-none-any.whl", hash = "sha256:40f9e3e7761eb34f2a1001f4543028783ac26e2db27e420d5374f2cca0182dad"}, - {file = "opentelemetry_exporter_otlp_proto_grpc-1.23.0.tar.gz", hash = "sha256:aa1a012eea5342bfef51fcf3f7f22601dcb0f0984a07ffe6025b2fbb6d91a2a9"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.24.0-py3-none-any.whl", hash = "sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.24.0.tar.gz", hash = "sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa"}, ] [package.dependencies] @@ -3495,36 +3496,33 @@ deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" grpcio = ">=1.0.0,<2.0.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.23.0" -opentelemetry-proto = "1.23.0" -opentelemetry-sdk = ">=1.23.0,<1.24.0" +opentelemetry-exporter-otlp-proto-common = "1.24.0" +opentelemetry-proto = "1.24.0" +opentelemetry-sdk = ">=1.24.0,<1.25.0" [package.extras] test = ["pytest-grpc"] [[package]] name = "opentelemetry-exporter-otlp-proto-http" -version = "1.23.0" +version = "1.24.0" description = "OpenTelemetry Collector Protobuf over HTTP Exporter" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_http-1.23.0-py3-none-any.whl", hash = "sha256:ad853b58681df8efcb2cfc93be2b5fd86351c99ff4ab47dc917da384b8650d91"}, - {file = "opentelemetry_exporter_otlp_proto_http-1.23.0.tar.gz", hash = "sha256:088eac2320f4a604e2d9ff71aced71fdae601ac6457005fb0303d6bbbf44e6ca"}, + {file = "opentelemetry_exporter_otlp_proto_http-1.24.0-py3-none-any.whl", hash = "sha256:25af10e46fdf4cd3833175e42f4879a1255fc01655fe14c876183a2903949836"}, + {file = "opentelemetry_exporter_otlp_proto_http-1.24.0.tar.gz", hash = "sha256:704c066cc96f5131881b75c0eac286cd73fc735c490b054838b4513254bd7850"}, ] [package.dependencies] deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.23.0" -opentelemetry-proto = "1.23.0" -opentelemetry-sdk = ">=1.23.0,<1.24.0" +opentelemetry-exporter-otlp-proto-common = "1.24.0" +opentelemetry-proto = "1.24.0" +opentelemetry-sdk = ">=1.24.0,<1.25.0" requests = ">=2.7,<3.0" -[package.extras] -test = ["responses (>=0.22.0,<0.25)"] - [[package]] name = "opentelemetry-instrumentation" version = "0.44b0" @@ -3543,13 +3541,13 @@ wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-proto" -version = "1.23.0" +version = "1.24.0" description = "OpenTelemetry Python Proto" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_proto-1.23.0-py3-none-any.whl", hash = "sha256:4c017deca052cb287a6003b7c989ed8b47af65baeb5d57ebf93dde0793f78509"}, - {file = "opentelemetry_proto-1.23.0.tar.gz", hash = "sha256:e6aaf8b7ace8d021942d546161401b83eed90f9f2cc6f13275008cea730e4651"}, + {file = "opentelemetry_proto-1.24.0-py3-none-any.whl", hash = "sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce"}, + {file = "opentelemetry_proto-1.24.0.tar.gz", hash = "sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8"}, ] [package.dependencies] @@ -3557,29 +3555,29 @@ protobuf = ">=3.19,<5.0" [[package]] name = "opentelemetry-sdk" -version = "1.23.0" +version = "1.24.0" description = "OpenTelemetry Python SDK" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_sdk-1.23.0-py3-none-any.whl", hash = "sha256:a93c96990ac0f07c6d679e2f1015864ff7a4f5587122dd5af968034436efb1fd"}, - {file = "opentelemetry_sdk-1.23.0.tar.gz", hash = "sha256:9ddf60195837b59e72fd2033d6a47e2b59a0f74f0ec37d89387d89e3da8cab7f"}, + {file = "opentelemetry_sdk-1.24.0-py3-none-any.whl", hash = "sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59"}, + {file = "opentelemetry_sdk-1.24.0.tar.gz", hash = "sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5"}, ] [package.dependencies] -opentelemetry-api = "1.23.0" -opentelemetry-semantic-conventions = "0.44b0" +opentelemetry-api = "1.24.0" +opentelemetry-semantic-conventions = "0.45b0" typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.44b0" +version = "0.45b0" description = "OpenTelemetry Semantic Conventions" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_semantic_conventions-0.44b0-py3-none-any.whl", hash = "sha256:7c434546c9cbd797ab980cc88bf9ff3f4a5a28f941117cad21694e43d5d92019"}, - {file = "opentelemetry_semantic_conventions-0.44b0.tar.gz", hash = "sha256:2e997cb28cd4ca81a25a9a43365f593d0c2b76be0685015349a89abdf1aa4ffa"}, + {file = "opentelemetry_semantic_conventions-0.45b0-py3-none-any.whl", hash = "sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864"}, + {file = "opentelemetry_semantic_conventions-0.45b0.tar.gz", hash = "sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118"}, ] [[package]] @@ -4204,18 +4202,18 @@ files = [ [[package]] name = "pydantic" -version = "2.6.3" +version = "2.7.0" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.6.3-py3-none-any.whl", hash = "sha256:72c6034df47f46ccdf81869fddb81aade68056003900a8724a4f160700016a2a"}, - {file = "pydantic-2.6.3.tar.gz", hash = "sha256:e07805c4c7f5c6826e33a1d4c9d47950d7eaf34868e2690f8594d2e30241f11f"}, + {file = "pydantic-2.7.0-py3-none-any.whl", hash = "sha256:9dee74a271705f14f9a1567671d144a851c675b072736f0a7b2608fd9e495352"}, + {file = "pydantic-2.7.0.tar.gz", hash = "sha256:b5ecdd42262ca2462e2624793551e80911a1e989f462910bb81aef974b4bb383"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.16.3" +pydantic-core = "2.18.1" typing-extensions = ">=4.6.1" [package.extras] @@ -4223,90 +4221,90 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.16.3" -description = "" +version = "2.18.1" +description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, - {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, - {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, - {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, - {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, - {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, - {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, - {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, - {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, - {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, - {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, - {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, - {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, - {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, - {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, - {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, - {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, - {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, - {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, - {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, - {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, - {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, - {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, - {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, - {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, - {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, - {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, - {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, - {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, - {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, - {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, - {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, - {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, + {file = "pydantic_core-2.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ee9cf33e7fe14243f5ca6977658eb7d1042caaa66847daacbd2117adb258b226"}, + {file = "pydantic_core-2.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b7bbb97d82659ac8b37450c60ff2e9f97e4eb0f8a8a3645a5568b9334b08b50"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df4249b579e75094f7e9bb4bd28231acf55e308bf686b952f43100a5a0be394c"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d0491006a6ad20507aec2be72e7831a42efc93193d2402018007ff827dc62926"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ae80f72bb7a3e397ab37b53a2b49c62cc5496412e71bc4f1277620a7ce3f52b"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58aca931bef83217fca7a390e0486ae327c4af9c3e941adb75f8772f8eeb03a1"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be91ad664fc9245404a789d60cba1e91c26b1454ba136d2a1bf0c2ac0c0505a"}, + {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:667880321e916a8920ef49f5d50e7983792cf59f3b6079f3c9dac2b88a311d17"}, + {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f7054fdc556f5421f01e39cbb767d5ec5c1139ea98c3e5b350e02e62201740c7"}, + {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:030e4f9516f9947f38179249778709a460a3adb516bf39b5eb9066fcfe43d0e6"}, + {file = "pydantic_core-2.18.1-cp310-none-win32.whl", hash = "sha256:2e91711e36e229978d92642bfc3546333a9127ecebb3f2761372e096395fc649"}, + {file = "pydantic_core-2.18.1-cp310-none-win_amd64.whl", hash = "sha256:9a29726f91c6cb390b3c2338f0df5cd3e216ad7a938762d11c994bb37552edb0"}, + {file = "pydantic_core-2.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9ece8a49696669d483d206b4474c367852c44815fca23ac4e48b72b339807f80"}, + {file = "pydantic_core-2.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a5d83efc109ceddb99abd2c1316298ced2adb4570410defe766851a804fcd5b"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f7973c381283783cd1043a8c8f61ea5ce7a3a58b0369f0ee0ee975eaf2f2a1b"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54c7375c62190a7845091f521add19b0f026bcf6ae674bdb89f296972272e86d"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd63cec4e26e790b70544ae5cc48d11b515b09e05fdd5eff12e3195f54b8a586"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:561cf62c8a3498406495cfc49eee086ed2bb186d08bcc65812b75fda42c38294"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68717c38a68e37af87c4da20e08f3e27d7e4212e99e96c3d875fbf3f4812abfc"}, + {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d5728e93d28a3c63ee513d9ffbac9c5989de8c76e049dbcb5bfe4b923a9739d"}, + {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f0f17814c505f07806e22b28856c59ac80cee7dd0fbb152aed273e116378f519"}, + {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d816f44a51ba5175394bc6c7879ca0bd2be560b2c9e9f3411ef3a4cbe644c2e9"}, + {file = "pydantic_core-2.18.1-cp311-none-win32.whl", hash = "sha256:09f03dfc0ef8c22622eaa8608caa4a1e189cfb83ce847045eca34f690895eccb"}, + {file = "pydantic_core-2.18.1-cp311-none-win_amd64.whl", hash = "sha256:27f1009dc292f3b7ca77feb3571c537276b9aad5dd4efb471ac88a8bd09024e9"}, + {file = "pydantic_core-2.18.1-cp311-none-win_arm64.whl", hash = "sha256:48dd883db92e92519201f2b01cafa881e5f7125666141a49ffba8b9facc072b0"}, + {file = "pydantic_core-2.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b6b0e4912030c6f28bcb72b9ebe4989d6dc2eebcd2a9cdc35fefc38052dd4fe8"}, + {file = "pydantic_core-2.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3202a429fe825b699c57892d4371c74cc3456d8d71b7f35d6028c96dfecad31"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3982b0a32d0a88b3907e4b0dc36809fda477f0757c59a505d4e9b455f384b8b"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25595ac311f20e5324d1941909b0d12933f1fd2171075fcff763e90f43e92a0d"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14fe73881cf8e4cbdaded8ca0aa671635b597e42447fec7060d0868b52d074e6"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca976884ce34070799e4dfc6fbd68cb1d181db1eefe4a3a94798ddfb34b8867f"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684d840d2c9ec5de9cb397fcb3f36d5ebb6fa0d94734f9886032dd796c1ead06"}, + {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:54764c083bbe0264f0f746cefcded6cb08fbbaaf1ad1d78fb8a4c30cff999a90"}, + {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:201713f2f462e5c015b343e86e68bd8a530a4f76609b33d8f0ec65d2b921712a"}, + {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fd1a9edb9dd9d79fbeac1ea1f9a8dd527a6113b18d2e9bcc0d541d308dae639b"}, + {file = "pydantic_core-2.18.1-cp312-none-win32.whl", hash = "sha256:d5e6b7155b8197b329dc787356cfd2684c9d6a6b1a197f6bbf45f5555a98d411"}, + {file = "pydantic_core-2.18.1-cp312-none-win_amd64.whl", hash = "sha256:9376d83d686ec62e8b19c0ac3bf8d28d8a5981d0df290196fb6ef24d8a26f0d6"}, + {file = "pydantic_core-2.18.1-cp312-none-win_arm64.whl", hash = "sha256:c562b49c96906b4029b5685075fe1ebd3b5cc2601dfa0b9e16c2c09d6cbce048"}, + {file = "pydantic_core-2.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:3e352f0191d99fe617371096845070dee295444979efb8f27ad941227de6ad09"}, + {file = "pydantic_core-2.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0295d52b012cbe0d3059b1dba99159c3be55e632aae1999ab74ae2bd86a33d7"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56823a92075780582d1ffd4489a2e61d56fd3ebb4b40b713d63f96dd92d28144"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd3f79e17b56741b5177bcc36307750d50ea0698df6aa82f69c7db32d968c1c2"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38a5024de321d672a132b1834a66eeb7931959c59964b777e8f32dbe9523f6b1"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ce426ee691319d4767748c8e0895cfc56593d725594e415f274059bcf3cb76"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2adaeea59849ec0939af5c5d476935f2bab4b7f0335b0110f0f069a41024278e"}, + {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9b6431559676a1079eac0f52d6d0721fb8e3c5ba43c37bc537c8c83724031feb"}, + {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:85233abb44bc18d16e72dc05bf13848a36f363f83757541f1a97db2f8d58cfd9"}, + {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:641a018af4fe48be57a2b3d7a1f0f5dbca07c1d00951d3d7463f0ac9dac66622"}, + {file = "pydantic_core-2.18.1-cp38-none-win32.whl", hash = "sha256:63d7523cd95d2fde0d28dc42968ac731b5bb1e516cc56b93a50ab293f4daeaad"}, + {file = "pydantic_core-2.18.1-cp38-none-win_amd64.whl", hash = "sha256:907a4d7720abfcb1c81619863efd47c8a85d26a257a2dbebdb87c3b847df0278"}, + {file = "pydantic_core-2.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:aad17e462f42ddbef5984d70c40bfc4146c322a2da79715932cd8976317054de"}, + {file = "pydantic_core-2.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:94b9769ba435b598b547c762184bcfc4783d0d4c7771b04a3b45775c3589ca44"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80e0e57cc704a52fb1b48f16d5b2c8818da087dbee6f98d9bf19546930dc64b5"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:76b86e24039c35280ceee6dce7e62945eb93a5175d43689ba98360ab31eebc4a"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a05db5013ec0ca4a32cc6433f53faa2a014ec364031408540ba858c2172bb0"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:250ae39445cb5475e483a36b1061af1bc233de3e9ad0f4f76a71b66231b07f88"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a32204489259786a923e02990249c65b0f17235073149d0033efcebe80095570"}, + {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6395a4435fa26519fd96fdccb77e9d00ddae9dd6c742309bd0b5610609ad7fb2"}, + {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2533ad2883f001efa72f3d0e733fb846710c3af6dcdd544fe5bf14fa5fe2d7db"}, + {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b560b72ed4816aee52783c66854d96157fd8175631f01ef58e894cc57c84f0f6"}, + {file = "pydantic_core-2.18.1-cp39-none-win32.whl", hash = "sha256:582cf2cead97c9e382a7f4d3b744cf0ef1a6e815e44d3aa81af3ad98762f5a9b"}, + {file = "pydantic_core-2.18.1-cp39-none-win_amd64.whl", hash = "sha256:ca71d501629d1fa50ea7fa3b08ba884fe10cefc559f5c6c8dfe9036c16e8ae89"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e178e5b66a06ec5bf51668ec0d4ac8cfb2bdcb553b2c207d58148340efd00143"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:72722ce529a76a4637a60be18bd789d8fb871e84472490ed7ddff62d5fed620d"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fe0c1ce5b129455e43f941f7a46f61f3d3861e571f2905d55cdbb8b5c6f5e2c"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4284c621f06a72ce2cb55f74ea3150113d926a6eb78ab38340c08f770eb9b4d"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a0c3e718f4e064efde68092d9d974e39572c14e56726ecfaeebbe6544521f47"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2027493cc44c23b598cfaf200936110433d9caa84e2c6cf487a83999638a96ac"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:76909849d1a6bffa5a07742294f3fa1d357dc917cb1fe7b470afbc3a7579d539"}, + {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ee7ccc7fb7e921d767f853b47814c3048c7de536663e82fbc37f5eb0d532224b"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ee2794111c188548a4547eccc73a6a8527fe2af6cf25e1a4ebda2fd01cdd2e60"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a139fe9f298dc097349fb4f28c8b81cc7a202dbfba66af0e14be5cfca4ef7ce5"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d074b07a10c391fc5bbdcb37b2f16f20fcd9e51e10d01652ab298c0d07908ee2"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c69567ddbac186e8c0aadc1f324a60a564cfe25e43ef2ce81bcc4b8c3abffbae"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:baf1c7b78cddb5af00971ad5294a4583188bda1495b13760d9f03c9483bb6203"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2684a94fdfd1b146ff10689c6e4e815f6a01141781c493b97342cdc5b06f4d5d"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:73c1bc8a86a5c9e8721a088df234265317692d0b5cd9e86e975ce3bc3db62a59"}, + {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e60defc3c15defb70bb38dd605ff7e0fae5f6c9c7cbfe0ad7868582cb7e844a6"}, + {file = "pydantic_core-2.18.1.tar.gz", hash = "sha256:de9d3e8717560eb05e28739d1b35e4eac2e458553a52a301e51352a7ffc86a35"}, ] [package.dependencies] @@ -4514,13 +4512,13 @@ tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} [[package]] name = "pytelegrambotapi" -version = "4.16.1" +version = "4.17.0" description = "Python Telegram bot api." optional = true python-versions = ">=3.8" files = [ - {file = "pytelegrambotapi-4.16.1-py3-none-any.whl", hash = "sha256:85451b4fa1a47d99318a50aef361d177d2eb580c5ea6429fadb071cfad17fb35"}, - {file = "pytelegrambotapi-4.16.1.tar.gz", hash = "sha256:7ecfdac60de4a4c254059fc0f1997ceeb5da72803ffe4f35544b3ec9e9629edb"}, + {file = "pytelegrambotapi-4.17.0-py3-none-any.whl", hash = "sha256:326b51fdaa4f5dcb1e12d326beb9d9aa1289ffb578110b17d5ea269971a39160"}, + {file = "pytelegrambotapi-4.17.0.tar.gz", hash = "sha256:8cfda15e64a12fe73b78545ccc7b59e035d7fb3e54da5722ddf756296f3b8159"}, ] [package.dependencies] @@ -5776,19 +5774,18 @@ sqlcipher = ["sqlcipher3_binary"] [[package]] name = "sqlparse" -version = "0.4.4" +version = "0.5.0" description = "A non-validating SQL parser." optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"}, - {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"}, + {file = "sqlparse-0.5.0-py3-none-any.whl", hash = "sha256:c204494cd97479d0e39f28c93d46c0b2d5959c7b9ab904762ea6c7af211c8663"}, + {file = "sqlparse-0.5.0.tar.gz", hash = "sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93"}, ] [package.extras] -dev = ["build", "flake8"] +dev = ["build", "hatch"] doc = ["sphinx"] -test = ["pytest", "pytest-cov"] [[package]] name = "stack-data" @@ -5829,13 +5826,13 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7 [[package]] name = "streamlit" -version = "1.32.2" +version = "1.33.0" description = "A faster way to build and share data apps" optional = false -python-versions = ">=3.8, !=3.9.7" +python-versions = "!=3.9.7,>=3.8" files = [ - {file = "streamlit-1.32.2-py2.py3-none-any.whl", hash = "sha256:a0b8044e76fec364b07be145f8b40dbd8d083e20ebbb189ceb1fa9423f3dedea"}, - {file = "streamlit-1.32.2.tar.gz", hash = "sha256:1258b9cbc3ff957bf7d09b1bfc85cedc308f1065b30748545295a9af8d5577ab"}, + {file = "streamlit-1.33.0-py2.py3-none-any.whl", hash = "sha256:bfacb5d1edefcf803c2040b051a21b4c81317a9865448e6767d0a0c6aae7edae"}, + {file = "streamlit-1.33.0.tar.gz", hash = "sha256:a8da8ff46f5b948c56d2dc7aca7a61cf8d995f4f21744cf82258ae75e63004ba"}, ] [package.dependencies] @@ -5845,7 +5842,7 @@ cachetools = ">=4.0,<6" click = ">=7.0,<9" gitpython = ">=3.0.7,<3.1.19 || >3.1.19,<4" numpy = ">=1.19.3,<2" -packaging = ">=16.8,<24" +packaging = ">=16.8,<25" pandas = ">=1.3.0,<3" pillow = ">=7.1.0,<11" protobuf = ">=3.20,<5" @@ -6104,13 +6101,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.10.0" +version = "4.11.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, - {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, + {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, + {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, ] [[package]] @@ -6653,13 +6650,13 @@ multidict = ">=4.0" [[package]] name = "ydb" -version = "3.8.0" +version = "3.10.0" description = "YDB Python SDK" optional = true python-versions = "*" files = [ - {file = "ydb-3.8.0-py2.py3-none-any.whl", hash = "sha256:29d94f4c6047c24440e11a326604f913f1cf3d909f175329e081ac37f90a9152"}, - {file = "ydb-3.8.0.tar.gz", hash = "sha256:d5bdbc7d069977de86d6ceac62602803696d6c911d685d99edc5a9988710aaf5"}, + {file = "ydb-3.10.0-py2.py3-none-any.whl", hash = "sha256:f62ef4789b1be19cf204cf60125c03a15b9e30d946337672ebd88b27091fb87f"}, + {file = "ydb-3.10.0.tar.gz", hash = "sha256:7d84d1d58539747f524c6741faf237e40c1ec39ade52b24cb095530b6c0301bf"}, ] [package.dependencies] From abb04807d71c54afe78e837edadbf9d0778e0d2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Apr 2024 15:24:43 +0300 Subject: [PATCH 13/31] build(deps): bump the deps group with 2 updates (#352) --- poetry.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9a336e4ea..ddb983aa3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -5477,22 +5477,22 @@ test = ["cython", "filelock", "html5lib", "pytest (>=4.6)"] [[package]] name = "sphinx-autodoc-typehints" -version = "2.0.0" +version = "2.0.1" description = "Type hints (PEP 484) support for the Sphinx autodoc extension" optional = false python-versions = ">=3.8" files = [ - {file = "sphinx_autodoc_typehints-2.0.0-py3-none-any.whl", hash = "sha256:12c0e161f6fe191c2cdfd8fa3caea271f5387d9fbc67ebcd6f4f1f24ce880993"}, - {file = "sphinx_autodoc_typehints-2.0.0.tar.gz", hash = "sha256:7f2cdac2e70fd9787926b6e9e541cd4ded1e838d2b46fda2a1bb0a75ec5b7f3a"}, + {file = "sphinx_autodoc_typehints-2.0.1-py3-none-any.whl", hash = "sha256:f73ae89b43a799e587e39266672c1075b2ef783aeb382d3ebed77c38a3fc0149"}, + {file = "sphinx_autodoc_typehints-2.0.1.tar.gz", hash = "sha256:60ed1e3b2c970acc0aa6e877be42d48029a9faec7378a17838716cacd8c10b12"}, ] [package.dependencies] sphinx = ">=7.1.2" [package.extras] -docs = ["furo (>=2023.9.10)"] +docs = ["furo (>=2024.1.29)"] numpy = ["nptyping (>=2.5)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "sphobjinv (>=2.3.1)", "typing-extensions (>=4.8)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.4.2)", "diff-cover (>=8.0.3)", "pytest (>=8.0.1)", "pytest-cov (>=4.1)", "sphobjinv (>=2.3.1)", "typing-extensions (>=4.9)"] [[package]] name = "sphinx-copybutton" @@ -6650,13 +6650,13 @@ multidict = ">=4.0" [[package]] name = "ydb" -version = "3.10.0" +version = "3.11.1" description = "YDB Python SDK" optional = true python-versions = "*" files = [ - {file = "ydb-3.10.0-py2.py3-none-any.whl", hash = "sha256:f62ef4789b1be19cf204cf60125c03a15b9e30d946337672ebd88b27091fb87f"}, - {file = "ydb-3.10.0.tar.gz", hash = "sha256:7d84d1d58539747f524c6741faf237e40c1ec39ade52b24cb095530b6c0301bf"}, + {file = "ydb-3.11.1-py2.py3-none-any.whl", hash = "sha256:d9c070ae99692a0f96abd2c21bde9fafbd5e2ebace7dc6a8d796078468c426d0"}, + {file = "ydb-3.11.1.tar.gz", hash = "sha256:eac092e6215c21d74e8db99bc89c1e984828894d7be74bd39f133f0f4069c80d"}, ] [package.dependencies] From 2e1aeb193dcc228466a3652528ed6392cdb515a8 Mon Sep 17 00:00:00 2001 From: Roman Zlobin Date: Tue, 7 May 2024 02:49:00 +0300 Subject: [PATCH 14/31] return venv to ignore files --- .dockerignore | 2 ++ .gitignore | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.dockerignore b/.dockerignore index 7f6151613..20720fea6 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,7 @@ *.DS_Store* *.egg-info/ dist/ +venv/ build/ docs/source/apiref docs/source/_misc @@ -21,6 +22,7 @@ GlobalUserTableAccessor* memory_debugging* opening_database* _globals.py +venv* .vscode .coverage .coverage.* diff --git a/.gitignore b/.gitignore index 7f6151613..20720fea6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.DS_Store* *.egg-info/ dist/ +venv/ build/ docs/source/apiref docs/source/_misc @@ -21,6 +22,7 @@ GlobalUserTableAccessor* memory_debugging* opening_database* _globals.py +venv* .vscode .coverage .coverage.* From 44fbd5a21a0d6d6386116c60b5e0ff66af66b379 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Jun 2024 14:38:54 +0000 Subject: [PATCH 15/31] build(deps): bump the deps group across 1 directory with 17 updates (#360) --- poetry.lock | 756 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 567 insertions(+), 189 deletions(-) diff --git a/poetry.lock b/poetry.lock index ddb983aa3..00b728981 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1074,63 +1074,63 @@ files = [ [[package]] name = "coverage" -version = "7.4.3" +version = "7.5.3" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8580b827d4746d47294c0e0b92854c85a92c2227927433998f0d3320ae8a71b6"}, - {file = "coverage-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:718187eeb9849fc6cc23e0d9b092bc2348821c5e1a901c9f8975df0bc785bfd4"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:767b35c3a246bcb55b8044fd3a43b8cd553dd1f9f2c1eeb87a302b1f8daa0524"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae7f19afe0cce50039e2c782bff379c7e347cba335429678450b8fe81c4ef96d"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba3a8aaed13770e970b3df46980cb068d1c24af1a1968b7818b69af8c4347efb"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ee866acc0861caebb4f2ab79f0b94dbfbdbfadc19f82e6e9c93930f74e11d7a0"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:506edb1dd49e13a2d4cac6a5173317b82a23c9d6e8df63efb4f0380de0fbccbc"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd6545d97c98a192c5ac995d21c894b581f1fd14cf389be90724d21808b657e2"}, - {file = "coverage-7.4.3-cp310-cp310-win32.whl", hash = "sha256:f6a09b360d67e589236a44f0c39218a8efba2593b6abdccc300a8862cffc2f94"}, - {file = "coverage-7.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:18d90523ce7553dd0b7e23cbb28865db23cddfd683a38fb224115f7826de78d0"}, - {file = "coverage-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbbe5e739d45a52f3200a771c6d2c7acf89eb2524890a4a3aa1a7fa0695d2a47"}, - {file = "coverage-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:489763b2d037b164846ebac0cbd368b8a4ca56385c4090807ff9fad817de4113"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:451f433ad901b3bb00184d83fd83d135fb682d780b38af7944c9faeecb1e0bfe"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcc66e222cf4c719fe7722a403888b1f5e1682d1679bd780e2b26c18bb648cdc"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ec74cfef2d985e145baae90d9b1b32f85e1741b04cd967aaf9cfa84c1334f3"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:abbbd8093c5229c72d4c2926afaee0e6e3140de69d5dcd918b2921f2f0c8baba"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:35eb581efdacf7b7422af677b92170da4ef34500467381e805944a3201df2079"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8249b1c7334be8f8c3abcaaa996e1e4927b0e5a23b65f5bf6cfe3180d8ca7840"}, - {file = "coverage-7.4.3-cp311-cp311-win32.whl", hash = "sha256:cf30900aa1ba595312ae41978b95e256e419d8a823af79ce670835409fc02ad3"}, - {file = "coverage-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:18c7320695c949de11a351742ee001849912fd57e62a706d83dfc1581897fa2e"}, - {file = "coverage-7.4.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b51bfc348925e92a9bd9b2e48dad13431b57011fd1038f08316e6bf1df107d10"}, - {file = "coverage-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d6cdecaedea1ea9e033d8adf6a0ab11107b49571bbb9737175444cea6eb72328"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b2eccb883368f9e972e216c7b4c7c06cabda925b5f06dde0650281cb7666a30"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c00cdc8fa4e50e1cc1f941a7f2e3e0f26cb2a1233c9696f26963ff58445bac7"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4a8dd3dcf4cbd3165737358e4d7dfbd9d59902ad11e3b15eebb6393b0446e"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:062b0a75d9261e2f9c6d071753f7eef0fc9caf3a2c82d36d76667ba7b6470003"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ebe7c9e67a2d15fa97b77ea6571ce5e1e1f6b0db71d1d5e96f8d2bf134303c1d"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c0a120238dd71c68484f02562f6d446d736adcc6ca0993712289b102705a9a3a"}, - {file = "coverage-7.4.3-cp312-cp312-win32.whl", hash = "sha256:37389611ba54fd6d278fde86eb2c013c8e50232e38f5c68235d09d0a3f8aa352"}, - {file = "coverage-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:d25b937a5d9ffa857d41be042b4238dd61db888533b53bc76dc082cb5a15e914"}, - {file = "coverage-7.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28ca2098939eabab044ad68850aac8f8db6bf0b29bc7f2887d05889b17346454"}, - {file = "coverage-7.4.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:280459f0a03cecbe8800786cdc23067a8fc64c0bd51dc614008d9c36e1659d7e"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c0cdedd3500e0511eac1517bf560149764b7d8e65cb800d8bf1c63ebf39edd2"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a9babb9466fe1da12417a4aed923e90124a534736de6201794a3aea9d98484e"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dec9de46a33cf2dd87a5254af095a409ea3bf952d85ad339751e7de6d962cde6"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:16bae383a9cc5abab9bb05c10a3e5a52e0a788325dc9ba8499e821885928968c"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2c854ce44e1ee31bda4e318af1dbcfc929026d12c5ed030095ad98197eeeaed0"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ce8c50520f57ec57aa21a63ea4f325c7b657386b3f02ccaedeccf9ebe27686e1"}, - {file = "coverage-7.4.3-cp38-cp38-win32.whl", hash = "sha256:708a3369dcf055c00ddeeaa2b20f0dd1ce664eeabde6623e516c5228b753654f"}, - {file = "coverage-7.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:1bf25fbca0c8d121a3e92a2a0555c7e5bc981aee5c3fdaf4bb7809f410f696b9"}, - {file = "coverage-7.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b253094dbe1b431d3a4ac2f053b6d7ede2664ac559705a704f621742e034f1f"}, - {file = "coverage-7.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77fbfc5720cceac9c200054b9fab50cb2a7d79660609200ab83f5db96162d20c"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6679060424faa9c11808598504c3ab472de4531c571ab2befa32f4971835788e"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4af154d617c875b52651dd8dd17a31270c495082f3d55f6128e7629658d63765"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8640f1fde5e1b8e3439fe482cdc2b0bb6c329f4bb161927c28d2e8879c6029ee"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:69b9f6f66c0af29642e73a520b6fed25ff9fd69a25975ebe6acb297234eda501"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0842571634f39016a6c03e9d4aba502be652a6e4455fadb73cd3a3a49173e38f"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a78ed23b08e8ab524551f52953a8a05d61c3a760781762aac49f8de6eede8c45"}, - {file = "coverage-7.4.3-cp39-cp39-win32.whl", hash = "sha256:c0524de3ff096e15fcbfe8f056fdb4ea0bf497d584454f344d59fce069d3e6e9"}, - {file = "coverage-7.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:0209a6369ccce576b43bb227dc8322d8ef9e323d089c6f3f26a597b09cb4d2aa"}, - {file = "coverage-7.4.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:7cbde573904625509a3f37b6fecea974e363460b556a627c60dc2f47e2fffa51"}, - {file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52"}, + {file = "coverage-7.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45"}, + {file = "coverage-7.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c"}, + {file = "coverage-7.5.3-cp310-cp310-win32.whl", hash = "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84"}, + {file = "coverage-7.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac"}, + {file = "coverage-7.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974"}, + {file = "coverage-7.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614"}, + {file = "coverage-7.5.3-cp311-cp311-win32.whl", hash = "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9"}, + {file = "coverage-7.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a"}, + {file = "coverage-7.5.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8"}, + {file = "coverage-7.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84"}, + {file = "coverage-7.5.3-cp312-cp312-win32.whl", hash = "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08"}, + {file = "coverage-7.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb"}, + {file = "coverage-7.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb"}, + {file = "coverage-7.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155"}, + {file = "coverage-7.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24"}, + {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98"}, + {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d"}, + {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d"}, + {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce"}, + {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0"}, + {file = "coverage-7.5.3-cp38-cp38-win32.whl", hash = "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485"}, + {file = "coverage-7.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56"}, + {file = "coverage-7.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85"}, + {file = "coverage-7.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31"}, + {file = "coverage-7.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d"}, + {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341"}, + {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7"}, + {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52"}, + {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303"}, + {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd"}, + {file = "coverage-7.5.3-cp39-cp39-win32.whl", hash = "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d"}, + {file = "coverage-7.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0"}, + {file = "coverage-7.5.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884"}, + {file = "coverage-7.5.3.tar.gz", hash = "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f"}, ] [package.dependencies] @@ -1289,7 +1289,7 @@ files = [ name = "dnspython" version = "2.6.1" description = "DNS toolkit" -optional = true +optional = false python-versions = ">=3.8" files = [ {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, @@ -1403,6 +1403,21 @@ https = ["urllib3 (>=1.24.1)"] paramiko = ["paramiko"] pgp = ["gpg"] +[[package]] +name = "email-validator" +version = "2.1.2" +description = "A robust email address syntax and deliverability validation library." +optional = false +python-versions = ">=3.8" +files = [ + {file = "email_validator-2.1.2-py3-none-any.whl", hash = "sha256:d89f6324e13b1e39889eab7f9ca2f91dc9aebb6fa50a6d8bd4329ab50f251115"}, + {file = "email_validator-2.1.2.tar.gz", hash = "sha256:14c0f3d343c4beda37400421b39fa411bbe33a75df20825df73ad53e06a9f04c"}, +] + +[package.dependencies] +dnspython = ">=2.0.0" +idna = ">=2.0.0" + [[package]] name = "exceptiongroup" version = "1.2.0" @@ -1447,22 +1462,47 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "fastapi" -version = "0.110.0" +version = "0.111.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.110.0-py3-none-any.whl", hash = "sha256:87a1f6fb632a218222c5984be540055346a8f5d8a68e8f6fb647b1dc9934de4b"}, - {file = "fastapi-0.110.0.tar.gz", hash = "sha256:266775f0dcc95af9d3ef39bad55cff525329a931d5fd51930aadd4f428bf7ff3"}, + {file = "fastapi-0.111.0-py3-none-any.whl", hash = "sha256:97ecbf994be0bcbdadedf88c3150252bed7b2087075ac99735403b1b76cc8fc0"}, + {file = "fastapi-0.111.0.tar.gz", hash = "sha256:b9db9dd147c91cb8b769f7183535773d8741dd46f9dc6676cd82eab510228cd7"}, ] [package.dependencies] +email_validator = ">=2.0.0" +fastapi-cli = ">=0.0.2" +httpx = ">=0.23.0" +jinja2 = ">=2.11.2" +orjson = ">=3.2.1" pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" -starlette = ">=0.36.3,<0.37.0" +python-multipart = ">=0.0.7" +starlette = ">=0.37.2,<0.38.0" typing-extensions = ">=4.8.0" +ujson = ">=4.0.1,<4.0.2 || >4.0.2,<4.1.0 || >4.1.0,<4.2.0 || >4.2.0,<4.3.0 || >4.3.0,<5.0.0 || >5.0.0,<5.1.0 || >5.1.0" +uvicorn = {version = ">=0.12.0", extras = ["standard"]} + +[package.extras] +all = ["email_validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] + +[[package]] +name = "fastapi-cli" +version = "0.0.4" +description = "Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fastapi_cli-0.0.4-py3-none-any.whl", hash = "sha256:a2552f3a7ae64058cdbb530be6fa6dbfc975dc165e4fa66d224c3d396e25e809"}, + {file = "fastapi_cli-0.0.4.tar.gz", hash = "sha256:e2e9ffaffc1f7767f488d6da34b6f5a377751c996f397902eb6abb99a67bde32"}, +] + +[package.dependencies] +typer = ">=0.12.3" [package.extras] -all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +standard = ["fastapi", "uvicorn[standard] (>=0.15.0)"] [[package]] name = "fastjsonschema" @@ -1496,18 +1536,18 @@ typing = ["typing-extensions (>=4.8)"] [[package]] name = "flake8" -version = "7.0.0" +version = "7.1.0" description = "the modular source code checker: pep8 pyflakes and co" optional = false python-versions = ">=3.8.1" files = [ - {file = "flake8-7.0.0-py2.py3-none-any.whl", hash = "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3"}, - {file = "flake8-7.0.0.tar.gz", hash = "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132"}, + {file = "flake8-7.1.0-py2.py3-none-any.whl", hash = "sha256:2e416edcc62471a64cea09353f4e7bdba32aeb079b6e360554c659a122b1bc6a"}, + {file = "flake8-7.1.0.tar.gz", hash = "sha256:48a07b626b55236e0fb4784ee69a465fbf59d79eec1f5b4785c3d3bc57d17aa5"}, ] [package.dependencies] mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.11.0,<2.12.0" +pycodestyle = ">=2.12.0,<2.13.0" pyflakes = ">=3.2.0,<3.3.0" [[package]] @@ -2066,6 +2106,54 @@ http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] trio = ["trio (>=0.22.0,<0.25.0)"] +[[package]] +name = "httptools" +version = "0.6.1" +description = "A collection of framework independent HTTP protocol utils." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f"}, + {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563"}, + {file = "httptools-0.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:639dc4f381a870c9ec860ce5c45921db50205a37cc3334e756269736ff0aac58"}, + {file = "httptools-0.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e57997ac7fb7ee43140cc03664de5f268813a481dff6245e0075925adc6aa185"}, + {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0ac5a0ae3d9f4fe004318d64b8a854edd85ab76cffbf7ef5e32920faef62f142"}, + {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3f30d3ce413088a98b9db71c60a6ada2001a08945cb42dd65a9a9fe228627658"}, + {file = "httptools-0.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:1ed99a373e327f0107cb513b61820102ee4f3675656a37a50083eda05dc9541b"}, + {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1"}, + {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0"}, + {file = "httptools-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc"}, + {file = "httptools-0.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2"}, + {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837"}, + {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d"}, + {file = "httptools-0.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3"}, + {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0"}, + {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2"}, + {file = "httptools-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90"}, + {file = "httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503"}, + {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84"}, + {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb"}, + {file = "httptools-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949"}, + {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8e216a038d2d52ea13fdd9b9c9c7459fb80d78302b257828285eca1c773b99b3"}, + {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3e802e0b2378ade99cd666b5bffb8b2a7cc8f3d28988685dc300469ea8dd86cb"}, + {file = "httptools-0.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd3e488b447046e386a30f07af05f9b38d3d368d1f7b4d8f7e10af85393db97"}, + {file = "httptools-0.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe467eb086d80217b7584e61313ebadc8d187a4d95bb62031b7bab4b205c3ba3"}, + {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3c3b214ce057c54675b00108ac42bacf2ab8f85c58e3f324a4e963bbc46424f4"}, + {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8ae5b97f690badd2ca27cbf668494ee1b6d34cf1c464271ef7bfa9ca6b83ffaf"}, + {file = "httptools-0.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:405784577ba6540fa7d6ff49e37daf104e04f4b4ff2d1ac0469eaa6a20fde084"}, + {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:95fb92dd3649f9cb139e9c56604cc2d7c7bf0fc2e7c8d7fbd58f96e35eddd2a3"}, + {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dcbab042cc3ef272adc11220517278519adf8f53fd3056d0e68f0a6f891ba94e"}, + {file = "httptools-0.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cf2372e98406efb42e93bfe10f2948e467edfd792b015f1b4ecd897903d3e8d"}, + {file = "httptools-0.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:678fcbae74477a17d103b7cae78b74800d795d702083867ce160fc202104d0da"}, + {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e0b281cf5a125c35f7f6722b65d8542d2e57331be573e9e88bc8b0115c4a7a81"}, + {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:95658c342529bba4e1d3d2b1a874db16c7cca435e8827422154c9da76ac4e13a"}, + {file = "httptools-0.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ebaec1bf683e4bf5e9fbb49b8cc36da482033596a415b3e4ebab5a4c0d7ec5e"}, + {file = "httptools-0.6.1.tar.gz", hash = "sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a"}, +] + +[package.extras] +test = ["Cython (>=0.29.24,<0.30.0)"] + [[package]] name = "httpx" version = "0.27.0" @@ -2413,13 +2501,13 @@ files = [ [[package]] name = "jsonschema" -version = "4.21.1" +version = "4.22.0" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.8" files = [ - {file = "jsonschema-4.21.1-py3-none-any.whl", hash = "sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f"}, - {file = "jsonschema-4.21.1.tar.gz", hash = "sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5"}, + {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"}, + {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"}, ] [package.dependencies] @@ -3177,38 +3265,38 @@ files = [ [[package]] name = "mypy" -version = "1.9.0" +version = "1.10.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8a67616990062232ee4c3952f41c779afac41405806042a8126fe96e098419f"}, - {file = "mypy-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d357423fa57a489e8c47b7c85dfb96698caba13d66e086b412298a1a0ea3b0ed"}, - {file = "mypy-1.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49c87c15aed320de9b438ae7b00c1ac91cd393c1b854c2ce538e2a72d55df150"}, - {file = "mypy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:48533cdd345c3c2e5ef48ba3b0d3880b257b423e7995dada04248725c6f77374"}, - {file = "mypy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:4d3dbd346cfec7cb98e6cbb6e0f3c23618af826316188d587d1c1bc34f0ede03"}, - {file = "mypy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:653265f9a2784db65bfca694d1edd23093ce49740b2244cde583aeb134c008f3"}, - {file = "mypy-1.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a3c007ff3ee90f69cf0a15cbcdf0995749569b86b6d2f327af01fd1b8aee9dc"}, - {file = "mypy-1.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2418488264eb41f69cc64a69a745fad4a8f86649af4b1041a4c64ee61fc61129"}, - {file = "mypy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:68edad3dc7d70f2f17ae4c6c1b9471a56138ca22722487eebacfd1eb5321d612"}, - {file = "mypy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:85ca5fcc24f0b4aeedc1d02f93707bccc04733f21d41c88334c5482219b1ccb3"}, - {file = "mypy-1.9.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aceb1db093b04db5cd390821464504111b8ec3e351eb85afd1433490163d60cd"}, - {file = "mypy-1.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0235391f1c6f6ce487b23b9dbd1327b4ec33bb93934aa986efe8a9563d9349e6"}, - {file = "mypy-1.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4d5ddc13421ba3e2e082a6c2d74c2ddb3979c39b582dacd53dd5d9431237185"}, - {file = "mypy-1.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:190da1ee69b427d7efa8aa0d5e5ccd67a4fb04038c380237a0d96829cb157913"}, - {file = "mypy-1.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:fe28657de3bfec596bbeef01cb219833ad9d38dd5393fc649f4b366840baefe6"}, - {file = "mypy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e54396d70be04b34f31d2edf3362c1edd023246c82f1730bbf8768c28db5361b"}, - {file = "mypy-1.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5e6061f44f2313b94f920e91b204ec600982961e07a17e0f6cd83371cb23f5c2"}, - {file = "mypy-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a10926e5473c5fc3da8abb04119a1f5811a236dc3a38d92015cb1e6ba4cb9e"}, - {file = "mypy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b685154e22e4e9199fc95f298661deea28aaede5ae16ccc8cbb1045e716b3e04"}, - {file = "mypy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:5d741d3fc7c4da608764073089e5f58ef6352bedc223ff58f2f038c2c4698a89"}, - {file = "mypy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:587ce887f75dd9700252a3abbc9c97bbe165a4a630597845c61279cf32dfbf02"}, - {file = "mypy-1.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f88566144752999351725ac623471661c9d1cd8caa0134ff98cceeea181789f4"}, - {file = "mypy-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61758fabd58ce4b0720ae1e2fea5cfd4431591d6d590b197775329264f86311d"}, - {file = "mypy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e49499be624dead83927e70c756970a0bc8240e9f769389cdf5714b0784ca6bf"}, - {file = "mypy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:571741dc4194b4f82d344b15e8837e8c5fcc462d66d076748142327626a1b6e9"}, - {file = "mypy-1.9.0-py3-none-any.whl", hash = "sha256:a260627a570559181a9ea5de61ac6297aa5af202f06fd7ab093ce74e7181e43e"}, - {file = "mypy-1.9.0.tar.gz", hash = "sha256:3cc5da0127e6a478cddd906068496a97a7618a21ce9b54bde5bf7e539c7af974"}, + {file = "mypy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2"}, + {file = "mypy-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99"}, + {file = "mypy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2"}, + {file = "mypy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9"}, + {file = "mypy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051"}, + {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, + {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, + {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, + {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, + {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, + {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, + {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, + {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, + {file = "mypy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9fd50226364cd2737351c79807775136b0abe084433b55b2e29181a4c3c878c0"}, + {file = "mypy-1.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f90cff89eea89273727d8783fef5d4a934be2fdca11b47def50cf5d311aff727"}, + {file = "mypy-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcfc70599efde5c67862a07a1aaf50e55bce629ace26bb19dc17cece5dd31ca4"}, + {file = "mypy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:075cbf81f3e134eadaf247de187bd604748171d6b79736fa9b6c9685b4083061"}, + {file = "mypy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:3f298531bca95ff615b6e9f2fc0333aae27fa48052903a0ac90215021cdcfa4f"}, + {file = "mypy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976"}, + {file = "mypy-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec"}, + {file = "mypy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821"}, + {file = "mypy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746"}, + {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"}, + {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, + {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, ] [package.dependencies] @@ -3438,57 +3526,57 @@ PyYAML = ">=5.1.0" [[package]] name = "opentelemetry-api" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Python API" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_api-1.24.0-py3-none-any.whl", hash = "sha256:0f2c363d98d10d1ce93330015ca7fd3a65f60be64e05e30f557c61de52c80ca2"}, - {file = "opentelemetry_api-1.24.0.tar.gz", hash = "sha256:42719f10ce7b5a9a73b10a4baf620574fb8ad495a9cbe5c18d76b75d8689c67e"}, + {file = "opentelemetry_api-1.25.0-py3-none-any.whl", hash = "sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737"}, + {file = "opentelemetry_api-1.25.0.tar.gz", hash = "sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<=7.0" +importlib-metadata = ">=6.0,<=7.1" [[package]] name = "opentelemetry-exporter-otlp" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Collector Exporters" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp-1.24.0-py3-none-any.whl", hash = "sha256:1dfe2e4befe1f0efc193a896837740407669b2929233b406ac0a813151200cac"}, - {file = "opentelemetry_exporter_otlp-1.24.0.tar.gz", hash = "sha256:649c6e249e55cbdebe99ba2846e3851c04c9f328570328c35b3af9c094314b55"}, + {file = "opentelemetry_exporter_otlp-1.25.0-py3-none-any.whl", hash = "sha256:d67a831757014a3bc3174e4cd629ae1493b7ba8d189e8a007003cacb9f1a6b60"}, + {file = "opentelemetry_exporter_otlp-1.25.0.tar.gz", hash = "sha256:ce03199c1680a845f82e12c0a6a8f61036048c07ec7a0bd943142aca8fa6ced0"}, ] [package.dependencies] -opentelemetry-exporter-otlp-proto-grpc = "1.24.0" -opentelemetry-exporter-otlp-proto-http = "1.24.0" +opentelemetry-exporter-otlp-proto-grpc = "1.25.0" +opentelemetry-exporter-otlp-proto-http = "1.25.0" [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Protobuf encoding" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_common-1.24.0-py3-none-any.whl", hash = "sha256:e51f2c9735054d598ad2df5d3eca830fecfb5b0bda0a2fa742c9c7718e12f641"}, - {file = "opentelemetry_exporter_otlp_proto_common-1.24.0.tar.gz", hash = "sha256:5d31fa1ff976cacc38be1ec4e3279a3f88435c75b38b1f7a099a1faffc302461"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.25.0-py3-none-any.whl", hash = "sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693"}, + {file = "opentelemetry_exporter_otlp_proto_common-1.25.0.tar.gz", hash = "sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3"}, ] [package.dependencies] -opentelemetry-proto = "1.24.0" +opentelemetry-proto = "1.25.0" [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Collector Protobuf over gRPC Exporter" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_grpc-1.24.0-py3-none-any.whl", hash = "sha256:f40d62aa30a0a43cc1657428e59fcf82ad5f7ea8fff75de0f9d9cb6f739e0a3b"}, - {file = "opentelemetry_exporter_otlp_proto_grpc-1.24.0.tar.gz", hash = "sha256:217c6e30634f2c9797999ea9da29f7300479a94a610139b9df17433f915e7baa"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0-py3-none-any.whl", hash = "sha256:3131028f0c0a155a64c430ca600fd658e8e37043cb13209f0109db5c1a3e4eb4"}, + {file = "opentelemetry_exporter_otlp_proto_grpc-1.25.0.tar.gz", hash = "sha256:c0b1661415acec5af87625587efa1ccab68b873745ca0ee96b69bb1042087eac"}, ] [package.dependencies] @@ -3496,42 +3584,39 @@ deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" grpcio = ">=1.0.0,<2.0.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.24.0" -opentelemetry-proto = "1.24.0" -opentelemetry-sdk = ">=1.24.0,<1.25.0" - -[package.extras] -test = ["pytest-grpc"] +opentelemetry-exporter-otlp-proto-common = "1.25.0" +opentelemetry-proto = "1.25.0" +opentelemetry-sdk = ">=1.25.0,<1.26.0" [[package]] name = "opentelemetry-exporter-otlp-proto-http" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Collector Protobuf over HTTP Exporter" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_exporter_otlp_proto_http-1.24.0-py3-none-any.whl", hash = "sha256:25af10e46fdf4cd3833175e42f4879a1255fc01655fe14c876183a2903949836"}, - {file = "opentelemetry_exporter_otlp_proto_http-1.24.0.tar.gz", hash = "sha256:704c066cc96f5131881b75c0eac286cd73fc735c490b054838b4513254bd7850"}, + {file = "opentelemetry_exporter_otlp_proto_http-1.25.0-py3-none-any.whl", hash = "sha256:2eca686ee11b27acd28198b3ea5e5863a53d1266b91cda47c839d95d5e0541a6"}, + {file = "opentelemetry_exporter_otlp_proto_http-1.25.0.tar.gz", hash = "sha256:9f8723859e37c75183ea7afa73a3542f01d0fd274a5b97487ea24cb683d7d684"}, ] [package.dependencies] deprecated = ">=1.2.6" googleapis-common-protos = ">=1.52,<2.0" opentelemetry-api = ">=1.15,<2.0" -opentelemetry-exporter-otlp-proto-common = "1.24.0" -opentelemetry-proto = "1.24.0" -opentelemetry-sdk = ">=1.24.0,<1.25.0" +opentelemetry-exporter-otlp-proto-common = "1.25.0" +opentelemetry-proto = "1.25.0" +opentelemetry-sdk = ">=1.25.0,<1.26.0" requests = ">=2.7,<3.0" [[package]] name = "opentelemetry-instrumentation" -version = "0.44b0" +version = "0.46b0" description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_instrumentation-0.44b0-py3-none-any.whl", hash = "sha256:79560f386425176bcc60c59190064597096114c4a8e5154f1cb281bb4e47d2fc"}, - {file = "opentelemetry_instrumentation-0.44b0.tar.gz", hash = "sha256:8213d02d8c0987b9b26386ae3e091e0477d6331673123df736479322e1a50b48"}, + {file = "opentelemetry_instrumentation-0.46b0-py3-none-any.whl", hash = "sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b"}, + {file = "opentelemetry_instrumentation-0.46b0.tar.gz", hash = "sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda"}, ] [package.dependencies] @@ -3541,13 +3626,13 @@ wrapt = ">=1.0.0,<2.0.0" [[package]] name = "opentelemetry-proto" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Python Proto" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_proto-1.24.0-py3-none-any.whl", hash = "sha256:bcb80e1e78a003040db71ccf83f2ad2019273d1e0828089d183b18a1476527ce"}, - {file = "opentelemetry_proto-1.24.0.tar.gz", hash = "sha256:ff551b8ad63c6cabb1845ce217a6709358dfaba0f75ea1fa21a61ceddc78cab8"}, + {file = "opentelemetry_proto-1.25.0-py3-none-any.whl", hash = "sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f"}, + {file = "opentelemetry_proto-1.25.0.tar.gz", hash = "sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3"}, ] [package.dependencies] @@ -3555,29 +3640,87 @@ protobuf = ">=3.19,<5.0" [[package]] name = "opentelemetry-sdk" -version = "1.24.0" +version = "1.25.0" description = "OpenTelemetry Python SDK" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_sdk-1.24.0-py3-none-any.whl", hash = "sha256:fa731e24efe832e98bcd90902085b359dcfef7d9c9c00eb5b9a18587dae3eb59"}, - {file = "opentelemetry_sdk-1.24.0.tar.gz", hash = "sha256:75bc0563affffa827700e0f4f4a68e1e257db0df13372344aebc6f8a64cde2e5"}, + {file = "opentelemetry_sdk-1.25.0-py3-none-any.whl", hash = "sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9"}, + {file = "opentelemetry_sdk-1.25.0.tar.gz", hash = "sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7"}, ] [package.dependencies] -opentelemetry-api = "1.24.0" -opentelemetry-semantic-conventions = "0.45b0" +opentelemetry-api = "1.25.0" +opentelemetry-semantic-conventions = "0.46b0" typing-extensions = ">=3.7.4" [[package]] name = "opentelemetry-semantic-conventions" -version = "0.45b0" +version = "0.46b0" description = "OpenTelemetry Semantic Conventions" optional = true python-versions = ">=3.8" files = [ - {file = "opentelemetry_semantic_conventions-0.45b0-py3-none-any.whl", hash = "sha256:a4a6fb9a7bacd9167c082aa4681009e9acdbfa28ffb2387af50c2fef3d30c864"}, - {file = "opentelemetry_semantic_conventions-0.45b0.tar.gz", hash = "sha256:7c84215a44ac846bc4b8e32d5e78935c5c43482e491812a0bb8aaf87e4d92118"}, + {file = "opentelemetry_semantic_conventions-0.46b0-py3-none-any.whl", hash = "sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07"}, + {file = "opentelemetry_semantic_conventions-0.46b0.tar.gz", hash = "sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa"}, +] + +[package.dependencies] +opentelemetry-api = "1.25.0" + +[[package]] +name = "orjson" +version = "3.10.5" +description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +optional = false +python-versions = ">=3.8" +files = [ + {file = "orjson-3.10.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:545d493c1f560d5ccfc134803ceb8955a14c3fcb47bbb4b2fee0232646d0b932"}, + {file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4324929c2dd917598212bfd554757feca3e5e0fa60da08be11b4aa8b90013c1"}, + {file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c13ca5e2ddded0ce6a927ea5a9f27cae77eee4c75547b4297252cb20c4d30e6"}, + {file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b6c8e30adfa52c025f042a87f450a6b9ea29649d828e0fec4858ed5e6caecf63"}, + {file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:338fd4f071b242f26e9ca802f443edc588fa4ab60bfa81f38beaedf42eda226c"}, + {file = "orjson-3.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6970ed7a3126cfed873c5d21ece1cd5d6f83ca6c9afb71bbae21a0b034588d96"}, + {file = "orjson-3.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:235dadefb793ad12f7fa11e98a480db1f7c6469ff9e3da5e73c7809c700d746b"}, + {file = "orjson-3.10.5-cp310-none-win32.whl", hash = "sha256:be79e2393679eda6a590638abda16d167754393f5d0850dcbca2d0c3735cebe2"}, + {file = "orjson-3.10.5-cp310-none-win_amd64.whl", hash = "sha256:c4a65310ccb5c9910c47b078ba78e2787cb3878cdded1702ac3d0da71ddc5228"}, + {file = "orjson-3.10.5-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:cdf7365063e80899ae3a697def1277c17a7df7ccfc979990a403dfe77bb54d40"}, + {file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b68742c469745d0e6ca5724506858f75e2f1e5b59a4315861f9e2b1df77775a"}, + {file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7d10cc1b594951522e35a3463da19e899abe6ca95f3c84c69e9e901e0bd93d38"}, + {file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dcbe82b35d1ac43b0d84072408330fd3295c2896973112d495e7234f7e3da2e1"}, + {file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c0eb7e0c75e1e486c7563fe231b40fdd658a035ae125c6ba651ca3b07936f5"}, + {file = "orjson-3.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:53ed1c879b10de56f35daf06dbc4a0d9a5db98f6ee853c2dbd3ee9d13e6f302f"}, + {file = "orjson-3.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:099e81a5975237fda3100f918839af95f42f981447ba8f47adb7b6a3cdb078fa"}, + {file = "orjson-3.10.5-cp311-none-win32.whl", hash = "sha256:1146bf85ea37ac421594107195db8bc77104f74bc83e8ee21a2e58596bfb2f04"}, + {file = "orjson-3.10.5-cp311-none-win_amd64.whl", hash = "sha256:36a10f43c5f3a55c2f680efe07aa93ef4a342d2960dd2b1b7ea2dd764fe4a37c"}, + {file = "orjson-3.10.5-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:68f85ecae7af14a585a563ac741b0547a3f291de81cd1e20903e79f25170458f"}, + {file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28afa96f496474ce60d3340fe8d9a263aa93ea01201cd2bad844c45cd21f5268"}, + {file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cd684927af3e11b6e754df80b9ffafd9fb6adcaa9d3e8fdd5891be5a5cad51e"}, + {file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d21b9983da032505f7050795e98b5d9eee0df903258951566ecc358f6696969"}, + {file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ad1de7fef79736dde8c3554e75361ec351158a906d747bd901a52a5c9c8d24b"}, + {file = "orjson-3.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2d97531cdfe9bdd76d492e69800afd97e5930cb0da6a825646667b2c6c6c0211"}, + {file = "orjson-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d69858c32f09c3e1ce44b617b3ebba1aba030e777000ebdf72b0d8e365d0b2b3"}, + {file = "orjson-3.10.5-cp312-none-win32.whl", hash = "sha256:64c9cc089f127e5875901ac05e5c25aa13cfa5dbbbd9602bda51e5c611d6e3e2"}, + {file = "orjson-3.10.5-cp312-none-win_amd64.whl", hash = "sha256:b2efbd67feff8c1f7728937c0d7f6ca8c25ec81373dc8db4ef394c1d93d13dc5"}, + {file = "orjson-3.10.5-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:03b565c3b93f5d6e001db48b747d31ea3819b89abf041ee10ac6988886d18e01"}, + {file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:584c902ec19ab7928fd5add1783c909094cc53f31ac7acfada817b0847975f26"}, + {file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a35455cc0b0b3a1eaf67224035f5388591ec72b9b6136d66b49a553ce9eb1e6"}, + {file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1670fe88b116c2745a3a30b0f099b699a02bb3482c2591514baf5433819e4f4d"}, + {file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:185c394ef45b18b9a7d8e8f333606e2e8194a50c6e3c664215aae8cf42c5385e"}, + {file = "orjson-3.10.5-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ca0b3a94ac8d3886c9581b9f9de3ce858263865fdaa383fbc31c310b9eac07c9"}, + {file = "orjson-3.10.5-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dfc91d4720d48e2a709e9c368d5125b4b5899dced34b5400c3837dadc7d6271b"}, + {file = "orjson-3.10.5-cp38-none-win32.whl", hash = "sha256:c05f16701ab2a4ca146d0bca950af254cb7c02f3c01fca8efbbad82d23b3d9d4"}, + {file = "orjson-3.10.5-cp38-none-win_amd64.whl", hash = "sha256:8a11d459338f96a9aa7f232ba95679fc0c7cedbd1b990d736467894210205c09"}, + {file = "orjson-3.10.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:85c89131d7b3218db1b24c4abecea92fd6c7f9fab87441cfc342d3acc725d807"}, + {file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66215277a230c456f9038d5e2d84778141643207f85336ef8d2a9da26bd7ca"}, + {file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:51bbcdea96cdefa4a9b4461e690c75ad4e33796530d182bdd5c38980202c134a"}, + {file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbead71dbe65f959b7bd8cf91e0e11d5338033eba34c114f69078d59827ee139"}, + {file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5df58d206e78c40da118a8c14fc189207fffdcb1f21b3b4c9c0c18e839b5a214"}, + {file = "orjson-3.10.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c4057c3b511bb8aef605616bd3f1f002a697c7e4da6adf095ca5b84c0fd43595"}, + {file = "orjson-3.10.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b39e006b00c57125ab974362e740c14a0c6a66ff695bff44615dcf4a70ce2b86"}, + {file = "orjson-3.10.5-cp39-none-win32.whl", hash = "sha256:eded5138cc565a9d618e111c6d5c2547bbdd951114eb822f7f6309e04db0fb47"}, + {file = "orjson-3.10.5-cp39-none-win_amd64.whl", hash = "sha256:cc28e90a7cae7fcba2493953cff61da5a52950e78dc2dacfe931a317ee3d8de7"}, + {file = "orjson-3.10.5.tar.gz", hash = "sha256:7a5baef8a4284405d96c90c7c62b755e9ef1ada84c2406c24a9ebec86b89f46d"}, ] [[package]] @@ -3913,13 +4056,13 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest- [[package]] name = "pluggy" -version = "1.4.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, - {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] @@ -3928,13 +4071,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "poethepoet" -version = "0.25.0" +version = "0.26.1" description = "A task runner that works well with poetry." optional = false python-versions = ">=3.8" files = [ - {file = "poethepoet-0.25.0-py3-none-any.whl", hash = "sha256:42c0fd654f23e1b7c67aa8aa395c72e15eb275034bd5105171003daf679c1470"}, - {file = "poethepoet-0.25.0.tar.gz", hash = "sha256:ca8f1d8475aa10d2ceeb26331d2626fc4a6b51df1e7e70d3d0d6481a984faab6"}, + {file = "poethepoet-0.26.1-py3-none-any.whl", hash = "sha256:aa43b443fec5d17d7e76771cccd484e5285805301721a74f059c483ad3276edd"}, + {file = "poethepoet-0.26.1.tar.gz", hash = "sha256:aaad8541f6072617a60bcff2562d00779b58b353bd0f1847b06d8d0f2b6dc192"}, ] [package.dependencies] @@ -4180,13 +4323,13 @@ files = [ [[package]] name = "pycodestyle" -version = "2.11.1" +version = "2.12.0" description = "Python style guide checker" optional = false python-versions = ">=3.8" files = [ - {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, - {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, + {file = "pycodestyle-2.12.0-py2.py3-none-any.whl", hash = "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4"}, + {file = "pycodestyle-2.12.0.tar.gz", hash = "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c"}, ] [[package]] @@ -4512,13 +4655,13 @@ tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} [[package]] name = "pytelegrambotapi" -version = "4.17.0" +version = "4.19.2" description = "Python Telegram bot api." optional = true python-versions = ">=3.8" files = [ - {file = "pytelegrambotapi-4.17.0-py3-none-any.whl", hash = "sha256:326b51fdaa4f5dcb1e12d326beb9d9aa1289ffb578110b17d5ea269971a39160"}, - {file = "pytelegrambotapi-4.17.0.tar.gz", hash = "sha256:8cfda15e64a12fe73b78545ccc7b59e035d7fb3e54da5722ddf756296f3b8159"}, + {file = "pytelegrambotapi-4.19.2-py3-none-any.whl", hash = "sha256:c2c87807523dc3eb3a3f73f2c9a037e34612e89019d0ce04ae81351c740757ff"}, + {file = "pytelegrambotapi-4.19.2.tar.gz", hash = "sha256:39481e607c76b217606052f3e542322a53eada212914090a46d565a47729711d"}, ] [package.dependencies] @@ -4538,13 +4681,13 @@ watchdog = ["watchdog"] [[package]] name = "pytest" -version = "8.1.1" +version = "8.2.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.1.1-py3-none-any.whl", hash = "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7"}, - {file = "pytest-8.1.1.tar.gz", hash = "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044"}, + {file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"}, + {file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"}, ] [package.dependencies] @@ -4552,11 +4695,11 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=1.4,<2.0" +pluggy = ">=1.5,<2.0" tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" @@ -4693,15 +4836,29 @@ files = [ {file = "python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd"}, ] +[[package]] +name = "python-multipart" +version = "0.0.9" +description = "A streaming multipart parser for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python_multipart-0.0.9-py3-none-any.whl", hash = "sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215"}, + {file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"}, +] + +[package.extras] +dev = ["atomicwrites (==1.4.1)", "attrs (==23.2.0)", "coverage (==7.4.1)", "hatch", "invoke (==2.2.0)", "more-itertools (==10.2.0)", "pbr (==6.0.0)", "pluggy (==1.4.0)", "py (==1.11.0)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.2.0)", "pyyaml (==6.0.1)", "ruff (==0.2.1)"] + [[package]] name = "python-on-whales" -version = "0.70.0" +version = "0.71.0" description = "A Docker client for Python, designed to be fun and intuitive!" optional = false python-versions = "<4,>=3.8" files = [ - {file = "python-on-whales-0.70.0.tar.gz", hash = "sha256:bb89e91c86e049f9c04e2636f2d40faa000ff5b17d54f71e68581201e449eda5"}, - {file = "python_on_whales-0.70.0-py3-none-any.whl", hash = "sha256:492325387d7686adc6669e911820bd4da1cd672bc5a7fb6d54c32ee849bfe7e6"}, + {file = "python_on_whales-0.71.0-py3-none-any.whl", hash = "sha256:9d23c025e2e887f8336fbdd324ce764e72e60f7db2d0599601e8f6ddac1cae2d"}, + {file = "python_on_whales-0.71.0.tar.gz", hash = "sha256:0967be1b716f4a40e44a4b3bf091f721b494205425c1215f64a1a612eb932900"}, ] [package.dependencies] @@ -5118,13 +5275,13 @@ rpds-py = ">=0.7.0" [[package]] name = "requests" -version = "2.31.0" +version = "2.32.3" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -5533,13 +5690,13 @@ test = ["beautifulsoup4", "pytest", "pytest-cov"] [[package]] name = "sphinx-gallery" -version = "0.15.0" -description = "A `Sphinx `_ extension that builds an HTML gallery of examples from any set of Python scripts." +version = "0.16.0" +description = "A Sphinx extension that builds an HTML gallery of examples from any set of Python scripts." optional = false python-versions = ">=3.8" files = [ - {file = "sphinx-gallery-0.15.0.tar.gz", hash = "sha256:7217fe98f8c4cce248db798c48f34183e4cdb277d2381e188182f92a14ec26b7"}, - {file = "sphinx_gallery-0.15.0-py3-none-any.whl", hash = "sha256:d66d38d901f6b65b6e3ee6c2584e37476b035d9e52907b1593a3f312946ae724"}, + {file = "sphinx_gallery-0.16.0-py3-none-any.whl", hash = "sha256:f5456514f4efb230a6f1db6241667774ca3ee8f15e9a7456678f1d1815118e60"}, + {file = "sphinx_gallery-0.16.0.tar.gz", hash = "sha256:3912765bc5e7b5451dc471ad50ead808a9752280b23fd2ec4277719a5ef68e42"}, ] [package.dependencies] @@ -5808,13 +5965,13 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] [[package]] name = "starlette" -version = "0.36.3" +version = "0.37.2" description = "The little ASGI library that shines." optional = false python-versions = ">=3.8" files = [ - {file = "starlette-0.36.3-py3-none-any.whl", hash = "sha256:13d429aa93a61dc40bf503e8c801db1f1bca3dc706b10ef2434a36123568f044"}, - {file = "starlette-0.36.3.tar.gz", hash = "sha256:90a671733cfb35771d8cc605e0b679d23b992f8dcfad48cc60b38cb29aeb7080"}, + {file = "starlette-0.37.2-py3-none-any.whl", hash = "sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee"}, + {file = "starlette-0.37.2.tar.gz", hash = "sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823"}, ] [package.dependencies] @@ -5826,13 +5983,13 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7 [[package]] name = "streamlit" -version = "1.33.0" +version = "1.35.0" description = "A faster way to build and share data apps" optional = false python-versions = "!=3.9.7,>=3.8" files = [ - {file = "streamlit-1.33.0-py2.py3-none-any.whl", hash = "sha256:bfacb5d1edefcf803c2040b051a21b4c81317a9865448e6767d0a0c6aae7edae"}, - {file = "streamlit-1.33.0.tar.gz", hash = "sha256:a8da8ff46f5b948c56d2dc7aca7a61cf8d995f4f21744cf82258ae75e63004ba"}, + {file = "streamlit-1.35.0-py2.py3-none-any.whl", hash = "sha256:e17d1d86830a0d7687c37faf2fe47bffa752d0c95a306e96d7749bd3faa72a5b"}, + {file = "streamlit-1.35.0.tar.gz", hash = "sha256:679d55bb6189743f606abf0696623df0bfd223a6d0c8d96b8d60678d4891d2d6"}, ] [package.dependencies] @@ -5875,12 +6032,12 @@ streamlit = ">=0.63" [[package]] name = "telethon" -version = "1.34.0" +version = "1.36.0" description = "Full-featured Telegram client library for Python 3" optional = false python-versions = ">=3.5" files = [ - {file = "Telethon-1.34.0.tar.gz", hash = "sha256:55290809a30081fa0bb5052abb7547cbb25d7fbca94f32f13c147504d521804f"}, + {file = "Telethon-1.36.0.tar.gz", hash = "sha256:11db5c7ed7e37f1272d443fb7eea0f1db580d56c6949165233946fb323aaf3a7"}, ] [package.dependencies] @@ -6069,25 +6226,21 @@ files = [ [[package]] name = "typer" -version = "0.9.0" +version = "0.12.3" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "typer-0.9.0-py3-none-any.whl", hash = "sha256:5d96d986a21493606a358cae4461bd8cdf83cbf33a5aa950ae629ca3b51467ee"}, - {file = "typer-0.9.0.tar.gz", hash = "sha256:50922fd79aea2f4751a8e0408ff10d2662bd0c8bbfa84755a699f3bada2978b2"}, + {file = "typer-0.12.3-py3-none-any.whl", hash = "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914"}, + {file = "typer-0.12.3.tar.gz", hash = "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"}, ] [package.dependencies] -click = ">=7.1.1,<9.0.0" +click = ">=8.0.0" +rich = ">=10.11.0" +shellingham = ">=1.3.0" typing-extensions = ">=3.7.4.3" -[package.extras] -all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] -dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"] -doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"] -test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] - [[package]] name = "types-python-dateutil" version = "2.8.19.20240106" @@ -6101,13 +6254,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.11.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, - {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] @@ -6121,6 +6274,93 @@ files = [ {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] +[[package]] +name = "ujson" +version = "5.10.0" +description = "Ultra fast JSON encoder and decoder for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "ujson-5.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2601aa9ecdbee1118a1c2065323bda35e2c5a2cf0797ef4522d485f9d3ef65bd"}, + {file = "ujson-5.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:348898dd702fc1c4f1051bc3aacbf894caa0927fe2c53e68679c073375f732cf"}, + {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22cffecf73391e8abd65ef5f4e4dd523162a3399d5e84faa6aebbf9583df86d6"}, + {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26b0e2d2366543c1bb4fbd457446f00b0187a2bddf93148ac2da07a53fe51569"}, + {file = "ujson-5.10.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:caf270c6dba1be7a41125cd1e4fc7ba384bf564650beef0df2dd21a00b7f5770"}, + {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a245d59f2ffe750446292b0094244df163c3dc96b3ce152a2c837a44e7cda9d1"}, + {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94a87f6e151c5f483d7d54ceef83b45d3a9cca7a9cb453dbdbb3f5a6f64033f5"}, + {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:29b443c4c0a113bcbb792c88bea67b675c7ca3ca80c3474784e08bba01c18d51"}, + {file = "ujson-5.10.0-cp310-cp310-win32.whl", hash = "sha256:c18610b9ccd2874950faf474692deee4223a994251bc0a083c114671b64e6518"}, + {file = "ujson-5.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:924f7318c31874d6bb44d9ee1900167ca32aa9b69389b98ecbde34c1698a250f"}, + {file = "ujson-5.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a5b366812c90e69d0f379a53648be10a5db38f9d4ad212b60af00bd4048d0f00"}, + {file = "ujson-5.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:502bf475781e8167f0f9d0e41cd32879d120a524b22358e7f205294224c71126"}, + {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b91b5d0d9d283e085e821651184a647699430705b15bf274c7896f23fe9c9d8"}, + {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:129e39af3a6d85b9c26d5577169c21d53821d8cf68e079060602e861c6e5da1b"}, + {file = "ujson-5.10.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f77b74475c462cb8b88680471193064d3e715c7c6074b1c8c412cb526466efe9"}, + {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ec0ca8c415e81aa4123501fee7f761abf4b7f386aad348501a26940beb1860f"}, + {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab13a2a9e0b2865a6c6db9271f4b46af1c7476bfd51af1f64585e919b7c07fd4"}, + {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:57aaf98b92d72fc70886b5a0e1a1ca52c2320377360341715dd3933a18e827b1"}, + {file = "ujson-5.10.0-cp311-cp311-win32.whl", hash = "sha256:2987713a490ceb27edff77fb184ed09acdc565db700ee852823c3dc3cffe455f"}, + {file = "ujson-5.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:f00ea7e00447918ee0eff2422c4add4c5752b1b60e88fcb3c067d4a21049a720"}, + {file = "ujson-5.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98ba15d8cbc481ce55695beee9f063189dce91a4b08bc1d03e7f0152cd4bbdd5"}, + {file = "ujson-5.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9d2edbf1556e4f56e50fab7d8ff993dbad7f54bac68eacdd27a8f55f433578e"}, + {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6627029ae4f52d0e1a2451768c2c37c0c814ffc04f796eb36244cf16b8e57043"}, + {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8ccb77b3e40b151e20519c6ae6d89bfe3f4c14e8e210d910287f778368bb3d1"}, + {file = "ujson-5.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3caf9cd64abfeb11a3b661329085c5e167abbe15256b3b68cb5d914ba7396f3"}, + {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6e32abdce572e3a8c3d02c886c704a38a1b015a1fb858004e03d20ca7cecbb21"}, + {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a65b6af4d903103ee7b6f4f5b85f1bfd0c90ba4eeac6421aae436c9988aa64a2"}, + {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:604a046d966457b6cdcacc5aa2ec5314f0e8c42bae52842c1e6fa02ea4bda42e"}, + {file = "ujson-5.10.0-cp312-cp312-win32.whl", hash = "sha256:6dea1c8b4fc921bf78a8ff00bbd2bfe166345f5536c510671bccececb187c80e"}, + {file = "ujson-5.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:38665e7d8290188b1e0d57d584eb8110951a9591363316dd41cf8686ab1d0abc"}, + {file = "ujson-5.10.0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:618efd84dc1acbd6bff8eaa736bb6c074bfa8b8a98f55b61c38d4ca2c1f7f287"}, + {file = "ujson-5.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38d5d36b4aedfe81dfe251f76c0467399d575d1395a1755de391e58985ab1c2e"}, + {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67079b1f9fb29ed9a2914acf4ef6c02844b3153913eb735d4bf287ee1db6e557"}, + {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7d0e0ceeb8fe2468c70ec0c37b439dd554e2aa539a8a56365fd761edb418988"}, + {file = "ujson-5.10.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59e02cd37bc7c44d587a0ba45347cc815fb7a5fe48de16bf05caa5f7d0d2e816"}, + {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a890b706b64e0065f02577bf6d8ca3b66c11a5e81fb75d757233a38c07a1f20"}, + {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:621e34b4632c740ecb491efc7f1fcb4f74b48ddb55e65221995e74e2d00bbff0"}, + {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b9500e61fce0cfc86168b248104e954fead61f9be213087153d272e817ec7b4f"}, + {file = "ujson-5.10.0-cp313-cp313-win32.whl", hash = "sha256:4c4fc16f11ac1612f05b6f5781b384716719547e142cfd67b65d035bd85af165"}, + {file = "ujson-5.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539"}, + {file = "ujson-5.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a984a3131da7f07563057db1c3020b1350a3e27a8ec46ccbfbf21e5928a43050"}, + {file = "ujson-5.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73814cd1b9db6fc3270e9d8fe3b19f9f89e78ee9d71e8bd6c9a626aeaeaf16bd"}, + {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61e1591ed9376e5eddda202ec229eddc56c612b61ac6ad07f96b91460bb6c2fb"}, + {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2c75269f8205b2690db4572a4a36fe47cd1338e4368bc73a7a0e48789e2e35a"}, + {file = "ujson-5.10.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7223f41e5bf1f919cd8d073e35b229295aa8e0f7b5de07ed1c8fddac63a6bc5d"}, + {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc2fd6b3067c0782e7002ac3b38cf48608ee6366ff176bbd02cf969c9c20fe"}, + {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:232cc85f8ee3c454c115455195a205074a56ff42608fd6b942aa4c378ac14dd7"}, + {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cc6139531f13148055d691e442e4bc6601f6dba1e6d521b1585d4788ab0bfad4"}, + {file = "ujson-5.10.0-cp38-cp38-win32.whl", hash = "sha256:e7ce306a42b6b93ca47ac4a3b96683ca554f6d35dd8adc5acfcd55096c8dfcb8"}, + {file = "ujson-5.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:e82d4bb2138ab05e18f089a83b6564fee28048771eb63cdecf4b9b549de8a2cc"}, + {file = "ujson-5.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dfef2814c6b3291c3c5f10065f745a1307d86019dbd7ea50e83504950136ed5b"}, + {file = "ujson-5.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4734ee0745d5928d0ba3a213647f1c4a74a2a28edc6d27b2d6d5bd9fa4319e27"}, + {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d47ebb01bd865fdea43da56254a3930a413f0c5590372a1241514abae8aa7c76"}, + {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dee5e97c2496874acbf1d3e37b521dd1f307349ed955e62d1d2f05382bc36dd5"}, + {file = "ujson-5.10.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7490655a2272a2d0b072ef16b0b58ee462f4973a8f6bbe64917ce5e0a256f9c0"}, + {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ba17799fcddaddf5c1f75a4ba3fd6441f6a4f1e9173f8a786b42450851bd74f1"}, + {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2aff2985cef314f21d0fecc56027505804bc78802c0121343874741650a4d3d1"}, + {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ad88ac75c432674d05b61184178635d44901eb749786c8eb08c102330e6e8996"}, + {file = "ujson-5.10.0-cp39-cp39-win32.whl", hash = "sha256:2544912a71da4ff8c4f7ab5606f947d7299971bdd25a45e008e467ca638d13c9"}, + {file = "ujson-5.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:3ff201d62b1b177a46f113bb43ad300b424b7847f9c5d38b1b4ad8f75d4a282a"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5b6fee72fa77dc172a28f21693f64d93166534c263adb3f96c413ccc85ef6e64"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:61d0af13a9af01d9f26d2331ce49bb5ac1fb9c814964018ac8df605b5422dcb3"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecb24f0bdd899d368b715c9e6664166cf694d1e57be73f17759573a6986dd95a"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbd8fd427f57a03cff3ad6574b5e299131585d9727c8c366da4624a9069ed746"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beeaf1c48e32f07d8820c705ff8e645f8afa690cca1544adba4ebfa067efdc88"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:baed37ea46d756aca2955e99525cc02d9181de67f25515c468856c38d52b5f3b"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7663960f08cd5a2bb152f5ee3992e1af7690a64c0e26d31ba7b3ff5b2ee66337"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:d8640fb4072d36b08e95a3a380ba65779d356b2fee8696afeb7794cf0902d0a1"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78778a3aa7aafb11e7ddca4e29f46bc5139131037ad628cc10936764282d6753"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0111b27f2d5c820e7f2dbad7d48e3338c824e7ac4d2a12da3dc6061cc39c8e6"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:c66962ca7565605b355a9ed478292da628b8f18c0f2793021ca4425abf8b01e5"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba43cc34cce49cf2d4bc76401a754a81202d8aa926d0e2b79f0ee258cb15d3a4"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ac56eb983edce27e7f51d05bc8dd820586c6e6be1c5216a6809b0c668bb312b8"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44bd4b23a0e723bf8b10628288c2c7c335161d6840013d4d5de20e48551773b"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c10f4654e5326ec14a46bcdeb2b685d4ada6911050aa8baaf3501e57024b804"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0de4971a89a762398006e844ae394bd46991f7c385d7a6a3b93ba229e6dac17e"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e1402f0564a97d2a52310ae10a64d25bcef94f8dd643fcf5d310219d915484f7"}, + {file = "ujson-5.10.0.tar.gz", hash = "sha256:b3cd8f3c5d8c7738257f1018880444f7b7d9b66232c64649f562d7ba86ad4bc1"}, +] + [[package]] name = "uri-template" version = "1.3.0" @@ -6153,23 +6393,74 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "uvicorn" -version = "0.29.0" +version = "0.30.1" description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.8" files = [ - {file = "uvicorn-0.29.0-py3-none-any.whl", hash = "sha256:2c2aac7ff4f4365c206fd773a39bf4ebd1047c238f8b8268ad996829323473de"}, - {file = "uvicorn-0.29.0.tar.gz", hash = "sha256:6a69214c0b6a087462412670b3ef21224fa48cae0e452b5883e8e8bdfdd11dd0"}, + {file = "uvicorn-0.30.1-py3-none-any.whl", hash = "sha256:cd17daa7f3b9d7a24de3617820e634d0933b69eed8e33a516071174427238c81"}, + {file = "uvicorn-0.30.1.tar.gz", hash = "sha256:d46cd8e0fd80240baffbcd9ec1012a712938754afcf81bce56c024c1656aece8"}, ] [package.dependencies] click = ">=7.0" +colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} h11 = ">=0.8" +httptools = {version = ">=0.5.0", optional = true, markers = "extra == \"standard\""} +python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} +uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} +watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} [package.extras] standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] +[[package]] +name = "uvloop" +version = "0.19.0" +description = "Fast implementation of asyncio event loop on top of libuv" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e"}, + {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428"}, + {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b1fd71c3843327f3bbc3237bedcdb6504fd50368ab3e04d0410e52ec293f5b8"}, + {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a05128d315e2912791de6088c34136bfcdd0c7cbc1cf85fd6fd1bb321b7c849"}, + {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cd81bdc2b8219cb4b2556eea39d2e36bfa375a2dd021404f90a62e44efaaf957"}, + {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f17766fb6da94135526273080f3455a112f82570b2ee5daa64d682387fe0dcd"}, + {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4ce6b0af8f2729a02a5d1575feacb2a94fc7b2e983868b009d51c9a9d2149bef"}, + {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:31e672bb38b45abc4f26e273be83b72a0d28d074d5b370fc4dcf4c4eb15417d2"}, + {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:570fc0ed613883d8d30ee40397b79207eedd2624891692471808a95069a007c1"}, + {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5138821e40b0c3e6c9478643b4660bd44372ae1e16a322b8fc07478f92684e24"}, + {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:91ab01c6cd00e39cde50173ba4ec68a1e578fee9279ba64f5221810a9e786533"}, + {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:47bf3e9312f63684efe283f7342afb414eea4d3011542155c7e625cd799c3b12"}, + {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:da8435a3bd498419ee8c13c34b89b5005130a476bda1d6ca8cfdde3de35cd650"}, + {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:02506dc23a5d90e04d4f65c7791e65cf44bd91b37f24cfc3ef6cf2aff05dc7ec"}, + {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2693049be9d36fef81741fddb3f441673ba12a34a704e7b4361efb75cf30befc"}, + {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7010271303961c6f0fe37731004335401eb9075a12680738731e9c92ddd96ad6"}, + {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5daa304d2161d2918fa9a17d5635099a2f78ae5b5960e742b2fcfbb7aefaa593"}, + {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7207272c9520203fea9b93843bb775d03e1cf88a80a936ce760f60bb5add92f3"}, + {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:78ab247f0b5671cc887c31d33f9b3abfb88d2614b84e4303f1a63b46c046c8bd"}, + {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:472d61143059c84947aa8bb74eabbace30d577a03a1805b77933d6bd13ddebbd"}, + {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45bf4c24c19fb8a50902ae37c5de50da81de4922af65baf760f7c0c42e1088be"}, + {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271718e26b3e17906b28b67314c45d19106112067205119dddbd834c2b7ce797"}, + {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:34175c9fd2a4bc3adc1380e1261f60306344e3407c20a4d684fd5f3be010fa3d"}, + {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e27f100e1ff17f6feeb1f33968bc185bf8ce41ca557deee9d9bbbffeb72030b7"}, + {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13dfdf492af0aa0a0edf66807d2b465607d11c4fa48f4a1fd41cbea5b18e8e8b"}, + {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e3d4e85ac060e2342ff85e90d0c04157acb210b9ce508e784a944f852a40e67"}, + {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca4956c9ab567d87d59d49fa3704cf29e37109ad348f2d5223c9bf761a332e7"}, + {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f467a5fd23b4fc43ed86342641f3936a68ded707f4627622fa3f82a120e18256"}, + {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:492e2c32c2af3f971473bc22f086513cedfc66a130756145a931a90c3958cb17"}, + {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2df95fca285a9f5bfe730e51945ffe2fa71ccbfdde3b0da5772b4ee4f2e770d5"}, + {file = "uvloop-0.19.0.tar.gz", hash = "sha256:0246f4fd1bf2bf702e06b0d45ee91677ee5c31242f39aab4ea6fe0c51aedd0fd"}, +] + +[package.extras] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] + [[package]] name = "virtualenv" version = "20.25.1" @@ -6231,6 +6522,93 @@ files = [ [package.extras] watchmedo = ["PyYAML (>=3.10)"] +[[package]] +name = "watchfiles" +version = "0.22.0" +description = "Simple, modern and high performance file watching and code reload in python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "watchfiles-0.22.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:da1e0a8caebf17976e2ffd00fa15f258e14749db5e014660f53114b676e68538"}, + {file = "watchfiles-0.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61af9efa0733dc4ca462347becb82e8ef4945aba5135b1638bfc20fad64d4f0e"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d9188979a58a096b6f8090e816ccc3f255f137a009dd4bbec628e27696d67c1"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2bdadf6b90c099ca079d468f976fd50062905d61fae183f769637cb0f68ba59a"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:067dea90c43bf837d41e72e546196e674f68c23702d3ef80e4e816937b0a3ffd"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbf8a20266136507abf88b0df2328e6a9a7c7309e8daff124dda3803306a9fdb"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1235c11510ea557fe21be5d0e354bae2c655a8ee6519c94617fe63e05bca4171"}, + {file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2444dc7cb9d8cc5ab88ebe792a8d75709d96eeef47f4c8fccb6df7c7bc5be71"}, + {file = "watchfiles-0.22.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c5af2347d17ab0bd59366db8752d9e037982e259cacb2ba06f2c41c08af02c39"}, + {file = "watchfiles-0.22.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9624a68b96c878c10437199d9a8b7d7e542feddda8d5ecff58fdc8e67b460848"}, + {file = "watchfiles-0.22.0-cp310-none-win32.whl", hash = "sha256:4b9f2a128a32a2c273d63eb1fdbf49ad64852fc38d15b34eaa3f7ca2f0d2b797"}, + {file = "watchfiles-0.22.0-cp310-none-win_amd64.whl", hash = "sha256:2627a91e8110b8de2406d8b2474427c86f5a62bf7d9ab3654f541f319ef22bcb"}, + {file = "watchfiles-0.22.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8c39987a1397a877217be1ac0fb1d8b9f662c6077b90ff3de2c05f235e6a8f96"}, + {file = "watchfiles-0.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a927b3034d0672f62fb2ef7ea3c9fc76d063c4b15ea852d1db2dc75fe2c09696"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052d668a167e9fc345c24203b104c313c86654dd6c0feb4b8a6dfc2462239249"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e45fb0d70dda1623a7045bd00c9e036e6f1f6a85e4ef2c8ae602b1dfadf7550"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c49b76a78c156979759d759339fb62eb0549515acfe4fd18bb151cc07366629c"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a65474fd2b4c63e2c18ac67a0c6c66b82f4e73e2e4d940f837ed3d2fd9d4da"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc0cba54f47c660d9fa3218158b8963c517ed23bd9f45fe463f08262a4adae1"}, + {file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94ebe84a035993bb7668f58a0ebf998174fb723a39e4ef9fce95baabb42b787f"}, + {file = "watchfiles-0.22.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e0f0a874231e2839abbf473256efffe577d6ee2e3bfa5b540479e892e47c172d"}, + {file = "watchfiles-0.22.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:213792c2cd3150b903e6e7884d40660e0bcec4465e00563a5fc03f30ea9c166c"}, + {file = "watchfiles-0.22.0-cp311-none-win32.whl", hash = "sha256:b44b70850f0073b5fcc0b31ede8b4e736860d70e2dbf55701e05d3227a154a67"}, + {file = "watchfiles-0.22.0-cp311-none-win_amd64.whl", hash = "sha256:00f39592cdd124b4ec5ed0b1edfae091567c72c7da1487ae645426d1b0ffcad1"}, + {file = "watchfiles-0.22.0-cp311-none-win_arm64.whl", hash = "sha256:3218a6f908f6a276941422b035b511b6d0d8328edd89a53ae8c65be139073f84"}, + {file = "watchfiles-0.22.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c7b978c384e29d6c7372209cbf421d82286a807bbcdeb315427687f8371c340a"}, + {file = "watchfiles-0.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd4c06100bce70a20c4b81e599e5886cf504c9532951df65ad1133e508bf20be"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:425440e55cd735386ec7925f64d5dde392e69979d4c8459f6bb4e920210407f2"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68fe0c4d22332d7ce53ad094622b27e67440dacefbaedd29e0794d26e247280c"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8a31bfd98f846c3c284ba694c6365620b637debdd36e46e1859c897123aa232"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc2e8fe41f3cac0660197d95216c42910c2b7e9c70d48e6d84e22f577d106fc1"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b7cc10261c2786c41d9207193a85c1db1b725cf87936df40972aab466179b6"}, + {file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28585744c931576e535860eaf3f2c0ec7deb68e3b9c5a85ca566d69d36d8dd27"}, + {file = "watchfiles-0.22.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00095dd368f73f8f1c3a7982a9801190cc88a2f3582dd395b289294f8975172b"}, + {file = "watchfiles-0.22.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:52fc9b0dbf54d43301a19b236b4a4614e610605f95e8c3f0f65c3a456ffd7d35"}, + {file = "watchfiles-0.22.0-cp312-none-win32.whl", hash = "sha256:581f0a051ba7bafd03e17127735d92f4d286af941dacf94bcf823b101366249e"}, + {file = "watchfiles-0.22.0-cp312-none-win_amd64.whl", hash = "sha256:aec83c3ba24c723eac14225194b862af176d52292d271c98820199110e31141e"}, + {file = "watchfiles-0.22.0-cp312-none-win_arm64.whl", hash = "sha256:c668228833c5619f6618699a2c12be057711b0ea6396aeaece4ded94184304ea"}, + {file = "watchfiles-0.22.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d47e9ef1a94cc7a536039e46738e17cce058ac1593b2eccdede8bf72e45f372a"}, + {file = "watchfiles-0.22.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:28f393c1194b6eaadcdd8f941307fc9bbd7eb567995232c830f6aef38e8a6e88"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd64f3a4db121bc161644c9e10a9acdb836853155a108c2446db2f5ae1778c3d"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2abeb79209630da981f8ebca30a2c84b4c3516a214451bfc5f106723c5f45843"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4cc382083afba7918e32d5ef12321421ef43d685b9a67cc452a6e6e18920890e"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d048ad5d25b363ba1d19f92dcf29023988524bee6f9d952130b316c5802069cb"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:103622865599f8082f03af4214eaff90e2426edff5e8522c8f9e93dc17caee13"}, + {file = "watchfiles-0.22.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3e1f3cf81f1f823e7874ae563457828e940d75573c8fbf0ee66818c8b6a9099"}, + {file = "watchfiles-0.22.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8597b6f9dc410bdafc8bb362dac1cbc9b4684a8310e16b1ff5eee8725d13dcd6"}, + {file = "watchfiles-0.22.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0b04a2cbc30e110303baa6d3ddce8ca3664bc3403be0f0ad513d1843a41c97d1"}, + {file = "watchfiles-0.22.0-cp38-none-win32.whl", hash = "sha256:b610fb5e27825b570554d01cec427b6620ce9bd21ff8ab775fc3a32f28bba63e"}, + {file = "watchfiles-0.22.0-cp38-none-win_amd64.whl", hash = "sha256:fe82d13461418ca5e5a808a9e40f79c1879351fcaeddbede094028e74d836e86"}, + {file = "watchfiles-0.22.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3973145235a38f73c61474d56ad6199124e7488822f3a4fc97c72009751ae3b0"}, + {file = "watchfiles-0.22.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:280a4afbc607cdfc9571b9904b03a478fc9f08bbeec382d648181c695648202f"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a0d883351a34c01bd53cfa75cd0292e3f7e268bacf2f9e33af4ecede7e21d1d"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9165bcab15f2b6d90eedc5c20a7f8a03156b3773e5fb06a790b54ccecdb73385"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc1b9b56f051209be458b87edb6856a449ad3f803315d87b2da4c93b43a6fe72"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dc1fc25a1dedf2dd952909c8e5cb210791e5f2d9bc5e0e8ebc28dd42fed7562"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc92d2d2706d2b862ce0568b24987eba51e17e14b79a1abcd2edc39e48e743c8"}, + {file = "watchfiles-0.22.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97b94e14b88409c58cdf4a8eaf0e67dfd3ece7e9ce7140ea6ff48b0407a593ec"}, + {file = "watchfiles-0.22.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:96eec15e5ea7c0b6eb5bfffe990fc7c6bd833acf7e26704eb18387fb2f5fd087"}, + {file = "watchfiles-0.22.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:28324d6b28bcb8d7c1041648d7b63be07a16db5510bea923fc80b91a2a6cbed6"}, + {file = "watchfiles-0.22.0-cp39-none-win32.whl", hash = "sha256:8c3e3675e6e39dc59b8fe5c914a19d30029e36e9f99468dddffd432d8a7b1c93"}, + {file = "watchfiles-0.22.0-cp39-none-win_amd64.whl", hash = "sha256:25c817ff2a86bc3de3ed2df1703e3d24ce03479b27bb4527c57e722f8554d971"}, + {file = "watchfiles-0.22.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b810a2c7878cbdecca12feae2c2ae8af59bea016a78bc353c184fa1e09f76b68"}, + {file = "watchfiles-0.22.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f7e1f9c5d1160d03b93fc4b68a0aeb82fe25563e12fbcdc8507f8434ab6f823c"}, + {file = "watchfiles-0.22.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:030bc4e68d14bcad2294ff68c1ed87215fbd9a10d9dea74e7cfe8a17869785ab"}, + {file = "watchfiles-0.22.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace7d060432acde5532e26863e897ee684780337afb775107c0a90ae8dbccfd2"}, + {file = "watchfiles-0.22.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5834e1f8b71476a26df97d121c0c0ed3549d869124ed2433e02491553cb468c2"}, + {file = "watchfiles-0.22.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:0bc3b2f93a140df6806c8467c7f51ed5e55a931b031b5c2d7ff6132292e803d6"}, + {file = "watchfiles-0.22.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8fdebb655bb1ba0122402352b0a4254812717a017d2dc49372a1d47e24073795"}, + {file = "watchfiles-0.22.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c8e0aa0e8cc2a43561e0184c0513e291ca891db13a269d8d47cb9841ced7c71"}, + {file = "watchfiles-0.22.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2f350cbaa4bb812314af5dab0eb8d538481e2e2279472890864547f3fe2281ed"}, + {file = "watchfiles-0.22.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7a74436c415843af2a769b36bf043b6ccbc0f8d784814ba3d42fc961cdb0a9dc"}, + {file = "watchfiles-0.22.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00ad0bcd399503a84cc688590cdffbe7a991691314dde5b57b3ed50a41319a31"}, + {file = "watchfiles-0.22.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72a44e9481afc7a5ee3291b09c419abab93b7e9c306c9ef9108cb76728ca58d2"}, + {file = "watchfiles-0.22.0.tar.gz", hash = "sha256:988e981aaab4f3955209e7e28c7794acdb690be1efa7f16f8ea5aba7ffdadacb"}, +] + +[package.dependencies] +anyio = ">=3.0.0" + [[package]] name = "wcwidth" version = "0.2.13" From 5f73d0524bae377751d145cf3ee440a819cec9d6 Mon Sep 17 00:00:00 2001 From: Roman Zlobin Date: Wed, 19 Jun 2024 17:39:26 +0300 Subject: [PATCH 16/31] update exclude-members with some pydantic fields (#361) Some of technical pydantic fields were still included in the docs. --- docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 4b6769059..3ac5149e3 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -152,7 +152,7 @@ "undoc-members": False, "private-members": True, "member-order": "bysource", - "exclude-members": "_abc_impl, model_fields", + "exclude-members": "_abc_impl, model_fields, model_computed_fields, model_config", } From b5ed32e02d25d0ae2f65ee20f33408adb0b6847a Mon Sep 17 00:00:00 2001 From: ZergLev <64711614+ZergLev@users.noreply.github.com> Date: Wed, 19 Jun 2024 22:00:20 +0500 Subject: [PATCH 17/31] Fix tutorial error and update API reference (#334) Minor fix and updates to 'Tutorials' and 'API reference'. - 'API reference' claimed "wrappers" are a parameter of both classes Pipeline() and Service(), but instead there are "before_handler" and "after_handler", now updated. - For the above reason, replaced term "wrapper" with "extra handler" where appropriate within both tutorials and docs. (user guides required no changes) - Similarly and for the same reasons, references of "services" from class Pipeline() changed to "components" both within docs and tutorials. (user guides required no changes) - In tutorial Script/Core:4.Transitions comments had wrong order of transitions, now fixed. # Checklist - [x] I have performed a self-review of the changes # To Consider - In dff/stats/utils.py there is a function called get_wrapper_field(), but wrappers were changed to extra handlers, I think. Is this intended? - Currently, there are no explanations or links to API within the tutorials as to what ExtraHandlerBuilder and ExtraHandlerFunction objects are. - Search for references to changed entities in the API reference/tutorials/guides --- dff/pipeline/pipeline/pipeline.py | 11 ++++++---- dff/pipeline/pipeline/utils.py | 4 ++-- dff/pipeline/service/extra.py | 5 ++--- dff/pipeline/service/group.py | 14 ++++++------ dff/pipeline/service/service.py | 7 ++++-- dff/pipeline/types.py | 18 +++++++-------- dff/stats/__init__.py | 2 +- dff/stats/default_extractors.py | 6 ++--- dff/stats/instrumentor.py | 4 ++-- dff/stats/utils.py | 3 ++- .../3_pipeline_dict_with_services_basic.py | 8 +++---- .../3_pipeline_dict_with_services_full.py | 22 ++++++++++++++----- .../pipeline/4_groups_and_conditions_basic.py | 4 ++-- .../pipeline/4_groups_and_conditions_full.py | 11 +++++++--- tutorials/script/core/4_transitions.py | 6 ++--- 15 files changed, 73 insertions(+), 52 deletions(-) diff --git a/dff/pipeline/pipeline/pipeline.py b/dff/pipeline/pipeline/pipeline.py index d901a3ebf..1c3e9d456 100644 --- a/dff/pipeline/pipeline/pipeline.py +++ b/dff/pipeline/pipeline/pipeline.py @@ -47,6 +47,9 @@ class Pipeline: Class that automates service execution and creates service pipeline. It accepts constructor parameters: + :param components: (required) A :py:data:`~.ServiceGroupBuilder` object, + that will be transformed to root service group. It should include :py:class:`~.Actor`, + but only once (raises exception otherwise). It will always be named pipeline. :param script: (required) A :py:class:`~.Script` instance (object or dict). :param start_label: (required) Actor start label. :param fallback_label: Actor fallback label. @@ -62,10 +65,10 @@ class Pipeline: :param messenger_interface: An `AbsMessagingInterface` instance for this pipeline. :param context_storage: An :py:class:`~.DBContextStorage` instance for this pipeline or a dict to store dialog :py:class:`~.Context`. - :param services: (required) A :py:data:`~.ServiceGroupBuilder` object, - that will be transformed to root service group. It should include :py:class:`~.Actor`, - but only once (raises exception otherwise). It will always be named pipeline. - :param wrappers: List of wrappers to add to pipeline root service group. + :param before_handler: List of `ExtraHandlerBuilder` to add to the group. + :type before_handler: Optional[:py:data:`~.ExtraHandlerBuilder`] + :param after_handler: List of `ExtraHandlerBuilder` to add to the group. + :type after_handler: Optional[:py:data:`~.ExtraHandlerBuilder`] :param timeout: Timeout to add to pipeline root service group. :param optimization_warnings: Asynchronous pipeline optimization check request flag; warnings will be sent to logs. Additionally it has some calculated fields: diff --git a/dff/pipeline/pipeline/utils.py b/dff/pipeline/pipeline/utils.py index 5da8285a0..752bde18c 100644 --- a/dff/pipeline/pipeline/utils.py +++ b/dff/pipeline/pipeline/utils.py @@ -28,9 +28,9 @@ def pretty_format_component_info_dict( However, most preferable usage is via `pipeline.pretty_format`. :param service: (required) Pipeline components info dictionary. - :param show_wrappers: (required) Whether to include Wrappers or not (could be many and/or generated). + :param show_extra_handlers: (required) Whether to include Extra Handlers or not (could be many and/or generated). :param offset: Current level new line offset. - :param wrappers_key: Key that is mapped to Wrappers lists. + :param extra_handlers_key: Key that is mapped to Extra Handlers lists. :param type_key: Key that is mapped to components type name. :param name_key: Key that is mapped to components name. :param indent: Current level new line offset (whitespace number). diff --git a/dff/pipeline/service/extra.py b/dff/pipeline/service/extra.py index 61ec64d09..caebbd58c 100644 --- a/dff/pipeline/service/extra.py +++ b/dff/pipeline/service/extra.py @@ -114,10 +114,9 @@ async def _run_function( async def _run(self, ctx: Context, pipeline: Pipeline, component_info: ServiceRuntimeInfo): """ - Method for executing one of the wrapper functions (before or after). + Method for executing one of the extra handler functions (before or after). If the function is not set, nothing happens. - :param stage: current `WrapperStage` (before or after). :param ctx: current dialog context. :param pipeline: the current pipeline. :param component_info: associated component's info dictionary. @@ -155,7 +154,7 @@ async def __call__(self, ctx: Context, pipeline: Pipeline, component_info: Servi @property def info_dict(self) -> dict: """ - Property for retrieving info dictionary about this wrapper. + Property for retrieving info dictionary about this extra handler. :return: Info dict, containing its fields as well as its type. All not set fields there are replaced with `None`. diff --git a/dff/pipeline/service/group.py b/dff/pipeline/service/group.py index de7ae0b29..13e412663 100644 --- a/dff/pipeline/service/group.py +++ b/dff/pipeline/service/group.py @@ -102,7 +102,7 @@ def __init__( async def _run_services_group(self, ctx: Context, pipeline: Pipeline) -> None: """ Method for running this service group. - It doesn't include wrappers execution, start condition checking or error handling - pure execution only. + It doesn't include extra handlers execution, start condition checking or error handling - pure execution only. Executes components inside the group based on its `asynchronous` property. Collects information about their execution state - group is finished successfully only if all components in it finished successfully. @@ -137,7 +137,7 @@ async def _run( ) -> None: """ Method for handling this group execution. - Executes before and after execution wrappers, checks start condition and catches runtime exceptions. + Executes extra handlers before and after execution, checks start condition and catches runtime exceptions. :param ctx: Current dialog context. :param pipeline: The current pipeline. @@ -198,13 +198,13 @@ def add_extra_handler( condition: ExtraHandlerConditionFunction = lambda _: True, ): """ - Method for adding a global wrapper to this group. - Adds wrapper to itself and propagates it to all inner components. - Uses a special condition function to determine whether to add wrapper to any particular inner component or not. + Method for adding a global extra handler to this group. + Adds extra handler to itself and propagates it to all inner components. + Uses a special condition function to determine whether to add extra handler to any particular inner component. Condition checks components path to be in whitelist (if defined) and not to be in blacklist (if defined). - :param global_extra_handler_type: A type of wrapper to add. - :param extra_handler: A `WrapperFunction` to add as a wrapper. + :param global_extra_handler_type: A type of extra handler to add. + :param extra_handler: A `ExtraHandlerFunction` to add as an extra handler. :type extra_handler: :py:data:`~.ExtraHandlerFunction` :param condition: A condition function. :return: `None` diff --git a/dff/pipeline/service/service.py b/dff/pipeline/service/service.py index 7359cda8f..c0834fee4 100644 --- a/dff/pipeline/service/service.py +++ b/dff/pipeline/service/service.py @@ -42,7 +42,10 @@ class Service(PipelineComponent): :param handler: A service function or an actor. :type handler: :py:data:`~.ServiceBuilder` - :param wrappers: List of Wrappers to add to the service. + :param before_handler: List of `ExtraHandlerBuilder` to add to the group. + :type before_handler: Optional[:py:data:`~.ExtraHandlerBuilder`] + :param after_handler: List of `ExtraHandlerBuilder` to add to the group. + :type after_handler: Optional[:py:data:`~.ExtraHandlerBuilder`] :param timeout: Timeout to add to the group. :param asynchronous: Requested asynchronous property. :param start_condition: StartConditionCheckerFunction that is invoked before each service execution; @@ -159,7 +162,7 @@ async def _run_as_service(self, ctx: Context, pipeline: Pipeline) -> None: async def _run(self, ctx: Context, pipeline: Pipeline) -> None: """ Method for handling this service execution. - Executes before and after execution wrappers, launches `_run_as_actor` or `_run_as_service` method. + Executes extra handlers before and after execution, launches `_run_as_actor` or `_run_as_service` method. :param ctx: (required) Current dialog context. :param pipeline: the current pipeline. diff --git a/dff/pipeline/types.py b/dff/pipeline/types.py index c26525972..48f93e9cb 100644 --- a/dff/pipeline/types.py +++ b/dff/pipeline/types.py @@ -72,7 +72,7 @@ class ComponentExecutionState(str, Enum): @unique class GlobalExtraHandlerType(str, Enum): """ - Enum, representing types of global wrappers, that can be set applied for a pipeline. + Enum, representing types of global extra handlers, that can be set applied for a pipeline. The following types are supported: - BEFORE_ALL: function called before each pipeline call, @@ -93,9 +93,9 @@ class ExtraHandlerType(str, Enum): Enum, representing wrapper execution stage: before or after the wrapped function. The following types are supported: - - UNDEFINED: wrapper function with undetermined execution stage, - - BEFORE: wrapper function called before component, - - AFTER: wrapper function called after component. + - UNDEFINED: extra handler function with undetermined execution stage, + - BEFORE: extra handler function called before component, + - AFTER: extra handler function called after component. """ UNDEFINED = "UNDEFINED" @@ -126,10 +126,10 @@ class ExtraHandlerType(str, Enum): ExtraHandlerConditionFunction: TypeAlias = Callable[[str], bool] """ -A function type used during global wrappers initialization to determine -whether wrapper should be applied to component with given path or not. +A function type used during global extra handler initialization to determine +whether extra handler should be applied to component with given path or not. Checks components path to be in whitelist (if defined) and not to be in blacklist (if defined). -Accepts str (component path), returns boolean (whether wrapper should be applied). +Accepts str (component path), returns boolean (whether extra handler should be applied). """ @@ -154,8 +154,8 @@ class ServiceRuntimeInfo(BaseModel): Callable[[Context, "Pipeline", "ExtraHandlerRuntimeInfo"], Any], ] """ -A function type for creating wrappers (before and after functions). -Can accept current dialog context, pipeline, and current wrapper info. +A function type for creating extra handler (before and after functions). +Can accept current dialog context, pipeline, and current extra handler info. """ diff --git a/dff/stats/__init__.py b/dff/stats/__init__.py index a93d7dbf8..0ef77234e 100644 --- a/dff/stats/__init__.py +++ b/dff/stats/__init__.py @@ -4,5 +4,5 @@ from opentelemetry.sdk.trace.export import ConsoleSpanExporter from opentelemetry.sdk._logs.export import InMemoryLogExporter, ConsoleLogExporter from opentelemetry.sdk.metrics.export import InMemoryMetricReader, ConsoleMetricExporter -from .utils import get_wrapper_field, set_logger_destination, set_tracer_destination +from .utils import get_extra_handler_name, set_logger_destination, set_tracer_destination from .instrumentor import OtelInstrumentor, OTLPMetricExporter, OTLPLogExporter, OTLPSpanExporter diff --git a/dff/stats/default_extractors.py b/dff/stats/default_extractors.py index d9667d4a6..aac41b112 100644 --- a/dff/stats/default_extractors.py +++ b/dff/stats/default_extractors.py @@ -15,7 +15,7 @@ from dff.script import Context from dff.pipeline import ExtraHandlerRuntimeInfo, Pipeline -from .utils import get_wrapper_field +from .utils import get_extra_handler_name async def get_current_label(ctx: Context, pipeline: Pipeline, info: ExtraHandlerRuntimeInfo): @@ -44,7 +44,7 @@ async def get_timing_before(ctx: Context, _, info: ExtraHandlerRuntimeInfo): to the context storage. """ start_time = datetime.now() - ctx.framework_states[get_wrapper_field(info, "time")] = start_time + ctx.framework_states[get_extra_handler_name(info, "time")] = start_time async def get_timing_after(ctx: Context, _, info: ExtraHandlerRuntimeInfo): # noqa: F811 @@ -56,7 +56,7 @@ async def get_timing_after(ctx: Context, _, info: ExtraHandlerRuntimeInfo): # n As a result, the function output is cleared on every turn and does not get persisted to the context storage. """ - start_time = ctx.framework_states[get_wrapper_field(info, "time")] + start_time = ctx.framework_states[get_extra_handler_name(info, "time")] data = {"execution_time": str(datetime.now() - start_time)} return data diff --git a/dff/stats/instrumentor.py b/dff/stats/instrumentor.py index 5106820bb..30f7cd20f 100644 --- a/dff/stats/instrumentor.py +++ b/dff/stats/instrumentor.py @@ -29,7 +29,7 @@ from dff.script.core.context import get_last_index from dff.stats.utils import ( resource, - get_wrapper_field, + get_extra_handler_name, set_logger_destination, set_meter_destination, set_tracer_destination, @@ -158,7 +158,7 @@ async def __call__(self, wrapped, _, args, kwargs): :param kwargs: Keyword arguments of the decorated function. """ ctx, _, info = args - pipeline_component = get_wrapper_field(info) + pipeline_component = get_extra_handler_name(info) attributes = { "context_id": str(ctx.id), "request_id": get_last_index(ctx.requests), diff --git a/dff/stats/utils.py b/dff/stats/utils.py index f0149bcb3..7e2152ccd 100644 --- a/dff/stats/utils.py +++ b/dff/stats/utils.py @@ -89,7 +89,7 @@ def set_tracer_destination(exporter: Optional[SpanExporter] = None): get_tracer_provider().add_span_processor(BatchSpanProcessor(exporter)) -def get_wrapper_field(info: ExtraHandlerRuntimeInfo, postfix: str = "") -> str: +def get_extra_handler_name(info: ExtraHandlerRuntimeInfo, postfix: str = "") -> str: """ This function can be used to obtain a key, under which the wrapper data will be stored in the context. @@ -97,6 +97,7 @@ def get_wrapper_field(info: ExtraHandlerRuntimeInfo, postfix: str = "") -> str: :param info: Handler runtime info obtained from the pipeline. :param postfix: Field-specific postfix that will be appended to the field name. """ + path = info.component.path.replace(".", "-") return f"{path}" + (f"-{postfix}" if postfix else "") diff --git a/tutorials/pipeline/3_pipeline_dict_with_services_basic.py b/tutorials/pipeline/3_pipeline_dict_with_services_basic.py index 131b62523..fbdfbcee6 100644 --- a/tutorials/pipeline/3_pipeline_dict_with_services_basic.py +++ b/tutorials/pipeline/3_pipeline_dict_with_services_basic.py @@ -33,16 +33,16 @@ """ When Pipeline is created using `from_dict` method, pipeline should be defined as a dictionary. -It should contain `services` - a `ServiceGroupBuilder` object, +It should contain `components` - a `ServiceGroupBuilder` object, basically a list of `ServiceBuilder` or `ServiceGroupBuilder` objects, see tutorial 4. -On pipeline execution services from `services` +On pipeline execution services from `components` list are run without difference between pre- and postprocessors. Actor constant "ACTOR" is required to be passed as one of the services. -ServiceBuilder object can be defined either with callable +`ServiceBuilder` object can be defined either with callable (see tutorial 2) or with dict / object. -It should contain `handler` - a ServiceBuilder object. +It should contain `handler` - a `ServiceBuilder` object. Not only Pipeline can be run using `__call__` method, for most cases `run` method should be used. diff --git a/tutorials/pipeline/3_pipeline_dict_with_services_full.py b/tutorials/pipeline/3_pipeline_dict_with_services_full.py index e24999ab9..0503d12a2 100644 --- a/tutorials/pipeline/3_pipeline_dict_with_services_full.py +++ b/tutorials/pipeline/3_pipeline_dict_with_services_full.py @@ -43,20 +43,25 @@ is used to connect to channel and transfer IO to user. * `context_storage` - Place to store dialog contexts (dictionary or a `DBContextStorage` instance). -* `services` (required) - A `ServiceGroupBuilder` object, +* `components` (required) - A `ServiceGroupBuilder` object, basically a list of `ServiceBuilder` or `ServiceGroupBuilder` objects, see tutorial 4. -* `wrappers` - A list of pipeline wrappers, see tutorial 7. +* `before_handler` - a list of `ExtraHandlerFunction` objects, + `ExtraHandlerBuilder` objects and lists of them. + See tutorials 6 and 7. +* `after_handler` - a list of `ExtraHandlerFunction` objects, + `ExtraHandlerBuilder` objects and lists of them. + See tutorials 6 and 7. * `timeout` - Pipeline timeout, see tutorial 5. * `optimization_warnings` - Whether pipeline asynchronous structure should be checked during initialization, see tutorial 5. -On pipeline execution services from `services` list are run +On pipeline execution services from `components` list are run without difference between pre- and postprocessors. -If "ACTOR" constant is not found among `services` pipeline creation fails. +If "ACTOR" constant is not found among `components` pipeline creation fails. There can be only one "ACTOR" constant in the pipeline. -ServiceBuilder object can be defined either with callable (see tutorial 2) or +`ServiceBuilder` object can be defined either with callable (see tutorial 2) or with dict of structure / object with following constructor arguments: * `handler` (required) - ServiceBuilder, @@ -64,7 +69,12 @@ it will be used instead of base ServiceBuilder. NB! Fields of nested ServiceBuilder will be overridden by defined fields of the base ServiceBuilder. -* `wrappers` - a list of service wrappers, see tutorial 7. +* `before_handler` - a list of `ExtraHandlerFunction` objects, + `ExtraHandlerBuilder` objects and lists of them. + See tutorials 6 and 7. +* `after_handler` - a list of `ExtraHandlerFunction` objects, + `ExtraHandlerBuilder` objects and lists of them. + See tutorials 6 and 7. * `timeout` - service timeout, see tutorial 5. * `asynchronous` - whether or not this service _should_ be asynchronous (keep in mind that not all services _can_ be asynchronous), diff --git a/tutorials/pipeline/4_groups_and_conditions_basic.py b/tutorials/pipeline/4_groups_and_conditions_basic.py index 18b4527b5..dbaa7d738 100644 --- a/tutorials/pipeline/4_groups_and_conditions_basic.py +++ b/tutorials/pipeline/4_groups_and_conditions_basic.py @@ -39,8 +39,8 @@ Pipeline can contain not only single services, but also service groups. Service groups can be defined as `ServiceGroupBuilder` objects: lists of `ServiceBuilders` and `ServiceGroupBuilders` or objects. -The objects should contain `services` - -a ServiceBuilder and ServiceGroupBuilder object list. +The objects should contain `components` - +a `ServiceBuilder` and `ServiceGroupBuilder` object list. To receive serialized information about service, service group or pipeline a property `info_dict` can be used, diff --git a/tutorials/pipeline/4_groups_and_conditions_full.py b/tutorials/pipeline/4_groups_and_conditions_full.py index f899b47af..177075352 100644 --- a/tutorials/pipeline/4_groups_and_conditions_full.py +++ b/tutorials/pipeline/4_groups_and_conditions_full.py @@ -44,9 +44,14 @@ Alternatively, the groups can be defined as objects with following constructor arguments: -* `components` (required) - A list of ServiceBuilder objects, - ServiceGroup objects and lists of them. -* `wrappers` - A list of pipeline wrappers, see tutorial 7. +* `components` (required) - A list of `ServiceBuilder` objects, + `ServiceGroupBuilder` objects and lists of them. +* `before_handler` - a list of `ExtraHandlerFunction` objects, + `ExtraHandlerBuilder` objects and lists of them. + See tutorials 6 and 7. +* `after_handler` - a list of `ExtraHandlerFunction` objects, + `ExtraHandlerBuilder` objects and lists of them. + See tutorials 6 and 7. * `timeout` - Pipeline timeout, see tutorial 5. * `asynchronous` - Whether or not this service group _should_ be asynchronous (keep in mind that not all service groups _can_ be asynchronous), diff --git a/tutorials/script/core/4_transitions.py b/tutorials/script/core/4_transitions.py index 250cd0d23..8acf16143 100644 --- a/tutorials/script/core/4_transitions.py +++ b/tutorials/script/core/4_transitions.py @@ -154,10 +154,10 @@ def transition(_: Context, __: Pipeline) -> ConstLabel: "node2": { RESPONSE: Message("Good. What do you want to talk about?"), TRANSITIONS: { - lbl.to_fallback(0.1): cnd.true(), # third check + lbl.to_fallback(0.1): cnd.true(), # fourth check # lbl.to_fallback(0.1) is equivalent # to ("global_flow", "fallback_node", 0.1) - lbl.forward(0.5): cnd.regexp(r"talk about"), # second check + lbl.forward(0.5): cnd.regexp(r"talk about"), # third check # lbl.forward(0.5) is equivalent # to ("greeting_flow", "node3", 0.5) ("music_flow", "node1"): cnd.regexp( @@ -167,7 +167,7 @@ def transition(_: Context, __: Pipeline) -> ConstLabel: # to ("music_flow", "node1", 1.0) lbl.previous(): cnd.regexp( r"previous", re.IGNORECASE - ), # third check + ), # second check }, }, "node3": { From 4c087cf82f24163a6b89cefd5fffa803204eeba9 Mon Sep 17 00:00:00 2001 From: ZergLev <64711614+ZergLev@users.noreply.github.com> Date: Wed, 19 Jun 2024 22:01:21 +0500 Subject: [PATCH 18/31] Make functions accept str along with Message (#337) # Description - Made `dff.script.conditions.exact_match` and `dff.utils.testing.common.check_happy_path` accept `str` along with `Message` - Tests added for `exact_match()`, but not for `check_happy_path()`. - Changed all instances of `exact_match(Message("some text"))` to `exact_match("some text")` # Checklist - [x] I have performed a self-review of the changes # To Consider - Update tutorials / guides --------- Co-authored-by: Roman Zlobin --- README.md | 2 +- dff/script/conditions/std_conditions.py | 10 ++- dff/utils/testing/common.py | 10 ++- dff/utils/testing/toy_script.py | 74 ++++++++-------- docs/source/user_guides/basic_conceptions.rst | 16 ++-- tests/pipeline/test_messenger_interface.py | 6 +- tests/script/conditions/test_conditions.py | 22 ++--- tests/tutorials/test_utils.py | 3 +- tutorials/messengers/telegram/1_basic.py | 4 +- tutorials/script/core/1_basics.py | 52 +++++------ tutorials/script/core/2_conditions.py | 46 +++++----- tutorials/script/core/3_responses.py | 46 +++++----- tutorials/script/core/4_transitions.py | 87 ++++++++----------- tutorials/script/core/5_global_transitions.py | 87 ++++++++----------- .../script/core/6_context_serialization.py | 8 +- .../script/core/7_pre_response_processing.py | 15 ++-- tutorials/script/core/8_misc.py | 60 +++++-------- .../core/9_pre_transitions_processing.py | 10 +-- tutorials/script/responses/1_basics.py | 16 ++-- tutorials/script/responses/4_multi_message.py | 16 ++-- tutorials/utils/1_cache.py | 6 +- tutorials/utils/2_lru_cache.py | 6 +- 22 files changed, 277 insertions(+), 325 deletions(-) diff --git a/README.md b/README.md index 2afa8b3ae..6b54cf43f 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ import dff.script.conditions.std_conditions as cnd script = { GLOBAL: { TRANSITIONS: { - ("flow", "node_hi"): cnd.exact_match(Message("Hi")), + ("flow", "node_hi"): cnd.exact_match("Hi"), ("flow", "node_ok"): cnd.true() } }, diff --git a/dff/script/conditions/std_conditions.py b/dff/script/conditions/std_conditions.py index 88c086ab4..56cbc1ef9 100644 --- a/dff/script/conditions/std_conditions.py +++ b/dff/script/conditions/std_conditions.py @@ -22,18 +22,22 @@ @validate_call -def exact_match(match: Message, skip_none: bool = True) -> Callable[[Context, Pipeline], bool]: +def exact_match(match: Union[str, Message], skip_none: bool = True) -> Callable[[Context, Pipeline], bool]: """ Return function handler. This handler returns `True` only if the last user phrase - is the same Message as the `match`. + is the same `Message` as the `match`. If `skip_none` the handler will not compare `None` fields of `match`. - :param match: A Message variable to compare user request with. + :param match: A `Message` variable to compare user request with. + Can also accept `str`, which will be converted into a `Message` with its text field equal to `match`. :param skip_none: Whether fields should be compared if they are `None` in :py:const:`match`. """ def exact_match_condition_handler(ctx: Context, pipeline: Pipeline) -> bool: request = ctx.last_request + nonlocal match + if isinstance(match, str): + match = Message(text=match) if request is None: return False for field in match.model_fields: diff --git a/dff/utils/testing/common.py b/dff/utils/testing/common.py index b89621044..77310b2b6 100644 --- a/dff/utils/testing/common.py +++ b/dff/utils/testing/common.py @@ -5,7 +5,7 @@ """ from os import getenv -from typing import Callable, Tuple, Optional +from typing import Callable, Tuple, Optional, Union from uuid import uuid4 from dff.script import Context, Message @@ -32,7 +32,7 @@ def is_interactive_mode() -> bool: # pragma: no cover def check_happy_path( pipeline: Pipeline, - happy_path: Tuple[Tuple[Message, Message], ...], + happy_path: Tuple[Tuple[Union[str, Message], Union[str, Message]], ...], # This optional argument is used for additional processing of candidate responses and reference responses response_comparer: Callable[[Message, Message, Context], Optional[str]] = default_comparer, printout_enable: bool = True, @@ -51,7 +51,11 @@ def check_happy_path( """ ctx_id = uuid4() # get random ID for current context - for step_id, (request, reference_response) in enumerate(happy_path): + for step_id, (request_raw, reference_response_raw) in enumerate(happy_path): + request = Message(text=request_raw) if isinstance(request_raw, str) else request_raw + reference_response = ( + Message(text=reference_response_raw) if isinstance(reference_response_raw, str) else reference_response_raw + ) ctx = pipeline(request, ctx_id) candidate_response = ctx.last_response if printout_enable: diff --git a/dff/utils/testing/toy_script.py b/dff/utils/testing/toy_script.py index dfcd7594e..ee56a7ecf 100644 --- a/dff/utils/testing/toy_script.py +++ b/dff/utils/testing/toy_script.py @@ -12,24 +12,24 @@ "greeting_flow": { "start_node": { RESPONSE: Message(), - TRANSITIONS: {"node1": exact_match(Message("Hi"))}, + TRANSITIONS: {"node1": exact_match("Hi")}, }, "node1": { RESPONSE: Message("Hi, how are you?"), - TRANSITIONS: {"node2": exact_match(Message("i'm fine, how are you?"))}, + TRANSITIONS: {"node2": exact_match("i'm fine, how are you?")}, }, "node2": { RESPONSE: Message("Good. What do you want to talk about?"), - TRANSITIONS: {"node3": exact_match(Message("Let's talk about music."))}, + TRANSITIONS: {"node3": exact_match("Let's talk about music.")}, }, "node3": { RESPONSE: Message("Sorry, I can not talk about music now."), - TRANSITIONS: {"node4": exact_match(Message("Ok, goodbye."))}, + TRANSITIONS: {"node4": exact_match("Ok, goodbye.")}, }, - "node4": {RESPONSE: Message("bye"), TRANSITIONS: {"node1": exact_match(Message("Hi"))}}, + "node4": {RESPONSE: Message("bye"), TRANSITIONS: {"node1": exact_match("Hi")}}, "fallback_node": { RESPONSE: Message("Ooops"), - TRANSITIONS: {"node1": exact_match(Message("Hi"))}, + TRANSITIONS: {"node1": exact_match("Hi")}, }, } } @@ -52,11 +52,11 @@ """ HAPPY_PATH = ( - (Message("Hi"), Message("Hi, how are you?")), - (Message("i'm fine, how are you?"), Message("Good. What do you want to talk about?")), - (Message("Let's talk about music."), Message("Sorry, I can not talk about music now.")), - (Message("Ok, goodbye."), Message("bye")), - (Message("Hi"), Message("Hi, how are you?")), + ("Hi", "Hi, how are you?"), + ("i'm fine, how are you?", "Good. What do you want to talk about?"), + ("Let's talk about music.", "Sorry, I can not talk about music now."), + ("Ok, goodbye.", "bye"), + ("Hi", "Hi, how are you?"), ) """ An example of a simple dialog. @@ -69,10 +69,10 @@ "start": { RESPONSE: Message("Hi"), TRANSITIONS: { - ("small_talk", "ask_some_questions"): exact_match(Message("hi")), - ("animals", "have_pets"): exact_match(Message("i like animals")), - ("animals", "like_animals"): exact_match(Message("let's talk about animals")), - ("news", "what_news"): exact_match(Message("let's talk about news")), + ("small_talk", "ask_some_questions"): exact_match("hi"), + ("animals", "have_pets"): exact_match("i like animals"), + ("animals", "like_animals"): exact_match("let's talk about animals"), + ("news", "what_news"): exact_match("let's talk about news"), }, }, "fallback": {RESPONSE: Message("Oops")}, @@ -80,26 +80,26 @@ "animals": { "have_pets": { RESPONSE: Message("do you have pets?"), - TRANSITIONS: {"what_animal": exact_match(Message("yes"))}, + TRANSITIONS: {"what_animal": exact_match("yes")}, }, "like_animals": { RESPONSE: Message("do you like it?"), - TRANSITIONS: {"what_animal": exact_match(Message("yes"))}, + TRANSITIONS: {"what_animal": exact_match("yes")}, }, "what_animal": { RESPONSE: Message("what animals do you have?"), TRANSITIONS: { - "ask_about_color": exact_match(Message("bird")), - "ask_about_breed": exact_match(Message("dog")), + "ask_about_color": exact_match("bird"), + "ask_about_breed": exact_match("dog"), }, }, "ask_about_color": {RESPONSE: Message("what color is it")}, "ask_about_breed": { RESPONSE: Message("what is this breed?"), TRANSITIONS: { - "ask_about_breed": exact_match(Message("pereat")), - "tell_fact_about_breed": exact_match(Message("bulldog")), - "ask_about_training": exact_match(Message("I don't know")), + "ask_about_breed": exact_match("pereat"), + "tell_fact_about_breed": exact_match("bulldog"), + "ask_about_training": exact_match("I don't know"), }, }, "tell_fact_about_breed": { @@ -111,36 +111,36 @@ "what_news": { RESPONSE: Message("what kind of news do you prefer?"), TRANSITIONS: { - "ask_about_science": exact_match(Message("science")), - "ask_about_sport": exact_match(Message("sport")), + "ask_about_science": exact_match("science"), + "ask_about_sport": exact_match("sport"), }, }, "ask_about_science": { RESPONSE: Message("i got news about science, do you want to hear?"), TRANSITIONS: { - "science_news": exact_match(Message("yes")), - ("small_talk", "ask_some_questions"): exact_match(Message("let's change the topic")), + "science_news": exact_match("yes"), + ("small_talk", "ask_some_questions"): exact_match("let's change the topic"), }, }, "science_news": { RESPONSE: Message("This is science news"), TRANSITIONS: { - "what_news": exact_match(Message("ok")), - ("small_talk", "ask_some_questions"): exact_match(Message("let's change the topic")), + "what_news": exact_match("ok"), + ("small_talk", "ask_some_questions"): exact_match("let's change the topic"), }, }, "ask_about_sport": { RESPONSE: Message("i got news about sport, do you want to hear?"), TRANSITIONS: { - "sport_news": exact_match(Message("yes")), - ("small_talk", "ask_some_questions"): exact_match(Message("let's change the topic")), + "sport_news": exact_match("yes"), + ("small_talk", "ask_some_questions"): exact_match("let's change the topic"), }, }, "sport_news": { RESPONSE: Message("This is sport news"), TRANSITIONS: { - "what_news": exact_match(Message("ok")), - ("small_talk", "ask_some_questions"): exact_match(Message("let's change the topic")), + "what_news": exact_match("ok"), + ("small_talk", "ask_some_questions"): exact_match("let's change the topic"), }, }, }, @@ -148,16 +148,16 @@ "ask_some_questions": { RESPONSE: Message("how are you"), TRANSITIONS: { - "ask_talk_about": exact_match(Message("fine")), - ("animals", "like_animals"): exact_match(Message("let's talk about animals")), - ("news", "what_news"): exact_match(Message("let's talk about news")), + "ask_talk_about": exact_match("fine"), + ("animals", "like_animals"): exact_match("let's talk about animals"), + ("news", "what_news"): exact_match("let's talk about news"), }, }, "ask_talk_about": { RESPONSE: Message("what do you want to talk about"), TRANSITIONS: { - ("animals", "like_animals"): exact_match(Message("dog")), - ("news", "what_news"): exact_match(Message("let's talk about news")), + ("animals", "like_animals"): exact_match("dog"), + ("news", "what_news"): exact_match("let's talk about news"), }, }, }, diff --git a/docs/source/user_guides/basic_conceptions.rst b/docs/source/user_guides/basic_conceptions.rst index 515b4ff49..f1a819f6e 100644 --- a/docs/source/user_guides/basic_conceptions.rst +++ b/docs/source/user_guides/basic_conceptions.rst @@ -89,14 +89,14 @@ Example flow & script RESPONSE: Message(), # the response of the initial node is skipped TRANSITIONS: { ("greeting_flow", "greeting_node"): - cnd.exact_match(Message("/start")), + cnd.exact_match("/start"), }, }, "greeting_node": { RESPONSE: Message("Hi!"), TRANSITIONS: { ("ping_pong_flow", "game_start_node"): - cnd.exact_match(Message("Hello!")) + cnd.exact_match("Hello!") } }, "fallback_node": { @@ -111,14 +111,14 @@ Example flow & script RESPONSE: Message("Let's play ping-pong!"), TRANSITIONS: { ("ping_pong_flow", "response_node"): - cnd.exact_match(Message("Ping!")), + cnd.exact_match("Ping!"), }, }, "response_node": { RESPONSE: Message("Pong!"), TRANSITIONS: { ("ping_pong_flow", "response_node"): - cnd.exact_match(Message("Ping!")), + cnd.exact_match("Ping!"), }, }, }, @@ -289,9 +289,9 @@ conversational service. .. code-block:: python happy_path = ( - (Message("/start"), Message("Hi!")), - (Message("Hello!"), Message("Let's play ping-pong!")), - (Message("Ping!"), Message("Pong!")) + ("/start", "Hi!"), + ("Hello!", "Let's play ping-pong!"), + ("Ping!", "Pong!") ) A special function is then used to ascertain complete identity of the messages taken from @@ -384,4 +384,4 @@ Further reading * `Guide on Context <../user_guides/context_guide.html>`_ * `Tutorial on global transitions <../tutorials/tutorials.script.core.5_global_transitions.html>`_ * `Tutorial on context serialization <../tutorials/tutorials.script.core.6_context_serialization.html>`_ -* `Tutorial on script MISC <../tutorials/tutorials.script.core.8_misc.html>`_ \ No newline at end of file +* `Tutorial on script MISC <../tutorials/tutorials.script.core.8_misc.html>`_ diff --git a/tests/pipeline/test_messenger_interface.py b/tests/pipeline/test_messenger_interface.py index 855efeb96..c85384b09 100644 --- a/tests/pipeline/test_messenger_interface.py +++ b/tests/pipeline/test_messenger_interface.py @@ -13,19 +13,19 @@ RESPONSE: { "text": "", }, - TRANSITIONS: {"node1": cnd.exact_match(Message("Ping"))}, + TRANSITIONS: {"node1": cnd.exact_match("Ping")}, }, "node1": { RESPONSE: { "text": "Pong", }, - TRANSITIONS: {"node1": cnd.exact_match(Message("Ping"))}, + TRANSITIONS: {"node1": cnd.exact_match("Ping")}, }, "fallback_node": { RESPONSE: { "text": "Ooops", }, - TRANSITIONS: {"node1": cnd.exact_match(Message("Ping"))}, + TRANSITIONS: {"node1": cnd.exact_match("Ping")}, }, } } diff --git a/tests/script/conditions/test_conditions.py b/tests/script/conditions/test_conditions.py index ab85df16a..60035c728 100644 --- a/tests/script/conditions/test_conditions.py +++ b/tests/script/conditions/test_conditions.py @@ -14,12 +14,14 @@ def test_conditions(): failed_ctx.add_label(label) pipeline = Pipeline.from_script(script={"flow": {"node": {}}}, start_label=("flow", "node")) - assert cnd.exact_match(Message("text"))(ctx, pipeline) + assert cnd.exact_match("text")(ctx, pipeline) assert cnd.exact_match(Message("text", misc={}))(ctx, pipeline) assert not cnd.exact_match(Message("text", misc={1: 1}))(ctx, pipeline) - assert not cnd.exact_match(Message("text1"))(ctx, pipeline) + assert not cnd.exact_match("text1")(ctx, pipeline) assert cnd.exact_match(Message())(ctx, pipeline) assert not cnd.exact_match(Message(), skip_none=False)(ctx, pipeline) + assert cnd.exact_match("text")(ctx, pipeline) + assert not cnd.exact_match("text1")(ctx, pipeline) assert cnd.has_text("text")(ctx, pipeline) assert cnd.has_text("te")(ctx, pipeline) @@ -30,17 +32,17 @@ def test_conditions(): assert not cnd.regexp("t.*t1")(ctx, pipeline) assert not cnd.regexp("t.*t1")(failed_ctx, pipeline) - assert cnd.agg([cnd.regexp("t.*t"), cnd.exact_match(Message("text"))], aggregate_func=all)(ctx, pipeline) - assert not cnd.agg([cnd.regexp("t.*t1"), cnd.exact_match(Message("text"))], aggregate_func=all)(ctx, pipeline) + assert cnd.agg([cnd.regexp("t.*t"), cnd.exact_match("text")], aggregate_func=all)(ctx, pipeline) + assert not cnd.agg([cnd.regexp("t.*t1"), cnd.exact_match("text")], aggregate_func=all)(ctx, pipeline) - assert cnd.any([cnd.regexp("t.*t1"), cnd.exact_match(Message("text"))])(ctx, pipeline) - assert not cnd.any([cnd.regexp("t.*t1"), cnd.exact_match(Message("text1"))])(ctx, pipeline) + assert cnd.any([cnd.regexp("t.*t1"), cnd.exact_match("text")])(ctx, pipeline) + assert not cnd.any([cnd.regexp("t.*t1"), cnd.exact_match("text1")])(ctx, pipeline) - assert cnd.all([cnd.regexp("t.*t"), cnd.exact_match(Message("text"))])(ctx, pipeline) - assert not cnd.all([cnd.regexp("t.*t1"), cnd.exact_match(Message("text"))])(ctx, pipeline) + assert cnd.all([cnd.regexp("t.*t"), cnd.exact_match("text")])(ctx, pipeline) + assert not cnd.all([cnd.regexp("t.*t1"), cnd.exact_match("text")])(ctx, pipeline) - assert cnd.neg(cnd.exact_match(Message("text1")))(ctx, pipeline) - assert not cnd.neg(cnd.exact_match(Message("text")))(ctx, pipeline) + assert cnd.neg(cnd.exact_match("text1"))(ctx, pipeline) + assert not cnd.neg(cnd.exact_match("text"))(ctx, pipeline) assert cnd.has_last_labels(flow_labels=["flow"])(ctx, pipeline) assert not cnd.has_last_labels(flow_labels=["flow1"])(ctx, pipeline) diff --git a/tests/tutorials/test_utils.py b/tests/tutorials/test_utils.py index 2ed14aa6b..55fd5aae4 100644 --- a/tests/tutorials/test_utils.py +++ b/tests/tutorials/test_utils.py @@ -2,14 +2,13 @@ import re import pytest -from dff.script import Message from dff.utils.testing.common import check_happy_path, is_interactive_mode from tests.pipeline.test_messenger_interface import pipeline def test_unhappy_path(): with pytest.raises(Exception) as e: - check_happy_path(pipeline, ((Message("Hi"), Message("false_response")),)) + check_happy_path(pipeline, (("Hi", "false_response"),)) assert e msg = str(e) assert msg diff --git a/tutorials/messengers/telegram/1_basic.py b/tutorials/messengers/telegram/1_basic.py index 5f633c500..7d804eafe 100644 --- a/tutorials/messengers/telegram/1_basic.py +++ b/tutorials/messengers/telegram/1_basic.py @@ -44,7 +44,7 @@ class and [telebot](https://pytba.readthedocs.io/en/latest/index.html) script = { "greeting_flow": { "start_node": { - TRANSITIONS: {"greeting_node": cnd.exact_match(Message("/start"))}, + TRANSITIONS: {"greeting_node": cnd.exact_match("/start")}, }, "greeting_node": { RESPONSE: Message("Hi"), @@ -52,7 +52,7 @@ class and [telebot](https://pytba.readthedocs.io/en/latest/index.html) }, "fallback_node": { RESPONSE: Message("Please, repeat the request"), - TRANSITIONS: {"greeting_node": cnd.exact_match(Message("/start"))}, + TRANSITIONS: {"greeting_node": cnd.exact_match("/start")}, }, } } diff --git a/tutorials/script/core/1_basics.py b/tutorials/script/core/1_basics.py index b53c3b352..dc9314686 100644 --- a/tutorials/script/core/1_basics.py +++ b/tutorials/script/core/1_basics.py @@ -57,7 +57,7 @@ "start_node": { # This is the initial node, # it doesn't contain a `RESPONSE`. RESPONSE: Message(), - TRANSITIONS: {"node1": cnd.exact_match(Message("Hi"))}, + TRANSITIONS: {"node1": cnd.exact_match("Hi")}, # If "Hi" == request of the user then we make the transition. }, "node1": { @@ -65,29 +65,25 @@ text="Hi, how are you?" ), # When the agent enters node1, # return "Hi, how are you?". - TRANSITIONS: { - "node2": cnd.exact_match(Message("I'm fine, how are you?")) - }, + TRANSITIONS: {"node2": cnd.exact_match("I'm fine, how are you?")}, }, "node2": { RESPONSE: Message("Good. What do you want to talk about?"), - TRANSITIONS: { - "node3": cnd.exact_match(Message("Let's talk about music.")) - }, + TRANSITIONS: {"node3": cnd.exact_match("Let's talk about music.")}, }, "node3": { RESPONSE: Message("Sorry, I can not talk about music now."), - TRANSITIONS: {"node4": cnd.exact_match(Message("Ok, goodbye."))}, + TRANSITIONS: {"node4": cnd.exact_match("Ok, goodbye.")}, }, "node4": { RESPONSE: Message("Bye"), - TRANSITIONS: {"node1": cnd.exact_match(Message("Hi"))}, + TRANSITIONS: {"node1": cnd.exact_match("Hi")}, }, "fallback_node": { # We get to this node if the conditions # for switching to other nodes are not performed. RESPONSE: Message("Ooops"), - TRANSITIONS: {"node1": cnd.exact_match(Message("Hi"))}, + TRANSITIONS: {"node1": cnd.exact_match("Hi")}, }, } } @@ -95,37 +91,37 @@ happy_path = ( ( - Message("Hi"), - Message("Hi, how are you?"), + "Hi", + "Hi, how are you?", ), # start_node -> node1 ( - Message("I'm fine, how are you?"), - Message("Good. What do you want to talk about?"), + "I'm fine, how are you?", + "Good. What do you want to talk about?", ), # node1 -> node2 ( - Message("Let's talk about music."), - Message("Sorry, I can not talk about music now."), + "Let's talk about music.", + "Sorry, I can not talk about music now.", ), # node2 -> node3 - (Message("Ok, goodbye."), Message("Bye")), # node3 -> node4 - (Message("Hi"), Message("Hi, how are you?")), # node4 -> node1 - (Message("stop"), Message("Ooops")), # node1 -> fallback_node + ("Ok, goodbye.", "Bye"), # node3 -> node4 + ("Hi", "Hi, how are you?"), # node4 -> node1 + ("stop", "Ooops"), # node1 -> fallback_node ( - Message("stop"), - Message("Ooops"), + "stop", + "Ooops", ), # fallback_node -> fallback_node ( - Message("Hi"), - Message("Hi, how are you?"), + "Hi", + "Hi, how are you?", ), # fallback_node -> node1 ( - Message("I'm fine, how are you?"), - Message("Good. What do you want to talk about?"), + "I'm fine, how are you?", + "Good. What do you want to talk about?", ), # node1 -> node2 ( - Message("Let's talk about music."), - Message("Sorry, I can not talk about music now."), + "Let's talk about music.", + "Sorry, I can not talk about music now.", ), # node2 -> node3 - (Message("Ok, goodbye."), Message("Bye")), # node3 -> node4 + ("Ok, goodbye.", "Bye"), # node3 -> node4 ) diff --git a/tutorials/script/core/2_conditions.py b/tutorials/script/core/2_conditions.py index 95e96c14f..d4ecc0bcd 100644 --- a/tutorials/script/core/2_conditions.py +++ b/tutorials/script/core/2_conditions.py @@ -107,7 +107,7 @@ def internal_condition_function(ctx: Context, _: Pipeline) -> bool: "start_node": { # This is the initial node, # it doesn't contain a `RESPONSE`. RESPONSE: Message(), - TRANSITIONS: {"node1": cnd.exact_match(Message("Hi"))}, + TRANSITIONS: {"node1": cnd.exact_match("Hi")}, # If "Hi" == request of user then we make the transition }, "node1": { @@ -137,7 +137,7 @@ def internal_condition_function(ctx: Context, _: Pipeline) -> bool: "node1": cnd.any( [ hi_lower_case_condition, - cnd.exact_match(Message("hello")), + cnd.exact_match("hello"), ] ) }, @@ -170,45 +170,45 @@ def internal_condition_function(ctx: Context, _: Pipeline) -> bool: # testing happy_path = ( ( - Message("Hi"), - Message("Hi, how are you?"), + "Hi", + "Hi, how are you?", ), # start_node -> node1 ( - Message("i'm fine, how are you?"), - Message("Good. What do you want to talk about?"), + "i'm fine, how are you?", + "Good. What do you want to talk about?", ), # node1 -> node2 ( - Message("Let's talk about music."), - Message("Sorry, I can not talk about music now."), + "Let's talk about music.", + "Sorry, I can not talk about music now.", ), # node2 -> node3 - (Message("Ok, goodbye."), Message("bye")), # node3 -> node4 - (Message("Hi"), Message("Hi, how are you?")), # node4 -> node1 - (Message("stop"), Message("Ooops")), # node1 -> fallback_node + ("Ok, goodbye.", "bye"), # node3 -> node4 + ("Hi", "Hi, how are you?"), # node4 -> node1 + ("stop", "Ooops"), # node1 -> fallback_node ( - Message("one"), - Message("Ooops"), + "one", + "Ooops", ), # fallback_node -> fallback_node ( - Message("help"), - Message("Ooops"), + "help", + "Ooops", ), # fallback_node -> fallback_node ( - Message("nope"), - Message("Ooops"), + "nope", + "Ooops", ), # fallback_node -> fallback_node ( Message(misc={"some_key": "some_value"}), - Message("Hi, how are you?"), + "Hi, how are you?", ), # fallback_node -> node1 ( - Message("i'm fine, how are you?"), - Message("Good. What do you want to talk about?"), + "i'm fine, how are you?", + "Good. What do you want to talk about?", ), # node1 -> node2 ( - Message("Let's talk about music."), - Message("Sorry, I can not talk about music now."), + "Let's talk about music.", + "Sorry, I can not talk about music now.", ), # node2 -> node3 - (Message("Ok, goodbye."), Message("bye")), # node3 -> node4 + ("Ok, goodbye.", "bye"), # node3 -> node4 ) # %% diff --git a/tutorials/script/core/3_responses.py b/tutorials/script/core/3_responses.py index 0eef02ecc..f6e879e5e 100644 --- a/tutorials/script/core/3_responses.py +++ b/tutorials/script/core/3_responses.py @@ -84,7 +84,7 @@ def fallback_trace_response(ctx: Context, _: Pipeline) -> Message: "start_node": { # This is an initial node, # it doesn't need a `RESPONSE`. RESPONSE: Message(), - TRANSITIONS: {"node1": cnd.exact_match(Message("Hi"))}, + TRANSITIONS: {"node1": cnd.exact_match("Hi")}, # If "Hi" == request of user then we make the transition }, "node1": { @@ -95,28 +95,24 @@ def fallback_trace_response(ctx: Context, _: Pipeline) -> Message: ] ), # Random choice from candidate list. - TRANSITIONS: { - "node2": cnd.exact_match(Message("I'm fine, how are you?")) - }, + TRANSITIONS: {"node2": cnd.exact_match("I'm fine, how are you?")}, }, "node2": { RESPONSE: Message("Good. What do you want to talk about?"), - TRANSITIONS: { - "node3": cnd.exact_match(Message("Let's talk about music.")) - }, + TRANSITIONS: {"node3": cnd.exact_match("Let's talk about music.")}, }, "node3": { RESPONSE: cannot_talk_about_topic_response, - TRANSITIONS: {"node4": cnd.exact_match(Message("Ok, goodbye."))}, + TRANSITIONS: {"node4": cnd.exact_match("Ok, goodbye.")}, }, "node4": { RESPONSE: upper_case_response(Message("bye")), - TRANSITIONS: {"node1": cnd.exact_match(Message("Hi"))}, + TRANSITIONS: {"node1": cnd.exact_match("Hi")}, }, "fallback_node": { # We get to this node # if an error occurred while the agent was running. RESPONSE: fallback_trace_response, - TRANSITIONS: {"node1": cnd.exact_match(Message("Hi"))}, + TRANSITIONS: {"node1": cnd.exact_match("Hi")}, }, } } @@ -124,19 +120,19 @@ def fallback_trace_response(ctx: Context, _: Pipeline) -> Message: # testing happy_path = ( ( - Message("Hi"), - Message("Hello, how are you?"), + "Hi", + "Hello, how are you?", ), # start_node -> node1 ( - Message("I'm fine, how are you?"), - Message("Good. What do you want to talk about?"), + "I'm fine, how are you?", + "Good. What do you want to talk about?", ), # node1 -> node2 ( - Message("Let's talk about music."), - Message("Sorry, I can not talk about music now."), + "Let's talk about music.", + "Sorry, I can not talk about music now.", ), # node2 -> node3 - (Message("Ok, goodbye."), Message("BYE")), # node3 -> node4 - (Message("Hi"), Message("Hello, how are you?")), # node4 -> node1 + ("Ok, goodbye.", "BYE"), # node3 -> node4 + ("Hi", "Hello, how are you?"), # node4 -> node1 ( Message("stop"), Message( @@ -175,18 +171,18 @@ def fallback_trace_response(ctx: Context, _: Pipeline) -> Message: ), ), # f_n->f_n ( - Message("Hi"), - Message("Hi, what is up?"), + "Hi", + "Hi, what is up?", ), # fallback_node -> node1 ( - Message("I'm fine, how are you?"), - Message("Good. What do you want to talk about?"), + "I'm fine, how are you?", + "Good. What do you want to talk about?", ), # node1 -> node2 ( - Message("Let's talk about music."), - Message("Sorry, I can not talk about music now."), + "Let's talk about music.", + "Sorry, I can not talk about music now.", ), # node2 -> node3 - (Message("Ok, goodbye."), Message("BYE")), # node3 -> node4 + ("Ok, goodbye.", "BYE"), # node3 -> node4 ) # %% diff --git a/tutorials/script/core/4_transitions.py b/tutorials/script/core/4_transitions.py index 8acf16143..84805c93f 100644 --- a/tutorials/script/core/4_transitions.py +++ b/tutorials/script/core/4_transitions.py @@ -235,76 +235,63 @@ def transition(_: Context, __: Pipeline) -> ConstLabel: # testing happy_path = ( - (Message("hi"), Message("Hi, how are you?")), + ("hi", "Hi, how are you?"), ( - Message("i'm fine, how are you?"), - Message("Good. What do you want to talk about?"), + "i'm fine, how are you?", + "Good. What do you want to talk about?", ), ( - Message("talk about music."), - Message( - text="I love `System of a Down` group, " - "would you like to talk about it?" - ), + "talk about music.", + "I love `System of a Down` group, " "would you like to talk about it?", ), ( - Message("yes"), - Message( - text="System of a Down is " - "an Armenian-American heavy metal band formed in 1994." - ), + "yes", + "System of a Down is " + "an Armenian-American heavy metal band formed in 1994.", ), ( - Message("next"), - Message( - text="The band achieved commercial success " - "with the release of five studio albums." - ), + "next", + "The band achieved commercial success " + "with the release of five studio albums.", ), ( - Message("back"), - Message( - text="System of a Down is " - "an Armenian-American heavy metal band formed in 1994." - ), + "back", + "System of a Down is " + "an Armenian-American heavy metal band formed in 1994.", ), ( - Message("repeat"), - Message( - text="System of a Down is " - "an Armenian-American heavy metal band formed in 1994." - ), + "repeat", + "System of a Down is " + "an Armenian-American heavy metal band formed in 1994.", ), ( - Message("next"), - Message( - text="The band achieved commercial success " - "with the release of five studio albums." - ), + "next", + "The band achieved commercial success " + "with the release of five studio albums.", ), - (Message("next"), Message("That's all what I know.")), + ("next", "That's all what I know."), ( - Message("next"), - Message("Good. What do you want to talk about?"), + "next", + "Good. What do you want to talk about?", ), - (Message("previous"), Message("That's all what I know.")), - (Message("next time"), Message("Bye")), - (Message("stop"), Message("Ooops")), - (Message("previous"), Message("Bye")), - (Message("stop"), Message("Ooops")), - (Message("nope"), Message("Ooops")), - (Message("hi"), Message("Hi, how are you?")), - (Message("stop"), Message("Ooops")), - (Message("previous"), Message("Hi, how are you?")), + ("previous", "That's all what I know."), + ("next time", "Bye"), + ("stop", "Ooops"), + ("previous", "Bye"), + ("stop", "Ooops"), + ("nope", "Ooops"), + ("hi", "Hi, how are you?"), + ("stop", "Ooops"), + ("previous", "Hi, how are you?"), ( - Message("i'm fine, how are you?"), - Message("Good. What do you want to talk about?"), + "i'm fine, how are you?", + "Good. What do you want to talk about?", ), ( - Message("let's talk about something."), - Message("Sorry, I can not talk about that now."), + "let's talk about something.", + "Sorry, I can not talk about that now.", ), - (Message("Ok, goodbye."), Message("Bye")), + ("Ok, goodbye.", "Bye"), ) # %% diff --git a/tutorials/script/core/5_global_transitions.py b/tutorials/script/core/5_global_transitions.py index 474bf068f..563fb5c59 100644 --- a/tutorials/script/core/5_global_transitions.py +++ b/tutorials/script/core/5_global_transitions.py @@ -136,76 +136,63 @@ # testing happy_path = ( - (Message("hi"), Message("Hi, how are you?")), + ("hi", "Hi, how are you?"), ( - Message("i'm fine, how are you?"), - Message("Good. What do you want to talk about?"), + "i'm fine, how are you?", + "Good. What do you want to talk about?", ), ( - Message("talk about music."), - Message( - text="I love `System of a Down` group, " - "would you like to talk about it?" - ), + "talk about music.", + "I love `System of a Down` group, " "would you like to talk about it?", ), ( - Message("yes"), - Message( - text="System of a Down is " - "an Armenian-American heavy metal band formed in 1994." - ), + "yes", + "System of a Down is " + "an Armenian-American heavy metal band formed in 1994.", ), ( - Message("next"), - Message( - text="The band achieved commercial success " - "with the release of five studio albums." - ), + "next", + "The band achieved commercial success " + "with the release of five studio albums.", ), ( - Message("back"), - Message( - text="System of a Down is " - "an Armenian-American heavy metal band formed in 1994." - ), + "back", + "System of a Down is " + "an Armenian-American heavy metal band formed in 1994.", ), ( - Message("repeat"), - Message( - text="System of a Down is " - "an Armenian-American heavy metal band formed in 1994." - ), + "repeat", + "System of a Down is " + "an Armenian-American heavy metal band formed in 1994.", ), ( - Message("next"), - Message( - text="The band achieved commercial success " - "with the release of five studio albums." - ), + "next", + "The band achieved commercial success " + "with the release of five studio albums.", ), - (Message("next"), Message("That's all what I know.")), + ("next", "That's all what I know."), ( - Message("next"), - Message("Good. What do you want to talk about?"), + "next", + "Good. What do you want to talk about?", ), - (Message("previous"), Message("That's all what I know.")), - (Message("next time"), Message("bye")), - (Message("stop"), Message("Ooops")), - (Message("previous"), Message("bye")), - (Message("stop"), Message("Ooops")), - (Message("nope"), Message("Ooops")), - (Message("hi"), Message("Hi, how are you?")), - (Message("stop"), Message("Ooops")), - (Message("previous"), Message("Hi, how are you?")), + ("previous", "That's all what I know."), + ("next time", "bye"), + ("stop", "Ooops"), + ("previous", "bye"), + ("stop", "Ooops"), + ("nope", "Ooops"), + ("hi", "Hi, how are you?"), + ("stop", "Ooops"), + ("previous", "Hi, how are you?"), ( - Message("i'm fine, how are you?"), - Message("Good. What do you want to talk about?"), + "i'm fine, how are you?", + "Good. What do you want to talk about?", ), ( - Message("let's talk about something."), - Message("Sorry, I can not talk about that now."), + "let's talk about something.", + "Sorry, I can not talk about that now.", ), - (Message("Ok, goodbye."), Message("bye")), + ("Ok, goodbye.", "bye"), ) # %% diff --git a/tutorials/script/core/6_context_serialization.py b/tutorials/script/core/6_context_serialization.py index 1af38c619..51d9749d8 100644 --- a/tutorials/script/core/6_context_serialization.py +++ b/tutorials/script/core/6_context_serialization.py @@ -46,10 +46,10 @@ def response_handler(ctx: Context, _: Pipeline) -> Message: # testing happy_path = ( - (Message("hi"), Message("answer 1")), - (Message("how are you?"), Message("answer 2")), - (Message("ok"), Message("answer 3")), - (Message("good"), Message("answer 4")), + ("hi", "answer 1"), + ("how are you?", "answer 2"), + ("ok", "answer 3"), + ("good", "answer 4"), ) # %% [markdown] diff --git a/tutorials/script/core/7_pre_response_processing.py b/tutorials/script/core/7_pre_response_processing.py index 9697b8675..5d7f5e584 100644 --- a/tutorials/script/core/7_pre_response_processing.py +++ b/tutorials/script/core/7_pre_response_processing.py @@ -107,15 +107,12 @@ def add_prefix_processing(ctx: Context, _: Pipeline): # testing happy_path = ( - (Message(), Message("l3_local: l2_local: l1_global: first")), - (Message(), Message("l3_local: l2_local: l1_step_1: second")), - (Message(), Message("l3_local: l2_step_2: l1_global: third")), - (Message(), Message("l3_step_3: l2_local: l1_global: fourth")), - ( - Message(), - Message("l4_step_4: l3_local: l2_local: l1_global: fifth"), - ), - (Message(), Message("l3_local: l2_local: l1_global: first")), + (Message(), "l3_local: l2_local: l1_global: first"), + (Message(), "l3_local: l2_local: l1_step_1: second"), + (Message(), "l3_local: l2_step_2: l1_global: third"), + (Message(), "l3_step_3: l2_local: l1_global: fourth"), + (Message(), "l4_step_4: l3_local: l2_local: l1_global: fifth"), + (Message(), "l3_local: l2_local: l1_global: first"), ) diff --git a/tutorials/script/core/8_misc.py b/tutorials/script/core/8_misc.py index 6379fede4..c42da6baa 100644 --- a/tutorials/script/core/8_misc.py +++ b/tutorials/script/core/8_misc.py @@ -98,57 +98,45 @@ def custom_response(ctx: Context, _: Pipeline) -> Message: happy_path = ( ( Message(), - Message( - text="ctx.last_label=('flow', 'step_0'): current_node.misc=" - "{'var1': 'global_data', " - "'var2': 'rewrite_by_local', " - "'var3': 'info_of_step_0'}" - ), + "ctx.last_label=('flow', 'step_0'): current_node.misc=" + "{'var1': 'global_data', " + "'var2': 'rewrite_by_local', " + "'var3': 'info_of_step_0'}", ), ( Message(), - Message( - text="ctx.last_label=('flow', 'step_1'): current_node.misc=" - "{'var1': 'global_data', " - "'var2': 'rewrite_by_local', " - "'var3': 'info_of_step_1'}" - ), + "ctx.last_label=('flow', 'step_1'): current_node.misc=" + "{'var1': 'global_data', " + "'var2': 'rewrite_by_local', " + "'var3': 'info_of_step_1'}", ), ( Message(), - Message( - text="ctx.last_label=('flow', 'step_2'): current_node.misc=" - "{'var1': 'global_data', " - "'var2': 'rewrite_by_local', " - "'var3': 'info_of_step_2'}" - ), + "ctx.last_label=('flow', 'step_2'): current_node.misc=" + "{'var1': 'global_data', " + "'var2': 'rewrite_by_local', " + "'var3': 'info_of_step_2'}", ), ( Message(), - Message( - text="ctx.last_label=('flow', 'step_3'): current_node.misc=" - "{'var1': 'global_data', " - "'var2': 'rewrite_by_local', " - "'var3': 'info_of_step_3'}" - ), + "ctx.last_label=('flow', 'step_3'): current_node.misc=" + "{'var1': 'global_data', " + "'var2': 'rewrite_by_local', " + "'var3': 'info_of_step_3'}", ), ( Message(), - Message( - text="ctx.last_label=('flow', 'step_4'): current_node.misc=" - "{'var1': 'global_data', " - "'var2': 'rewrite_by_local', " - "'var3': 'info_of_step_4'}" - ), + "ctx.last_label=('flow', 'step_4'): current_node.misc=" + "{'var1': 'global_data', " + "'var2': 'rewrite_by_local', " + "'var3': 'info_of_step_4'}", ), ( Message(), - Message( - text="ctx.last_label=('flow', 'step_0'): current_node.misc=" - "{'var1': 'global_data', " - "'var2': 'rewrite_by_local', " - "'var3': 'info_of_step_0'}" - ), + "ctx.last_label=('flow', 'step_0'): current_node.misc=" + "{'var1': 'global_data', " + "'var2': 'rewrite_by_local', " + "'var3': 'info_of_step_0'}", ), ) diff --git a/tutorials/script/core/9_pre_transitions_processing.py b/tutorials/script/core/9_pre_transitions_processing.py index 9f2eddc01..c0f6e1f24 100644 --- a/tutorials/script/core/9_pre_transitions_processing.py +++ b/tutorials/script/core/9_pre_transitions_processing.py @@ -78,11 +78,11 @@ def prepend_previous_node_response(ctx: Context, _: Pipeline): # testing happy_path = ( - (Message("1"), Message("previous=None: current=first")), - (Message("2"), Message("previous=first: current=second")), - (Message("3"), Message("previous=second: current=third")), - (Message("4"), Message("previous=third: current=fourth")), - (Message("5"), Message("previous=fourth: current=fifth")), + ("1", "previous=None: current=first"), + ("2", "previous=first: current=second"), + ("3", "previous=second: current=third"), + ("4", "previous=third: current=fourth"), + ("5", "previous=fourth: current=fifth"), ) diff --git a/tutorials/script/responses/1_basics.py b/tutorials/script/responses/1_basics.py index 2b1332d1d..debf55bec 100644 --- a/tutorials/script/responses/1_basics.py +++ b/tutorials/script/responses/1_basics.py @@ -29,31 +29,27 @@ "greeting_flow": { "start_node": { RESPONSE: Message(""), - TRANSITIONS: {"node1": exact_match(Message("Hi"))}, + TRANSITIONS: {"node1": exact_match("Hi")}, }, "node1": { RESPONSE: Message("Hi, how are you?"), - TRANSITIONS: { - "node2": exact_match(Message("i'm fine, how are you?")) - }, + TRANSITIONS: {"node2": exact_match("i'm fine, how are you?")}, }, "node2": { RESPONSE: Message("Good. What do you want to talk about?"), - TRANSITIONS: { - "node3": exact_match(Message("Let's talk about music.")) - }, + TRANSITIONS: {"node3": exact_match("Let's talk about music.")}, }, "node3": { RESPONSE: Message("Sorry, I can not talk about music now."), - TRANSITIONS: {"node4": exact_match(Message("Ok, goodbye."))}, + TRANSITIONS: {"node4": exact_match("Ok, goodbye.")}, }, "node4": { RESPONSE: Message("bye"), - TRANSITIONS: {"node1": exact_match(Message("Hi"))}, + TRANSITIONS: {"node1": exact_match("Hi")}, }, "fallback_node": { RESPONSE: Message("Ooops"), - TRANSITIONS: {"node1": exact_match(Message("Hi"))}, + TRANSITIONS: {"node1": exact_match("Hi")}, }, } } diff --git a/tutorials/script/responses/4_multi_message.py b/tutorials/script/responses/4_multi_message.py index 323ccffec..bfed3313b 100644 --- a/tutorials/script/responses/4_multi_message.py +++ b/tutorials/script/responses/4_multi_message.py @@ -27,7 +27,7 @@ toy_script = { "greeting_flow": { "start_node": { # This is an initial node, - TRANSITIONS: {"node1": cnd.exact_match(Message("Hi"))}, + TRANSITIONS: {"node1": cnd.exact_match("Hi")}, # If "Hi" == request of user then we make the transition }, "node1": { @@ -42,28 +42,24 @@ ] } ), - TRANSITIONS: { - "node2": cnd.exact_match(Message("I'm fine, how are you?")) - }, + TRANSITIONS: {"node2": cnd.exact_match("I'm fine, how are you?")}, }, "node2": { RESPONSE: Message("Good. What do you want to talk about?"), - TRANSITIONS: { - "node3": cnd.exact_match(Message("Let's talk about music.")) - }, + TRANSITIONS: {"node3": cnd.exact_match("Let's talk about music.")}, }, "node3": { RESPONSE: Message("Sorry, I can not talk about that now."), - TRANSITIONS: {"node4": cnd.exact_match(Message("Ok, goodbye."))}, + TRANSITIONS: {"node4": cnd.exact_match("Ok, goodbye.")}, }, "node4": { RESPONSE: Message("bye"), - TRANSITIONS: {"node1": cnd.exact_match(Message("Hi"))}, + TRANSITIONS: {"node1": cnd.exact_match("Hi")}, }, "fallback_node": { # We get to this node # if an error occurred while the agent was running. RESPONSE: Message("Ooops"), - TRANSITIONS: {"node1": cnd.exact_match(Message("Hi"))}, + TRANSITIONS: {"node1": cnd.exact_match("Hi")}, }, } } diff --git a/tutorials/utils/1_cache.py b/tutorials/utils/1_cache.py index bf1142a9f..dca14435a 100644 --- a/tutorials/utils/1_cache.py +++ b/tutorials/utils/1_cache.py @@ -60,9 +60,9 @@ def response(_: Context, __: Pipeline) -> Message: } happy_path = ( - (Message(), Message("1-2-1-2")), - (Message(), Message("3-4-3-4")), - (Message(), Message("5-6-5-6")), + (Message(), "1-2-1-2"), + (Message(), "3-4-3-4"), + (Message(), "5-6-5-6"), ) pipeline = Pipeline.from_script(toy_script, start_label=("flow", "node1")) diff --git a/tutorials/utils/2_lru_cache.py b/tutorials/utils/2_lru_cache.py index faca106d7..f764789e5 100644 --- a/tutorials/utils/2_lru_cache.py +++ b/tutorials/utils/2_lru_cache.py @@ -59,9 +59,9 @@ def response(_: Context, __: Pipeline) -> Message: } happy_path = ( - (Message(), Message("1-2-3-2-4")), - (Message(), Message("5-6-7-6-8")), - (Message(), Message("9-10-11-10-12")), + (Message(), "1-2-3-2-4"), + (Message(), "5-6-7-6-8"), + (Message(), "9-10-11-10-12"), ) pipeline = Pipeline.from_script(toy_script, start_label=("flow", "node1")) From facc5f7c422ee5193d33a19354eb3110cde5bd71 Mon Sep 17 00:00:00 2001 From: Roman Zlobin Date: Wed, 19 Jun 2024 20:01:58 +0300 Subject: [PATCH 19/31] Add quick test command (#344) # Description Add `quick_test` command which runs tests deselecting `slow` and `docker` marked items. # Checklist - [x] I have performed a self-review of the changes # To Consider - Add tests (if functionality is changed) - Update API reference / tutorials / guides - Update CONTRIBUTING.md (if devel workflow is changed) - Update `.ignore` files, scripts (such as `lint`), distribution manifest (if files are added/deleted) - Search for references to changed entities in the codebase --------- Co-authored-by: Alexander Sergeev <22302418+pseusys@users.noreply.github.com> --- CONTRIBUTING.md | 7 +++++++ pyproject.toml | 2 ++ scripts/test.py | 23 ++++++++++++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 85e0c7110..75347a0dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -114,6 +114,13 @@ poetry run poe test_all ``` for successful execution of this command `Docker` and `docker compose` are required. +To do a quick sanity check without the need to up docker containers or wait for long tests, run +```bash +poetry run poe quick_test +``` + +_There's also quick_test_coverage for quick htmlcov generation, though it is very likely to be incomplete due to deselection of some tests._ + To make sure that the code satisfies only the style requirements, run ```bash poetry run poe lint diff --git a/pyproject.toml b/pyproject.toml index 35011e723..22635a1f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -183,6 +183,8 @@ lint.ignore_fail = "return_non_zero" format = "scripts.codestyle:_run_black(modify=True)" clean_docs = "scripts.clean:clean_docs" clean = "scripts.clean:clean" +quick_test = "scripts.test:quick_test" +quick_test_coverage = "scripts.test:quick_test_coverage" test_no_cov = "scripts.test:test_no_cov" test_no_deps = "scripts.test:test_no_deps" test_all = "scripts.test:test_all" diff --git a/scripts/test.py b/scripts/test.py index 058126e5e..1af932f29 100644 --- a/scripts/test.py +++ b/scripts/test.py @@ -7,7 +7,7 @@ from .utils import docker_client -def _test(coverage: bool, dependencies: bool) -> int: +def _test(coverage: bool = False, dependencies: bool = False, quick: bool = False) -> int: """ Run framework tests, located in `tests/` dir, using env defined in `.env_file`. Please keep in mind that: @@ -16,12 +16,25 @@ def _test(coverage: bool, dependencies: bool) -> int: 2. Enabling dependencies is effectively same as enabling docker (docker containers **should** be running in that case). 3. Coverage requires all dependencies and docker (will have no effect otherwise). + + :param coverage: Enable coverage calculation + :param dependencies: Disallow skipping tests + :param quick: Deselect 'slow' and 'docker' marked tests """ test_coverage_threshold = 90 dotenv.load_dotenv(".env_file") args = ["tests/"] + if quick: + args = [ + "-m", + "not docker", + "-m", + "not slow", + *args, + ] + if dependencies and coverage: args = [ "-m", @@ -67,6 +80,14 @@ def _test(coverage: bool, dependencies: bool) -> int: return pytest.main(args) +def quick_test(): + exit(_test(quick=True)) + + +def quick_test_coverage(): + exit(_test(coverage=True, quick=True)) + + @docker_client def test_no_cov(docker: Optional[DockerClient]): result = _test(False, docker is not None) From f631e088f45518c11f6a872281e056ebd35593df Mon Sep 17 00:00:00 2001 From: Roman Zlobin Date: Thu, 20 Jun 2024 14:19:58 +0300 Subject: [PATCH 20/31] framework states rework (#359) # Description Replace framework_states dict with a pydantic model FrameworkData. This makes it clear which data is stored in the field as well as allows using pydantic validation to process framework data. # Checklist - [x] I have performed a self-review of the changes # To Consider - Add tests (if functionality is changed) - Update API reference / tutorials / guides - Update CONTRIBUTING.md (if devel workflow is changed) - Update `.ignore` files, scripts (such as `lint`), distribution manifest (if files are added/deleted) - Search for references to changed entities in the codebase --- dff/__init__.py | 2 +- dff/__rebuild_pydantic_models__.py | 9 +++ dff/pipeline/__init__.py | 3 - dff/pipeline/conditions.py | 3 +- dff/pipeline/pipeline/actor.py | 90 +++++++++++------------ dff/pipeline/pipeline/component.py | 16 ++-- dff/pipeline/pipeline/pipeline.py | 4 +- dff/pipeline/types.py | 45 +++++------- dff/script/__init__.py | 1 - dff/script/core/context.py | 56 +++++++------- dff/script/core/types.py | 6 -- dff/stats/default_extractors.py | 19 ++--- docs/source/user_guides/context_guide.rst | 6 +- tests/script/core/test_context.py | 2 +- 14 files changed, 119 insertions(+), 143 deletions(-) create mode 100644 dff/__rebuild_pydantic_models__.py diff --git a/dff/__init__.py b/dff/__init__.py index f3cfbd963..37b06376e 100644 --- a/dff/__init__.py +++ b/dff/__init__.py @@ -13,4 +13,4 @@ from dff.pipeline import Pipeline from dff.script import Context, Script -Script.model_rebuild() +import dff.__rebuild_pydantic_models__ diff --git a/dff/__rebuild_pydantic_models__.py b/dff/__rebuild_pydantic_models__.py new file mode 100644 index 000000000..6702006b7 --- /dev/null +++ b/dff/__rebuild_pydantic_models__.py @@ -0,0 +1,9 @@ +# flake8: noqa: F401 + +from dff.pipeline import Pipeline +from dff.pipeline.types import ExtraHandlerRuntimeInfo +from dff.script import Context, Script + +Script.model_rebuild() +Context.model_rebuild() +ExtraHandlerRuntimeInfo.model_rebuild() diff --git a/dff/pipeline/__init__.py b/dff/pipeline/__init__.py index 1b345f647..4fbe2286f 100644 --- a/dff/pipeline/__init__.py +++ b/dff/pipeline/__init__.py @@ -13,7 +13,6 @@ ComponentExecutionState, GlobalExtraHandlerType, ExtraHandlerType, - PIPELINE_STATE_KEY, StartConditionCheckerFunction, StartConditionCheckerAggregationFunction, ExtraHandlerConditionFunction, @@ -32,5 +31,3 @@ from .service.extra import BeforeHandler, AfterHandler from .service.group import ServiceGroup from .service.service import Service, to_service - -ExtraHandlerRuntimeInfo.model_rebuild() diff --git a/dff/pipeline/conditions.py b/dff/pipeline/conditions.py index a8a6f236a..3fd14dde6 100644 --- a/dff/pipeline/conditions.py +++ b/dff/pipeline/conditions.py @@ -12,7 +12,6 @@ from dff.script import Context from .types import ( - PIPELINE_STATE_KEY, StartConditionCheckerFunction, ComponentExecutionState, StartConditionCheckerAggregationFunction, @@ -41,7 +40,7 @@ def service_successful_condition(path: Optional[str] = None) -> StartConditionCh """ def check_service_state(ctx: Context, _: Pipeline): - state = ctx.framework_states[PIPELINE_STATE_KEY].get(path, ComponentExecutionState.NOT_RUN) + state = ctx.framework_data.service_states.get(path, ComponentExecutionState.NOT_RUN) return ComponentExecutionState[state] == ComponentExecutionState.FINISHED return check_service_state diff --git a/dff/pipeline/pipeline/actor.py b/dff/pipeline/pipeline/actor.py index 3bac71feb..c4f49a082 100644 --- a/dff/pipeline/pipeline/actor.py +++ b/dff/pipeline/pipeline/actor.py @@ -97,8 +97,6 @@ def __init__( self._clean_turn_cache = True async def __call__(self, pipeline: Pipeline, ctx: Context): - # context init - self._context_init(ctx) await self._run_handlers(ctx, pipeline, ActorStage.CONTEXT_INIT) # get previous node @@ -121,7 +119,7 @@ async def __call__(self, pipeline: Pipeline, ctx: Context): self._get_next_node(ctx) await self._run_handlers(ctx, pipeline, ActorStage.GET_NEXT_NODE) - ctx.add_label(ctx.framework_states["actor"]["next_label"][:2]) + ctx.add_label(ctx.framework_data.actor_data["next_label"][:2]) # rewrite next node self._rewrite_next_node(ctx) @@ -132,89 +130,85 @@ async def __call__(self, pipeline: Pipeline, ctx: Context): await self._run_handlers(ctx, pipeline, ActorStage.RUN_PRE_RESPONSE_PROCESSING) # create response - ctx.framework_states["actor"]["response"] = await self.run_response( - ctx.framework_states["actor"]["pre_response_processed_node"].response, ctx, pipeline + ctx.framework_data.actor_data["response"] = await self.run_response( + ctx.framework_data.actor_data["pre_response_processed_node"].response, ctx, pipeline ) await self._run_handlers(ctx, pipeline, ActorStage.CREATE_RESPONSE) - ctx.add_response(ctx.framework_states["actor"]["response"]) + ctx.add_response(ctx.framework_data.actor_data["response"]) await self._run_handlers(ctx, pipeline, ActorStage.FINISH_TURN) if self._clean_turn_cache: cache_clear() - del ctx.framework_states["actor"] - - @staticmethod - def _context_init(ctx: Optional[Union[Context, dict, str]] = None): - ctx.framework_states["actor"] = {} + ctx.framework_data.actor_data.clear() def _get_previous_node(self, ctx: Context): - ctx.framework_states["actor"]["previous_label"] = ( + ctx.framework_data.actor_data["previous_label"] = ( normalize_label(ctx.last_label) if ctx.last_label else self.start_label ) - ctx.framework_states["actor"]["previous_node"] = self.script.get( - ctx.framework_states["actor"]["previous_label"][0], {} - ).get(ctx.framework_states["actor"]["previous_label"][1], Node()) + ctx.framework_data.actor_data["previous_node"] = self.script.get( + ctx.framework_data.actor_data["previous_label"][0], {} + ).get(ctx.framework_data.actor_data["previous_label"][1], Node()) async def _get_true_labels(self, ctx: Context, pipeline: Pipeline): # GLOBAL - ctx.framework_states["actor"]["global_transitions"] = ( + ctx.framework_data.actor_data["global_transitions"] = ( self.script.get(GLOBAL, {}).get(GLOBAL, Node()).transitions ) - ctx.framework_states["actor"]["global_true_label"] = await self._get_true_label( - ctx.framework_states["actor"]["global_transitions"], ctx, pipeline, GLOBAL, "global" + ctx.framework_data.actor_data["global_true_label"] = await self._get_true_label( + ctx.framework_data.actor_data["global_transitions"], ctx, pipeline, GLOBAL, "global" ) # LOCAL - ctx.framework_states["actor"]["local_transitions"] = ( - self.script.get(ctx.framework_states["actor"]["previous_label"][0], {}).get(LOCAL, Node()).transitions + ctx.framework_data.actor_data["local_transitions"] = ( + self.script.get(ctx.framework_data.actor_data["previous_label"][0], {}).get(LOCAL, Node()).transitions ) - ctx.framework_states["actor"]["local_true_label"] = await self._get_true_label( - ctx.framework_states["actor"]["local_transitions"], + ctx.framework_data.actor_data["local_true_label"] = await self._get_true_label( + ctx.framework_data.actor_data["local_transitions"], ctx, pipeline, - ctx.framework_states["actor"]["previous_label"][0], + ctx.framework_data.actor_data["previous_label"][0], "local", ) # NODE - ctx.framework_states["actor"]["node_transitions"] = ctx.framework_states["actor"][ + ctx.framework_data.actor_data["node_transitions"] = ctx.framework_data.actor_data[ "pre_transitions_processed_node" ].transitions - ctx.framework_states["actor"]["node_true_label"] = await self._get_true_label( - ctx.framework_states["actor"]["node_transitions"], + ctx.framework_data.actor_data["node_true_label"] = await self._get_true_label( + ctx.framework_data.actor_data["node_transitions"], ctx, pipeline, - ctx.framework_states["actor"]["previous_label"][0], + ctx.framework_data.actor_data["previous_label"][0], "node", ) def _get_next_node(self, ctx: Context): # choose next label - ctx.framework_states["actor"]["next_label"] = self._choose_label( - ctx.framework_states["actor"]["node_true_label"], ctx.framework_states["actor"]["local_true_label"] + ctx.framework_data.actor_data["next_label"] = self._choose_label( + ctx.framework_data.actor_data["node_true_label"], ctx.framework_data.actor_data["local_true_label"] ) - ctx.framework_states["actor"]["next_label"] = self._choose_label( - ctx.framework_states["actor"]["next_label"], ctx.framework_states["actor"]["global_true_label"] + ctx.framework_data.actor_data["next_label"] = self._choose_label( + ctx.framework_data.actor_data["next_label"], ctx.framework_data.actor_data["global_true_label"] ) # get next node - ctx.framework_states["actor"]["next_node"] = self.script.get( - ctx.framework_states["actor"]["next_label"][0], {} - ).get(ctx.framework_states["actor"]["next_label"][1]) + ctx.framework_data.actor_data["next_node"] = self.script.get( + ctx.framework_data.actor_data["next_label"][0], {} + ).get(ctx.framework_data.actor_data["next_label"][1]) def _rewrite_previous_node(self, ctx: Context): - node = ctx.framework_states["actor"]["previous_node"] - flow_label = ctx.framework_states["actor"]["previous_label"][0] - ctx.framework_states["actor"]["previous_node"] = self._overwrite_node( + node = ctx.framework_data.actor_data["previous_node"] + flow_label = ctx.framework_data.actor_data["previous_label"][0] + ctx.framework_data.actor_data["previous_node"] = self._overwrite_node( node, flow_label, only_current_node_transitions=True, ) def _rewrite_next_node(self, ctx: Context): - node = ctx.framework_states["actor"]["next_node"] - flow_label = ctx.framework_states["actor"]["next_label"][0] - ctx.framework_states["actor"]["next_node"] = self._overwrite_node(node, flow_label) + node = ctx.framework_data.actor_data["next_node"] + flow_label = ctx.framework_data.actor_data["next_label"][0] + ctx.framework_data.actor_data["next_node"] = self._overwrite_node(node, flow_label) def _overwrite_node( self, @@ -290,18 +284,18 @@ async def _run_pre_transitions_processing(self, ctx: Context, pipeline: Pipeline The execution order depends on the value of the :py:class:`.Pipeline`'s `parallelize_processing` flag. """ - ctx.framework_states["actor"]["processed_node"] = copy.deepcopy(ctx.framework_states["actor"]["previous_node"]) - pre_transitions_processing = ctx.framework_states["actor"]["previous_node"].pre_transitions_processing + ctx.framework_data.actor_data["processed_node"] = copy.deepcopy(ctx.framework_data.actor_data["previous_node"]) + pre_transitions_processing = ctx.framework_data.actor_data["previous_node"].pre_transitions_processing if pipeline.parallelize_processing: await self._run_processing_parallel(pre_transitions_processing, ctx, pipeline) else: await self._run_processing_sequential(pre_transitions_processing, ctx, pipeline) - ctx.framework_states["actor"]["pre_transitions_processed_node"] = ctx.framework_states["actor"][ + ctx.framework_data.actor_data["pre_transitions_processed_node"] = ctx.framework_data.actor_data[ "processed_node" ] - del ctx.framework_states["actor"]["processed_node"] + del ctx.framework_data.actor_data["processed_node"] async def _run_pre_response_processing(self, ctx: Context, pipeline: Pipeline) -> None: """ @@ -312,16 +306,16 @@ async def _run_pre_response_processing(self, ctx: Context, pipeline: Pipeline) - The execution order depends on the value of the :py:class:`.Pipeline`'s `parallelize_processing` flag. """ - ctx.framework_states["actor"]["processed_node"] = copy.deepcopy(ctx.framework_states["actor"]["next_node"]) - pre_response_processing = ctx.framework_states["actor"]["next_node"].pre_response_processing + ctx.framework_data.actor_data["processed_node"] = copy.deepcopy(ctx.framework_data.actor_data["next_node"]) + pre_response_processing = ctx.framework_data.actor_data["next_node"].pre_response_processing if pipeline.parallelize_processing: await self._run_processing_parallel(pre_response_processing, ctx, pipeline) else: await self._run_processing_sequential(pre_response_processing, ctx, pipeline) - ctx.framework_states["actor"]["pre_response_processed_node"] = ctx.framework_states["actor"]["processed_node"] - del ctx.framework_states["actor"]["processed_node"] + ctx.framework_data.actor_data["pre_response_processed_node"] = ctx.framework_data.actor_data["processed_node"] + del ctx.framework_data.actor_data["processed_node"] async def _get_true_label( self, diff --git a/dff/pipeline/pipeline/component.py b/dff/pipeline/pipeline/component.py index dcd74b34e..7384578b7 100644 --- a/dff/pipeline/pipeline/component.py +++ b/dff/pipeline/pipeline/component.py @@ -13,7 +13,6 @@ import logging import abc import asyncio -import copy from typing import Optional, Awaitable, TYPE_CHECKING from dff.script import Context @@ -21,7 +20,6 @@ from ..service.extra import BeforeHandler, AfterHandler from ..conditions import always_start_condition from ..types import ( - PIPELINE_STATE_KEY, StartConditionCheckerFunction, ComponentExecutionState, ServiceRuntimeInfo, @@ -109,28 +107,24 @@ def __init__( def _set_state(self, ctx: Context, value: ComponentExecutionState): """ - Method for component runtime state setting, state is preserved in `ctx.framework_states` dict, - in subdict, dedicated to this library. + Method for component runtime state setting, state is preserved in `ctx.framework_data`. :param ctx: :py:class:`~.Context` to keep state in. :param value: State to set. :return: `None` """ - if PIPELINE_STATE_KEY not in ctx.framework_states: - ctx.framework_states[PIPELINE_STATE_KEY] = {} - ctx.framework_states[PIPELINE_STATE_KEY][self.path] = value + ctx.framework_data.service_states[self.path] = value def get_state(self, ctx: Context, default: Optional[ComponentExecutionState] = None) -> ComponentExecutionState: """ - Method for component runtime state getting, state is preserved in `ctx.framework_states` dict, - in subdict, dedicated to this library. + Method for component runtime state getting, state is preserved in `ctx.framework_data`. :param ctx: :py:class:`~.Context` to get state from. :param default: Default to return if no record found (usually it's :py:attr:`~.pipeline.types.ComponentExecutionState.NOT_RUN`). :return: :py:class:`~pipeline.types.ComponentExecutionState` of this service or default if not found. """ - return ctx.framework_states[PIPELINE_STATE_KEY].get(self.path, default if default is not None else None) + return ctx.framework_data.service_states.get(self.path, default if default is not None else None) @property def asynchronous(self) -> bool: @@ -218,7 +212,7 @@ def _get_runtime_info(self, ctx: Context) -> ServiceRuntimeInfo: path=self.path if self.path is not None else "[None]", timeout=self.timeout, asynchronous=self.asynchronous, - execution_state=copy.deepcopy(ctx.framework_states[PIPELINE_STATE_KEY]), + execution_state=ctx.framework_data.service_states.copy(), ) @property diff --git a/dff/pipeline/pipeline/pipeline.py b/dff/pipeline/pipeline/pipeline.py index 1c3e9d456..18049a41f 100644 --- a/dff/pipeline/pipeline/pipeline.py +++ b/dff/pipeline/pipeline/pipeline.py @@ -33,7 +33,6 @@ ExtraHandlerFunction, ExtraHandlerBuilder, ) -from ..types import PIPELINE_STATE_KEY from .utils import finalize_service_group, pretty_format_component_info_dict from dff.pipeline.pipeline.actor import Actor @@ -320,14 +319,13 @@ async def _run_pipeline( if update_ctx_misc is not None: ctx.misc.update(update_ctx_misc) - ctx.framework_states[PIPELINE_STATE_KEY] = {} ctx.add_request(request) result = await self._services_pipeline(ctx, self) if asyncio.iscoroutine(result): await result - del ctx.framework_states[PIPELINE_STATE_KEY] + ctx.framework_data.service_states.clear() if isinstance(self.context_storage, DBContextStorage): await self.context_storage.set_item_async(ctx_id, ctx) diff --git a/dff/pipeline/types.py b/dff/pipeline/types.py index 48f93e9cb..be345f850 100644 --- a/dff/pipeline/types.py +++ b/dff/pipeline/types.py @@ -9,18 +9,18 @@ from __future__ import annotations from enum import unique, Enum from typing import Callable, Union, Awaitable, Dict, List, Optional, Iterable, Any, Protocol, Hashable, TYPE_CHECKING - -from dff.context_storages import DBContextStorage -from dff.script import Context, ActorStage, NodeLabel2Type, Script, Message from typing_extensions import NotRequired, TypedDict, TypeAlias from pydantic import BaseModel + if TYPE_CHECKING: from dff.pipeline.pipeline.pipeline import Pipeline from dff.pipeline.service.service import Service from dff.pipeline.service.group import ServiceGroup from dff.pipeline.service.extra import _ComponentExtraHandler from dff.messengers.common.interface import MessengerInterface + from dff.context_storages import DBContextStorage + from dff.script import Context, ActorStage, NodeLabel2Type, Script, Message class PipelineRunnerFunction(Protocol): @@ -53,7 +53,7 @@ def __call__( class ComponentExecutionState(str, Enum): """ Enum, representing pipeline component execution state. - These states are stored in `ctx.framework_keys[PIPELINE_STATE_KEY]`, + These states are stored in `ctx.framework_keys.service_states`, that should always be requested with `NOT_RUN` being default fallback. Following states are supported: @@ -103,14 +103,7 @@ class ExtraHandlerType(str, Enum): AFTER = "AFTER" -PIPELINE_STATE_KEY = "PIPELINE" -""" -PIPELINE: storage for services and groups execution status. -Should be used in `ctx.framework_keys[PIPELINE_STATE_KEY]`. -""" - - -StartConditionCheckerFunction: TypeAlias = Callable[[Context, "Pipeline"], bool] +StartConditionCheckerFunction: TypeAlias = Callable[["Context", "Pipeline"], bool] """ A function type for components `start_conditions`. Accepts context and pipeline, returns boolean (whether service can be launched). @@ -149,9 +142,9 @@ class ServiceRuntimeInfo(BaseModel): ExtraHandlerFunction: TypeAlias = Union[ - Callable[[Context], Any], - Callable[[Context, "Pipeline"], Any], - Callable[[Context, "Pipeline", "ExtraHandlerRuntimeInfo"], Any], + Callable[["Context"], Any], + Callable[["Context", "Pipeline"], Any], + Callable[["Context", "Pipeline", "ExtraHandlerRuntimeInfo"], Any], ] """ A function type for creating extra handler (before and after functions). @@ -173,12 +166,12 @@ class ExtraHandlerRuntimeInfo(BaseModel): ServiceFunction: TypeAlias = Union[ - Callable[[Context], None], - Callable[[Context], Awaitable[None]], - Callable[[Context, "Pipeline"], None], - Callable[[Context, "Pipeline"], Awaitable[None]], - Callable[[Context, "Pipeline", ServiceRuntimeInfo], None], - Callable[[Context, "Pipeline", ServiceRuntimeInfo], Awaitable[None]], + Callable[["Context"], None], + Callable[["Context"], Awaitable[None]], + Callable[["Context", "Pipeline"], None], + Callable[["Context", "Pipeline"], Awaitable[None]], + Callable[["Context", "Pipeline", ServiceRuntimeInfo], None], + Callable[["Context", "Pipeline", ServiceRuntimeInfo], Awaitable[None]], ] """ A function type for creating service handlers. @@ -253,18 +246,18 @@ class ExtraHandlerRuntimeInfo(BaseModel): "PipelineBuilder", { "messenger_interface": NotRequired[Optional["MessengerInterface"]], - "context_storage": NotRequired[Optional[Union[DBContextStorage, Dict]]], + "context_storage": NotRequired[Optional[Union["DBContextStorage", Dict]]], "components": ServiceGroupBuilder, "before_handler": NotRequired[Optional[ExtraHandlerBuilder]], "after_handler": NotRequired[Optional[ExtraHandlerBuilder]], "optimization_warnings": NotRequired[bool], "parallelize_processing": NotRequired[bool], - "script": Union[Script, Dict], - "start_label": NodeLabel2Type, - "fallback_label": NotRequired[Optional[NodeLabel2Type]], + "script": Union["Script", Dict], + "start_label": "NodeLabel2Type", + "fallback_label": NotRequired[Optional["NodeLabel2Type"]], "label_priority": NotRequired[float], "condition_handler": NotRequired[Optional[Callable]], - "handlers": NotRequired[Optional[Dict[ActorStage, List[Callable]]]], + "handlers": NotRequired[Optional[Dict["ActorStage", List[Callable]]]], }, ) """ diff --git a/dff/script/__init__.py b/dff/script/__init__.py index 9ac057b45..942d9441d 100644 --- a/dff/script/__init__.py +++ b/dff/script/__init__.py @@ -21,7 +21,6 @@ ConstLabel, Label, ConditionType, - ModuleName, ActorStage, ) from .core.message import Message diff --git a/dff/script/core/context.py b/dff/script/core/context.py index 4b223eef5..03c2cae5e 100644 --- a/dff/script/core/context.py +++ b/dff/script/core/context.py @@ -24,8 +24,9 @@ from pydantic import BaseModel, Field, field_validator -from .types import NodeLabel2Type, ModuleName -from .message import Message +from dff.script.core.message import Message +from dff.script.core.types import NodeLabel2Type +from dff.pipeline.types import ComponentExecutionState if TYPE_CHECKING: from dff.script.core.script import Node @@ -44,6 +45,19 @@ def get_last_index(dictionary: dict) -> int: return indices[-1] if indices else -1 +class FrameworkData(BaseModel): + """ + Framework uses this to store data related to any of its modules. + """ + + service_states: Dict[str, ComponentExecutionState] = Field(default_factory=dict, exclude=True) + "Statuses of all the pipeline services. Cleared at the end of every turn." + actor_data: Dict[str, Any] = Field(default_factory=dict, exclude=True) + "Actor service data. Cleared at the end of every turn." + stats: Dict[str, Any] = Field(default_factory=dict) + "Enables complex stats collection across multiple turns." + + class Context(BaseModel): """ A structure that is used to store data about the context of a dialog. @@ -57,28 +71,28 @@ class Context(BaseModel): `id` is the unique context identifier. By default, randomly generated using `uuid4` `id` is used. `id` can be used to trace the user behavior, e.g while collecting the statistical data. """ - labels: Dict[int, NodeLabel2Type] = {} + labels: Dict[int, NodeLabel2Type] = Field(default_factory=dict) """ `labels` stores the history of all passed `labels` - key - `id` of the turn. - value - `label` on this turn. """ - requests: Dict[int, Message] = {} + requests: Dict[int, Message] = Field(default_factory=dict) """ `requests` stores the history of all `requests` received by the agent - key - `id` of the turn. - value - `request` on this turn. """ - responses: Dict[int, Message] = {} + responses: Dict[int, Message] = Field(default_factory=dict) """ `responses` stores the history of all agent `responses` - key - `id` of the turn. - value - `response` on this turn. """ - misc: Dict[str, Any] = {} + misc: Dict[str, Any] = Field(default_factory=dict) """ `misc` stores any custom data. The scripting doesn't use this dictionary by default, so storage of any data won't reflect on the work on the internal Dialog Flow Scripting functions. @@ -88,18 +102,10 @@ class Context(BaseModel): - key - Arbitrary data name. - value - Arbitrary data. """ - framework_states: Dict[ModuleName, Dict[str, Any]] = {} + framework_data: FrameworkData = Field(default_factory=FrameworkData) """ - `framework_states` is used for addons states or for - :py:class:`~dff.pipeline.pipeline.pipeline.Pipeline`'s states. - :py:class:`~dff.pipeline.pipeline.pipeline.Pipeline` - records all its intermediate conditions into the `framework_states`. - After :py:class:`~.Context` processing is finished, - :py:class:`~dff.pipeline.pipeline.pipeline.Pipeline` resets `framework_states` and - returns :py:class:`~.Context`. - - - key - Temporary variable name. - - value - Temporary variable data. + This attribute is used for storing custom data required for pipeline execution. + It is meant to be used by the framework only. Accessing it may result in pipeline breakage. """ @field_validator("labels", "requests", "responses") @@ -199,8 +205,8 @@ def clear( if "labels" in field_names: for index in list(self.labels)[:-hold_last_n_indices]: del self.labels[index] - if "framework_states" in field_names: - self.framework_states.clear() + if "framework_data" in field_names: + self.framework_data = FrameworkData() @property def last_label(self) -> Optional[NodeLabel2Type]: @@ -256,13 +262,13 @@ def current_node(self) -> Optional[Node]: """ Return current :py:class:`~dff.script.core.script.Node`. """ - actor = self.framework_states.get("actor", {}) + actor_data = self.framework_data.actor_data node = ( - actor.get("processed_node") - or actor.get("pre_response_processed_node") - or actor.get("next_node") - or actor.get("pre_transitions_processed_node") - or actor.get("previous_node") + actor_data.get("processed_node") + or actor_data.get("pre_response_processed_node") + or actor_data.get("next_node") + or actor_data.get("pre_transitions_processed_node") + or actor_data.get("previous_node") ) if node is None: logger.warning( diff --git a/dff/script/core/types.py b/dff/script/core/types.py index 69b8aafd2..413159174 100644 --- a/dff/script/core/types.py +++ b/dff/script/core/types.py @@ -39,12 +39,6 @@ ConditionType: TypeAlias = Callable """Condition type can be only `Callable`.""" -ModuleName: TypeAlias = "str" -""" -Module name names addon state, or your own module state. For example module name can be `"dff_context_storages"`. -""" -# TODO: change example - class ActorStage(Enum): """ diff --git a/dff/stats/default_extractors.py b/dff/stats/default_extractors.py index aac41b112..9b3856e2a 100644 --- a/dff/stats/default_extractors.py +++ b/dff/stats/default_extractors.py @@ -36,27 +36,22 @@ async def get_current_label(ctx: Context, pipeline: Pipeline, info: ExtraHandler async def get_timing_before(ctx: Context, _, info: ExtraHandlerRuntimeInfo): """ - Extract the pipeline component's start time. + Store the pipeline component's start time inside the context. This function is required for running the dashboard with the default configuration. - - The function leverages the `framework_states` field of the context to store results. - As a result, the function output is cleared on every turn and does not get persisted - to the context storage. """ start_time = datetime.now() - ctx.framework_states[get_extra_handler_name(info, "time")] = start_time + ctx.framework_data.stats[get_extra_handler_name(info, "time")] = start_time async def get_timing_after(ctx: Context, _, info: ExtraHandlerRuntimeInfo): # noqa: F811 """ - Extract the pipeline component's finish time. + Extract the pipeline component's execution time. + Requires :py:func:`~.get_timing_before` to be called previously in order to calculate the time. This function is required for running the dashboard with the default configuration. - - The function leverages the `framework_states` field of the context to store results. - As a result, the function output is cleared on every turn and does not get persisted - to the context storage. """ - start_time = ctx.framework_states[get_extra_handler_name(info, "time")] + start_time = ctx.framework_data.stats.pop(get_extra_handler_name(info, "time"), None) + if start_time is None: + return None data = {"execution_time": str(datetime.now() - start_time)} return data diff --git a/docs/source/user_guides/context_guide.rst b/docs/source/user_guides/context_guide.rst index 36117ecce..34d2119a6 100644 --- a/docs/source/user_guides/context_guide.rst +++ b/docs/source/user_guides/context_guide.rst @@ -109,10 +109,8 @@ Attributes built-in DFF classes or functions, so the values that you write there are guaranteed to persist throughout the lifetime of the ``Context`` object. -* **framework_states**: This attribute is used for storing addon or pipeline states. - Each turn, the DFF pipeline records the intermediary states of its components into this field, - and clears it at the end of the turn. For this reason, developers are discouraged from storing - their own data in this field. +* **framework_data**: This attribute is used for storing custom data required for pipeline execution. + It is meant to be used by the framework only. Accessing it may result in pipeline breakage. Methods ======= diff --git a/tests/script/core/test_context.py b/tests/script/core/test_context.py index 1910ded2c..a78463746 100644 --- a/tests/script/core/test_context.py +++ b/tests/script/core/test_context.py @@ -19,7 +19,7 @@ def test_context(): ctx.responses = shuffle_dict_keys(ctx.responses) ctx = Context.cast(ctx.model_dump_json()) ctx.misc[123] = 312 - ctx.clear(5, ["requests", "responses", "misc", "labels", "framework_states"]) + ctx.clear(5, ["requests", "responses", "misc", "labels", "framework_data"]) ctx.misc["1001"] = "11111" ctx.add_request(Message(str(1000))) ctx.add_label((str(1000), str(1000 + 1))) From ca84b4b81034bb377cc8673bf2e46a92c182a850 Mon Sep 17 00:00:00 2001 From: Roman Zlobin Date: Tue, 2 Jul 2024 13:35:24 +0300 Subject: [PATCH 21/31] Fix stats (#366) freeze otel col version --- compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compose.yml b/compose.yml index a753b946b..273e49bb7 100644 --- a/compose.yml +++ b/compose.yml @@ -147,7 +147,7 @@ services: start_period: 30s otelcol: - image: otel/opentelemetry-collector-contrib:latest + image: otel/opentelemetry-collector-contrib:0.103.1 profiles: - stats container_name: otel-col From 1593559423971c95404ee5b3af195d7dcc0d0720 Mon Sep 17 00:00:00 2001 From: Alexander Sergeev <22302418+pseusys@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:11:17 +0200 Subject: [PATCH 22/31] Telegram interface upgrade (#328) # Description - Telegram interface was rewritten and updated to be used with the most recent `Interface` and `Attachment` classes. - Added JSONPickle Serialization tools to allow json-serializing pickle-serializable objects. - Attachments reworked. --------- Co-authored-by: Roman Zlobin --- dff/messengers/common/__init__.py | 7 +- dff/messengers/common/interface.py | 102 +- dff/messengers/console.py | 49 + dff/messengers/telegram/__init__.py | 14 +- dff/messengers/telegram/abstract.py | 660 ++++ dff/messengers/telegram/interface.py | 230 +- dff/messengers/telegram/message.py | 106 - dff/messengers/telegram/messenger.py | 248 -- dff/messengers/telegram/utils.py | 55 - dff/pipeline/pipeline/pipeline.py | 3 +- dff/pipeline/types.py | 2 +- dff/script/conditions/__init__.py | 1 + dff/script/conditions/std_conditions.py | 19 + dff/script/core/message.py | 327 +- dff/utils/devel/__init__.py | 13 + dff/utils/devel/extra_field_helpers.py | 22 + dff/utils/devel/json_serialization.py | 191 + dff/utils/testing/telegram.py | 278 -- docs/source/conf.py | 1 + poetry.lock | 3262 +++++++++-------- pyproject.toml | 5 +- scripts/test.py | 8 +- tests/conftest.py | 2 +- tests/messengers/telegram/conftest.py | 78 - .../messengers/telegram/test_happy_paths.json | 958 +++++ tests/messengers/telegram/test_tutorials.py | 77 +- tests/messengers/telegram/test_types.py | 222 -- tests/messengers/telegram/utils.py | 130 + tests/pipeline/test_messenger_interface.py | 3 +- tests/script/conditions/test_conditions.py | 2 +- tests/script/core/test_message.py | 178 +- tests/utils/test_serialization.py | 115 + tutorials/messengers/telegram/1_basic.py | 53 +- .../messengers/telegram/2_attachments.py | 274 ++ tutorials/messengers/telegram/2_buttons.py | 193 - tutorials/messengers/telegram/3_advanced.py | 263 ++ .../telegram/3_buttons_with_callback.py | 181 - tutorials/messengers/telegram/4_conditions.py | 147 - .../telegram/5_conditions_with_media.py | 204 -- .../telegram/6_conditions_extras.py | 126 - .../messengers/telegram/7_polling_setup.py | 64 - .../messengers/telegram/8_webhook_setup.py | 61 - .../pipeline/2_pre_and_post_processors.py | 2 +- .../3_pipeline_dict_with_services_full.py | 2 +- tutorials/script/responses/2_buttons.py | 259 -- .../responses/{3_media.py => 2_media.py} | 14 +- ...{4_multi_message.py => 3_multi_message.py} | 2 +- utils/test_data_generators/__init__.py | 0 .../telegram_tutorial_data.py | 67 + 49 files changed, 4962 insertions(+), 4318 deletions(-) create mode 100644 dff/messengers/console.py create mode 100644 dff/messengers/telegram/abstract.py delete mode 100644 dff/messengers/telegram/message.py delete mode 100644 dff/messengers/telegram/messenger.py delete mode 100644 dff/messengers/telegram/utils.py create mode 100644 dff/utils/devel/__init__.py create mode 100644 dff/utils/devel/extra_field_helpers.py create mode 100644 dff/utils/devel/json_serialization.py delete mode 100644 dff/utils/testing/telegram.py delete mode 100644 tests/messengers/telegram/conftest.py create mode 100644 tests/messengers/telegram/test_happy_paths.json delete mode 100644 tests/messengers/telegram/test_types.py create mode 100644 tests/messengers/telegram/utils.py create mode 100644 tests/utils/test_serialization.py create mode 100644 tutorials/messengers/telegram/2_attachments.py delete mode 100644 tutorials/messengers/telegram/2_buttons.py create mode 100644 tutorials/messengers/telegram/3_advanced.py delete mode 100644 tutorials/messengers/telegram/3_buttons_with_callback.py delete mode 100644 tutorials/messengers/telegram/4_conditions.py delete mode 100644 tutorials/messengers/telegram/5_conditions_with_media.py delete mode 100644 tutorials/messengers/telegram/6_conditions_extras.py delete mode 100644 tutorials/messengers/telegram/7_polling_setup.py delete mode 100644 tutorials/messengers/telegram/8_webhook_setup.py delete mode 100644 tutorials/script/responses/2_buttons.py rename tutorials/script/responses/{3_media.py => 2_media.py} (88%) rename tutorials/script/responses/{4_multi_message.py => 3_multi_message.py} (99%) create mode 100644 utils/test_data_generators/__init__.py create mode 100644 utils/test_data_generators/telegram_tutorial_data.py diff --git a/dff/messengers/common/__init__.py b/dff/messengers/common/__init__.py index d9c66d921..713974c16 100644 --- a/dff/messengers/common/__init__.py +++ b/dff/messengers/common/__init__.py @@ -1,4 +1,9 @@ # -*- coding: utf-8 -*- -from .interface import MessengerInterface, PollingMessengerInterface, CallbackMessengerInterface, CLIMessengerInterface +from .interface import ( + MessengerInterface, + MessengerInterfaceWithAttachments, + PollingMessengerInterface, + CallbackMessengerInterface, +) from .types import PollingInterfaceLoopFunction diff --git a/dff/messengers/common/interface.py b/dff/messengers/common/interface.py index 772107f4c..8037c0408 100644 --- a/dff/messengers/common/interface.py +++ b/dff/messengers/common/interface.py @@ -9,14 +9,15 @@ import abc import asyncio import logging -import uuid -from typing import Optional, Any, List, Tuple, TextIO, Hashable, TYPE_CHECKING - -from dff.script import Context, Message -from dff.messengers.common.types import PollingInterfaceLoopFunction +from pathlib import Path +from tempfile import gettempdir +from typing import Optional, Any, List, Tuple, Hashable, TYPE_CHECKING, Type if TYPE_CHECKING: + from dff.script import Context, Message from dff.pipeline.types import PipelineRunnerFunction + from dff.messengers.common.types import PollingInterfaceLoopFunction + from dff.script.core.message import Attachment logger = logging.getLogger(__name__) @@ -39,6 +40,55 @@ async def connect(self, pipeline_runner: PipelineRunnerFunction): raise NotImplementedError +class MessengerInterfaceWithAttachments(MessengerInterface, abc.ABC): + """ + MessengerInterface subclass that has methods for attachment handling. + + :param attachments_directory: Directory where attachments will be stored. + If not specified, the temporary directory will be used. + """ + + supported_request_attachment_types: set[Type[Attachment]] = set() + """ + Types of attachment that this messenger interface can receive. + Attachments not in this list will be neglected. + """ + + supported_response_attachment_types: set[Type[Attachment]] = set() + """ + Types of attachment that this messenger interface can send. + Attachments not in this list will be neglected. + """ + + def __init__(self, attachments_directory: Optional[Path] = None) -> None: + tempdir = gettempdir() + if attachments_directory is not None and not str(attachments_directory.absolute()).startswith(tempdir): + self.attachments_directory = attachments_directory + else: + warning_start = f"Attachments directory for {type(self).__name__} messenger interface" + warning_end = "attachment data won't be cached locally!" + if attachments_directory is None: + self.attachments_directory = Path(tempdir) / f"dff-cache-{type(self).__name__}" + logger.info(f"{warning_start} is None, so will be set to tempdir and {warning_end}") + else: + self.attachments_directory = attachments_directory + logger.info(f"{warning_start} is in tempdir, so {warning_end}") + self.attachments_directory.mkdir(parents=True, exist_ok=True) + + @abc.abstractmethod + async def get_attachment_bytes(self, source: str) -> bytes: + """ + Get attachment bytes from file source. + + E.g. if a file attachment consists of a URL of the file uploaded to the messenger servers, + this method is the right place to call the messenger API for the file downloading. + + :param source: Identifying string for the file. + :return: The attachment bytes. + """ + raise NotImplementedError + + class PollingMessengerInterface(MessengerInterface): """ Polling message interface runs in a loop, constantly asking users for a new input. @@ -119,7 +169,7 @@ class CallbackMessengerInterface(MessengerInterface): Callback message interface is waiting for user input and answers once it gets one. """ - def __init__(self): + def __init__(self) -> None: self._pipeline_runner: Optional[PipelineRunnerFunction] = None async def connect(self, pipeline_runner: PipelineRunnerFunction): @@ -142,43 +192,3 @@ def on_request( This method has the same signature as :py:class:`~dff.pipeline.types.PipelineRunnerFunction`. """ return asyncio.run(self.on_request_async(request, ctx_id, update_ctx_misc)) - - -class CLIMessengerInterface(PollingMessengerInterface): - """ - Command line message interface is the default message interface, communicating with user via `STDIN/STDOUT`. - This message interface can maintain dialog with one user at a time only. - """ - - def __init__( - self, - intro: Optional[str] = None, - prompt_request: str = "request: ", - prompt_response: str = "response: ", - out_descriptor: Optional[TextIO] = None, - ): - super().__init__() - self._ctx_id: Optional[Hashable] = None - self._intro: Optional[str] = intro - self._prompt_request: str = prompt_request - self._prompt_response: str = prompt_response - self._descriptor: Optional[TextIO] = out_descriptor - - def _request(self) -> List[Tuple[Message, Any]]: - return [(Message(input(self._prompt_request)), self._ctx_id)] - - def _respond(self, responses: List[Context]): - print(f"{self._prompt_response}{responses[0].last_response.text}", file=self._descriptor) - - async def connect(self, pipeline_runner: PipelineRunnerFunction, **kwargs): - """ - The CLIProvider generates new dialog id used to user identification on each `connect` call. - - :param pipeline_runner: A function that should process user request and return context; - usually it's a :py:meth:`~dff.pipeline.pipeline.pipeline.Pipeline._run_pipeline` function. - :param \\**kwargs: argument, added for compatibility with super class, it shouldn't be used normally. - """ - self._ctx_id = uuid.uuid4() - if self._intro is not None: - print(self._intro) - await super().connect(pipeline_runner, **kwargs) diff --git a/dff/messengers/console.py b/dff/messengers/console.py new file mode 100644 index 000000000..12d3ee669 --- /dev/null +++ b/dff/messengers/console.py @@ -0,0 +1,49 @@ +from typing import Any, Hashable, List, Optional, TextIO, Tuple +from uuid import uuid4 +from dff.messengers.common.interface import PollingMessengerInterface +from dff.pipeline.types import PipelineRunnerFunction +from dff.script.core.context import Context +from dff.script.core.message import Message + + +class CLIMessengerInterface(PollingMessengerInterface): + """ + Command line message interface is the default message interface, communicating with user via `STDIN/STDOUT`. + This message interface can maintain dialog with one user at a time only. + """ + + supported_request_attachment_types = set() + supported_response_attachment_types = set() + + def __init__( + self, + intro: Optional[str] = None, + prompt_request: str = "request: ", + prompt_response: str = "response: ", + out_descriptor: Optional[TextIO] = None, + ): + super().__init__() + self._ctx_id: Optional[Hashable] = None + self._intro: Optional[str] = intro + self._prompt_request: str = prompt_request + self._prompt_response: str = prompt_response + self._descriptor: Optional[TextIO] = out_descriptor + + def _request(self) -> List[Tuple[Message, Any]]: + return [(Message(input(self._prompt_request)), self._ctx_id)] + + def _respond(self, responses: List[Context]): + print(f"{self._prompt_response}{responses[0].last_response.text}", file=self._descriptor) + + async def connect(self, pipeline_runner: PipelineRunnerFunction, **kwargs): + """ + The CLIProvider generates new dialog id used to user identification on each `connect` call. + + :param pipeline_runner: A function that should process user request and return context; + usually it's a :py:meth:`~dff.pipeline.pipeline.pipeline.Pipeline._run_pipeline` function. + :param \\**kwargs: argument, added for compatibility with super class, it shouldn't be used normally. + """ + self._ctx_id = uuid4() + if self._intro is not None: + print(self._intro) + await super().connect(pipeline_runner, **kwargs) diff --git a/dff/messengers/telegram/__init__.py b/dff/messengers/telegram/__init__.py index cb7e38305..771e96332 100644 --- a/dff/messengers/telegram/__init__.py +++ b/dff/messengers/telegram/__init__.py @@ -1,14 +1,4 @@ # -*- coding: utf-8 -*- -try: - import telebot -except ImportError: - raise ImportError("telebot is not installed. Run `pip install dff[telegram]`") - -from .messenger import TelegramMessenger -from .interface import PollingTelegramInterface, CallbackTelegramInterface -from .message import TelegramUI, TelegramMessage, RemoveKeyboard, ParseMode -from .messenger import ( - UpdateType, - telegram_condition, -) +from .abstract import telegram_available +from .interface import LongpollingInterface, WebhookInterface diff --git a/dff/messengers/telegram/abstract.py b/dff/messengers/telegram/abstract.py new file mode 100644 index 000000000..e0e192d4e --- /dev/null +++ b/dff/messengers/telegram/abstract.py @@ -0,0 +1,660 @@ +""" +Telegram Base +------------- +This module implements a base interface for interactions with the +Telegram API. +""" + +from pathlib import Path +from typing import Any, Callable, Optional + +from dff.utils.devel.extra_field_helpers import grab_extra_fields + +from dff.messengers.common import MessengerInterfaceWithAttachments +from dff.pipeline.types import PipelineRunnerFunction +from dff.script.core.message import ( + Animation, + Audio, + CallbackQuery, + Contact, + Document, + Image, + Invoice, + Location, + Message, + Poll, + PollOption, + Sticker, + Video, + VideoMessage, + VoiceMessage, + MediaGroup, +) + +try: + from telegram import ( + InputMediaAnimation, + InputMediaAudio, + InputMediaDocument, + InputMediaPhoto, + InputMediaVideo, + Update, + Message as TelegramMessage, + ) + from telegram.ext import Application, ExtBot, MessageHandler, CallbackQueryHandler + from telegram.ext.filters import ALL + + telegram_available = True +except ImportError: + ExtBot = Any + Update = Any + TelegramMessage = Any + + telegram_available = False + + +class _AbstractTelegramInterface(MessengerInterfaceWithAttachments): + """ + Messenger interface mixin for Telegram API usage. + """ + + supported_request_attachment_types = { + Location, + Contact, + Poll, + Sticker, + Audio, + Video, + Animation, + Image, + Document, + VoiceMessage, + VideoMessage, + Invoice, + } + supported_response_attachment_types = { + Location, + Contact, + Poll, + Sticker, + Audio, + Video, + Animation, + Image, + Document, + VoiceMessage, + VideoMessage, + MediaGroup, + } + + def __init__(self, token: str, attachments_directory: Optional[Path] = None) -> None: + super().__init__(attachments_directory) + if not telegram_available: + raise ImportError("`python-telegram-bot` package is missing.\nTry to run `pip install dff[telegram]`.") + + self.application = Application.builder().token(token).build() + self.application.add_handler(MessageHandler(ALL, self.on_message)) + self.application.add_handler(CallbackQueryHandler(self.on_callback)) + + async def get_attachment_bytes(self, source: str) -> bytes: + file = await self.application.bot.get_file(source) + data = await file.download_as_bytearray() + return bytes(data) + + def extract_message_from_telegram(self, update: TelegramMessage) -> Message: + """ + Convert Telegram update to DFF message. + Extract text and supported attachments. + + :param update: Telegram update object. + :return: DFF message object. + """ + + message = Message() + message.attachments = list() + + message.text = update.text or update.caption + if update.location is not None: + message.attachments += [Location(latitude=update.location.latitude, longitude=update.location.longitude)] + if update.contact is not None: + message.attachments += [ + Contact( + phone_number=update.contact.phone_number, + first_name=update.contact.first_name, + last_name=update.contact.last_name, + user_id=update.contact.user_id, + ) + ] + if update.invoice is not None: + message.attachments += [ + Invoice( + title=update.invoice.title, + description=update.invoice.description, + currency=update.invoice.currency, + amount=update.invoice.total_amount, + ) + ] + if update.poll is not None: + message.attachments += [ + Poll( + question=update.poll.question, + options=[PollOption(text=option.text, votes=option.voter_count) for option in update.poll.options], + is_closed=update.poll.is_closed, + is_anonymous=update.poll.is_anonymous, + type=update.poll.type, + multiple_answers=update.poll.allows_multiple_answers, + correct_option_id=update.poll.correct_option_id, + explanation=update.poll.explanation, + open_period=update.poll.open_period, + ) + ] + if update.sticker is not None: + message.attachments += [ + Sticker( + id=update.sticker.file_id, + is_animated=update.sticker.is_animated, + is_video=update.sticker.is_video, + type=update.sticker.type, + ) + ] + if update.audio is not None: + thumbnail = ( + Image(id=update.audio.thumbnail.file_id, file_unique_id=update.audio.thumbnail.file_unique_id) + if update.audio.thumbnail is not None + else None + ) + message.attachments += [ + Audio( + id=update.audio.file_id, + file_unique_id=update.audio.file_unique_id, + duration=update.audio.duration, + performer=update.audio.performer, + file_name=update.audio.file_name, + mime_type=update.audio.mime_type, + thumbnail=thumbnail, + ) + ] + if update.video is not None: + thumbnail = ( + Image(id=update.video.thumbnail.file_id, file_unique_id=update.video.thumbnail.file_unique_id) + if update.video.thumbnail is not None + else None + ) + message.attachments += [ + Video( + id=update.video.file_id, + file_unique_id=update.video.file_unique_id, + width=update.video.width, + height=update.video.height, + duration=update.video.duration, + file_name=update.video.file_name, + mime_type=update.video.mime_type, + thumbnail=thumbnail, + ) + ] + if update.animation is not None: + thumbnail = ( + Image(id=update.animation.thumbnail.file_id, file_unique_id=update.animation.thumbnail.file_unique_id) + if update.animation.thumbnail is not None + else None + ) + message.attachments += [ + Animation( + id=update.animation.file_id, + file_unique_id=update.animation.file_unique_id, + width=update.animation.width, + height=update.animation.height, + duration=update.animation.duration, + file_name=update.animation.file_name, + mime_type=update.animation.mime_type, + thumbnail=thumbnail, + ) + ] + if len(update.photo) > 0: + message.attachments += [ + Image( + id=picture.file_id, + file_unique_id=picture.file_unique_id, + width=picture.width, + height=picture.height, + ) + for picture in update.photo + ] + if update.document is not None: + thumbnail = ( + Image(id=update.document.thumbnail.file_id, file_unique_id=update.document.thumbnail.file_unique_id) + if update.document.thumbnail is not None + else None + ) + message.attachments += [ + Document( + id=update.document.file_id, + file_unique_id=update.document.file_unique_id, + file_name=update.document.file_name, + mime_type=update.document.mime_type, + thumbnail=thumbnail, + ) + ] + if update.voice is not None: + message.attachments += [ + VoiceMessage( + id=update.voice.file_id, + file_unique_id=update.voice.file_unique_id, + mime_type=update.voice.mime_type, + ) + ] + if update.video_note is not None: + thumbnail = ( + Image(id=update.video_note.thumbnail.file_id, file_unique_id=update.video_note.thumbnail.file_unique_id) + if update.video_note.thumbnail is not None + else None + ) + message.attachments += [ + VideoMessage( + id=update.video_note.file_id, + file_unique_id=update.video_note.file_unique_id, + thumbnail=thumbnail, + ) + ] + + return message + + async def cast_message_to_telegram_and_send(self, bot: ExtBot, chat_id: int, message: Message) -> None: + """ + Send DFF message to Telegram. + Sometimes, if several attachments included into message can not be sent as one update, + several Telegram updates will be produced. + Sometimes, if no text and none of the supported attachments are included, + nothing will happen. + + :param bot: Telegram bot, that is used for connection to Telegram API. + :param chat_id: Telegram dialog ID that the message will be sent to. + :param message: DFF message that will be processed into Telegram updates. + """ + + if message.text is not None: + await bot.send_message( + chat_id, + message.text, + **grab_extra_fields( + message, + [ + "parse_mode", + "disable_notification", + "protect_content", + "reply_markup", + "message_effect_id", + "reply_to_message_id", + "disable_web_page_preview", + ], + ), + ) + if message.attachments is not None: + for attachment in message.attachments: + if isinstance(attachment, Location): + await bot.send_location( + chat_id, + attachment.latitude, + attachment.longitude, + **grab_extra_fields( + attachment, + [ + "horizontal_accuracy", + "disable_notification", + "protect_content", + "reply_markup", + "message_effect_id", + "reply_to_message_id", + ], + ), + ) + elif isinstance(attachment, Contact): + await bot.send_contact( + chat_id, + attachment.phone_number, + attachment.first_name, + attachment.last_name, + **grab_extra_fields( + attachment, + [ + "vcard", + "disable_notification", + "protect_content", + "reply_markup", + "message_effect_id", + "reply_to_message_id", + ], + ), + ) + elif isinstance(attachment, Poll): + await bot.send_poll( + chat_id, + attachment.question, + [option.text for option in attachment.options], + **grab_extra_fields( + attachment, + [ + "is_anonymous", + "type", + "allows_multiple_answers", + "correct_option_id", + "explanation", + "explanation_parse_mode", + "open_period", + "is_closed", + "disable_notification", + "protect_content", + "reply_markup", + "question_parse_mode", + "message_effect_id", + "reply_to_message_id", + ], + ), + ) + elif isinstance(attachment, Audio): + attachment_bytes = await attachment.get_bytes(self) + if attachment_bytes is not None: + await bot.send_audio( + chat_id, + attachment_bytes, + **grab_extra_fields( + attachment, + [ + "caption", + "parse_mode", + "performer", + "title", + "disable_notification", + "protect_content", + "reply_markup", + "thumbnail", + "message_effect_id", + "reply_to_message_id", + "filename", + ], + ), + ) + elif isinstance(attachment, Video): + attachment_bytes = await attachment.get_bytes(self) + if attachment_bytes is not None: + await bot.send_video( + chat_id, + attachment_bytes, + **grab_extra_fields( + attachment, + [ + "caption", + "parse_mode", + "supports_streaming", + "disable_notification", + "protect_content", + "reply_markup", + "has_spoiler", + "thumbnail", + "message_effect_id", + "show_caption_above_media", + "reply_to_message_id", + "filename", + ], + ), + ) + elif isinstance(attachment, Animation): + attachment_bytes = await attachment.get_bytes(self) + if attachment_bytes is not None: + await bot.send_animation( + chat_id, + attachment_bytes, + **grab_extra_fields( + attachment, + [ + "caption", + "parse_mode", + "disable_notification", + "protect_content", + "reply_markup", + "has_spoiler", + "thumbnail", + "message_effect_id", + "show_caption_above_media", + "reply_to_message_id", + "filename", + ], + ), + ) + elif isinstance(attachment, Image): + attachment_bytes = await attachment.get_bytes(self) + if attachment_bytes is not None: + await bot.send_photo( + chat_id, + attachment_bytes, + **grab_extra_fields( + attachment, + [ + "caption", + "parse_mode", + "disable_notification", + "protect_content", + "reply_markup", + "has_spoiler", + "message_effect_id", + "reply_to_message_id", + "filename", + ], + ), + ) + elif isinstance(attachment, Sticker): + sticker = await attachment.get_bytes(self) if attachment.id is None else attachment.id + if sticker is not None: + await bot.send_sticker( + chat_id, + sticker, + **grab_extra_fields( + attachment, + [ + "emoji", + "disable_notification", + "protect_content", + "reply_markup", + "message_effect_id", + "reply_to_message_id", + ], + ), + ) + elif isinstance(attachment, Document): + attachment_bytes = await attachment.get_bytes(self) + if attachment_bytes is not None: + await bot.send_document( + chat_id, + attachment_bytes, + **grab_extra_fields( + attachment, + [ + "caption", + "parse_mode", + "disable_notification", + "protect_content", + "reply_markup", + "thumbnail", + "message_effect_id", + "reply_to_message_id", + "filename", + ], + ), + ) + elif isinstance(attachment, VoiceMessage): + attachment_bytes = await attachment.get_bytes(self) + if attachment_bytes is not None: + await bot.send_voice( + chat_id, + attachment_bytes, + **grab_extra_fields( + attachment, + [ + "caption", + "parse_mode", + "disable_notification", + "protect_content", + "reply_markup", + "message_effect_id", + "reply_to_message_id", + "filename", + ], + ), + ) + elif isinstance(attachment, VideoMessage): + attachment_bytes = await attachment.get_bytes(self) + if attachment_bytes is not None: + await bot.send_video_note( + chat_id, + attachment_bytes, + **grab_extra_fields( + attachment, + [ + "disable_notification", + "protect_content", + "reply_markup", + "thumbnail", + "message_effect_id", + "reply_to_message_id", + "filename", + ], + ), + ) + elif isinstance(attachment, MediaGroup): + files = list() + for media in attachment.group: + if isinstance(media, Image): + media_bytes = await media.get_bytes(self) + files += [ + InputMediaPhoto( + media_bytes, + **grab_extra_fields( + media, + [ + "filename", + "caption", + "parse_mode", + "has_spoiler", + "show_caption_above_media", + ], + ), + ), + ] + elif isinstance(media, Video): + media_bytes = await media.get_bytes(self) + files += [ + InputMediaVideo( + media_bytes, + **grab_extra_fields( + media, + [ + "filename", + "caption", + "parse_mode", + "supports_streaming", + "has_spoiler", + "thumbnail", + "show_caption_above_media", + ], + ), + ), + ] + elif isinstance(media, Animation): + media_bytes = await media.get_bytes(self) + files += [ + InputMediaAnimation( + media_bytes, + **grab_extra_fields( + media, + [ + "filename", + "caption", + "parse_mode", + "has_spoiler", + "thumbnail", + "show_caption_above_media", + ], + ), + ), + ] + elif isinstance(media, Audio): + media_bytes = await media.get_bytes(self) + files += [ + InputMediaAudio( + media_bytes, + **grab_extra_fields( + media, + ["filename", "caption", "parse_mode", "performer", "title", "thumbnail"], + ), + ), + ] + elif isinstance(media, Document): + media_bytes = await media.get_bytes(self) + files += [ + InputMediaDocument( + media_bytes, + **grab_extra_fields(media, ["filename", "caption", "parse_mode", "thumbnail"]), + ), + ] + else: + raise ValueError(f"Attachment {type(media).__name__} can not be sent in a media group!") + await bot.send_media_group( + chat_id, + files, + **grab_extra_fields( + attachment, + [ + "caption", + "disable_notification", + "protect_content", + "message_effect_id", + "reply_to_message_id", + "parse_mode", + ], + ), + ) + else: + raise ValueError(f"Attachment {type(attachment).__name__} is not supported!") + + async def _on_event(self, update: Update, _: Any, create_message: Callable[[Update], Message]) -> None: + """ + Process Telegram update, run pipeline and send response to Telegram. + + :param update: Telegram update that will be processed. + :param create_message: function that converts Telegram update to DFF message. + """ + + data_available = update.message is not None or update.callback_query is not None + if update.effective_chat is not None and data_available: + message = create_message(update) + message.original_message = update + resp = await self._pipeline_runner(message, update.effective_chat.id) + if resp.last_response is not None: + await self.cast_message_to_telegram_and_send( + self.application.bot, update.effective_chat.id, resp.last_response + ) + + async def on_message(self, update: Update, _: Any) -> None: + """ + Process normal Telegram update, extracting DFF message from it + using :py:meth:`~._AbstractTelegramInterface.extract_message_from_telegram`. + + :param update: Telegram update that will be processed. + """ + + await self._on_event(update, _, lambda s: self.extract_message_from_telegram(s.message)) + + async def on_callback(self, update: Update, _: Any) -> None: + """ + Process Telegram callback update, creating empty DFF message + with only one callback query attachment from `callback_query.data` field. + + :param update: Telegram update that will be processed. + """ + + await self._on_event( + update, _, lambda s: Message(attachments=[CallbackQuery(query_string=s.callback_query.data)]) + ) + + async def connect(self, pipeline_runner: PipelineRunnerFunction, *args, **kwargs): + self._pipeline_runner = pipeline_runner diff --git a/dff/messengers/telegram/interface.py b/dff/messengers/telegram/interface.py index 27a6ddd77..bcfabb0c1 100644 --- a/dff/messengers/telegram/interface.py +++ b/dff/messengers/telegram/interface.py @@ -1,223 +1,65 @@ """ -Interface ------------- -This module implements various interfaces for :py:class:`~dff.messengers.telegram.messenger.TelegramMessenger` -that can be used to interact with the Telegram API. +Telegram Interfaces +------------------- +This module provides concrete implementations of the +:py:class:`~._AbstractTelegramInterface`. """ -import asyncio -from typing import Any, Optional, List, Tuple, Callable +from pathlib import Path +from typing import Any, Optional -from telebot import types, apihelper - -from dff.messengers.common import MessengerInterface, CallbackMessengerInterface from dff.pipeline.types import PipelineRunnerFunction -from .messenger import TelegramMessenger -from .message import TelegramMessage -try: - from flask import Flask, request, abort +from .abstract import _AbstractTelegramInterface - flask_imported = True +try: + from telegram import Update except ImportError: - flask_imported = False - Flask = Any - request, abort = None, None - - -apihelper.ENABLE_MIDDLEWARE = True - - -def extract_telegram_request_and_id( - update: types.Update, messenger: Optional[TelegramMessenger] = None -) -> Tuple[TelegramMessage, int]: # pragma: no cover - """ - Utility function that extracts parameters from a telegram update. - Changes the messenger state, setting the last update id. + Update = Any - Returned message has the following fields: - - | `update_id` -- this field stores `update.update_id`, - - | `update` -- this field stores the first non-empty field of `update`, - - | `update_type` -- this field stores the name of the first non-empty field of `update`, - - | `text` -- this field stores `update.message.text`, - - | `callback_query` -- this field stores `update.callback_query.data`. - - Also return context id which is `chat`, `from_user` or `user` of the update. - - :param update: Update to process. - :param messenger: - Messenger instance. If passed updates `last_update_id`. - Defaults to None. +class LongpollingInterface(_AbstractTelegramInterface): """ - if messenger is not None: - if update.update_id > messenger.last_update_id: - messenger.last_update_id = update.update_id - - message = TelegramMessage(update_id=update.update_id) - ctx_id = None - - for update_field, update_value in vars(update).items(): - if update_field != "update_id" and update_value is not None: - if message.update is not None: - raise RuntimeError(f"Two update fields. First: {message.update_type}; second: {update_field}") - message.update_type = update_field - message.update = update_value - if isinstance(update_value, types.Message): - message.text = update_value.text - - if isinstance(update_value, types.CallbackQuery): - data = update_value.data - if data is not None: - message.callback_query = data - - dict_update = vars(update_value) - # if 'chat' is not available, fall back to 'from_user', then to 'user' - user = dict_update.get("chat", dict_update.get("from_user", dict_update.get("user"))) - ctx_id = getattr(user, "id", None) - if message.update is None: - raise RuntimeError(f"No update fields found: {update}") - - return message, ctx_id - + Telegram messenger interface, that requests Telegram API in a loop. -class PollingTelegramInterface(MessengerInterface): # pragma: no cover - """ - Telegram interface that retrieves updates by polling. - Multi-threaded polling is currently not supported. - - :param token: Bot token - :param messenger: - :py:class:`~dff.messengers.telegram.messenger.TelegramMessenger` instance. - If not `None` will be used instead of creating messenger from token. - Token value does not matter in that case. - Defaults to None. - :param interval: - Polling interval. See `link `__. - Defaults to 2. - :param allowed_updates: - Processed updates. See `link `__. - Defaults to None. - :param timeout: - General timeout. See `link `__. - Defaults to 20. - :param long_polling_timeout: - Polling timeout. See `link `__. - Defaults to 20. + :param token: The Telegram bot token. + :param attachments_directory: The directory for storing attachments. + :param interval: A time interval between polls (in seconds). + :param timeout: Timeout in seconds for long polling. """ def __init__( - self, - token: str, - interval: int = 2, - allowed_updates: Optional[List[str]] = None, - timeout: int = 20, - long_polling_timeout: int = 20, - messenger: Optional[TelegramMessenger] = None, - ): - self.messenger = ( - messenger if messenger is not None else TelegramMessenger(token, suppress_middleware_excepions=True) - ) - self.allowed_updates = allowed_updates + self, token: str, attachments_directory: Optional[Path] = None, interval: int = 2, timeout: int = 20 + ) -> None: + super().__init__(token, attachments_directory) self.interval = interval self.timeout = timeout - self.long_polling_timeout = long_polling_timeout - - async def connect(self, callback: PipelineRunnerFunction, loop: Optional[Callable] = None, *args, **kwargs): - def dff_middleware(bot_instance, update): - message, ctx_id = extract_telegram_request_and_id(update, self.messenger) - - ctx = asyncio.run(callback(message, ctx_id)) - - bot_instance.send_response(ctx_id, ctx.last_response) - - self.messenger.middleware_handler()(dff_middleware) - self.messenger.infinity_polling( - timeout=self.timeout, long_polling_timeout=self.long_polling_timeout, interval=self.interval + async def connect(self, pipeline_runner: PipelineRunnerFunction, *args, **kwargs): + await super().connect(pipeline_runner, *args, **kwargs) + self.application.run_polling( + poll_interval=self.interval, timeout=self.timeout, allowed_updates=Update.ALL_TYPES ) -class CallbackTelegramInterface(CallbackMessengerInterface): # pragma: no cover +class WebhookInterface(_AbstractTelegramInterface): """ - Asynchronous Telegram interface that retrieves updates via webhook. - Any Flask server can be passed to set up a webhook on a separate endpoint. + Telegram messenger interface, that brings a special webserver up + and registers up for listening for Telegram updates. - :param token: Bot token - :param messenger: - :py:class:`~dff.messengers.telegram.messenger.TelegramMessenger` instance. - If not `None` will be used instead of creating messenger from token. - Token value does not matter in that case. - Defaults to None. - :param app: - Flask instance. - Defaults to `Flask(__name__)`. - :param endpoint: - Webhook endpoint. Should be prefixed with "/". - Defaults to "/telegram-webhook". - :param host: - Host IP. - Defaults to "localhost". - :param port: - Port of the app. - Defaults to 8443. - :param debug: - Run the Flask app in debug mode. - :param load_dotenv: - Whether or not the .env file in the project folder - should be used to set environment variables. - :param full_uri: - Full public IP of your webhook that is accessible by https. - Defaults to `"https://{host}:{port}{endpoint}"`. - :param wsgi_options: - Keyword arguments to forward to `Flask.run` method. - Use these to set `ssl_context` and other WSGI options. + :param token: The Telegram bot token. + :param attachments_directory: The directory for storing attachments. + :param host: Local host name (or IP address). + :param port: Local port for running Telegram webhook. """ def __init__( - self, - token: str, - app: Optional[Flask] = None, - host: str = "localhost", - port: int = 8443, - debug: Optional[bool] = None, - load_dotenv: bool = True, - endpoint: str = "/telegram-webhook", - full_uri: Optional[str] = None, - messenger: Optional[TelegramMessenger] = None, - **wsgi_options, + self, token: str, attachments_directory: Optional[Path] = None, host: str = "localhost", port: int = 844 ): - if not flask_imported: - raise ModuleNotFoundError("Flask is not installed. Install it with `pip install flask`.") - - self.messenger = messenger if messenger is not None else TelegramMessenger(token) - self.app = app if app else Flask(__name__) - self.host = host + super().__init__(token, attachments_directory) + self.listen = host self.port = port - self.debug = debug - self.load_dotenv = load_dotenv - self.wsgi_options = wsgi_options - self.endpoint = endpoint - self.full_uri = full_uri if full_uri is not None else "".join([f"https://{host}:{port}", endpoint]) - - async def endpoint(): - if not request.headers.get("content-type") == "application/json": - abort(403) - - json_string = request.get_data().decode("utf-8") - update = types.Update.de_json(json_string) - resp = await self.on_request_async(*extract_telegram_request_and_id(update, self.messenger)) - self.messenger.send_response(resp.id, resp.last_response) - return "" - - self.app.route(self.endpoint, methods=["POST"])(endpoint) - async def connect(self, callback: PipelineRunnerFunction): - await super().connect(callback) - - self.messenger.remove_webhook() - self.messenger.set_webhook(self.full_uri) - - self.app.run( - host=self.host, port=self.port, load_dotenv=self.load_dotenv, debug=self.debug, **self.wsgi_options - ) + async def connect(self, pipeline_runner: PipelineRunnerFunction, *args, **kwargs): + await super().connect(pipeline_runner, *args, **kwargs) + self.application.run_webhook(listen=self.listen, port=self.port, allowed_updates=Update.ALL_TYPES) diff --git a/dff/messengers/telegram/message.py b/dff/messengers/telegram/message.py deleted file mode 100644 index 2061c470f..000000000 --- a/dff/messengers/telegram/message.py +++ /dev/null @@ -1,106 +0,0 @@ -""" -Telegram Message ----------------- -This module implements inherited classes :py:mod:`dff.script.core.message` modified for usage with Telegram. -""" - -from typing import Optional, Union -from enum import Enum - -from telebot.types import ( - ReplyKeyboardRemove, - ReplyKeyboardMarkup, - InlineKeyboardMarkup, - Message as tlMessage, - InlineQuery, - ChosenInlineResult, - CallbackQuery as tlCallbackQuery, - ShippingQuery, - PreCheckoutQuery, - Poll, - PollAnswer, - ChatMemberUpdated, - ChatJoinRequest, -) - -from dff.script.core.message import Message, Location, Keyboard, DataModel -from pydantic import model_validator - - -class TelegramUI(Keyboard): - is_inline: bool = True - """ - Whether to use `inline keyboard `__ or - a `keyboard `__. - """ - row_width: int = 3 - """Limits the maximum number of buttons in a row.""" - - @model_validator(mode="after") - def validate_buttons(self, _): - if not self.is_inline: - for button in self.buttons: - if button.payload is not None or button.source is not None: - raise AssertionError(f"`payload` and `source` are only used for inline keyboards: {button}") - return self - - -class _ClickButton(DataModel): - """This class is only used in telegram tests (to click buttons as a client).""" - - button_index: int - - -class RemoveKeyboard(DataModel): - """Pass an instance of this class to :py:attr:`~.TelegramMessage.ui` to remove current keyboard.""" - - ... - - -class ParseMode(Enum): - """ - Parse mode of the message. - More info: https://core.telegram.org/bots/api#formatting-options. - """ - - HTML = "HTML" - MARKDOWN = "MarkdownV2" - - -class TelegramMessage(Message): - ui: Optional[Union[TelegramUI, RemoveKeyboard, ReplyKeyboardRemove, ReplyKeyboardMarkup, InlineKeyboardMarkup]] = ( - None - ) - location: Optional[Location] = None - callback_query: Optional[Union[str, _ClickButton]] = None - update: Optional[ - Union[ - tlMessage, - InlineQuery, - ChosenInlineResult, - tlCallbackQuery, - ShippingQuery, - PreCheckoutQuery, - Poll, - PollAnswer, - ChatMemberUpdated, - ChatJoinRequest, - ] - ] = None - """This field stores an update representing this message.""" - update_id: Optional[int] = None - update_type: Optional[str] = None - """Name of the field that stores an update representing this message.""" - parse_mode: Optional[ParseMode] = None - """Parse mode of the message.""" - - def __eq__(self, other): - if isinstance(other, Message): - for field in self.model_fields: - if field not in ("parse_mode", "update_id", "update", "update_type"): - if field not in other.model_fields: - return False - if self.__getattribute__(field) != other.__getattribute__(field): - return False - return True - return NotImplemented diff --git a/dff/messengers/telegram/messenger.py b/dff/messengers/telegram/messenger.py deleted file mode 100644 index b88d149f9..000000000 --- a/dff/messengers/telegram/messenger.py +++ /dev/null @@ -1,248 +0,0 @@ -""" -Messenger ------------------ -The Messenger module provides the :py:class:`~dff.messengers.telegram.messenger.TelegramMessenger` class. -The former inherits from the :py:class:`~TeleBot` class from the `pytelegrambotapi` library. -Using it, you can put Telegram update handlers inside your script and condition your transitions accordingly. - -""" - -from pathlib import Path -from typing import Union, List, Optional, Callable -from enum import Enum - -from telebot import types, TeleBot - -from dff.script import Context -from dff.pipeline import Pipeline - -from .utils import batch_open_io -from .message import TelegramMessage, TelegramUI, RemoveKeyboard - -from dff.script import Message -from dff.script.core.message import Audio, Video, Image, Document - - -class TelegramMessenger(TeleBot): # pragma: no cover - """ - This class inherits from `Telebot` and implements framework-specific functionality - like sending generic responses. - - :param token: A Telegram API bot token. - :param kwargs: Arbitrary parameters that match the signature of the `Telebot` class. - For reference see: `link `_ . - - """ - - def __init__( - self, - token: str, - **kwargs, - ): - super().__init__(token, threaded=False, **kwargs) - - def send_response(self, chat_id: Union[str, int], response: Union[str, dict, Message]) -> None: - """ - Cast `response` to :py:class:`~dff.messengers.telegram.types.TelegramMessage` and send it. - Message fields are sent in separate messages in the following order: - - 1. Attachments - 2. Location - 3. Text with keyboard - - :param chat_id: Telegram chat ID. - :param response: Response data. String, dictionary or :py:class:`~dff.script.responses.generics.Response`. - will be cast to :py:class:`~dff.messengers.telegram.types.TelegramMessage`. - """ - if isinstance(response, TelegramMessage): - ready_response = response - elif isinstance(response, str): - ready_response = TelegramMessage(text=response) - elif isinstance(response, Message): - ready_response = TelegramMessage.model_validate(response.model_dump()) - elif isinstance(response, dict): - ready_response = TelegramMessage.model_validate(response) - else: - raise TypeError( - "Type of the response argument should be one of the following:" - " `str`, `dict`, `Message`, or `TelegramMessage`." - ) - parse_mode = ready_response.parse_mode.value if ready_response.parse_mode is not None else None - if ready_response.attachments is not None: - if len(ready_response.attachments.files) == 1: - attachment = ready_response.attachments.files[0] - if isinstance(attachment, Audio): - method = self.send_audio - elif isinstance(attachment, Document): - method = self.send_document - elif isinstance(attachment, Video): - method = self.send_video - elif isinstance(attachment, Image): - method = self.send_photo - else: - raise TypeError(type(attachment)) - params = {"caption": attachment.title, "parse_mode": parse_mode} - if isinstance(attachment.source, Path): - with open(attachment.source, "rb") as file: - method(chat_id, file, **params) - else: - method(chat_id, str(attachment.source or attachment.id), **params) - else: - - def cast(file): - if isinstance(file, Image): - cast_to_media_type = types.InputMediaPhoto - elif isinstance(file, Audio): - cast_to_media_type = types.InputMediaAudio - elif isinstance(file, Document): - cast_to_media_type = types.InputMediaDocument - elif isinstance(file, Video): - cast_to_media_type = types.InputMediaVideo - else: - raise TypeError(type(file)) - return cast_to_media_type(media=str(file.source or file.id), caption=file.title) - - files = map(cast, ready_response.attachments.files) - with batch_open_io(files) as media: - self.send_media_group(chat_id=chat_id, media=media) - - if ready_response.location: - self.send_location( - chat_id=chat_id, - latitude=ready_response.location.latitude, - longitude=ready_response.location.longitude, - ) - - if ready_response.ui is not None: - if isinstance(ready_response.ui, RemoveKeyboard): - keyboard = types.ReplyKeyboardRemove() - elif isinstance(ready_response.ui, TelegramUI): - if ready_response.ui.is_inline: - keyboard = types.InlineKeyboardMarkup(row_width=ready_response.ui.row_width) - buttons = [ - types.InlineKeyboardButton( - text=item.text, - url=item.source, - callback_data=item.payload, - ) - for item in ready_response.ui.buttons - ] - else: - keyboard = types.ReplyKeyboardMarkup(row_width=ready_response.ui.row_width) - buttons = [ - types.KeyboardButton( - text=item.text, - ) - for item in ready_response.ui.buttons - ] - keyboard.add(*buttons, row_width=ready_response.ui.row_width) - else: - keyboard = ready_response.ui - else: - keyboard = None - - if ready_response.text is not None: - self.send_message( - chat_id=chat_id, - text=ready_response.text, - reply_markup=keyboard, - parse_mode=parse_mode, - ) - elif keyboard is not None: - self.send_message( - chat_id=chat_id, - text="", - reply_markup=keyboard, - parse_mode=parse_mode, - ) - - -_default_messenger = TeleBot("") - - -class UpdateType(Enum): - """ - Represents a type of the telegram update - (which field contains an update in :py:class:`telebot.types.Update`). - See `link `__. - """ - - ALL = "ALL" - MESSAGE = "message" - EDITED_MESSAGE = "edited_message" - CHANNEL_POST = "channel_post" - EDITED_CHANNEL_POST = "edited_channel_post" - INLINE_QUERY = "inline_query" - CHOSEN_INLINE_RESULT = "chosen_inline_result" - CALLBACK_QUERY = "callback_query" - SHIPPING_QUERY = "shipping_query" - PRE_CHECKOUT_QUERY = "pre_checkout_query" - POLL = "poll" - POLL_ANSWER = "poll_answer" - MY_CHAT_MEMBER = "my_chat_member" - CHAT_MEMBER = "chat_member" - CHAT_JOIN_REQUEST = "chat_join_request" - - -def telegram_condition( - messenger: TeleBot = _default_messenger, - update_type: UpdateType = UpdateType.MESSAGE, - commands: Optional[List[str]] = None, - regexp: Optional[str] = None, - func: Optional[Callable] = None, - content_types: Optional[List[str]] = None, - chat_types: Optional[List[str]] = None, - **kwargs, -): - """ - A condition triggered by updates that match the given parameters. - - :param messenger: - Messenger to test filters on. Used only for :py:attr:`Telebot.custom_filters`. - Defaults to :py:data:`._default_messenger`. - :param update_type: - If set to any `UpdateType` other than `UpdateType.ALL` - it will check that an update is of the same type. - Defaults to `UpdateType.Message`. - :param commands: - Telegram command trigger. - See `link `__. - :param regexp: - Regex trigger. - See `link `__. - :param func: - Callable trigger. - See `link `__. - :param content_types: - Content type trigger. - See `link `__. - :param chat_types: - Chat type trigger. - See `link `__. - """ - - update_handler = messenger._build_handler_dict( - None, - False, - commands=commands, - regexp=regexp, - func=func, - content_types=content_types, - chat_types=chat_types, - **kwargs, - ) - - def condition(ctx: Context, _: Pipeline) -> bool: # pragma: no cover - last_request = ctx.last_request - if last_request is None: - return False - update = getattr(last_request, "update", None) - request_update_type = getattr(last_request, "update_type", None) - if update is None: - return False - if update_type != UpdateType.ALL and request_update_type != update_type.value: - return False - test_result = messenger._test_message_handler(update_handler, update) - return test_result - - return condition diff --git a/dff/messengers/telegram/utils.py b/dff/messengers/telegram/utils.py deleted file mode 100644 index de73e6369..000000000 --- a/dff/messengers/telegram/utils.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Utils ------- -This module contains utilities for connecting to Telegram. -""" - -from typing import Union, Iterable -from contextlib import contextmanager -from pathlib import Path -from io import IOBase - -from telebot import types - - -def open_io(item: types.InputMedia): - """ - Returns `InputMedia` with an opened file descriptor instead of path. - - :param item: InputMedia object. - """ - if isinstance(item.media, Path): - item.media = item.media.open(mode="rb") - return item - - -def close_io(item: types.InputMedia): - """ - Closes an IO in an `InputMedia` object to perform the cleanup. - - :param item: InputMedia object. - """ - if isinstance(item.media, IOBase): - item.media.close() - - -@contextmanager -def batch_open_io(item: Union[types.InputMedia, Iterable[types.InputMedia]]): - """ - Context manager that controls the state of file descriptors inside `InputMedia`. - Can be used both for single objects and collections. - - :param item: InputMedia objects that contain file descriptors. - """ - if isinstance(item, Iterable): - resources = list(map(open_io, item)) - else: - resources = open_io(item) - try: - yield resources - finally: - if isinstance(resources, Iterable): - for resource in resources: - close_io(resource) - else: - close_io(resources) diff --git a/dff/pipeline/pipeline/pipeline.py b/dff/pipeline/pipeline/pipeline.py index 18049a41f..a96b7b814 100644 --- a/dff/pipeline/pipeline/pipeline.py +++ b/dff/pipeline/pipeline/pipeline.py @@ -23,7 +23,8 @@ from dff.script import NodeLabel2Type, Message from dff.utils.turn_caching import cache_clear -from dff.messengers.common import MessengerInterface, CLIMessengerInterface +from dff.messengers.console import CLIMessengerInterface +from dff.messengers.common import MessengerInterface from ..service.group import ServiceGroup from ..types import ( ServiceBuilder, diff --git a/dff/pipeline/types.py b/dff/pipeline/types.py index be345f850..aafec8393 100644 --- a/dff/pipeline/types.py +++ b/dff/pipeline/types.py @@ -30,7 +30,7 @@ class PipelineRunnerFunction(Protocol): def __call__( self, message: Message, ctx_id: Optional[Hashable] = None, update_ctx_misc: Optional[dict] = None - ) -> Context: + ) -> Awaitable[Context]: """ :param message: User request for pipeline to process. :param ctx_id: diff --git a/dff/script/conditions/__init__.py b/dff/script/conditions/__init__.py index 06bebb91a..9b5fe812f 100644 --- a/dff/script/conditions/__init__.py +++ b/dff/script/conditions/__init__.py @@ -14,4 +14,5 @@ false, agg, neg, + has_callback_query, ) diff --git a/dff/script/conditions/std_conditions.py b/dff/script/conditions/std_conditions.py index 56cbc1ef9..8568a98ce 100644 --- a/dff/script/conditions/std_conditions.py +++ b/dff/script/conditions/std_conditions.py @@ -17,6 +17,7 @@ from dff.pipeline import Pipeline from dff.script import NodeLabel2Type, Context, Message +from dff.script.core.message import CallbackQuery logger = logging.getLogger(__name__) @@ -247,3 +248,21 @@ def false_handler(ctx: Context, pipeline: Pipeline) -> bool: """ :py:func:`~neg` is an alias for :py:func:`~negation`. """ + + +def has_callback_query(expected_query_string: str) -> Callable[[Context, Pipeline], bool]: + """ + Condition that checks if :py:attr:`~.CallbackQuery.query_string` + of the last message matches `expected_query_string`. + + :param expected_query_string: The expected query string to compare with. + :return: The callback query comparator function. + """ + + def has_callback_query_handler(ctx: Context, _: Pipeline) -> bool: + last_request = ctx.last_request + if last_request is None or last_request.attachments is None: + return False + return CallbackQuery(query_string=expected_query_string) in last_request.attachments + + return has_callback_query_handler diff --git a/dff/script/core/message.py b/dff/script/core/message.py index 8df480b8e..6fdf18977 100644 --- a/dff/script/core/message.py +++ b/dff/script/core/message.py @@ -5,41 +5,48 @@ DFF. It only contains types and properties that are compatible with most messaging services. """ -from typing import Any, Optional, List, Union -from enum import Enum, auto +from typing import Literal, Optional, List, Union from pathlib import Path from urllib.request import urlopen +import uuid +import abc -from pydantic import field_validator, Field, FilePath, HttpUrl, BaseModel, model_validator +from pydantic import Field, FilePath, HttpUrl, model_validator +from pydantic_core import Url +from dff.messengers.common.interface import MessengerInterfaceWithAttachments +from dff.utils.devel import JSONSerializableDict, PickleEncodedValue, JSONSerializableExtras -class Session(Enum): + +class DataModel(JSONSerializableExtras): """ - An enumeration that defines two possible states of a session. + This class is a Pydantic BaseModel that can have any type and number of extras. """ - ACTIVE = auto() - FINISHED = auto() + pass -class DataModel(BaseModel, extra="allow", arbitrary_types_allowed=True): +class Attachment(DataModel, abc.ABC): """ - This class is a Pydantic BaseModel that serves as a base class for all DFF models. + DFF Message attachment base class. + It is capable of serializing and validating all the model fields to JSON. """ - ... + dff_attachment_type: str -class Command(DataModel): +class CallbackQuery(Attachment): """ - This class is a subclass of DataModel and represents - a command that can be executed in response to a user input. + This class is a data model that represents a callback query attachment. + It is sent as a response to non-message events, e.g. keyboard UI interactions. + It has query string attribute, that represents the response data string. """ - ... + query_string: Optional[str] + dff_attachment_type: Literal["callback_query"] = "callback_query" -class Location(DataModel): +class Location(Attachment): """ This class is a data model that represents a geographical location on the Earth's surface. @@ -50,41 +57,122 @@ class Location(DataModel): longitude: float latitude: float + dff_attachment_type: Literal["location"] = "location" + + +class Contact(Attachment): + """ + This class is a data model that represents a contact. + It includes phone number, and user first and last name. + """ + + phone_number: str + first_name: str + last_name: Optional[str] + dff_attachment_type: Literal["contact"] = "contact" - def __eq__(self, other): - if isinstance(other, Location): - return abs(self.latitude - other.latitude) + abs(self.longitude - other.longitude) < 0.00004 - return NotImplemented + +class Invoice(Attachment): + """ + This class is a data model that represents an invoice. + It includes title, description, currency name and amount. + """ + + title: str + description: str + currency: str + amount: int + dff_attachment_type: Literal["invoice"] = "invoice" -class Attachment(DataModel): +class PollOption(DataModel): + """ + This class is a data model that represents a poll option. + It includes the option name and votes number. + """ + + text: str + votes: int = Field(default=0) + dff_attachment_type: Literal["poll_option"] = "poll_option" + + +class Poll(Attachment): + """ + This class is a data model that represents a poll. + It includes a list of poll options. + """ + + question: str + options: List[PollOption] + dff_attachment_type: Literal["poll"] = "poll" + + +class DataAttachment(Attachment): """ This class represents an attachment that can be either - a file or a URL, along with an optional ID and title. + a local file, a URL to a file or a ID of a file on a certain server (such as telegram). + This attachment can also be optionally cached for future use. """ source: Optional[Union[HttpUrl, FilePath]] = None - id: Optional[str] = None # id field is made separate to simplify type validation - title: Optional[str] = None + """Attachment source -- either a URL to a file or a local filepath.""" + use_cache: bool = True + """ + Whether to cache the file (only for URL and ID files). + Disable this if you want to always respond with the most up-to-date version of the file. + """ + cached_filename: Optional[Path] = None + """ + This field is used to store a path to cached version of this file (retrieved from id or URL). + This field is managed by framework. + """ + id: Optional[str] = None + """ + ID of the file on a file server (e.g. file_id for telegram attachments). + :py:meth:`~.MessengerInterfaceWithAttachments.get_attachment_bytes` is used to retrieve bytes from ID. + """ + + async def _cache_attachment(self, data: bytes, directory: Path) -> None: + """ + Cache attachment, save bytes into a file. + File has a UUID name based on its `self.source` or `self.id`. + + :param data: attachment data bytes. + :param directory: cache directory where attachment will be saved. + """ + + filename = str(uuid.uuid5(uuid.NAMESPACE_URL, str(self.source or self.id))) + self.cached_filename = directory / filename + self.cached_filename.write_bytes(data) + + async def get_bytes(self, from_interface: MessengerInterfaceWithAttachments) -> Optional[bytes]: + """ + Retrieve attachment bytes. + If the attachment is represented by URL or saved in a file, + it will be downloaded or read automatically. + If cache use is allowed and the attachment is cached, cached file will be used. + Otherwise, a :py:meth:`~.MessengerInterfaceWithAttachments.get_attachment_bytes` + will be used for receiving attachment bytes via ID. + + If cache use is allowed and the attachment is a URL or an ID, bytes will be cached locally. + + :param from_interface: messenger interface the attachment was received from. + """ - def get_bytes(self) -> Optional[bytes]: - if self.source is None: - return None if isinstance(self.source, Path): with open(self.source, "rb") as file: return file.read() - else: - with urlopen(self.source.unicode_string()) as file: + elif self.use_cache and self.cached_filename is not None and self.cached_filename.exists(): + with open(self.cached_filename, "rb") as file: return file.read() - - def __eq__(self, other): - if isinstance(other, Attachment): - if self.title != other.title: - return False - if self.id != other.id: - return False - return self.get_bytes() == other.get_bytes() - return NotImplemented + elif isinstance(self.source, Url): + with urlopen(self.source.unicode_string()) as url: + attachment_data = url.read() + else: + attachment_data = await from_interface.get_attachment_bytes(self.id) + if self.use_cache: + await self._cache_attachment(attachment_data, from_interface.attachments_directory) + return attachment_data @model_validator(mode="before") @classmethod @@ -95,134 +183,133 @@ def validate_source_or_id(cls, values: dict): raise AssertionError("Attachment type requires exactly one parameter, `source` or `id`, to be set.") return values - @field_validator("source", mode="before") - @classmethod - def validate_source(cls, value): - if isinstance(value, Path): - return Path(value) - return value - -class Audio(Attachment): +class Audio(DataAttachment): """Represents an audio file attachment.""" - pass + dff_attachment_type: Literal["audio"] = "audio" -class Video(Attachment): +class Video(DataAttachment): """Represents a video file attachment.""" - pass + dff_attachment_type: Literal["video"] = "video" -class Image(Attachment): - """Represents an image file attachment.""" +class Animation(DataAttachment): + """Represents an animation file attachment.""" - pass + dff_attachment_type: Literal["animation"] = "animation" -class Document(Attachment): - """Represents a document file attachment.""" +class Image(DataAttachment): + """Represents an image file attachment.""" - pass + dff_attachment_type: Literal["image"] = "image" -class Attachments(DataModel): - """This class is a data model that represents a list of attachments.""" +class Sticker(DataAttachment): + """Represents a sticker as a file attachment.""" - files: List[Attachment] = Field(default_factory=list) + dff_attachment_type: Literal["sticker"] = "sticker" - def __eq__(self, other): - if isinstance(other, Attachments): - return self.files == other.files - return NotImplemented +class Document(DataAttachment): + """Represents a document file attachment.""" -class Link(DataModel): - """This class is a DataModel representing a hyperlink.""" + dff_attachment_type: Literal["document"] = "document" - source: HttpUrl - title: Optional[str] = None - @property - def html(self): - return f'{self.title if self.title else self.source}' +class VoiceMessage(DataAttachment): + """Represents a voice message.""" + dff_attachment_type: Literal["voice_message"] = "voice_message" -class Button(DataModel): - """ - This class allows for the creation of a button object - with a source URL, a text description, and a payload. - """ - source: Optional[HttpUrl] = None - text: str - payload: Optional[Any] = None +class VideoMessage(DataAttachment): + """Represents a video message.""" - def __eq__(self, other): - if isinstance(other, Button): - if self.source != other.source: - return False - if self.text != other.text: - return False - first_payload = bytes(self.payload, encoding="utf-8") if isinstance(self.payload, str) else self.payload - second_payload = bytes(other.payload, encoding="utf-8") if isinstance(other.payload, str) else other.payload - return first_payload == second_payload - return NotImplemented + dff_attachment_type: Literal["video_message"] = "video_message" -class Keyboard(DataModel): - """ - This class is a DataModel that represents a keyboard object - that can be used for a chatbot or messaging application. +class MediaGroup(Attachment): """ + Represents a group of media attachments. + Without this class attachments are sent one-by-one. - buttons: List[Button] = Field(default_factory=list, min_length=1) + Be mindful of limitations that certain services apply + (e.g. Telegram does not allow audio or document files to be mixed with other types when using media groups, + so you should send them separately by putting them directly in :py:attr:`~.Message.attachments`). + """ - def __eq__(self, other): - if isinstance(other, Keyboard): - return self.buttons == other.buttons - return NotImplemented + group: List[Union[Audio, Video, Image, Document, DataAttachment]] = Field(default_factory=list) + dff_attachment_type: Literal["media_group"] = "media_group" class Message(DataModel): """ Class representing a message and contains several class level variables to store message information. + + It includes message text, list of attachments, annotations, + MISC dictionary (that consists of user-defined parameters) + and original message field that represents + the update received from messenger interface API. """ text: Optional[str] = None - commands: Optional[List[Command]] = None - attachments: Optional[Attachments] = None - annotations: Optional[dict] = None - misc: Optional[dict] = None - # commands and state options are required for integration with services - # that use an intermediate backend server, like Yandex's Alice - # state: Optional[Session] = Session.ACTIVE - # ui: Optional[Union[Keyboard, DataModel]] = None + attachments: Optional[ + List[ + Union[ + CallbackQuery, + Location, + Contact, + Invoice, + Poll, + Audio, + Video, + Animation, + Image, + Sticker, + Document, + VoiceMessage, + VideoMessage, + MediaGroup, + ] + ] + ] = None + annotations: Optional[JSONSerializableDict] = None + misc: Optional[JSONSerializableDict] = None + original_message: Optional[PickleEncodedValue] = None def __init__( self, text: Optional[str] = None, - commands: Optional[List[Command]] = None, - attachments: Optional[Attachments] = None, - annotations: Optional[dict] = None, - misc: Optional[dict] = None, + attachments: Optional[ + List[ + Union[ + CallbackQuery, + Location, + Contact, + Invoice, + Poll, + Audio, + Video, + Animation, + Image, + Sticker, + Document, + VoiceMessage, + VideoMessage, + MediaGroup, + ] + ] + ] = None, + annotations: Optional[JSONSerializableDict] = None, + misc: Optional[JSONSerializableDict] = None, **kwargs, ): - super().__init__( - text=text, commands=commands, attachments=attachments, annotations=annotations, misc=misc, **kwargs - ) - - def __eq__(self, other): - if isinstance(other, Message): - for field in self.model_fields: - if field not in other.model_fields: - return False - if self.__getattribute__(field) != other.__getattribute__(field): - return False - return True - return NotImplemented + super().__init__(text=text, attachments=attachments, annotations=annotations, misc=misc, **kwargs) def __repr__(self) -> str: return " ".join([f"{key}='{value}'" for key, value in self.model_dump(exclude_none=True).items()]) diff --git a/dff/utils/devel/__init__.py b/dff/utils/devel/__init__.py new file mode 100644 index 000000000..08ff1afbc --- /dev/null +++ b/dff/utils/devel/__init__.py @@ -0,0 +1,13 @@ +""" +Devel Utils +----------- +These utils contain useful classes/functions that are often used in various +parts of the framework. +""" + +from .json_serialization import ( + JSONSerializableDict, + PickleEncodedValue, + JSONSerializableExtras, +) +from .extra_field_helpers import grab_extra_fields diff --git a/dff/utils/devel/extra_field_helpers.py b/dff/utils/devel/extra_field_helpers.py new file mode 100644 index 000000000..13f457d27 --- /dev/null +++ b/dff/utils/devel/extra_field_helpers.py @@ -0,0 +1,22 @@ +""" +Extra field helpers +------------------- +Helpers for managing pydantic extra fields. +""" + +from typing import List + +from pydantic import BaseModel + + +def grab_extra_fields(attachment: BaseModel, extra_fields: List[str]): + """ + Convenience method for passing attachment extras as named arguments to API functions. + This might be useful for making sure no typos appear in code. + Accepts a list of extra names and makes a dictionary of extras mathing these names. + + :param attachment: attachment whose extras will be used. + :param extra_fields: list of extras that will be used. + """ + + return {extra_field: attachment.__pydantic_extra__.get(extra_field, None) for extra_field in extra_fields} diff --git a/dff/utils/devel/json_serialization.py b/dff/utils/devel/json_serialization.py new file mode 100644 index 000000000..017fc791e --- /dev/null +++ b/dff/utils/devel/json_serialization.py @@ -0,0 +1,191 @@ +""" +Serialization +------------- +Tools that provide JSON serialization via Pickle for unserializable objects. + +- :py:data:`~.PickleEncodedValue`: + A field annotated with this will be pickled/unpickled during JSON-serialization/validation. +- :py:data:`~.JSONSerializableDict`: + A dictionary field annotated with this will make all its items smart-serializable: + If an item is serializable -- nothing would change. + Otherwise -- it will be serialized via pickle. +- :py:class:`~.JSONSerializableExtras`: + A pydantic base class that makes its extra fields a `JSONSerializableDict`. +""" + +from base64 import decodebytes, encodebytes +from copy import deepcopy +from pickle import dumps, loads +from typing import Any, Dict, List, Union +from typing_extensions import Annotated, TypeAlias +from pydantic import ( + JsonValue, + PlainSerializer, + PlainValidator, + RootModel, + BaseModel, + model_validator, + model_serializer, +) +from pydantic_core import PydanticSerializationError + +_JSON_EXTRA_FIELDS_KEYS = "__pickled_extra_fields__" +""" +This key is used in :py:data:`~.JSONSerializableDict` to remember pickled items. +""" + +Serializable: TypeAlias = Dict[str, Union[JsonValue, List[Any], Dict[str, Any], Any]] +"""Type annotation for objects supported by :py:func:`~.json_pickle_serializer`.""" + + +class _WrapperModel(RootModel): + """ + Wrapper model for testing whether an object is serializable to JSON. + """ + + root: Any + + +def pickle_serializer(value: Any) -> str: + """ + Serializer function that serializes any pickle-serializable value into JSON-serializable. + Serializes value with pickle and encodes bytes as base64 string. + + :param value: Pickle-serializable object. + :return: String-encoded object. + """ + + return encodebytes(dumps(value)).decode() + + +def pickle_validator(value: str) -> Any: + """ + Validator function that validates base64 string encoded bytes as a pickle-serializable value. + Decodes base64 string and validates value with pickle. + + :param value: String-encoded string. + :return: Pickle-serializable object. + """ + + return loads(decodebytes(value.encode())) + + +def json_pickle_serializer(model: Serializable) -> Serializable: + """ + Serializer function that serializes a dictionary or Pydantic object to JSON. + For every object field, it checks whether the field is JSON serializable, + and if it's not, serializes it using pickle. + It also keeps track of pickle-serializable field names in a special list. + + :param model: Pydantic model object or a dictionary. + :original_serializer: Original serializer function for model. + :return: model with all the fields serialized to JSON. + """ + + extra_fields = list() + model_copy = deepcopy(model) + + for field_name, field_value in model_copy.items(): + try: + if isinstance(field_value, bytes): + raise PydanticSerializationError("") + else: + model_copy[field_name] = _WrapperModel(root=field_value).model_dump(mode="json") + except PydanticSerializationError: + model_copy[field_name] = pickle_serializer(field_value) + extra_fields += [field_name] + + if len(extra_fields) > 0: + model_copy[_JSON_EXTRA_FIELDS_KEYS] = extra_fields + return model_copy + + +def json_pickle_validator(model: Serializable) -> Serializable: + """ + Validator function that validates a JSON dictionary to a python dictionary. + For every object field, it checks if the field is pickle-serialized, + and if it is, validates it using pickle. + + :param model: Pydantic model object or a dictionary. + :return: model with all the fields serialized to JSON. + """ + + model_copy = deepcopy(model) + + if _JSON_EXTRA_FIELDS_KEYS in model.keys(): + for extra_key in model[_JSON_EXTRA_FIELDS_KEYS]: + extra_value = model[extra_key] + model_copy[extra_key] = pickle_validator(extra_value) + del model_copy[_JSON_EXTRA_FIELDS_KEYS] + + return model_copy + + +PickleSerializer = PlainSerializer(pickle_serializer, when_used="json") +"""Pydantic wrapper of :py:func:`~.pickle_serializer`.""" +PickleValidator = PlainValidator(pickle_validator) +"""Pydantic wrapper of :py:func:`~.pickle_validator`.""" +PickleEncodedValue = Annotated[Any, PickleSerializer, PickleValidator] +""" +Annotation for field that makes it JSON serializable via pickle: + +This field is always a normal object when inside its class but is a string encoding of the object +outside of the class -- either after serialization or before initialization. +As such this field cannot be used during initialization and the only way to use it is to bypass validation. + +.. code:: python + + class MyClass(BaseModel): + my_field: Optional[PickleEncodedValue] = None # the field must have a default value + + my_obj = MyClass() # the field cannot be set during init + my_obj.my_field = unserializable_object # can be set manually to avoid validation + +""" + +JSONPickleSerializer = PlainSerializer(json_pickle_serializer, when_used="json") +"""Pydantic wrapper of :py:func:`~.json_pickle_serializer`.""" +JSONPickleValidator = PlainValidator(json_pickle_validator) +"""Pydantic wrapper of :py:func:`~.json_pickle_validator`.""" +JSONSerializableDict = Annotated[Serializable, JSONPickleSerializer, JSONPickleValidator] +""" +Annotation for dictionary or Pydantic model that makes all its fields JSON serializable. + +This uses a reserved dictionary key :py:data:`~._JSON_EXTRA_FIELDS_KEYS` to store +fields serialized that way. +""" + + +class JSONSerializableExtras(BaseModel, extra="allow"): + """ + This model makes extra fields pickle-serializable. + Do not use :py:data:`~._JSON_EXTRA_FIELDS_KEYS` as an extra field name. + """ + + def __init__(self, **kwargs): # supress unknown arg warnings + super().__init__(**kwargs) + + @model_validator(mode="after") + def extra_validator(self): + """ + Validate model along with the `extras` field: i.e. all the fields not listed in the model. + + :return: Validated model. + """ + self.__pydantic_extra__ = json_pickle_validator(self.__pydantic_extra__) + return self + + @model_serializer(mode="wrap", when_used="json") + def extra_serializer(self, original_serializer) -> Dict[str, Any]: + """ + Serialize model along with the `extras` field: i.e. all the fields not listed in the model. + + :param original_serializer: Function originally used for serialization by Pydantic. + :return: Serialized model. + """ + model_copy = self.model_copy(deep=True) + for extra_name in self.model_extra.keys(): + delattr(model_copy, extra_name) + model_dict = original_serializer(model_copy) + model_dict.update(json_pickle_serializer(self.model_extra)) + return model_dict diff --git a/dff/utils/testing/telegram.py b/dff/utils/testing/telegram.py deleted file mode 100644 index 90fcd06b2..000000000 --- a/dff/utils/testing/telegram.py +++ /dev/null @@ -1,278 +0,0 @@ -""" -Telegram testing utils ----------------------- -This module defines functions used to test Telegram interface. -""" - -from typing import List, Optional, cast, Tuple -from contextlib import asynccontextmanager, nullcontext -import logging -import asyncio -from tempfile import TemporaryDirectory -from pathlib import Path -from copy import deepcopy - -from telethon.tl.types import ReplyKeyboardHide -from telethon import TelegramClient -from telethon.types import User -from telethon.custom import Message as TlMessage -from telebot import types - -from dff.pipeline.pipeline.pipeline import Pipeline -from dff.script.core.message import Message, Attachments, Attachment, Button, Location -from dff.messengers.telegram.interface import PollingTelegramInterface -from dff.messengers.telegram.message import TelegramMessage, TelegramUI, RemoveKeyboard, _ClickButton - - -def replace_click_button(happy_path): - """ - Replace all _ClickButton instances in `happy_path`. - This allows using :py:func:`~dff.utils.testing.common.check_happy_path` instead of - :py:meth:~dff.utils.testing.telegram.TelegramTesting.check_happy_path`. - - :return: A `happy_path` with all `_ClickButton` replaced with payload values of the buttons. - """ - result = deepcopy(happy_path) - for index in range(len(happy_path)): - user_request = happy_path[index][0] - if not isinstance(user_request, TelegramMessage): - continue - if isinstance(user_request.callback_query, _ClickButton): - callback_query = None - for _, bot_response in reversed(happy_path[:index]): - if isinstance(bot_response, TelegramMessage) and bot_response.ui is not None and callback_query is None: - callback_query = bot_response.ui.buttons[user_request.callback_query.button_index].payload - if callback_query is None: - raise RuntimeError("Bot response with buttons not found.") - result[index][0].callback_query = callback_query - return result - - -async def get_bot_user(client: TelegramClient, username: str): - async with client: - return await client.get_entity(username) - - -class TelegramTesting: # pragma: no cover - """ - Defines functions for testing. - - :param pipeline: - Pipeline with the telegram messenger interface. - Required for :py:meth:`~dff.utils.testing.telegram.TelegramTesting.send_and_check` and - :py:meth:`~dff.utils.testing.telegram.TelegramTesting.check_happy_path` with `run_bot=True` - :param api_credentials: - Telegram API id and hash. - Obtainable via https://core.telegram.org/api/obtaining_api_id. - :param session_file: - A `telethon` session file. - Obtainable by connecting to :py:class:`telethon.TelegramClient` and entering phone number and code. - :param client: - An alternative to passing `api_credentials` and `session_file`. - :param bot_username: - Either a link to the bot user or its handle. Used to determine whom to talk with as a client. - :param bot: - An alternative to passing `bot_username`. - Result of calling :py:func:`~dff.utils.testing.telegram.get_bot_user` with `bot_username` as parameter. - """ - - def __init__( - self, - pipeline: Pipeline, - api_credentials: Optional[Tuple[int, str]] = None, - session_file: Optional[str] = None, - client: Optional[TelegramClient] = None, - bot_username: Optional[str] = None, - bot: Optional[User] = None, - ): - if client is None: - if api_credentials is None or session_file is None: - raise RuntimeError("Pass either `client` or `api_credentials` and `session_file`.") - client = TelegramClient(session_file, *api_credentials) - self.client = client - """Telegram client (not bot). Needed to verify bot replies.""" - self.pipeline = pipeline - if bot is None: - if bot_username is None: - raise RuntimeError("Pass either `bot_username` or `bot`.") - bot = asyncio.run(get_bot_user(self.client, bot_username)) - self.bot = bot - """Bot user (to know whom to send messages to from client).""" - - async def send_message(self, message: TelegramMessage, last_bot_messages: List[TlMessage]): - """ - Send a message from client to bot. - If the message contains `callback_query`, only press the button, ignore other fields. - - :param message: Message to send. - :param last_bot_messages: - The last bot response. Accepts a list because messages with multiple fields are split in telegram. - Can only contain one keyboard in the list. - Used to determine which button to press when message contains - :py:class:`~dff.messengers.telegram.message._ClickButton`. - """ - if message.callback_query is not None: - query = message.callback_query - if not isinstance(query, _ClickButton): - raise RuntimeError(f"Use `_ClickButton` during tests: {query}") - for bot_message in last_bot_messages: - if bot_message.buttons is not None: - await bot_message.click(i=query.button_index) - return None - if message.attachments is None or len(message.attachments.files) == 0: - return await self.client.send_message(self.bot, message.text) - else: - if len(message.attachments.files) == 1: - attachment = message.attachments.files[0] - files = attachment.source - else: - files = [file.source for file in message.attachments.files] - return await self.client.send_file(self.bot, files, caption=message.text) - - @staticmethod - async def parse_responses(responses: List[TlMessage], file_download_destination) -> Message: - """ - Convert a list of bot responses into a single message. - This function accepts a list because messages with multiple attachments are split. - - :param responses: A list of bot responses that are considered to be a single message. - :param file_download_destination: A directory to download sent media to. - """ - msg = TelegramMessage() - for response in responses: - if response.text and response.file is None: - if msg.text: - raise RuntimeError(f"Several messages with text:\n{msg.text}\n{response.text}") - msg.text = response.text or msg.text - if response.file is not None: - file = Path(file_download_destination) / (str(response.file.media.id) + response.file.ext) - await response.download_media(file=file) - if msg.attachments is None: - msg.attachments = Attachments() - msg.attachments.files.append( - Attachment(source=file, id=None, title=response.file.title or response.text or None) - ) - if response.buttons is not None: - buttons = [] - for row in response.buttons: - for button in row: - buttons.append( - Button( - source=button.url, - text=button.text, - payload=button.data, - ) - ) - if msg.ui is not None: - raise RuntimeError(f"Several messages with ui:\n{msg.ui}\n{TelegramUI(buttons=buttons)}") - msg.ui = TelegramUI(buttons=buttons) - if isinstance(response.reply_markup, ReplyKeyboardHide): - if msg.ui is not None: - raise RuntimeError(f"Several messages with ui:\n{msg.ui}\n{types.ReplyKeyboardRemove()}") - msg.ui = RemoveKeyboard() - if response.geo is not None: - location = Location(latitude=response.geo.lat, longitude=response.geo.long) - if msg.location is not None: - raise RuntimeError(f"Several messages with location:\n{msg.location}\n{location}") - msg.location = location - return msg - - @asynccontextmanager - async def run_bot_loop(self): - """A context manager that returns a function to run one polling loop of a messenger interface.""" - self.pipeline.messenger_interface.timeout = 2 - self.pipeline.messenger_interface.long_polling_timeout = 2 - await self.forget_previous_updates() - - yield lambda: self.pipeline.messenger_interface._polling_loop(self.pipeline._run_pipeline) - - self.pipeline.messenger_interface.forget_processed_updates() - - async def send_and_check(self, message: Message, file_download_destination=None): - """ - Send a message from a bot, receive it as client, verify it. - - :param message: Message to send and check. - :param file_download_destination: - Temporary directory (used to download sent files). - Defaults to :py:class:`tempfile.TemporaryDirectory`. - """ - await self.forget_previous_updates() - - async with self.client: - messenger_interface = cast(PollingTelegramInterface, self.pipeline.messenger_interface) - - messages = await self.client.get_messages(self.bot, limit=1) - if len(messages) == 0: - last_message_id = 0 - else: - last_message_id = messages[0].id - - messenger_interface.messenger.send_response((await self.client.get_me(input_peer=True)).user_id, message) - - await asyncio.sleep(3) - bot_messages = [ - x async for x in self.client.iter_messages(self.bot, min_id=last_message_id, from_user=self.bot) - ] # iter_messages is used instead of get_messages because get_messages requires bot min_id and max_id - - if file_download_destination is None: - fd_context = TemporaryDirectory() - else: - fd_context = nullcontext(file_download_destination) - - with fd_context as file_download_destination: - result = await self.parse_responses(bot_messages, file_download_destination) - - assert result == message - - async def forget_previous_updates(self): - messenger_interface = cast(PollingTelegramInterface, self.pipeline.messenger_interface) - messenger = messenger_interface.messenger - updates = messenger.get_updates(offset=messenger.last_update_id + 1, timeout=1, long_polling_timeout=1) - max_update_id = max([*map(lambda x: x.update_id, updates), -1]) - messenger.get_updates(offset=max_update_id + 1, timeout=1, long_polling_timeout=1) - - async def check_happy_path(self, happy_path, file_download_destination=None, run_bot: bool = True): - """ - Play out a dialogue with the bot. Check that the dialogue is correct. - - :param happy_path: Expected dialogue - :param file_download_destination: Temporary directory (used to download sent files) - :param run_bot: Whether a bot inside pipeline should be running (disable this to test non-async bots) - :return: - """ - if run_bot: - bot = self.run_bot_loop() - else: - - async def null(): ... # noqa: E704 - - bot = nullcontext(null) - - if file_download_destination is None: - fd_context = TemporaryDirectory() - else: - fd_context = nullcontext(file_download_destination) - - async with self.client, bot as boot_loop: - with fd_context as file_download_destination: - bot_messages = [] - last_message = None - for request, response in happy_path: - logging.info(f"Sending request {request}") - user_message = await self.send_message(TelegramMessage.model_validate(request), bot_messages) - if user_message is not None: - last_message = user_message - logging.info("Request sent") - await boot_loop() - await asyncio.sleep(2) - logging.info("Extracting responses") - bot_messages = [ - x async for x in self.client.iter_messages(self.bot, min_id=last_message.id, from_user=self.bot) - ] - # iter_messages is used instead of get_messages because get_messages requires bot min_id and max_id - if len(bot_messages) > 0: - last_message = bot_messages[0] - logging.info("Got responses") - result = await self.parse_responses(bot_messages, file_download_destination) - assert result == TelegramMessage.model_validate(response) diff --git a/docs/source/conf.py b/docs/source/conf.py index 3ac5149e3..a4b65beb8 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -197,5 +197,6 @@ def setup(_): ("dff.utils.testing", "Testing Utils"), ("dff.utils.turn_caching", "Caching"), ("dff.utils.db_benchmark", "DB Benchmark"), + ("dff.utils.devel", "Development Utils"), ] ) diff --git a/poetry.lock b/poetry.lock index 00b728981..5f1b51b77 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "accessible-pygments" @@ -35,98 +35,98 @@ httpx-speedups = ["ciso8601 (>=2.3.0)", "httpx"] [[package]] name = "aiofiles" -version = "23.2.1" +version = "24.1.0" description = "File support for asyncio." optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "aiofiles-23.2.1-py3-none-any.whl", hash = "sha256:19297512c647d4b27a2cf7c34caa7e405c0d60b5560618a29a9fe027b18b0107"}, - {file = "aiofiles-23.2.1.tar.gz", hash = "sha256:84ec2218d8419404abcb9f0c02df3f34c6e0a68ed41072acfb1cef5cbc29051a"}, + {file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"}, + {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"}, ] [[package]] name = "aiohttp" -version = "3.9.3" +version = "3.9.5" description = "Async http client/server framework (asyncio)" optional = true python-versions = ">=3.8" files = [ - {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54"}, - {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc"}, - {file = "aiohttp-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52"}, - {file = "aiohttp-3.9.3-cp310-cp310-win32.whl", hash = "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b"}, - {file = "aiohttp-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4"}, - {file = "aiohttp-3.9.3-cp311-cp311-win32.whl", hash = "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5"}, - {file = "aiohttp-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f"}, - {file = "aiohttp-3.9.3-cp312-cp312-win32.whl", hash = "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38"}, - {file = "aiohttp-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ed621426d961df79aa3b963ac7af0d40392956ffa9be022024cd16297b30c8c"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f46acd6a194287b7e41e87957bfe2ad1ad88318d447caf5b090012f2c5bb528"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feeb18a801aacb098220e2c3eea59a512362eb408d4afd0c242044c33ad6d542"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f734e38fd8666f53da904c52a23ce517f1b07722118d750405af7e4123933511"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b40670ec7e2156d8e57f70aec34a7216407848dfe6c693ef131ddf6e76feb672"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdd215b7b7fd4a53994f238d0f46b7ba4ac4c0adb12452beee724ddd0743ae5d"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e99abf0bba688259a496f966211c49a514e65afa9b3073a1fcee08856e04425b"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:648056db9a9fa565d3fa851880f99f45e3f9a771dd3ff3bb0c048ea83fb28194"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8aacb477dc26797ee089721536a292a664846489c49d3ef9725f992449eda5a8"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:522a11c934ea660ff8953eda090dcd2154d367dec1ae3c540aff9f8a5c109ab4"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5bce0dc147ca85caa5d33debc4f4d65e8e8b5c97c7f9f660f215fa74fc49a321"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b4af9f25b49a7be47c0972139e59ec0e8285c371049df1a63b6ca81fdd216a2"}, - {file = "aiohttp-3.9.3-cp38-cp38-win32.whl", hash = "sha256:298abd678033b8571995650ccee753d9458dfa0377be4dba91e4491da3f2be63"}, - {file = "aiohttp-3.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:69361bfdca5468c0488d7017b9b1e5ce769d40b46a9f4a2eed26b78619e9396c"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d"}, - {file = "aiohttp-3.9.3-cp39-cp39-win32.whl", hash = "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051"}, - {file = "aiohttp-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc"}, - {file = "aiohttp-3.9.3.tar.gz", hash = "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7"}, + {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7"}, + {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c"}, + {file = "aiohttp-3.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10"}, + {file = "aiohttp-3.9.5-cp310-cp310-win32.whl", hash = "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb"}, + {file = "aiohttp-3.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb"}, + {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342"}, + {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d"}, + {file = "aiohttp-3.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75"}, + {file = "aiohttp-3.9.5-cp311-cp311-win32.whl", hash = "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6"}, + {file = "aiohttp-3.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a"}, + {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678"}, + {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c"}, + {file = "aiohttp-3.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da"}, + {file = "aiohttp-3.9.5-cp312-cp312-win32.whl", hash = "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59"}, + {file = "aiohttp-3.9.5-cp312-cp312-win_amd64.whl", hash = "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888"}, + {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8"}, + {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8"}, + {file = "aiohttp-3.9.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe"}, + {file = "aiohttp-3.9.5-cp38-cp38-win32.whl", hash = "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da"}, + {file = "aiohttp-3.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a"}, + {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed"}, + {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a"}, + {file = "aiohttp-3.9.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2"}, + {file = "aiohttp-3.9.5-cp39-cp39-win32.whl", hash = "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09"}, + {file = "aiohttp-3.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1"}, + {file = "aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551"}, ] [package.dependencies] @@ -140,6 +140,17 @@ yarl = ">=1.0,<2.0" [package.extras] speedups = ["Brotli", "aiodns", "brotlicffi"] +[[package]] +name = "aiolimiter" +version = "1.1.0" +description = "asyncio rate limiter, a leaky bucket implementation" +optional = true +python-versions = ">=3.7,<4.0" +files = [ + {file = "aiolimiter-1.1.0-py3-none-any.whl", hash = "sha256:0b4997961fc58b8df40279e739f9cf0d3e255e63e9a44f64df567a8c17241e24"}, + {file = "aiolimiter-1.1.0.tar.gz", hash = "sha256:461cf02f82a29347340d031626c92853645c099cb5ff85577b831a7bd21132b5"}, +] + [[package]] name = "aiosignal" version = "1.3.1" @@ -210,13 +221,13 @@ doc = ["docutils", "jinja2", "myst-parser", "numpydoc", "pillow (>=9,<10)", "pyd [[package]] name = "annotated-types" -version = "0.6.0" +version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" files = [ - {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, - {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, ] [package.dependencies] @@ -234,13 +245,13 @@ files = [ [[package]] name = "anyio" -version = "4.3.0" +version = "4.4.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" files = [ - {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, - {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, + {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, + {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, ] [package.dependencies] @@ -265,6 +276,34 @@ files = [ {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, ] +[[package]] +name = "apscheduler" +version = "3.10.4" +description = "In-process task scheduler with Cron-like capabilities" +optional = true +python-versions = ">=3.6" +files = [ + {file = "APScheduler-3.10.4-py3-none-any.whl", hash = "sha256:fb91e8a768632a4756a585f79ec834e0e27aad5860bac7eaa523d9ccefd87661"}, + {file = "APScheduler-3.10.4.tar.gz", hash = "sha256:e6df071b27d9be898e486bc7940a7be50b4af2e9da7c08f0744a96d4bd4cef4a"}, +] + +[package.dependencies] +pytz = "*" +six = ">=1.4.0" +tzlocal = ">=2.0,<3.dev0 || >=4.dev0" + +[package.extras] +doc = ["sphinx", "sphinx-rtd-theme"] +gevent = ["gevent"] +mongodb = ["pymongo (>=3.0)"] +redis = ["redis (>=3.0)"] +rethinkdb = ["rethinkdb (>=2.4.0)"] +sqlalchemy = ["sqlalchemy (>=1.4)"] +testing = ["pytest", "pytest-asyncio", "pytest-cov", "pytest-tornado5"] +tornado = ["tornado (>=4.3)"] +twisted = ["twisted"] +zookeeper = ["kazoo"] + [[package]] name = "argon2-cffi" version = "23.1.0" @@ -343,13 +382,13 @@ test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock [[package]] name = "asgiref" -version = "3.7.2" +version = "3.8.1" description = "ASGI specs, helper code, and adapters" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, - {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, + {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, + {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, ] [package.dependencies] @@ -545,13 +584,13 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p [[package]] name = "babel" -version = "2.14.0" +version = "2.15.0" description = "Internationalization utilities" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Babel-2.14.0-py3-none-any.whl", hash = "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"}, - {file = "Babel-2.14.0.tar.gz", hash = "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363"}, + {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, + {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, ] [package.dependencies] @@ -571,6 +610,34 @@ files = [ {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, ] +[[package]] +name = "backports-zoneinfo" +version = "0.2.1" +description = "Backport of the standard library zoneinfo module" +optional = true +python-versions = ">=3.6" +files = [ + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"}, + {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, +] + +[package.extras] +tzdata = ["tzdata"] + [[package]] name = "beautifulsoup4" version = "4.12.3" @@ -594,33 +661,33 @@ lxml = ["lxml"] [[package]] name = "black" -version = "24.4.0" +version = "24.4.2" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-24.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6ad001a9ddd9b8dfd1b434d566be39b1cd502802c8d38bbb1ba612afda2ef436"}, - {file = "black-24.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3a3a092b8b756c643fe45f4624dbd5a389f770a4ac294cf4d0fce6af86addaf"}, - {file = "black-24.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dae79397f367ac8d7adb6c779813328f6d690943f64b32983e896bcccd18cbad"}, - {file = "black-24.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:71d998b73c957444fb7c52096c3843875f4b6b47a54972598741fe9a7f737fcb"}, - {file = "black-24.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8e5537f456a22cf5cfcb2707803431d2feeb82ab3748ade280d6ccd0b40ed2e8"}, - {file = "black-24.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64e60a7edd71fd542a10a9643bf369bfd2644de95ec71e86790b063aa02ff745"}, - {file = "black-24.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cd5b4f76056cecce3e69b0d4c228326d2595f506797f40b9233424e2524c070"}, - {file = "black-24.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:64578cf99b6b46a6301bc28bdb89f9d6f9b592b1c5837818a177c98525dbe397"}, - {file = "black-24.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f95cece33329dc4aa3b0e1a771c41075812e46cf3d6e3f1dfe3d91ff09826ed2"}, - {file = "black-24.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4396ca365a4310beef84d446ca5016f671b10f07abdba3e4e4304218d2c71d33"}, - {file = "black-24.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44d99dfdf37a2a00a6f7a8dcbd19edf361d056ee51093b2445de7ca09adac965"}, - {file = "black-24.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:21f9407063ec71c5580b8ad975653c66508d6a9f57bd008bb8691d273705adcd"}, - {file = "black-24.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:652e55bb722ca026299eb74e53880ee2315b181dfdd44dca98e43448620ddec1"}, - {file = "black-24.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7f2966b9b2b3b7104fca9d75b2ee856fe3fdd7ed9e47c753a4bb1a675f2caab8"}, - {file = "black-24.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bb9ca06e556a09f7f7177bc7cb604e5ed2d2df1e9119e4f7d2f1f7071c32e5d"}, - {file = "black-24.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4e71cdebdc8efeb6deaf5f2deb28325f8614d48426bed118ecc2dcaefb9ebf3"}, - {file = "black-24.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6644f97a7ef6f401a150cca551a1ff97e03c25d8519ee0bbc9b0058772882665"}, - {file = "black-24.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:75a2d0b4f5eb81f7eebc31f788f9830a6ce10a68c91fbe0fade34fff7a2836e6"}, - {file = "black-24.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb949f56a63c5e134dfdca12091e98ffb5fd446293ebae123d10fc1abad00b9e"}, - {file = "black-24.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:7852b05d02b5b9a8c893ab95863ef8986e4dda29af80bbbda94d7aee1abf8702"}, - {file = "black-24.4.0-py3-none-any.whl", hash = "sha256:74eb9b5420e26b42c00a3ff470dc0cd144b80a766128b1771d07643165e08d0e"}, - {file = "black-24.4.0.tar.gz", hash = "sha256:f07b69fda20578367eaebbd670ff8fc653ab181e1ff95d84497f9fa20e7d0641"}, + {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, + {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, + {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, + {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, + {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, + {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, + {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, + {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, + {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, + {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, + {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, + {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, + {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, + {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, + {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, + {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, + {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, + {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, + {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, + {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, + {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, + {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, ] [package.dependencies] @@ -658,13 +725,13 @@ css = ["tinycss2 (>=1.1.0,<1.3)"] [[package]] name = "blinker" -version = "1.7.0" +version = "1.8.2" description = "Fast, simple object-to-object and broadcast signaling" optional = false python-versions = ">=3.8" files = [ - {file = "blinker-1.7.0-py3-none-any.whl", hash = "sha256:c3f865d4d54db7abc53758a01601cf343fe55b84c1de4e3fa910e420b438d5b9"}, - {file = "blinker-1.7.0.tar.gz", hash = "sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182"}, + {file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"}, + {file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"}, ] [[package]] @@ -761,26 +828,27 @@ files = [ [[package]] name = "build" -version = "1.0.3" +version = "1.2.1" description = "A simple, correct Python build frontend" optional = false -python-versions = ">= 3.7" +python-versions = ">=3.8" files = [ - {file = "build-1.0.3-py3-none-any.whl", hash = "sha256:589bf99a67df7c9cf07ec0ac0e5e2ea5d4b37ac63301c4986d1acb126aa83f8f"}, - {file = "build-1.0.3.tar.gz", hash = "sha256:538aab1b64f9828977f84bc63ae570b060a8ed1be419e7870b8b4fc5e6ea553b"}, + {file = "build-1.2.1-py3-none-any.whl", hash = "sha256:75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4"}, + {file = "build-1.2.1.tar.gz", hash = "sha256:526263f4870c26f26c433545579475377b2b7588b6f1eac76a001e873ae3e19d"}, ] [package.dependencies] colorama = {version = "*", markers = "os_name == \"nt\""} -importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""} -packaging = ">=19.0" +importlib-metadata = {version = ">=4.6", markers = "python_full_version < \"3.10.2\""} +packaging = ">=19.1" pyproject_hooks = "*" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} [package.extras] docs = ["furo (>=2023.08.17)", "sphinx (>=7.0,<8.0)", "sphinx-argparse-cli (>=1.5)", "sphinx-autodoc-typehints (>=1.10)", "sphinx-issues (>=3.0.0)"] -test = ["filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0)", "setuptools (>=56.0.0)", "setuptools (>=56.0.0)", "setuptools (>=67.8.0)", "wheel (>=0.36.0)"] -typing = ["importlib-metadata (>=5.1)", "mypy (>=1.5.0,<1.6.0)", "tomli", "typing-extensions (>=3.7.4.3)"] +test = ["build[uv,virtualenv]", "filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0)", "setuptools (>=56.0.0)", "setuptools (>=56.0.0)", "setuptools (>=67.8.0)", "wheel (>=0.36.0)"] +typing = ["build[uv]", "importlib-metadata (>=5.1)", "mypy (>=1.9.0,<1.10.0)", "tomli", "typing-extensions (>=3.7.4.3)"] +uv = ["uv (>=0.1.18)"] virtualenv = ["virtualenv (>=20.0.35)"] [[package]] @@ -817,13 +885,13 @@ files = [ [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.6.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, + {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, ] [[package]] @@ -1031,13 +1099,13 @@ files = [ [[package]] name = "comm" -version = "0.2.1" +version = "0.2.2" description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." optional = false python-versions = ">=3.8" files = [ - {file = "comm-0.2.1-py3-none-any.whl", hash = "sha256:87928485c0dfc0e7976fd89fc1e187023cf587e7c353e4a9b417555b44adf021"}, - {file = "comm-0.2.1.tar.gz", hash = "sha256:0bc91edae1344d39d3661dcbc36937181fdaddb304790458f8b044dbc064b89a"}, + {file = "comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"}, + {file = "comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e"}, ] [package.dependencies] @@ -1074,63 +1142,63 @@ files = [ [[package]] name = "coverage" -version = "7.5.3" +version = "7.5.4" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45"}, - {file = "coverage-7.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec"}, - {file = "coverage-7.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286"}, - {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc"}, - {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d"}, - {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83"}, - {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d"}, - {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c"}, - {file = "coverage-7.5.3-cp310-cp310-win32.whl", hash = "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84"}, - {file = "coverage-7.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac"}, - {file = "coverage-7.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974"}, - {file = "coverage-7.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232"}, - {file = "coverage-7.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd"}, - {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807"}, - {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb"}, - {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc"}, - {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8"}, - {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614"}, - {file = "coverage-7.5.3-cp311-cp311-win32.whl", hash = "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9"}, - {file = "coverage-7.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a"}, - {file = "coverage-7.5.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8"}, - {file = "coverage-7.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3"}, - {file = "coverage-7.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1"}, - {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db"}, - {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd"}, - {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523"}, - {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"}, - {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84"}, - {file = "coverage-7.5.3-cp312-cp312-win32.whl", hash = "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08"}, - {file = "coverage-7.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb"}, - {file = "coverage-7.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb"}, - {file = "coverage-7.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155"}, - {file = "coverage-7.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24"}, - {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98"}, - {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d"}, - {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d"}, - {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce"}, - {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0"}, - {file = "coverage-7.5.3-cp38-cp38-win32.whl", hash = "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485"}, - {file = "coverage-7.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56"}, - {file = "coverage-7.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85"}, - {file = "coverage-7.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31"}, - {file = "coverage-7.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d"}, - {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341"}, - {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7"}, - {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52"}, - {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303"}, - {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd"}, - {file = "coverage-7.5.3-cp39-cp39-win32.whl", hash = "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d"}, - {file = "coverage-7.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0"}, - {file = "coverage-7.5.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884"}, - {file = "coverage-7.5.3.tar.gz", hash = "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f"}, + {file = "coverage-7.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6cfb5a4f556bb51aba274588200a46e4dd6b505fb1a5f8c5ae408222eb416f99"}, + {file = "coverage-7.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2174e7c23e0a454ffe12267a10732c273243b4f2d50d07544a91198f05c48f47"}, + {file = "coverage-7.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2214ee920787d85db1b6a0bd9da5f8503ccc8fcd5814d90796c2f2493a2f4d2e"}, + {file = "coverage-7.5.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1137f46adb28e3813dec8c01fefadcb8c614f33576f672962e323b5128d9a68d"}, + {file = "coverage-7.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b385d49609f8e9efc885790a5a0e89f2e3ae042cdf12958b6034cc442de428d3"}, + {file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b4a474f799456e0eb46d78ab07303286a84a3140e9700b9e154cfebc8f527016"}, + {file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5cd64adedf3be66f8ccee418473c2916492d53cbafbfcff851cbec5a8454b136"}, + {file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e564c2cf45d2f44a9da56f4e3a26b2236504a496eb4cb0ca7221cd4cc7a9aca9"}, + {file = "coverage-7.5.4-cp310-cp310-win32.whl", hash = "sha256:7076b4b3a5f6d2b5d7f1185fde25b1e54eb66e647a1dfef0e2c2bfaf9b4c88c8"}, + {file = "coverage-7.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:018a12985185038a5b2bcafab04ab833a9a0f2c59995b3cec07e10074c78635f"}, + {file = "coverage-7.5.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:db14f552ac38f10758ad14dd7b983dbab424e731588d300c7db25b6f89e335b5"}, + {file = "coverage-7.5.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3257fdd8e574805f27bb5342b77bc65578e98cbc004a92232106344053f319ba"}, + {file = "coverage-7.5.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a6612c99081d8d6134005b1354191e103ec9705d7ba2754e848211ac8cacc6b"}, + {file = "coverage-7.5.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d45d3cbd94159c468b9b8c5a556e3f6b81a8d1af2a92b77320e887c3e7a5d080"}, + {file = "coverage-7.5.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed550e7442f278af76d9d65af48069f1fb84c9f745ae249c1a183c1e9d1b025c"}, + {file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7a892be37ca35eb5019ec85402c3371b0f7cda5ab5056023a7f13da0961e60da"}, + {file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8192794d120167e2a64721d88dbd688584675e86e15d0569599257566dec9bf0"}, + {file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:820bc841faa502e727a48311948e0461132a9c8baa42f6b2b84a29ced24cc078"}, + {file = "coverage-7.5.4-cp311-cp311-win32.whl", hash = "sha256:6aae5cce399a0f065da65c7bb1e8abd5c7a3043da9dceb429ebe1b289bc07806"}, + {file = "coverage-7.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:d2e344d6adc8ef81c5a233d3a57b3c7d5181f40e79e05e1c143da143ccb6377d"}, + {file = "coverage-7.5.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:54317c2b806354cbb2dc7ac27e2b93f97096912cc16b18289c5d4e44fc663233"}, + {file = "coverage-7.5.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:042183de01f8b6d531e10c197f7f0315a61e8d805ab29c5f7b51a01d62782747"}, + {file = "coverage-7.5.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6bb74ed465d5fb204b2ec41d79bcd28afccf817de721e8a807d5141c3426638"}, + {file = "coverage-7.5.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3d45ff86efb129c599a3b287ae2e44c1e281ae0f9a9bad0edc202179bcc3a2e"}, + {file = "coverage-7.5.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5013ed890dc917cef2c9f765c4c6a8ae9df983cd60dbb635df8ed9f4ebc9f555"}, + {file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1014fbf665fef86cdfd6cb5b7371496ce35e4d2a00cda501cf9f5b9e6fced69f"}, + {file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3684bc2ff328f935981847082ba4fdc950d58906a40eafa93510d1b54c08a66c"}, + {file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:581ea96f92bf71a5ec0974001f900db495488434a6928a2ca7f01eee20c23805"}, + {file = "coverage-7.5.4-cp312-cp312-win32.whl", hash = "sha256:73ca8fbc5bc622e54627314c1a6f1dfdd8db69788f3443e752c215f29fa87a0b"}, + {file = "coverage-7.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:cef4649ec906ea7ea5e9e796e68b987f83fa9a718514fe147f538cfeda76d7a7"}, + {file = "coverage-7.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdd31315fc20868c194130de9ee6bfd99755cc9565edff98ecc12585b90be882"}, + {file = "coverage-7.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:02ff6e898197cc1e9fa375581382b72498eb2e6d5fc0b53f03e496cfee3fac6d"}, + {file = "coverage-7.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d05c16cf4b4c2fc880cb12ba4c9b526e9e5d5bb1d81313d4d732a5b9fe2b9d53"}, + {file = "coverage-7.5.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5986ee7ea0795a4095ac4d113cbb3448601efca7f158ec7f7087a6c705304e4"}, + {file = "coverage-7.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5df54843b88901fdc2f598ac06737f03d71168fd1175728054c8f5a2739ac3e4"}, + {file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ab73b35e8d109bffbda9a3e91c64e29fe26e03e49addf5b43d85fc426dde11f9"}, + {file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:aea072a941b033813f5e4814541fc265a5c12ed9720daef11ca516aeacd3bd7f"}, + {file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:16852febd96acd953b0d55fc842ce2dac1710f26729b31c80b940b9afcd9896f"}, + {file = "coverage-7.5.4-cp38-cp38-win32.whl", hash = "sha256:8f894208794b164e6bd4bba61fc98bf6b06be4d390cf2daacfa6eca0a6d2bb4f"}, + {file = "coverage-7.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:e2afe743289273209c992075a5a4913e8d007d569a406ffed0bd080ea02b0633"}, + {file = "coverage-7.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b95c3a8cb0463ba9f77383d0fa8c9194cf91f64445a63fc26fb2327e1e1eb088"}, + {file = "coverage-7.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d7564cc09dd91b5a6001754a5b3c6ecc4aba6323baf33a12bd751036c998be4"}, + {file = "coverage-7.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44da56a2589b684813f86d07597fdf8a9c6ce77f58976727329272f5a01f99f7"}, + {file = "coverage-7.5.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e16f3d6b491c48c5ae726308e6ab1e18ee830b4cdd6913f2d7f77354b33f91c8"}, + {file = "coverage-7.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbc5958cb471e5a5af41b0ddaea96a37e74ed289535e8deca404811f6cb0bc3d"}, + {file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a04e990a2a41740b02d6182b498ee9796cf60eefe40cf859b016650147908029"}, + {file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ddbd2f9713a79e8e7242d7c51f1929611e991d855f414ca9996c20e44a895f7c"}, + {file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b1ccf5e728ccf83acd313c89f07c22d70d6c375a9c6f339233dcf792094bcbf7"}, + {file = "coverage-7.5.4-cp39-cp39-win32.whl", hash = "sha256:56b4eafa21c6c175b3ede004ca12c653a88b6f922494b023aeb1e836df953ace"}, + {file = "coverage-7.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:65e528e2e921ba8fd67d9055e6b9f9e34b21ebd6768ae1c1723f4ea6ace1234d"}, + {file = "coverage-7.5.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:79b356f3dd5b26f3ad23b35c75dbdaf1f9e2450b6bcefc6d0825ea0aa3f86ca5"}, + {file = "coverage-7.5.4.tar.gz", hash = "sha256:a44963520b069e12789d0faea4e9fdb1e410cdc4aab89d94f7f55cbb7fef0353"}, ] [package.dependencies] @@ -1152,43 +1220,43 @@ files = [ [[package]] name = "cryptography" -version = "42.0.5" +version = "42.0.8" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.5-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16"}, - {file = "cryptography-42.0.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da"}, - {file = "cryptography-42.0.5-cp37-abi3-win32.whl", hash = "sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74"}, - {file = "cryptography-42.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940"}, - {file = "cryptography-42.0.5-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30"}, - {file = "cryptography-42.0.5-cp39-abi3-win32.whl", hash = "sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413"}, - {file = "cryptography-42.0.5-cp39-abi3-win_amd64.whl", hash = "sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd"}, - {file = "cryptography-42.0.5.tar.gz", hash = "sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"}, + {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"}, + {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"}, + {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"}, + {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"}, + {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"}, + {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"}, ] [package.dependencies] @@ -1206,33 +1274,33 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "debugpy" -version = "1.8.1" +version = "1.8.2" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" files = [ - {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, - {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, - {file = "debugpy-1.8.1-cp310-cp310-win32.whl", hash = "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0"}, - {file = "debugpy-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd"}, - {file = "debugpy-1.8.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb"}, - {file = "debugpy-1.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099"}, - {file = "debugpy-1.8.1-cp311-cp311-win32.whl", hash = "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146"}, - {file = "debugpy-1.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8"}, - {file = "debugpy-1.8.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539"}, - {file = "debugpy-1.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace"}, - {file = "debugpy-1.8.1-cp312-cp312-win32.whl", hash = "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0"}, - {file = "debugpy-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98"}, - {file = "debugpy-1.8.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39"}, - {file = "debugpy-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7"}, - {file = "debugpy-1.8.1-cp38-cp38-win32.whl", hash = "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9"}, - {file = "debugpy-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234"}, - {file = "debugpy-1.8.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42"}, - {file = "debugpy-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703"}, - {file = "debugpy-1.8.1-cp39-cp39-win32.whl", hash = "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23"}, - {file = "debugpy-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3"}, - {file = "debugpy-1.8.1-py2.py3-none-any.whl", hash = "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242"}, - {file = "debugpy-1.8.1.zip", hash = "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42"}, + {file = "debugpy-1.8.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:7ee2e1afbf44b138c005e4380097d92532e1001580853a7cb40ed84e0ef1c3d2"}, + {file = "debugpy-1.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f8c3f7c53130a070f0fc845a0f2cee8ed88d220d6b04595897b66605df1edd6"}, + {file = "debugpy-1.8.2-cp310-cp310-win32.whl", hash = "sha256:f179af1e1bd4c88b0b9f0fa153569b24f6b6f3de33f94703336363ae62f4bf47"}, + {file = "debugpy-1.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:0600faef1d0b8d0e85c816b8bb0cb90ed94fc611f308d5fde28cb8b3d2ff0fe3"}, + {file = "debugpy-1.8.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:8a13417ccd5978a642e91fb79b871baded925d4fadd4dfafec1928196292aa0a"}, + {file = "debugpy-1.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acdf39855f65c48ac9667b2801234fc64d46778021efac2de7e50907ab90c634"}, + {file = "debugpy-1.8.2-cp311-cp311-win32.whl", hash = "sha256:2cbd4d9a2fc5e7f583ff9bf11f3b7d78dfda8401e8bb6856ad1ed190be4281ad"}, + {file = "debugpy-1.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:d3408fddd76414034c02880e891ea434e9a9cf3a69842098ef92f6e809d09afa"}, + {file = "debugpy-1.8.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:5d3ccd39e4021f2eb86b8d748a96c766058b39443c1f18b2dc52c10ac2757835"}, + {file = "debugpy-1.8.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62658aefe289598680193ff655ff3940e2a601765259b123dc7f89c0239b8cd3"}, + {file = "debugpy-1.8.2-cp312-cp312-win32.whl", hash = "sha256:bd11fe35d6fd3431f1546d94121322c0ac572e1bfb1f6be0e9b8655fb4ea941e"}, + {file = "debugpy-1.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:15bc2f4b0f5e99bf86c162c91a74c0631dbd9cef3c6a1d1329c946586255e859"}, + {file = "debugpy-1.8.2-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:5a019d4574afedc6ead1daa22736c530712465c0c4cd44f820d803d937531b2d"}, + {file = "debugpy-1.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40f062d6877d2e45b112c0bbade9a17aac507445fd638922b1a5434df34aed02"}, + {file = "debugpy-1.8.2-cp38-cp38-win32.whl", hash = "sha256:c78ba1680f1015c0ca7115671fe347b28b446081dada3fedf54138f44e4ba031"}, + {file = "debugpy-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:cf327316ae0c0e7dd81eb92d24ba8b5e88bb4d1b585b5c0d32929274a66a5210"}, + {file = "debugpy-1.8.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:1523bc551e28e15147815d1397afc150ac99dbd3a8e64641d53425dba57b0ff9"}, + {file = "debugpy-1.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e24ccb0cd6f8bfaec68d577cb49e9c680621c336f347479b3fce060ba7c09ec1"}, + {file = "debugpy-1.8.2-cp39-cp39-win32.whl", hash = "sha256:7f8d57a98c5a486c5c7824bc0b9f2f11189d08d73635c326abef268f83950326"}, + {file = "debugpy-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:16c8dcab02617b75697a0a925a62943e26a0330da076e2a10437edd9f0bf3755"}, + {file = "debugpy-1.8.2-py2.py3-none-any.whl", hash = "sha256:16e16df3a98a35c63c3ab1e4d19be4cbc7fdda92d9ddc059294f18910928e0ca"}, + {file = "debugpy-1.8.2.zip", hash = "sha256:95378ed08ed2089221896b9b3a8d021e642c24edc8fef20e5d4342ca8be65c00"}, ] [[package]] @@ -1405,13 +1473,13 @@ pgp = ["gpg"] [[package]] name = "email-validator" -version = "2.1.2" +version = "2.2.0" description = "A robust email address syntax and deliverability validation library." optional = false python-versions = ">=3.8" files = [ - {file = "email_validator-2.1.2-py3-none-any.whl", hash = "sha256:d89f6324e13b1e39889eab7f9ca2f91dc9aebb6fa50a6d8bd4329ab50f251115"}, - {file = "email_validator-2.1.2.tar.gz", hash = "sha256:14c0f3d343c4beda37400421b39fa411bbe33a75df20825df73ad53e06a9f04c"}, + {file = "email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631"}, + {file = "email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7"}, ] [package.dependencies] @@ -1420,13 +1488,13 @@ idna = ">=2.0.0" [[package]] name = "exceptiongroup" -version = "1.2.0" +version = "1.2.1" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, - {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, + {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, + {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, ] [package.extras] @@ -1434,13 +1502,13 @@ test = ["pytest (>=6)"] [[package]] name = "execnet" -version = "2.0.2" +version = "2.1.1" description = "execnet: rapid multi-Python deployment" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "execnet-2.0.2-py3-none-any.whl", hash = "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41"}, - {file = "execnet-2.0.2.tar.gz", hash = "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af"}, + {file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"}, + {file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"}, ] [package.extras] @@ -1506,13 +1574,13 @@ standard = ["fastapi", "uvicorn[standard] (>=0.15.0)"] [[package]] name = "fastjsonschema" -version = "2.19.1" +version = "2.20.0" description = "Fastest Python implementation of JSON schema" optional = false python-versions = "*" files = [ - {file = "fastjsonschema-2.19.1-py3-none-any.whl", hash = "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0"}, - {file = "fastjsonschema-2.19.1.tar.gz", hash = "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d"}, + {file = "fastjsonschema-2.20.0-py3-none-any.whl", hash = "sha256:5875f0b0fa7a0043a91e93a9b8f793bcbbba9691e7fd83dca95c28ba26d21f0a"}, + {file = "fastjsonschema-2.20.0.tar.gz", hash = "sha256:3d48fc5300ee96f5d116f10fe6f28d938e6008f59a6a025c2649475b87f76a23"}, ] [package.extras] @@ -1520,18 +1588,18 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc [[package]] name = "filelock" -version = "3.13.1" +version = "3.15.4" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, - {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, + {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, + {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"] typing = ["typing-extensions (>=4.8)"] [[package]] @@ -1552,13 +1620,13 @@ pyflakes = ">=3.2.0,<3.3.0" [[package]] name = "flask" -version = "3.0.2" +version = "3.0.3" description = "A simple framework for building complex web applications." optional = false python-versions = ">=3.8" files = [ - {file = "flask-3.0.2-py3-none-any.whl", hash = "sha256:3232e0e9c850d781933cf0207523d1ece087eb8d87b23777ae38456e2fbe7c6e"}, - {file = "flask-3.0.2.tar.gz", hash = "sha256:822c03f4b799204250a7ee84b1eddc40665395333973dfb9deebfe425fefcb7d"}, + {file = "flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3"}, + {file = "flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"}, ] [package.dependencies] @@ -1576,13 +1644,13 @@ dotenv = ["python-dotenv"] [[package]] name = "flask-cors" -version = "4.0.0" +version = "4.0.1" description = "A Flask extension adding a decorator for CORS support" optional = false python-versions = "*" files = [ - {file = "Flask-Cors-4.0.0.tar.gz", hash = "sha256:f268522fcb2f73e2ecdde1ef45e2fd5c71cc48fe03cffb4b441c6d1b40684eb0"}, - {file = "Flask_Cors-4.0.0-py2.py3-none-any.whl", hash = "sha256:bc3492bfd6368d27cfe79c7821df5a8a319e1a6d5eab277a3794be19bdc51783"}, + {file = "Flask_Cors-4.0.1-py2.py3-none-any.whl", hash = "sha256:f2a704e4458665580c074b714c4627dd5a306b333deb9074d0b1794dfa2fb677"}, + {file = "flask_cors-4.0.1.tar.gz", hash = "sha256:eeb69b342142fdbf4766ad99357a7f3876a2ceb77689dc10ff912aac06c389e4"}, ] [package.dependencies] @@ -1753,8 +1821,8 @@ files = [ [package.dependencies] cffi = {version = ">=1.12.2", markers = "platform_python_implementation == \"CPython\" and sys_platform == \"win32\""} greenlet = [ - {version = ">=2.0.0", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""}, {version = ">=3.0rc3", markers = "platform_python_implementation == \"CPython\" and python_version >= \"3.11\""}, + {version = ">=2.0.0", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""}, ] "zope.event" = "*" "zope.interface" = "*" @@ -1768,119 +1836,119 @@ test = ["cffi (>=1.12.2)", "coverage (>=5.0)", "dnspython (>=1.16.0,<2.0)", "idn [[package]] name = "geventhttpclient" -version = "2.0.11" +version = "2.0.12" description = "http client library for gevent" optional = false python-versions = "*" files = [ - {file = "geventhttpclient-2.0.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f509176bc7754b1181375a25ec6909425a5997e58c98ea29a36fe8b6a376852f"}, - {file = "geventhttpclient-2.0.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cda51b46d8ab3993763a394ed6601137c32f70cff78dfe703edecb3dfa143009"}, - {file = "geventhttpclient-2.0.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:072f24198c0f179fcd8567e9270d5cb78ceea1d562a55b052cd083cf4c67feef"}, - {file = "geventhttpclient-2.0.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b97c84e9be76bdd726757437327be5446710eafb64f7097d8d86db9c0f7d280"}, - {file = "geventhttpclient-2.0.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:abb32554c1ad103ed1114cee3d75fa6a3c5d8a0898e4e64db68f3fc0f11fb0de"}, - {file = "geventhttpclient-2.0.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78a7e493e09d0aa4ba9651147d02fc555159371fecab0e4e96196c72f191322e"}, - {file = "geventhttpclient-2.0.11-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e521089a3a95c98e1742f1a1ea41568b029bc2528cc6fc7ab91bb5d416f1f2c"}, - {file = "geventhttpclient-2.0.11-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8329c60d94e688d75ec1c6f67a77ab96f726f8ea562a8d48afa1ed6470334a6f"}, - {file = "geventhttpclient-2.0.11-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:572364fc4acd7ff2e77641e6bd1e64cf315d899a7fc48953eac1dd3b6865fd99"}, - {file = "geventhttpclient-2.0.11-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:81e73ee32f4217072935825a0bad7264dc803b0d24cc4e2f4bfcac3fff49a899"}, - {file = "geventhttpclient-2.0.11-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d79ee0d7ab5d775b056400155cab1e3547a7fa6511f6098e25613ed8705ae8b8"}, - {file = "geventhttpclient-2.0.11-cp310-cp310-win32.whl", hash = "sha256:2911d3657e2426b6a2d59af0b52285c1a7c4a78d0e4d03ee4ec1d5195a25a09f"}, - {file = "geventhttpclient-2.0.11-cp310-cp310-win_amd64.whl", hash = "sha256:a489573a0a0559f8960b38795dc53d1e222bc0978b211763d1303b2f94e4c3e0"}, - {file = "geventhttpclient-2.0.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1e27a9521e0ad0d97d0ff81578fd4dd6ae9eee8095d46edb820dfda33c0bd233"}, - {file = "geventhttpclient-2.0.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d54b886ce042186a4f731dcbcb4ffa8d674b0542907fc72de20d0b5088adc252"}, - {file = "geventhttpclient-2.0.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2337e10e2ad20970436f216d7b3b8d1503f8e4645d439173a98b4b418fe5768"}, - {file = "geventhttpclient-2.0.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f41bcdcec859264a1b6cc7c57bdb9411da8047f17b982cb62756bcc74a1b045b"}, - {file = "geventhttpclient-2.0.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f5d73be013a7a2a357eb27d18e5990c773365f63f50a43eaf357d6efb1fd46a6"}, - {file = "geventhttpclient-2.0.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4d86f042501a783e94188ef8b099f32bc4680f2423bbbb56f40158d4556a56b"}, - {file = "geventhttpclient-2.0.11-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaa2bc31a38dbb387c7539cfa03d3bafaa32151972d34b42f2f648b66778e128"}, - {file = "geventhttpclient-2.0.11-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3e24ff4c398f9e49c5c0740585f12fcf7033dc27a20ec884f3b2c729e2f47f14"}, - {file = "geventhttpclient-2.0.11-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b70f80528ae74518a16214261abba2a276739e6e35ce518fdbd8be2a3f42f93a"}, - {file = "geventhttpclient-2.0.11-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:efa467997f87d39f774ed1916a9e184c9a936f8fa90ab1a8ebf97aba2ee7ed63"}, - {file = "geventhttpclient-2.0.11-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4597ea18ddc9838dc0e6cb9d5efb812191f2ca65ab38c115a56894045c73ea40"}, - {file = "geventhttpclient-2.0.11-cp311-cp311-win32.whl", hash = "sha256:a4361c5a522d2a79d8a9047926b8f8926e0f797777da9f450d359bed9f33ac33"}, - {file = "geventhttpclient-2.0.11-cp311-cp311-win_amd64.whl", hash = "sha256:f430257a7b0a75e7f4c0d6f4f3f8960d45b5aae56b8eca7988963487501a52a0"}, - {file = "geventhttpclient-2.0.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a84f48f2eff42171cc446690baffa914122e88cea5b1de44cf6dd1c82b07623b"}, - {file = "geventhttpclient-2.0.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0a21dba9cf5e7511e76845f62dcf5072f4df7415bb8f20e47e0dfde675943a39"}, - {file = "geventhttpclient-2.0.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:99feb5581111c7ec44e1ce507b4420947b4c49b363b2fbc3edd543e2ac67a1e0"}, - {file = "geventhttpclient-2.0.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bc799d50db685e093b5819459889f356dd7478a82af66f880832a95fcfa37c3"}, - {file = "geventhttpclient-2.0.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94a8be54ac74ff6cf4703d049766e6ed07787fa9b6a2dd538c46f81de72ffdde"}, - {file = "geventhttpclient-2.0.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:71a9e152bb3cb86552f61659f3c7bdc272d9baf21726b3caceb5ab5d0e703fe6"}, - {file = "geventhttpclient-2.0.11-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05a7699b49c9bc478b7ae165809ff97b21811a624791abe3927da5066128a10c"}, - {file = "geventhttpclient-2.0.11-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:598951751b2162b0697cd5b6a9edcc65ec30f34388b6e09caaa0c453fb08fb6e"}, - {file = "geventhttpclient-2.0.11-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4f0c773ceeeedfab56b24b97a0c8f04c58a716dfc7403e51ea898ad01599f1a6"}, - {file = "geventhttpclient-2.0.11-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:ee03ea884e6aa318078c0c7132d246fe92b51d587410532e63b864e6e61ea192"}, - {file = "geventhttpclient-2.0.11-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:98a25e30ddccd49f80e037d48f136050b8f3c24ed9c6a69df7a643989f29c4e8"}, - {file = "geventhttpclient-2.0.11-cp312-cp312-win32.whl", hash = "sha256:968587b59372e825411935e188b9a05dcdec6db6769be3eb3bba949cb414ae98"}, - {file = "geventhttpclient-2.0.11-cp312-cp312-win_amd64.whl", hash = "sha256:465e62fb055e2ca5907606d32d421970f93506309b11a33b367eef33d95a6b7a"}, - {file = "geventhttpclient-2.0.11-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ba597da51b59df28cf484326d7d59e33a57d3b32d7a4e1646c580f175354d6ce"}, - {file = "geventhttpclient-2.0.11-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c125a225188bcacd51f05878d6e62554116a5be6b3a203cd0ba2460857bc8cd3"}, - {file = "geventhttpclient-2.0.11-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f016093e8d26b724efdeda776968368fb591a57afbded2d86c408db8723e38ce"}, - {file = "geventhttpclient-2.0.11-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a25a7fc768791cf9fe590f1b4f231727441e8f7e9279e8ae2bee83e0f3b010f8"}, - {file = "geventhttpclient-2.0.11-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae71a7740526be78c6e899b03b63ab47a1a434332f7ca725dcdc916d938d46c6"}, - {file = "geventhttpclient-2.0.11-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:06914f401541681d8cb834652f53e65a8179ea17dd0e496fd52712fd3f548fbb"}, - {file = "geventhttpclient-2.0.11-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6ccdebfd20ab07ace7aa4dcd020f094d1cae237b4eacfca08ac523cac64e02d3"}, - {file = "geventhttpclient-2.0.11-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:b2bea1386dbfd262571157da319e2285e20844fdbaabb22f95e784ca8b47d90c"}, - {file = "geventhttpclient-2.0.11-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:f468f88df7649bfcc6f74878182d0b7bcb3c23445a76be2b8b59e46224e2c244"}, - {file = "geventhttpclient-2.0.11-cp36-cp36m-win32.whl", hash = "sha256:d75c706f2a2401f703585cddf51cb0e43c28b7f12b1998c4a41fd6d14feec89b"}, - {file = "geventhttpclient-2.0.11-cp36-cp36m-win_amd64.whl", hash = "sha256:27f9e22a31451087854204f7f341bd4adc32050180580f74b5de75b61a3b405f"}, - {file = "geventhttpclient-2.0.11-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:105af48455d4eecb4e0f2b2b7f766131811aa1a9a1e768fb020b9ae0ba840ee4"}, - {file = "geventhttpclient-2.0.11-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb9e9c6f3fb902dd622964097df77e0ed9b249b8904b44fc3461734cc791b0aa"}, - {file = "geventhttpclient-2.0.11-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1b73c37fbecb26475fa6e2d018dab4b5a03c7ba08c8907598605c874a70ee79"}, - {file = "geventhttpclient-2.0.11-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09167de901f5b5273ddc14fd53512cc696495be07f02e3cb8a0335e1ecbff57e"}, - {file = "geventhttpclient-2.0.11-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52ac561df8d363fe2e00ba4cccea470745129a48bb86f665a1447d0d68abec54"}, - {file = "geventhttpclient-2.0.11-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ceb038cbf92105d124433066685c73e6a4a762c15885f00be2e25663468e4f29"}, - {file = "geventhttpclient-2.0.11-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:0b70eedf64c162067765ddfb30c8f52daeb875c717a3d25f81d5e411e5ac4367"}, - {file = "geventhttpclient-2.0.11-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:e87fb8bd748bf32e9902e9cbea3f20ff5456705d3f53f0a8ea0c4983594457a8"}, - {file = "geventhttpclient-2.0.11-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0ae01d50529ac739573bc9cbc192b71bf9a13c3fcdbf2054952947a25e9f75a3"}, - {file = "geventhttpclient-2.0.11-cp37-cp37m-win32.whl", hash = "sha256:beb3a99e7a0a5130fbed2453348d81a78f2ef7d6aa326b5799c7f3dde88cabea"}, - {file = "geventhttpclient-2.0.11-cp37-cp37m-win_amd64.whl", hash = "sha256:63fc49d73e70cab8316a4d0106c037a2a5d0f6650683af05d0d05d354b694d49"}, - {file = "geventhttpclient-2.0.11-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:106e2ba0ce34a3501651995dd46ed38b87e7b5ada0fb977142d952661853f36a"}, - {file = "geventhttpclient-2.0.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0edacd51cd9a6f0b88e25cb6c8744488ba6c7c22044b09de585b2a1224f2a7b9"}, - {file = "geventhttpclient-2.0.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2214352e01fef4218bbbc61bd84af6f101bb5a33244088f6db28ff6d1141797f"}, - {file = "geventhttpclient-2.0.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38384af2da776563a19951958df65e31ecc7b8d20788d43aff35ec909e4a115f"}, - {file = "geventhttpclient-2.0.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33c4af3aa0312c27668171ea061d461f678848a09a32953b4d895f72a1bde0c9"}, - {file = "geventhttpclient-2.0.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d461cdac133d4a4d173e2c1cc213f3a9924e6e092aeebd49bf8924719a073e0b"}, - {file = "geventhttpclient-2.0.11-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ad49019e2828508526d35e7026b95a1fd9ef49ed0cdd2526a5cb3eb39583640"}, - {file = "geventhttpclient-2.0.11-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a59b164a68bbb1a6f7bee859d7e75ef148b1e9bd72c4810c712cd49603dc37cd"}, - {file = "geventhttpclient-2.0.11-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6cc44c57c02db1ded6f5a6bd4ccc385c4d13c7ae3528b831e70b5cc87e5b0ad1"}, - {file = "geventhttpclient-2.0.11-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:2d7318b3493c2e21df79429be3dbfefbc254c41a5b5c02c148a4521d59169ad6"}, - {file = "geventhttpclient-2.0.11-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:40df90cd9b5f5f7355526cc538e626466cb60c2e737e9cb8958569377d568e9f"}, - {file = "geventhttpclient-2.0.11-cp38-cp38-win32.whl", hash = "sha256:6f89edc316a8ff967a50c6f98277619786ed6abf2dd36ea905baf840a02b1b1b"}, - {file = "geventhttpclient-2.0.11-cp38-cp38-win_amd64.whl", hash = "sha256:b179a13c113a90c5501f1b1121bdc4c1f816d942280a9c3d2d46aff2bc97269a"}, - {file = "geventhttpclient-2.0.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:63826170b520894578bd269b54139bb2f0cc2d96ae1f4a49b3928fe01ffa22ff"}, - {file = "geventhttpclient-2.0.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a6fcc3968ea1adf764bc11b0e7d01b94ffe27bdd21c5b1d9e55be56de6a53c3"}, - {file = "geventhttpclient-2.0.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c61c02c2d32e1b5b1f73d2b201c1e088e956b73e431ed6b5589010faed88380"}, - {file = "geventhttpclient-2.0.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aec646409fa6eee277e33a1f4f1860d4c25e0448eedea149df92918d4502f38c"}, - {file = "geventhttpclient-2.0.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b91290138518b201fba98bc82b062ef32e5e3da28843998902852298c354dcf"}, - {file = "geventhttpclient-2.0.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b523860ee558f752847b29ad6678d1b8a40154d06bc7a8973132991aff727fdd"}, - {file = "geventhttpclient-2.0.11-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5594bc889a686511039d1efd17473eecc4a91fa01d66a59bfa0a8cf04fb34551"}, - {file = "geventhttpclient-2.0.11-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e573b86999cfeae38c4dd881f05818b9a60245a6763bc77efb48fa136cefdfcc"}, - {file = "geventhttpclient-2.0.11-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a30bd715480ddbab0217764b516a65e36ecee2e81c9a04d074769eec6e0c1681"}, - {file = "geventhttpclient-2.0.11-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:49ff1c00e64e0820a02fadc6a72b49ae8cc69028caa40170873a3012de98d475"}, - {file = "geventhttpclient-2.0.11-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ea232981e29869524e85b5e6c79ad64abf40dd7b6dc01be6765b5e6bd191fd73"}, - {file = "geventhttpclient-2.0.11-cp39-cp39-win32.whl", hash = "sha256:a0b30fef1eb118927b5d8cab106198883f1bde021e9036277ea2f9e0020e0ad2"}, - {file = "geventhttpclient-2.0.11-cp39-cp39-win_amd64.whl", hash = "sha256:844b30e3694a4d9518fe6f0b167fa3ffc3ea3444563d9fdd7a18a961f6a77d9c"}, - {file = "geventhttpclient-2.0.11-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:94579ec289d46fca939b78cfe91732e82491f3dab03604f974a2e711654e7210"}, - {file = "geventhttpclient-2.0.11-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955b04deac7ea09a3d5183ba92a3d2a81121ad71d10f1489cb56fd31d0cb4ac4"}, - {file = "geventhttpclient-2.0.11-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7947aae2d7123a970669ebd763a09ef0c85104cda414689dd77b5e5a5c1f2a40"}, - {file = "geventhttpclient-2.0.11-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c483daa1deda0c52a77ed7af2906a38657c15120cb3240bf589dfb139255921"}, - {file = "geventhttpclient-2.0.11-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bc9634e025f17dc25987ebd5b0461659178ca57052ec70ad65052d0495111a74"}, - {file = "geventhttpclient-2.0.11-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9dca243f58f245872458647b0b6da4be9ce8d707639d76a50d2e8d3f4abb1659"}, - {file = "geventhttpclient-2.0.11-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64d36604974bc2b2ed0166bc666cead87f3c0f2d9487ef73d4e11df9ba6ebcc8"}, - {file = "geventhttpclient-2.0.11-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:46677a56fa9f2f650be74024601b3a1968cfc58a434f5819fc2fc227bb292836"}, - {file = "geventhttpclient-2.0.11-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:989a1ed8dbdaf683dd5701087b736b93e6bacb3c29f4090014e64033cc8620e2"}, - {file = "geventhttpclient-2.0.11-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:9b406ef64382a9c42b88331cdd6639a2b998e8034dbb1b702264d27c01f3ad5d"}, - {file = "geventhttpclient-2.0.11-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:713530c8f67a08ce0d5a4af80045112213c63eacefa1c08b76beebf780c755b0"}, - {file = "geventhttpclient-2.0.11-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd894ec63974fe4e916a1bf6efd35307b86ef53bd88e8fbe61020a289fee2f7c"}, - {file = "geventhttpclient-2.0.11-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e18e622171d09f068b26304b7d3c484d55952813e09eec5b3db1012dc53795de"}, - {file = "geventhttpclient-2.0.11-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce8421aa0a2307edf04a7086236e7e9f9188ab349154c409d723744032746eb"}, - {file = "geventhttpclient-2.0.11-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:237eba77682553253040588f136a2980dfcd71307202422a17b716e9d8be5614"}, - {file = "geventhttpclient-2.0.11-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:60641b8ff7077a57bb68f1189c8ae8ffc6f14ae238ba6a81748659c30894d580"}, - {file = "geventhttpclient-2.0.11-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5939bca6ab38a482352be8a7141570464d4d18281d8a3a2e2f7a82a0d8c38c4"}, - {file = "geventhttpclient-2.0.11-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:025026620e5a369844b576981ddab25d60e7e3bb0e0657c1fe9360a52769eb9d"}, - {file = "geventhttpclient-2.0.11-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b48b10e2a812b9297ad5c43e7a1a088220940060bbfb84fb721b17ab3012e0d"}, - {file = "geventhttpclient-2.0.11-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e572e63e51fde06c30beabf8021e7d3f93e198a9c241ef2f3ed16d7828966768"}, - {file = "geventhttpclient-2.0.11.tar.gz", hash = "sha256:549d0f3af08420b9ad2beeda211153c7605b5ba409b228db7f1b81c8bfbec6b4"}, + {file = "geventhttpclient-2.0.12-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6d0fafc15bbd93b1f271b4c14b327d15c6930c8d78d8ee0d8a55c9cd3e34c18f"}, + {file = "geventhttpclient-2.0.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3f429ece7b6612ef333e9bbeb205513cec33a178f545b3612530a9c5c36a0310"}, + {file = "geventhttpclient-2.0.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:20ffc5a2b9cb5557d529d9296ffdaa5057a23e6bb439a905160a787079ec78a2"}, + {file = "geventhttpclient-2.0.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80a96670c5ab668f52dcaf705640b442faeafb2bfd2e54d5f08ac29ac80aab12"}, + {file = "geventhttpclient-2.0.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4766aff690198119c998474d9c20c1b3ffaff337d0d62a6d8b19cc871c3a276d"}, + {file = "geventhttpclient-2.0.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6d15f459737178e2b9a1d37b32161955a7d72062a3fc473d88c9e9f146cff22"}, + {file = "geventhttpclient-2.0.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a75007314fc15947fd94f154e139a6f78a4d40ed70d52dbb1724e7ea2d732ca7"}, + {file = "geventhttpclient-2.0.12-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:16e440152ea4f943dfc476462c1c3f29d47d583e679b58bccac9bfaa33eedcfd"}, + {file = "geventhttpclient-2.0.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e1d9c9b533b6c0b5a7eac23f68b25c8d3db1d38b8e504756c53366d2622a24a5"}, + {file = "geventhttpclient-2.0.12-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:758dd4a3172f740255f755fd393f0888e879a7102a537bba98a35a417be30d3e"}, + {file = "geventhttpclient-2.0.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:933426c92e85d8f6717c4d61f2c6c99fbb7d84c91373400eaf381052a35ea414"}, + {file = "geventhttpclient-2.0.12-cp310-cp310-win32.whl", hash = "sha256:e70247c900c4e4413af155e49f342055af9eb20c141735cce36d8a9dc10dc314"}, + {file = "geventhttpclient-2.0.12-cp310-cp310-win_amd64.whl", hash = "sha256:8dac40240fe446b94dd8645e2691d077b98b1e109ed945d2c91923c300c6f66d"}, + {file = "geventhttpclient-2.0.12-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3e3b3b2857ed48dd8af15c8e09539c8e0bf3721f515c0a8f3cfcbe0090196cc4"}, + {file = "geventhttpclient-2.0.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:114cfa7f4db7dcb5603ade4744bc6f5d6d168c94b05aca052e2fc84c906d2009"}, + {file = "geventhttpclient-2.0.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:904aaab04a8c4ebf52217930242693509cfbbd90f2b2afc454e14da82710367f"}, + {file = "geventhttpclient-2.0.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56935ebec38a7c9ccc3dcadaebf2624601567504cd3a44794dc9262aca147040"}, + {file = "geventhttpclient-2.0.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bff88eededd1f915cd86de5e8a891e1988b6d42093cc07be5fe3133f8baf170c"}, + {file = "geventhttpclient-2.0.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:212014f4133938ba6453dbfa6d3a643c915dd4873d1de1d6172e4c6c178e4a6c"}, + {file = "geventhttpclient-2.0.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d471e79a55d37ad021a4832b0895bccb638f70664040a29230e156a0b92b23d"}, + {file = "geventhttpclient-2.0.12-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:599c4d37d928323b5f0353434f73de9e88f305f59a5472ffc7f5c131a2485512"}, + {file = "geventhttpclient-2.0.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fddf2b3c4d5d99b826561173be04adbc92cab52081ba142c2158e0ba3b08b762"}, + {file = "geventhttpclient-2.0.12-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5075c7f15e0a39b7ceae6afcb0b3a66c0ab9364a9eb589b7f51b567835fae5d7"}, + {file = "geventhttpclient-2.0.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:58a6f9d93ef2b1a09479564c951bc7b058350bd757628a32945f274cd314fb98"}, + {file = "geventhttpclient-2.0.12-cp311-cp311-win32.whl", hash = "sha256:a0bb5a35b199356b0c9b5ec3c3152ebfe4ecbd79e00d486d461920a9d96d1fd2"}, + {file = "geventhttpclient-2.0.12-cp311-cp311-win_amd64.whl", hash = "sha256:972a92f4a453a3ef4737e79e7e64f3089a06f385e13493fa19381486e893bd98"}, + {file = "geventhttpclient-2.0.12-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0bee74f32eed6278f3837e07983b5a6b186920c7eb3b35bc6e97360697632655"}, + {file = "geventhttpclient-2.0.12-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fb85d8ed42cc389e5cdac06221f16cb6bca9dbbf5219c44d0731f742a6bffc09"}, + {file = "geventhttpclient-2.0.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c302a16328406003cf4d7d71f59cafc2d42f13d5dc9ea4c8bd248390de985a86"}, + {file = "geventhttpclient-2.0.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3266ef4da21a47d0181d4e3cb5209494e3ce6e4d4cc71414ea74b3a1f7e0e921"}, + {file = "geventhttpclient-2.0.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acb7a257e8f4f0c0335a259f2e9eae527fa042db9ea2e4580a381e9c01fc49f4"}, + {file = "geventhttpclient-2.0.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4741d66098b2b289f584effa7de3ae7bf1efb06e2d83abdbbc468a0a4dec6b3a"}, + {file = "geventhttpclient-2.0.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ef2b523043ab9c6057ed19993f629e3fa47f8f92a319f5682de05e604ed8cc9"}, + {file = "geventhttpclient-2.0.12-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:235058a6e420b2aae196a4ba7e23f81ebc2dc3acf6baa9d85dc99963b3e0f0cf"}, + {file = "geventhttpclient-2.0.12-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:c918d731e0fe676b4c06f53081526f4d3f4836b7a72be7b46c90603a280260fa"}, + {file = "geventhttpclient-2.0.12-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:9e7696a61b384f8d2a075cca9633fdcc897c43eabbcf70fca492206241fa1a3b"}, + {file = "geventhttpclient-2.0.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:105a1aa161223079dbd669b4334cd765964b5917ca4f3da8c5b59c4ef36a0adf"}, + {file = "geventhttpclient-2.0.12-cp312-cp312-win32.whl", hash = "sha256:09e13c05633d1eeb2cba68835618f4ee25c5a7b466c47cfdb01174f61e51a23d"}, + {file = "geventhttpclient-2.0.12-cp312-cp312-win_amd64.whl", hash = "sha256:f853438a1850d45fb434e42ffbb06be81af558e5dd9243d530c2cdc5f804627f"}, + {file = "geventhttpclient-2.0.12-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:62ad2ac321967ff92768e93ea18cb59f8920fbae5b42340b93e7cf11ee4f35d3"}, + {file = "geventhttpclient-2.0.12-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de8b6618a354bded39224def8b6e8b939c468f0edeb2570fdacd9003fd14c57c"}, + {file = "geventhttpclient-2.0.12-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:902ba66284d40dd97a693e952e4bb2f59528806ee40ecd586471fd5bca7fb295"}, + {file = "geventhttpclient-2.0.12-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ef6c9acff6ce379c8a851554954eee6481c35531d82888a46ccada0ea17a791"}, + {file = "geventhttpclient-2.0.12-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e8abf4ccd59d58f7aa91f4c68760d82534bac5c5c9b7d2ccb4c0a5fc69585ff"}, + {file = "geventhttpclient-2.0.12-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:bdeed563faa09fd51ee4606b92f69ecd42b67277ed590f2921816941ed031177"}, + {file = "geventhttpclient-2.0.12-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5a7d9b7e2dbc962f143938cdef8a657af1ccf423b2443a194b86ba0e85735c23"}, + {file = "geventhttpclient-2.0.12-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:a9a7ea4665418abe093e48576769181ae3c75a97cafe107c0463a169af755b2c"}, + {file = "geventhttpclient-2.0.12-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:19488a212c858792fd4fa83be568d4cdbbd4c1267b03b10b6a8a654fd862d2f9"}, + {file = "geventhttpclient-2.0.12-cp36-cp36m-win32.whl", hash = "sha256:445b80548062ef6c1b30e5e1b4ec471937fda64b783da953462972f48c2038de"}, + {file = "geventhttpclient-2.0.12-cp36-cp36m-win_amd64.whl", hash = "sha256:bf283bdbb4b935bfef114e1af19535a602e717ae9a7e8408ab61775d06a463b4"}, + {file = "geventhttpclient-2.0.12-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:370086ced942449f9b60590d215eec7f81fe54d7e3ee3add6b2f014ccac4f38d"}, + {file = "geventhttpclient-2.0.12-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e405735db8261ca99d9b80fda3f46d457f04b98a7ce0e49bb35ca32c2a5bbb2d"}, + {file = "geventhttpclient-2.0.12-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f4680b0ed5e588437797026f25829eb9681954ac64470dc8014436910b2fb09"}, + {file = "geventhttpclient-2.0.12-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad053e7b4ac2f9fcdb02a5d9b99fd72acf28265ba8be7392a25235bb631d2511"}, + {file = "geventhttpclient-2.0.12-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64232158542f2adfde24f41c1e3ed731cca67e469e653ac7634815af168551b4"}, + {file = "geventhttpclient-2.0.12-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9be5c3f68e4f41aceccae38508029a70b1fb3f9fc840b7c55971f5fbe099d7e4"}, + {file = "geventhttpclient-2.0.12-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:06b4276075f4f3eeb30a3c1476f40d53030159450def58c1d8c3b724411d8ed9"}, + {file = "geventhttpclient-2.0.12-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b311beb0657394b5df09af05ec5d84058f3531f3176ab1a0f7f4eae7b56bc315"}, + {file = "geventhttpclient-2.0.12-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b6a9d00b58527328d9f7a0a20b715d4e780a990b0fb75b556085417c22d73dd0"}, + {file = "geventhttpclient-2.0.12-cp37-cp37m-win32.whl", hash = "sha256:987ef3bd0d7e3b01cafc8e135ab6e8f977b60eeda096ead2cb5504124896b1a2"}, + {file = "geventhttpclient-2.0.12-cp37-cp37m-win_amd64.whl", hash = "sha256:dca64867b2d79433eb8557db00e74e17a2f0d444a9a90fb6f49cadaeddf703a5"}, + {file = "geventhttpclient-2.0.12-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:707467d6e8ad19749e7130b7c7bcb3a446c8e4f66454e1d47f4dfffa974683da"}, + {file = "geventhttpclient-2.0.12-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c2e436a2c41c71db17fd46df4925eb5e4d3856eb1b5fda0ce6b1137a6c6c87fa"}, + {file = "geventhttpclient-2.0.12-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f88d2f3a20afa999548622b31dbc3db5aa355c3032f3ae96a4195c5f938fee92"}, + {file = "geventhttpclient-2.0.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31a6581b8de9fa4b44916dcfabdc608409cfcf02fac39a62d40f6bcf6af726ad"}, + {file = "geventhttpclient-2.0.12-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c91e0ee50f8a1ea3a268f06c5bd44efe86b7f57961d7c923602038fcc010c3c"}, + {file = "geventhttpclient-2.0.12-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e3031817b8f2411086765de4bb1080c755b009ee8dc4a6111ad74f6ff4a363f"}, + {file = "geventhttpclient-2.0.12-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ff9a95e2d2035c1f5ac726166a598ea4071412c304a74a8cd5d2d8dfbf40b5e"}, + {file = "geventhttpclient-2.0.12-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:04f41d8f14e241e8d0c828ff59634674e98f96f39f6d12f43009a7332c4e2c82"}, + {file = "geventhttpclient-2.0.12-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:bea7376205629e8964f624b08d6836892e8d17ed8b8a57d5d2edbd7983440652"}, + {file = "geventhttpclient-2.0.12-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:fd9baf30e2bdd3110394365998037a45b43f86804b8f3c77f194f64eddc7dc54"}, + {file = "geventhttpclient-2.0.12-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:23c27b04ad25258959c088c0d87832befc7be2b09c5c35fdd76e417f5b546da0"}, + {file = "geventhttpclient-2.0.12-cp38-cp38-win32.whl", hash = "sha256:792e154009f6f63e3fbbe4b3109780ada275c4ed29659430c06dc8e1b2ed03ef"}, + {file = "geventhttpclient-2.0.12-cp38-cp38-win_amd64.whl", hash = "sha256:7b41a0510297a8ebbeffbef082e0896ecf37d5302999a3b58d208193c3c3e362"}, + {file = "geventhttpclient-2.0.12-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5006e34586bba4ebd5a7a5482f9e7743e1b3b9ff50c994105fb45e43044c38c9"}, + {file = "geventhttpclient-2.0.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d812074192822f57603973d6bcced0f02c6cc371cf63e729793f193c874f30ce"}, + {file = "geventhttpclient-2.0.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2a64bd8bce446be4fe869b64af310cd218d2329aa4e9d85b6a060da93c62296b"}, + {file = "geventhttpclient-2.0.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7fc536f2972c75da85f9360d0a3e5433baf6d777442a013052f9a501311ddcd"}, + {file = "geventhttpclient-2.0.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a60dec2ac44f494af9e42889dd7f7d653545b4c4892da4acbe383c0ffc305a1"}, + {file = "geventhttpclient-2.0.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa2ef1b92662ee9866bda52123f6f266ff4479437e7b5037a6427cf09e071e25"}, + {file = "geventhttpclient-2.0.12-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b8215e9a018a3634bdef4891634ceb9b10f47292b0091a1d96c363d8d5d7fdd"}, + {file = "geventhttpclient-2.0.12-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:90d5c0974518d35514a8896529d113e778e9d42d10699ac6051cd3e8f1ff81f6"}, + {file = "geventhttpclient-2.0.12-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:83c28617b02b6ab53653324b2a9ff2d4a4b1f1582fbc4e70f47d2ef9fe6ab1f7"}, + {file = "geventhttpclient-2.0.12-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:d8c7dfa2bcd15988a350e90b32c6b5426924f2ffd0ce75f52ca2d5ef540b3fbc"}, + {file = "geventhttpclient-2.0.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ded99bdbe7953f0734720d9908ed6f808fd12e97de05508822695a87b69f10f2"}, + {file = "geventhttpclient-2.0.12-cp39-cp39-win32.whl", hash = "sha256:ebcd7311901e52929d2bd3af9442970fdd12b200285d9a55d52994e033e73050"}, + {file = "geventhttpclient-2.0.12-cp39-cp39-win_amd64.whl", hash = "sha256:204c3976b2a4fcefe8f157fe303da45b85fc31147bdfce7b53b1098f05f1cad2"}, + {file = "geventhttpclient-2.0.12-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c651d22fae3084502afc876e8c73d521496f512e16828939333f17cad64ea47f"}, + {file = "geventhttpclient-2.0.12-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45c111addb5b27431805a8ad544dec292a7153cc44b68df28e782821431970d8"}, + {file = "geventhttpclient-2.0.12-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14cb7f4854d77c63506e31677fb548d137b20cbe34a11b5442f065b1e46c2246"}, + {file = "geventhttpclient-2.0.12-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8ac257aa714999b523282c0da6faf4d333d44131cea3b15fe802e00d35dd5c2"}, + {file = "geventhttpclient-2.0.12-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d97a41f959cd331eb8a633ed8edf6cc002a2a41a21e94876db833729b803924f"}, + {file = "geventhttpclient-2.0.12-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6ecb9a600a2da862b079ef3ebdffc9acec089c914bebc0c54614049584bfbb94"}, + {file = "geventhttpclient-2.0.12-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:662bb04e99466c25a1bf8b47351f79b339b6627721bb357bf3bc0d263c394176"}, + {file = "geventhttpclient-2.0.12-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80a6b4c9e1ade3ae090b7b679d5b691d0c87460612983d4ab951043f859adffb"}, + {file = "geventhttpclient-2.0.12-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13a359605dab2b92df4ef1bab7f1bec26e82acdc4253828a508f55375af50b48"}, + {file = "geventhttpclient-2.0.12-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:fc17f57be8254329715702d00536a443c29b52f2ef750bc0650554fb3b7e33e7"}, + {file = "geventhttpclient-2.0.12-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b58096bcaaa259e8d107749539b1d3804fc6ec395e91dec8040d448d298861c8"}, + {file = "geventhttpclient-2.0.12-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eb66bff9ed4d4f0bced3498746d86c949bf99e2440ceb968e6e7c542b3982b0"}, + {file = "geventhttpclient-2.0.12-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0158f45fd611b585c54380d981181c303313f3e059395310112805f53998d061"}, + {file = "geventhttpclient-2.0.12-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13129723ba3568f0a373cbd612130e2d78b3f284cf6a62385e26a92d7627a570"}, + {file = "geventhttpclient-2.0.12-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:571be0c875503ef5088cb417e84b707c922e3e2bd5e302e609d25e008cf037eb"}, + {file = "geventhttpclient-2.0.12-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:46e1706e3a44bb3423fc8d10b44e71c8a52c6535e22d483519dde008723c4f25"}, + {file = "geventhttpclient-2.0.12-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9de259de7ccc19b47537e21b47a74442ad64d1a1a262b971713d6af8cc8f16f9"}, + {file = "geventhttpclient-2.0.12-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4d777dced8a8e04fd8e0811c3b764d9a476b6a4c865f10079cc4f27b95b37196"}, + {file = "geventhttpclient-2.0.12-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcd4f45055a2e2f66e67016599d3fac33bc67b3bd67b672c1503a5de7543c1b6"}, + {file = "geventhttpclient-2.0.12-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:61b078cfc4b34a0d50224adf80c7eeae8e23fe6d8cb35926ccd3f3a6b86f921f"}, + {file = "geventhttpclient-2.0.12.tar.gz", hash = "sha256:ebea08e79c1aa7d03b43936b347c0f87356e6fb1c6845735a11f23c949c655f7"}, ] [package.dependencies] @@ -1905,34 +1973,35 @@ smmap = ">=3.0.1,<6" [[package]] name = "gitpython" -version = "3.1.42" +version = "3.1.43" description = "GitPython is a Python library used to interact with Git repositories" optional = false python-versions = ">=3.7" files = [ - {file = "GitPython-3.1.42-py3-none-any.whl", hash = "sha256:1bf9cd7c9e7255f77778ea54359e54ac22a72a5b51288c457c881057b7bb9ecd"}, - {file = "GitPython-3.1.42.tar.gz", hash = "sha256:2d99869e0fef71a73cbd242528105af1d6c1b108c60dfabd994bf292f76c3ceb"}, + {file = "GitPython-3.1.43-py3-none-any.whl", hash = "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff"}, + {file = "GitPython-3.1.43.tar.gz", hash = "sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c"}, ] [package.dependencies] gitdb = ">=4.0.1,<5" [package.extras] -test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar"] +doc = ["sphinx (==4.3.2)", "sphinx-autodoc-typehints", "sphinx-rtd-theme", "sphinxcontrib-applehelp (>=1.0.2,<=1.0.4)", "sphinxcontrib-devhelp (==1.0.2)", "sphinxcontrib-htmlhelp (>=2.0.0,<=2.0.1)", "sphinxcontrib-qthelp (==1.0.3)", "sphinxcontrib-serializinghtml (==1.1.5)"] +test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions"] [[package]] name = "googleapis-common-protos" -version = "1.62.0" +version = "1.63.2" description = "Common protobufs used in Google APIs" optional = true python-versions = ">=3.7" files = [ - {file = "googleapis-common-protos-1.62.0.tar.gz", hash = "sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277"}, - {file = "googleapis_common_protos-1.62.0-py2.py3-none-any.whl", hash = "sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07"}, + {file = "googleapis-common-protos-1.63.2.tar.gz", hash = "sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87"}, + {file = "googleapis_common_protos-1.63.2-py2.py3-none-any.whl", hash = "sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945"}, ] [package.dependencies] -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" [package.extras] grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] @@ -2010,69 +2079,61 @@ test = ["objgraph", "psutil"] [[package]] name = "grpcio" -version = "1.62.0" +version = "1.64.1" description = "HTTP/2-based RPC framework" optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "grpcio-1.62.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:136ffd79791b1eddda8d827b607a6285474ff8a1a5735c4947b58c481e5e4271"}, - {file = "grpcio-1.62.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:d6a56ba703be6b6267bf19423d888600c3f574ac7c2cc5e6220af90662a4d6b0"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:4cd356211579043fce9f52acc861e519316fff93980a212c8109cca8f47366b6"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e803e9b58d8f9b4ff0ea991611a8d51b31c68d2e24572cd1fe85e99e8cc1b4f8"}, - {file = "grpcio-1.62.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4c04fe33039b35b97c02d2901a164bbbb2f21fb9c4e2a45a959f0b044c3512c"}, - {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:95370c71b8c9062f9ea033a0867c4c73d6f0ff35113ebd2618171ec1f1e903e0"}, - {file = "grpcio-1.62.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c912688acc05e4ff012c8891803659d6a8a8b5106f0f66e0aed3fb7e77898fa6"}, - {file = "grpcio-1.62.0-cp310-cp310-win32.whl", hash = "sha256:821a44bd63d0f04e33cf4ddf33c14cae176346486b0df08b41a6132b976de5fc"}, - {file = "grpcio-1.62.0-cp310-cp310-win_amd64.whl", hash = "sha256:81531632f93fece32b2762247c4c169021177e58e725494f9a746ca62c83acaa"}, - {file = "grpcio-1.62.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:3fa15850a6aba230eed06b236287c50d65a98f05054a0f01ccedf8e1cc89d57f"}, - {file = "grpcio-1.62.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:36df33080cd7897623feff57831eb83c98b84640b016ce443305977fac7566fb"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:7a195531828b46ea9c4623c47e1dc45650fc7206f8a71825898dd4c9004b0928"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab140a3542bbcea37162bdfc12ce0d47a3cda3f2d91b752a124cc9fe6776a9e2"}, - {file = "grpcio-1.62.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f9d6c3223914abb51ac564dc9c3782d23ca445d2864321b9059d62d47144021"}, - {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fbe0c20ce9a1cff75cfb828b21f08d0a1ca527b67f2443174af6626798a754a4"}, - {file = "grpcio-1.62.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38f69de9c28c1e7a8fd24e4af4264726637b72f27c2099eaea6e513e7142b47e"}, - {file = "grpcio-1.62.0-cp311-cp311-win32.whl", hash = "sha256:ce1aafdf8d3f58cb67664f42a617af0e34555fe955450d42c19e4a6ad41c84bd"}, - {file = "grpcio-1.62.0-cp311-cp311-win_amd64.whl", hash = "sha256:eef1d16ac26c5325e7d39f5452ea98d6988c700c427c52cbc7ce3201e6d93334"}, - {file = "grpcio-1.62.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:8aab8f90b2a41208c0a071ec39a6e5dbba16fd827455aaa070fec241624ccef8"}, - {file = "grpcio-1.62.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:62aa1659d8b6aad7329ede5d5b077e3d71bf488d85795db517118c390358d5f6"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:0d7ae7fc7dbbf2d78d6323641ded767d9ec6d121aaf931ec4a5c50797b886532"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f359d635ee9428f0294bea062bb60c478a8ddc44b0b6f8e1f42997e5dc12e2ee"}, - {file = "grpcio-1.62.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d48e5b1f8f4204889f1acf30bb57c30378e17c8d20df5acbe8029e985f735c"}, - {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:662d3df5314ecde3184cf87ddd2c3a66095b3acbb2d57a8cada571747af03873"}, - {file = "grpcio-1.62.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92cdb616be44c8ac23a57cce0243af0137a10aa82234f23cd46e69e115071388"}, - {file = "grpcio-1.62.0-cp312-cp312-win32.whl", hash = "sha256:0b9179478b09ee22f4a36b40ca87ad43376acdccc816ce7c2193a9061bf35701"}, - {file = "grpcio-1.62.0-cp312-cp312-win_amd64.whl", hash = "sha256:614c3ed234208e76991992342bab725f379cc81c7dd5035ee1de2f7e3f7a9842"}, - {file = "grpcio-1.62.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:7e1f51e2a460b7394670fdb615e26d31d3260015154ea4f1501a45047abe06c9"}, - {file = "grpcio-1.62.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:bcff647e7fe25495e7719f779cc219bbb90b9e79fbd1ce5bda6aae2567f469f2"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:56ca7ba0b51ed0de1646f1735154143dcbdf9ec2dbe8cc6645def299bb527ca1"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e84bfb2a734e4a234b116be208d6f0214e68dcf7804306f97962f93c22a1839"}, - {file = "grpcio-1.62.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c1488b31a521fbba50ae86423f5306668d6f3a46d124f7819c603979fc538c4"}, - {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:98d8f4eb91f1ce0735bf0b67c3b2a4fea68b52b2fd13dc4318583181f9219b4b"}, - {file = "grpcio-1.62.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b3d3d755cfa331d6090e13aac276d4a3fb828bf935449dc16c3d554bf366136b"}, - {file = "grpcio-1.62.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a33f2bfd8a58a02aab93f94f6c61279be0f48f99fcca20ebaee67576cd57307b"}, - {file = "grpcio-1.62.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:5e709f7c8028ce0443bddc290fb9c967c1e0e9159ef7a030e8c21cac1feabd35"}, - {file = "grpcio-1.62.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:2f3d9a4d0abb57e5f49ed5039d3ed375826c2635751ab89dcc25932ff683bbb6"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:62ccb92f594d3d9fcd00064b149a0187c246b11e46ff1b7935191f169227f04c"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:921148f57c2e4b076af59a815467d399b7447f6e0ee10ef6d2601eb1e9c7f402"}, - {file = "grpcio-1.62.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f897b16190b46bc4d4aaf0a32a4b819d559a37a756d7c6b571e9562c360eed72"}, - {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1bc8449084fe395575ed24809752e1dc4592bb70900a03ca42bf236ed5bf008f"}, - {file = "grpcio-1.62.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81d444e5e182be4c7856cd33a610154fe9ea1726bd071d07e7ba13fafd202e38"}, - {file = "grpcio-1.62.0-cp38-cp38-win32.whl", hash = "sha256:88f41f33da3840b4a9bbec68079096d4caf629e2c6ed3a72112159d570d98ebe"}, - {file = "grpcio-1.62.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc2836cb829895ee190813446dce63df67e6ed7b9bf76060262c55fcd097d270"}, - {file = "grpcio-1.62.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fcc98cff4084467839d0a20d16abc2a76005f3d1b38062464d088c07f500d170"}, - {file = "grpcio-1.62.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:0d3dee701e48ee76b7d6fbbba18ba8bc142e5b231ef7d3d97065204702224e0e"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:b7a6be562dd18e5d5bec146ae9537f20ae1253beb971c0164f1e8a2f5a27e829"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29cb592c4ce64a023712875368bcae13938c7f03e99f080407e20ffe0a9aa33b"}, - {file = "grpcio-1.62.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eda79574aec8ec4d00768dcb07daba60ed08ef32583b62b90bbf274b3c279f7"}, - {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7eea57444a354ee217fda23f4b479a4cdfea35fb918ca0d8a0e73c271e52c09c"}, - {file = "grpcio-1.62.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0e97f37a3b7c89f9125b92d22e9c8323f4e76e7993ba7049b9f4ccbe8bae958a"}, - {file = "grpcio-1.62.0-cp39-cp39-win32.whl", hash = "sha256:39cd45bd82a2e510e591ca2ddbe22352e8413378852ae814549c162cf3992a93"}, - {file = "grpcio-1.62.0-cp39-cp39-win_amd64.whl", hash = "sha256:b71c65427bf0ec6a8b48c68c17356cb9fbfc96b1130d20a07cb462f4e4dcdcd5"}, - {file = "grpcio-1.62.0.tar.gz", hash = "sha256:748496af9238ac78dcd98cce65421f1adce28c3979393e3609683fcd7f3880d7"}, -] - -[package.extras] -protobuf = ["grpcio-tools (>=1.62.0)"] + {file = "grpcio-1.64.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:55697ecec192bc3f2f3cc13a295ab670f51de29884ca9ae6cd6247df55df2502"}, + {file = "grpcio-1.64.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:3b64ae304c175671efdaa7ec9ae2cc36996b681eb63ca39c464958396697daff"}, + {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:bac71b4b28bc9af61efcdc7630b166440bbfbaa80940c9a697271b5e1dabbc61"}, + {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c024ffc22d6dc59000faf8ad781696d81e8e38f4078cb0f2630b4a3cf231a90"}, + {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7cd5c1325f6808b8ae31657d281aadb2a51ac11ab081ae335f4f7fc44c1721d"}, + {file = "grpcio-1.64.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0a2813093ddb27418a4c99f9b1c223fab0b053157176a64cc9db0f4557b69bd9"}, + {file = "grpcio-1.64.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2981c7365a9353f9b5c864595c510c983251b1ab403e05b1ccc70a3d9541a73b"}, + {file = "grpcio-1.64.1-cp310-cp310-win32.whl", hash = "sha256:1262402af5a511c245c3ae918167eca57342c72320dffae5d9b51840c4b2f86d"}, + {file = "grpcio-1.64.1-cp310-cp310-win_amd64.whl", hash = "sha256:19264fc964576ddb065368cae953f8d0514ecc6cb3da8903766d9fb9d4554c33"}, + {file = "grpcio-1.64.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:58b1041e7c870bb30ee41d3090cbd6f0851f30ae4eb68228955d973d3efa2e61"}, + {file = "grpcio-1.64.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bbc5b1d78a7822b0a84c6f8917faa986c1a744e65d762ef6d8be9d75677af2ca"}, + {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:5841dd1f284bd1b3d8a6eca3a7f062b06f1eec09b184397e1d1d43447e89a7ae"}, + {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8caee47e970b92b3dd948371230fcceb80d3f2277b3bf7fbd7c0564e7d39068e"}, + {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73819689c169417a4f978e562d24f2def2be75739c4bed1992435d007819da1b"}, + {file = "grpcio-1.64.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6503b64c8b2dfad299749cad1b595c650c91e5b2c8a1b775380fcf8d2cbba1e9"}, + {file = "grpcio-1.64.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1de403fc1305fd96cfa75e83be3dee8538f2413a6b1685b8452301c7ba33c294"}, + {file = "grpcio-1.64.1-cp311-cp311-win32.whl", hash = "sha256:d4d29cc612e1332237877dfa7fe687157973aab1d63bd0f84cf06692f04c0367"}, + {file = "grpcio-1.64.1-cp311-cp311-win_amd64.whl", hash = "sha256:5e56462b05a6f860b72f0fa50dca06d5b26543a4e88d0396259a07dc30f4e5aa"}, + {file = "grpcio-1.64.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:4657d24c8063e6095f850b68f2d1ba3b39f2b287a38242dcabc166453e950c59"}, + {file = "grpcio-1.64.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:62b4e6eb7bf901719fce0ca83e3ed474ae5022bb3827b0a501e056458c51c0a1"}, + {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:ee73a2f5ca4ba44fa33b4d7d2c71e2c8a9e9f78d53f6507ad68e7d2ad5f64a22"}, + {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:198908f9b22e2672a998870355e226a725aeab327ac4e6ff3a1399792ece4762"}, + {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39b9d0acaa8d835a6566c640f48b50054f422d03e77e49716d4c4e8e279665a1"}, + {file = "grpcio-1.64.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:5e42634a989c3aa6049f132266faf6b949ec2a6f7d302dbb5c15395b77d757eb"}, + {file = "grpcio-1.64.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b1a82e0b9b3022799c336e1fc0f6210adc019ae84efb7321d668129d28ee1efb"}, + {file = "grpcio-1.64.1-cp312-cp312-win32.whl", hash = "sha256:55260032b95c49bee69a423c2f5365baa9369d2f7d233e933564d8a47b893027"}, + {file = "grpcio-1.64.1-cp312-cp312-win_amd64.whl", hash = "sha256:c1a786ac592b47573a5bb7e35665c08064a5d77ab88a076eec11f8ae86b3e3f6"}, + {file = "grpcio-1.64.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:a011ac6c03cfe162ff2b727bcb530567826cec85eb8d4ad2bfb4bd023287a52d"}, + {file = "grpcio-1.64.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4d6dab6124225496010bd22690f2d9bd35c7cbb267b3f14e7a3eb05c911325d4"}, + {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:a5e771d0252e871ce194d0fdcafd13971f1aae0ddacc5f25615030d5df55c3a2"}, + {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c3c1b90ab93fed424e454e93c0ed0b9d552bdf1b0929712b094f5ecfe7a23ad"}, + {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20405cb8b13fd779135df23fabadc53b86522d0f1cba8cca0e87968587f50650"}, + {file = "grpcio-1.64.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0cc79c982ccb2feec8aad0e8fb0d168bcbca85bc77b080d0d3c5f2f15c24ea8f"}, + {file = "grpcio-1.64.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a3a035c37ce7565b8f4f35ff683a4db34d24e53dc487e47438e434eb3f701b2a"}, + {file = "grpcio-1.64.1-cp38-cp38-win32.whl", hash = "sha256:1257b76748612aca0f89beec7fa0615727fd6f2a1ad580a9638816a4b2eb18fd"}, + {file = "grpcio-1.64.1-cp38-cp38-win_amd64.whl", hash = "sha256:0a12ddb1678ebc6a84ec6b0487feac020ee2b1659cbe69b80f06dbffdb249122"}, + {file = "grpcio-1.64.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:75dbbf415026d2862192fe1b28d71f209e2fd87079d98470db90bebe57b33179"}, + {file = "grpcio-1.64.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e3d9f8d1221baa0ced7ec7322a981e28deb23749c76eeeb3d33e18b72935ab62"}, + {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5f8b75f64d5d324c565b263c67dbe4f0af595635bbdd93bb1a88189fc62ed2e5"}, + {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c84ad903d0d94311a2b7eea608da163dace97c5fe9412ea311e72c3684925602"}, + {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:940e3ec884520155f68a3b712d045e077d61c520a195d1a5932c531f11883489"}, + {file = "grpcio-1.64.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f10193c69fc9d3d726e83bbf0f3d316f1847c3071c8c93d8090cf5f326b14309"}, + {file = "grpcio-1.64.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac15b6c2c80a4d1338b04d42a02d376a53395ddf0ec9ab157cbaf44191f3ffdd"}, + {file = "grpcio-1.64.1-cp39-cp39-win32.whl", hash = "sha256:03b43d0ccf99c557ec671c7dede64f023c7da9bb632ac65dbc57f166e4970040"}, + {file = "grpcio-1.64.1-cp39-cp39-win_amd64.whl", hash = "sha256:ed6091fa0adcc7e4ff944090cf203a52da35c37a130efa564ded02b7aff63bcd"}, + {file = "grpcio-1.64.1.tar.gz", hash = "sha256:8d51dd1c59d5fa0f34266b80a3805ec29a1f26425c2a54736133f6d87fc4968a"}, +] + +[package.extras] +protobuf = ["grpcio-tools (>=1.64.1)"] [[package]] name = "h11" @@ -2085,15 +2146,41 @@ files = [ {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, ] +[[package]] +name = "h2" +version = "4.1.0" +description = "HTTP/2 State-Machine based protocol implementation" +optional = true +python-versions = ">=3.6.1" +files = [ + {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, + {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"}, +] + +[package.dependencies] +hpack = ">=4.0,<5" +hyperframe = ">=6.0,<7" + +[[package]] +name = "hpack" +version = "4.0.0" +description = "Pure-Python HPACK header compression" +optional = true +python-versions = ">=3.6.1" +files = [ + {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, + {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, +] + [[package]] name = "httpcore" -version = "1.0.4" +version = "1.0.5" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.4-py3-none-any.whl", hash = "sha256:ac418c1db41bade2ad53ae2f3834a3a0f5ae76b56cf5aa497d2d033384fc7d73"}, - {file = "httpcore-1.0.4.tar.gz", hash = "sha256:cb2839ccfcba0d2d3c1131d3c3e26dfc327326fbe7a5dc0dbfe9f6c9151bb022"}, + {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, + {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, ] [package.dependencies] @@ -2104,7 +2191,7 @@ h11 = ">=0.13,<0.15" asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.25.0)"] +trio = ["trio (>=0.22.0,<0.26.0)"] [[package]] name = "httptools" @@ -2168,9 +2255,11 @@ files = [ [package.dependencies] anyio = "*" certifi = "*" +h2 = {version = ">=3,<5", optional = true, markers = "extra == \"http2\""} httpcore = "==1.*" idna = "*" sniffio = "*" +socksio = {version = "==1.*", optional = true, markers = "extra == \"socks\""} [package.extras] brotli = ["brotli", "brotlicffi"] @@ -2192,6 +2281,17 @@ files = [ [package.extras] tests = ["freezegun", "pytest", "pytest-cov"] +[[package]] +name = "hyperframe" +version = "6.0.1" +description = "HTTP/2 framing layer for Python" +optional = true +python-versions = ">=3.6.1" +files = [ + {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, + {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, +] + [[package]] name = "idna" version = "3.7" @@ -2216,32 +2316,32 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.11.0" +version = "7.1.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-6.11.0-py3-none-any.whl", hash = "sha256:f0afba6205ad8f8947c7d338b5342d5db2afbfd82f9cbef7879a9539cc12eb9b"}, - {file = "importlib_metadata-6.11.0.tar.gz", hash = "sha256:1231cf92d825c9e03cfc4da076a16de6422c863558229ea0b22b675657463443"}, + {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, + {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "importlib-resources" -version = "6.1.2" +version = "6.4.0" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.2-py3-none-any.whl", hash = "sha256:9a0a862501dc38b68adebc82970140c9e4209fc99601782925178f8386339938"}, - {file = "importlib_resources-6.1.2.tar.gz", hash = "sha256:308abf8474e2dba5f867d279237cd4076482c3de7104a40b41426370e891549b"}, + {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, + {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, ] [package.dependencies] @@ -2249,7 +2349,7 @@ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] +testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] [[package]] name = "iniconfig" @@ -2275,13 +2375,13 @@ files = [ [[package]] name = "ipykernel" -version = "6.29.3" +version = "6.29.4" description = "IPython Kernel for Jupyter" optional = false python-versions = ">=3.8" files = [ - {file = "ipykernel-6.29.3-py3-none-any.whl", hash = "sha256:5aa086a4175b0229d4eca211e181fb473ea78ffd9869af36ba7694c947302a21"}, - {file = "ipykernel-6.29.3.tar.gz", hash = "sha256:e14c250d1f9ea3989490225cc1a542781b095a18a19447fcf2b5eaf7d0ac5bd2"}, + {file = "ipykernel-6.29.4-py3-none-any.whl", hash = "sha256:1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da"}, + {file = "ipykernel-6.29.4.tar.gz", hash = "sha256:3d44070060f9475ac2092b760123fadf105d2e2493c24848b6691a7c4f42af5c"}, ] [package.dependencies] @@ -2347,21 +2447,21 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pa [[package]] name = "ipywidgets" -version = "8.1.2" +version = "8.1.3" description = "Jupyter interactive widgets" optional = false python-versions = ">=3.7" files = [ - {file = "ipywidgets-8.1.2-py3-none-any.whl", hash = "sha256:bbe43850d79fb5e906b14801d6c01402857996864d1e5b6fa62dd2ee35559f60"}, - {file = "ipywidgets-8.1.2.tar.gz", hash = "sha256:d0b9b41e49bae926a866e613a39b0f0097745d2b9f1f3dd406641b4a57ec42c9"}, + {file = "ipywidgets-8.1.3-py3-none-any.whl", hash = "sha256:efafd18f7a142248f7cb0ba890a68b96abd4d6e88ddbda483c9130d12667eaf2"}, + {file = "ipywidgets-8.1.3.tar.gz", hash = "sha256:f5f9eeaae082b1823ce9eac2575272952f40d748893972956dc09700a6392d9c"}, ] [package.dependencies] comm = ">=0.1.3" ipython = ">=6.1.0" -jupyterlab-widgets = ">=3.0.10,<3.1.0" +jupyterlab-widgets = ">=3.0.11,<3.1.0" traitlets = ">=4.3.1" -widgetsnbextension = ">=4.0.10,<4.1.0" +widgetsnbextension = ">=4.0.11,<4.1.0" [package.extras] test = ["ipykernel", "jsonschema", "pytest (>=3.6.0)", "pytest-cov", "pytz"] @@ -2396,31 +2496,31 @@ colors = ["colorama (>=0.4.6)"] [[package]] name = "itsdangerous" -version = "2.1.2" +version = "2.2.0" description = "Safely pass data to untrusted environments and back." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, - {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, + {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, + {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, ] [[package]] name = "jaraco-classes" -version = "3.3.1" +version = "3.4.0" description = "Utility functions for Python class constructs" optional = false python-versions = ">=3.8" files = [ - {file = "jaraco.classes-3.3.1-py3-none-any.whl", hash = "sha256:86b534de565381f6b3c1c830d13f931d7be1a75f0081c57dff615578676e2206"}, - {file = "jaraco.classes-3.3.1.tar.gz", hash = "sha256:cb28a5ebda8bc47d8c8015307d93163464f9f2b91ab4006e09ff0ce07e8bfb30"}, + {file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"}, + {file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"}, ] [package.dependencies] more-itertools = "*" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [[package]] @@ -2459,13 +2559,13 @@ trio = ["async_generator", "trio"] [[package]] name = "jinja2" -version = "3.1.3" +version = "3.1.4" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, - {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, ] [package.dependencies] @@ -2476,27 +2576,24 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "json5" -version = "0.9.17" +version = "0.9.25" description = "A Python implementation of the JSON5 data format." optional = false python-versions = ">=3.8" files = [ - {file = "json5-0.9.17-py2.py3-none-any.whl", hash = "sha256:f8ec1ecf985951d70f780f6f877c4baca6a47b6e61e02c4cd190138d10a7805a"}, - {file = "json5-0.9.17.tar.gz", hash = "sha256:717d99d657fa71b7094877b1d921b1cce40ab444389f6d770302563bb7dfd9ae"}, + {file = "json5-0.9.25-py3-none-any.whl", hash = "sha256:34ed7d834b1341a86987ed52f3f76cd8ee184394906b6e22a1e0deb9ab294e8f"}, + {file = "json5-0.9.25.tar.gz", hash = "sha256:548e41b9be043f9426776f05df8635a00fe06104ea51ed24b67f908856e151ae"}, ] -[package.extras] -dev = ["hypothesis"] - [[package]] name = "jsonpointer" -version = "2.4" +version = "3.0.0" description = "Identify specific nodes in a JSON document (RFC 6901)" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +python-versions = ">=3.7" files = [ - {file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"}, - {file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"}, + {file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"}, + {file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"}, ] [[package]] @@ -2567,13 +2664,13 @@ qtconsole = "*" [[package]] name = "jupyter-client" -version = "8.6.0" +version = "8.6.2" description = "Jupyter protocol implementation and client libraries" optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_client-8.6.0-py3-none-any.whl", hash = "sha256:909c474dbe62582ae62b758bca86d6518c85234bdee2d908c778db6d72f39d99"}, - {file = "jupyter_client-8.6.0.tar.gz", hash = "sha256:0642244bb83b4764ae60d07e010e15f0e2d275ec4e918a8f7b80fbbef3ca60c7"}, + {file = "jupyter_client-8.6.2-py3-none-any.whl", hash = "sha256:50cbc5c66fd1b8f65ecb66bc490ab73217993632809b6e505687de18e9dea39f"}, + {file = "jupyter_client-8.6.2.tar.gz", hash = "sha256:2bda14d55ee5ba58552a8c53ae43d215ad9868853489213f37da060ced54d8df"}, ] [package.dependencies] @@ -2586,7 +2683,7 @@ traitlets = ">=5.3" [package.extras] docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] +test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest (<8.2.0)", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] [[package]] name = "jupyter-console" @@ -2614,13 +2711,13 @@ test = ["flaky", "pexpect", "pytest"] [[package]] name = "jupyter-core" -version = "5.7.1" +version = "5.7.2" description = "Jupyter core package. A base package on which Jupyter projects rely." optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_core-5.7.1-py3-none-any.whl", hash = "sha256:c65c82126453a723a2804aa52409930434598fd9d35091d63dfb919d2b765bb7"}, - {file = "jupyter_core-5.7.1.tar.gz", hash = "sha256:de61a9d7fc71240f688b2fb5ab659fbb56979458dc66a71decd098e03c79e218"}, + {file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"}, + {file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"}, ] [package.dependencies] @@ -2630,17 +2727,17 @@ traitlets = ">=5.3" [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] -test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] +test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"] [[package]] name = "jupyter-events" -version = "0.9.0" +version = "0.10.0" description = "Jupyter Event System library" optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_events-0.9.0-py3-none-any.whl", hash = "sha256:d853b3c10273ff9bc8bb8b30076d65e2c9685579db736873de6c2232dde148bf"}, - {file = "jupyter_events-0.9.0.tar.gz", hash = "sha256:81ad2e4bc710881ec274d31c6c50669d71bbaa5dd9d01e600b56faa85700d399"}, + {file = "jupyter_events-0.10.0-py3-none-any.whl", hash = "sha256:4b72130875e59d57716d327ea70d3ebc3af1944d3717e5a498b8a06c6c159960"}, + {file = "jupyter_events-0.10.0.tar.gz", hash = "sha256:670b8229d3cc882ec782144ed22e0d29e1c2d639263f92ca8383e66682845e22"}, ] [package.dependencies] @@ -2659,13 +2756,13 @@ test = ["click", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.19.0)", "p [[package]] name = "jupyter-lsp" -version = "2.2.3" +version = "2.2.5" description = "Multi-Language Server WebSocket proxy for Jupyter Notebook/Lab server" optional = false python-versions = ">=3.8" files = [ - {file = "jupyter-lsp-2.2.3.tar.gz", hash = "sha256:33dbcbc5df24237ff5c8b696b04ff4689fcd316cb8d4957d620fe5504d7d2c3f"}, - {file = "jupyter_lsp-2.2.3-py3-none-any.whl", hash = "sha256:57dd90d0a2e2530831793550846168c81c952b49e187aa339e455027a5f0fd2e"}, + {file = "jupyter-lsp-2.2.5.tar.gz", hash = "sha256:793147a05ad446f809fd53ef1cd19a9f5256fd0a2d6b7ce943a982cb4f545001"}, + {file = "jupyter_lsp-2.2.5-py3-none-any.whl", hash = "sha256:45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da"}, ] [package.dependencies] @@ -2674,49 +2771,49 @@ jupyter-server = ">=1.1.2" [[package]] name = "jupyter-server" -version = "2.12.5" +version = "2.14.1" description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_server-2.12.5-py3-none-any.whl", hash = "sha256:184a0f82809a8522777cfb6b760ab6f4b1bb398664c5860a27cec696cb884923"}, - {file = "jupyter_server-2.12.5.tar.gz", hash = "sha256:0edb626c94baa22809be1323f9770cf1c00a952b17097592e40d03e6a3951689"}, + {file = "jupyter_server-2.14.1-py3-none-any.whl", hash = "sha256:16f7177c3a4ea8fe37784e2d31271981a812f0b2874af17339031dc3510cc2a5"}, + {file = "jupyter_server-2.14.1.tar.gz", hash = "sha256:12558d158ec7a0653bf96cc272bc7ad79e0127d503b982ed144399346694f726"}, ] [package.dependencies] anyio = ">=3.1.0" -argon2-cffi = "*" -jinja2 = "*" +argon2-cffi = ">=21.1" +jinja2 = ">=3.0.3" jupyter-client = ">=7.4.4" jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" jupyter-events = ">=0.9.0" -jupyter-server-terminals = "*" +jupyter-server-terminals = ">=0.4.4" nbconvert = ">=6.4.4" nbformat = ">=5.3.0" -overrides = "*" -packaging = "*" -prometheus-client = "*" -pywinpty = {version = "*", markers = "os_name == \"nt\""} +overrides = ">=5.0" +packaging = ">=22.0" +prometheus-client = ">=0.9" +pywinpty = {version = ">=2.0.1", markers = "os_name == \"nt\""} pyzmq = ">=24" send2trash = ">=1.8.2" terminado = ">=0.8.3" tornado = ">=6.2.0" traitlets = ">=5.6.0" -websocket-client = "*" +websocket-client = ">=1.7" [package.extras] -docs = ["ipykernel", "jinja2", "jupyter-client", "jupyter-server", "myst-parser", "nbformat", "prometheus-client", "pydata-sphinx-theme", "send2trash", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-openapi (>=0.8.0)", "sphinxcontrib-spelling", "sphinxemoji", "tornado", "typing-extensions"] -test = ["flaky", "ipykernel", "pre-commit", "pytest (>=7.0)", "pytest-console-scripts", "pytest-jupyter[server] (>=0.4)", "pytest-timeout", "requests"] +docs = ["ipykernel", "jinja2", "jupyter-client", "myst-parser", "nbformat", "prometheus-client", "pydata-sphinx-theme", "send2trash", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-openapi (>=0.8.0)", "sphinxcontrib-spelling", "sphinxemoji", "tornado", "typing-extensions"] +test = ["flaky", "ipykernel", "pre-commit", "pytest (>=7.0,<9)", "pytest-console-scripts", "pytest-jupyter[server] (>=0.7)", "pytest-timeout", "requests"] [[package]] name = "jupyter-server-terminals" -version = "0.5.2" +version = "0.5.3" description = "A Jupyter Server Extension Providing Terminals." optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_server_terminals-0.5.2-py3-none-any.whl", hash = "sha256:1b80c12765da979513c42c90215481bbc39bd8ae7c0350b4f85bc3eb58d0fa80"}, - {file = "jupyter_server_terminals-0.5.2.tar.gz", hash = "sha256:396b5ccc0881e550bf0ee7012c6ef1b53edbde69e67cab1d56e89711b46052e8"}, + {file = "jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa"}, + {file = "jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269"}, ] [package.dependencies] @@ -2729,13 +2826,13 @@ test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (> [[package]] name = "jupyterlab" -version = "4.1.2" +version = "4.2.3" description = "JupyterLab computational environment" optional = false python-versions = ">=3.8" files = [ - {file = "jupyterlab-4.1.2-py3-none-any.whl", hash = "sha256:aa88193f03cf4d3555f6712f04d74112b5eb85edd7d222c588c7603a26d33c5b"}, - {file = "jupyterlab-4.1.2.tar.gz", hash = "sha256:5d6348b3ed4085181499f621b7dfb6eb0b1f57f3586857aadfc8e3bf4c4885f9"}, + {file = "jupyterlab-4.2.3-py3-none-any.whl", hash = "sha256:0b59d11808e84bb84105c73364edfa867dd475492429ab34ea388a52f2e2e596"}, + {file = "jupyterlab-4.2.3.tar.gz", hash = "sha256:df6e46969ea51d66815167f23d92f105423b7f1f06fa604d4f44aeb018c82c7b"}, ] [package.dependencies] @@ -2743,23 +2840,25 @@ async-lru = ">=1.0.0" httpx = ">=0.25.0" importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} importlib-resources = {version = ">=1.4", markers = "python_version < \"3.9\""} -ipykernel = "*" +ipykernel = ">=6.5.0" jinja2 = ">=3.0.3" jupyter-core = "*" jupyter-lsp = ">=2.0.0" jupyter-server = ">=2.4.0,<3" -jupyterlab-server = ">=2.19.0,<3" +jupyterlab-server = ">=2.27.1,<3" notebook-shim = ">=0.2" packaging = "*" -tomli = {version = "*", markers = "python_version < \"3.11\""} +setuptools = ">=40.1.0" +tomli = {version = ">=1.2.2", markers = "python_version < \"3.11\""} tornado = ">=6.2.0" traitlets = "*" [package.extras] -dev = ["build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.2.0)"] +dev = ["build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.3.5)"] docs = ["jsx-lexer", "myst-parser", "pydata-sphinx-theme (>=0.13.0)", "pytest", "pytest-check-links", "pytest-jupyter", "sphinx (>=1.8,<7.3.0)", "sphinx-copybutton"] -docs-screenshots = ["altair (==5.2.0)", "ipython (==8.16.1)", "ipywidgets (==8.1.1)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.0.post6)", "matplotlib (==3.8.2)", "nbconvert (>=7.0.0)", "pandas (==2.2.0)", "scipy (==1.12.0)", "vega-datasets (==0.9.0)"] +docs-screenshots = ["altair (==5.3.0)", "ipython (==8.16.1)", "ipywidgets (==8.1.2)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.1.post2)", "matplotlib (==3.8.3)", "nbconvert (>=7.0.0)", "pandas (==2.2.1)", "scipy (==1.12.0)", "vega-datasets (==0.9.0)"] test = ["coverage", "pytest (>=7.0)", "pytest-check-links (>=0.7)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter (>=0.5.3)", "pytest-timeout", "pytest-tornasync", "requests", "requests-cache", "virtualenv"] +upgrade-extension = ["copier (>=8,<10)", "jinja2-time (<0.3)", "pydantic (<2.0)", "pyyaml-include (<2.0)", "tomli-w (<2.0)"] [[package]] name = "jupyterlab-pygments" @@ -2774,13 +2873,13 @@ files = [ [[package]] name = "jupyterlab-server" -version = "2.25.3" +version = "2.27.2" description = "A set of server components for JupyterLab and JupyterLab like applications." optional = false python-versions = ">=3.8" files = [ - {file = "jupyterlab_server-2.25.3-py3-none-any.whl", hash = "sha256:c48862519fded9b418c71645d85a49b2f0ec50d032ba8316738e9276046088c1"}, - {file = "jupyterlab_server-2.25.3.tar.gz", hash = "sha256:846f125a8a19656611df5b03e5912c8393cea6900859baa64fa515eb64a8dc40"}, + {file = "jupyterlab_server-2.27.2-py3-none-any.whl", hash = "sha256:54aa2d64fd86383b5438d9f0c032f043c4d8c0264b8af9f60bd061157466ea43"}, + {file = "jupyterlab_server-2.27.2.tar.gz", hash = "sha256:15cbb349dc45e954e09bacf81b9f9bcb10815ff660fb2034ecd7417db3a7ea27"}, ] [package.dependencies] @@ -2796,28 +2895,28 @@ requests = ">=2.31" [package.extras] docs = ["autodoc-traits", "jinja2 (<3.2.0)", "mistune (<4)", "myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-copybutton", "sphinxcontrib-openapi (>0.8)"] openapi = ["openapi-core (>=0.18.0,<0.19.0)", "ruamel-yaml"] -test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-validator (>=0.6.0,<0.8.0)", "pytest (>=7.0)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter[server] (>=0.6.2)", "pytest-timeout", "requests-mock", "ruamel-yaml", "sphinxcontrib-spelling", "strict-rfc3339", "werkzeug"] +test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-validator (>=0.6.0,<0.8.0)", "pytest (>=7.0,<8)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter[server] (>=0.6.2)", "pytest-timeout", "requests-mock", "ruamel-yaml", "sphinxcontrib-spelling", "strict-rfc3339", "werkzeug"] [[package]] name = "jupyterlab-widgets" -version = "3.0.10" +version = "3.0.11" description = "Jupyter interactive widgets for JupyterLab" optional = false python-versions = ">=3.7" files = [ - {file = "jupyterlab_widgets-3.0.10-py3-none-any.whl", hash = "sha256:dd61f3ae7a5a7f80299e14585ce6cf3d6925a96c9103c978eda293197730cb64"}, - {file = "jupyterlab_widgets-3.0.10.tar.gz", hash = "sha256:04f2ac04976727e4f9d0fa91cdc2f1ab860f965e504c29dbd6a65c882c9d04c0"}, + {file = "jupyterlab_widgets-3.0.11-py3-none-any.whl", hash = "sha256:78287fd86d20744ace330a61625024cf5521e1c012a352ddc0a3cdc2348becd0"}, + {file = "jupyterlab_widgets-3.0.11.tar.gz", hash = "sha256:dd5ac679593c969af29c9bed054c24f26842baa51352114736756bc035deee27"}, ] [[package]] name = "jupytext" -version = "1.16.1" +version = "1.16.2" description = "Jupyter notebooks as Markdown documents, Julia, Python or R scripts" optional = false python-versions = ">=3.8" files = [ - {file = "jupytext-1.16.1-py3-none-any.whl", hash = "sha256:796ec4f68ada663569e5d38d4ef03738a01284bfe21c943c485bc36433898bd0"}, - {file = "jupytext-1.16.1.tar.gz", hash = "sha256:68c7b68685e870e80e60fda8286fbd6269e9c74dc1df4316df6fe46eabc94c99"}, + {file = "jupytext-1.16.2-py3-none-any.whl", hash = "sha256:197a43fef31dca612b68b311e01b8abd54441c7e637810b16b6cb8f2ab66065e"}, + {file = "jupytext-1.16.2.tar.gz", hash = "sha256:8627dd9becbbebd79cc4a4ed4727d89d78e606b4b464eab72357b3b029023a14"}, ] [package.dependencies] @@ -2826,16 +2925,16 @@ mdit-py-plugins = "*" nbformat = "*" packaging = "*" pyyaml = "*" -toml = "*" +tomli = {version = "*", markers = "python_version < \"3.11\""} [package.extras] -dev = ["jupytext[test-cov,test-external]"] +dev = ["autopep8", "black", "flake8", "gitpython", "ipykernel", "isort", "jupyter-fs (<0.4.0)", "jupyter-server (!=2.11)", "nbconvert", "pre-commit", "pytest", "pytest-cov (>=2.6.1)", "pytest-randomly", "pytest-xdist", "sphinx-gallery (<0.8)"] docs = ["myst-parser", "sphinx", "sphinx-copybutton", "sphinx-rtd-theme"] test = ["pytest", "pytest-randomly", "pytest-xdist"] -test-cov = ["jupytext[test-integration]", "pytest-cov (>=2.6.1)"] -test-external = ["autopep8", "black", "flake8", "gitpython", "isort", "jupyter-fs (<0.4.0)", "jupytext[test-integration]", "pre-commit", "sphinx-gallery (<0.8)"] -test-functional = ["jupytext[test]"] -test-integration = ["ipykernel", "jupyter-server (!=2.11)", "jupytext[test-functional]", "nbconvert"] +test-cov = ["ipykernel", "jupyter-server (!=2.11)", "nbconvert", "pytest", "pytest-cov (>=2.6.1)", "pytest-randomly", "pytest-xdist"] +test-external = ["autopep8", "black", "flake8", "gitpython", "ipykernel", "isort", "jupyter-fs (<0.4.0)", "jupyter-server (!=2.11)", "nbconvert", "pre-commit", "pytest", "pytest-randomly", "pytest-xdist", "sphinx-gallery (<0.8)"] +test-functional = ["pytest", "pytest-randomly", "pytest-xdist"] +test-integration = ["ipykernel", "jupyter-server (!=2.11)", "nbconvert", "pytest", "pytest-randomly", "pytest-xdist"] test-ui = ["calysto-bash"] [[package]] @@ -2984,13 +3083,13 @@ files = [ [[package]] name = "matplotlib-inline" -version = "0.1.6" +version = "0.1.7" description = "Inline Matplotlib backend for Jupyter" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, - {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, + {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, + {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, ] [package.dependencies] @@ -3009,13 +3108,13 @@ files = [ [[package]] name = "mdit-py-plugins" -version = "0.4.0" +version = "0.4.1" description = "Collection of plugins for markdown-it-py" optional = false python-versions = ">=3.8" files = [ - {file = "mdit_py_plugins-0.4.0-py3-none-any.whl", hash = "sha256:b51b3bb70691f57f974e257e367107857a93b36f322a9e6d44ca5bf28ec2def9"}, - {file = "mdit_py_plugins-0.4.0.tar.gz", hash = "sha256:d8ab27e9aed6c38aa716819fedfde15ca275715955f8a185a8e1cf90fb1d2c1b"}, + {file = "mdit_py_plugins-0.4.1-py3-none-any.whl", hash = "sha256:1020dfe4e6bfc2c79fb49ae4e3f5b297f5ccd20f010187acc52af2921e27dc6a"}, + {file = "mdit_py_plugins-0.4.1.tar.gz", hash = "sha256:834b8ac23d1cd60cec703646ffd22ae97b7955a6d596eb1d304be1e251ae499c"}, ] [package.dependencies] @@ -3066,24 +3165,24 @@ test = ["pytest", "pytest-cov"] [[package]] name = "more-itertools" -version = "10.2.0" +version = "10.3.0" description = "More routines for operating on iterables, beyond itertools" optional = false python-versions = ">=3.8" files = [ - {file = "more-itertools-10.2.0.tar.gz", hash = "sha256:8fccb480c43d3e99a00087634c06dd02b0d50fbf088b380de5a41a015ec239e1"}, - {file = "more_itertools-10.2.0-py3-none-any.whl", hash = "sha256:686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684"}, + {file = "more-itertools-10.3.0.tar.gz", hash = "sha256:e5d93ef411224fbcef366a6e8ddc4c5781bc6359d43412a65dd5964e46111463"}, + {file = "more_itertools-10.3.0-py3-none-any.whl", hash = "sha256:ea6a02e24a9161e51faad17a8782b92a0df82c12c1c8886fec7f0c3fa1a1b320"}, ] [[package]] name = "motor" -version = "3.4.0" +version = "3.5.0" description = "Non-blocking MongoDB driver for Tornado or asyncio" optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "motor-3.4.0-py3-none-any.whl", hash = "sha256:4b1e1a0cc5116ff73be2c080a72da078f2bb719b53bc7a6bb9e9a2f7dcd421ed"}, - {file = "motor-3.4.0.tar.gz", hash = "sha256:c89b4e4eb2e711345e91c7c9b122cb68cce0e5e869ed0387dd0acb10775e3131"}, + {file = "motor-3.5.0-py3-none-any.whl", hash = "sha256:e8f1d7a3370e8dd30eb4c68aaaee46dc608fbac70a757e58f3e828124f5e7693"}, + {file = "motor-3.5.0.tar.gz", hash = "sha256:2b38e405e5a0c52d499edb8d23fa029debdf0158da092c21b44d92cac7f59942"}, ] [package.dependencies] @@ -3091,77 +3190,77 @@ pymongo = ">=4.5,<5" [package.extras] aws = ["pymongo[aws] (>=4.5,<5)"] +docs = ["aiohttp", "readthedocs-sphinx-search (>=0.3,<1.0)", "sphinx (>=5.3,<8)", "sphinx-rtd-theme (>=2,<3)", "tornado"] encryption = ["pymongo[encryption] (>=4.5,<5)"] gssapi = ["pymongo[gssapi] (>=4.5,<5)"] ocsp = ["pymongo[ocsp] (>=4.5,<5)"] snappy = ["pymongo[snappy] (>=4.5,<5)"] -srv = ["pymongo[srv] (>=4.5,<5)"] -test = ["aiohttp (!=3.8.6)", "mockupdb", "motor[encryption]", "pytest (>=7)", "tornado (>=5)"] +test = ["aiohttp (!=3.8.6)", "mockupdb", "pymongo[encryption] (>=4.5,<5)", "pytest (>=7)", "tornado (>=5)"] zstd = ["pymongo[zstd] (>=4.5,<5)"] [[package]] name = "msgpack" -version = "1.0.7" +version = "1.0.8" description = "MessagePack serializer" optional = false python-versions = ">=3.8" files = [ - {file = "msgpack-1.0.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:04ad6069c86e531682f9e1e71b71c1c3937d6014a7c3e9edd2aa81ad58842862"}, - {file = "msgpack-1.0.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cca1b62fe70d761a282496b96a5e51c44c213e410a964bdffe0928e611368329"}, - {file = "msgpack-1.0.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e50ebce52f41370707f1e21a59514e3375e3edd6e1832f5e5235237db933c98b"}, - {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7b4f35de6a304b5533c238bee86b670b75b03d31b7797929caa7a624b5dda6"}, - {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28efb066cde83c479dfe5a48141a53bc7e5f13f785b92ddde336c716663039ee"}, - {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4cb14ce54d9b857be9591ac364cb08dc2d6a5c4318c1182cb1d02274029d590d"}, - {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b573a43ef7c368ba4ea06050a957c2a7550f729c31f11dd616d2ac4aba99888d"}, - {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ccf9a39706b604d884d2cb1e27fe973bc55f2890c52f38df742bc1d79ab9f5e1"}, - {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cb70766519500281815dfd7a87d3a178acf7ce95390544b8c90587d76b227681"}, - {file = "msgpack-1.0.7-cp310-cp310-win32.whl", hash = "sha256:b610ff0f24e9f11c9ae653c67ff8cc03c075131401b3e5ef4b82570d1728f8a9"}, - {file = "msgpack-1.0.7-cp310-cp310-win_amd64.whl", hash = "sha256:a40821a89dc373d6427e2b44b572efc36a2778d3f543299e2f24eb1a5de65415"}, - {file = "msgpack-1.0.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:576eb384292b139821c41995523654ad82d1916da6a60cff129c715a6223ea84"}, - {file = "msgpack-1.0.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:730076207cb816138cf1af7f7237b208340a2c5e749707457d70705715c93b93"}, - {file = "msgpack-1.0.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:85765fdf4b27eb5086f05ac0491090fc76f4f2b28e09d9350c31aac25a5aaff8"}, - {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3476fae43db72bd11f29a5147ae2f3cb22e2f1a91d575ef130d2bf49afd21c46"}, - {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d4c80667de2e36970ebf74f42d1088cc9ee7ef5f4e8c35eee1b40eafd33ca5b"}, - {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b0bf0effb196ed76b7ad883848143427a73c355ae8e569fa538365064188b8e"}, - {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f9a7c509542db4eceed3dcf21ee5267ab565a83555c9b88a8109dcecc4709002"}, - {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:84b0daf226913133f899ea9b30618722d45feffa67e4fe867b0b5ae83a34060c"}, - {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ec79ff6159dffcc30853b2ad612ed572af86c92b5168aa3fc01a67b0fa40665e"}, - {file = "msgpack-1.0.7-cp311-cp311-win32.whl", hash = "sha256:3e7bf4442b310ff154b7bb9d81eb2c016b7d597e364f97d72b1acc3817a0fdc1"}, - {file = "msgpack-1.0.7-cp311-cp311-win_amd64.whl", hash = "sha256:3f0c8c6dfa6605ab8ff0611995ee30d4f9fcff89966cf562733b4008a3d60d82"}, - {file = "msgpack-1.0.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f0936e08e0003f66bfd97e74ee530427707297b0d0361247e9b4f59ab78ddc8b"}, - {file = "msgpack-1.0.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98bbd754a422a0b123c66a4c341de0474cad4a5c10c164ceed6ea090f3563db4"}, - {file = "msgpack-1.0.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b291f0ee7961a597cbbcc77709374087fa2a9afe7bdb6a40dbbd9b127e79afee"}, - {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebbbba226f0a108a7366bf4b59bf0f30a12fd5e75100c630267d94d7f0ad20e5"}, - {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e2d69948e4132813b8d1131f29f9101bc2c915f26089a6d632001a5c1349672"}, - {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdf38ba2d393c7911ae989c3bbba510ebbcdf4ecbdbfec36272abe350c454075"}, - {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:993584fc821c58d5993521bfdcd31a4adf025c7d745bbd4d12ccfecf695af5ba"}, - {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:52700dc63a4676669b341ba33520f4d6e43d3ca58d422e22ba66d1736b0a6e4c"}, - {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e45ae4927759289c30ccba8d9fdce62bb414977ba158286b5ddaf8df2cddb5c5"}, - {file = "msgpack-1.0.7-cp312-cp312-win32.whl", hash = "sha256:27dcd6f46a21c18fa5e5deed92a43d4554e3df8d8ca5a47bf0615d6a5f39dbc9"}, - {file = "msgpack-1.0.7-cp312-cp312-win_amd64.whl", hash = "sha256:7687e22a31e976a0e7fc99c2f4d11ca45eff652a81eb8c8085e9609298916dcf"}, - {file = "msgpack-1.0.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5b6ccc0c85916998d788b295765ea0e9cb9aac7e4a8ed71d12e7d8ac31c23c95"}, - {file = "msgpack-1.0.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:235a31ec7db685f5c82233bddf9858748b89b8119bf4538d514536c485c15fe0"}, - {file = "msgpack-1.0.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cab3db8bab4b7e635c1c97270d7a4b2a90c070b33cbc00c99ef3f9be03d3e1f7"}, - {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bfdd914e55e0d2c9e1526de210f6fe8ffe9705f2b1dfcc4aecc92a4cb4b533d"}, - {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36e17c4592231a7dbd2ed09027823ab295d2791b3b1efb2aee874b10548b7524"}, - {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38949d30b11ae5f95c3c91917ee7a6b239f5ec276f271f28638dec9156f82cfc"}, - {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ff1d0899f104f3921d94579a5638847f783c9b04f2d5f229392ca77fba5b82fc"}, - {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dc43f1ec66eb8440567186ae2f8c447d91e0372d793dfe8c222aec857b81a8cf"}, - {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dd632777ff3beaaf629f1ab4396caf7ba0bdd075d948a69460d13d44357aca4c"}, - {file = "msgpack-1.0.7-cp38-cp38-win32.whl", hash = "sha256:4e71bc4416de195d6e9b4ee93ad3f2f6b2ce11d042b4d7a7ee00bbe0358bd0c2"}, - {file = "msgpack-1.0.7-cp38-cp38-win_amd64.whl", hash = "sha256:8f5b234f567cf76ee489502ceb7165c2a5cecec081db2b37e35332b537f8157c"}, - {file = "msgpack-1.0.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfef2bb6ef068827bbd021017a107194956918ab43ce4d6dc945ffa13efbc25f"}, - {file = "msgpack-1.0.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:484ae3240666ad34cfa31eea7b8c6cd2f1fdaae21d73ce2974211df099a95d81"}, - {file = "msgpack-1.0.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3967e4ad1aa9da62fd53e346ed17d7b2e922cba5ab93bdd46febcac39be636fc"}, - {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dd178c4c80706546702c59529ffc005681bd6dc2ea234c450661b205445a34d"}, - {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ffbc252eb0d229aeb2f9ad051200668fc3a9aaa8994e49f0cb2ffe2b7867e7"}, - {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:822ea70dc4018c7e6223f13affd1c5c30c0f5c12ac1f96cd8e9949acddb48a61"}, - {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:384d779f0d6f1b110eae74cb0659d9aa6ff35aaf547b3955abf2ab4c901c4819"}, - {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f64e376cd20d3f030190e8c32e1c64582eba56ac6dc7d5b0b49a9d44021b52fd"}, - {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ed82f5a7af3697b1c4786053736f24a0efd0a1b8a130d4c7bfee4b9ded0f08f"}, - {file = "msgpack-1.0.7-cp39-cp39-win32.whl", hash = "sha256:f26a07a6e877c76a88e3cecac8531908d980d3d5067ff69213653649ec0f60ad"}, - {file = "msgpack-1.0.7-cp39-cp39-win_amd64.whl", hash = "sha256:1dc93e8e4653bdb5910aed79f11e165c85732067614f180f70534f056da97db3"}, - {file = "msgpack-1.0.7.tar.gz", hash = "sha256:572efc93db7a4d27e404501975ca6d2d9775705c2d922390d878fcf768d92c87"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653"}, + {file = "msgpack-1.0.8-cp310-cp310-win32.whl", hash = "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693"}, + {file = "msgpack-1.0.8-cp310-cp310-win_amd64.whl", hash = "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce"}, + {file = "msgpack-1.0.8-cp311-cp311-win32.whl", hash = "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305"}, + {file = "msgpack-1.0.8-cp311-cp311-win_amd64.whl", hash = "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543"}, + {file = "msgpack-1.0.8-cp312-cp312-win32.whl", hash = "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c"}, + {file = "msgpack-1.0.8-cp312-cp312-win_amd64.whl", hash = "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a"}, + {file = "msgpack-1.0.8-cp38-cp38-win32.whl", hash = "sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c"}, + {file = "msgpack-1.0.8-cp38-cp38-win_amd64.whl", hash = "sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"}, + {file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"}, + {file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"}, + {file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"}, ] [[package]] @@ -3265,38 +3364,38 @@ files = [ [[package]] name = "mypy" -version = "1.10.0" +version = "1.10.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2"}, - {file = "mypy-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99"}, - {file = "mypy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2"}, - {file = "mypy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9"}, - {file = "mypy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051"}, - {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, - {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, - {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, - {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, - {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, - {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, - {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, - {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, - {file = "mypy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9fd50226364cd2737351c79807775136b0abe084433b55b2e29181a4c3c878c0"}, - {file = "mypy-1.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f90cff89eea89273727d8783fef5d4a934be2fdca11b47def50cf5d311aff727"}, - {file = "mypy-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcfc70599efde5c67862a07a1aaf50e55bce629ace26bb19dc17cece5dd31ca4"}, - {file = "mypy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:075cbf81f3e134eadaf247de187bd604748171d6b79736fa9b6c9685b4083061"}, - {file = "mypy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:3f298531bca95ff615b6e9f2fc0333aae27fa48052903a0ac90215021cdcfa4f"}, - {file = "mypy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976"}, - {file = "mypy-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec"}, - {file = "mypy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821"}, - {file = "mypy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746"}, - {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"}, - {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, - {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, + {file = "mypy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e36f229acfe250dc660790840916eb49726c928e8ce10fbdf90715090fe4ae02"}, + {file = "mypy-1.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:51a46974340baaa4145363b9e051812a2446cf583dfaeba124af966fa44593f7"}, + {file = "mypy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:901c89c2d67bba57aaaca91ccdb659aa3a312de67f23b9dfb059727cce2e2e0a"}, + {file = "mypy-1.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0cd62192a4a32b77ceb31272d9e74d23cd88c8060c34d1d3622db3267679a5d9"}, + {file = "mypy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a2cbc68cb9e943ac0814c13e2452d2046c2f2b23ff0278e26599224cf164e78d"}, + {file = "mypy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a"}, + {file = "mypy-1.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84"}, + {file = "mypy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8edd4e9bbbc9d7b79502eb9592cab808585516ae1bcc1446eb9122656c6066f"}, + {file = "mypy-1.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6166a88b15f1759f94a46fa474c7b1b05d134b1b61fca627dd7335454cc9aa6b"}, + {file = "mypy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bb9cd11c01c8606a9d0b83ffa91d0b236a0e91bc4126d9ba9ce62906ada868e"}, + {file = "mypy-1.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d8681909f7b44d0b7b86e653ca152d6dff0eb5eb41694e163c6092124f8246d7"}, + {file = "mypy-1.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:378c03f53f10bbdd55ca94e46ec3ba255279706a6aacaecac52ad248f98205d3"}, + {file = "mypy-1.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bacf8f3a3d7d849f40ca6caea5c055122efe70e81480c8328ad29c55c69e93e"}, + {file = "mypy-1.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:701b5f71413f1e9855566a34d6e9d12624e9e0a8818a5704d74d6b0402e66c04"}, + {file = "mypy-1.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c4c2992f6ea46ff7fce0072642cfb62af7a2484efe69017ed8b095f7b39ef31"}, + {file = "mypy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:604282c886497645ffb87b8f35a57ec773a4a2721161e709a4422c1636ddde5c"}, + {file = "mypy-1.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37fd87cab83f09842653f08de066ee68f1182b9b5282e4634cdb4b407266bade"}, + {file = "mypy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8addf6313777dbb92e9564c5d32ec122bf2c6c39d683ea64de6a1fd98b90fe37"}, + {file = "mypy-1.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cc3ca0a244eb9a5249c7c583ad9a7e881aa5d7b73c35652296ddcdb33b2b9c7"}, + {file = "mypy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:1b3a2ffce52cc4dbaeee4df762f20a2905aa171ef157b82192f2e2f368eec05d"}, + {file = "mypy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe85ed6836165d52ae8b88f99527d3d1b2362e0cb90b005409b8bed90e9059b3"}, + {file = "mypy-1.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2ae450d60d7d020d67ab440c6e3fae375809988119817214440033f26ddf7bf"}, + {file = "mypy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6be84c06e6abd72f960ba9a71561c14137a583093ffcf9bbfaf5e613d63fa531"}, + {file = "mypy-1.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2189ff1e39db399f08205e22a797383613ce1cb0cb3b13d8bcf0170e45b96cc3"}, + {file = "mypy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:97a131ee36ac37ce9581f4220311247ab6cba896b4395b9c87af0675a13a755f"}, + {file = "mypy-1.10.1-py3-none-any.whl", hash = "sha256:71d8ac0b906354ebda8ef1673e5fde785936ac1f29ff6987c7483cfbd5a4235a"}, + {file = "mypy-1.10.1.tar.gz", hash = "sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0"}, ] [package.dependencies] @@ -3323,13 +3422,13 @@ files = [ [[package]] name = "nbclient" -version = "0.9.0" +version = "0.10.0" description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." optional = false python-versions = ">=3.8.0" files = [ - {file = "nbclient-0.9.0-py3-none-any.whl", hash = "sha256:a3a1ddfb34d4a9d17fc744d655962714a866639acd30130e9be84191cd97cd15"}, - {file = "nbclient-0.9.0.tar.gz", hash = "sha256:4b28c207877cf33ef3a9838cdc7a54c5ceff981194a82eac59d558f05487295e"}, + {file = "nbclient-0.10.0-py3-none-any.whl", hash = "sha256:f13e3529332a1f1f81d82a53210322476a168bb7090a0289c795fe9cc11c9d3f"}, + {file = "nbclient-0.10.0.tar.gz", hash = "sha256:4b3f1b7dba531e498449c4db4f53da339c91d449dc11e9af3a43b4eb5c5abb09"}, ] [package.dependencies] @@ -3341,17 +3440,17 @@ traitlets = ">=5.4" [package.extras] dev = ["pre-commit"] docs = ["autodoc-traits", "mock", "moto", "myst-parser", "nbclient[test]", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling"] -test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] +test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] [[package]] name = "nbconvert" -version = "7.16.1" +version = "7.16.4" description = "Converting Jupyter Notebooks (.ipynb files) to other formats. Output formats include asciidoc, html, latex, markdown, pdf, py, rst, script. nbconvert can be used both as a Python library (`import nbconvert`) or as a command line tool (invoked as `jupyter nbconvert ...`)." optional = false python-versions = ">=3.8" files = [ - {file = "nbconvert-7.16.1-py3-none-any.whl", hash = "sha256:3188727dffadfdc9c6a1c7250729063d7bc78b355ad7aa023138afa030d1cd07"}, - {file = "nbconvert-7.16.1.tar.gz", hash = "sha256:e79e6a074f49ba3ed29428ed86487bf51509d9aab613bd8522ac08f6d28fd7fd"}, + {file = "nbconvert-7.16.4-py3-none-any.whl", hash = "sha256:05873c620fe520b6322bf8a5ad562692343fe3452abda5765c7a34b7d1aa3eb3"}, + {file = "nbconvert-7.16.4.tar.gz", hash = "sha256:86ca91ba266b0a448dc96fa6c5b9d98affabde2867b363258703536807f9f7f4"}, ] [package.dependencies] @@ -3373,29 +3472,29 @@ tinycss2 = "*" traitlets = ">=5.1" [package.extras] -all = ["nbconvert[docs,qtpdf,serve,test,webpdf]"] +all = ["flaky", "ipykernel", "ipython", "ipywidgets (>=7.5)", "myst-parser", "nbsphinx (>=0.2.12)", "playwright", "pydata-sphinx-theme", "pyqtwebengine (>=5.15)", "pytest (>=7)", "sphinx (==5.0.2)", "sphinxcontrib-spelling", "tornado (>=6.1)"] docs = ["ipykernel", "ipython", "myst-parser", "nbsphinx (>=0.2.12)", "pydata-sphinx-theme", "sphinx (==5.0.2)", "sphinxcontrib-spelling"] -qtpdf = ["nbconvert[qtpng]"] +qtpdf = ["pyqtwebengine (>=5.15)"] qtpng = ["pyqtwebengine (>=5.15)"] serve = ["tornado (>=6.1)"] -test = ["flaky", "ipykernel", "ipywidgets (>=7.5)", "pytest"] +test = ["flaky", "ipykernel", "ipywidgets (>=7.5)", "pytest (>=7)"] webpdf = ["playwright"] [[package]] name = "nbformat" -version = "5.9.2" +version = "5.10.4" description = "The Jupyter Notebook format" optional = false python-versions = ">=3.8" files = [ - {file = "nbformat-5.9.2-py3-none-any.whl", hash = "sha256:1c5172d786a41b82bcfd0c23f9e6b6f072e8fb49c39250219e4acfff1efe89e9"}, - {file = "nbformat-5.9.2.tar.gz", hash = "sha256:5f98b5ba1997dff175e77e0c17d5c10a96eaed2cbd1de3533d1fc35d5e111192"}, + {file = "nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b"}, + {file = "nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a"}, ] [package.dependencies] -fastjsonschema = "*" +fastjsonschema = ">=2.15" jsonschema = ">=2.6" -jupyter-core = "*" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" traitlets = ">=5.1" [package.extras] @@ -3404,19 +3503,19 @@ test = ["pep440", "pre-commit", "pytest", "testpath"] [[package]] name = "nbsphinx" -version = "0.9.3" +version = "0.9.4" description = "Jupyter Notebook Tools for Sphinx" optional = false python-versions = ">=3.6" files = [ - {file = "nbsphinx-0.9.3-py3-none-any.whl", hash = "sha256:6e805e9627f4a358bd5720d5cbf8bf48853989c79af557afd91a5f22e163029f"}, - {file = "nbsphinx-0.9.3.tar.gz", hash = "sha256:ec339c8691b688f8676104a367a4b8cf3ea01fd089dc28d24dec22d563b11562"}, + {file = "nbsphinx-0.9.4-py3-none-any.whl", hash = "sha256:22cb1d974a8300e8118ca71aea1f649553743c0c5830a54129dcd446e6a8ba17"}, + {file = "nbsphinx-0.9.4.tar.gz", hash = "sha256:042a60806fc23d519bc5bef59d95570713913fe442fda759d53e3aaf62104794"}, ] [package.dependencies] -docutils = "*" +docutils = ">=0.18.1" jinja2 = "*" -nbconvert = "!=5.4" +nbconvert = ">=5.3,<5.4 || >5.4" nbformat = "*" sphinx = ">=1.8" traitlets = ">=5" @@ -3434,26 +3533,26 @@ files = [ [[package]] name = "notebook" -version = "7.1.1" +version = "7.2.1" description = "Jupyter Notebook - A web-based notebook environment for interactive computing" optional = false python-versions = ">=3.8" files = [ - {file = "notebook-7.1.1-py3-none-any.whl", hash = "sha256:197d8e0595acabf4005851c8716e952a81b405f7aefb648067a761fbde267ce7"}, - {file = "notebook-7.1.1.tar.gz", hash = "sha256:818e7420fa21f402e726afb9f02df7f3c10f294c02e383ed19852866c316108b"}, + {file = "notebook-7.2.1-py3-none-any.whl", hash = "sha256:f45489a3995746f2195a137e0773e2130960b51c9ac3ce257dbc2705aab3a6ca"}, + {file = "notebook-7.2.1.tar.gz", hash = "sha256:4287b6da59740b32173d01d641f763d292f49c30e7a51b89c46ba8473126341e"}, ] [package.dependencies] jupyter-server = ">=2.4.0,<3" -jupyterlab = ">=4.1.1,<4.2" -jupyterlab-server = ">=2.22.1,<3" +jupyterlab = ">=4.2.0,<4.3" +jupyterlab-server = ">=2.27.1,<3" notebook-shim = ">=0.2,<0.3" tornado = ">=6.2.0" [package.extras] dev = ["hatch", "pre-commit"] docs = ["myst-parser", "nbsphinx", "pydata-sphinx-theme", "sphinx (>=1.3.6)", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["importlib-resources (>=5.0)", "ipykernel", "jupyter-server[test] (>=2.4.0,<3)", "jupyterlab-server[test] (>=2.22.1,<3)", "nbval", "pytest (>=7.0)", "pytest-console-scripts", "pytest-timeout", "pytest-tornasync", "requests"] +test = ["importlib-resources (>=5.0)", "ipykernel", "jupyter-server[test] (>=2.4.0,<3)", "jupyterlab-server[test] (>=2.27.1,<3)", "nbval", "pytest (>=7.0)", "pytest-console-scripts", "pytest-timeout", "pytest-tornasync", "requests"] [[package]] name = "notebook-shim" @@ -3736,13 +3835,13 @@ files = [ [[package]] name = "packaging" -version = "23.2" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -3781,8 +3880,8 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.20.3", markers = "python_version < \"3.10\""}, {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, + {version = ">=1.20.3", markers = "python_version < \"3.10\""}, {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" @@ -3825,18 +3924,18 @@ files = [ [[package]] name = "parso" -version = "0.8.3" +version = "0.8.4" description = "A Python Parser" optional = false python-versions = ">=3.6" files = [ - {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, - {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, + {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, + {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, ] [package.extras] -qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["docopt", "pytest (<6.0.0)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["docopt", "pytest"] [[package]] name = "pastel" @@ -3851,18 +3950,18 @@ files = [ [[package]] name = "path" -version = "16.10.0" +version = "16.14.0" description = "A module wrapper for os.path" optional = false python-versions = ">=3.8" files = [ - {file = "path-16.10.0-py3-none-any.whl", hash = "sha256:902afa16e63943c1d6f14d9f74a6603beaa56980807e0234098256fd0ac33fed"}, - {file = "path-16.10.0.tar.gz", hash = "sha256:b32b22b76fe810a8ded6d136268cc8b6698ae7c47c29b94a9ea12623f3051e46"}, + {file = "path-16.14.0-py3-none-any.whl", hash = "sha256:8ee37703cbdc7cc83835ed4ecc6b638226fb2b43b7b45f26b620589981a109a5"}, + {file = "path-16.14.0.tar.gz", hash = "sha256:dbaaa7efd4602fd6ba8d82890dc7823d69e5de740a6e842d9919b0faaf2b6a8e"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["appdirs", "more-itertools", "packaging", "pygments", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "pywin32"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["appdirs", "more-itertools", "packaging", "pygments", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "pywin32"] [[package]] name = "path-py" @@ -3931,79 +4030,80 @@ files = [ [[package]] name = "pillow" -version = "10.2.0" +version = "10.3.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" files = [ - {file = "pillow-10.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e"}, - {file = "pillow-10.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2"}, - {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c"}, - {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0"}, - {file = "pillow-10.2.0-cp310-cp310-win32.whl", hash = "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023"}, - {file = "pillow-10.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72"}, - {file = "pillow-10.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad"}, - {file = "pillow-10.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5"}, - {file = "pillow-10.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311"}, - {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1"}, - {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757"}, - {file = "pillow-10.2.0-cp311-cp311-win32.whl", hash = "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068"}, - {file = "pillow-10.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56"}, - {file = "pillow-10.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1"}, - {file = "pillow-10.2.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef"}, - {file = "pillow-10.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04"}, - {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f"}, - {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb"}, - {file = "pillow-10.2.0-cp312-cp312-win32.whl", hash = "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f"}, - {file = "pillow-10.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9"}, - {file = "pillow-10.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48"}, - {file = "pillow-10.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9"}, - {file = "pillow-10.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d"}, - {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6"}, - {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe"}, - {file = "pillow-10.2.0-cp38-cp38-win32.whl", hash = "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e"}, - {file = "pillow-10.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39"}, - {file = "pillow-10.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67"}, - {file = "pillow-10.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13"}, - {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7"}, - {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591"}, - {file = "pillow-10.2.0-cp39-cp39-win32.whl", hash = "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516"}, - {file = "pillow-10.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8"}, - {file = "pillow-10.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6"}, - {file = "pillow-10.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868"}, - {file = "pillow-10.2.0.tar.gz", hash = "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e"}, + {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"}, + {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"}, + {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"}, + {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"}, + {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"}, + {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"}, + {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"}, + {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"}, + {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"}, + {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"}, + {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"}, + {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"}, + {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"}, + {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"}, + {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"}, + {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"}, + {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"}, + {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"}, + {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"}, + {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"}, + {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"}, + {file = "pillow-10.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b"}, + {file = "pillow-10.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd"}, + {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d"}, + {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3"}, + {file = "pillow-10.3.0-cp38-cp38-win32.whl", hash = "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b"}, + {file = "pillow-10.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999"}, + {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"}, + {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"}, + {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"}, + {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"}, + {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"}, + {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"}, + {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"}, + {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, ] [package.extras] @@ -4016,17 +4116,17 @@ xmp = ["defusedxml"] [[package]] name = "pkginfo" -version = "1.9.6" +version = "1.11.1" description = "Query metadata from sdists / bdists / installed packages." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "pkginfo-1.9.6-py3-none-any.whl", hash = "sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546"}, - {file = "pkginfo-1.9.6.tar.gz", hash = "sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046"}, + {file = "pkginfo-1.11.1-py3-none-any.whl", hash = "sha256:bfa76a714fdfc18a045fcd684dbfc3816b603d9d075febef17cb6582bea29573"}, + {file = "pkginfo-1.11.1.tar.gz", hash = "sha256:2e0dca1cf4c8e39644eed32408ea9966ee15e0d324c62ba899a393b3c6b467aa"}, ] [package.extras] -testing = ["pytest", "pytest-cov"] +testing = ["pytest", "pytest-cov", "wheel"] [[package]] name = "pkgutil-resolve-name" @@ -4041,18 +4141,19 @@ files = [ [[package]] name = "platformdirs" -version = "4.2.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "4.2.2" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, - {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, ] [package.extras] docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +type = ["mypy (>=1.8)"] [[package]] name = "pluggy" @@ -4071,13 +4172,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "poethepoet" -version = "0.26.1" +version = "0.27.0" description = "A task runner that works well with poetry." optional = false python-versions = ">=3.8" files = [ - {file = "poethepoet-0.26.1-py3-none-any.whl", hash = "sha256:aa43b443fec5d17d7e76771cccd484e5285805301721a74f059c483ad3276edd"}, - {file = "poethepoet-0.26.1.tar.gz", hash = "sha256:aaad8541f6072617a60bcff2562d00779b58b353bd0f1847b06d8d0f2b6dc192"}, + {file = "poethepoet-0.27.0-py3-none-any.whl", hash = "sha256:0032d980a623b96e26dc7450ae200b0998be523f27d297d799b97510fe252a24"}, + {file = "poethepoet-0.27.0.tar.gz", hash = "sha256:907ab4dc1bc6326be5a3b10d2aa39d1acc0ca12024317d9506fbe9c0cdc912c9"}, ] [package.dependencies] @@ -4090,13 +4191,13 @@ poetry-plugin = ["poetry (>=1.0,<2.0)"] [[package]] name = "poetry" -version = "1.8.1" +version = "1.8.3" description = "Python dependency management and packaging made easy." optional = false -python-versions = ">=3.8,<4.0" +python-versions = "<4.0,>=3.8" files = [ - {file = "poetry-1.8.1-py3-none-any.whl", hash = "sha256:cf133946661025822672422769567980f8e489ed5b6fc170d1025a4d6c9aac29"}, - {file = "poetry-1.8.1.tar.gz", hash = "sha256:23519cc45eb3cf48e899145bc762425a141e3afd52ecc53ec443ca635122327f"}, + {file = "poetry-1.8.3-py3-none-any.whl", hash = "sha256:88191c69b08d06f9db671b793d68f40048e8904c0718404b63dcc2b5aec62d13"}, + {file = "poetry-1.8.3.tar.gz", hash = "sha256:67f4eb68288eab41e841cc71a00d26cf6bdda9533022d0189a145a34d0a35f48"}, ] [package.dependencies] @@ -4111,7 +4212,7 @@ installer = ">=0.7.0,<0.8.0" keyring = ">=24.0.0,<25.0.0" packaging = ">=23.1" pexpect = ">=4.7.0,<5.0.0" -pkginfo = ">=1.9.4,<2.0.0" +pkginfo = ">=1.10,<2.0" platformdirs = ">=3.0.0,<5" poetry-core = "1.9.0" poetry-plugin-export = ">=1.6.0,<2.0.0" @@ -4138,18 +4239,18 @@ files = [ [[package]] name = "poetry-plugin-export" -version = "1.6.0" +version = "1.8.0" description = "Poetry plugin to export the dependencies to various formats" optional = false -python-versions = ">=3.8,<4.0" +python-versions = "<4.0,>=3.8" files = [ - {file = "poetry_plugin_export-1.6.0-py3-none-any.whl", hash = "sha256:2dce6204c9318f1f6509a11a03921fb3f461b201840b59f1c237b6ab454dabcf"}, - {file = "poetry_plugin_export-1.6.0.tar.gz", hash = "sha256:091939434984267a91abf2f916a26b00cff4eee8da63ec2a24ba4b17cf969a59"}, + {file = "poetry_plugin_export-1.8.0-py3-none-any.whl", hash = "sha256:adbe232cfa0cc04991ea3680c865cf748bff27593b9abcb1f35fb50ed7ba2c22"}, + {file = "poetry_plugin_export-1.8.0.tar.gz", hash = "sha256:1fa6168a85d59395d835ca564bc19862a7c76061e60c3e7dfaec70d50937fc61"}, ] [package.dependencies] -poetry = ">=1.6.0,<2.0.0" -poetry-core = ">=1.7.0,<2.0.0" +poetry = ">=1.8.0,<3.0.0" +poetry-core = ">=1.7.0,<3.0.0" [[package]] name = "prometheus-client" @@ -4167,13 +4268,13 @@ twisted = ["twisted"] [[package]] name = "prompt-toolkit" -version = "3.0.43" +version = "3.0.47" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, - {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, + {file = "prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10"}, + {file = "prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360"}, ] [package.dependencies] @@ -4201,27 +4302,28 @@ files = [ [[package]] name = "psutil" -version = "5.9.8" +version = "6.0.0" description = "Cross-platform lib for process and system monitoring in Python." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, - {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, - {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, - {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, - {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, - {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, - {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, - {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, - {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, - {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, - {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, - {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, - {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, - {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, - {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, - {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, + {file = "psutil-6.0.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6"}, + {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0"}, + {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a9a3dbfb4de4f18174528d87cc352d1f788b7496991cca33c6996f40c9e3c92c"}, + {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6ec7588fb3ddaec7344a825afe298db83fe01bfaaab39155fa84cf1c0d6b13c3"}, + {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e7c870afcb7d91fdea2b37c24aeb08f98b6d67257a5cb0a8bc3ac68d0f1a68c"}, + {file = "psutil-6.0.0-cp27-none-win32.whl", hash = "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35"}, + {file = "psutil-6.0.0-cp27-none-win_amd64.whl", hash = "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1"}, + {file = "psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0"}, + {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0"}, + {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd"}, + {file = "psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132"}, + {file = "psutil-6.0.0-cp36-cp36m-win32.whl", hash = "sha256:fc8c9510cde0146432bbdb433322861ee8c3efbf8589865c8bf8d21cb30c4d14"}, + {file = "psutil-6.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:34859b8d8f423b86e4385ff3665d3f4d94be3cdf48221fbe476e883514fdb71c"}, + {file = "psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d"}, + {file = "psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3"}, + {file = "psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0"}, + {file = "psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2"}, ] [package.extras] @@ -4264,61 +4366,61 @@ files = [ [[package]] name = "pyarrow" -version = "15.0.0" +version = "16.1.0" description = "Python library for Apache Arrow" optional = false python-versions = ">=3.8" files = [ - {file = "pyarrow-15.0.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:0a524532fd6dd482edaa563b686d754c70417c2f72742a8c990b322d4c03a15d"}, - {file = "pyarrow-15.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:60a6bdb314affa9c2e0d5dddf3d9cbb9ef4a8dddaa68669975287d47ece67642"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66958fd1771a4d4b754cd385835e66a3ef6b12611e001d4e5edfcef5f30391e2"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f500956a49aadd907eaa21d4fff75f73954605eaa41f61cb94fb008cf2e00c6"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6f87d9c4f09e049c2cade559643424da84c43a35068f2a1c4653dc5b1408a929"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:85239b9f93278e130d86c0e6bb455dcb66fc3fd891398b9d45ace8799a871a1e"}, - {file = "pyarrow-15.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:5b8d43e31ca16aa6e12402fcb1e14352d0d809de70edd185c7650fe80e0769e3"}, - {file = "pyarrow-15.0.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:fa7cd198280dbd0c988df525e50e35b5d16873e2cdae2aaaa6363cdb64e3eec5"}, - {file = "pyarrow-15.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8780b1a29d3c8b21ba6b191305a2a607de2e30dab399776ff0aa09131e266340"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0ec198ccc680f6c92723fadcb97b74f07c45ff3fdec9dd765deb04955ccf19"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036a7209c235588c2f07477fe75c07e6caced9b7b61bb897c8d4e52c4b5f9555"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2bd8a0e5296797faf9a3294e9fa2dc67aa7f10ae2207920dbebb785c77e9dbe5"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e8ebed6053dbe76883a822d4e8da36860f479d55a762bd9e70d8494aed87113e"}, - {file = "pyarrow-15.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:17d53a9d1b2b5bd7d5e4cd84d018e2a45bc9baaa68f7e6e3ebed45649900ba99"}, - {file = "pyarrow-15.0.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:9950a9c9df24090d3d558b43b97753b8f5867fb8e521f29876aa021c52fda351"}, - {file = "pyarrow-15.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:003d680b5e422d0204e7287bb3fa775b332b3fce2996aa69e9adea23f5c8f970"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f75fce89dad10c95f4bf590b765e3ae98bcc5ba9f6ce75adb828a334e26a3d40"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca9cb0039923bec49b4fe23803807e4ef39576a2bec59c32b11296464623dc2"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:9ed5a78ed29d171d0acc26a305a4b7f83c122d54ff5270810ac23c75813585e4"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6eda9e117f0402dfcd3cd6ec9bfee89ac5071c48fc83a84f3075b60efa96747f"}, - {file = "pyarrow-15.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:9a3a6180c0e8f2727e6f1b1c87c72d3254cac909e609f35f22532e4115461177"}, - {file = "pyarrow-15.0.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:19a8918045993349b207de72d4576af0191beef03ea655d8bdb13762f0cd6eac"}, - {file = "pyarrow-15.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0ec076b32bacb6666e8813a22e6e5a7ef1314c8069d4ff345efa6246bc38593"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5db1769e5d0a77eb92344c7382d6543bea1164cca3704f84aa44e26c67e320fb"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2617e3bf9df2a00020dd1c1c6dce5cc343d979efe10bc401c0632b0eef6ef5b"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:d31c1d45060180131caf10f0f698e3a782db333a422038bf7fe01dace18b3a31"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:c8c287d1d479de8269398b34282e206844abb3208224dbdd7166d580804674b7"}, - {file = "pyarrow-15.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:07eb7f07dc9ecbb8dace0f58f009d3a29ee58682fcdc91337dfeb51ea618a75b"}, - {file = "pyarrow-15.0.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:47af7036f64fce990bb8a5948c04722e4e3ea3e13b1007ef52dfe0aa8f23cf7f"}, - {file = "pyarrow-15.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93768ccfff85cf044c418bfeeafce9a8bb0cee091bd8fd19011aff91e58de540"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6ee87fd6892700960d90abb7b17a72a5abb3b64ee0fe8db6c782bcc2d0dc0b4"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:001fca027738c5f6be0b7a3159cc7ba16a5c52486db18160909a0831b063c4e4"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:d1c48648f64aec09accf44140dccb92f4f94394b8d79976c426a5b79b11d4fa7"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:972a0141be402bb18e3201448c8ae62958c9c7923dfaa3b3d4530c835ac81aed"}, - {file = "pyarrow-15.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:f01fc5cf49081426429127aa2d427d9d98e1cb94a32cb961d583a70b7c4504e6"}, - {file = "pyarrow-15.0.0.tar.gz", hash = "sha256:876858f549d540898f927eba4ef77cd549ad8d24baa3207cf1b72e5788b50e83"}, -] - -[package.dependencies] -numpy = ">=1.16.6,<2" + {file = "pyarrow-16.1.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:17e23b9a65a70cc733d8b738baa6ad3722298fa0c81d88f63ff94bf25eaa77b9"}, + {file = "pyarrow-16.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4740cc41e2ba5d641071d0ab5e9ef9b5e6e8c7611351a5cb7c1d175eaf43674a"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98100e0268d04e0eec47b73f20b39c45b4006f3c4233719c3848aa27a03c1aef"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68f409e7b283c085f2da014f9ef81e885d90dcd733bd648cfba3ef265961848"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:a8914cd176f448e09746037b0c6b3a9d7688cef451ec5735094055116857580c"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:48be160782c0556156d91adbdd5a4a7e719f8d407cb46ae3bb4eaee09b3111bd"}, + {file = "pyarrow-16.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:9cf389d444b0f41d9fe1444b70650fea31e9d52cfcb5f818b7888b91b586efff"}, + {file = "pyarrow-16.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:d0ebea336b535b37eee9eee31761813086d33ed06de9ab6fc6aaa0bace7b250c"}, + {file = "pyarrow-16.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e73cfc4a99e796727919c5541c65bb88b973377501e39b9842ea71401ca6c1c"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf9251264247ecfe93e5f5a0cd43b8ae834f1e61d1abca22da55b20c788417f6"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddf5aace92d520d3d2a20031d8b0ec27b4395cab9f74e07cc95edf42a5cc0147"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:25233642583bf658f629eb230b9bb79d9af4d9f9229890b3c878699c82f7d11e"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a33a64576fddfbec0a44112eaf844c20853647ca833e9a647bfae0582b2ff94b"}, + {file = "pyarrow-16.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:185d121b50836379fe012753cf15c4ba9638bda9645183ab36246923875f8d1b"}, + {file = "pyarrow-16.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:2e51ca1d6ed7f2e9d5c3c83decf27b0d17bb207a7dea986e8dc3e24f80ff7d6f"}, + {file = "pyarrow-16.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06ebccb6f8cb7357de85f60d5da50e83507954af617d7b05f48af1621d331c9a"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b04707f1979815f5e49824ce52d1dceb46e2f12909a48a6a753fe7cafbc44a0c"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d32000693deff8dc5df444b032b5985a48592c0697cb6e3071a5d59888714e2"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8785bb10d5d6fd5e15d718ee1d1f914fe768bf8b4d1e5e9bf253de8a26cb1628"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e1369af39587b794873b8a307cc6623a3b1194e69399af0efd05bb202195a5a7"}, + {file = "pyarrow-16.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:febde33305f1498f6df85e8020bca496d0e9ebf2093bab9e0f65e2b4ae2b3444"}, + {file = "pyarrow-16.1.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b5f5705ab977947a43ac83b52ade3b881eb6e95fcc02d76f501d549a210ba77f"}, + {file = "pyarrow-16.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0d27bf89dfc2576f6206e9cd6cf7a107c9c06dc13d53bbc25b0bd4556f19cf5f"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d07de3ee730647a600037bc1d7b7994067ed64d0eba797ac74b2bc77384f4c2"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbef391b63f708e103df99fbaa3acf9f671d77a183a07546ba2f2c297b361e83"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:19741c4dbbbc986d38856ee7ddfdd6a00fc3b0fc2d928795b95410d38bb97d15"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f2c5fb249caa17b94e2b9278b36a05ce03d3180e6da0c4c3b3ce5b2788f30eed"}, + {file = "pyarrow-16.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:e6b6d3cd35fbb93b70ade1336022cc1147b95ec6af7d36906ca7fe432eb09710"}, + {file = "pyarrow-16.1.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:18da9b76a36a954665ccca8aa6bd9f46c1145f79c0bb8f4f244f5f8e799bca55"}, + {file = "pyarrow-16.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:99f7549779b6e434467d2aa43ab2b7224dd9e41bdde486020bae198978c9e05e"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f07fdffe4fd5b15f5ec15c8b64584868d063bc22b86b46c9695624ca3505b7b4"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddfe389a08ea374972bd4065d5f25d14e36b43ebc22fc75f7b951f24378bf0b5"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3b20bd67c94b3a2ea0a749d2a5712fc845a69cb5d52e78e6449bbd295611f3aa"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:ba8ac20693c0bb0bf4b238751d4409e62852004a8cf031c73b0e0962b03e45e3"}, + {file = "pyarrow-16.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:31a1851751433d89a986616015841977e0a188662fcffd1a5677453f1df2de0a"}, + {file = "pyarrow-16.1.0.tar.gz", hash = "sha256:15fbb22ea96d11f0b5768504a3f961edab25eaf4197c341720c4a387f6c60315"}, +] + +[package.dependencies] +numpy = ">=1.16.6" [[package]] name = "pyasn1" -version = "0.5.1" +version = "0.6.0" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.8" files = [ - {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, - {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, + {file = "pyasn1-0.6.0-py2.py3-none-any.whl", hash = "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473"}, + {file = "pyasn1-0.6.0.tar.gz", hash = "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c"}, ] [[package]] @@ -4334,29 +4436,29 @@ files = [ [[package]] name = "pycparser" -version = "2.21" +version = "2.22" description = "C parser in Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.8" files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] [[package]] name = "pydantic" -version = "2.7.0" +version = "2.7.4" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.7.0-py3-none-any.whl", hash = "sha256:9dee74a271705f14f9a1567671d144a851c675b072736f0a7b2608fd9e495352"}, - {file = "pydantic-2.7.0.tar.gz", hash = "sha256:b5ecdd42262ca2462e2624793551e80911a1e989f462910bb81aef974b4bb383"}, + {file = "pydantic-2.7.4-py3-none-any.whl", hash = "sha256:ee8538d41ccb9c0a9ad3e0e5f07bf15ed8015b481ced539a1759d8cc89ae90d0"}, + {file = "pydantic-2.7.4.tar.gz", hash = "sha256:0c84efd9548d545f63ac0060c1e4d39bb9b14db8b3c0652338aecc07b5adec52"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.18.1" +pydantic-core = "2.18.4" typing-extensions = ">=4.6.1" [package.extras] @@ -4364,90 +4466,90 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.18.1" +version = "2.18.4" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ee9cf33e7fe14243f5ca6977658eb7d1042caaa66847daacbd2117adb258b226"}, - {file = "pydantic_core-2.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b7bbb97d82659ac8b37450c60ff2e9f97e4eb0f8a8a3645a5568b9334b08b50"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df4249b579e75094f7e9bb4bd28231acf55e308bf686b952f43100a5a0be394c"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d0491006a6ad20507aec2be72e7831a42efc93193d2402018007ff827dc62926"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ae80f72bb7a3e397ab37b53a2b49c62cc5496412e71bc4f1277620a7ce3f52b"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58aca931bef83217fca7a390e0486ae327c4af9c3e941adb75f8772f8eeb03a1"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be91ad664fc9245404a789d60cba1e91c26b1454ba136d2a1bf0c2ac0c0505a"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:667880321e916a8920ef49f5d50e7983792cf59f3b6079f3c9dac2b88a311d17"}, - {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f7054fdc556f5421f01e39cbb767d5ec5c1139ea98c3e5b350e02e62201740c7"}, - {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:030e4f9516f9947f38179249778709a460a3adb516bf39b5eb9066fcfe43d0e6"}, - {file = "pydantic_core-2.18.1-cp310-none-win32.whl", hash = "sha256:2e91711e36e229978d92642bfc3546333a9127ecebb3f2761372e096395fc649"}, - {file = "pydantic_core-2.18.1-cp310-none-win_amd64.whl", hash = "sha256:9a29726f91c6cb390b3c2338f0df5cd3e216ad7a938762d11c994bb37552edb0"}, - {file = "pydantic_core-2.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9ece8a49696669d483d206b4474c367852c44815fca23ac4e48b72b339807f80"}, - {file = "pydantic_core-2.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a5d83efc109ceddb99abd2c1316298ced2adb4570410defe766851a804fcd5b"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f7973c381283783cd1043a8c8f61ea5ce7a3a58b0369f0ee0ee975eaf2f2a1b"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54c7375c62190a7845091f521add19b0f026bcf6ae674bdb89f296972272e86d"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd63cec4e26e790b70544ae5cc48d11b515b09e05fdd5eff12e3195f54b8a586"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:561cf62c8a3498406495cfc49eee086ed2bb186d08bcc65812b75fda42c38294"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68717c38a68e37af87c4da20e08f3e27d7e4212e99e96c3d875fbf3f4812abfc"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d5728e93d28a3c63ee513d9ffbac9c5989de8c76e049dbcb5bfe4b923a9739d"}, - {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f0f17814c505f07806e22b28856c59ac80cee7dd0fbb152aed273e116378f519"}, - {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d816f44a51ba5175394bc6c7879ca0bd2be560b2c9e9f3411ef3a4cbe644c2e9"}, - {file = "pydantic_core-2.18.1-cp311-none-win32.whl", hash = "sha256:09f03dfc0ef8c22622eaa8608caa4a1e189cfb83ce847045eca34f690895eccb"}, - {file = "pydantic_core-2.18.1-cp311-none-win_amd64.whl", hash = "sha256:27f1009dc292f3b7ca77feb3571c537276b9aad5dd4efb471ac88a8bd09024e9"}, - {file = "pydantic_core-2.18.1-cp311-none-win_arm64.whl", hash = "sha256:48dd883db92e92519201f2b01cafa881e5f7125666141a49ffba8b9facc072b0"}, - {file = "pydantic_core-2.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b6b0e4912030c6f28bcb72b9ebe4989d6dc2eebcd2a9cdc35fefc38052dd4fe8"}, - {file = "pydantic_core-2.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3202a429fe825b699c57892d4371c74cc3456d8d71b7f35d6028c96dfecad31"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3982b0a32d0a88b3907e4b0dc36809fda477f0757c59a505d4e9b455f384b8b"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25595ac311f20e5324d1941909b0d12933f1fd2171075fcff763e90f43e92a0d"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14fe73881cf8e4cbdaded8ca0aa671635b597e42447fec7060d0868b52d074e6"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca976884ce34070799e4dfc6fbd68cb1d181db1eefe4a3a94798ddfb34b8867f"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684d840d2c9ec5de9cb397fcb3f36d5ebb6fa0d94734f9886032dd796c1ead06"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:54764c083bbe0264f0f746cefcded6cb08fbbaaf1ad1d78fb8a4c30cff999a90"}, - {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:201713f2f462e5c015b343e86e68bd8a530a4f76609b33d8f0ec65d2b921712a"}, - {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fd1a9edb9dd9d79fbeac1ea1f9a8dd527a6113b18d2e9bcc0d541d308dae639b"}, - {file = "pydantic_core-2.18.1-cp312-none-win32.whl", hash = "sha256:d5e6b7155b8197b329dc787356cfd2684c9d6a6b1a197f6bbf45f5555a98d411"}, - {file = "pydantic_core-2.18.1-cp312-none-win_amd64.whl", hash = "sha256:9376d83d686ec62e8b19c0ac3bf8d28d8a5981d0df290196fb6ef24d8a26f0d6"}, - {file = "pydantic_core-2.18.1-cp312-none-win_arm64.whl", hash = "sha256:c562b49c96906b4029b5685075fe1ebd3b5cc2601dfa0b9e16c2c09d6cbce048"}, - {file = "pydantic_core-2.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:3e352f0191d99fe617371096845070dee295444979efb8f27ad941227de6ad09"}, - {file = "pydantic_core-2.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0295d52b012cbe0d3059b1dba99159c3be55e632aae1999ab74ae2bd86a33d7"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56823a92075780582d1ffd4489a2e61d56fd3ebb4b40b713d63f96dd92d28144"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd3f79e17b56741b5177bcc36307750d50ea0698df6aa82f69c7db32d968c1c2"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38a5024de321d672a132b1834a66eeb7931959c59964b777e8f32dbe9523f6b1"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ce426ee691319d4767748c8e0895cfc56593d725594e415f274059bcf3cb76"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2adaeea59849ec0939af5c5d476935f2bab4b7f0335b0110f0f069a41024278e"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9b6431559676a1079eac0f52d6d0721fb8e3c5ba43c37bc537c8c83724031feb"}, - {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:85233abb44bc18d16e72dc05bf13848a36f363f83757541f1a97db2f8d58cfd9"}, - {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:641a018af4fe48be57a2b3d7a1f0f5dbca07c1d00951d3d7463f0ac9dac66622"}, - {file = "pydantic_core-2.18.1-cp38-none-win32.whl", hash = "sha256:63d7523cd95d2fde0d28dc42968ac731b5bb1e516cc56b93a50ab293f4daeaad"}, - {file = "pydantic_core-2.18.1-cp38-none-win_amd64.whl", hash = "sha256:907a4d7720abfcb1c81619863efd47c8a85d26a257a2dbebdb87c3b847df0278"}, - {file = "pydantic_core-2.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:aad17e462f42ddbef5984d70c40bfc4146c322a2da79715932cd8976317054de"}, - {file = "pydantic_core-2.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:94b9769ba435b598b547c762184bcfc4783d0d4c7771b04a3b45775c3589ca44"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80e0e57cc704a52fb1b48f16d5b2c8818da087dbee6f98d9bf19546930dc64b5"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:76b86e24039c35280ceee6dce7e62945eb93a5175d43689ba98360ab31eebc4a"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a05db5013ec0ca4a32cc6433f53faa2a014ec364031408540ba858c2172bb0"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:250ae39445cb5475e483a36b1061af1bc233de3e9ad0f4f76a71b66231b07f88"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a32204489259786a923e02990249c65b0f17235073149d0033efcebe80095570"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6395a4435fa26519fd96fdccb77e9d00ddae9dd6c742309bd0b5610609ad7fb2"}, - {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2533ad2883f001efa72f3d0e733fb846710c3af6dcdd544fe5bf14fa5fe2d7db"}, - {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b560b72ed4816aee52783c66854d96157fd8175631f01ef58e894cc57c84f0f6"}, - {file = "pydantic_core-2.18.1-cp39-none-win32.whl", hash = "sha256:582cf2cead97c9e382a7f4d3b744cf0ef1a6e815e44d3aa81af3ad98762f5a9b"}, - {file = "pydantic_core-2.18.1-cp39-none-win_amd64.whl", hash = "sha256:ca71d501629d1fa50ea7fa3b08ba884fe10cefc559f5c6c8dfe9036c16e8ae89"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e178e5b66a06ec5bf51668ec0d4ac8cfb2bdcb553b2c207d58148340efd00143"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:72722ce529a76a4637a60be18bd789d8fb871e84472490ed7ddff62d5fed620d"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fe0c1ce5b129455e43f941f7a46f61f3d3861e571f2905d55cdbb8b5c6f5e2c"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4284c621f06a72ce2cb55f74ea3150113d926a6eb78ab38340c08f770eb9b4d"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a0c3e718f4e064efde68092d9d974e39572c14e56726ecfaeebbe6544521f47"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2027493cc44c23b598cfaf200936110433d9caa84e2c6cf487a83999638a96ac"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:76909849d1a6bffa5a07742294f3fa1d357dc917cb1fe7b470afbc3a7579d539"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ee7ccc7fb7e921d767f853b47814c3048c7de536663e82fbc37f5eb0d532224b"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ee2794111c188548a4547eccc73a6a8527fe2af6cf25e1a4ebda2fd01cdd2e60"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a139fe9f298dc097349fb4f28c8b81cc7a202dbfba66af0e14be5cfca4ef7ce5"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d074b07a10c391fc5bbdcb37b2f16f20fcd9e51e10d01652ab298c0d07908ee2"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c69567ddbac186e8c0aadc1f324a60a564cfe25e43ef2ce81bcc4b8c3abffbae"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:baf1c7b78cddb5af00971ad5294a4583188bda1495b13760d9f03c9483bb6203"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2684a94fdfd1b146ff10689c6e4e815f6a01141781c493b97342cdc5b06f4d5d"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:73c1bc8a86a5c9e8721a088df234265317692d0b5cd9e86e975ce3bc3db62a59"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e60defc3c15defb70bb38dd605ff7e0fae5f6c9c7cbfe0ad7868582cb7e844a6"}, - {file = "pydantic_core-2.18.1.tar.gz", hash = "sha256:de9d3e8717560eb05e28739d1b35e4eac2e458553a52a301e51352a7ffc86a35"}, + {file = "pydantic_core-2.18.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4"}, + {file = "pydantic_core-2.18.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb"}, + {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c"}, + {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e"}, + {file = "pydantic_core-2.18.4-cp310-none-win32.whl", hash = "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc"}, + {file = "pydantic_core-2.18.4-cp310-none-win_amd64.whl", hash = "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0"}, + {file = "pydantic_core-2.18.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d"}, + {file = "pydantic_core-2.18.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951"}, + {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2"}, + {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9"}, + {file = "pydantic_core-2.18.4-cp311-none-win32.whl", hash = "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558"}, + {file = "pydantic_core-2.18.4-cp311-none-win_amd64.whl", hash = "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b"}, + {file = "pydantic_core-2.18.4-cp311-none-win_arm64.whl", hash = "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805"}, + {file = "pydantic_core-2.18.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2"}, + {file = "pydantic_core-2.18.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9"}, + {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c"}, + {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8"}, + {file = "pydantic_core-2.18.4-cp312-none-win32.whl", hash = "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07"}, + {file = "pydantic_core-2.18.4-cp312-none-win_amd64.whl", hash = "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a"}, + {file = "pydantic_core-2.18.4-cp312-none-win_arm64.whl", hash = "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f"}, + {file = "pydantic_core-2.18.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2"}, + {file = "pydantic_core-2.18.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057"}, + {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b"}, + {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af"}, + {file = "pydantic_core-2.18.4-cp38-none-win32.whl", hash = "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2"}, + {file = "pydantic_core-2.18.4-cp38-none-win_amd64.whl", hash = "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443"}, + {file = "pydantic_core-2.18.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528"}, + {file = "pydantic_core-2.18.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23"}, + {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b"}, + {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a"}, + {file = "pydantic_core-2.18.4-cp39-none-win32.whl", hash = "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d"}, + {file = "pydantic_core-2.18.4-cp39-none-win_amd64.whl", hash = "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9"}, + {file = "pydantic_core-2.18.4.tar.gz", hash = "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864"}, ] [package.dependencies] @@ -4482,13 +4584,13 @@ test = ["pytest", "pytest-cov", "pytest-regressions"] [[package]] name = "pydeck" -version = "0.8.0" +version = "0.9.1" description = "Widget for deck.gl maps" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydeck-0.8.0-py2.py3-none-any.whl", hash = "sha256:a8fa7757c6f24bba033af39db3147cb020eef44012ba7e60d954de187f9ed4d5"}, - {file = "pydeck-0.8.0.tar.gz", hash = "sha256:07edde833f7cfcef6749124351195aa7dcd24663d4909fd7898dbd0b6fbc01ec"}, + {file = "pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038"}, + {file = "pydeck-0.9.1.tar.gz", hash = "sha256:f74475ae637951d63f2ee58326757f8d4f9cd9f2a457cf42950715003e2cb605"}, ] [package.dependencies] @@ -4512,116 +4614,84 @@ files = [ [[package]] name = "pygments" -version = "2.17.2" +version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, - {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, ] [package.extras] -plugins = ["importlib-metadata"] windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pymongo" -version = "4.6.2" +version = "4.8.0" description = "Python driver for MongoDB " optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pymongo-4.6.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7640d176ee5b0afec76a1bda3684995cb731b2af7fcfd7c7ef8dc271c5d689af"}, - {file = "pymongo-4.6.2-cp310-cp310-manylinux1_i686.whl", hash = "sha256:4e2129ec8f72806751b621470ac5d26aaa18fae4194796621508fa0e6068278a"}, - {file = "pymongo-4.6.2-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:c43205e85cbcbdf03cff62ad8f50426dd9d20134a915cfb626d805bab89a1844"}, - {file = "pymongo-4.6.2-cp310-cp310-manylinux2014_i686.whl", hash = "sha256:91ddf95cedca12f115fbc5f442b841e81197d85aa3cc30b82aee3635a5208af2"}, - {file = "pymongo-4.6.2-cp310-cp310-manylinux2014_ppc64le.whl", hash = "sha256:0fbdbf2fba1b4f5f1522e9f11e21c306e095b59a83340a69e908f8ed9b450070"}, - {file = "pymongo-4.6.2-cp310-cp310-manylinux2014_s390x.whl", hash = "sha256:097791d5a8d44e2444e0c8c4d6e14570ac11e22bcb833808885a5db081c3dc2a"}, - {file = "pymongo-4.6.2-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:e0b208ebec3b47ee78a5c836e2e885e8c1e10f8ffd101aaec3d63997a4bdcd04"}, - {file = "pymongo-4.6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1849fd6f1917b4dc5dbf744b2f18e41e0538d08dd8e9ba9efa811c5149d665a3"}, - {file = "pymongo-4.6.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa0bbbfbd1f8ebbd5facaa10f9f333b20027b240af012748555148943616fdf3"}, - {file = "pymongo-4.6.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4522ad69a4ab0e1b46a8367d62ad3865b8cd54cf77518c157631dac1fdc97584"}, - {file = "pymongo-4.6.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397949a9cc85e4a1452f80b7f7f2175d557237177120954eff00bf79553e89d3"}, - {file = "pymongo-4.6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d511db310f43222bc58d811037b176b4b88dc2b4617478c5ef01fea404f8601"}, - {file = "pymongo-4.6.2-cp310-cp310-win32.whl", hash = "sha256:991e406db5da4d89fb220a94d8caaf974ffe14ce6b095957bae9273c609784a0"}, - {file = "pymongo-4.6.2-cp310-cp310-win_amd64.whl", hash = "sha256:94637941fe343000f728e28d3fe04f1f52aec6376b67b85583026ff8dab2a0e0"}, - {file = "pymongo-4.6.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:84593447a5c5fe7a59ba86b72c2c89d813fbac71c07757acdf162fbfd5d005b9"}, - {file = "pymongo-4.6.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9aebddb2ec2128d5fc2fe3aee6319afef8697e0374f8a1fcca3449d6f625e7b4"}, - {file = "pymongo-4.6.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f706c1a644ed33eaea91df0a8fb687ce572b53eeb4ff9b89270cb0247e5d0e1"}, - {file = "pymongo-4.6.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18c422e6b08fa370ed9d8670c67e78d01f50d6517cec4522aa8627014dfa38b6"}, - {file = "pymongo-4.6.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d002ae456a15b1d790a78bb84f87af21af1cb716a63efb2c446ab6bcbbc48ca"}, - {file = "pymongo-4.6.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f86ba0c781b497a3c9c886765d7b6402a0e3ae079dd517365044c89cd7abb06"}, - {file = "pymongo-4.6.2-cp311-cp311-win32.whl", hash = "sha256:ac20dd0c7b42555837c86f5ea46505f35af20a08b9cf5770cd1834288d8bd1b4"}, - {file = "pymongo-4.6.2-cp311-cp311-win_amd64.whl", hash = "sha256:e78af59fd0eb262c2a5f7c7d7e3b95e8596a75480d31087ca5f02f2d4c6acd19"}, - {file = "pymongo-4.6.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:6125f73503407792c8b3f80165f8ab88a4e448d7d9234c762681a4d0b446fcb4"}, - {file = "pymongo-4.6.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba052446a14bd714ec83ca4e77d0d97904f33cd046d7bb60712a6be25eb31dbb"}, - {file = "pymongo-4.6.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b65433c90e07dc252b4a55dfd885ca0df94b1cf77c5b8709953ec1983aadc03"}, - {file = "pymongo-4.6.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2160d9c8cd20ce1f76a893f0daf7c0d38af093f36f1b5c9f3dcf3e08f7142814"}, - {file = "pymongo-4.6.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f251f287e6d42daa3654b686ce1fcb6d74bf13b3907c3ae25954978c70f2cd4"}, - {file = "pymongo-4.6.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d7d227a60b00925dd3aeae4675575af89c661a8e89a1f7d1677e57eba4a3693c"}, - {file = "pymongo-4.6.2-cp312-cp312-win32.whl", hash = "sha256:311794ef3ccae374aaef95792c36b0e5c06e8d5cf04a1bdb1b2bf14619ac881f"}, - {file = "pymongo-4.6.2-cp312-cp312-win_amd64.whl", hash = "sha256:f673b64a0884edcc56073bda0b363428dc1bf4eb1b5e7d0b689f7ec6173edad6"}, - {file = "pymongo-4.6.2-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:fe010154dfa9e428bd2fb3e9325eff2216ab20a69ccbd6b5cac6785ca2989161"}, - {file = "pymongo-4.6.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:1f5f4cd2969197e25b67e24d5b8aa2452d381861d2791d06c493eaa0b9c9fcfe"}, - {file = "pymongo-4.6.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c9519c9d341983f3a1bd19628fecb1d72a48d8666cf344549879f2e63f54463b"}, - {file = "pymongo-4.6.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:c68bf4a399e37798f1b5aa4f6c02886188ef465f4ac0b305a607b7579413e366"}, - {file = "pymongo-4.6.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:a509db602462eb736666989739215b4b7d8f4bb8ac31d0bffd4be9eae96c63ef"}, - {file = "pymongo-4.6.2-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:362a5adf6f3f938a8ff220a4c4aaa93e84ef932a409abecd837c617d17a5990f"}, - {file = "pymongo-4.6.2-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:ee30a9d4c27a88042d0636aca0275788af09cc237ae365cd6ebb34524bddb9cc"}, - {file = "pymongo-4.6.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:477914e13501bb1d4608339ee5bb618be056d2d0e7267727623516cfa902e652"}, - {file = "pymongo-4.6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd343ca44982d480f1e39372c48e8e263fc6f32e9af2be456298f146a3db715"}, - {file = "pymongo-4.6.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3797e0a628534e07a36544d2bfa69e251a578c6d013e975e9e3ed2ac41f2d95"}, - {file = "pymongo-4.6.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97d81d357e1a2a248b3494d52ebc8bf15d223ee89d59ee63becc434e07438a24"}, - {file = "pymongo-4.6.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed694c0d1977cb54281cb808bc2b247c17fb64b678a6352d3b77eb678ebe1bd9"}, - {file = "pymongo-4.6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ceaaff4b812ae368cf9774989dea81b9bbb71e5bed666feca6a9f3087c03e49"}, - {file = "pymongo-4.6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7dd63f7c2b3727541f7f37d0fb78d9942eb12a866180fbeb898714420aad74e2"}, - {file = "pymongo-4.6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e571434633f99a81e081738721bb38e697345281ed2f79c2f290f809ba3fbb2f"}, - {file = "pymongo-4.6.2-cp37-cp37m-win32.whl", hash = "sha256:3e9f6e2f3da0a6af854a3e959a6962b5f8b43bbb8113cd0bff0421c5059b3106"}, - {file = "pymongo-4.6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:3a5280f496297537301e78bde250c96fadf4945e7b2c397d8bb8921861dd236d"}, - {file = "pymongo-4.6.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:5f6bcd2d012d82d25191a911a239fd05a8a72e8c5a7d81d056c0f3520cad14d1"}, - {file = "pymongo-4.6.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4fa30494601a6271a8b416554bd7cde7b2a848230f0ec03e3f08d84565b4bf8c"}, - {file = "pymongo-4.6.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:bea62f03a50f363265a7a651b4e2a4429b4f138c1864b2d83d4bf6f9851994be"}, - {file = "pymongo-4.6.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:b2d445f1cf147331947cc35ec10342f898329f29dd1947a3f8aeaf7e0e6878d1"}, - {file = "pymongo-4.6.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:5db133d6ec7a4f7fc7e2bd098e4df23d7ad949f7be47b27b515c9fb9301c61e4"}, - {file = "pymongo-4.6.2-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:9eec7140cf7513aa770ea51505d312000c7416626a828de24318fdcc9ac3214c"}, - {file = "pymongo-4.6.2-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:5379ca6fd325387a34cda440aec2bd031b5ef0b0aa2e23b4981945cff1dab84c"}, - {file = "pymongo-4.6.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:579508536113dbd4c56e4738955a18847e8a6c41bf3c0b4ab18b51d81a6b7be8"}, - {file = "pymongo-4.6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3bae553ca39ed52db099d76acd5e8566096064dc7614c34c9359bb239ec4081"}, - {file = "pymongo-4.6.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0257e0eebb50f242ca28a92ef195889a6ad03dcdde5bf1c7ab9f38b7e810801"}, - {file = "pymongo-4.6.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbafe3a1df21eeadb003c38fc02c1abf567648b6477ec50c4a3c042dca205371"}, - {file = "pymongo-4.6.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaecfafb407feb6f562c7f2f5b91f22bfacba6dd739116b1912788cff7124c4a"}, - {file = "pymongo-4.6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e942945e9112075a84d2e2d6e0d0c98833cdcdfe48eb8952b917f996025c7ffa"}, - {file = "pymongo-4.6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2f7b98f8d2cf3eeebde738d080ae9b4276d7250912d9751046a9ac1efc9b1ce2"}, - {file = "pymongo-4.6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8110b78fc4b37dced85081d56795ecbee6a7937966e918e05e33a3900e8ea07d"}, - {file = "pymongo-4.6.2-cp38-cp38-win32.whl", hash = "sha256:df813f0c2c02281720ccce225edf39dc37855bf72cdfde6f789a1d1cf32ffb4b"}, - {file = "pymongo-4.6.2-cp38-cp38-win_amd64.whl", hash = "sha256:64ec3e2dcab9af61bdbfcb1dd863c70d1b0c220b8e8ac11df8b57f80ee0402b3"}, - {file = "pymongo-4.6.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bff601fbfcecd2166d9a2b70777c2985cb9689e2befb3278d91f7f93a0456cae"}, - {file = "pymongo-4.6.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:f1febca6f79e91feafc572906871805bd9c271b6a2d98a8bb5499b6ace0befed"}, - {file = "pymongo-4.6.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d788cb5cc947d78934be26eef1623c78cec3729dc93a30c23f049b361aa6d835"}, - {file = "pymongo-4.6.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5c2f258489de12a65b81e1b803a531ee8cf633fa416ae84de65cd5f82d2ceb37"}, - {file = "pymongo-4.6.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:fb24abcd50501b25d33a074c1790a1389b6460d2509e4b240d03fd2e5c79f463"}, - {file = "pymongo-4.6.2-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:4d982c6db1da7cf3018183891883660ad085de97f21490d314385373f775915b"}, - {file = "pymongo-4.6.2-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:b2dd8c874927a27995f64a3b44c890e8a944c98dec1ba79eab50e07f1e3f801b"}, - {file = "pymongo-4.6.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:4993593de44c741d1e9f230f221fe623179f500765f9855936e4ff6f33571bad"}, - {file = "pymongo-4.6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:658f6c028edaeb02761ebcaca8d44d519c22594b2a51dcbc9bd2432aa93319e3"}, - {file = "pymongo-4.6.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68109c13176749fbbbbbdb94dd4a58dcc604db6ea43ee300b2602154aebdd55f"}, - {file = "pymongo-4.6.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:707d28a822b918acf941cff590affaddb42a5d640614d71367c8956623a80cbc"}, - {file = "pymongo-4.6.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f251db26c239aec2a4d57fbe869e0a27b7f6b5384ec6bf54aeb4a6a5e7408234"}, - {file = "pymongo-4.6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57c05f2e310701fc17ae358caafd99b1830014e316f0242d13ab6c01db0ab1c2"}, - {file = "pymongo-4.6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b575fbe6396bbf21e4d0e5fd2e3cdb656dc90c930b6c5532192e9a89814f72d"}, - {file = "pymongo-4.6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ca5877754f3fa6e4fe5aacf5c404575f04c2d9efc8d22ed39576ed9098d555c8"}, - {file = "pymongo-4.6.2-cp39-cp39-win32.whl", hash = "sha256:8caa73fb19070008e851a589b744aaa38edd1366e2487284c61158c77fdf72af"}, - {file = "pymongo-4.6.2-cp39-cp39-win_amd64.whl", hash = "sha256:3e03c732cb64b96849310e1d8688fb70d75e2571385485bf2f1e7ad1d309fa53"}, - {file = "pymongo-4.6.2.tar.gz", hash = "sha256:ab7d01ac832a1663dad592ccbd92bb0f0775bc8f98a1923c5e1a7d7fead495af"}, + {file = "pymongo-4.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f2b7bec27e047e84947fbd41c782f07c54c30c76d14f3b8bf0c89f7413fac67a"}, + {file = "pymongo-4.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c68fe128a171493018ca5c8020fc08675be130d012b7ab3efe9e22698c612a1"}, + {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:920d4f8f157a71b3cb3f39bc09ce070693d6e9648fb0e30d00e2657d1dca4e49"}, + {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52b4108ac9469febba18cea50db972605cc43978bedaa9fea413378877560ef8"}, + {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:180d5eb1dc28b62853e2f88017775c4500b07548ed28c0bd9c005c3d7bc52526"}, + {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aec2b9088cdbceb87e6ca9c639d0ff9b9d083594dda5ca5d3c4f6774f4c81b33"}, + {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0cf61450feadca81deb1a1489cb1a3ae1e4266efd51adafecec0e503a8dcd84"}, + {file = "pymongo-4.8.0-cp310-cp310-win32.whl", hash = "sha256:8b18c8324809539c79bd6544d00e0607e98ff833ca21953df001510ca25915d1"}, + {file = "pymongo-4.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e5df28f74002e37bcbdfdc5109799f670e4dfef0fb527c391ff84f078050e7b5"}, + {file = "pymongo-4.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6b50040d9767197b77ed420ada29b3bf18a638f9552d80f2da817b7c4a4c9c68"}, + {file = "pymongo-4.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:417369ce39af2b7c2a9c7152c1ed2393edfd1cbaf2a356ba31eb8bcbd5c98dd7"}, + {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf821bd3befb993a6db17229a2c60c1550e957de02a6ff4dd0af9476637b2e4d"}, + {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9365166aa801c63dff1a3cb96e650be270da06e3464ab106727223123405510f"}, + {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc8b8582f4209c2459b04b049ac03c72c618e011d3caa5391ff86d1bda0cc486"}, + {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e5019f75f6827bb5354b6fef8dfc9d6c7446894a27346e03134d290eb9e758"}, + {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b5802151fc2b51cd45492c80ed22b441d20090fb76d1fd53cd7760b340ff554"}, + {file = "pymongo-4.8.0-cp311-cp311-win32.whl", hash = "sha256:4bf58e6825b93da63e499d1a58de7de563c31e575908d4e24876234ccb910eba"}, + {file = "pymongo-4.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:b747c0e257b9d3e6495a018309b9e0c93b7f0d65271d1d62e572747f4ffafc88"}, + {file = "pymongo-4.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e6a720a3d22b54183352dc65f08cd1547204d263e0651b213a0a2e577e838526"}, + {file = "pymongo-4.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:31e4d21201bdf15064cf47ce7b74722d3e1aea2597c6785882244a3bb58c7eab"}, + {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6b804bb4f2d9dc389cc9e827d579fa327272cdb0629a99bfe5b83cb3e269ebf"}, + {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f2fbdb87fe5075c8beb17a5c16348a1ea3c8b282a5cb72d173330be2fecf22f5"}, + {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd39455b7ee70aabee46f7399b32ab38b86b236c069ae559e22be6b46b2bbfc4"}, + {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:940d456774b17814bac5ea7fc28188c7a1338d4a233efbb6ba01de957bded2e8"}, + {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:236bbd7d0aef62e64caf4b24ca200f8c8670d1a6f5ea828c39eccdae423bc2b2"}, + {file = "pymongo-4.8.0-cp312-cp312-win32.whl", hash = "sha256:47ec8c3f0a7b2212dbc9be08d3bf17bc89abd211901093e3ef3f2adea7de7a69"}, + {file = "pymongo-4.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:e84bc7707492f06fbc37a9f215374d2977d21b72e10a67f1b31893ec5a140ad8"}, + {file = "pymongo-4.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:519d1bab2b5e5218c64340b57d555d89c3f6c9d717cecbf826fb9d42415e7750"}, + {file = "pymongo-4.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:87075a1feb1e602e539bdb1ef8f4324a3427eb0d64208c3182e677d2c0718b6f"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f53429515d2b3e86dcc83dadecf7ff881e538c168d575f3688698a8707b80a"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fdc20cd1e1141b04696ffcdb7c71e8a4a665db31fe72e51ec706b3bdd2d09f36"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:284d0717d1a7707744018b0b6ee7801b1b1ff044c42f7be7a01bb013de639470"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5bf0eb8b6ef40fa22479f09375468c33bebb7fe49d14d9c96c8fd50355188b0"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ecd71b9226bd1d49416dc9f999772038e56f415a713be51bf18d8676a0841c8"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0061af6e8c5e68b13f1ec9ad5251247726653c5af3c0bbdfbca6cf931e99216"}, + {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:658d0170f27984e0d89c09fe5c42296613b711a3ffd847eb373b0dbb5b648d5f"}, + {file = "pymongo-4.8.0-cp38-cp38-win32.whl", hash = "sha256:3ed1c316718a2836f7efc3d75b4b0ffdd47894090bc697de8385acd13c513a70"}, + {file = "pymongo-4.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:7148419eedfea9ecb940961cfe465efaba90595568a1fb97585fb535ea63fe2b"}, + {file = "pymongo-4.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8400587d594761e5136a3423111f499574be5fd53cf0aefa0d0f05b180710b0"}, + {file = "pymongo-4.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af3e98dd9702b73e4e6fd780f6925352237f5dce8d99405ff1543f3771201704"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de3a860f037bb51f968de320baef85090ff0bbb42ec4f28ec6a5ddf88be61871"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0fc18b3a093f3db008c5fea0e980dbd3b743449eee29b5718bc2dc15ab5088bb"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18c9d8f975dd7194c37193583fd7d1eb9aea0c21ee58955ecf35362239ff31ac"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:408b2f8fdbeca3c19e4156f28fff1ab11c3efb0407b60687162d49f68075e63c"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6564780cafd6abeea49759fe661792bd5a67e4f51bca62b88faab497ab5fe89"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d18d86bc9e103f4d3d4f18b85a0471c0e13ce5b79194e4a0389a224bb70edd53"}, + {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9097c331577cecf8034422956daaba7ec74c26f7b255d718c584faddd7fa2e3c"}, + {file = "pymongo-4.8.0-cp39-cp39-win32.whl", hash = "sha256:d5428dbcd43d02f6306e1c3c95f692f68b284e6ee5390292242f509004c9e3a8"}, + {file = "pymongo-4.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:ef7225755ed27bfdb18730c68f6cb023d06c28f2b734597480fb4c0e500feb6f"}, + {file = "pymongo-4.8.0.tar.gz", hash = "sha256:454f2295875744dc70f1881e4b2eb99cdad008a33574bc8aaf120530f66c0cde"}, ] [package.dependencies] dnspython = ">=1.16.0,<3.0.0" [package.extras] -aws = ["pymongo-auth-aws (<2.0.0)"] -encryption = ["certifi", "pymongo[aws]", "pymongocrypt (>=1.6.0,<2.0.0)"] +aws = ["pymongo-auth-aws (>=1.1.0,<2.0.0)"] +docs = ["furo (==2023.9.10)", "readthedocs-sphinx-search (>=0.3,<1.0)", "sphinx (>=5.3,<8)", "sphinx-rtd-theme (>=2,<3)", "sphinxcontrib-shellcheck (>=1,<2)"] +encryption = ["certifi", "pymongo-auth-aws (>=1.1.0,<2.0.0)", "pymongocrypt (>=1.6.0,<2.0.0)"] gssapi = ["pykerberos", "winkerberos (>=0.5.0)"] ocsp = ["certifi", "cryptography (>=2.5)", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] snappy = ["python-snappy"] @@ -4641,44 +4711,15 @@ files = [ [[package]] name = "pyproject-hooks" -version = "1.0.0" +version = "1.1.0" description = "Wrappers to call pyproject.toml-based build backend hooks." optional = false python-versions = ">=3.7" files = [ - {file = "pyproject_hooks-1.0.0-py3-none-any.whl", hash = "sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8"}, - {file = "pyproject_hooks-1.0.0.tar.gz", hash = "sha256:f271b298b97f5955d53fb12b72c1fb1948c22c1a6b70b315c54cedaca0264ef5"}, + {file = "pyproject_hooks-1.1.0-py3-none-any.whl", hash = "sha256:7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2"}, + {file = "pyproject_hooks-1.1.0.tar.gz", hash = "sha256:4b37730834edbd6bd37f26ece6b44802fb1c1ee2ece0e54ddff8bfc06db86965"}, ] -[package.dependencies] -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} - -[[package]] -name = "pytelegrambotapi" -version = "4.19.2" -description = "Python Telegram bot api." -optional = true -python-versions = ">=3.8" -files = [ - {file = "pytelegrambotapi-4.19.2-py3-none-any.whl", hash = "sha256:c2c87807523dc3eb3a3f73f2c9a037e34612e89019d0ce04ae81351c740757ff"}, - {file = "pytelegrambotapi-4.19.2.tar.gz", hash = "sha256:39481e607c76b217606052f3e542322a53eada212914090a46d565a47729711d"}, -] - -[package.dependencies] -requests = "*" - -[package.extras] -aiohttp = ["aiohttp"] -aioredis = ["aioredis"] -coloredlogs = ["coloredlogs"] -fastapi = ["fastapi"] -json = ["ujson"] -pil = ["pillow"] -psutil = ["psutil"] -redis = ["redis (>=3.4.1)"] -uvicorn = ["uvicorn"] -watchdog = ["watchdog"] - [[package]] name = "pytest" version = "8.2.2" @@ -4703,13 +4744,13 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments [[package]] name = "pytest-asyncio" -version = "0.23.5" +version = "0.23.7" description = "Pytest support for asyncio" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-asyncio-0.23.5.tar.gz", hash = "sha256:3a048872a9c4ba14c3e90cc1aa20cbc2def7d01c7c8db3777ec281ba9c057675"}, - {file = "pytest_asyncio-0.23.5-py3-none-any.whl", hash = "sha256:4e7093259ba018d58ede7d5315131d21923a60f8a6e9ee266ce1589685c89eac"}, + {file = "pytest_asyncio-0.23.7-py3-none-any.whl", hash = "sha256:009b48127fbe44518a547bddd25611551b0e43ccdbf1e67d12479f569832c20b"}, + {file = "pytest_asyncio-0.23.7.tar.gz", hash = "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268"}, ] [package.dependencies] @@ -4799,13 +4840,13 @@ tests = ["mock"] [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -4871,6 +4912,41 @@ typing-extensions = "*" [package.extras] test = ["pytest"] +[[package]] +name = "python-telegram-bot" +version = "21.3" +description = "We have made you a wrapper you can't refuse" +optional = true +python-versions = ">=3.8" +files = [ + {file = "python-telegram-bot-21.3.tar.gz", hash = "sha256:1be3c8b6f2b7354418109daa3f23c522e82ed22e7fc904346bee0c7b4aab52ae"}, + {file = "python_telegram_bot-21.3-py3-none-any.whl", hash = "sha256:8f575e6da903edd1e78967b5b481455ee6b27f2804d2384029177eab165f2e93"}, +] + +[package.dependencies] +aiolimiter = {version = ">=1.1.0,<1.2.0", optional = true, markers = "extra == \"all\""} +APScheduler = {version = ">=3.10.4,<3.11.0", optional = true, markers = "extra == \"all\""} +cachetools = {version = ">=5.3.3,<5.4.0", optional = true, markers = "extra == \"all\""} +cryptography = {version = ">=39.0.1", optional = true, markers = "extra == \"all\""} +httpx = [ + {version = ">=0.27,<1.0"}, + {version = "*", extras = ["socks"], optional = true, markers = "extra == \"all\""}, + {version = "*", extras = ["http2"], optional = true, markers = "extra == \"all\""}, +] +pytz = {version = ">=2018.6", optional = true, markers = "extra == \"all\""} +tornado = {version = ">=6.4,<7.0", optional = true, markers = "extra == \"all\""} + +[package.extras] +all = ["APScheduler (>=3.10.4,<3.11.0)", "aiolimiter (>=1.1.0,<1.2.0)", "cachetools (>=5.3.3,<5.4.0)", "cryptography (>=39.0.1)", "httpx[http2]", "httpx[socks]", "pytz (>=2018.6)", "tornado (>=6.4,<7.0)"] +callback-data = ["cachetools (>=5.3.3,<5.4.0)"] +ext = ["APScheduler (>=3.10.4,<3.11.0)", "aiolimiter (>=1.1.0,<1.2.0)", "cachetools (>=5.3.3,<5.4.0)", "pytz (>=2018.6)", "tornado (>=6.4,<7.0)"] +http2 = ["httpx[http2]"] +job-queue = ["APScheduler (>=3.10.4,<3.11.0)", "pytz (>=2018.6)"] +passport = ["cryptography (>=39.0.1)"] +rate-limiter = ["aiolimiter (>=1.1.0,<1.2.0)"] +socks = ["httpx[socks]"] +webhooks = ["tornado (>=6.4,<7.0)"] + [[package]] name = "pytz" version = "2024.1" @@ -4993,104 +5069,99 @@ files = [ [[package]] name = "pyzmq" -version = "25.1.2" +version = "26.0.3" description = "Python bindings for 0MQ" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "pyzmq-25.1.2-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:e624c789359f1a16f83f35e2c705d07663ff2b4d4479bad35621178d8f0f6ea4"}, - {file = "pyzmq-25.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:49151b0efece79f6a79d41a461d78535356136ee70084a1c22532fc6383f4ad0"}, - {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9a5f194cf730f2b24d6af1f833c14c10f41023da46a7f736f48b6d35061e76e"}, - {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:faf79a302f834d9e8304fafdc11d0d042266667ac45209afa57e5efc998e3872"}, - {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f51a7b4ead28d3fca8dda53216314a553b0f7a91ee8fc46a72b402a78c3e43d"}, - {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:0ddd6d71d4ef17ba5a87becf7ddf01b371eaba553c603477679ae817a8d84d75"}, - {file = "pyzmq-25.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:246747b88917e4867e2367b005fc8eefbb4a54b7db363d6c92f89d69abfff4b6"}, - {file = "pyzmq-25.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:00c48ae2fd81e2a50c3485de1b9d5c7c57cd85dc8ec55683eac16846e57ac979"}, - {file = "pyzmq-25.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5a68d491fc20762b630e5db2191dd07ff89834086740f70e978bb2ef2668be08"}, - {file = "pyzmq-25.1.2-cp310-cp310-win32.whl", hash = "sha256:09dfe949e83087da88c4a76767df04b22304a682d6154de2c572625c62ad6886"}, - {file = "pyzmq-25.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:fa99973d2ed20417744fca0073390ad65ce225b546febb0580358e36aa90dba6"}, - {file = "pyzmq-25.1.2-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:82544e0e2d0c1811482d37eef297020a040c32e0687c1f6fc23a75b75db8062c"}, - {file = "pyzmq-25.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:01171fc48542348cd1a360a4b6c3e7d8f46cdcf53a8d40f84db6707a6768acc1"}, - {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc69c96735ab501419c432110016329bf0dea8898ce16fab97c6d9106dc0b348"}, - {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e124e6b1dd3dfbeb695435dff0e383256655bb18082e094a8dd1f6293114642"}, - {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7598d2ba821caa37a0f9d54c25164a4fa351ce019d64d0b44b45540950458840"}, - {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d1299d7e964c13607efd148ca1f07dcbf27c3ab9e125d1d0ae1d580a1682399d"}, - {file = "pyzmq-25.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4e6f689880d5ad87918430957297c975203a082d9a036cc426648fcbedae769b"}, - {file = "pyzmq-25.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cc69949484171cc961e6ecd4a8911b9ce7a0d1f738fcae717177c231bf77437b"}, - {file = "pyzmq-25.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9880078f683466b7f567b8624bfc16cad65077be046b6e8abb53bed4eeb82dd3"}, - {file = "pyzmq-25.1.2-cp311-cp311-win32.whl", hash = "sha256:4e5837af3e5aaa99a091302df5ee001149baff06ad22b722d34e30df5f0d9097"}, - {file = "pyzmq-25.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:25c2dbb97d38b5ac9fd15586e048ec5eb1e38f3d47fe7d92167b0c77bb3584e9"}, - {file = "pyzmq-25.1.2-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:11e70516688190e9c2db14fcf93c04192b02d457b582a1f6190b154691b4c93a"}, - {file = "pyzmq-25.1.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:313c3794d650d1fccaaab2df942af9f2c01d6217c846177cfcbc693c7410839e"}, - {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b3cbba2f47062b85fe0ef9de5b987612140a9ba3a9c6d2543c6dec9f7c2ab27"}, - {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc31baa0c32a2ca660784d5af3b9487e13b61b3032cb01a115fce6588e1bed30"}, - {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02c9087b109070c5ab0b383079fa1b5f797f8d43e9a66c07a4b8b8bdecfd88ee"}, - {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:f8429b17cbb746c3e043cb986328da023657e79d5ed258b711c06a70c2ea7537"}, - {file = "pyzmq-25.1.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5074adeacede5f810b7ef39607ee59d94e948b4fd954495bdb072f8c54558181"}, - {file = "pyzmq-25.1.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7ae8f354b895cbd85212da245f1a5ad8159e7840e37d78b476bb4f4c3f32a9fe"}, - {file = "pyzmq-25.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b264bf2cc96b5bc43ce0e852be995e400376bd87ceb363822e2cb1964fcdc737"}, - {file = "pyzmq-25.1.2-cp312-cp312-win32.whl", hash = "sha256:02bbc1a87b76e04fd780b45e7f695471ae6de747769e540da909173d50ff8e2d"}, - {file = "pyzmq-25.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:ced111c2e81506abd1dc142e6cd7b68dd53747b3b7ae5edbea4578c5eeff96b7"}, - {file = "pyzmq-25.1.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7b6d09a8962a91151f0976008eb7b29b433a560fde056ec7a3db9ec8f1075438"}, - {file = "pyzmq-25.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:967668420f36878a3c9ecb5ab33c9d0ff8d054f9c0233d995a6d25b0e95e1b6b"}, - {file = "pyzmq-25.1.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5edac3f57c7ddaacdb4d40f6ef2f9e299471fc38d112f4bc6d60ab9365445fb0"}, - {file = "pyzmq-25.1.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0dabfb10ef897f3b7e101cacba1437bd3a5032ee667b7ead32bbcdd1a8422fe7"}, - {file = "pyzmq-25.1.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:2c6441e0398c2baacfe5ba30c937d274cfc2dc5b55e82e3749e333aabffde561"}, - {file = "pyzmq-25.1.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:16b726c1f6c2e7625706549f9dbe9b06004dfbec30dbed4bf50cbdfc73e5b32a"}, - {file = "pyzmq-25.1.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:a86c2dd76ef71a773e70551a07318b8e52379f58dafa7ae1e0a4be78efd1ff16"}, - {file = "pyzmq-25.1.2-cp36-cp36m-win32.whl", hash = "sha256:359f7f74b5d3c65dae137f33eb2bcfa7ad9ebefd1cab85c935f063f1dbb245cc"}, - {file = "pyzmq-25.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:55875492f820d0eb3417b51d96fea549cde77893ae3790fd25491c5754ea2f68"}, - {file = "pyzmq-25.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b8c8a419dfb02e91b453615c69568442e897aaf77561ee0064d789705ff37a92"}, - {file = "pyzmq-25.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8807c87fa893527ae8a524c15fc505d9950d5e856f03dae5921b5e9aa3b8783b"}, - {file = "pyzmq-25.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5e319ed7d6b8f5fad9b76daa0a68497bc6f129858ad956331a5835785761e003"}, - {file = "pyzmq-25.1.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3c53687dde4d9d473c587ae80cc328e5b102b517447456184b485587ebd18b62"}, - {file = "pyzmq-25.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9add2e5b33d2cd765ad96d5eb734a5e795a0755f7fc49aa04f76d7ddda73fd70"}, - {file = "pyzmq-25.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e690145a8c0c273c28d3b89d6fb32c45e0d9605b2293c10e650265bf5c11cfec"}, - {file = "pyzmq-25.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:00a06faa7165634f0cac1abb27e54d7a0b3b44eb9994530b8ec73cf52e15353b"}, - {file = "pyzmq-25.1.2-cp37-cp37m-win32.whl", hash = "sha256:0f97bc2f1f13cb16905a5f3e1fbdf100e712d841482b2237484360f8bc4cb3d7"}, - {file = "pyzmq-25.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6cc0020b74b2e410287e5942e1e10886ff81ac77789eb20bec13f7ae681f0fdd"}, - {file = "pyzmq-25.1.2-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:bef02cfcbded83473bdd86dd8d3729cd82b2e569b75844fb4ea08fee3c26ae41"}, - {file = "pyzmq-25.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e10a4b5a4b1192d74853cc71a5e9fd022594573926c2a3a4802020360aa719d8"}, - {file = "pyzmq-25.1.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8c5f80e578427d4695adac6fdf4370c14a2feafdc8cb35549c219b90652536ae"}, - {file = "pyzmq-25.1.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5dde6751e857910c1339890f3524de74007958557593b9e7e8c5f01cd919f8a7"}, - {file = "pyzmq-25.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea1608dd169da230a0ad602d5b1ebd39807ac96cae1845c3ceed39af08a5c6df"}, - {file = "pyzmq-25.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0f513130c4c361201da9bc69df25a086487250e16b5571ead521b31ff6b02220"}, - {file = "pyzmq-25.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:019744b99da30330798bb37df33549d59d380c78e516e3bab9c9b84f87a9592f"}, - {file = "pyzmq-25.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2e2713ef44be5d52dd8b8e2023d706bf66cb22072e97fc71b168e01d25192755"}, - {file = "pyzmq-25.1.2-cp38-cp38-win32.whl", hash = "sha256:07cd61a20a535524906595e09344505a9bd46f1da7a07e504b315d41cd42eb07"}, - {file = "pyzmq-25.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb7e49a17fb8c77d3119d41a4523e432eb0c6932187c37deb6fbb00cc3028088"}, - {file = "pyzmq-25.1.2-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:94504ff66f278ab4b7e03e4cba7e7e400cb73bfa9d3d71f58d8972a8dc67e7a6"}, - {file = "pyzmq-25.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6dd0d50bbf9dca1d0bdea219ae6b40f713a3fb477c06ca3714f208fd69e16fd8"}, - {file = "pyzmq-25.1.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:004ff469d21e86f0ef0369717351073e0e577428e514c47c8480770d5e24a565"}, - {file = "pyzmq-25.1.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c0b5ca88a8928147b7b1e2dfa09f3b6c256bc1135a1338536cbc9ea13d3b7add"}, - {file = "pyzmq-25.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c9a79f1d2495b167119d02be7448bfba57fad2a4207c4f68abc0bab4b92925b"}, - {file = "pyzmq-25.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:518efd91c3d8ac9f9b4f7dd0e2b7b8bf1a4fe82a308009016b07eaa48681af82"}, - {file = "pyzmq-25.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1ec23bd7b3a893ae676d0e54ad47d18064e6c5ae1fadc2f195143fb27373f7f6"}, - {file = "pyzmq-25.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db36c27baed588a5a8346b971477b718fdc66cf5b80cbfbd914b4d6d355e44e2"}, - {file = "pyzmq-25.1.2-cp39-cp39-win32.whl", hash = "sha256:39b1067f13aba39d794a24761e385e2eddc26295826530a8c7b6c6c341584289"}, - {file = "pyzmq-25.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:8e9f3fabc445d0ce320ea2c59a75fe3ea591fdbdeebec5db6de530dd4b09412e"}, - {file = "pyzmq-25.1.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a8c1d566344aee826b74e472e16edae0a02e2a044f14f7c24e123002dcff1c05"}, - {file = "pyzmq-25.1.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:759cfd391a0996345ba94b6a5110fca9c557ad4166d86a6e81ea526c376a01e8"}, - {file = "pyzmq-25.1.2-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c61e346ac34b74028ede1c6b4bcecf649d69b707b3ff9dc0fab453821b04d1e"}, - {file = "pyzmq-25.1.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cb8fc1f8d69b411b8ec0b5f1ffbcaf14c1db95b6bccea21d83610987435f1a4"}, - {file = "pyzmq-25.1.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3c00c9b7d1ca8165c610437ca0c92e7b5607b2f9076f4eb4b095c85d6e680a1d"}, - {file = "pyzmq-25.1.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:df0c7a16ebb94452d2909b9a7b3337940e9a87a824c4fc1c7c36bb4404cb0cde"}, - {file = "pyzmq-25.1.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:45999e7f7ed5c390f2e87ece7f6c56bf979fb213550229e711e45ecc7d42ccb8"}, - {file = "pyzmq-25.1.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ac170e9e048b40c605358667aca3d94e98f604a18c44bdb4c102e67070f3ac9b"}, - {file = "pyzmq-25.1.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1b604734bec94f05f81b360a272fc824334267426ae9905ff32dc2be433ab96"}, - {file = "pyzmq-25.1.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:a793ac733e3d895d96f865f1806f160696422554e46d30105807fdc9841b9f7d"}, - {file = "pyzmq-25.1.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0806175f2ae5ad4b835ecd87f5f85583316b69f17e97786f7443baaf54b9bb98"}, - {file = "pyzmq-25.1.2-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ef12e259e7bc317c7597d4f6ef59b97b913e162d83b421dd0db3d6410f17a244"}, - {file = "pyzmq-25.1.2-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea253b368eb41116011add00f8d5726762320b1bda892f744c91997b65754d73"}, - {file = "pyzmq-25.1.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b9b1f2ad6498445a941d9a4fee096d387fee436e45cc660e72e768d3d8ee611"}, - {file = "pyzmq-25.1.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:8b14c75979ce932c53b79976a395cb2a8cd3aaf14aef75e8c2cb55a330b9b49d"}, - {file = "pyzmq-25.1.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:889370d5174a741a62566c003ee8ddba4b04c3f09a97b8000092b7ca83ec9c49"}, - {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a18fff090441a40ffda8a7f4f18f03dc56ae73f148f1832e109f9bffa85df15"}, - {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99a6b36f95c98839ad98f8c553d8507644c880cf1e0a57fe5e3a3f3969040882"}, - {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4345c9a27f4310afbb9c01750e9461ff33d6fb74cd2456b107525bbeebcb5be3"}, - {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3516e0b6224cf6e43e341d56da15fd33bdc37fa0c06af4f029f7d7dfceceabbc"}, - {file = "pyzmq-25.1.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:146b9b1f29ead41255387fb07be56dc29639262c0f7344f570eecdcd8d683314"}, - {file = "pyzmq-25.1.2.tar.gz", hash = "sha256:93f1aa311e8bb912e34f004cf186407a4e90eec4f0ecc0efd26056bf7eda0226"}, + {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:44dd6fc3034f1eaa72ece33588867df9e006a7303725a12d64c3dff92330f625"}, + {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:acb704195a71ac5ea5ecf2811c9ee19ecdc62b91878528302dd0be1b9451cc90"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbb9c997932473a27afa93954bb77a9f9b786b4ccf718d903f35da3232317de"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bcb34f869d431799c3ee7d516554797f7760cb2198ecaa89c3f176f72d062be"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ece17ec5f20d7d9b442e5174ae9f020365d01ba7c112205a4d59cf19dc38ee"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ba6e5e6588e49139a0979d03a7deb9c734bde647b9a8808f26acf9c547cab1bf"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3bf8b000a4e2967e6dfdd8656cd0757d18c7e5ce3d16339e550bd462f4857e59"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2136f64fbb86451dbbf70223635a468272dd20075f988a102bf8a3f194a411dc"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e8918973fbd34e7814f59143c5f600ecd38b8038161239fd1a3d33d5817a38b8"}, + {file = "pyzmq-26.0.3-cp310-cp310-win32.whl", hash = "sha256:0aaf982e68a7ac284377d051c742610220fd06d330dcd4c4dbb4cdd77c22a537"}, + {file = "pyzmq-26.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:f1a9b7d00fdf60b4039f4455afd031fe85ee8305b019334b72dcf73c567edc47"}, + {file = "pyzmq-26.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:80b12f25d805a919d53efc0a5ad7c0c0326f13b4eae981a5d7b7cc343318ebb7"}, + {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:a72a84570f84c374b4c287183debc776dc319d3e8ce6b6a0041ce2e400de3f32"}, + {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ca684ee649b55fd8f378127ac8462fb6c85f251c2fb027eb3c887e8ee347bcd"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e222562dc0f38571c8b1ffdae9d7adb866363134299264a1958d077800b193b7"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f17cde1db0754c35a91ac00b22b25c11da6eec5746431d6e5092f0cd31a3fea9"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7c0c0b3244bb2275abe255d4a30c050d541c6cb18b870975553f1fb6f37527"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:ac97a21de3712afe6a6c071abfad40a6224fd14fa6ff0ff8d0c6e6cd4e2f807a"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:88b88282e55fa39dd556d7fc04160bcf39dea015f78e0cecec8ff4f06c1fc2b5"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:72b67f966b57dbd18dcc7efbc1c7fc9f5f983e572db1877081f075004614fcdd"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4b6cecbbf3b7380f3b61de3a7b93cb721125dc125c854c14ddc91225ba52f83"}, + {file = "pyzmq-26.0.3-cp311-cp311-win32.whl", hash = "sha256:eed56b6a39216d31ff8cd2f1d048b5bf1700e4b32a01b14379c3b6dde9ce3aa3"}, + {file = "pyzmq-26.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:3191d312c73e3cfd0f0afdf51df8405aafeb0bad71e7ed8f68b24b63c4f36500"}, + {file = "pyzmq-26.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:b6907da3017ef55139cf0e417c5123a84c7332520e73a6902ff1f79046cd3b94"}, + {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:068ca17214038ae986d68f4a7021f97e187ed278ab6dccb79f837d765a54d753"}, + {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7821d44fe07335bea256b9f1f41474a642ca55fa671dfd9f00af8d68a920c2d4"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeb438a26d87c123bb318e5f2b3d86a36060b01f22fbdffd8cf247d52f7c9a2b"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69ea9d6d9baa25a4dc9cef5e2b77b8537827b122214f210dd925132e34ae9b12"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7daa3e1369355766dea11f1d8ef829905c3b9da886ea3152788dc25ee6079e02"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6ca7a9a06b52d0e38ccf6bca1aeff7be178917893f3883f37b75589d42c4ac20"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1b7d0e124948daa4d9686d421ef5087c0516bc6179fdcf8828b8444f8e461a77"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e746524418b70f38550f2190eeee834db8850088c834d4c8406fbb9bc1ae10b2"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6b3146f9ae6af82c47a5282ac8803523d381b3b21caeae0327ed2f7ecb718798"}, + {file = "pyzmq-26.0.3-cp312-cp312-win32.whl", hash = "sha256:2b291d1230845871c00c8462c50565a9cd6026fe1228e77ca934470bb7d70ea0"}, + {file = "pyzmq-26.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:926838a535c2c1ea21c903f909a9a54e675c2126728c21381a94ddf37c3cbddf"}, + {file = "pyzmq-26.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:5bf6c237f8c681dfb91b17f8435b2735951f0d1fad10cc5dfd96db110243370b"}, + {file = "pyzmq-26.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c0991f5a96a8e620f7691e61178cd8f457b49e17b7d9cfa2067e2a0a89fc1d5"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dbf012d8fcb9f2cf0643b65df3b355fdd74fc0035d70bb5c845e9e30a3a4654b"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:01fbfbeb8249a68d257f601deb50c70c929dc2dfe683b754659569e502fbd3aa"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c8eb19abe87029c18f226d42b8a2c9efdd139d08f8bf6e085dd9075446db450"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5344b896e79800af86ad643408ca9aa303a017f6ebff8cee5a3163c1e9aec987"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:204e0f176fd1d067671157d049466869b3ae1fc51e354708b0dc41cf94e23a3a"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a42db008d58530efa3b881eeee4991146de0b790e095f7ae43ba5cc612decbc5"}, + {file = "pyzmq-26.0.3-cp37-cp37m-win32.whl", hash = "sha256:8d7a498671ca87e32b54cb47c82a92b40130a26c5197d392720a1bce1b3c77cf"}, + {file = "pyzmq-26.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:3b4032a96410bdc760061b14ed6a33613ffb7f702181ba999df5d16fb96ba16a"}, + {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2cc4e280098c1b192c42a849de8de2c8e0f3a84086a76ec5b07bfee29bda7d18"}, + {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5bde86a2ed3ce587fa2b207424ce15b9a83a9fa14422dcc1c5356a13aed3df9d"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:34106f68e20e6ff253c9f596ea50397dbd8699828d55e8fa18bd4323d8d966e6"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ebbbd0e728af5db9b04e56389e2299a57ea8b9dd15c9759153ee2455b32be6ad"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6b1d1c631e5940cac5a0b22c5379c86e8df6a4ec277c7a856b714021ab6cfad"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e891ce81edd463b3b4c3b885c5603c00141151dd9c6936d98a680c8c72fe5c67"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9b273ecfbc590a1b98f014ae41e5cf723932f3b53ba9367cfb676f838038b32c"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b32bff85fb02a75ea0b68f21e2412255b5731f3f389ed9aecc13a6752f58ac97"}, + {file = "pyzmq-26.0.3-cp38-cp38-win32.whl", hash = "sha256:f6c21c00478a7bea93caaaef9e7629145d4153b15a8653e8bb4609d4bc70dbfc"}, + {file = "pyzmq-26.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:3401613148d93ef0fd9aabdbddb212de3db7a4475367f49f590c837355343972"}, + {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:2ed8357f4c6e0daa4f3baf31832df8a33334e0fe5b020a61bc8b345a3db7a606"}, + {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c1c8f2a2ca45292084c75bb6d3a25545cff0ed931ed228d3a1810ae3758f975f"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b63731993cdddcc8e087c64e9cf003f909262b359110070183d7f3025d1c56b5"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b3cd31f859b662ac5d7f4226ec7d8bd60384fa037fc02aee6ff0b53ba29a3ba8"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:115f8359402fa527cf47708d6f8a0f8234f0e9ca0cab7c18c9c189c194dbf620"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:715bdf952b9533ba13dfcf1f431a8f49e63cecc31d91d007bc1deb914f47d0e4"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e1258c639e00bf5e8a522fec6c3eaa3e30cf1c23a2f21a586be7e04d50c9acab"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:15c59e780be8f30a60816a9adab900c12a58d79c1ac742b4a8df044ab2a6d920"}, + {file = "pyzmq-26.0.3-cp39-cp39-win32.whl", hash = "sha256:d0cdde3c78d8ab5b46595054e5def32a755fc028685add5ddc7403e9f6de9879"}, + {file = "pyzmq-26.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:ce828058d482ef860746bf532822842e0ff484e27f540ef5c813d516dd8896d2"}, + {file = "pyzmq-26.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:788f15721c64109cf720791714dc14afd0f449d63f3a5487724f024345067381"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c18645ef6294d99b256806e34653e86236eb266278c8ec8112622b61db255de"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e6bc96ebe49604df3ec2c6389cc3876cabe475e6bfc84ced1bf4e630662cb35"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:971e8990c5cc4ddcff26e149398fc7b0f6a042306e82500f5e8db3b10ce69f84"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8416c23161abd94cc7da80c734ad7c9f5dbebdadfdaa77dad78244457448223"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:082a2988364b60bb5de809373098361cf1dbb239623e39e46cb18bc035ed9c0c"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d57dfbf9737763b3a60d26e6800e02e04284926329aee8fb01049635e957fe81"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:77a85dca4c2430ac04dc2a2185c2deb3858a34fe7f403d0a946fa56970cf60a1"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4c82a6d952a1d555bf4be42b6532927d2a5686dd3c3e280e5f63225ab47ac1f5"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4496b1282c70c442809fc1b151977c3d967bfb33e4e17cedbf226d97de18f709"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e4946d6bdb7ba972dfda282f9127e5756d4f299028b1566d1245fa0d438847e6"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03c0ae165e700364b266876d712acb1ac02693acd920afa67da2ebb91a0b3c09"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3e3070e680f79887d60feeda051a58d0ac36622e1759f305a41059eff62c6da7"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6ca08b840fe95d1c2bd9ab92dac5685f949fc6f9ae820ec16193e5ddf603c3b2"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e76654e9dbfb835b3518f9938e565c7806976c07b37c33526b574cc1a1050480"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:871587bdadd1075b112e697173e946a07d722459d20716ceb3d1bd6c64bd08ce"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d0a2d1bd63a4ad79483049b26514e70fa618ce6115220da9efdff63688808b17"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0270b49b6847f0d106d64b5086e9ad5dc8a902413b5dbbb15d12b60f9c1747a4"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:703c60b9910488d3d0954ca585c34f541e506a091a41930e663a098d3b794c67"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74423631b6be371edfbf7eabb02ab995c2563fee60a80a30829176842e71722a"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4adfbb5451196842a88fda3612e2c0414134874bffb1c2ce83ab4242ec9e027d"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3516119f4f9b8671083a70b6afaa0a070f5683e431ab3dc26e9215620d7ca1ad"}, + {file = "pyzmq-26.0.3.tar.gz", hash = "sha256:dba7d9f2e047dfa2bca3b01f4f84aa5246725203d6284e3790f2ca15fba6b40a"}, ] [package.dependencies] @@ -5098,13 +5169,13 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} [[package]] name = "qtconsole" -version = "5.5.1" +version = "5.5.2" description = "Jupyter Qt console" optional = false -python-versions = ">= 3.8" +python-versions = ">=3.8" files = [ - {file = "qtconsole-5.5.1-py3-none-any.whl", hash = "sha256:8c75fa3e9b4ed884880ff7cea90a1b67451219279ec33deaee1d59e3df1a5d2b"}, - {file = "qtconsole-5.5.1.tar.gz", hash = "sha256:a0e806c6951db9490628e4df80caec9669b65149c7ba40f9bf033c025a5b56bc"}, + {file = "qtconsole-5.5.2-py3-none-any.whl", hash = "sha256:42d745f3d05d36240244a04e1e1ec2a86d5d9b6edb16dbdef582ccb629e87e0b"}, + {file = "qtconsole-5.5.2.tar.gz", hash = "sha256:6b5fb11274b297463706af84dcbbd5c92273b1f619e6d25d08874b0a88516989"}, ] [package.dependencies] @@ -5140,101 +5211,104 @@ test = ["pytest (>=6,!=7.0.0,!=7.0.1)", "pytest-cov (>=3.0.0)", "pytest-qt"] [[package]] name = "rapidfuzz" -version = "3.6.1" +version = "3.9.3" description = "rapid fuzzy string matching" optional = false python-versions = ">=3.8" files = [ - {file = "rapidfuzz-3.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ac434fc71edda30d45db4a92ba5e7a42c7405e1a54cb4ec01d03cc668c6dcd40"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2a791168e119cfddf4b5a40470620c872812042f0621e6a293983a2d52372db0"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5a2f3e9df346145c2be94e4d9eeffb82fab0cbfee85bd4a06810e834fe7c03fa"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23de71e7f05518b0bbeef55d67b5dbce3bcd3e2c81e7e533051a2e9401354eb0"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d056e342989248d2bdd67f1955bb7c3b0ecfa239d8f67a8dfe6477b30872c607"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01835d02acd5d95c1071e1da1bb27fe213c84a013b899aba96380ca9962364bc"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed0f712e0bb5fea327e92aec8a937afd07ba8de4c529735d82e4c4124c10d5a0"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96cd19934f76a1264e8ecfed9d9f5291fde04ecb667faef5f33bdbfd95fe2d1f"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e06c4242a1354cf9d48ee01f6f4e6e19c511d50bb1e8d7d20bcadbb83a2aea90"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d73dcfe789d37c6c8b108bf1e203e027714a239e50ad55572ced3c004424ed3b"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:06e98ff000e2619e7cfe552d086815671ed09b6899408c2c1b5103658261f6f3"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:08b6fb47dd889c69fbc0b915d782aaed43e025df6979b6b7f92084ba55edd526"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a1788ebb5f5b655a15777e654ea433d198f593230277e74d51a2a1e29a986283"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-win32.whl", hash = "sha256:c65f92881753aa1098c77818e2b04a95048f30edbe9c3094dc3707d67df4598b"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:4243a9c35667a349788461aae6471efde8d8800175b7db5148a6ab929628047f"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-win_arm64.whl", hash = "sha256:f59d19078cc332dbdf3b7b210852ba1f5db8c0a2cd8cc4c0ed84cc00c76e6802"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fbc07e2e4ac696497c5f66ec35c21ddab3fc7a406640bffed64c26ab2f7ce6d6"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:40cced1a8852652813f30fb5d4b8f9b237112a0bbaeebb0f4cc3611502556764"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:82300e5f8945d601c2daaaac139d5524d7c1fdf719aa799a9439927739917460"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf97c321fd641fea2793abce0e48fa4f91f3c202092672f8b5b4e781960b891"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7420e801b00dee4a344ae2ee10e837d603461eb180e41d063699fb7efe08faf0"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:060bd7277dc794279fa95522af355034a29c90b42adcb7aa1da358fc839cdb11"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7e3375e4f2bfec77f907680328e4cd16cc64e137c84b1886d547ab340ba6928"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a490cd645ef9d8524090551016f05f052e416c8adb2d8b85d35c9baa9d0428ab"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2e03038bfa66d2d7cffa05d81c2f18fd6acbb25e7e3c068d52bb7469e07ff382"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2b19795b26b979c845dba407fe79d66975d520947b74a8ab6cee1d22686f7967"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:064c1d66c40b3a0f488db1f319a6e75616b2e5fe5430a59f93a9a5e40a656d15"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3c772d04fb0ebeece3109d91f6122b1503023086a9591a0b63d6ee7326bd73d9"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:841eafba6913c4dfd53045835545ba01a41e9644e60920c65b89c8f7e60c00a9"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-win32.whl", hash = "sha256:266dd630f12696ea7119f31d8b8e4959ef45ee2cbedae54417d71ae6f47b9848"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:d79aec8aeee02ab55d0ddb33cea3ecd7b69813a48e423c966a26d7aab025cdfe"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-win_arm64.whl", hash = "sha256:484759b5dbc5559e76fefaa9170147d1254468f555fd9649aea3bad46162a88b"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b2ef4c0fd3256e357b70591ffb9e8ed1d439fb1f481ba03016e751a55261d7c1"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:588c4b20fa2fae79d60a4e438cf7133d6773915df3cc0a7f1351da19eb90f720"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7142ee354e9c06e29a2636b9bbcb592bb00600a88f02aa5e70e4f230347b373e"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dfc557c0454ad22382373ec1b7df530b4bbd974335efe97a04caec936f2956a"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:03f73b381bdeccb331a12c3c60f1e41943931461cdb52987f2ecf46bfc22f50d"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b0ccc2ec1781c7e5370d96aef0573dd1f97335343e4982bdb3a44c133e27786"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da3e8c9f7e64bb17faefda085ff6862ecb3ad8b79b0f618a6cf4452028aa2222"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fde9b14302a31af7bdafbf5cfbb100201ba21519be2b9dedcf4f1048e4fbe65d"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1a23eee225dfb21c07f25c9fcf23eb055d0056b48e740fe241cbb4b22284379"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e49b9575d16c56c696bc7b06a06bf0c3d4ef01e89137b3ddd4e2ce709af9fe06"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:0a9fc714b8c290261669f22808913aad49553b686115ad0ee999d1cb3df0cd66"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:a3ee4f8f076aa92184e80308fc1a079ac356b99c39408fa422bbd00145be9854"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f056ba42fd2f32e06b2c2ba2443594873cfccc0c90c8b6327904fc2ddf6d5799"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-win32.whl", hash = "sha256:5d82b9651e3d34b23e4e8e201ecd3477c2baa17b638979deeabbb585bcb8ba74"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:dad55a514868dae4543ca48c4e1fc0fac704ead038dafedf8f1fc0cc263746c1"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-win_arm64.whl", hash = "sha256:3c84294f4470fcabd7830795d754d808133329e0a81d62fcc2e65886164be83b"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e19d519386e9db4a5335a4b29f25b8183a1c3f78cecb4c9c3112e7f86470e37f"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01eb03cd880a294d1bf1a583fdd00b87169b9cc9c9f52587411506658c864d73"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:be368573255f8fbb0125a78330a1a40c65e9ba3c5ad129a426ff4289099bfb41"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3e5af946f419c30f5cb98b69d40997fe8580efe78fc83c2f0f25b60d0e56efb"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f382f7ffe384ce34345e1c0b2065451267d3453cadde78946fbd99a59f0cc23c"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be156f51f3a4f369e758505ed4ae64ea88900dcb2f89d5aabb5752676d3f3d7e"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1936d134b6c513fbe934aeb668b0fee1ffd4729a3c9d8d373f3e404fbb0ce8a0"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ff8eaf4a9399eb2bebd838f16e2d1ded0955230283b07376d68947bbc2d33d"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae598a172e3a95df3383634589660d6b170cc1336fe7578115c584a99e0ba64d"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cd4ba4c18b149da11e7f1b3584813159f189dc20833709de5f3df8b1342a9759"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:0402f1629e91a4b2e4aee68043a30191e5e1b7cd2aa8dacf50b1a1bcf6b7d3ab"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:1e12319c6b304cd4c32d5db00b7a1e36bdc66179c44c5707f6faa5a889a317c0"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0bbfae35ce4de4c574b386c43c78a0be176eeddfdae148cb2136f4605bebab89"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-win32.whl", hash = "sha256:7fec74c234d3097612ea80f2a80c60720eec34947066d33d34dc07a3092e8105"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:a553cc1a80d97459d587529cc43a4c7c5ecf835f572b671107692fe9eddf3e24"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:757dfd7392ec6346bd004f8826afb3bf01d18a723c97cbe9958c733ab1a51791"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2963f4a3f763870a16ee076796be31a4a0958fbae133dbc43fc55c3968564cf5"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d2f0274595cc5b2b929c80d4e71b35041104b577e118cf789b3fe0a77b37a4c5"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f211e366e026de110a4246801d43a907cd1a10948082f47e8a4e6da76fef52"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a59472b43879012b90989603aa5a6937a869a72723b1bf2ff1a0d1edee2cc8e6"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a03863714fa6936f90caa7b4b50ea59ea32bb498cc91f74dc25485b3f8fccfe9"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5dd95b6b7bfb1584f806db89e1e0c8dbb9d25a30a4683880c195cc7f197eaf0c"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7183157edf0c982c0b8592686535c8b3e107f13904b36d85219c77be5cefd0d8"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ad9d74ef7c619b5b0577e909582a1928d93e07d271af18ba43e428dc3512c2a1"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b53137d81e770c82189e07a8f32722d9e4260f13a0aec9914029206ead38cac3"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:49b9ed2472394d306d5dc967a7de48b0aab599016aa4477127b20c2ed982dbf9"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:dec307b57ec2d5054d77d03ee4f654afcd2c18aee00c48014cb70bfed79597d6"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4381023fa1ff32fd5076f5d8321249a9aa62128eb3f21d7ee6a55373e672b261"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-win32.whl", hash = "sha256:8d7a072f10ee57c8413c8ab9593086d42aaff6ee65df4aa6663eecdb7c398dca"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:ebcfb5bfd0a733514352cfc94224faad8791e576a80ffe2fd40b2177bf0e7198"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-win_arm64.whl", hash = "sha256:1c47d592e447738744905c18dda47ed155620204714e6df20eb1941bb1ba315e"}, - {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:eef8b346ab331bec12bbc83ac75641249e6167fab3d84d8f5ca37fd8e6c7a08c"}, - {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53251e256017e2b87f7000aee0353ba42392c442ae0bafd0f6b948593d3f68c6"}, - {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6dede83a6b903e3ebcd7e8137e7ff46907ce9316e9d7e7f917d7e7cdc570ee05"}, - {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e4da90e4c2b444d0a171d7444ea10152e07e95972bb40b834a13bdd6de1110c"}, - {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ca3dfcf74f2b6962f411c33dd95b0adf3901266e770da6281bc96bb5a8b20de9"}, - {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bcc957c0a8bde8007f1a8a413a632a1a409890f31f73fe764ef4eac55f59ca87"}, - {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:692c9a50bea7a8537442834f9bc6b7d29d8729a5b6379df17c31b6ab4df948c2"}, - {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c23ceaea27e790ddd35ef88b84cf9d721806ca366199a76fd47cfc0457a81b"}, - {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b155e67fff215c09f130555002e42f7517d0ea72cbd58050abb83cb7c880cec"}, - {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3028ee8ecc48250607fa8a0adce37b56275ec3b1acaccd84aee1f68487c8557b"}, - {file = "rapidfuzz-3.6.1.tar.gz", hash = "sha256:35660bee3ce1204872574fa041c7ad7ec5175b3053a4cb6e181463fc07013de7"}, + {file = "rapidfuzz-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bdb8c5b8e29238ec80727c2ba3b301efd45aa30c6a7001123a6647b8e6f77ea4"}, + {file = "rapidfuzz-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b3bd0d9632088c63a241f217742b1cf86e2e8ae573e01354775bd5016d12138c"}, + {file = "rapidfuzz-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:153f23c03d4917f6a1fc2fb56d279cc6537d1929237ff08ee7429d0e40464a18"}, + {file = "rapidfuzz-3.9.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a96c5225e840f1587f1bac8fa6f67562b38e095341576e82b728a82021f26d62"}, + {file = "rapidfuzz-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b777cd910ceecd738adc58593d6ed42e73f60ad04ecdb4a841ae410b51c92e0e"}, + {file = "rapidfuzz-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:53e06e4b81f552da04940aa41fc556ba39dee5513d1861144300c36c33265b76"}, + {file = "rapidfuzz-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c7ca5b6050f18fdcacdada2dc5fb7619ff998cd9aba82aed2414eee74ebe6cd"}, + {file = "rapidfuzz-3.9.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:87bb8d84cb41446a808c4b5f746e29d8a53499381ed72f6c4e456fe0f81c80a8"}, + {file = "rapidfuzz-3.9.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:959a15186d18425d19811bea86a8ffbe19fd48644004d29008e636631420a9b7"}, + {file = "rapidfuzz-3.9.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a24603dd05fb4e3c09d636b881ce347e5f55f925a6b1b4115527308a323b9f8e"}, + {file = "rapidfuzz-3.9.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d055da0e801c71dd74ba81d72d41b2fa32afa182b9fea6b4b199d2ce937450d"}, + {file = "rapidfuzz-3.9.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:875b581afb29a7213cf9d98cb0f98df862f1020bce9d9b2e6199b60e78a41d14"}, + {file = "rapidfuzz-3.9.3-cp310-cp310-win32.whl", hash = "sha256:6073a46f61479a89802e3f04655267caa6c14eb8ac9d81a635a13805f735ebc1"}, + {file = "rapidfuzz-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:119c010e20e561249b99ca2627f769fdc8305b07193f63dbc07bca0a6c27e892"}, + {file = "rapidfuzz-3.9.3-cp310-cp310-win_arm64.whl", hash = "sha256:790b0b244f3213581d42baa2fed8875f9ee2b2f9b91f94f100ec80d15b140ba9"}, + {file = "rapidfuzz-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f57e8305c281e8c8bc720515540e0580355100c0a7a541105c6cafc5de71daae"}, + {file = "rapidfuzz-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a4fc7b784cf987dbddc300cef70e09a92ed1bce136f7bb723ea79d7e297fe76d"}, + {file = "rapidfuzz-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b422c0a6fe139d5447a0766268e68e6a2a8c2611519f894b1f31f0a392b9167"}, + {file = "rapidfuzz-3.9.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f50fed4a9b0c9825ff37cf0bccafd51ff5792090618f7846a7650f21f85579c9"}, + {file = "rapidfuzz-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b80eb7cbe62348c61d3e67e17057cddfd6defab168863028146e07d5a8b24a89"}, + {file = "rapidfuzz-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f45be77ec82da32ce5709a362e236ccf801615cc7163b136d1778cf9e31b14"}, + {file = "rapidfuzz-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd84b7f652a5610733400307dc732f57c4a907080bef9520412e6d9b55bc9adc"}, + {file = "rapidfuzz-3.9.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3e6d27dad8c990218b8cd4a5c99cbc8834f82bb46ab965a7265d5aa69fc7ced7"}, + {file = "rapidfuzz-3.9.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:05ee0696ebf0dfe8f7c17f364d70617616afc7dafe366532730ca34056065b8a"}, + {file = "rapidfuzz-3.9.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:2bc8391749e5022cd9e514ede5316f86e332ffd3cfceeabdc0b17b7e45198a8c"}, + {file = "rapidfuzz-3.9.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:93981895602cf5944d89d317ae3b1b4cc684d175a8ae2a80ce5b65615e72ddd0"}, + {file = "rapidfuzz-3.9.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:754b719a4990735f66653c9e9261dcf52fd4d925597e43d6b9069afcae700d21"}, + {file = "rapidfuzz-3.9.3-cp311-cp311-win32.whl", hash = "sha256:14c9f268ade4c88cf77ab007ad0fdf63699af071ee69378de89fff7aa3cae134"}, + {file = "rapidfuzz-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc1991b4cde6c9d3c0bbcb83d5581dc7621bec8c666c095c65b4277233265a82"}, + {file = "rapidfuzz-3.9.3-cp311-cp311-win_arm64.whl", hash = "sha256:0c34139df09a61b1b557ab65782ada971b4a3bce7081d1b2bee45b0a52231adb"}, + {file = "rapidfuzz-3.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5d6a210347d6e71234af5c76d55eeb0348b026c9bb98fe7c1cca89bac50fb734"}, + {file = "rapidfuzz-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b300708c917ce52f6075bdc6e05b07c51a085733650f14b732c087dc26e0aaad"}, + {file = "rapidfuzz-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83ea7ca577d76778250421de61fb55a719e45b841deb769351fc2b1740763050"}, + {file = "rapidfuzz-3.9.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8319838fb5b7b5f088d12187d91d152b9386ce3979ed7660daa0ed1bff953791"}, + {file = "rapidfuzz-3.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:505d99131afd21529293a9a7b91dfc661b7e889680b95534756134dc1cc2cd86"}, + {file = "rapidfuzz-3.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c52970f7784518d7c82b07a62a26e345d2de8c2bd8ed4774e13342e4b3ff4200"}, + {file = "rapidfuzz-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:143caf7247449055ecc3c1e874b69e42f403dfc049fc2f3d5f70e1daf21c1318"}, + {file = "rapidfuzz-3.9.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b8ab0fa653d9225195a8ff924f992f4249c1e6fa0aea563f685e71b81b9fcccf"}, + {file = "rapidfuzz-3.9.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57e7c5bf7b61c7320cfa5dde1e60e678d954ede9bb7da8e763959b2138391401"}, + {file = "rapidfuzz-3.9.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:51fa1ba84653ab480a2e2044e2277bd7f0123d6693051729755addc0d015c44f"}, + {file = "rapidfuzz-3.9.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:17ff7f7eecdb169f9236e3b872c96dbbaf116f7787f4d490abd34b0116e3e9c8"}, + {file = "rapidfuzz-3.9.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:afe7c72d3f917b066257f7ff48562e5d462d865a25fbcabf40fca303a9fa8d35"}, + {file = "rapidfuzz-3.9.3-cp312-cp312-win32.whl", hash = "sha256:e53ed2e9b32674ce96eed80b3b572db9fd87aae6742941fb8e4705e541d861ce"}, + {file = "rapidfuzz-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:35b7286f177e4d8ba1e48b03612f928a3c4bdac78e5651379cec59f95d8651e6"}, + {file = "rapidfuzz-3.9.3-cp312-cp312-win_arm64.whl", hash = "sha256:e6e4b9380ed4758d0cb578b0d1970c3f32dd9e87119378729a5340cb3169f879"}, + {file = "rapidfuzz-3.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a39890013f6d5b056cc4bfdedc093e322462ece1027a57ef0c636537bdde7531"}, + {file = "rapidfuzz-3.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b5bc0fdbf419493163c5c9cb147c5fbe95b8e25844a74a8807dcb1a125e630cf"}, + {file = "rapidfuzz-3.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efe6e200a75a792d37b960457904c4fce7c928a96ae9e5d21d2bd382fe39066e"}, + {file = "rapidfuzz-3.9.3-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de077c468c225d4c18f7188c47d955a16d65f21aab121cbdd98e3e2011002c37"}, + {file = "rapidfuzz-3.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f917eaadf5388466a95f6a236f678a1588d231e52eda85374077101842e794e"}, + {file = "rapidfuzz-3.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:858ba57c05afd720db8088a8707079e8d024afe4644001fe0dbd26ef7ca74a65"}, + {file = "rapidfuzz-3.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d36447d21b05f90282a6f98c5a33771805f9222e5d0441d03eb8824e33e5bbb4"}, + {file = "rapidfuzz-3.9.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:acbe4b6f1ccd5b90c29d428e849aa4242e51bb6cab0448d5f3c022eb9a25f7b1"}, + {file = "rapidfuzz-3.9.3-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:53c7f27cdf899e94712972237bda48cfd427646aa6f5d939bf45d084780e4c16"}, + {file = "rapidfuzz-3.9.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:6175682a829c6dea4d35ed707f1dadc16513270ef64436568d03b81ccb6bdb74"}, + {file = "rapidfuzz-3.9.3-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:5276df395bd8497397197fca2b5c85f052d2e6a66ffc3eb0544dd9664d661f95"}, + {file = "rapidfuzz-3.9.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:77b5c4f3e72924d7845f0e189c304270066d0f49635cf8a3938e122c437e58de"}, + {file = "rapidfuzz-3.9.3-cp38-cp38-win32.whl", hash = "sha256:8add34061e5cd561c72ed4febb5c15969e7b25bda2bb5102d02afc3abc1f52d0"}, + {file = "rapidfuzz-3.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:604e0502a39cf8e67fa9ad239394dddad4cdef6d7008fdb037553817d420e108"}, + {file = "rapidfuzz-3.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21047f55d674614eb4b0ab34e35c3dc66f36403b9fbfae645199c4a19d4ed447"}, + {file = "rapidfuzz-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a56da3aff97cb56fe85d9ca957d1f55dbac7c27da927a86a2a86d8a7e17f80aa"}, + {file = "rapidfuzz-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:964c08481aec2fe574f0062e342924db2c6b321391aeb73d68853ed42420fd6d"}, + {file = "rapidfuzz-3.9.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e2b827258beefbe5d3f958243caa5a44cf46187eff0c20e0b2ab62d1550327a"}, + {file = "rapidfuzz-3.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6e65a301fcd19fbfbee3a514cc0014ff3f3b254b9fd65886e8a9d6957fb7bca"}, + {file = "rapidfuzz-3.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe93ba1725a8d47d2b9dca6c1f435174859427fbc054d83de52aea5adc65729"}, + {file = "rapidfuzz-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aca21c0a34adee582775da997a600283e012a608a107398d80a42f9a57ad323d"}, + {file = "rapidfuzz-3.9.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:256e07d3465173b2a91c35715a2277b1ee3ae0b9bbab4e519df6af78570741d0"}, + {file = "rapidfuzz-3.9.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:802ca2cc8aa6b8b34c6fdafb9e32540c1ba05fca7ad60b3bbd7ec89ed1797a87"}, + {file = "rapidfuzz-3.9.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:dd789100fc852cffac1449f82af0da139d36d84fd9faa4f79fc4140a88778343"}, + {file = "rapidfuzz-3.9.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:5d0abbacdb06e27ff803d7ae0bd0624020096802758068ebdcab9bd49cf53115"}, + {file = "rapidfuzz-3.9.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:378d1744828e27490a823fc6fe6ebfb98c15228d54826bf4e49e4b76eb5f5579"}, + {file = "rapidfuzz-3.9.3-cp39-cp39-win32.whl", hash = "sha256:5d0cb272d43e6d3c0dedefdcd9d00007471f77b52d2787a4695e9dd319bb39d2"}, + {file = "rapidfuzz-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:15e4158ac4b3fb58108072ec35b8a69165f651ba1c8f43559a36d518dbf9fb3f"}, + {file = "rapidfuzz-3.9.3-cp39-cp39-win_arm64.whl", hash = "sha256:58c6a4936190c558d5626b79fc9e16497e5df7098589a7e80d8bff68148ff096"}, + {file = "rapidfuzz-3.9.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5410dc848c947a603792f4f51b904a3331cf1dc60621586bfbe7a6de72da1091"}, + {file = "rapidfuzz-3.9.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:282d55700a1a3d3a7980746eb2fcd48c9bbc1572ebe0840d0340d548a54d01fe"}, + {file = "rapidfuzz-3.9.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc1037507810833646481f5729901a154523f98cbebb1157ba3a821012e16402"}, + {file = "rapidfuzz-3.9.3-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e33f779391caedcba2ba3089fb6e8e557feab540e9149a5c3f7fea7a3a7df37"}, + {file = "rapidfuzz-3.9.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41a81a9f311dc83d22661f9b1a1de983b201322df0c4554042ffffd0f2040c37"}, + {file = "rapidfuzz-3.9.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a93250bd8fae996350c251e1752f2c03335bb8a0a5b0c7e910a593849121a435"}, + {file = "rapidfuzz-3.9.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3617d1aa7716c57d120b6adc8f7c989f2d65bc2b0cbd5f9288f1fc7bf469da11"}, + {file = "rapidfuzz-3.9.3-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:ad04a3f5384b82933213bba2459f6424decc2823df40098920856bdee5fd6e88"}, + {file = "rapidfuzz-3.9.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8709918da8a88ad73c9d4dd0ecf24179a4f0ceba0bee21efc6ea21a8b5290349"}, + {file = "rapidfuzz-3.9.3-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b770f85eab24034e6ef7df04b2bfd9a45048e24f8a808e903441aa5abde8ecdd"}, + {file = "rapidfuzz-3.9.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930b4e6fdb4d914390141a2b99a6f77a52beacf1d06aa4e170cba3a98e24c1bc"}, + {file = "rapidfuzz-3.9.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:c8444e921bfc3757c475c4f4d7416a7aa69b2d992d5114fe55af21411187ab0d"}, + {file = "rapidfuzz-3.9.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c1d3ef3878f871abe6826e386c3d61b5292ef5f7946fe646f4206b85836b5da"}, + {file = "rapidfuzz-3.9.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d861bf326ee7dabc35c532a40384541578cd1ec1e1b7db9f9ecbba56eb76ca22"}, + {file = "rapidfuzz-3.9.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cde6b9d9ba5007077ee321ec722fa714ebc0cbd9a32ccf0f4dd3cc3f20952d71"}, + {file = "rapidfuzz-3.9.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bb6546e7b6bed1aefbe24f68a5fb9b891cc5aef61bca6c1a7b1054b7f0359bb"}, + {file = "rapidfuzz-3.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d8a57261ef7996d5ced7c8cba9189ada3fbeffd1815f70f635e4558d93766cb"}, + {file = "rapidfuzz-3.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:67201c02efc596923ad950519e0b75ceb78d524177ea557134d6567b9ac2c283"}, + {file = "rapidfuzz-3.9.3.tar.gz", hash = "sha256:b398ea66e8ed50451bce5997c430197d5e4b06ac4aa74602717f792d8d8d06e2"}, ] [package.extras] @@ -5242,17 +5316,17 @@ full = ["numpy"] [[package]] name = "redis" -version = "5.0.2" +version = "5.0.7" description = "Python client for Redis database and key-value store" optional = true python-versions = ">=3.7" files = [ - {file = "redis-5.0.2-py3-none-any.whl", hash = "sha256:4caa8e1fcb6f3c0ef28dba99535101d80934b7d4cd541bbb47f4a3826ee472d1"}, - {file = "redis-5.0.2.tar.gz", hash = "sha256:3f82cc80d350e93042c8e6e7a5d0596e4dd68715babffba79492733e1f367037"}, + {file = "redis-5.0.7-py3-none-any.whl", hash = "sha256:0e479e24da960c690be5d9b96d21f7b918a98c0cf49af3b6fafaa0753f93a0db"}, + {file = "redis-5.0.7.tar.gz", hash = "sha256:8f611490b93c8109b50adc317b31bfd84fff31def3475b92e7e80bf39f48175b"}, ] [package.dependencies] -async-timeout = ">=4.0.3" +async-timeout = {version = ">=4.0.3", markers = "python_full_version < \"3.11.3\""} [package.extras] hiredis = ["hiredis (>=1.0.0)"] @@ -5260,13 +5334,13 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" [[package]] name = "referencing" -version = "0.33.0" +version = "0.35.1" description = "JSON Referencing + Python" optional = false python-versions = ">=3.8" files = [ - {file = "referencing-0.33.0-py3-none-any.whl", hash = "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5"}, - {file = "referencing-0.33.0.tar.gz", hash = "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7"}, + {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, + {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, ] [package.dependencies] @@ -5364,110 +5438,110 @@ files = [ [[package]] name = "rpds-py" -version = "0.18.0" +version = "0.18.1" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" files = [ - {file = "rpds_py-0.18.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5b4e7d8d6c9b2e8ee2d55c90b59c707ca59bc30058269b3db7b1f8df5763557e"}, - {file = "rpds_py-0.18.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c463ed05f9dfb9baebef68048aed8dcdc94411e4bf3d33a39ba97e271624f8f7"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01e36a39af54a30f28b73096dd39b6802eddd04c90dbe161c1b8dbe22353189f"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d62dec4976954a23d7f91f2f4530852b0c7608116c257833922a896101336c51"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd18772815d5f008fa03d2b9a681ae38d5ae9f0e599f7dda233c439fcaa00d40"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:923d39efa3cfb7279a0327e337a7958bff00cc447fd07a25cddb0a1cc9a6d2da"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39514da80f971362f9267c600b6d459bfbbc549cffc2cef8e47474fddc9b45b1"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a34d557a42aa28bd5c48a023c570219ba2593bcbbb8dc1b98d8cf5d529ab1434"}, - {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:93df1de2f7f7239dc9cc5a4a12408ee1598725036bd2dedadc14d94525192fc3"}, - {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:34b18ba135c687f4dac449aa5157d36e2cbb7c03cbea4ddbd88604e076aa836e"}, - {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c0b5dcf9193625afd8ecc92312d6ed78781c46ecbf39af9ad4681fc9f464af88"}, - {file = "rpds_py-0.18.0-cp310-none-win32.whl", hash = "sha256:c4325ff0442a12113a6379af66978c3fe562f846763287ef66bdc1d57925d337"}, - {file = "rpds_py-0.18.0-cp310-none-win_amd64.whl", hash = "sha256:7223a2a5fe0d217e60a60cdae28d6949140dde9c3bcc714063c5b463065e3d66"}, - {file = "rpds_py-0.18.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3a96e0c6a41dcdba3a0a581bbf6c44bb863f27c541547fb4b9711fd8cf0ffad4"}, - {file = "rpds_py-0.18.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30f43887bbae0d49113cbaab729a112251a940e9b274536613097ab8b4899cf6"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d68c93e381010662ab873fea609bf6c0f428b6d0bb00f2c6939782e0818d37bf"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b34b7aa8b261c1dbf7720b5d6f01f38243e9b9daf7e6b8bc1fd4657000062f2c"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e6d75ab12b0bbab7215e5d40f1e5b738aa539598db27ef83b2ec46747df90e1"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8612cd233543a3781bc659c731b9d607de65890085098986dfd573fc2befe5"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aec493917dd45e3c69d00a8874e7cbed844efd935595ef78a0f25f14312e33c6"}, - {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:661d25cbffaf8cc42e971dd570d87cb29a665f49f4abe1f9e76be9a5182c4688"}, - {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1df3659d26f539ac74fb3b0c481cdf9d725386e3552c6fa2974f4d33d78e544b"}, - {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a1ce3ba137ed54f83e56fb983a5859a27d43a40188ba798993812fed73c70836"}, - {file = "rpds_py-0.18.0-cp311-none-win32.whl", hash = "sha256:69e64831e22a6b377772e7fb337533c365085b31619005802a79242fee620bc1"}, - {file = "rpds_py-0.18.0-cp311-none-win_amd64.whl", hash = "sha256:998e33ad22dc7ec7e030b3df701c43630b5bc0d8fbc2267653577e3fec279afa"}, - {file = "rpds_py-0.18.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7f2facbd386dd60cbbf1a794181e6aa0bd429bd78bfdf775436020172e2a23f0"}, - {file = "rpds_py-0.18.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1d9a5be316c15ffb2b3c405c4ff14448c36b4435be062a7f578ccd8b01f0c4d8"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd5bf1af8efe569654bbef5a3e0a56eca45f87cfcffab31dd8dde70da5982475"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5417558f6887e9b6b65b4527232553c139b57ec42c64570569b155262ac0754f"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:56a737287efecafc16f6d067c2ea0117abadcd078d58721f967952db329a3e5c"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8f03bccbd8586e9dd37219bce4d4e0d3ab492e6b3b533e973fa08a112cb2ffc9"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4457a94da0d5c53dc4b3e4de1158bdab077db23c53232f37a3cb7afdb053a4e3"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ab39c1ba9023914297dd88ec3b3b3c3f33671baeb6acf82ad7ce883f6e8e157"}, - {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9d54553c1136b50fd12cc17e5b11ad07374c316df307e4cfd6441bea5fb68496"}, - {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0af039631b6de0397ab2ba16eaf2872e9f8fca391b44d3d8cac317860a700a3f"}, - {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:84ffab12db93b5f6bad84c712c92060a2d321b35c3c9960b43d08d0f639d60d7"}, - {file = "rpds_py-0.18.0-cp312-none-win32.whl", hash = "sha256:685537e07897f173abcf67258bee3c05c374fa6fff89d4c7e42fb391b0605e98"}, - {file = "rpds_py-0.18.0-cp312-none-win_amd64.whl", hash = "sha256:e003b002ec72c8d5a3e3da2989c7d6065b47d9eaa70cd8808b5384fbb970f4ec"}, - {file = "rpds_py-0.18.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:08f9ad53c3f31dfb4baa00da22f1e862900f45908383c062c27628754af2e88e"}, - {file = "rpds_py-0.18.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0013fe6b46aa496a6749c77e00a3eb07952832ad6166bd481c74bda0dcb6d58"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e32a92116d4f2a80b629778280103d2a510a5b3f6314ceccd6e38006b5e92dcb"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e541ec6f2ec456934fd279a3120f856cd0aedd209fc3852eca563f81738f6861"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bed88b9a458e354014d662d47e7a5baafd7ff81c780fd91584a10d6ec842cb73"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2644e47de560eb7bd55c20fc59f6daa04682655c58d08185a9b95c1970fa1e07"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e8916ae4c720529e18afa0b879473049e95949bf97042e938530e072fde061d"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:465a3eb5659338cf2a9243e50ad9b2296fa15061736d6e26240e713522b6235c"}, - {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ea7d4a99f3b38c37eac212dbd6ec42b7a5ec51e2c74b5d3223e43c811609e65f"}, - {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:67071a6171e92b6da534b8ae326505f7c18022c6f19072a81dcf40db2638767c"}, - {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:41ef53e7c58aa4ef281da975f62c258950f54b76ec8e45941e93a3d1d8580594"}, - {file = "rpds_py-0.18.0-cp38-none-win32.whl", hash = "sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e"}, - {file = "rpds_py-0.18.0-cp38-none-win_amd64.whl", hash = "sha256:7cd863afe7336c62ec78d7d1349a2f34c007a3cc6c2369d667c65aeec412a5b1"}, - {file = "rpds_py-0.18.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:5307def11a35f5ae4581a0b658b0af8178c65c530e94893345bebf41cc139d33"}, - {file = "rpds_py-0.18.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77f195baa60a54ef9d2de16fbbfd3ff8b04edc0c0140a761b56c267ac11aa467"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39f5441553f1c2aed4de4377178ad8ff8f9d733723d6c66d983d75341de265ab"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a00312dea9310d4cb7dbd7787e722d2e86a95c2db92fbd7d0155f97127bcb40"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f2fc11e8fe034ee3c34d316d0ad8808f45bc3b9ce5857ff29d513f3ff2923a1"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:586f8204935b9ec884500498ccc91aa869fc652c40c093bd9e1471fbcc25c022"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddc2f4dfd396c7bfa18e6ce371cba60e4cf9d2e5cdb71376aa2da264605b60b9"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ddcba87675b6d509139d1b521e0c8250e967e63b5909a7e8f8944d0f90ff36f"}, - {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7bd339195d84439cbe5771546fe8a4e8a7a045417d8f9de9a368c434e42a721e"}, - {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:d7c36232a90d4755b720fbd76739d8891732b18cf240a9c645d75f00639a9024"}, - {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6b0817e34942b2ca527b0e9298373e7cc75f429e8da2055607f4931fded23e20"}, - {file = "rpds_py-0.18.0-cp39-none-win32.whl", hash = "sha256:99f70b740dc04d09e6b2699b675874367885217a2e9f782bdf5395632ac663b7"}, - {file = "rpds_py-0.18.0-cp39-none-win_amd64.whl", hash = "sha256:6ef687afab047554a2d366e112dd187b62d261d49eb79b77e386f94644363294"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ad36cfb355e24f1bd37cac88c112cd7730873f20fb0bdaf8ba59eedf8216079f"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:36b3ee798c58ace201289024b52788161e1ea133e4ac93fba7d49da5fec0ef9e"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e4461d0f003a0aa9be2bdd1b798a041f177189c1a0f7619fe8c95ad08d9a45d7"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8db715ebe3bb7d86d77ac1826f7d67ec11a70dbd2376b7cc214199360517b641"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:793968759cd0d96cac1e367afd70c235867831983f876a53389ad869b043c948"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66e6a3af5a75363d2c9a48b07cb27c4ea542938b1a2e93b15a503cdfa8490795"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ef0befbb5d79cf32d0266f5cff01545602344eda89480e1dd88aca964260b18"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d4acf42190d449d5e89654d5c1ed3a4f17925eec71f05e2a41414689cda02d1"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:a5f446dd5055667aabaee78487f2b5ab72e244f9bc0b2ffebfeec79051679984"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9dbbeb27f4e70bfd9eec1be5477517365afe05a9b2c441a0b21929ee61048124"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:22806714311a69fd0af9b35b7be97c18a0fc2826e6827dbb3a8c94eac6cf7eeb"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b34ae4636dfc4e76a438ab826a0d1eed2589ca7d9a1b2d5bb546978ac6485461"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c8370641f1a7f0e0669ddccca22f1da893cef7628396431eb445d46d893e5cd"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c8362467a0fdeccd47935f22c256bec5e6abe543bf0d66e3d3d57a8fb5731863"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11a8c85ef4a07a7638180bf04fe189d12757c696eb41f310d2426895356dcf05"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b316144e85316da2723f9d8dc75bada12fa58489a527091fa1d5a612643d1a0e"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf1ea2e34868f6fbf070e1af291c8180480310173de0b0c43fc38a02929fc0e3"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e546e768d08ad55b20b11dbb78a745151acbd938f8f00d0cfbabe8b0199b9880"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4901165d170a5fde6f589acb90a6b33629ad1ec976d4529e769c6f3d885e3e80"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:618a3d6cae6ef8ec88bb76dd80b83cfe415ad4f1d942ca2a903bf6b6ff97a2da"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ed4eb745efbff0a8e9587d22a84be94a5eb7d2d99c02dacf7bd0911713ed14dd"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c81e5f372cd0dc5dc4809553d34f832f60a46034a5f187756d9b90586c2c307"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:43fbac5f22e25bee1d482c97474f930a353542855f05c1161fd804c9dc74a09d"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d7faa6f14017c0b1e69f5e2c357b998731ea75a442ab3841c0dbbbfe902d2c4"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:08231ac30a842bd04daabc4d71fddd7e6d26189406d5a69535638e4dcb88fe76"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:044a3e61a7c2dafacae99d1e722cc2d4c05280790ec5a05031b3876809d89a5c"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3f26b5bd1079acdb0c7a5645e350fe54d16b17bfc5e71f371c449383d3342e17"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:482103aed1dfe2f3b71a58eff35ba105289b8d862551ea576bd15479aba01f66"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1374f4129f9bcca53a1bba0bb86bf78325a0374577cf7e9e4cd046b1e6f20e24"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:635dc434ff724b178cb192c70016cc0ad25a275228f749ee0daf0eddbc8183b1"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:bc362ee4e314870a70f4ae88772d72d877246537d9f8cb8f7eacf10884862432"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4832d7d380477521a8c1644bbab6588dfedea5e30a7d967b5fb75977c45fd77f"}, - {file = "rpds_py-0.18.0.tar.gz", hash = "sha256:42821446ee7a76f5d9f71f9e33a4fb2ffd724bb3e7f93386150b61a43115788d"}, + {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"}, + {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1"}, + {file = "rpds_py-0.18.1-cp310-none-win32.whl", hash = "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333"}, + {file = "rpds_py-0.18.1-cp310-none-win_amd64.whl", hash = "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88"}, + {file = "rpds_py-0.18.1-cp311-none-win32.whl", hash = "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb"}, + {file = "rpds_py-0.18.1-cp311-none-win_amd64.whl", hash = "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a"}, + {file = "rpds_py-0.18.1-cp312-none-win32.whl", hash = "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6"}, + {file = "rpds_py-0.18.1-cp312-none-win_amd64.whl", hash = "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc"}, + {file = "rpds_py-0.18.1-cp38-none-win32.whl", hash = "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9"}, + {file = "rpds_py-0.18.1-cp38-none-win_amd64.whl", hash = "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26"}, + {file = "rpds_py-0.18.1-cp39-none-win32.whl", hash = "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360"}, + {file = "rpds_py-0.18.1-cp39-none-win_amd64.whl", hash = "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e"}, + {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"}, ] [[package]] @@ -5501,13 +5575,13 @@ jeepney = ">=0.6" [[package]] name = "send2trash" -version = "1.8.2" +version = "1.8.3" description = "Send file to trash natively under Mac OS X, Windows and Linux" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "Send2Trash-1.8.2-py3-none-any.whl", hash = "sha256:a384719d99c07ce1eefd6905d2decb6f8b7ed054025bb0e618919f945de4f679"}, - {file = "Send2Trash-1.8.2.tar.gz", hash = "sha256:c132d59fa44b9ca2b1699af5c86f57ce9f4c5eb56629d5d55fbb7a35f84e2312"}, + {file = "Send2Trash-1.8.3-py3-none-any.whl", hash = "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9"}, + {file = "Send2Trash-1.8.3.tar.gz", hash = "sha256:b18e7a3966d99871aefeb00cfbcfdced55ce4871194810fc71f4aa484b953abf"}, ] [package.extras] @@ -5517,19 +5591,18 @@ win32 = ["pywin32"] [[package]] name = "setuptools" -version = "69.1.1" +version = "70.1.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.1.1-py3-none-any.whl", hash = "sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56"}, - {file = "setuptools-69.1.1.tar.gz", hash = "sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8"}, + {file = "setuptools-70.1.1-py3-none-any.whl", hash = "sha256:a58a8fde0541dab0419750bcc521fbdf8585f6e5cb41909df3a472ef7b81ca95"}, + {file = "setuptools-70.1.1.tar.gz", hash = "sha256:937a48c7cdb7a21eb53cd7f9b59e525503aa8abaf3584c730dc5f7a5bec3a650"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "shellingham" @@ -5586,6 +5659,17 @@ files = [ {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] +[[package]] +name = "socksio" +version = "1.0.0" +description = "Sans-I/O implementation of SOCKS4, SOCKS4A, and SOCKS5." +optional = true +python-versions = ">=3.6" +files = [ + {file = "socksio-1.0.0-py3-none-any.whl", hash = "sha256:95dc1f15f9b34e8d7b16f06d74b8ccf48f609af32ab33c608d08761c5dcbb1f3"}, + {file = "socksio-1.0.0.tar.gz", hash = "sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac"}, +] + [[package]] name = "soupsieve" version = "2.5" @@ -5800,13 +5884,13 @@ test = ["flake8", "mypy", "pytest"] [[package]] name = "sphinxcontrib-katex" -version = "0.9.9" +version = "0.9.10" description = "A Sphinx extension for rendering math in HTML pages" optional = false python-versions = ">=3.7" files = [ - {file = "sphinxcontrib-katex-0.9.9.tar.gz", hash = "sha256:d594c82df54b048d59d48e46b109f62217b311ab9b95208cab96d902f9a3fe29"}, - {file = "sphinxcontrib_katex-0.9.9-py3-none-any.whl", hash = "sha256:9b88f2b815ec04025ff0f96b50a22678bb9a186710aa34f20a308dd58fbb7f08"}, + {file = "sphinxcontrib_katex-0.9.10-py3-none-any.whl", hash = "sha256:4e5f0b18761cd2cd058a1b2392f42a7edea4cc5beaa504a44aaee07d17ace9b7"}, + {file = "sphinxcontrib_katex-0.9.10.tar.gz", hash = "sha256:309a92dae245dbc584ff7ea5fb6549727bae95e4e52008b74d259d2fd1ad0dec"}, ] [package.dependencies] @@ -5844,64 +5928,64 @@ test = ["pytest"] [[package]] name = "sqlalchemy" -version = "2.0.27" +version = "2.0.31" description = "Database Abstraction Library" optional = true python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.27-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d04e579e911562f1055d26dab1868d3e0bb905db3bccf664ee8ad109f035618a"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fa67d821c1fd268a5a87922ef4940442513b4e6c377553506b9db3b83beebbd8"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c7a596d0be71b7baa037f4ac10d5e057d276f65a9a611c46970f012752ebf2d"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:954d9735ee9c3fa74874c830d089a815b7b48df6f6b6e357a74130e478dbd951"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5cd20f58c29bbf2680039ff9f569fa6d21453fbd2fa84dbdb4092f006424c2e6"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:03f448ffb731b48323bda68bcc93152f751436ad6037f18a42b7e16af9e91c07"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-win32.whl", hash = "sha256:d997c5938a08b5e172c30583ba6b8aad657ed9901fc24caf3a7152eeccb2f1b4"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-win_amd64.whl", hash = "sha256:eb15ef40b833f5b2f19eeae65d65e191f039e71790dd565c2af2a3783f72262f"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6c5bad7c60a392850d2f0fee8f355953abaec878c483dd7c3836e0089f046bf6"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3012ab65ea42de1be81fff5fb28d6db893ef978950afc8130ba707179b4284a"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbcd77c4d94b23e0753c5ed8deba8c69f331d4fd83f68bfc9db58bc8983f49cd"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d177b7e82f6dd5e1aebd24d9c3297c70ce09cd1d5d37b43e53f39514379c029c"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:680b9a36029b30cf063698755d277885d4a0eab70a2c7c6e71aab601323cba45"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1306102f6d9e625cebaca3d4c9c8f10588735ef877f0360b5cdb4fdfd3fd7131"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-win32.whl", hash = "sha256:5b78aa9f4f68212248aaf8943d84c0ff0f74efc65a661c2fc68b82d498311fd5"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-win_amd64.whl", hash = "sha256:15e19a84b84528f52a68143439d0c7a3a69befcd4f50b8ef9b7b69d2628ae7c4"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0de1263aac858f288a80b2071990f02082c51d88335a1db0d589237a3435fe71"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce850db091bf7d2a1f2fdb615220b968aeff3849007b1204bf6e3e50a57b3d32"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dfc936870507da96aebb43e664ae3a71a7b96278382bcfe84d277b88e379b18"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4fbe6a766301f2e8a4519f4500fe74ef0a8509a59e07a4085458f26228cd7cc"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4535c49d961fe9a77392e3a630a626af5baa967172d42732b7a43496c8b28876"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0fb3bffc0ced37e5aa4ac2416f56d6d858f46d4da70c09bb731a246e70bff4d5"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-win32.whl", hash = "sha256:7f470327d06400a0aa7926b375b8e8c3c31d335e0884f509fe272b3c700a7254"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-win_amd64.whl", hash = "sha256:f9374e270e2553653d710ece397df67db9d19c60d2647bcd35bfc616f1622dcd"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e97cf143d74a7a5a0f143aa34039b4fecf11343eed66538610debc438685db4a"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7b5a3e2120982b8b6bd1d5d99e3025339f7fb8b8267551c679afb39e9c7c7f1"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e36aa62b765cf9f43a003233a8c2d7ffdeb55bc62eaa0a0380475b228663a38f"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5ada0438f5b74c3952d916c199367c29ee4d6858edff18eab783b3978d0db16d"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b1d9d1bfd96eef3c3faedb73f486c89e44e64e40e5bfec304ee163de01cf996f"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-win32.whl", hash = "sha256:ca891af9f3289d24a490a5fde664ea04fe2f4984cd97e26de7442a4251bd4b7c"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-win_amd64.whl", hash = "sha256:fd8aafda7cdff03b905d4426b714601c0978725a19efc39f5f207b86d188ba01"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ec1f5a328464daf7a1e4e385e4f5652dd9b1d12405075ccba1df842f7774b4fc"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ad862295ad3f644e3c2c0d8b10a988e1600d3123ecb48702d2c0f26771f1c396"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48217be1de7d29a5600b5c513f3f7664b21d32e596d69582be0a94e36b8309cb"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e56afce6431450442f3ab5973156289bd5ec33dd618941283847c9fd5ff06bf"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:611068511b5531304137bcd7fe8117c985d1b828eb86043bd944cebb7fae3910"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b86abba762ecfeea359112b2bb4490802b340850bbee1948f785141a5e020de8"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-win32.whl", hash = "sha256:30d81cc1192dc693d49d5671cd40cdec596b885b0ce3b72f323888ab1c3863d5"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-win_amd64.whl", hash = "sha256:120af1e49d614d2525ac247f6123841589b029c318b9afbfc9e2b70e22e1827d"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d07ee7793f2aeb9b80ec8ceb96bc8cc08a2aec8a1b152da1955d64e4825fcbac"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb0845e934647232b6ff5150df37ceffd0b67b754b9fdbb095233deebcddbd4a"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fc19ae2e07a067663dd24fca55f8ed06a288384f0e6e3910420bf4b1270cc51"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b90053be91973a6fb6020a6e44382c97739736a5a9d74e08cc29b196639eb979"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2f5c9dfb0b9ab5e3a8a00249534bdd838d943ec4cfb9abe176a6c33408430230"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:33e8bde8fff203de50399b9039c4e14e42d4d227759155c21f8da4a47fc8053c"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-win32.whl", hash = "sha256:d873c21b356bfaf1589b89090a4011e6532582b3a8ea568a00e0c3aab09399dd"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-win_amd64.whl", hash = "sha256:ff2f1b7c963961d41403b650842dc2039175b906ab2093635d8319bef0b7d620"}, - {file = "SQLAlchemy-2.0.27-py3-none-any.whl", hash = "sha256:1ab4e0448018d01b142c916cc7119ca573803a4745cfe341b8f95657812700ac"}, - {file = "SQLAlchemy-2.0.27.tar.gz", hash = "sha256:86a6ed69a71fe6b88bf9331594fa390a2adda4a49b5c06f98e47bf0d392534f8"}, -] - -[package.dependencies] -greenlet = {version = "!=0.4.17", optional = true, markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\" or extra == \"asyncio\""} + {file = "SQLAlchemy-2.0.31-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f2a213c1b699d3f5768a7272de720387ae0122f1becf0901ed6eaa1abd1baf6c"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9fea3d0884e82d1e33226935dac990b967bef21315cbcc894605db3441347443"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3ad7f221d8a69d32d197e5968d798217a4feebe30144986af71ada8c548e9fa"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2bee229715b6366f86a95d497c347c22ddffa2c7c96143b59a2aa5cc9eebbc"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cd5b94d4819c0c89280b7c6109c7b788a576084bf0a480ae17c227b0bc41e109"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:750900a471d39a7eeba57580b11983030517a1f512c2cb287d5ad0fcf3aebd58"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-win32.whl", hash = "sha256:7bd112be780928c7f493c1a192cd8c5fc2a2a7b52b790bc5a84203fb4381c6be"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-win_amd64.whl", hash = "sha256:5a48ac4d359f058474fadc2115f78a5cdac9988d4f99eae44917f36aa1476327"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f68470edd70c3ac3b6cd5c2a22a8daf18415203ca1b036aaeb9b0fb6f54e8298"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e2c38c2a4c5c634fe6c3c58a789712719fa1bf9b9d6ff5ebfce9a9e5b89c1ca"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd15026f77420eb2b324dcb93551ad9c5f22fab2c150c286ef1dc1160f110203"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2196208432deebdfe3b22185d46b08f00ac9d7b01284e168c212919891289396"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:352b2770097f41bff6029b280c0e03b217c2dcaddc40726f8f53ed58d8a85da4"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:56d51ae825d20d604583f82c9527d285e9e6d14f9a5516463d9705dab20c3740"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-win32.whl", hash = "sha256:6e2622844551945db81c26a02f27d94145b561f9d4b0c39ce7bfd2fda5776dac"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-win_amd64.whl", hash = "sha256:ccaf1b0c90435b6e430f5dd30a5aede4764942a695552eb3a4ab74ed63c5b8d3"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3b74570d99126992d4b0f91fb87c586a574a5872651185de8297c6f90055ae42"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f77c4f042ad493cb8595e2f503c7a4fe44cd7bd59c7582fd6d78d7e7b8ec52c"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd1591329333daf94467e699e11015d9c944f44c94d2091f4ac493ced0119449"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74afabeeff415e35525bf7a4ecdab015f00e06456166a2eba7590e49f8db940e"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b9c01990d9015df2c6f818aa8f4297d42ee71c9502026bb074e713d496e26b67"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:66f63278db425838b3c2b1c596654b31939427016ba030e951b292e32b99553e"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-win32.whl", hash = "sha256:0b0f658414ee4e4b8cbcd4a9bb0fd743c5eeb81fc858ca517217a8013d282c96"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-win_amd64.whl", hash = "sha256:fa4b1af3e619b5b0b435e333f3967612db06351217c58bfb50cee5f003db2a5a"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f43e93057cf52a227eda401251c72b6fbe4756f35fa6bfebb5d73b86881e59b0"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d337bf94052856d1b330d5fcad44582a30c532a2463776e1651bd3294ee7e58b"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c06fb43a51ccdff3b4006aafee9fcf15f63f23c580675f7734245ceb6b6a9e05"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:b6e22630e89f0e8c12332b2b4c282cb01cf4da0d26795b7eae16702a608e7ca1"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:79a40771363c5e9f3a77f0e28b3302801db08040928146e6808b5b7a40749c88"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-win32.whl", hash = "sha256:501ff052229cb79dd4c49c402f6cb03b5a40ae4771efc8bb2bfac9f6c3d3508f"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-win_amd64.whl", hash = "sha256:597fec37c382a5442ffd471f66ce12d07d91b281fd474289356b1a0041bdf31d"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dc6d69f8829712a4fd799d2ac8d79bdeff651c2301b081fd5d3fe697bd5b4ab9"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:23b9fbb2f5dd9e630db70fbe47d963c7779e9c81830869bd7d137c2dc1ad05fb"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a21c97efcbb9f255d5c12a96ae14da873233597dfd00a3a0c4ce5b3e5e79704"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26a6a9837589c42b16693cf7bf836f5d42218f44d198f9343dd71d3164ceeeac"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc251477eae03c20fae8db9c1c23ea2ebc47331bcd73927cdcaecd02af98d3c3"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2fd17e3bb8058359fa61248c52c7b09a97cf3c820e54207a50af529876451808"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-win32.whl", hash = "sha256:c76c81c52e1e08f12f4b6a07af2b96b9b15ea67ccdd40ae17019f1c373faa227"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-win_amd64.whl", hash = "sha256:4b600e9a212ed59355813becbcf282cfda5c93678e15c25a0ef896b354423238"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b6cf796d9fcc9b37011d3f9936189b3c8074a02a4ed0c0fbbc126772c31a6d4"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:78fe11dbe37d92667c2c6e74379f75746dc947ee505555a0197cfba9a6d4f1a4"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fc47dc6185a83c8100b37acda27658fe4dbd33b7d5e7324111f6521008ab4fe"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a41514c1a779e2aa9a19f67aaadeb5cbddf0b2b508843fcd7bafdf4c6864005"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:afb6dde6c11ea4525318e279cd93c8734b795ac8bb5dda0eedd9ebaca7fa23f1"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3f9faef422cfbb8fd53716cd14ba95e2ef655400235c3dfad1b5f467ba179c8c"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-win32.whl", hash = "sha256:fc6b14e8602f59c6ba893980bea96571dd0ed83d8ebb9c4479d9ed5425d562e9"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-win_amd64.whl", hash = "sha256:3cb8a66b167b033ec72c3812ffc8441d4e9f5f78f5e31e54dcd4c90a4ca5bebc"}, + {file = "SQLAlchemy-2.0.31-py3-none-any.whl", hash = "sha256:69f3e3c08867a8e4856e92d7afb618b95cdee18e0bc1647b77599722c9a28911"}, + {file = "SQLAlchemy-2.0.31.tar.gz", hash = "sha256:b607489dd4a54de56984a0c7656247504bd5523d9d0ba799aef59d4add009484"}, +] + +[package.dependencies] +greenlet = {version = "!=0.4.17", optional = true, markers = "python_version < \"3.13\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\") or extra == \"asyncio\""} typing-extensions = ">=4.6.0" [package.extras] @@ -5983,13 +6067,13 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7 [[package]] name = "streamlit" -version = "1.35.0" +version = "1.36.0" description = "A faster way to build and share data apps" optional = false python-versions = "!=3.9.7,>=3.8" files = [ - {file = "streamlit-1.35.0-py2.py3-none-any.whl", hash = "sha256:e17d1d86830a0d7687c37faf2fe47bffa752d0c95a306e96d7749bd3faa72a5b"}, - {file = "streamlit-1.35.0.tar.gz", hash = "sha256:679d55bb6189743f606abf0696623df0bfd223a6d0c8d96b8d60678d4891d2d6"}, + {file = "streamlit-1.36.0-py2.py3-none-any.whl", hash = "sha256:3399a33ea5faa26c05dd433d142eefe68ade67e9189a9e1d47a1731ae30a1c42"}, + {file = "streamlit-1.36.0.tar.gz", hash = "sha256:a12af9f0eb61ab5832f438336257b1ec20eb29d8e0e0c6b40a79116ba939bc9c"}, ] [package.dependencies] @@ -5998,11 +6082,11 @@ blinker = ">=1.0.0,<2" cachetools = ">=4.0,<6" click = ">=7.0,<9" gitpython = ">=3.0.7,<3.1.19 || >3.1.19,<4" -numpy = ">=1.19.3,<2" -packaging = ">=16.8,<25" +numpy = ">=1.20,<3" +packaging = ">=20,<25" pandas = ">=1.3.0,<3" pillow = ">=7.1.0,<11" -protobuf = ">=3.20,<5" +protobuf = ">=3.20,<6" pyarrow = ">=7.0" pydeck = ">=0.8.0b4,<1" requests = ">=2.27,<3" @@ -6011,7 +6095,7 @@ tenacity = ">=8.1.0,<9" toml = ">=0.10.1,<2" tornado = ">=6.0.3,<7" typing-extensions = ">=4.3.0,<5" -watchdog = {version = ">=2.1.5", markers = "platform_system != \"Darwin\""} +watchdog = {version = ">=2.1.5,<5", markers = "platform_system != \"Darwin\""} [package.extras] snowflake = ["snowflake-connector-python (>=2.8.0)", "snowflake-snowpark-python (>=0.9.0)"] @@ -6049,17 +6133,18 @@ cryptg = ["cryptg"] [[package]] name = "tenacity" -version = "8.2.3" +version = "8.4.2" description = "Retry code until it succeeds" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tenacity-8.2.3-py3-none-any.whl", hash = "sha256:ce510e327a630c9e1beaf17d42e6ffacc88185044ad85cf74c0a8887c6a0f88c"}, - {file = "tenacity-8.2.3.tar.gz", hash = "sha256:5398ef0d78e63f40007c1fb4c0bff96e1911394d2fa8d194f77619c05ff6cc8a"}, + {file = "tenacity-8.4.2-py3-none-any.whl", hash = "sha256:9e6f7cf7da729125c7437222f8a522279751cdfbe6b67bfe64f75d3a348661b2"}, + {file = "tenacity-8.4.2.tar.gz", hash = "sha256:cd80a53a79336edba8489e767f729e4f391c896956b57140b5d7511a64bbd3ef"}, ] [package.extras] -doc = ["reno", "sphinx", "tornado (>=4.5)"] +doc = ["reno", "sphinx"] +test = ["pytest", "tornado (>=4.5)", "typeguard"] [[package]] name = "termcolor" @@ -6077,13 +6162,13 @@ tests = ["pytest", "pytest-cov"] [[package]] name = "terminado" -version = "0.18.0" +version = "0.18.1" description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library." optional = false python-versions = ">=3.8" files = [ - {file = "terminado-0.18.0-py3-none-any.whl", hash = "sha256:87b0d96642d0fe5f5abd7783857b9cab167f221a39ff98e3b9619a788a3c0f2e"}, - {file = "terminado-0.18.0.tar.gz", hash = "sha256:1ea08a89b835dd1b8c0c900d92848147cef2537243361b2e3f4dc15df9b6fded"}, + {file = "terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0"}, + {file = "terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e"}, ] [package.dependencies] @@ -6098,13 +6183,13 @@ typing = ["mypy (>=1.6,<2.0)", "traitlets (>=5.11.1)"] [[package]] name = "tinycss2" -version = "1.2.1" +version = "1.3.0" description = "A tiny CSS parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tinycss2-1.2.1-py3-none-any.whl", hash = "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847"}, - {file = "tinycss2-1.2.1.tar.gz", hash = "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627"}, + {file = "tinycss2-1.3.0-py3-none-any.whl", hash = "sha256:54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7"}, + {file = "tinycss2-1.3.0.tar.gz", hash = "sha256:152f9acabd296a8375fbca5b84c961ff95971fcfc32e79550c8df8e29118c54d"}, ] [package.dependencies] @@ -6112,7 +6197,7 @@ webencodings = ">=0.4" [package.extras] doc = ["sphinx", "sphinx_rtd_theme"] -test = ["flake8", "isort", "pytest"] +test = ["pytest", "ruff"] [[package]] name = "toml" @@ -6138,13 +6223,13 @@ files = [ [[package]] name = "tomlkit" -version = "0.12.4" +version = "0.12.5" description = "Style preserving TOML library" optional = false python-versions = ">=3.7" files = [ - {file = "tomlkit-0.12.4-py3-none-any.whl", hash = "sha256:5cd82d48a3dd89dee1f9d64420aa20ae65cfbd00668d6f094d7578a78efbb77b"}, - {file = "tomlkit-0.12.4.tar.gz", hash = "sha256:7ca1cfc12232806517a8515047ba66a19369e71edf2439d0f5824f91032b6cc3"}, + {file = "tomlkit-0.12.5-py3-none-any.whl", hash = "sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f"}, + {file = "tomlkit-0.12.5.tar.gz", hash = "sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c"}, ] [[package]] @@ -6160,33 +6245,33 @@ files = [ [[package]] name = "tornado" -version = "6.4" +version = "6.4.1" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." optional = false -python-versions = ">= 3.8" +python-versions = ">=3.8" files = [ - {file = "tornado-6.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0"}, - {file = "tornado-6.4-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263"}, - {file = "tornado-6.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e"}, - {file = "tornado-6.4-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579"}, - {file = "tornado-6.4-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212"}, - {file = "tornado-6.4-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2"}, - {file = "tornado-6.4-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78"}, - {file = "tornado-6.4-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f"}, - {file = "tornado-6.4-cp38-abi3-win32.whl", hash = "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052"}, - {file = "tornado-6.4-cp38-abi3-win_amd64.whl", hash = "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63"}, - {file = "tornado-6.4.tar.gz", hash = "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee"}, + {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8"}, + {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698"}, + {file = "tornado-6.4.1-cp38-abi3-win32.whl", hash = "sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d"}, + {file = "tornado-6.4.1-cp38-abi3-win_amd64.whl", hash = "sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7"}, + {file = "tornado-6.4.1.tar.gz", hash = "sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9"}, ] [[package]] name = "tqdm" -version = "4.66.2" +version = "4.66.4" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.2-py3-none-any.whl", hash = "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9"}, - {file = "tqdm-4.66.2.tar.gz", hash = "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531"}, + {file = "tqdm-4.66.4-py3-none-any.whl", hash = "sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644"}, + {file = "tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb"}, ] [package.dependencies] @@ -6200,28 +6285,28 @@ telegram = ["requests"] [[package]] name = "traitlets" -version = "5.14.1" +version = "5.14.3" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" files = [ - {file = "traitlets-5.14.1-py3-none-any.whl", hash = "sha256:2e5a030e6eff91737c643231bfcf04a65b0132078dad75e4936700b213652e74"}, - {file = "traitlets-5.14.1.tar.gz", hash = "sha256:8585105b371a04b8316a43d5ce29c098575c2e477850b62b848b964f1444527e"}, + {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, + {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, ] [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] [[package]] name = "trove-classifiers" -version = "2024.2.23" +version = "2024.5.22" description = "Canonical source for classifiers on PyPI (pypi.org)." optional = false python-versions = "*" files = [ - {file = "trove-classifiers-2024.2.23.tar.gz", hash = "sha256:8385160a12aac69c93fff058fb613472ed773a24a27eb3cd4b144cfbdd79f38c"}, - {file = "trove_classifiers-2024.2.23-py3-none-any.whl", hash = "sha256:3094534b8021dc1822aadb1d11d4c7b62a854d464d19458fd0a49d6fe2b68b77"}, + {file = "trove_classifiers-2024.5.22-py3-none-any.whl", hash = "sha256:c43ade18704823e4afa3d9db7083294bc4708a5e02afbcefacd0e9d03a7a24ef"}, + {file = "trove_classifiers-2024.5.22.tar.gz", hash = "sha256:8a6242bbb5c9ae88d34cf665e816b287d2212973c8777dfaef5ec18d72ac1d03"}, ] [[package]] @@ -6243,13 +6328,13 @@ typing-extensions = ">=3.7.4.3" [[package]] name = "types-python-dateutil" -version = "2.8.19.20240106" +version = "2.9.0.20240316" description = "Typing stubs for python-dateutil" optional = false python-versions = ">=3.8" files = [ - {file = "types-python-dateutil-2.8.19.20240106.tar.gz", hash = "sha256:1f8db221c3b98e6ca02ea83a58371b22c374f42ae5bbdf186db9c9a76581459f"}, - {file = "types_python_dateutil-2.8.19.20240106-py3-none-any.whl", hash = "sha256:efbbdc54590d0f16152fa103c9879c7d4a00e82078f6e2cf01769042165acaa2"}, + {file = "types-python-dateutil-2.9.0.20240316.tar.gz", hash = "sha256:5d2f2e240b86905e40944dd787db6da9263f0deabef1076ddaed797351ec0202"}, + {file = "types_python_dateutil-2.9.0.20240316-py3-none-any.whl", hash = "sha256:6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b"}, ] [[package]] @@ -6274,6 +6359,24 @@ files = [ {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] +[[package]] +name = "tzlocal" +version = "5.2" +description = "tzinfo object for the local timezone" +optional = true +python-versions = ">=3.8" +files = [ + {file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"}, + {file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"}, +] + +[package.dependencies] +"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} +tzdata = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"] + [[package]] name = "ujson" version = "5.10.0" @@ -6377,13 +6480,13 @@ dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake [[package]] name = "urllib3" -version = "1.26.18" +version = "1.26.19" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, - {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, + {file = "urllib3-1.26.19-py2.py3-none-any.whl", hash = "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3"}, + {file = "urllib3-1.26.19.tar.gz", hash = "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429"}, ] [package.extras] @@ -6463,13 +6566,13 @@ test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)" [[package]] name = "virtualenv" -version = "20.25.1" +version = "20.26.3" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.25.1-py3-none-any.whl", hash = "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a"}, - {file = "virtualenv-20.25.1.tar.gz", hash = "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197"}, + {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, + {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, ] [package.dependencies] @@ -6478,45 +6581,48 @@ filelock = ">=3.12.2,<4" platformdirs = ">=3.9.1,<5" [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] name = "watchdog" -version = "4.0.0" +version = "4.0.1" description = "Filesystem events monitoring" optional = false python-versions = ">=3.8" files = [ - {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:39cb34b1f1afbf23e9562501673e7146777efe95da24fab5707b88f7fb11649b"}, - {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c522392acc5e962bcac3b22b9592493ffd06d1fc5d755954e6be9f4990de932b"}, - {file = "watchdog-4.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6c47bdd680009b11c9ac382163e05ca43baf4127954c5f6d0250e7d772d2b80c"}, - {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8350d4055505412a426b6ad8c521bc7d367d1637a762c70fdd93a3a0d595990b"}, - {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c17d98799f32e3f55f181f19dd2021d762eb38fdd381b4a748b9f5a36738e935"}, - {file = "watchdog-4.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4986db5e8880b0e6b7cd52ba36255d4793bf5cdc95bd6264806c233173b1ec0b"}, - {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11e12fafb13372e18ca1bbf12d50f593e7280646687463dd47730fd4f4d5d257"}, - {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5369136a6474678e02426bd984466343924d1df8e2fd94a9b443cb7e3aa20d19"}, - {file = "watchdog-4.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76ad8484379695f3fe46228962017a7e1337e9acadafed67eb20aabb175df98b"}, - {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:45cc09cc4c3b43fb10b59ef4d07318d9a3ecdbff03abd2e36e77b6dd9f9a5c85"}, - {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eed82cdf79cd7f0232e2fdc1ad05b06a5e102a43e331f7d041e5f0e0a34a51c4"}, - {file = "watchdog-4.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba30a896166f0fee83183cec913298151b73164160d965af2e93a20bbd2ab605"}, - {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d18d7f18a47de6863cd480734613502904611730f8def45fc52a5d97503e5101"}, - {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2895bf0518361a9728773083908801a376743bcc37dfa252b801af8fd281b1ca"}, - {file = "watchdog-4.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87e9df830022488e235dd601478c15ad73a0389628588ba0b028cb74eb72fed8"}, - {file = "watchdog-4.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6e949a8a94186bced05b6508faa61b7adacc911115664ccb1923b9ad1f1ccf7b"}, - {file = "watchdog-4.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6a4db54edea37d1058b08947c789a2354ee02972ed5d1e0dca9b0b820f4c7f92"}, - {file = "watchdog-4.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d31481ccf4694a8416b681544c23bd271f5a123162ab603c7d7d2dd7dd901a07"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8fec441f5adcf81dd240a5fe78e3d83767999771630b5ddfc5867827a34fa3d3"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:6a9c71a0b02985b4b0b6d14b875a6c86ddea2fdbebd0c9a720a806a8bbffc69f"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:557ba04c816d23ce98a06e70af6abaa0485f6d94994ec78a42b05d1c03dcbd50"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d0f9bd1fd919134d459d8abf954f63886745f4660ef66480b9d753a7c9d40927"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f9b2fdca47dc855516b2d66eef3c39f2672cbf7e7a42e7e67ad2cbfcd6ba107d"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:73c7a935e62033bd5e8f0da33a4dcb763da2361921a69a5a95aaf6c93aa03a87"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6a80d5cae8c265842c7419c560b9961561556c4361b297b4c431903f8c33b269"}, - {file = "watchdog-4.0.0-py3-none-win32.whl", hash = "sha256:8f9a542c979df62098ae9c58b19e03ad3df1c9d8c6895d96c0d51da17b243b1c"}, - {file = "watchdog-4.0.0-py3-none-win_amd64.whl", hash = "sha256:f970663fa4f7e80401a7b0cbeec00fa801bf0287d93d48368fc3e6fa32716245"}, - {file = "watchdog-4.0.0-py3-none-win_ia64.whl", hash = "sha256:9a03e16e55465177d416699331b0f3564138f1807ecc5f2de9d55d8f188d08c7"}, - {file = "watchdog-4.0.0.tar.gz", hash = "sha256:e3e7065cbdabe6183ab82199d7a4f6b3ba0a438c5a512a68559846ccb76a78ec"}, + {file = "watchdog-4.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:da2dfdaa8006eb6a71051795856bedd97e5b03e57da96f98e375682c48850645"}, + {file = "watchdog-4.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e93f451f2dfa433d97765ca2634628b789b49ba8b504fdde5837cdcf25fdb53b"}, + {file = "watchdog-4.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ef0107bbb6a55f5be727cfc2ef945d5676b97bffb8425650dadbb184be9f9a2b"}, + {file = "watchdog-4.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:17e32f147d8bf9657e0922c0940bcde863b894cd871dbb694beb6704cfbd2fb5"}, + {file = "watchdog-4.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03e70d2df2258fb6cb0e95bbdbe06c16e608af94a3ffbd2b90c3f1e83eb10767"}, + {file = "watchdog-4.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:123587af84260c991dc5f62a6e7ef3d1c57dfddc99faacee508c71d287248459"}, + {file = "watchdog-4.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:093b23e6906a8b97051191a4a0c73a77ecc958121d42346274c6af6520dec175"}, + {file = "watchdog-4.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:611be3904f9843f0529c35a3ff3fd617449463cb4b73b1633950b3d97fa4bfb7"}, + {file = "watchdog-4.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:62c613ad689ddcb11707f030e722fa929f322ef7e4f18f5335d2b73c61a85c28"}, + {file = "watchdog-4.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d4925e4bf7b9bddd1c3de13c9b8a2cdb89a468f640e66fbfabaf735bd85b3e35"}, + {file = "watchdog-4.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cad0bbd66cd59fc474b4a4376bc5ac3fc698723510cbb64091c2a793b18654db"}, + {file = "watchdog-4.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a3c2c317a8fb53e5b3d25790553796105501a235343f5d2bf23bb8649c2c8709"}, + {file = "watchdog-4.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c9904904b6564d4ee8a1ed820db76185a3c96e05560c776c79a6ce5ab71888ba"}, + {file = "watchdog-4.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:667f3c579e813fcbad1b784db7a1aaa96524bed53437e119f6a2f5de4db04235"}, + {file = "watchdog-4.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d10a681c9a1d5a77e75c48a3b8e1a9f2ae2928eda463e8d33660437705659682"}, + {file = "watchdog-4.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0144c0ea9997b92615af1d94afc0c217e07ce2c14912c7b1a5731776329fcfc7"}, + {file = "watchdog-4.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:998d2be6976a0ee3a81fb8e2777900c28641fb5bfbd0c84717d89bca0addcdc5"}, + {file = "watchdog-4.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e7921319fe4430b11278d924ef66d4daa469fafb1da679a2e48c935fa27af193"}, + {file = "watchdog-4.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:f0de0f284248ab40188f23380b03b59126d1479cd59940f2a34f8852db710625"}, + {file = "watchdog-4.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bca36be5707e81b9e6ce3208d92d95540d4ca244c006b61511753583c81c70dd"}, + {file = "watchdog-4.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ab998f567ebdf6b1da7dc1e5accfaa7c6992244629c0fdaef062f43249bd8dee"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:dddba7ca1c807045323b6af4ff80f5ddc4d654c8bce8317dde1bd96b128ed253"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:4513ec234c68b14d4161440e07f995f231be21a09329051e67a2118a7a612d2d"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_i686.whl", hash = "sha256:4107ac5ab936a63952dea2a46a734a23230aa2f6f9db1291bf171dac3ebd53c6"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:6e8c70d2cd745daec2a08734d9f63092b793ad97612470a0ee4cbb8f5f705c57"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f27279d060e2ab24c0aa98363ff906d2386aa6c4dc2f1a374655d4e02a6c5e5e"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:f8affdf3c0f0466e69f5b3917cdd042f89c8c63aebdb9f7c078996f607cdb0f5"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ac7041b385f04c047fcc2951dc001671dee1b7e0615cde772e84b01fbf68ee84"}, + {file = "watchdog-4.0.1-py3-none-win32.whl", hash = "sha256:206afc3d964f9a233e6ad34618ec60b9837d0582b500b63687e34011e15bb429"}, + {file = "watchdog-4.0.1-py3-none-win_amd64.whl", hash = "sha256:7577b3c43e5909623149f76b099ac49a1a01ca4e167d1785c76eb52fa585745a"}, + {file = "watchdog-4.0.1-py3-none-win_ia64.whl", hash = "sha256:d7b9f5f3299e8dd230880b6c55504a1f69cf1e4316275d1b215ebdd8187ec88d"}, + {file = "watchdog-4.0.1.tar.gz", hash = "sha256:eebaacf674fa25511e8867028d281e602ee6500045b57f43b08778082f7f8b44"}, ] [package.extras] @@ -6622,18 +6728,18 @@ files = [ [[package]] name = "webcolors" -version = "1.13" +version = "24.6.0" description = "A library for working with the color formats defined by HTML and CSS." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "webcolors-1.13-py3-none-any.whl", hash = "sha256:29bc7e8752c0a1bd4a1f03c14d6e6a72e93d82193738fa860cbff59d0fcc11bf"}, - {file = "webcolors-1.13.tar.gz", hash = "sha256:c225b674c83fa923be93d235330ce0300373d02885cef23238813b0d5668304a"}, + {file = "webcolors-24.6.0-py3-none-any.whl", hash = "sha256:8cf5bc7e28defd1d48b9e83d5fc30741328305a8195c29a8e668fa45586568a1"}, + {file = "webcolors-24.6.0.tar.gz", hash = "sha256:1d160d1de46b3e81e58d0a280d0c78b467dc80f47294b91b1ad8029d2cedb55b"}, ] [package.extras] docs = ["furo", "sphinx", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-notfound-page", "sphinxext-opengraph"] -tests = ["pytest", "pytest-cov"] +tests = ["coverage[toml]"] [[package]] name = "webencodings" @@ -6648,17 +6754,17 @@ files = [ [[package]] name = "websocket-client" -version = "1.7.0" +version = "1.8.0" description = "WebSocket client for Python with low level API options" optional = false python-versions = ">=3.8" files = [ - {file = "websocket-client-1.7.0.tar.gz", hash = "sha256:10e511ea3a8c744631d3bd77e61eb17ed09304c413ad42cf6ddfa4c7787e8fe6"}, - {file = "websocket_client-1.7.0-py3-none-any.whl", hash = "sha256:f4c3d22fec12a2461427a29957ff07d35098ee2d976d3ba244e688b8b4057588"}, + {file = "websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526"}, + {file = "websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da"}, ] [package.extras] -docs = ["Sphinx (>=6.0)", "sphinx-rtd-theme (>=1.1.0)"] +docs = ["Sphinx (>=6.0)", "myst-parser (>=2.0.0)", "sphinx-rtd-theme (>=1.1.0)"] optional = ["python-socks", "wsaccel"] test = ["websockets"] @@ -6745,13 +6851,13 @@ files = [ [[package]] name = "werkzeug" -version = "3.0.1" +version = "3.0.3" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.8" files = [ - {file = "werkzeug-3.0.1-py3-none-any.whl", hash = "sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10"}, - {file = "werkzeug-3.0.1.tar.gz", hash = "sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc"}, + {file = "werkzeug-3.0.3-py3-none-any.whl", hash = "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8"}, + {file = "werkzeug-3.0.3.tar.gz", hash = "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18"}, ] [package.dependencies] @@ -6762,13 +6868,13 @@ watchdog = ["watchdog (>=2.3)"] [[package]] name = "widgetsnbextension" -version = "4.0.10" +version = "4.0.11" description = "Jupyter interactive widgets for Jupyter Notebook" optional = false python-versions = ">=3.7" files = [ - {file = "widgetsnbextension-4.0.10-py3-none-any.whl", hash = "sha256:d37c3724ec32d8c48400a435ecfa7d3e259995201fbefa37163124a9fcb393cc"}, - {file = "widgetsnbextension-4.0.10.tar.gz", hash = "sha256:64196c5ff3b9a9183a8e699a4227fb0b7002f252c814098e66c4d1cd0644688f"}, + {file = "widgetsnbextension-4.0.11-py3-none-any.whl", hash = "sha256:55d4d6949d100e0d08b94948a42efc3ed6dfdc0e9468b2c4b128c9a2ce3a7a36"}, + {file = "widgetsnbextension-4.0.11.tar.gz", hash = "sha256:8b22a8f1910bfd188e596fe7fc05dcbd87e810c8a4ba010bdb3da86637398474"}, ] [[package]] @@ -7028,13 +7134,13 @@ multidict = ">=4.0" [[package]] name = "ydb" -version = "3.11.1" +version = "3.12.3" description = "YDB Python SDK" optional = true python-versions = "*" files = [ - {file = "ydb-3.11.1-py2.py3-none-any.whl", hash = "sha256:d9c070ae99692a0f96abd2c21bde9fafbd5e2ebace7dc6a8d796078468c426d0"}, - {file = "ydb-3.11.1.tar.gz", hash = "sha256:eac092e6215c21d74e8db99bc89c1e984828894d7be74bd39f133f0f4069c80d"}, + {file = "ydb-3.12.3-py2.py3-none-any.whl", hash = "sha256:0bb1094d471c47c3da773dc607ae47129899becdcca5756d199e343140599799"}, + {file = "ydb-3.12.3.tar.gz", hash = "sha256:6895e97218d464cb6e46fedebb8e855e385740e61bd700fd26983c9daeb9ba74"}, ] [package.dependencies] @@ -7048,18 +7154,18 @@ yc = ["yandexcloud"] [[package]] name = "zipp" -version = "3.17.0" +version = "3.19.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, - {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, + {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, + {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [[package]] name = "zope-event" @@ -7081,54 +7187,54 @@ test = ["zope.testrunner"] [[package]] name = "zope-interface" -version = "6.2" +version = "6.4.post2" description = "Interfaces for Python" optional = false python-versions = ">=3.7" files = [ - {file = "zope.interface-6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:506f5410b36e5ba494136d9fa04c548eaf1a0d9c442b0b0e7a0944db7620e0ab"}, - {file = "zope.interface-6.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b386b8b9d2b6a5e1e4eadd4e62335571244cb9193b7328c2b6e38b64cfda4f0e"}, - {file = "zope.interface-6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb0b3f2cb606981c7432f690db23506b1db5899620ad274e29dbbbdd740e797"}, - {file = "zope.interface-6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de7916380abaef4bb4891740879b1afcba2045aee51799dfd6d6ca9bdc71f35f"}, - {file = "zope.interface-6.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b240883fb43160574f8f738e6d09ddbdbf8fa3e8cea051603d9edfd947d9328"}, - {file = "zope.interface-6.2-cp310-cp310-win_amd64.whl", hash = "sha256:8af82afc5998e1f307d5e72712526dba07403c73a9e287d906a8aa2b1f2e33dd"}, - {file = "zope.interface-6.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4d45d2ba8195850e3e829f1f0016066a122bfa362cc9dc212527fc3d51369037"}, - {file = "zope.interface-6.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:76e0531d86523be7a46e15d379b0e975a9db84316617c0efe4af8338dc45b80c"}, - {file = "zope.interface-6.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59f7374769b326a217d0b2366f1c176a45a4ff21e8f7cebb3b4a3537077eff85"}, - {file = "zope.interface-6.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25e0af9663eeac6b61b231b43c52293c2cb7f0c232d914bdcbfd3e3bd5c182ad"}, - {file = "zope.interface-6.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e02a6fc1772b458ebb6be1c276528b362041217b9ca37e52ecea2cbdce9fac"}, - {file = "zope.interface-6.2-cp311-cp311-win_amd64.whl", hash = "sha256:02adbab560683c4eca3789cc0ac487dcc5f5a81cc48695ec247f00803cafe2fe"}, - {file = "zope.interface-6.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8f5d2c39f3283e461de3655e03faf10e4742bb87387113f787a7724f32db1e48"}, - {file = "zope.interface-6.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:75d2ec3d9b401df759b87bc9e19d1b24db73083147089b43ae748aefa63067ef"}, - {file = "zope.interface-6.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa994e8937e8ccc7e87395b7b35092818905cf27c651e3ff3e7f29729f5ce3ce"}, - {file = "zope.interface-6.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ede888382882f07b9e4cd942255921ffd9f2901684198b88e247c7eabd27a000"}, - {file = "zope.interface-6.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2606955a06c6852a6cff4abeca38346ed01e83f11e960caa9a821b3626a4467b"}, - {file = "zope.interface-6.2-cp312-cp312-win_amd64.whl", hash = "sha256:ac7c2046d907e3b4e2605a130d162b1b783c170292a11216479bb1deb7cadebe"}, - {file = "zope.interface-6.2-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:febceb04ee7dd2aef08c2ff3d6f8a07de3052fc90137c507b0ede3ea80c21440"}, - {file = "zope.interface-6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fc711acc4a1c702ca931fdbf7bf7c86f2a27d564c85c4964772dadf0e3c52f5"}, - {file = "zope.interface-6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:396f5c94654301819a7f3a702c5830f0ea7468d7b154d124ceac823e2419d000"}, - {file = "zope.interface-6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd374927c00764fcd6fe1046bea243ebdf403fba97a937493ae4be2c8912c2b"}, - {file = "zope.interface-6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a3046e8ab29b590d723821d0785598e0b2e32b636a0272a38409be43e3ae0550"}, - {file = "zope.interface-6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:de125151a53ecdb39df3cb3deb9951ed834dd6a110a9e795d985b10bb6db4532"}, - {file = "zope.interface-6.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f444de0565db46d26c9fa931ca14f497900a295bd5eba480fc3fad25af8c763e"}, - {file = "zope.interface-6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2fefad268ff5c5b314794e27e359e48aeb9c8bb2cbb5748a071757a56f6bb8f"}, - {file = "zope.interface-6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:97785604824981ec8c81850dd25c8071d5ce04717a34296eeac771231fbdd5cd"}, - {file = "zope.interface-6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7b2bed4eea047a949296e618552d3fed00632dc1b795ee430289bdd0e3717f3"}, - {file = "zope.interface-6.2-cp38-cp38-win_amd64.whl", hash = "sha256:d54f66c511ea01b9ef1d1a57420a93fbb9d48a08ec239f7d9c581092033156d0"}, - {file = "zope.interface-6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5ee9789a20b0081dc469f65ff6c5007e67a940d5541419ca03ef20c6213dd099"}, - {file = "zope.interface-6.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af27b3fe5b6bf9cd01b8e1c5ddea0a0d0a1b8c37dc1c7452f1e90bf817539c6d"}, - {file = "zope.interface-6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bce517b85f5debe07b186fc7102b332676760f2e0c92b7185dd49c138734b70"}, - {file = "zope.interface-6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ae9793f114cee5c464cc0b821ae4d36e1eba961542c6086f391a61aee167b6f"}, - {file = "zope.interface-6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e87698e2fea5ca2f0a99dff0a64ce8110ea857b640de536c76d92aaa2a91ff3a"}, - {file = "zope.interface-6.2-cp39-cp39-win_amd64.whl", hash = "sha256:b66335bbdbb4c004c25ae01cc4a54fd199afbc1fd164233813c6d3c2293bb7e1"}, - {file = "zope.interface-6.2.tar.gz", hash = "sha256:3b6c62813c63c543a06394a636978b22dffa8c5410affc9331ce6cdb5bfa8565"}, + {file = "zope.interface-6.4.post2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2eccd5bef45883802848f821d940367c1d0ad588de71e5cabe3813175444202c"}, + {file = "zope.interface-6.4.post2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:762e616199f6319bb98e7f4f27d254c84c5fb1c25c908c2a9d0f92b92fb27530"}, + {file = "zope.interface-6.4.post2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ef8356f16b1a83609f7a992a6e33d792bb5eff2370712c9eaae0d02e1924341"}, + {file = "zope.interface-6.4.post2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e4fa5d34d7973e6b0efa46fe4405090f3b406f64b6290facbb19dcbf642ad6b"}, + {file = "zope.interface-6.4.post2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d22fce0b0f5715cdac082e35a9e735a1752dc8585f005d045abb1a7c20e197f9"}, + {file = "zope.interface-6.4.post2-cp310-cp310-win_amd64.whl", hash = "sha256:97e615eab34bd8477c3f34197a17ce08c648d38467489359cb9eb7394f1083f7"}, + {file = "zope.interface-6.4.post2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:599f3b07bde2627e163ce484d5497a54a0a8437779362395c6b25e68c6590ede"}, + {file = "zope.interface-6.4.post2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:136cacdde1a2c5e5bc3d0b2a1beed733f97e2dad8c2ad3c2e17116f6590a3827"}, + {file = "zope.interface-6.4.post2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47937cf2e7ed4e0e37f7851c76edeb8543ec9b0eae149b36ecd26176ff1ca874"}, + {file = "zope.interface-6.4.post2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f0a6be264afb094975b5ef55c911379d6989caa87c4e558814ec4f5125cfa2e"}, + {file = "zope.interface-6.4.post2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47654177e675bafdf4e4738ce58cdc5c6d6ee2157ac0a78a3fa460942b9d64a8"}, + {file = "zope.interface-6.4.post2-cp311-cp311-win_amd64.whl", hash = "sha256:e2fb8e8158306567a3a9a41670c1ff99d0567d7fc96fa93b7abf8b519a46b250"}, + {file = "zope.interface-6.4.post2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b912750b13d76af8aac45ddf4679535def304b2a48a07989ec736508d0bbfbde"}, + {file = "zope.interface-6.4.post2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4ac46298e0143d91e4644a27a769d1388d5d89e82ee0cf37bf2b0b001b9712a4"}, + {file = "zope.interface-6.4.post2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86a94af4a88110ed4bb8961f5ac72edf782958e665d5bfceaab6bf388420a78b"}, + {file = "zope.interface-6.4.post2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73f9752cf3596771c7726f7eea5b9e634ad47c6d863043589a1c3bb31325c7eb"}, + {file = "zope.interface-6.4.post2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00b5c3e9744dcdc9e84c24ed6646d5cf0cf66551347b310b3ffd70f056535854"}, + {file = "zope.interface-6.4.post2-cp312-cp312-win_amd64.whl", hash = "sha256:551db2fe892fcbefb38f6f81ffa62de11090c8119fd4e66a60f3adff70751ec7"}, + {file = "zope.interface-6.4.post2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96ac6b3169940a8cd57b4f2b8edcad8f5213b60efcd197d59fbe52f0accd66e"}, + {file = "zope.interface-6.4.post2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cebff2fe5dc82cb22122e4e1225e00a4a506b1a16fafa911142ee124febf2c9e"}, + {file = "zope.interface-6.4.post2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33ee982237cffaf946db365c3a6ebaa37855d8e3ca5800f6f48890209c1cfefc"}, + {file = "zope.interface-6.4.post2-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:fbf649bc77510ef2521cf797700b96167bb77838c40780da7ea3edd8b78044d1"}, + {file = "zope.interface-6.4.post2-cp37-cp37m-win_amd64.whl", hash = "sha256:4c0b208a5d6c81434bdfa0f06d9b667e5de15af84d8cae5723c3a33ba6611b82"}, + {file = "zope.interface-6.4.post2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d3fe667935e9562407c2511570dca14604a654988a13d8725667e95161d92e9b"}, + {file = "zope.interface-6.4.post2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a96e6d4074db29b152222c34d7eec2e2db2f92638d2b2b2c704f9e8db3ae0edc"}, + {file = "zope.interface-6.4.post2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:866a0f583be79f0def667a5d2c60b7b4cc68f0c0a470f227e1122691b443c934"}, + {file = "zope.interface-6.4.post2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fe919027f29b12f7a2562ba0daf3e045cb388f844e022552a5674fcdf5d21f1"}, + {file = "zope.interface-6.4.post2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e0343a6e06d94f6b6ac52fbc75269b41dd3c57066541a6c76517f69fe67cb43"}, + {file = "zope.interface-6.4.post2-cp38-cp38-win_amd64.whl", hash = "sha256:dabb70a6e3d9c22df50e08dc55b14ca2a99da95a2d941954255ac76fd6982bc5"}, + {file = "zope.interface-6.4.post2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:706efc19f9679a1b425d6fa2b4bc770d976d0984335eaea0869bd32f627591d2"}, + {file = "zope.interface-6.4.post2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d136e5b8821073e1a09dde3eb076ea9988e7010c54ffe4d39701adf0c303438"}, + {file = "zope.interface-6.4.post2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1730c93a38b5a18d24549bc81613223962a19d457cfda9bdc66e542f475a36f4"}, + {file = "zope.interface-6.4.post2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc2676312cc3468a25aac001ec727168994ea3b69b48914944a44c6a0b251e79"}, + {file = "zope.interface-6.4.post2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a62fd6cd518693568e23e02f41816adedfca637f26716837681c90b36af3671"}, + {file = "zope.interface-6.4.post2-cp39-cp39-win_amd64.whl", hash = "sha256:d3f7e001328bd6466b3414215f66dde3c7c13d8025a9c160a75d7b2687090d15"}, + {file = "zope.interface-6.4.post2.tar.gz", hash = "sha256:1c207e6f6dfd5749a26f5a5fd966602d6b824ec00d2df84a7e9a924e8933654e"}, ] [package.dependencies] setuptools = "*" [package.extras] -docs = ["Sphinx", "repoze.sphinx.autointerface", "sphinx_rtd_theme"] +docs = ["Sphinx", "repoze.sphinx.autointerface", "sphinx-rtd-theme"] test = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] @@ -7142,10 +7248,10 @@ postgresql = ["asyncpg", "sqlalchemy"] redis = ["redis"] sqlite = ["aiosqlite", "sqlalchemy"] stats = ["omegaconf", "opentelemetry-exporter-otlp", "opentelemetry-instrumentation", "requests", "tqdm"] -telegram = ["pytelegrambotapi"] +telegram = ["python-telegram-bot"] ydb = ["six", "ydb"] [metadata] lock-version = "2.0" python-versions = "^3.8.1,!=3.9.7" -content-hash = "bfc9b006110db970767817b6eec3f44194dc36e29748cb319d75876610a2e1a8" +content-hash = "0fea55ff020381487754e65f4630de8bfaedc65c37b6d071763d427f1667b7b3" diff --git a/pyproject.toml b/pyproject.toml index 22635a1f4..a7ac29fb4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,7 +73,7 @@ aiosqlite = { version = "*", optional = true } omegaconf = { version = "*", optional = true } cryptography = { version = "*", optional = true } requests = { version = "*", optional = true } -pytelegrambotapi = { version = "*", optional = true } +python-telegram-bot = { version = "~=21.3", extras = ["all"], optional = true } opentelemetry-instrumentation = { version = "*", optional = true } sqlalchemy = { version = "*", extras = ["asyncio"], optional = true } opentelemetry-exporter-otlp = { version = ">=1.20.0", optional = true } # log body serialization is required @@ -87,7 +87,7 @@ mongodb = ["motor"] mysql = ["sqlalchemy", "asyncmy", "cryptography"] postgresql = ["sqlalchemy", "asyncpg"] ydb = ["ydb", "six"] -telegram = ["pytelegrambotapi"] +telegram = ["python-telegram-bot"] stats = ["opentelemetry-exporter-otlp", "opentelemetry-instrumentation", "requests", "tqdm", "omegaconf"] benchmark = ["pympler", "humanize", "pandas", "altair", "tqdm"] @@ -207,7 +207,6 @@ profile = "black" addopts = "--strict-markers" markers = [ "docker: marks tests as requiring docker containers to work", - "telegram: marks tests as requiring telegram client API token to work", "slow: marks tests as slow (taking more than a minute to complete)", "no_coverage: tests that either cannot run inside the `coverage` workflow or do not affect coverage stats", "all: reserved by allow-skip", diff --git a/scripts/test.py b/scripts/test.py index 1af932f29..4a040099d 100644 --- a/scripts/test.py +++ b/scripts/test.py @@ -12,10 +12,9 @@ def _test(coverage: bool = False, dependencies: bool = False, quick: bool = Fals Run framework tests, located in `tests/` dir, using env defined in `.env_file`. Please keep in mind that: - 1. Skipping `telegram` tests is **always** allowed. - 2. Enabling dependencies is effectively same as enabling docker + 1. Enabling dependencies is effectively same as enabling docker (docker containers **should** be running in that case). - 3. Coverage requires all dependencies and docker (will have no effect otherwise). + 2. Coverage requires all dependencies and docker (will have no effect otherwise). :param coverage: Enable coverage calculation :param dependencies: Disallow skipping tests @@ -39,12 +38,11 @@ def _test(coverage: bool = False, dependencies: bool = False, quick: bool = Fals args = [ "-m", "not no_coverage", - "--allow-skip=telegram", *args, ] elif dependencies: args = [ - "--allow-skip=telegram,docker", + "--allow-skip=docker", *args, ] else: diff --git a/tests/conftest.py b/tests/conftest.py index dd8301879..85ba92404 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,7 @@ import pytest -def pytest_report_header(config, start_path, startdir): +def pytest_report_header(config, start_path): print(f"allow_skip: {config.getoption('--allow-skip') }") diff --git a/tests/messengers/telegram/conftest.py b/tests/messengers/telegram/conftest.py deleted file mode 100644 index 60c3e801d..000000000 --- a/tests/messengers/telegram/conftest.py +++ /dev/null @@ -1,78 +0,0 @@ -import os -import asyncio -import importlib -from pathlib import Path - -import pytest - -from tests.test_utils import get_path_from_tests_to_current_dir - -try: - from dff.utils.testing.telegram import get_bot_user, TelegramClient - - telegram_available = True -except ImportError: - telegram_available = False - -dot_path_to_addon = get_path_from_tests_to_current_dir(__file__, separator=".") - - -@pytest.fixture(scope="session") -def pipeline_tutorial(): - if not telegram_available: - pytest.skip("`telegram` not available.") - yield importlib.import_module(f"tutorials.{dot_path_to_addon}.{'7_polling_setup'}") - - -@pytest.fixture(scope="session") -def session_file(): - dff_root_dir = Path(__file__).parent.parent.parent.parent - file = dff_root_dir / "anon.session" - - if not file.exists(): - pytest.skip(f"Session file does not exist at {str(file)}") - - return str(file) - - -@pytest.fixture(scope="session") -def env_vars(): - env_variables = {"TG_BOT_TOKEN": None, "TG_API_ID": None, "TG_API_HASH": None, "TG_BOT_USERNAME": None} - - for arg in env_variables: - env_variables[arg] = os.getenv(arg) - - if not env_variables[arg]: - pytest.skip(f"`{arg}` is not set", allow_module_level=True) - - yield env_variables - - -@pytest.fixture(scope="session") -def pipeline_instance(env_vars, pipeline_tutorial): - yield pipeline_tutorial.pipeline - - -@pytest.fixture(scope="session") -def document(tmpdir_factory): - filename: Path = tmpdir_factory.mktemp("data").join("file.txt") - with filename.open("w") as f: - f.write("test") - yield filename - - -@pytest.fixture(scope="session") -def api_credentials(env_vars): - yield (int(env_vars["TG_API_ID"]), env_vars["TG_API_HASH"]) - - -@pytest.fixture(scope="session") -def bot_user(api_credentials, env_vars, session_file): - if not telegram_available: - pytest.skip("`telegram` not available.") - client = TelegramClient(session_file, *api_credentials) - yield asyncio.run(get_bot_user(client, env_vars["TG_BOT_USERNAME"])) - - -def pytest_sessionfinish(session, exitstatus): - asyncio.get_event_loop().close() diff --git a/tests/messengers/telegram/test_happy_paths.json b/tests/messengers/telegram/test_happy_paths.json new file mode 100644 index 000000000..203848700 --- /dev/null +++ b/tests/messengers/telegram/test_happy_paths.json @@ -0,0 +1,958 @@ +{ + "1_basic": [ + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 8, 21, 5, 30, tzinfo=UTC), delete_chat_photo=False, entities=(MessageEntity(length=6, offset=0, type=MessageEntityType.BOT_COMMAND),), from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=1, supergroup_chat_created=False, text='/start'), update_id=1)", + "received_message": { + "text": "/start", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVXwsAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5SMF3RlbGVncmFtLl9tZXNzYWdlZW50aXR5lIwNTWVzc2FnZUVudGl0eZSTlCmB\nlH2UKIwPY3VzdG9tX2Vtb2ppX2lklE6MCGxhbmd1YWdllE6MBmxlbmd0aJRLBowGb2Zmc2V0lEsA\naBJoE4wRTWVzc2FnZUVudGl0eVR5cGWUk5SMC2JvdF9jb21tYW5klIWUUpSMA3VybJROjAR1c2Vy\nlE5oG4hoHGhdSwBLBoeUaB59lHVihZSMDmV4dGVybmFsX3JlcGx5lE6MEmZvcnVtX3RvcGljX2Ns\nb3NlZJROjBNmb3J1bV90b3BpY19jcmVhdGVklE6MEmZvcnVtX3RvcGljX2VkaXRlZJROjBRmb3J1\nbV90b3BpY19yZW9wZW5lZJROjA5mb3J3YXJkX29yaWdpbpROjAlmcm9tX3VzZXKUjA50ZWxlZ3Jh\nbS5fdXNlcpRoEJOUKYGUfZQojBhhZGRlZF90b19hdHRhY2htZW50X21lbnWUTowXY2FuX2Nvbm5l\nY3RfdG9fYnVzaW5lc3OUTowPY2FuX2pvaW5fZ3JvdXBzlE6MG2Nhbl9yZWFkX2FsbF9ncm91cF9t\nZXNzYWdlc5ROaAtoDGgNSyqMBmlzX2JvdJSJjAppc19wcmVtaXVtlE6MDWxhbmd1YWdlX2NvZGWU\njAJlbpRoD2gQjBdzdXBwb3J0c19pbmxpbmVfcXVlcmllc5ROaBloGmgbiGgcSyqFlGgefZR1YowE\nZ2FtZZROjBpnZW5lcmFsX2ZvcnVtX3RvcGljX2hpZGRlbpROjBxnZW5lcmFsX2ZvcnVtX3RvcGlj\nX3VuaGlkZGVulE6MCGdpdmVhd2F5lE6MEmdpdmVhd2F5X2NvbXBsZXRlZJROjBBnaXZlYXdheV9j\ncmVhdGVklE6MEGdpdmVhd2F5X3dpbm5lcnOUTowSZ3JvdXBfY2hhdF9jcmVhdGVklImMEWhhc19t\nZWRpYV9zcG9pbGVylE6MFWhhc19wcm90ZWN0ZWRfY29udGVudJROjAdpbnZvaWNllE6MFGlzX2F1\ndG9tYXRpY19mb3J3YXJklE6MD2lzX2Zyb21fb2ZmbGluZZROjBBpc190b3BpY19tZXNzYWdllE6M\nEGxlZnRfY2hhdF9tZW1iZXKUTowUbGlua19wcmV2aWV3X29wdGlvbnOUTowIbG9jYXRpb26UTowO\nbWVkaWFfZ3JvdXBfaWSUTowhbWVzc2FnZV9hdXRvX2RlbGV0ZV90aW1lcl9jaGFuZ2VklE6MEW1l\nc3NhZ2VfdGhyZWFkX2lklE6MFG1pZ3JhdGVfZnJvbV9jaGF0X2lklE6MEm1pZ3JhdGVfdG9fY2hh\ndF9pZJROjBBuZXdfY2hhdF9tZW1iZXJzlCmMDm5ld19jaGF0X3Bob3RvlCmMDm5ld19jaGF0X3Rp\ndGxllE6MDXBhc3Nwb3J0X2RhdGGUTowFcGhvdG+UKYwOcGlubmVkX21lc3NhZ2WUTowEcG9sbJRO\njBlwcm94aW1pdHlfYWxlcnRfdHJpZ2dlcmVklE6MBXF1b3RllE6MDHJlcGx5X21hcmt1cJROjBBy\nZXBseV90b19tZXNzYWdllE6MDnJlcGx5X3RvX3N0b3J5lE6MEnNlbmRlcl9ib29zdF9jb3VudJRO\njBNzZW5kZXJfYnVzaW5lc3NfYm90lE6MC3NlbmRlcl9jaGF0lE6MGHNob3dfY2FwdGlvbl9hYm92\nZV9tZWRpYZROjAdzdGlja2VylE6MBXN0b3J5lE6MEnN1Y2Nlc3NmdWxfcGF5bWVudJROjBdzdXBl\ncmdyb3VwX2NoYXRfY3JlYXRlZJSJjAR0ZXh0lIwGL3N0YXJ0lIwMdXNlcnNfc2hhcmVklE6MBXZl\nbnVllE6MB3ZpYV9ib3SUTowFdmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0\nX3BhcnRpY2lwYW50c19pbnZpdGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2No\nYXRfc3RhcnRlZJROjAp2aWRlb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0\nZV9hY2Nlc3NfYWxsb3dlZJROjARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZST\nlEMKB+gFCBUFHgAAAJSMBHB5dHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLAWgbiGgc\nSwFoCYaUaB59lHVijBBtZXNzYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSU\nTowObXlfY2hhdF9tZW1iZXKUTmiVTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5\nlE6MEnJlbW92ZWRfY2hhdF9ib29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwFo\nG4hoHEsBhZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Hi", + "attachments": null, + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, 'Hi', parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 8, 21, 5, 31, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=2, supergroup_chat_created=False, text='Hi'), update_id=2)", + "received_message": { + "text": "Hi", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVpQoAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpROjAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0\nX2NyZWF0ZWSUiYwEdGV4dJSMAkhplIwMdXNlcnNfc2hhcmVklE6MBXZlbnVllE6MB3ZpYV9ib3SU\nTowFdmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0X3BhcnRpY2lwYW50c19p\nbnZpdGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2NoYXRfc3RhcnRlZJROjAp2\naWRlb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0ZV9hY2Nlc3NfYWxsb3dl\nZJROjARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZSTlEMKB+gFCBUFHwAAAJSM\nBHB5dHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLAmgbiGgcSwJoCYaUaB59lHVijBBt\nZXNzYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowObXlfY2hhdF9tZW1i\nZXKUTmiCTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6MEnJlbW92ZWRfY2hh\ndF9ib29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwJoG4hoHEsChZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Hi", + "attachments": null, + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, 'Hi', parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)" + ] + } + ], + "2_attachments": [ + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 15, 19, 0, 14, tzinfo=UTC), delete_chat_photo=False, entities=(MessageEntity(length=6, offset=0, type=MessageEntityType.BOT_COMMAND),), from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=1, supergroup_chat_created=False, text='/start'), update_id=1)", + "received_message": { + "text": "/start", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVXwsAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5SMF3RlbGVncmFtLl9tZXNzYWdlZW50aXR5lIwNTWVzc2FnZUVudGl0eZSTlCmB\nlH2UKIwPY3VzdG9tX2Vtb2ppX2lklE6MCGxhbmd1YWdllE6MBmxlbmd0aJRLBowGb2Zmc2V0lEsA\naBJoE4wRTWVzc2FnZUVudGl0eVR5cGWUk5SMC2JvdF9jb21tYW5klIWUUpSMA3VybJROjAR1c2Vy\nlE5oG4hoHGhdSwBLBoeUaB59lHVihZSMDmV4dGVybmFsX3JlcGx5lE6MEmZvcnVtX3RvcGljX2Ns\nb3NlZJROjBNmb3J1bV90b3BpY19jcmVhdGVklE6MEmZvcnVtX3RvcGljX2VkaXRlZJROjBRmb3J1\nbV90b3BpY19yZW9wZW5lZJROjA5mb3J3YXJkX29yaWdpbpROjAlmcm9tX3VzZXKUjA50ZWxlZ3Jh\nbS5fdXNlcpRoEJOUKYGUfZQojBhhZGRlZF90b19hdHRhY2htZW50X21lbnWUTowXY2FuX2Nvbm5l\nY3RfdG9fYnVzaW5lc3OUTowPY2FuX2pvaW5fZ3JvdXBzlE6MG2Nhbl9yZWFkX2FsbF9ncm91cF9t\nZXNzYWdlc5ROaAtoDGgNSyqMBmlzX2JvdJSJjAppc19wcmVtaXVtlE6MDWxhbmd1YWdlX2NvZGWU\njAJlbpRoD2gQjBdzdXBwb3J0c19pbmxpbmVfcXVlcmllc5ROaBloGmgbiGgcSyqFlGgefZR1YowE\nZ2FtZZROjBpnZW5lcmFsX2ZvcnVtX3RvcGljX2hpZGRlbpROjBxnZW5lcmFsX2ZvcnVtX3RvcGlj\nX3VuaGlkZGVulE6MCGdpdmVhd2F5lE6MEmdpdmVhd2F5X2NvbXBsZXRlZJROjBBnaXZlYXdheV9j\ncmVhdGVklE6MEGdpdmVhd2F5X3dpbm5lcnOUTowSZ3JvdXBfY2hhdF9jcmVhdGVklImMEWhhc19t\nZWRpYV9zcG9pbGVylE6MFWhhc19wcm90ZWN0ZWRfY29udGVudJROjAdpbnZvaWNllE6MFGlzX2F1\ndG9tYXRpY19mb3J3YXJklE6MD2lzX2Zyb21fb2ZmbGluZZROjBBpc190b3BpY19tZXNzYWdllE6M\nEGxlZnRfY2hhdF9tZW1iZXKUTowUbGlua19wcmV2aWV3X29wdGlvbnOUTowIbG9jYXRpb26UTowO\nbWVkaWFfZ3JvdXBfaWSUTowhbWVzc2FnZV9hdXRvX2RlbGV0ZV90aW1lcl9jaGFuZ2VklE6MEW1l\nc3NhZ2VfdGhyZWFkX2lklE6MFG1pZ3JhdGVfZnJvbV9jaGF0X2lklE6MEm1pZ3JhdGVfdG9fY2hh\ndF9pZJROjBBuZXdfY2hhdF9tZW1iZXJzlCmMDm5ld19jaGF0X3Bob3RvlCmMDm5ld19jaGF0X3Rp\ndGxllE6MDXBhc3Nwb3J0X2RhdGGUTowFcGhvdG+UKYwOcGlubmVkX21lc3NhZ2WUTowEcG9sbJRO\njBlwcm94aW1pdHlfYWxlcnRfdHJpZ2dlcmVklE6MBXF1b3RllE6MDHJlcGx5X21hcmt1cJROjBBy\nZXBseV90b19tZXNzYWdllE6MDnJlcGx5X3RvX3N0b3J5lE6MEnNlbmRlcl9ib29zdF9jb3VudJRO\njBNzZW5kZXJfYnVzaW5lc3NfYm90lE6MC3NlbmRlcl9jaGF0lE6MGHNob3dfY2FwdGlvbl9hYm92\nZV9tZWRpYZROjAdzdGlja2VylE6MBXN0b3J5lE6MEnN1Y2Nlc3NmdWxfcGF5bWVudJROjBdzdXBl\ncmdyb3VwX2NoYXRfY3JlYXRlZJSJjAR0ZXh0lIwGL3N0YXJ0lIwMdXNlcnNfc2hhcmVklE6MBXZl\nbnVllE6MB3ZpYV9ib3SUTowFdmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0\nX3BhcnRpY2lwYW50c19pbnZpdGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2No\nYXRfc3RhcnRlZJROjAp2aWRlb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0\nZV9hY2Nlc3NfYWxsb3dlZJROjARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZST\nlEMKB+gFDxMADgAAAJSMBHB5dHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLAWgbiGgc\nSwFoCYaUaB59lHVijBBtZXNzYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSU\nTowObXlfY2hhdF9tZW1iZXKUTmiVTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5\nlE6MEnJlbW92ZWRfY2hhdF9ib29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwFo\nG4hoHEsBhZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Type \"location\", \"contact\", \"poll\", \"sticker\", \"audio\", \"video\", \"animation\", \"image\", \"document\", \"voice_message\", \"video_message\" or \"media_group\" to receive a corresponding attachment!", + "attachments": null, + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, 'Type \"location\", \"contact\", \"poll\", \"sticker\", \"audio\", \"video\", \"animation\", \"image\", \"document\", \"voice_message\", \"video_message\" or \"media_group\" to receive a corresponding attachment!', parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 15, 19, 0, 25, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=2, supergroup_chat_created=False, text='location'), update_id=2)", + "received_message": { + "text": "location", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVogoAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpROjAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0\nX2NyZWF0ZWSUiYwEdGV4dJRodowMdXNlcnNfc2hhcmVklE6MBXZlbnVllE6MB3ZpYV9ib3SUTowF\ndmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0X3BhcnRpY2lwYW50c19pbnZp\ndGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2NoYXRfc3RhcnRlZJROjAp2aWRl\nb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0ZV9hY2Nlc3NfYWxsb3dlZJRO\njARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZSTlEMKB+gFDxMAGQAAAJSMBHB5\ndHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLAmgbiGgcSwJoCYaUaB59lHVijBBtZXNz\nYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowObXlfY2hhdF9tZW1iZXKU\nTmiCTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6MEnJlbW92ZWRfY2hhdF9i\nb29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwJoG4hoHEsChZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Here's your location!", + "attachments": [ + { + "dff_attachment_type": "location", + "longitude": 3.916667, + "latitude": 50.65 + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your location!\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)", + "send_location(42, 50.65, 3.916667, horizontal_accuracy=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None)" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 15, 19, 0, 32, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=3, supergroup_chat_created=False, text='contact'), update_id=3)", + "received_message": { + "text": "contact", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVogoAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpROjAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0\nX2NyZWF0ZWSUiYwEdGV4dJRoSYwMdXNlcnNfc2hhcmVklE6MBXZlbnVllE6MB3ZpYV9ib3SUTowF\ndmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0X3BhcnRpY2lwYW50c19pbnZp\ndGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2NoYXRfc3RhcnRlZJROjAp2aWRl\nb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0ZV9hY2Nlc3NfYWxsb3dlZJRO\njARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZSTlEMKB+gFDxMAIAAAAJSMBHB5\ndHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLA2gbiGgcSwNoCYaUaB59lHVijBBtZXNz\nYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowObXlfY2hhdF9tZW1iZXKU\nTmiCTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6MEnJlbW92ZWRfY2hhdF9i\nb29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwNoG4hoHEsDhZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Here's your contact!", + "attachments": [ + { + "dff_attachment_type": "contact", + "phone_number": "8-900-555-35-35", + "first_name": "Hope", + "last_name": "Credit" + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your contact!\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)", + "send_contact(42, '8-900-555-35-35', 'Hope', 'Credit', vcard=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None)" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 15, 19, 0, 36, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=4, supergroup_chat_created=False, text='poll'), update_id=4)", + "received_message": { + "text": "poll", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVogoAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpROjAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0\nX2NyZWF0ZWSUiYwEdGV4dJRogowMdXNlcnNfc2hhcmVklE6MBXZlbnVllE6MB3ZpYV9ib3SUTowF\ndmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0X3BhcnRpY2lwYW50c19pbnZp\ndGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2NoYXRfc3RhcnRlZJROjAp2aWRl\nb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0ZV9hY2Nlc3NfYWxsb3dlZJRO\njARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZSTlEMKB+gFDxMAJAAAAJSMBHB5\ndHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLBGgbiGgcSwRoCYaUaB59lHVijBBtZXNz\nYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowObXlfY2hhdF9tZW1iZXKU\nTmiCTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6MEnJlbW92ZWRfY2hhdF9i\nb29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwRoG4hoHEsEhZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Here's your poll!", + "attachments": [ + { + "dff_attachment_type": "poll", + "question": "What is the poll question?", + "options": [ + { + "text": "This one!", + "votes": 0, + "dff_attachment_type": "poll_option" + }, + { + "text": "Not this one :(", + "votes": 0, + "dff_attachment_type": "poll_option" + } + ] + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your poll!\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)", + "send_poll(42, 'What is the poll question?', ['This one!', 'Not this one :('], is_anonymous=None, type=None, allows_multiple_answers=None, correct_option_id=None, explanation=None, explanation_parse_mode=None, open_period=None, is_closed=None, disable_notification=None, protect_content=None, reply_markup=None, question_parse_mode=None, message_effect_id=None, reply_to_message_id=None)" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 15, 19, 0, 43, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=5, supergroup_chat_created=False, text='sticker'), update_id=5)", + "received_message": { + "text": "sticker", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVogoAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpROjAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0\nX2NyZWF0ZWSUiYwEdGV4dJRojIwMdXNlcnNfc2hhcmVklE6MBXZlbnVllE6MB3ZpYV9ib3SUTowF\ndmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0X3BhcnRpY2lwYW50c19pbnZp\ndGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2NoYXRfc3RhcnRlZJROjAp2aWRl\nb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0ZV9hY2Nlc3NfYWxsb3dlZJRO\njARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZSTlEMKB+gFDxMAKwAAAJSMBHB5\ndHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLBWgbiGgcSwVoCYaUaB59lHVijBBtZXNz\nYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowObXlfY2hhdF9tZW1iZXKU\nTmiCTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6MEnJlbW92ZWRfY2hhdF9i\nb29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwVoG4hoHEsFhZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Here's your sticker!", + "attachments": [ + { + "dff_attachment_type": "sticker", + "source": null, + "use_cache": true, + "cached_filename": null, + "id": "CAACAgIAAxkBAAErAAFXZibO5ksphCKSXSe1CYiw5588yqsAAkEAAzyKVxogmx2BPCogYDQE", + "caption": "A sticker I've just found" + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your sticker!\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)", + "send_sticker(42, 'CAACAgIAAxkBAAErAAFXZibO5ksphCKSXSe1CYiw5588yqsAAkEAAzyKVxogmx2BPCogYDQE', emoji=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None)" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 15, 19, 0, 46, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=6, supergroup_chat_created=False, text='audio'), update_id=6)", + "received_message": { + "text": "audio", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVogoAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpROjAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0\nX2NyZWF0ZWSUiYwEdGV4dJRoP4wMdXNlcnNfc2hhcmVklE6MBXZlbnVllE6MB3ZpYV9ib3SUTowF\ndmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0X3BhcnRpY2lwYW50c19pbnZp\ndGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2NoYXRfc3RhcnRlZJROjAp2aWRl\nb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0ZV9hY2Nlc3NfYWxsb3dlZJRO\njARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZSTlEMKB+gFDxMALgAAAJSMBHB5\ndHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLBmgbiGgcSwZoCYaUaB59lHVijBBtZXNz\nYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowObXlfY2hhdF9tZW1iZXKU\nTmiCTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6MEnJlbW92ZWRfY2hhdF9i\nb29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwZoG4hoHEsGhZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Here's your audio!", + "attachments": [ + { + "dff_attachment_type": "audio", + "source": "https://github.com/deeppavlov/dialog_flow_framework/wiki/example_attachments/separation-william-king.mp3", + "use_cache": true, + "cached_filename": "/tmp/dff-cache-LongpollingInterface/9130a836-ac1c-5989-bb12-4e831c89f524", + "id": null, + "caption": "Separation melody by William King", + "filename": "separation-william-king.mp3" + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your audio!\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)", + "send_audio(42, '75ff19e65eef262114e1a6d93794ed8b4af6135a0cd0620f58023fd5b57204f4', caption='Separation melody by William King', parse_mode=None, performer=None, title=None, disable_notification=None, protect_content=None, reply_markup=None, thumbnail=None, message_effect_id=None, reply_to_message_id=None, filename='separation-william-king.mp3')" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 15, 19, 1, 4, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=7, supergroup_chat_created=False, text='video'), update_id=7)", + "received_message": { + "text": "video", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVogoAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpROjAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0\nX2NyZWF0ZWSUiYwEdGV4dJSMBXZpZGVvlIwMdXNlcnNfc2hhcmVklE6MBXZlbnVllE6MB3ZpYV9i\nb3SUTmiRTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0X3BhcnRpY2lwYW50c19pbnZp\ndGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2NoYXRfc3RhcnRlZJROjAp2aWRl\nb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0ZV9hY2Nlc3NfYWxsb3dlZJRO\njARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZSTlEMKB+gFDxMBBAAAAJSMBHB5\ndHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLB2gbiGgcSwdoCYaUaB59lHVijBBtZXNz\nYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowObXlfY2hhdF9tZW1iZXKU\nTmiCTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6MEnJlbW92ZWRfY2hhdF9i\nb29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwdoG4hoHEsHhZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Here's your video!", + "attachments": [ + { + "dff_attachment_type": "video", + "source": "https://github.com/deeppavlov/dialog_flow_framework/wiki/example_attachments/crownfall-lags-nkognit0.mp4", + "use_cache": true, + "cached_filename": "/tmp/dff-cache-LongpollingInterface/8eeccc49-60ae-5e50-8699-cce6cc4144cc", + "id": null, + "caption": "Epic Dota2 gameplay by Nkognit0", + "filename": "crownfall-lags-nkognit0.mp4" + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your video!\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)", + "send_video(42, '11d3472ad8534d632beca6a452e2dc03b7ec9f4aba19fbb3346da43bac7389d6', caption='Epic Dota2 gameplay by Nkognit0', parse_mode=None, supports_streaming=None, disable_notification=None, protect_content=None, reply_markup=None, has_spoiler=None, thumbnail=None, message_effect_id=None, show_caption_above_media=None, reply_to_message_id=None, filename='crownfall-lags-nkognit0.mp4')" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 15, 19, 1, 22, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=8, supergroup_chat_created=False, text='animation'), update_id=8)", + "received_message": { + "text": "animation", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVogoAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpROjAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0\nX2NyZWF0ZWSUiYwEdGV4dJRoPowMdXNlcnNfc2hhcmVklE6MBXZlbnVllE6MB3ZpYV9ib3SUTowF\ndmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0X3BhcnRpY2lwYW50c19pbnZp\ndGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2NoYXRfc3RhcnRlZJROjAp2aWRl\nb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0ZV9hY2Nlc3NfYWxsb3dlZJRO\njARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZSTlEMKB+gFDxMBFgAAAJSMBHB5\ndHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLCGgbiGgcSwhoCYaUaB59lHVijBBtZXNz\nYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowObXlfY2hhdF9tZW1iZXKU\nTmiCTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6MEnJlbW92ZWRfY2hhdF9i\nb29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwhoG4hoHEsIhZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Here's your animation!", + "attachments": [ + { + "dff_attachment_type": "animation", + "source": "https://github.com/deeppavlov/dialog_flow_framework/wiki/example_attachments/hong-kong-simplyart4794.gif", + "use_cache": true, + "cached_filename": "/tmp/dff-cache-LongpollingInterface/68ffd3ce-1c85-5e63-9aa1-aaa9347ccd63", + "id": null, + "caption": "Hong Kong skyscraper views by Simplyart4794", + "filename": "hong-kong-simplyart4794.gif" + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your animation!\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)", + "send_animation(42, '033391bab1eaefd6d8aa6ceb667b5dbaada7c4d6b1649a726541924a74539dc5', caption='Hong Kong skyscraper views by Simplyart4794', parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, has_spoiler=None, thumbnail=None, message_effect_id=None, show_caption_above_media=None, reply_to_message_id=None, filename='hong-kong-simplyart4794.gif')" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 15, 19, 1, 35, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=9, supergroup_chat_created=False, text='image'), update_id=9)", + "received_message": { + "text": "image", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVqAoAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpROjAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0\nX2NyZWF0ZWSUiYwEdGV4dJSMBWltYWdllIwMdXNlcnNfc2hhcmVklE6MBXZlbnVllE6MB3ZpYV9i\nb3SUTowFdmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0X3BhcnRpY2lwYW50\nc19pbnZpdGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2NoYXRfc3RhcnRlZJRO\njAp2aWRlb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0ZV9hY2Nlc3NfYWxs\nb3dlZJROjARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZSTlEMKB+gFDxMBIwAA\nAJSMBHB5dHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLCWgbiGgcSwloCYaUaB59lHVi\njBBtZXNzYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowObXlfY2hhdF9t\nZW1iZXKUTmiCTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6MEnJlbW92ZWRf\nY2hhdF9ib29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwloG4hoHEsJhZRoHn2U\ndWIu\n" + }, + "response_message": { + "text": "Here's your image!", + "attachments": [ + { + "dff_attachment_type": "image", + "source": "https://github.com/deeppavlov/dialog_flow_framework/wiki/example_attachments/deeppavlov.png", + "use_cache": true, + "cached_filename": "/tmp/dff-cache-LongpollingInterface/f5b9f966-df04-50fa-b6e1-e46fccd889bc", + "id": null, + "caption": "DeepPavlov logo", + "filename": "deeppavlov.png" + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your image!\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)", + "send_photo(42, '9f39f64560e6415032325cae1fec1ca06b3cc1a3549208a8a35564c0d3749062', caption='DeepPavlov logo', parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, has_spoiler=None, message_effect_id=None, reply_to_message_id=None, filename='deeppavlov.png')" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 15, 19, 2, 19, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=10, supergroup_chat_created=False, text='document'), update_id=10)", + "received_message": { + "text": "document", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVogoAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpROjAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0\nX2NyZWF0ZWSUiYwEdGV4dJRoTIwMdXNlcnNfc2hhcmVklE6MBXZlbnVllE6MB3ZpYV9ib3SUTowF\ndmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0X3BhcnRpY2lwYW50c19pbnZp\ndGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2NoYXRfc3RhcnRlZJROjAp2aWRl\nb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0ZV9hY2Nlc3NfYWxsb3dlZJRO\njARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZSTlEMKB+gFDxMCEwAAAJSMBHB5\ndHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLCmgbiGgcSwpoCYaUaB59lHVijBBtZXNz\nYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowObXlfY2hhdF9tZW1iZXKU\nTmiCTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6MEnJlbW92ZWRfY2hhdF9i\nb29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwpoG4hoHEsKhZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Here's your document!", + "attachments": [ + { + "dff_attachment_type": "document", + "source": "https://github.com/deeppavlov/dialog_flow_framework/wiki/example_attachments/deeppavlov-article.pdf", + "use_cache": true, + "cached_filename": "/tmp/dff-cache-LongpollingInterface/ff2b4361-417f-5fa1-be67-79e68a3f2e80", + "id": null, + "caption": "DeepPavlov article", + "filename": "deeppavlov-article.pdf" + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your document!\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)", + "send_document(42, '08a7a36671950baba722d94a87dea286f03d7a6f7d0c32d5707d877cd211739a', caption='DeepPavlov article', parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, thumbnail=None, message_effect_id=None, reply_to_message_id=None, filename='deeppavlov-article.pdf')" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 15, 19, 2, 46, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=11, supergroup_chat_created=False, text='voice_message'), update_id=11)", + "received_message": { + "text": "voice_message", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVsAoAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpROjAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0\nX2NyZWF0ZWSUiYwEdGV4dJSMDXZvaWNlX21lc3NhZ2WUjAx1c2Vyc19zaGFyZWSUTowFdmVudWWU\nTowHdmlhX2JvdJROjAV2aWRlb5ROjBB2aWRlb19jaGF0X2VuZGVklE6MH3ZpZGVvX2NoYXRfcGFy\ndGljaXBhbnRzX2ludml0ZWSUTowUdmlkZW9fY2hhdF9zY2hlZHVsZWSUTowSdmlkZW9fY2hhdF9z\ndGFydGVklE6MCnZpZGVvX25vdGWUTowFdm9pY2WUTowMd2ViX2FwcF9kYXRhlE6MFHdyaXRlX2Fj\nY2Vzc19hbGxvd2VklE6MBGNoYXSUaAmMBGRhdGWUjAhkYXRldGltZZSMCGRhdGV0aW1llJOUQwoH\n6AUPEwIuAAAAlIwEcHl0epSMBF9VVEOUk5QpUpSGlFKUjAptZXNzYWdlX2lklEsLaBuIaBxLC2gJ\nhpRoHn2UdWKMEG1lc3NhZ2VfcmVhY3Rpb26UTowWbWVzc2FnZV9yZWFjdGlvbl9jb3VudJROjA5t\neV9jaGF0X21lbWJlcpROaIJOjAtwb2xsX2Fuc3dlcpROjBJwcmVfY2hlY2tvdXRfcXVlcnmUTowS\ncmVtb3ZlZF9jaGF0X2Jvb3N0lE6MDnNoaXBwaW5nX3F1ZXJ5lE6MCXVwZGF0ZV9pZJRLC2gbiGgc\nSwuFlGgefZR1Yi4=\n" + }, + "response_message": { + "text": "Here's your voice message!", + "attachments": [ + { + "dff_attachment_type": "voice_message", + "source": "https://github.com/deeppavlov/dialog_flow_framework/wiki/example_attachments/separation-william-king.mp3", + "use_cache": true, + "cached_filename": "/tmp/dff-cache-LongpollingInterface/9130a836-ac1c-5989-bb12-4e831c89f524", + "id": null + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your voice message!\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)", + "send_voice(42, '75ff19e65eef262114e1a6d93794ed8b4af6135a0cd0620f58023fd5b57204f4', caption=None, parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, filename=None)" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 15, 19, 3, 16, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=12, supergroup_chat_created=False, text='video_message'), update_id=12)", + "received_message": { + "text": "video_message", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVsAoAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpROjAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0\nX2NyZWF0ZWSUiYwEdGV4dJSMDXZpZGVvX21lc3NhZ2WUjAx1c2Vyc19zaGFyZWSUTowFdmVudWWU\nTowHdmlhX2JvdJROjAV2aWRlb5ROjBB2aWRlb19jaGF0X2VuZGVklE6MH3ZpZGVvX2NoYXRfcGFy\ndGljaXBhbnRzX2ludml0ZWSUTowUdmlkZW9fY2hhdF9zY2hlZHVsZWSUTowSdmlkZW9fY2hhdF9z\ndGFydGVklE6MCnZpZGVvX25vdGWUTowFdm9pY2WUTowMd2ViX2FwcF9kYXRhlE6MFHdyaXRlX2Fj\nY2Vzc19hbGxvd2VklE6MBGNoYXSUaAmMBGRhdGWUjAhkYXRldGltZZSMCGRhdGV0aW1llJOUQwoH\n6AUPEwMQAAAAlIwEcHl0epSMBF9VVEOUk5QpUpSGlFKUjAptZXNzYWdlX2lklEsMaBuIaBxLDGgJ\nhpRoHn2UdWKMEG1lc3NhZ2VfcmVhY3Rpb26UTowWbWVzc2FnZV9yZWFjdGlvbl9jb3VudJROjA5t\neV9jaGF0X21lbWJlcpROaIJOjAtwb2xsX2Fuc3dlcpROjBJwcmVfY2hlY2tvdXRfcXVlcnmUTowS\ncmVtb3ZlZF9jaGF0X2Jvb3N0lE6MDnNoaXBwaW5nX3F1ZXJ5lE6MCXVwZGF0ZV9pZJRLDGgbiGgc\nSwyFlGgefZR1Yi4=\n" + }, + "response_message": { + "text": "Here's your video message!", + "attachments": [ + { + "dff_attachment_type": "video_message", + "source": "https://github.com/deeppavlov/dialog_flow_framework/wiki/example_attachments/crownfall-lags-nkognit0.mp4", + "use_cache": true, + "cached_filename": "/tmp/dff-cache-LongpollingInterface/8eeccc49-60ae-5e50-8699-cce6cc4144cc", + "id": null + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your video message!\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)", + "send_video_note(42, '11d3472ad8534d632beca6a452e2dc03b7ec9f4aba19fbb3346da43bac7389d6', disable_notification=None, protect_content=None, reply_markup=None, thumbnail=None, message_effect_id=None, reply_to_message_id=None, filename=None)" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 15, 19, 2, 32, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=13, supergroup_chat_created=False, text='media_group'), update_id=13)", + "received_message": { + "text": "media_group", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVrgoAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpROjAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0\nX2NyZWF0ZWSUiYwEdGV4dJSMC21lZGlhX2dyb3VwlIwMdXNlcnNfc2hhcmVklE6MBXZlbnVllE6M\nB3ZpYV9ib3SUTowFdmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0X3BhcnRp\nY2lwYW50c19pbnZpdGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2NoYXRfc3Rh\ncnRlZJROjAp2aWRlb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0ZV9hY2Nl\nc3NfYWxsb3dlZJROjARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZSTlEMKB+gF\nDxMCIAAAAJSMBHB5dHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLDWgbiGgcSw1oCYaU\naB59lHVijBBtZXNzYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowObXlf\nY2hhdF9tZW1iZXKUTmiCTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6MEnJl\nbW92ZWRfY2hhdF9ib29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSw1oG4hoHEsN\nhZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Here's your media group!", + "attachments": [ + { + "dff_attachment_type": "media_group", + "group": [ + { + "dff_attachment_type": "image", + "source": "https://github.com/deeppavlov/dialog_flow_framework/wiki/example_attachments/deeppavlov.png", + "use_cache": true, + "cached_filename": "/tmp/dff-cache-LongpollingInterface/f5b9f966-df04-50fa-b6e1-e46fccd889bc", + "id": null, + "caption": "DeepPavlov logo", + "filename": "deeppavlov.png" + }, + { + "dff_attachment_type": "video", + "source": "https://github.com/deeppavlov/dialog_flow_framework/wiki/example_attachments/crownfall-lags-nkognit0.mp4", + "use_cache": true, + "cached_filename": "/tmp/dff-cache-LongpollingInterface/8eeccc49-60ae-5e50-8699-cce6cc4144cc", + "id": null, + "caption": "Epic Dota2 gameplay by Nkognit0", + "filename": "crownfall-lags-nkognit0.mp4" + } + ] + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your media group!\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)", + "send_media_group(42, [InputMediaPhoto(data='9f39f64560e6415032325cae1fec1ca06b3cc1a3549208a8a35564c0d3749062', type=), InputMediaVideo(data='11d3472ad8534d632beca6a452e2dc03b7ec9f4aba19fbb3346da43bac7389d6', type=)], caption=None, disable_notification=None, protect_content=None, message_effect_id=None, reply_to_message_id=None, parse_mode=None)" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 15, 19, 2, 46, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=14, supergroup_chat_created=False, text='something else'), update_id=14)", + "received_message": { + "text": "something else", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVsQoAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpROjAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0\nX2NyZWF0ZWSUiYwEdGV4dJSMDnNvbWV0aGluZyBlbHNllIwMdXNlcnNfc2hhcmVklE6MBXZlbnVl\nlE6MB3ZpYV9ib3SUTowFdmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0X3Bh\ncnRpY2lwYW50c19pbnZpdGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2NoYXRf\nc3RhcnRlZJROjAp2aWRlb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0ZV9h\nY2Nlc3NfYWxsb3dlZJROjARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZSTlEMK\nB+gFDxMCLgAAAJSMBHB5dHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLDmgbiGgcSw5o\nCYaUaB59lHVijBBtZXNzYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowO\nbXlfY2hhdF9tZW1iZXKUTmiCTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6M\nEnJlbW92ZWRfY2hhdF9ib29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSw5oG4ho\nHEsOhZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Unknown attachment type, try again! Supported attachments are: \"location\", \"contact\", \"poll\", \"sticker\", \"audio\", \"video\", \"animation\", \"image\", \"document\", \"voice_message\", \"video_message\" and \"media_group\".", + "attachments": null, + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, 'Unknown attachment type, try again! Supported attachments are: \"location\", \"contact\", \"poll\", \"sticker\", \"audio\", \"video\", \"animation\", \"image\", \"document\", \"voice_message\", \"video_message\" and \"media_group\".', parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)" + ] + } + ], + "3_advanced": [ + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 21, 19, 9, 20, tzinfo=UTC), delete_chat_photo=False, entities=(MessageEntity(length=6, offset=0, type=MessageEntityType.BOT_COMMAND),), from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=1, supergroup_chat_created=False, text='/start'), update_id=1)", + "received_message": { + "text": "/start", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVXwsAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5SMF3RlbGVncmFtLl9tZXNzYWdlZW50aXR5lIwNTWVzc2FnZUVudGl0eZSTlCmB\nlH2UKIwPY3VzdG9tX2Vtb2ppX2lklE6MCGxhbmd1YWdllE6MBmxlbmd0aJRLBowGb2Zmc2V0lEsA\naBJoE4wRTWVzc2FnZUVudGl0eVR5cGWUk5SMC2JvdF9jb21tYW5klIWUUpSMA3VybJROjAR1c2Vy\nlE5oG4hoHGhdSwBLBoeUaB59lHVihZSMDmV4dGVybmFsX3JlcGx5lE6MEmZvcnVtX3RvcGljX2Ns\nb3NlZJROjBNmb3J1bV90b3BpY19jcmVhdGVklE6MEmZvcnVtX3RvcGljX2VkaXRlZJROjBRmb3J1\nbV90b3BpY19yZW9wZW5lZJROjA5mb3J3YXJkX29yaWdpbpROjAlmcm9tX3VzZXKUjA50ZWxlZ3Jh\nbS5fdXNlcpRoEJOUKYGUfZQojBhhZGRlZF90b19hdHRhY2htZW50X21lbnWUTowXY2FuX2Nvbm5l\nY3RfdG9fYnVzaW5lc3OUTowPY2FuX2pvaW5fZ3JvdXBzlE6MG2Nhbl9yZWFkX2FsbF9ncm91cF9t\nZXNzYWdlc5ROaAtoDGgNSyqMBmlzX2JvdJSJjAppc19wcmVtaXVtlE6MDWxhbmd1YWdlX2NvZGWU\njAJlbpRoD2gQjBdzdXBwb3J0c19pbmxpbmVfcXVlcmllc5ROaBloGmgbiGgcSyqFlGgefZR1YowE\nZ2FtZZROjBpnZW5lcmFsX2ZvcnVtX3RvcGljX2hpZGRlbpROjBxnZW5lcmFsX2ZvcnVtX3RvcGlj\nX3VuaGlkZGVulE6MCGdpdmVhd2F5lE6MEmdpdmVhd2F5X2NvbXBsZXRlZJROjBBnaXZlYXdheV9j\ncmVhdGVklE6MEGdpdmVhd2F5X3dpbm5lcnOUTowSZ3JvdXBfY2hhdF9jcmVhdGVklImMEWhhc19t\nZWRpYV9zcG9pbGVylE6MFWhhc19wcm90ZWN0ZWRfY29udGVudJROjAdpbnZvaWNllE6MFGlzX2F1\ndG9tYXRpY19mb3J3YXJklE6MD2lzX2Zyb21fb2ZmbGluZZROjBBpc190b3BpY19tZXNzYWdllE6M\nEGxlZnRfY2hhdF9tZW1iZXKUTowUbGlua19wcmV2aWV3X29wdGlvbnOUTowIbG9jYXRpb26UTowO\nbWVkaWFfZ3JvdXBfaWSUTowhbWVzc2FnZV9hdXRvX2RlbGV0ZV90aW1lcl9jaGFuZ2VklE6MEW1l\nc3NhZ2VfdGhyZWFkX2lklE6MFG1pZ3JhdGVfZnJvbV9jaGF0X2lklE6MEm1pZ3JhdGVfdG9fY2hh\ndF9pZJROjBBuZXdfY2hhdF9tZW1iZXJzlCmMDm5ld19jaGF0X3Bob3RvlCmMDm5ld19jaGF0X3Rp\ndGxllE6MDXBhc3Nwb3J0X2RhdGGUTowFcGhvdG+UKYwOcGlubmVkX21lc3NhZ2WUTowEcG9sbJRO\njBlwcm94aW1pdHlfYWxlcnRfdHJpZ2dlcmVklE6MBXF1b3RllE6MDHJlcGx5X21hcmt1cJROjBBy\nZXBseV90b19tZXNzYWdllE6MDnJlcGx5X3RvX3N0b3J5lE6MEnNlbmRlcl9ib29zdF9jb3VudJRO\njBNzZW5kZXJfYnVzaW5lc3NfYm90lE6MC3NlbmRlcl9jaGF0lE6MGHNob3dfY2FwdGlvbl9hYm92\nZV9tZWRpYZROjAdzdGlja2VylE6MBXN0b3J5lE6MEnN1Y2Nlc3NmdWxfcGF5bWVudJROjBdzdXBl\ncmdyb3VwX2NoYXRfY3JlYXRlZJSJjAR0ZXh0lIwGL3N0YXJ0lIwMdXNlcnNfc2hhcmVklE6MBXZl\nbnVllE6MB3ZpYV9ib3SUTowFdmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0\nX3BhcnRpY2lwYW50c19pbnZpdGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2No\nYXRfc3RhcnRlZJROjAp2aWRlb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0\nZV9hY2Nlc3NfYWxsb3dlZJROjARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZST\nlEMKB+gFFRMJFAAAAJSMBHB5dHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLAWgbiGgc\nSwFoCYaUaB59lHVijBBtZXNzYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSU\nTowObXlfY2hhdF9tZW1iZXKUTmiVTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5\nlE6MEnJlbW92ZWRfY2hhdF9ib29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwFo\nG4hoHEsBhZRoHn2UdWIu\n" + }, + "response_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "location", + "longitude": 27.792887, + "latitude": 58.43161, + "reply_markup": "gASV4gMAAAAAAACMJXRlbGVncmFtLl9pbmxpbmUuaW5saW5la2V5Ym9hcmRtYXJrdXCUjBRJbmxp\nbmVLZXlib2FyZE1hcmt1cJSTlCmBlH2UKIwPaW5saW5lX2tleWJvYXJklCiMJXRlbGVncmFtLl9p\nbmxpbmUuaW5saW5la2V5Ym9hcmRidXR0b26UjBRJbmxpbmVLZXlib2FyZEJ1dHRvbpSTlCmBlH2U\nKIwNY2FsbGJhY2tfZGF0YZSMCWZvcm1hdHRlZJSMDWNhbGxiYWNrX2dhbWWUTowJbG9naW5fdXJs\nlE6MA3BheZROjBNzd2l0Y2hfaW5saW5lX3F1ZXJ5lE6MH3N3aXRjaF9pbmxpbmVfcXVlcnlfY2hv\nc2VuX2NoYXSUTowgc3dpdGNoX2lubGluZV9xdWVyeV9jdXJyZW50X2NoYXSUTowEdGV4dJSMFEN1\ndGUgZm9ybWF0dGVkIHRleHQhlIwDdXJslE6MB3dlYl9hcHCUTowHX2Zyb3plbpSIjAlfaWRfYXR0\ncnOUKGgUTk5oDE5OTk5OdJSMCmFwaV9rd2FyZ3OUfZR1YoWUaAgpgZR9lChoC4wLYXR0YWNobWVu\ndHOUaA1OaA5OaA9OaBBOaBFOaBJOaBOMFU11bHRpcGxlIGF0dGFjaG1lbnRzIZRoFU5oFk5oF4ho\nGChoIE5OaB9OTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAZzZWNyZXSUaA1OaA5OaA9OaBBOaBFO\naBJOaBOMDVNlY3JldCBpbWFnZSGUaBVOaBZOaBeIaBgoaCdOTmgmTk5OTk50lGgafZR1YoWUaAgp\ngZR9lChoC4wJdGh1bWJuYWlslGgNTmgOTmgPTmgQTmgRTmgSTmgTjBhEb2N1bWVudCB3aXRoIHRo\ndW1ibmFpbCGUaBVOaBZOaBeIaBgoaC5OTmgtTk5OTk50lGgafZR1YoWUaAgpgZR9lChoC4wEaGFz\naJRoDU5oDk5oD05oEE5oEU5oEk5oE4wcRmlyc3QgYXR0YWNobWVudCBieXRlcyBoYXNoIZRoFU5o\nFk5oF4hoGChoNU5OaDROTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAdyZXN0YXJ0lGgNTmgOTmgP\nTmgQTmgRTmgSTmgTjAhSZXN0YXJ0IZRoFU5oFk5oF4hoGChoPE5OaDtOTk5OTnSUaBp9lHViaAgp\ngZR9lChoC4wEcXVpdJRoDU5oDk5oD05oEE5oEU5oEk5oE4wFUXVpdCGUaBVOaBZOaBeIaBgoaEJO\nTmhBTk5OTk50lGgafZR1YoaUdJRoF4hoGGhGhZRoGn2UdWIu\n", + "__pickled_extra_fields__": [ + "reply_markup" + ] + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_location(42, 58.43161, 27.792887, horizontal_accuracy=None, disable_notification=None, protect_content=None, reply_markup=InlineKeyboardMarkup(inline_keyboard=((InlineKeyboardButton(callback_data='formatted', text='Cute formatted text!'),), (InlineKeyboardButton(callback_data='attachments', text='Multiple attachments!'),), (InlineKeyboardButton(callback_data='secret', text='Secret image!'),), (InlineKeyboardButton(callback_data='thumbnail', text='Document with thumbnail!'),), (InlineKeyboardButton(callback_data='hash', text='First attachment bytes hash!'),), (InlineKeyboardButton(callback_data='restart', text='Restart!'), InlineKeyboardButton(callback_data='quit', text='Quit!')))), message_effect_id=None, reply_to_message_id=None)" + ] + }, + { + "update": "Update(callback_query=CallbackQuery(chat_instance='-1', data='formatted', from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), id='1', message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 21, 19, 9, 20, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Bot', id=16, is_bot=True, username='dff_bot'), group_chat_created=False, location=Location(latitude=58.43162, longitude=27.792879), message_id=2, reply_markup=InlineKeyboardMarkup(inline_keyboard=((InlineKeyboardButton(callback_data='formatted', text='Cute formatted text!'),), (InlineKeyboardButton(callback_data='attachments', text='Multiple attachments!'),), (InlineKeyboardButton(callback_data='secret', text='Secret image!'),), (InlineKeyboardButton(callback_data='thumbnail', text='Document with thumbnail!'),), (InlineKeyboardButton(callback_data='hash', text='First attachment bytes hash!'),), (InlineKeyboardButton(callback_data='restart', text='Restart!'), InlineKeyboardButton(callback_data='quit', text='Quit!')))), supergroup_chat_created=False)), update_id=2)", + "received_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "callback_query", + "query_string": "formatted" + } + ], + "annotations": null, + "misc": null, + "original_message": "gASV+g8AAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUjBd0ZWxlZ3JhbS5fY2FsbGJhY2txdWVyeZSMDUNhbGxiYWNrUXVlcnmUk5QpgZR9\nlCiMDWNoYXRfaW5zdGFuY2WUjAItMZSMBGRhdGGUjAlmb3JtYXR0ZWSUjAlmcm9tX3VzZXKUjA50\nZWxlZ3JhbS5fdXNlcpRoEJOUKYGUfZQojBhhZGRlZF90b19hdHRhY2htZW50X21lbnWUTowXY2Fu\nX2Nvbm5lY3RfdG9fYnVzaW5lc3OUTowPY2FuX2pvaW5fZ3JvdXBzlE6MG2Nhbl9yZWFkX2FsbF9n\ncm91cF9tZXNzYWdlc5ROaAtoDGgNSyqMBmlzX2JvdJSJjAppc19wcmVtaXVtlE6MDWxhbmd1YWdl\nX2NvZGWUjAJlbpRoD2gQjBdzdXBwb3J0c19pbmxpbmVfcXVlcmllc5ROaBloGmgbiGgcSyqFlGge\nfZR1YowPZ2FtZV9zaG9ydF9uYW1llE5oDYwBMZSMEWlubGluZV9tZXNzYWdlX2lklE6MB21lc3Nh\nZ2WUjBF0ZWxlZ3JhbS5fbWVzc2FnZZSMB01lc3NhZ2WUk5QpgZR9lCiMFV9lZmZlY3RpdmVfYXR0\nYWNobWVudJSMHHRlbGVncmFtLl91dGlscy5kZWZhdWx0dmFsdWWUjAxEZWZhdWx0VmFsdWWUk5Qp\ngZROfZSMBXZhbHVllE5zhpRijAlhbmltYXRpb26UTowFYXVkaW+UTowQYXV0aG9yX3NpZ25hdHVy\nZZROjAtib29zdF9hZGRlZJROjBZidXNpbmVzc19jb25uZWN0aW9uX2lklE6MB2NhcHRpb26UTowQ\nY2FwdGlvbl9lbnRpdGllc5QpjBRjaGFubmVsX2NoYXRfY3JlYXRlZJSJjBNjaGF0X2JhY2tncm91\nbmRfc2V0lE6MC2NoYXRfc2hhcmVklE6MEWNvbm5lY3RlZF93ZWJzaXRllE6MB2NvbnRhY3SUTowR\nZGVsZXRlX2NoYXRfcGhvdG+UiYwEZGljZZROjAhkb2N1bWVudJROjAllZGl0X2RhdGWUTowJZWZm\nZWN0X2lklE6MCGVudGl0aWVzlCmMDmV4dGVybmFsX3JlcGx5lE6MEmZvcnVtX3RvcGljX2Nsb3Nl\nZJROjBNmb3J1bV90b3BpY19jcmVhdGVklE6MEmZvcnVtX3RvcGljX2VkaXRlZJROjBRmb3J1bV90\nb3BpY19yZW9wZW5lZJROjA5mb3J3YXJkX29yaWdpbpROaC9oMSmBlH2UKGg0Tmg1Tmg2Tmg3TmgL\njANCb3SUaA1LEGg4iGg5Tmg6TmgPTmg8TmgZjAdkZmZfYm90lGgbiGgcSxCFlGgefZR1YowEZ2Ft\nZZROjBpnZW5lcmFsX2ZvcnVtX3RvcGljX2hpZGRlbpROjBxnZW5lcmFsX2ZvcnVtX3RvcGljX3Vu\naGlkZGVulE6MCGdpdmVhd2F5lE6MEmdpdmVhd2F5X2NvbXBsZXRlZJROjBBnaXZlYXdheV9jcmVh\ndGVklE6MEGdpdmVhd2F5X3dpbm5lcnOUTowSZ3JvdXBfY2hhdF9jcmVhdGVklImMEWhhc19tZWRp\nYV9zcG9pbGVylE6MFWhhc19wcm90ZWN0ZWRfY29udGVudJROjAdpbnZvaWNllE6MFGlzX2F1dG9t\nYXRpY19mb3J3YXJklE6MD2lzX2Zyb21fb2ZmbGluZZROjBBpc190b3BpY19tZXNzYWdllE6MEGxl\nZnRfY2hhdF9tZW1iZXKUTowUbGlua19wcmV2aWV3X29wdGlvbnOUTowIbG9jYXRpb26UjBh0ZWxl\nZ3JhbS5fZmlsZXMubG9jYXRpb26UjAhMb2NhdGlvbpSTlCmBlH2UKIwHaGVhZGluZ5ROjBNob3Jp\nem9udGFsX2FjY3VyYWN5lE6MCGxhdGl0dWRllEdATTc/UvwmV4wLbGl2ZV9wZXJpb2SUTowJbG9u\nZ2l0dWRllEdAO8r6Hj6vaIwWcHJveGltaXR5X2FsZXJ0X3JhZGl1c5ROaBuIaBxHQDvK+h4+r2hH\nQE03P1L8JleGlGgefZR1YowObWVkaWFfZ3JvdXBfaWSUTowhbWVzc2FnZV9hdXRvX2RlbGV0ZV90\naW1lcl9jaGFuZ2VklE6MEW1lc3NhZ2VfdGhyZWFkX2lklE6MFG1pZ3JhdGVfZnJvbV9jaGF0X2lk\nlE6MEm1pZ3JhdGVfdG9fY2hhdF9pZJROjBBuZXdfY2hhdF9tZW1iZXJzlCmMDm5ld19jaGF0X3Bo\nb3RvlCmMDm5ld19jaGF0X3RpdGxllE6MDXBhc3Nwb3J0X2RhdGGUTowFcGhvdG+UKYwOcGlubmVk\nX21lc3NhZ2WUTowEcG9sbJROjBlwcm94aW1pdHlfYWxlcnRfdHJpZ2dlcmVklE6MBXF1b3RllE6M\nDHJlcGx5X21hcmt1cJSMJXRlbGVncmFtLl9pbmxpbmUuaW5saW5la2V5Ym9hcmRtYXJrdXCUjBRJ\nbmxpbmVLZXlib2FyZE1hcmt1cJSTlCmBlH2UKIwPaW5saW5lX2tleWJvYXJklCiMJXRlbGVncmFt\nLl9pbmxpbmUuaW5saW5la2V5Ym9hcmRidXR0b26UjBRJbmxpbmVLZXlib2FyZEJ1dHRvbpSTlCmB\nlH2UKIwNY2FsbGJhY2tfZGF0YZRoLowNY2FsbGJhY2tfZ2FtZZROjAlsb2dpbl91cmyUTowDcGF5\nlE6ME3N3aXRjaF9pbmxpbmVfcXVlcnmUTowfc3dpdGNoX2lubGluZV9xdWVyeV9jaG9zZW5fY2hh\ndJROjCBzd2l0Y2hfaW5saW5lX3F1ZXJ5X2N1cnJlbnRfY2hhdJROjAR0ZXh0lIwUQ3V0ZSBmb3Jt\nYXR0ZWQgdGV4dCGUjAN1cmyUTowHd2ViX2FwcJROaBuIaBwoaK5OTmguTk5OTk50lGgefZR1YoWU\naKMpgZR9lChopowLYXR0YWNobWVudHOUaKdOaKhOaKlOaKpOaKtOaKxOaK2MFU11bHRpcGxlIGF0\ndGFjaG1lbnRzIZRor05osE5oG4hoHChot05OaLZOTk5OTnSUaB59lHVihZRooymBlH2UKGimjAZz\nZWNyZXSUaKdOaKhOaKlOaKpOaKtOaKxOaK2MDVNlY3JldCBpbWFnZSGUaK9OaLBOaBuIaBwoaL5O\nTmi9Tk5OTk50lGgefZR1YoWUaKMpgZR9lChopowJdGh1bWJuYWlslGinTmioTmipTmiqTmirTmis\nTmitjBhEb2N1bWVudCB3aXRoIHRodW1ibmFpbCGUaK9OaLBOaBuIaBwoaMVOTmjETk5OTk50lGge\nfZR1YoWUaKMpgZR9lChopowEaGFzaJRop05oqE5oqU5oqk5oq05orE5orYwcRmlyc3QgYXR0YWNo\nbWVudCBieXRlcyBoYXNoIZRor05osE5oG4hoHChozE5OaMtOTk5OTnSUaB59lHVihZRooymBlH2U\nKGimjAdyZXN0YXJ0lGinTmioTmipTmiqTmirTmisTmitjAhSZXN0YXJ0IZRor05osE5oG4hoHCho\n005OaNJOTk5OTnSUaB59lHViaKMpgZR9lChopowEcXVpdJRop05oqE5oqU5oqk5oq05orE5orYwF\nUXVpdCGUaK9OaLBOaBuIaBwoaNlOTmjYTk5OTk50lGgefZR1YoaUdJRoG4hoHGjdhZRoHn2UdWKM\nEHJlcGx5X3RvX21lc3NhZ2WUTowOcmVwbHlfdG9fc3RvcnmUTowSc2VuZGVyX2Jvb3N0X2NvdW50\nlE6ME3NlbmRlcl9idXNpbmVzc19ib3SUTowLc2VuZGVyX2NoYXSUTowYc2hvd19jYXB0aW9uX2Fi\nb3ZlX21lZGlhlE6MB3N0aWNrZXKUTowFc3RvcnmUTowSc3VjY2Vzc2Z1bF9wYXltZW50lE6MF3N1\ncGVyZ3JvdXBfY2hhdF9jcmVhdGVklIlorU6MDHVzZXJzX3NoYXJlZJROjAV2ZW51ZZROjAd2aWFf\nYm90lE6MBXZpZGVvlE6MEHZpZGVvX2NoYXRfZW5kZWSUTowfdmlkZW9fY2hhdF9wYXJ0aWNpcGFu\ndHNfaW52aXRlZJROjBR2aWRlb19jaGF0X3NjaGVkdWxlZJROjBJ2aWRlb19jaGF0X3N0YXJ0ZWSU\nTowKdmlkZW9fbm90ZZROjAV2b2ljZZROjAx3ZWJfYXBwX2RhdGGUTowUd3JpdGVfYWNjZXNzX2Fs\nbG93ZWSUTowEY2hhdJRoCYwEZGF0ZZSMCGRhdGV0aW1llIwIZGF0ZXRpbWWUk5RDCgfoBRUTCRQA\nAACUjARweXR6lIwEX1VUQ5STlClSlIaUUpSMCm1lc3NhZ2VfaWSUSwJoG4hoHEsCaAmGlGgefZR1\nYmgbiGgcaECFlGgefZR1YowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2lu\nX3JlcXVlc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRl\nZF9idXNpbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRf\nY2hhbm5lbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROaEJOjBBtZXNz\nYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowObXlfY2hhdF9tZW1iZXKU\nTmiXTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6MEnJlbW92ZWRfY2hhdF9i\nb29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwJoG4hoHEsChZRoHn2UdWIu\n" + }, + "response_message": { + "text": "\nVisit [this link](https://core.telegram.org/bots/api#formatting-options)\nfor more information about formatting options in telegram\\.\n\nRun /start command again to restart\\.\n", + "attachments": null, + "annotations": null, + "misc": null, + "original_message": null, + "parse_mode": "MarkdownV2" + }, + "response_functions": [ + "send_message(42, '\\nVisit [this link](https://core.telegram.org/bots/api#formatting-options)\\nfor more information about formatting options in telegram\\\\.\\n\\nRun /start command again to restart\\\\.\\n', parse_mode=, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 21, 19, 9, 24, tzinfo=UTC), delete_chat_photo=False, entities=(MessageEntity(length=6, offset=0, type=MessageEntityType.BOT_COMMAND),), from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=3, supergroup_chat_created=False, text='/start'), update_id=3)", + "received_message": { + "text": "/start", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVXwsAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5SMF3RlbGVncmFtLl9tZXNzYWdlZW50aXR5lIwNTWVzc2FnZUVudGl0eZSTlCmB\nlH2UKIwPY3VzdG9tX2Vtb2ppX2lklE6MCGxhbmd1YWdllE6MBmxlbmd0aJRLBowGb2Zmc2V0lEsA\naBJoE4wRTWVzc2FnZUVudGl0eVR5cGWUk5SMC2JvdF9jb21tYW5klIWUUpSMA3VybJROjAR1c2Vy\nlE5oG4hoHGhdSwBLBoeUaB59lHVihZSMDmV4dGVybmFsX3JlcGx5lE6MEmZvcnVtX3RvcGljX2Ns\nb3NlZJROjBNmb3J1bV90b3BpY19jcmVhdGVklE6MEmZvcnVtX3RvcGljX2VkaXRlZJROjBRmb3J1\nbV90b3BpY19yZW9wZW5lZJROjA5mb3J3YXJkX29yaWdpbpROjAlmcm9tX3VzZXKUjA50ZWxlZ3Jh\nbS5fdXNlcpRoEJOUKYGUfZQojBhhZGRlZF90b19hdHRhY2htZW50X21lbnWUTowXY2FuX2Nvbm5l\nY3RfdG9fYnVzaW5lc3OUTowPY2FuX2pvaW5fZ3JvdXBzlE6MG2Nhbl9yZWFkX2FsbF9ncm91cF9t\nZXNzYWdlc5ROaAtoDGgNSyqMBmlzX2JvdJSJjAppc19wcmVtaXVtlE6MDWxhbmd1YWdlX2NvZGWU\njAJlbpRoD2gQjBdzdXBwb3J0c19pbmxpbmVfcXVlcmllc5ROaBloGmgbiGgcSyqFlGgefZR1YowE\nZ2FtZZROjBpnZW5lcmFsX2ZvcnVtX3RvcGljX2hpZGRlbpROjBxnZW5lcmFsX2ZvcnVtX3RvcGlj\nX3VuaGlkZGVulE6MCGdpdmVhd2F5lE6MEmdpdmVhd2F5X2NvbXBsZXRlZJROjBBnaXZlYXdheV9j\ncmVhdGVklE6MEGdpdmVhd2F5X3dpbm5lcnOUTowSZ3JvdXBfY2hhdF9jcmVhdGVklImMEWhhc19t\nZWRpYV9zcG9pbGVylE6MFWhhc19wcm90ZWN0ZWRfY29udGVudJROjAdpbnZvaWNllE6MFGlzX2F1\ndG9tYXRpY19mb3J3YXJklE6MD2lzX2Zyb21fb2ZmbGluZZROjBBpc190b3BpY19tZXNzYWdllE6M\nEGxlZnRfY2hhdF9tZW1iZXKUTowUbGlua19wcmV2aWV3X29wdGlvbnOUTowIbG9jYXRpb26UTowO\nbWVkaWFfZ3JvdXBfaWSUTowhbWVzc2FnZV9hdXRvX2RlbGV0ZV90aW1lcl9jaGFuZ2VklE6MEW1l\nc3NhZ2VfdGhyZWFkX2lklE6MFG1pZ3JhdGVfZnJvbV9jaGF0X2lklE6MEm1pZ3JhdGVfdG9fY2hh\ndF9pZJROjBBuZXdfY2hhdF9tZW1iZXJzlCmMDm5ld19jaGF0X3Bob3RvlCmMDm5ld19jaGF0X3Rp\ndGxllE6MDXBhc3Nwb3J0X2RhdGGUTowFcGhvdG+UKYwOcGlubmVkX21lc3NhZ2WUTowEcG9sbJRO\njBlwcm94aW1pdHlfYWxlcnRfdHJpZ2dlcmVklE6MBXF1b3RllE6MDHJlcGx5X21hcmt1cJROjBBy\nZXBseV90b19tZXNzYWdllE6MDnJlcGx5X3RvX3N0b3J5lE6MEnNlbmRlcl9ib29zdF9jb3VudJRO\njBNzZW5kZXJfYnVzaW5lc3NfYm90lE6MC3NlbmRlcl9jaGF0lE6MGHNob3dfY2FwdGlvbl9hYm92\nZV9tZWRpYZROjAdzdGlja2VylE6MBXN0b3J5lE6MEnN1Y2Nlc3NmdWxfcGF5bWVudJROjBdzdXBl\ncmdyb3VwX2NoYXRfY3JlYXRlZJSJjAR0ZXh0lIwGL3N0YXJ0lIwMdXNlcnNfc2hhcmVklE6MBXZl\nbnVllE6MB3ZpYV9ib3SUTowFdmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0\nX3BhcnRpY2lwYW50c19pbnZpdGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2No\nYXRfc3RhcnRlZJROjAp2aWRlb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0\nZV9hY2Nlc3NfYWxsb3dlZJROjARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZST\nlEMKB+gFFRMJGAAAAJSMBHB5dHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLA2gbiGgc\nSwNoCYaUaB59lHVijBBtZXNzYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSU\nTowObXlfY2hhdF9tZW1iZXKUTmiVTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5\nlE6MEnJlbW92ZWRfY2hhdF9ib29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwNo\nG4hoHEsDhZRoHn2UdWIu\n" + }, + "response_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "location", + "longitude": 27.792887, + "latitude": 58.43161, + "reply_markup": "gASV4gMAAAAAAACMJXRlbGVncmFtLl9pbmxpbmUuaW5saW5la2V5Ym9hcmRtYXJrdXCUjBRJbmxp\nbmVLZXlib2FyZE1hcmt1cJSTlCmBlH2UKIwPaW5saW5lX2tleWJvYXJklCiMJXRlbGVncmFtLl9p\nbmxpbmUuaW5saW5la2V5Ym9hcmRidXR0b26UjBRJbmxpbmVLZXlib2FyZEJ1dHRvbpSTlCmBlH2U\nKIwNY2FsbGJhY2tfZGF0YZSMCWZvcm1hdHRlZJSMDWNhbGxiYWNrX2dhbWWUTowJbG9naW5fdXJs\nlE6MA3BheZROjBNzd2l0Y2hfaW5saW5lX3F1ZXJ5lE6MH3N3aXRjaF9pbmxpbmVfcXVlcnlfY2hv\nc2VuX2NoYXSUTowgc3dpdGNoX2lubGluZV9xdWVyeV9jdXJyZW50X2NoYXSUTowEdGV4dJSMFEN1\ndGUgZm9ybWF0dGVkIHRleHQhlIwDdXJslE6MB3dlYl9hcHCUTowHX2Zyb3plbpSIjAlfaWRfYXR0\ncnOUKGgUTk5oDE5OTk5OdJSMCmFwaV9rd2FyZ3OUfZR1YoWUaAgpgZR9lChoC4wLYXR0YWNobWVu\ndHOUaA1OaA5OaA9OaBBOaBFOaBJOaBOMFU11bHRpcGxlIGF0dGFjaG1lbnRzIZRoFU5oFk5oF4ho\nGChoIE5OaB9OTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAZzZWNyZXSUaA1OaA5OaA9OaBBOaBFO\naBJOaBOMDVNlY3JldCBpbWFnZSGUaBVOaBZOaBeIaBgoaCdOTmgmTk5OTk50lGgafZR1YoWUaAgp\ngZR9lChoC4wJdGh1bWJuYWlslGgNTmgOTmgPTmgQTmgRTmgSTmgTjBhEb2N1bWVudCB3aXRoIHRo\ndW1ibmFpbCGUaBVOaBZOaBeIaBgoaC5OTmgtTk5OTk50lGgafZR1YoWUaAgpgZR9lChoC4wEaGFz\naJRoDU5oDk5oD05oEE5oEU5oEk5oE4wcRmlyc3QgYXR0YWNobWVudCBieXRlcyBoYXNoIZRoFU5o\nFk5oF4hoGChoNU5OaDROTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAdyZXN0YXJ0lGgNTmgOTmgP\nTmgQTmgRTmgSTmgTjAhSZXN0YXJ0IZRoFU5oFk5oF4hoGChoPE5OaDtOTk5OTnSUaBp9lHViaAgp\ngZR9lChoC4wEcXVpdJRoDU5oDk5oD05oEE5oEU5oEk5oE4wFUXVpdCGUaBVOaBZOaBeIaBgoaEJO\nTmhBTk5OTk50lGgafZR1YoaUdJRoF4hoGGhGhZRoGn2UdWIu\n", + "__pickled_extra_fields__": [ + "reply_markup" + ] + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_location(42, 58.43161, 27.792887, horizontal_accuracy=None, disable_notification=None, protect_content=None, reply_markup=InlineKeyboardMarkup(inline_keyboard=((InlineKeyboardButton(callback_data='formatted', text='Cute formatted text!'),), (InlineKeyboardButton(callback_data='attachments', text='Multiple attachments!'),), (InlineKeyboardButton(callback_data='secret', text='Secret image!'),), (InlineKeyboardButton(callback_data='thumbnail', text='Document with thumbnail!'),), (InlineKeyboardButton(callback_data='hash', text='First attachment bytes hash!'),), (InlineKeyboardButton(callback_data='restart', text='Restart!'), InlineKeyboardButton(callback_data='quit', text='Quit!')))), message_effect_id=None, reply_to_message_id=None)" + ] + }, + { + "update": "Update(callback_query=CallbackQuery(chat_instance='-1', data='attachments', from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), id='3', message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 21, 19, 9, 24, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Bot', id=16, is_bot=True, username='dff_bot'), group_chat_created=False, location=Location(latitude=58.43162, longitude=27.792879), message_id=4, reply_markup=InlineKeyboardMarkup(inline_keyboard=((InlineKeyboardButton(callback_data='formatted', text='Cute formatted text!'),), (InlineKeyboardButton(callback_data='attachments', text='Multiple attachments!'),), (InlineKeyboardButton(callback_data='secret', text='Secret image!'),), (InlineKeyboardButton(callback_data='thumbnail', text='Document with thumbnail!'),), (InlineKeyboardButton(callback_data='hash', text='First attachment bytes hash!'),), (InlineKeyboardButton(callback_data='restart', text='Restart!'), InlineKeyboardButton(callback_data='quit', text='Quit!')))), supergroup_chat_created=False)), update_id=4)", + "received_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "callback_query", + "query_string": "attachments" + } + ], + "annotations": null, + "misc": null, + "original_message": "gASV+g8AAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUjBd0ZWxlZ3JhbS5fY2FsbGJhY2txdWVyeZSMDUNhbGxiYWNrUXVlcnmUk5QpgZR9\nlCiMDWNoYXRfaW5zdGFuY2WUjAItMZSMBGRhdGGUjAthdHRhY2htZW50c5SMCWZyb21fdXNlcpSM\nDnRlbGVncmFtLl91c2VylGgQk5QpgZR9lCiMGGFkZGVkX3RvX2F0dGFjaG1lbnRfbWVudZROjBdj\nYW5fY29ubmVjdF90b19idXNpbmVzc5ROjA9jYW5fam9pbl9ncm91cHOUTowbY2FuX3JlYWRfYWxs\nX2dyb3VwX21lc3NhZ2VzlE5oC2gMaA1LKowGaXNfYm90lImMCmlzX3ByZW1pdW2UTowNbGFuZ3Vh\nZ2VfY29kZZSMAmVulGgPaBCMF3N1cHBvcnRzX2lubGluZV9xdWVyaWVzlE5oGWgaaBuIaBxLKoWU\naB59lHVijA9nYW1lX3Nob3J0X25hbWWUTmgNjAEzlIwRaW5saW5lX21lc3NhZ2VfaWSUTowHbWVz\nc2FnZZSMEXRlbGVncmFtLl9tZXNzYWdllIwHTWVzc2FnZZSTlCmBlH2UKIwVX2VmZmVjdGl2ZV9h\ndHRhY2htZW50lIwcdGVsZWdyYW0uX3V0aWxzLmRlZmF1bHR2YWx1ZZSMDERlZmF1bHRWYWx1ZZST\nlCmBlE59lIwFdmFsdWWUTnOGlGKMCWFuaW1hdGlvbpROjAVhdWRpb5ROjBBhdXRob3Jfc2lnbmF0\ndXJllE6MC2Jvb3N0X2FkZGVklE6MFmJ1c2luZXNzX2Nvbm5lY3Rpb25faWSUTowHY2FwdGlvbpRO\njBBjYXB0aW9uX2VudGl0aWVzlCmMFGNoYW5uZWxfY2hhdF9jcmVhdGVklImME2NoYXRfYmFja2dy\nb3VuZF9zZXSUTowLY2hhdF9zaGFyZWSUTowRY29ubmVjdGVkX3dlYnNpdGWUTowHY29udGFjdJRO\njBFkZWxldGVfY2hhdF9waG90b5SJjARkaWNllE6MCGRvY3VtZW50lE6MCWVkaXRfZGF0ZZROjAll\nZmZlY3RfaWSUTowIZW50aXRpZXOUKYwOZXh0ZXJuYWxfcmVwbHmUTowSZm9ydW1fdG9waWNfY2xv\nc2VklE6ME2ZvcnVtX3RvcGljX2NyZWF0ZWSUTowSZm9ydW1fdG9waWNfZWRpdGVklE6MFGZvcnVt\nX3RvcGljX3Jlb3BlbmVklE6MDmZvcndhcmRfb3JpZ2lulE5oL2gxKYGUfZQoaDROaDVOaDZOaDdO\naAuMA0JvdJRoDUsQaDiIaDlOaDpOaA9OaDxOaBmMB2RmZl9ib3SUaBuIaBxLEIWUaB59lHVijARn\nYW1llE6MGmdlbmVyYWxfZm9ydW1fdG9waWNfaGlkZGVulE6MHGdlbmVyYWxfZm9ydW1fdG9waWNf\ndW5oaWRkZW6UTowIZ2l2ZWF3YXmUTowSZ2l2ZWF3YXlfY29tcGxldGVklE6MEGdpdmVhd2F5X2Ny\nZWF0ZWSUTowQZ2l2ZWF3YXlfd2lubmVyc5ROjBJncm91cF9jaGF0X2NyZWF0ZWSUiYwRaGFzX21l\nZGlhX3Nwb2lsZXKUTowVaGFzX3Byb3RlY3RlZF9jb250ZW50lE6MB2ludm9pY2WUTowUaXNfYXV0\nb21hdGljX2ZvcndhcmSUTowPaXNfZnJvbV9vZmZsaW5llE6MEGlzX3RvcGljX21lc3NhZ2WUTowQ\nbGVmdF9jaGF0X21lbWJlcpROjBRsaW5rX3ByZXZpZXdfb3B0aW9uc5ROjAhsb2NhdGlvbpSMGHRl\nbGVncmFtLl9maWxlcy5sb2NhdGlvbpSMCExvY2F0aW9ulJOUKYGUfZQojAdoZWFkaW5nlE6ME2hv\ncml6b250YWxfYWNjdXJhY3mUTowIbGF0aXR1ZGWUR0BNNz9S/CZXjAtsaXZlX3BlcmlvZJROjAls\nb25naXR1ZGWUR0A7yvoePq9ojBZwcm94aW1pdHlfYWxlcnRfcmFkaXVzlE5oG4hoHEdAO8r6Hj6v\naEdATTc/UvwmV4aUaB59lHVijA5tZWRpYV9ncm91cF9pZJROjCFtZXNzYWdlX2F1dG9fZGVsZXRl\nX3RpbWVyX2NoYW5nZWSUTowRbWVzc2FnZV90aHJlYWRfaWSUTowUbWlncmF0ZV9mcm9tX2NoYXRf\naWSUTowSbWlncmF0ZV90b19jaGF0X2lklE6MEG5ld19jaGF0X21lbWJlcnOUKYwObmV3X2NoYXRf\ncGhvdG+UKYwObmV3X2NoYXRfdGl0bGWUTowNcGFzc3BvcnRfZGF0YZROjAVwaG90b5QpjA5waW5u\nZWRfbWVzc2FnZZROjARwb2xslE6MGXByb3hpbWl0eV9hbGVydF90cmlnZ2VyZWSUTowFcXVvdGWU\nTowMcmVwbHlfbWFya3VwlIwldGVsZWdyYW0uX2lubGluZS5pbmxpbmVrZXlib2FyZG1hcmt1cJSM\nFElubGluZUtleWJvYXJkTWFya3VwlJOUKYGUfZQojA9pbmxpbmVfa2V5Ym9hcmSUKIwldGVsZWdy\nYW0uX2lubGluZS5pbmxpbmVrZXlib2FyZGJ1dHRvbpSMFElubGluZUtleWJvYXJkQnV0dG9ulJOU\nKYGUfZQojA1jYWxsYmFja19kYXRhlIwJZm9ybWF0dGVklIwNY2FsbGJhY2tfZ2FtZZROjAlsb2dp\nbl91cmyUTowDcGF5lE6ME3N3aXRjaF9pbmxpbmVfcXVlcnmUTowfc3dpdGNoX2lubGluZV9xdWVy\neV9jaG9zZW5fY2hhdJROjCBzd2l0Y2hfaW5saW5lX3F1ZXJ5X2N1cnJlbnRfY2hhdJROjAR0ZXh0\nlIwUQ3V0ZSBmb3JtYXR0ZWQgdGV4dCGUjAN1cmyUTowHd2ViX2FwcJROaBuIaBwoaK9OTminTk5O\nTk50lGgefZR1YoWUaKMpgZR9lChopmguaKhOaKlOaKpOaKtOaKxOaK1OaK6MFU11bHRpcGxlIGF0\ndGFjaG1lbnRzIZRosE5osU5oG4hoHChot05OaC5OTk5OTnSUaB59lHVihZRooymBlH2UKGimjAZz\nZWNyZXSUaKhOaKlOaKpOaKtOaKxOaK1OaK6MDVNlY3JldCBpbWFnZSGUaLBOaLFOaBuIaBwoaL5O\nTmi9Tk5OTk50lGgefZR1YoWUaKMpgZR9lChopowJdGh1bWJuYWlslGioTmipTmiqTmirTmisTmit\nTmiujBhEb2N1bWVudCB3aXRoIHRodW1ibmFpbCGUaLBOaLFOaBuIaBwoaMVOTmjETk5OTk50lGge\nfZR1YoWUaKMpgZR9lChopowEaGFzaJRoqE5oqU5oqk5oq05orE5orU5orowcRmlyc3QgYXR0YWNo\nbWVudCBieXRlcyBoYXNoIZRosE5osU5oG4hoHChozE5OaMtOTk5OTnSUaB59lHVihZRooymBlH2U\nKGimjAdyZXN0YXJ0lGioTmipTmiqTmirTmisTmitTmiujAhSZXN0YXJ0IZRosE5osU5oG4hoHCho\n005OaNJOTk5OTnSUaB59lHViaKMpgZR9lChopowEcXVpdJRoqE5oqU5oqk5oq05orE5orU5orowF\nUXVpdCGUaLBOaLFOaBuIaBwoaNlOTmjYTk5OTk50lGgefZR1YoaUdJRoG4hoHGjdhZRoHn2UdWKM\nEHJlcGx5X3RvX21lc3NhZ2WUTowOcmVwbHlfdG9fc3RvcnmUTowSc2VuZGVyX2Jvb3N0X2NvdW50\nlE6ME3NlbmRlcl9idXNpbmVzc19ib3SUTowLc2VuZGVyX2NoYXSUTowYc2hvd19jYXB0aW9uX2Fi\nb3ZlX21lZGlhlE6MB3N0aWNrZXKUTowFc3RvcnmUTowSc3VjY2Vzc2Z1bF9wYXltZW50lE6MF3N1\ncGVyZ3JvdXBfY2hhdF9jcmVhdGVklIlork6MDHVzZXJzX3NoYXJlZJROjAV2ZW51ZZROjAd2aWFf\nYm90lE6MBXZpZGVvlE6MEHZpZGVvX2NoYXRfZW5kZWSUTowfdmlkZW9fY2hhdF9wYXJ0aWNpcGFu\ndHNfaW52aXRlZJROjBR2aWRlb19jaGF0X3NjaGVkdWxlZJROjBJ2aWRlb19jaGF0X3N0YXJ0ZWSU\nTowKdmlkZW9fbm90ZZROjAV2b2ljZZROjAx3ZWJfYXBwX2RhdGGUTowUd3JpdGVfYWNjZXNzX2Fs\nbG93ZWSUTowEY2hhdJRoCYwEZGF0ZZSMCGRhdGV0aW1llIwIZGF0ZXRpbWWUk5RDCgfoBRUTCRgA\nAACUjARweXR6lIwEX1VUQ5STlClSlIaUUpSMCm1lc3NhZ2VfaWSUSwRoG4hoHEsEaAmGlGgefZR1\nYmgbiGgcaECFlGgefZR1YowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2lu\nX3JlcXVlc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRl\nZF9idXNpbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRf\nY2hhbm5lbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROaEJOjBBtZXNz\nYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowObXlfY2hhdF9tZW1iZXKU\nTmiXTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6MEnJlbW92ZWRfY2hhdF9i\nb29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwRoG4hoHEsEhZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Here's your message with multiple attachments (a location and a sticker)!\nRun /start command again to restart.", + "attachments": [ + { + "dff_attachment_type": "location", + "longitude": 30.3141, + "latitude": 59.9386 + }, + { + "dff_attachment_type": "sticker", + "source": null, + "use_cache": true, + "cached_filename": null, + "id": "CAACAgIAAxkBAAErBZ1mKAbZvEOmhscojaIL5q0u8vgp1wACRygAAiSjCUtLa7RHZy76ezQE" + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your message with multiple attachments (a location and a sticker)!\\nRun /start command again to restart.\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)", + "send_location(42, 59.9386, 30.3141, horizontal_accuracy=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None)", + "send_sticker(42, 'CAACAgIAAxkBAAErBZ1mKAbZvEOmhscojaIL5q0u8vgp1wACRygAAiSjCUtLa7RHZy76ezQE', emoji=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None)" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 21, 19, 9, 28, tzinfo=UTC), delete_chat_photo=False, entities=(MessageEntity(length=6, offset=0, type=MessageEntityType.BOT_COMMAND),), from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=5, supergroup_chat_created=False, text='/start'), update_id=5)", + "received_message": { + "text": "/start", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVXwsAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5SMF3RlbGVncmFtLl9tZXNzYWdlZW50aXR5lIwNTWVzc2FnZUVudGl0eZSTlCmB\nlH2UKIwPY3VzdG9tX2Vtb2ppX2lklE6MCGxhbmd1YWdllE6MBmxlbmd0aJRLBowGb2Zmc2V0lEsA\naBJoE4wRTWVzc2FnZUVudGl0eVR5cGWUk5SMC2JvdF9jb21tYW5klIWUUpSMA3VybJROjAR1c2Vy\nlE5oG4hoHGhdSwBLBoeUaB59lHVihZSMDmV4dGVybmFsX3JlcGx5lE6MEmZvcnVtX3RvcGljX2Ns\nb3NlZJROjBNmb3J1bV90b3BpY19jcmVhdGVklE6MEmZvcnVtX3RvcGljX2VkaXRlZJROjBRmb3J1\nbV90b3BpY19yZW9wZW5lZJROjA5mb3J3YXJkX29yaWdpbpROjAlmcm9tX3VzZXKUjA50ZWxlZ3Jh\nbS5fdXNlcpRoEJOUKYGUfZQojBhhZGRlZF90b19hdHRhY2htZW50X21lbnWUTowXY2FuX2Nvbm5l\nY3RfdG9fYnVzaW5lc3OUTowPY2FuX2pvaW5fZ3JvdXBzlE6MG2Nhbl9yZWFkX2FsbF9ncm91cF9t\nZXNzYWdlc5ROaAtoDGgNSyqMBmlzX2JvdJSJjAppc19wcmVtaXVtlE6MDWxhbmd1YWdlX2NvZGWU\njAJlbpRoD2gQjBdzdXBwb3J0c19pbmxpbmVfcXVlcmllc5ROaBloGmgbiGgcSyqFlGgefZR1YowE\nZ2FtZZROjBpnZW5lcmFsX2ZvcnVtX3RvcGljX2hpZGRlbpROjBxnZW5lcmFsX2ZvcnVtX3RvcGlj\nX3VuaGlkZGVulE6MCGdpdmVhd2F5lE6MEmdpdmVhd2F5X2NvbXBsZXRlZJROjBBnaXZlYXdheV9j\ncmVhdGVklE6MEGdpdmVhd2F5X3dpbm5lcnOUTowSZ3JvdXBfY2hhdF9jcmVhdGVklImMEWhhc19t\nZWRpYV9zcG9pbGVylE6MFWhhc19wcm90ZWN0ZWRfY29udGVudJROjAdpbnZvaWNllE6MFGlzX2F1\ndG9tYXRpY19mb3J3YXJklE6MD2lzX2Zyb21fb2ZmbGluZZROjBBpc190b3BpY19tZXNzYWdllE6M\nEGxlZnRfY2hhdF9tZW1iZXKUTowUbGlua19wcmV2aWV3X29wdGlvbnOUTowIbG9jYXRpb26UTowO\nbWVkaWFfZ3JvdXBfaWSUTowhbWVzc2FnZV9hdXRvX2RlbGV0ZV90aW1lcl9jaGFuZ2VklE6MEW1l\nc3NhZ2VfdGhyZWFkX2lklE6MFG1pZ3JhdGVfZnJvbV9jaGF0X2lklE6MEm1pZ3JhdGVfdG9fY2hh\ndF9pZJROjBBuZXdfY2hhdF9tZW1iZXJzlCmMDm5ld19jaGF0X3Bob3RvlCmMDm5ld19jaGF0X3Rp\ndGxllE6MDXBhc3Nwb3J0X2RhdGGUTowFcGhvdG+UKYwOcGlubmVkX21lc3NhZ2WUTowEcG9sbJRO\njBlwcm94aW1pdHlfYWxlcnRfdHJpZ2dlcmVklE6MBXF1b3RllE6MDHJlcGx5X21hcmt1cJROjBBy\nZXBseV90b19tZXNzYWdllE6MDnJlcGx5X3RvX3N0b3J5lE6MEnNlbmRlcl9ib29zdF9jb3VudJRO\njBNzZW5kZXJfYnVzaW5lc3NfYm90lE6MC3NlbmRlcl9jaGF0lE6MGHNob3dfY2FwdGlvbl9hYm92\nZV9tZWRpYZROjAdzdGlja2VylE6MBXN0b3J5lE6MEnN1Y2Nlc3NmdWxfcGF5bWVudJROjBdzdXBl\ncmdyb3VwX2NoYXRfY3JlYXRlZJSJjAR0ZXh0lIwGL3N0YXJ0lIwMdXNlcnNfc2hhcmVklE6MBXZl\nbnVllE6MB3ZpYV9ib3SUTowFdmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0\nX3BhcnRpY2lwYW50c19pbnZpdGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2No\nYXRfc3RhcnRlZJROjAp2aWRlb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0\nZV9hY2Nlc3NfYWxsb3dlZJROjARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZST\nlEMKB+gFFRMJHAAAAJSMBHB5dHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLBWgbiGgc\nSwVoCYaUaB59lHVijBBtZXNzYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSU\nTowObXlfY2hhdF9tZW1iZXKUTmiVTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5\nlE6MEnJlbW92ZWRfY2hhdF9ib29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwVo\nG4hoHEsFhZRoHn2UdWIu\n" + }, + "response_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "location", + "longitude": 27.792887, + "latitude": 58.43161, + "reply_markup": "gASV4gMAAAAAAACMJXRlbGVncmFtLl9pbmxpbmUuaW5saW5la2V5Ym9hcmRtYXJrdXCUjBRJbmxp\nbmVLZXlib2FyZE1hcmt1cJSTlCmBlH2UKIwPaW5saW5lX2tleWJvYXJklCiMJXRlbGVncmFtLl9p\nbmxpbmUuaW5saW5la2V5Ym9hcmRidXR0b26UjBRJbmxpbmVLZXlib2FyZEJ1dHRvbpSTlCmBlH2U\nKIwNY2FsbGJhY2tfZGF0YZSMCWZvcm1hdHRlZJSMDWNhbGxiYWNrX2dhbWWUTowJbG9naW5fdXJs\nlE6MA3BheZROjBNzd2l0Y2hfaW5saW5lX3F1ZXJ5lE6MH3N3aXRjaF9pbmxpbmVfcXVlcnlfY2hv\nc2VuX2NoYXSUTowgc3dpdGNoX2lubGluZV9xdWVyeV9jdXJyZW50X2NoYXSUTowEdGV4dJSMFEN1\ndGUgZm9ybWF0dGVkIHRleHQhlIwDdXJslE6MB3dlYl9hcHCUTowHX2Zyb3plbpSIjAlfaWRfYXR0\ncnOUKGgUTk5oDE5OTk5OdJSMCmFwaV9rd2FyZ3OUfZR1YoWUaAgpgZR9lChoC4wLYXR0YWNobWVu\ndHOUaA1OaA5OaA9OaBBOaBFOaBJOaBOMFU11bHRpcGxlIGF0dGFjaG1lbnRzIZRoFU5oFk5oF4ho\nGChoIE5OaB9OTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAZzZWNyZXSUaA1OaA5OaA9OaBBOaBFO\naBJOaBOMDVNlY3JldCBpbWFnZSGUaBVOaBZOaBeIaBgoaCdOTmgmTk5OTk50lGgafZR1YoWUaAgp\ngZR9lChoC4wJdGh1bWJuYWlslGgNTmgOTmgPTmgQTmgRTmgSTmgTjBhEb2N1bWVudCB3aXRoIHRo\ndW1ibmFpbCGUaBVOaBZOaBeIaBgoaC5OTmgtTk5OTk50lGgafZR1YoWUaAgpgZR9lChoC4wEaGFz\naJRoDU5oDk5oD05oEE5oEU5oEk5oE4wcRmlyc3QgYXR0YWNobWVudCBieXRlcyBoYXNoIZRoFU5o\nFk5oF4hoGChoNU5OaDROTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAdyZXN0YXJ0lGgNTmgOTmgP\nTmgQTmgRTmgSTmgTjAhSZXN0YXJ0IZRoFU5oFk5oF4hoGChoPE5OaDtOTk5OTnSUaBp9lHViaAgp\ngZR9lChoC4wEcXVpdJRoDU5oDk5oD05oEE5oEU5oEk5oE4wFUXVpdCGUaBVOaBZOaBeIaBgoaEJO\nTmhBTk5OTk50lGgafZR1YoaUdJRoF4hoGGhGhZRoGn2UdWIu\n", + "__pickled_extra_fields__": [ + "reply_markup" + ] + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_location(42, 58.43161, 27.792887, horizontal_accuracy=None, disable_notification=None, protect_content=None, reply_markup=InlineKeyboardMarkup(inline_keyboard=((InlineKeyboardButton(callback_data='formatted', text='Cute formatted text!'),), (InlineKeyboardButton(callback_data='attachments', text='Multiple attachments!'),), (InlineKeyboardButton(callback_data='secret', text='Secret image!'),), (InlineKeyboardButton(callback_data='thumbnail', text='Document with thumbnail!'),), (InlineKeyboardButton(callback_data='hash', text='First attachment bytes hash!'),), (InlineKeyboardButton(callback_data='restart', text='Restart!'), InlineKeyboardButton(callback_data='quit', text='Quit!')))), message_effect_id=None, reply_to_message_id=None)" + ] + }, + { + "update": "Update(callback_query=CallbackQuery(chat_instance='-1', data='secret', from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), id='5', message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 21, 19, 9, 28, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Bot', id=16, is_bot=True, username='dff_bot'), group_chat_created=False, location=Location(latitude=58.43162, longitude=27.792879), message_id=6, reply_markup=InlineKeyboardMarkup(inline_keyboard=((InlineKeyboardButton(callback_data='formatted', text='Cute formatted text!'),), (InlineKeyboardButton(callback_data='attachments', text='Multiple attachments!'),), (InlineKeyboardButton(callback_data='secret', text='Secret image!'),), (InlineKeyboardButton(callback_data='thumbnail', text='Document with thumbnail!'),), (InlineKeyboardButton(callback_data='hash', text='First attachment bytes hash!'),), (InlineKeyboardButton(callback_data='restart', text='Restart!'), InlineKeyboardButton(callback_data='quit', text='Quit!')))), supergroup_chat_created=False)), update_id=6)", + "received_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "callback_query", + "query_string": "secret" + } + ], + "annotations": null, + "misc": null, + "original_message": "gASV+g8AAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUjBd0ZWxlZ3JhbS5fY2FsbGJhY2txdWVyeZSMDUNhbGxiYWNrUXVlcnmUk5QpgZR9\nlCiMDWNoYXRfaW5zdGFuY2WUjAItMZSMBGRhdGGUjAZzZWNyZXSUjAlmcm9tX3VzZXKUjA50ZWxl\nZ3JhbS5fdXNlcpRoEJOUKYGUfZQojBhhZGRlZF90b19hdHRhY2htZW50X21lbnWUTowXY2FuX2Nv\nbm5lY3RfdG9fYnVzaW5lc3OUTowPY2FuX2pvaW5fZ3JvdXBzlE6MG2Nhbl9yZWFkX2FsbF9ncm91\ncF9tZXNzYWdlc5ROaAtoDGgNSyqMBmlzX2JvdJSJjAppc19wcmVtaXVtlE6MDWxhbmd1YWdlX2Nv\nZGWUjAJlbpRoD2gQjBdzdXBwb3J0c19pbmxpbmVfcXVlcmllc5ROaBloGmgbiGgcSyqFlGgefZR1\nYowPZ2FtZV9zaG9ydF9uYW1llE5oDYwBNZSMEWlubGluZV9tZXNzYWdlX2lklE6MB21lc3NhZ2WU\njBF0ZWxlZ3JhbS5fbWVzc2FnZZSMB01lc3NhZ2WUk5QpgZR9lCiMFV9lZmZlY3RpdmVfYXR0YWNo\nbWVudJSMHHRlbGVncmFtLl91dGlscy5kZWZhdWx0dmFsdWWUjAxEZWZhdWx0VmFsdWWUk5QpgZRO\nfZSMBXZhbHVllE5zhpRijAlhbmltYXRpb26UTowFYXVkaW+UTowQYXV0aG9yX3NpZ25hdHVyZZRO\njAtib29zdF9hZGRlZJROjBZidXNpbmVzc19jb25uZWN0aW9uX2lklE6MB2NhcHRpb26UTowQY2Fw\ndGlvbl9lbnRpdGllc5QpjBRjaGFubmVsX2NoYXRfY3JlYXRlZJSJjBNjaGF0X2JhY2tncm91bmRf\nc2V0lE6MC2NoYXRfc2hhcmVklE6MEWNvbm5lY3RlZF93ZWJzaXRllE6MB2NvbnRhY3SUTowRZGVs\nZXRlX2NoYXRfcGhvdG+UiYwEZGljZZROjAhkb2N1bWVudJROjAllZGl0X2RhdGWUTowJZWZmZWN0\nX2lklE6MCGVudGl0aWVzlCmMDmV4dGVybmFsX3JlcGx5lE6MEmZvcnVtX3RvcGljX2Nsb3NlZJRO\njBNmb3J1bV90b3BpY19jcmVhdGVklE6MEmZvcnVtX3RvcGljX2VkaXRlZJROjBRmb3J1bV90b3Bp\nY19yZW9wZW5lZJROjA5mb3J3YXJkX29yaWdpbpROaC9oMSmBlH2UKGg0Tmg1Tmg2Tmg3TmgLjANC\nb3SUaA1LEGg4iGg5Tmg6TmgPTmg8TmgZjAdkZmZfYm90lGgbiGgcSxCFlGgefZR1YowEZ2FtZZRO\njBpnZW5lcmFsX2ZvcnVtX3RvcGljX2hpZGRlbpROjBxnZW5lcmFsX2ZvcnVtX3RvcGljX3VuaGlk\nZGVulE6MCGdpdmVhd2F5lE6MEmdpdmVhd2F5X2NvbXBsZXRlZJROjBBnaXZlYXdheV9jcmVhdGVk\nlE6MEGdpdmVhd2F5X3dpbm5lcnOUTowSZ3JvdXBfY2hhdF9jcmVhdGVklImMEWhhc19tZWRpYV9z\ncG9pbGVylE6MFWhhc19wcm90ZWN0ZWRfY29udGVudJROjAdpbnZvaWNllE6MFGlzX2F1dG9tYXRp\nY19mb3J3YXJklE6MD2lzX2Zyb21fb2ZmbGluZZROjBBpc190b3BpY19tZXNzYWdllE6MEGxlZnRf\nY2hhdF9tZW1iZXKUTowUbGlua19wcmV2aWV3X29wdGlvbnOUTowIbG9jYXRpb26UjBh0ZWxlZ3Jh\nbS5fZmlsZXMubG9jYXRpb26UjAhMb2NhdGlvbpSTlCmBlH2UKIwHaGVhZGluZ5ROjBNob3Jpem9u\ndGFsX2FjY3VyYWN5lE6MCGxhdGl0dWRllEdATTc/UvwmV4wLbGl2ZV9wZXJpb2SUTowJbG9uZ2l0\ndWRllEdAO8r6Hj6vaIwWcHJveGltaXR5X2FsZXJ0X3JhZGl1c5ROaBuIaBxHQDvK+h4+r2hHQE03\nP1L8JleGlGgefZR1YowObWVkaWFfZ3JvdXBfaWSUTowhbWVzc2FnZV9hdXRvX2RlbGV0ZV90aW1l\ncl9jaGFuZ2VklE6MEW1lc3NhZ2VfdGhyZWFkX2lklE6MFG1pZ3JhdGVfZnJvbV9jaGF0X2lklE6M\nEm1pZ3JhdGVfdG9fY2hhdF9pZJROjBBuZXdfY2hhdF9tZW1iZXJzlCmMDm5ld19jaGF0X3Bob3Rv\nlCmMDm5ld19jaGF0X3RpdGxllE6MDXBhc3Nwb3J0X2RhdGGUTowFcGhvdG+UKYwOcGlubmVkX21l\nc3NhZ2WUTowEcG9sbJROjBlwcm94aW1pdHlfYWxlcnRfdHJpZ2dlcmVklE6MBXF1b3RllE6MDHJl\ncGx5X21hcmt1cJSMJXRlbGVncmFtLl9pbmxpbmUuaW5saW5la2V5Ym9hcmRtYXJrdXCUjBRJbmxp\nbmVLZXlib2FyZE1hcmt1cJSTlCmBlH2UKIwPaW5saW5lX2tleWJvYXJklCiMJXRlbGVncmFtLl9p\nbmxpbmUuaW5saW5la2V5Ym9hcmRidXR0b26UjBRJbmxpbmVLZXlib2FyZEJ1dHRvbpSTlCmBlH2U\nKIwNY2FsbGJhY2tfZGF0YZSMCWZvcm1hdHRlZJSMDWNhbGxiYWNrX2dhbWWUTowJbG9naW5fdXJs\nlE6MA3BheZROjBNzd2l0Y2hfaW5saW5lX3F1ZXJ5lE6MH3N3aXRjaF9pbmxpbmVfcXVlcnlfY2hv\nc2VuX2NoYXSUTowgc3dpdGNoX2lubGluZV9xdWVyeV9jdXJyZW50X2NoYXSUTowEdGV4dJSMFEN1\ndGUgZm9ybWF0dGVkIHRleHQhlIwDdXJslE6MB3dlYl9hcHCUTmgbiGgcKGivTk5op05OTk5OdJRo\nHn2UdWKFlGijKYGUfZQoaKaMC2F0dGFjaG1lbnRzlGioTmipTmiqTmirTmisTmitTmiujBVNdWx0\naXBsZSBhdHRhY2htZW50cyGUaLBOaLFOaBuIaBwoaLhOTmi3Tk5OTk50lGgefZR1YoWUaKMpgZR9\nlChopmguaKhOaKlOaKpOaKtOaKxOaK1OaK6MDVNlY3JldCBpbWFnZSGUaLBOaLFOaBuIaBwoaL5O\nTmguTk5OTk50lGgefZR1YoWUaKMpgZR9lChopowJdGh1bWJuYWlslGioTmipTmiqTmirTmisTmit\nTmiujBhEb2N1bWVudCB3aXRoIHRodW1ibmFpbCGUaLBOaLFOaBuIaBwoaMVOTmjETk5OTk50lGge\nfZR1YoWUaKMpgZR9lChopowEaGFzaJRoqE5oqU5oqk5oq05orE5orU5orowcRmlyc3QgYXR0YWNo\nbWVudCBieXRlcyBoYXNoIZRosE5osU5oG4hoHChozE5OaMtOTk5OTnSUaB59lHVihZRooymBlH2U\nKGimjAdyZXN0YXJ0lGioTmipTmiqTmirTmisTmitTmiujAhSZXN0YXJ0IZRosE5osU5oG4hoHCho\n005OaNJOTk5OTnSUaB59lHViaKMpgZR9lChopowEcXVpdJRoqE5oqU5oqk5oq05orE5orU5orowF\nUXVpdCGUaLBOaLFOaBuIaBwoaNlOTmjYTk5OTk50lGgefZR1YoaUdJRoG4hoHGjdhZRoHn2UdWKM\nEHJlcGx5X3RvX21lc3NhZ2WUTowOcmVwbHlfdG9fc3RvcnmUTowSc2VuZGVyX2Jvb3N0X2NvdW50\nlE6ME3NlbmRlcl9idXNpbmVzc19ib3SUTowLc2VuZGVyX2NoYXSUTowYc2hvd19jYXB0aW9uX2Fi\nb3ZlX21lZGlhlE6MB3N0aWNrZXKUTowFc3RvcnmUTowSc3VjY2Vzc2Z1bF9wYXltZW50lE6MF3N1\ncGVyZ3JvdXBfY2hhdF9jcmVhdGVklIlork6MDHVzZXJzX3NoYXJlZJROjAV2ZW51ZZROjAd2aWFf\nYm90lE6MBXZpZGVvlE6MEHZpZGVvX2NoYXRfZW5kZWSUTowfdmlkZW9fY2hhdF9wYXJ0aWNpcGFu\ndHNfaW52aXRlZJROjBR2aWRlb19jaGF0X3NjaGVkdWxlZJROjBJ2aWRlb19jaGF0X3N0YXJ0ZWSU\nTowKdmlkZW9fbm90ZZROjAV2b2ljZZROjAx3ZWJfYXBwX2RhdGGUTowUd3JpdGVfYWNjZXNzX2Fs\nbG93ZWSUTowEY2hhdJRoCYwEZGF0ZZSMCGRhdGV0aW1llIwIZGF0ZXRpbWWUk5RDCgfoBRUTCRwA\nAACUjARweXR6lIwEX1VUQ5STlClSlIaUUpSMCm1lc3NhZ2VfaWSUSwZoG4hoHEsGaAmGlGgefZR1\nYmgbiGgcaECFlGgefZR1YowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2lu\nX3JlcXVlc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRl\nZF9idXNpbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRf\nY2hhbm5lbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROaEJOjBBtZXNz\nYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowObXlfY2hhdF9tZW1iZXKU\nTmiXTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6MEnJlbW92ZWRfY2hhdF9i\nb29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwZoG4hoHEsGhZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Here's your secret image! Run /start command again to restart.", + "attachments": [ + { + "dff_attachment_type": "image", + "source": "https://github.com/deeppavlov/dialog_flow_framework/wiki/example_attachments/deeppavlov.png", + "use_cache": true, + "cached_filename": "/tmp/dff-cache-LongpollingInterface/f5b9f966-df04-50fa-b6e1-e46fccd889bc", + "id": null, + "caption": "DeepPavlov logo", + "has_spoiler": true, + "filename": "deeppavlov_logo.png" + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your secret image! Run /start command again to restart.\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)", + "send_photo(42, '9f39f64560e6415032325cae1fec1ca06b3cc1a3549208a8a35564c0d3749062', caption='DeepPavlov logo', parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, has_spoiler=True, message_effect_id=None, reply_to_message_id=None, filename='deeppavlov_logo.png')" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 21, 19, 9, 34, tzinfo=UTC), delete_chat_photo=False, entities=(MessageEntity(length=6, offset=0, type=MessageEntityType.BOT_COMMAND),), from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=7, supergroup_chat_created=False, text='/start'), update_id=7)", + "received_message": { + "text": "/start", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVXwsAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5SMF3RlbGVncmFtLl9tZXNzYWdlZW50aXR5lIwNTWVzc2FnZUVudGl0eZSTlCmB\nlH2UKIwPY3VzdG9tX2Vtb2ppX2lklE6MCGxhbmd1YWdllE6MBmxlbmd0aJRLBowGb2Zmc2V0lEsA\naBJoE4wRTWVzc2FnZUVudGl0eVR5cGWUk5SMC2JvdF9jb21tYW5klIWUUpSMA3VybJROjAR1c2Vy\nlE5oG4hoHGhdSwBLBoeUaB59lHVihZSMDmV4dGVybmFsX3JlcGx5lE6MEmZvcnVtX3RvcGljX2Ns\nb3NlZJROjBNmb3J1bV90b3BpY19jcmVhdGVklE6MEmZvcnVtX3RvcGljX2VkaXRlZJROjBRmb3J1\nbV90b3BpY19yZW9wZW5lZJROjA5mb3J3YXJkX29yaWdpbpROjAlmcm9tX3VzZXKUjA50ZWxlZ3Jh\nbS5fdXNlcpRoEJOUKYGUfZQojBhhZGRlZF90b19hdHRhY2htZW50X21lbnWUTowXY2FuX2Nvbm5l\nY3RfdG9fYnVzaW5lc3OUTowPY2FuX2pvaW5fZ3JvdXBzlE6MG2Nhbl9yZWFkX2FsbF9ncm91cF9t\nZXNzYWdlc5ROaAtoDGgNSyqMBmlzX2JvdJSJjAppc19wcmVtaXVtlE6MDWxhbmd1YWdlX2NvZGWU\njAJlbpRoD2gQjBdzdXBwb3J0c19pbmxpbmVfcXVlcmllc5ROaBloGmgbiGgcSyqFlGgefZR1YowE\nZ2FtZZROjBpnZW5lcmFsX2ZvcnVtX3RvcGljX2hpZGRlbpROjBxnZW5lcmFsX2ZvcnVtX3RvcGlj\nX3VuaGlkZGVulE6MCGdpdmVhd2F5lE6MEmdpdmVhd2F5X2NvbXBsZXRlZJROjBBnaXZlYXdheV9j\ncmVhdGVklE6MEGdpdmVhd2F5X3dpbm5lcnOUTowSZ3JvdXBfY2hhdF9jcmVhdGVklImMEWhhc19t\nZWRpYV9zcG9pbGVylE6MFWhhc19wcm90ZWN0ZWRfY29udGVudJROjAdpbnZvaWNllE6MFGlzX2F1\ndG9tYXRpY19mb3J3YXJklE6MD2lzX2Zyb21fb2ZmbGluZZROjBBpc190b3BpY19tZXNzYWdllE6M\nEGxlZnRfY2hhdF9tZW1iZXKUTowUbGlua19wcmV2aWV3X29wdGlvbnOUTowIbG9jYXRpb26UTowO\nbWVkaWFfZ3JvdXBfaWSUTowhbWVzc2FnZV9hdXRvX2RlbGV0ZV90aW1lcl9jaGFuZ2VklE6MEW1l\nc3NhZ2VfdGhyZWFkX2lklE6MFG1pZ3JhdGVfZnJvbV9jaGF0X2lklE6MEm1pZ3JhdGVfdG9fY2hh\ndF9pZJROjBBuZXdfY2hhdF9tZW1iZXJzlCmMDm5ld19jaGF0X3Bob3RvlCmMDm5ld19jaGF0X3Rp\ndGxllE6MDXBhc3Nwb3J0X2RhdGGUTowFcGhvdG+UKYwOcGlubmVkX21lc3NhZ2WUTowEcG9sbJRO\njBlwcm94aW1pdHlfYWxlcnRfdHJpZ2dlcmVklE6MBXF1b3RllE6MDHJlcGx5X21hcmt1cJROjBBy\nZXBseV90b19tZXNzYWdllE6MDnJlcGx5X3RvX3N0b3J5lE6MEnNlbmRlcl9ib29zdF9jb3VudJRO\njBNzZW5kZXJfYnVzaW5lc3NfYm90lE6MC3NlbmRlcl9jaGF0lE6MGHNob3dfY2FwdGlvbl9hYm92\nZV9tZWRpYZROjAdzdGlja2VylE6MBXN0b3J5lE6MEnN1Y2Nlc3NmdWxfcGF5bWVudJROjBdzdXBl\ncmdyb3VwX2NoYXRfY3JlYXRlZJSJjAR0ZXh0lIwGL3N0YXJ0lIwMdXNlcnNfc2hhcmVklE6MBXZl\nbnVllE6MB3ZpYV9ib3SUTowFdmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0\nX3BhcnRpY2lwYW50c19pbnZpdGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2No\nYXRfc3RhcnRlZJROjAp2aWRlb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0\nZV9hY2Nlc3NfYWxsb3dlZJROjARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZST\nlEMKB+gFFRMJIgAAAJSMBHB5dHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLB2gbiGgc\nSwdoCYaUaB59lHVijBBtZXNzYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSU\nTowObXlfY2hhdF9tZW1iZXKUTmiVTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5\nlE6MEnJlbW92ZWRfY2hhdF9ib29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwdo\nG4hoHEsHhZRoHn2UdWIu\n" + }, + "response_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "location", + "longitude": 27.792887, + "latitude": 58.43161, + "reply_markup": "gASV4gMAAAAAAACMJXRlbGVncmFtLl9pbmxpbmUuaW5saW5la2V5Ym9hcmRtYXJrdXCUjBRJbmxp\nbmVLZXlib2FyZE1hcmt1cJSTlCmBlH2UKIwPaW5saW5lX2tleWJvYXJklCiMJXRlbGVncmFtLl9p\nbmxpbmUuaW5saW5la2V5Ym9hcmRidXR0b26UjBRJbmxpbmVLZXlib2FyZEJ1dHRvbpSTlCmBlH2U\nKIwNY2FsbGJhY2tfZGF0YZSMCWZvcm1hdHRlZJSMDWNhbGxiYWNrX2dhbWWUTowJbG9naW5fdXJs\nlE6MA3BheZROjBNzd2l0Y2hfaW5saW5lX3F1ZXJ5lE6MH3N3aXRjaF9pbmxpbmVfcXVlcnlfY2hv\nc2VuX2NoYXSUTowgc3dpdGNoX2lubGluZV9xdWVyeV9jdXJyZW50X2NoYXSUTowEdGV4dJSMFEN1\ndGUgZm9ybWF0dGVkIHRleHQhlIwDdXJslE6MB3dlYl9hcHCUTowHX2Zyb3plbpSIjAlfaWRfYXR0\ncnOUKGgUTk5oDE5OTk5OdJSMCmFwaV9rd2FyZ3OUfZR1YoWUaAgpgZR9lChoC4wLYXR0YWNobWVu\ndHOUaA1OaA5OaA9OaBBOaBFOaBJOaBOMFU11bHRpcGxlIGF0dGFjaG1lbnRzIZRoFU5oFk5oF4ho\nGChoIE5OaB9OTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAZzZWNyZXSUaA1OaA5OaA9OaBBOaBFO\naBJOaBOMDVNlY3JldCBpbWFnZSGUaBVOaBZOaBeIaBgoaCdOTmgmTk5OTk50lGgafZR1YoWUaAgp\ngZR9lChoC4wJdGh1bWJuYWlslGgNTmgOTmgPTmgQTmgRTmgSTmgTjBhEb2N1bWVudCB3aXRoIHRo\ndW1ibmFpbCGUaBVOaBZOaBeIaBgoaC5OTmgtTk5OTk50lGgafZR1YoWUaAgpgZR9lChoC4wEaGFz\naJRoDU5oDk5oD05oEE5oEU5oEk5oE4wcRmlyc3QgYXR0YWNobWVudCBieXRlcyBoYXNoIZRoFU5o\nFk5oF4hoGChoNU5OaDROTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAdyZXN0YXJ0lGgNTmgOTmgP\nTmgQTmgRTmgSTmgTjAhSZXN0YXJ0IZRoFU5oFk5oF4hoGChoPE5OaDtOTk5OTnSUaBp9lHViaAgp\ngZR9lChoC4wEcXVpdJRoDU5oDk5oD05oEE5oEU5oEk5oE4wFUXVpdCGUaBVOaBZOaBeIaBgoaEJO\nTmhBTk5OTk50lGgafZR1YoaUdJRoF4hoGGhGhZRoGn2UdWIu\n", + "__pickled_extra_fields__": [ + "reply_markup" + ] + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_location(42, 58.43161, 27.792887, horizontal_accuracy=None, disable_notification=None, protect_content=None, reply_markup=InlineKeyboardMarkup(inline_keyboard=((InlineKeyboardButton(callback_data='formatted', text='Cute formatted text!'),), (InlineKeyboardButton(callback_data='attachments', text='Multiple attachments!'),), (InlineKeyboardButton(callback_data='secret', text='Secret image!'),), (InlineKeyboardButton(callback_data='thumbnail', text='Document with thumbnail!'),), (InlineKeyboardButton(callback_data='hash', text='First attachment bytes hash!'),), (InlineKeyboardButton(callback_data='restart', text='Restart!'), InlineKeyboardButton(callback_data='quit', text='Quit!')))), message_effect_id=None, reply_to_message_id=None)" + ] + }, + { + "update": "Update(callback_query=CallbackQuery(chat_instance='-1', data='thumbnail', from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), id='7', message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 21, 19, 9, 34, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Bot', id=16, is_bot=True, username='dff_bot'), group_chat_created=False, location=Location(latitude=58.43162, longitude=27.792879), message_id=8, reply_markup=InlineKeyboardMarkup(inline_keyboard=((InlineKeyboardButton(callback_data='formatted', text='Cute formatted text!'),), (InlineKeyboardButton(callback_data='attachments', text='Multiple attachments!'),), (InlineKeyboardButton(callback_data='secret', text='Secret image!'),), (InlineKeyboardButton(callback_data='thumbnail', text='Document with thumbnail!'),), (InlineKeyboardButton(callback_data='hash', text='First attachment bytes hash!'),), (InlineKeyboardButton(callback_data='restart', text='Restart!'), InlineKeyboardButton(callback_data='quit', text='Quit!')))), supergroup_chat_created=False)), update_id=8)", + "received_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "callback_query", + "query_string": "thumbnail" + } + ], + "annotations": null, + "misc": null, + "original_message": "gASV+g8AAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUjBd0ZWxlZ3JhbS5fY2FsbGJhY2txdWVyeZSMDUNhbGxiYWNrUXVlcnmUk5QpgZR9\nlCiMDWNoYXRfaW5zdGFuY2WUjAItMZSMBGRhdGGUjAl0aHVtYm5haWyUjAlmcm9tX3VzZXKUjA50\nZWxlZ3JhbS5fdXNlcpRoEJOUKYGUfZQojBhhZGRlZF90b19hdHRhY2htZW50X21lbnWUTowXY2Fu\nX2Nvbm5lY3RfdG9fYnVzaW5lc3OUTowPY2FuX2pvaW5fZ3JvdXBzlE6MG2Nhbl9yZWFkX2FsbF9n\ncm91cF9tZXNzYWdlc5ROaAtoDGgNSyqMBmlzX2JvdJSJjAppc19wcmVtaXVtlE6MDWxhbmd1YWdl\nX2NvZGWUjAJlbpRoD2gQjBdzdXBwb3J0c19pbmxpbmVfcXVlcmllc5ROaBloGmgbiGgcSyqFlGge\nfZR1YowPZ2FtZV9zaG9ydF9uYW1llE5oDYwBN5SMEWlubGluZV9tZXNzYWdlX2lklE6MB21lc3Nh\nZ2WUjBF0ZWxlZ3JhbS5fbWVzc2FnZZSMB01lc3NhZ2WUk5QpgZR9lCiMFV9lZmZlY3RpdmVfYXR0\nYWNobWVudJSMHHRlbGVncmFtLl91dGlscy5kZWZhdWx0dmFsdWWUjAxEZWZhdWx0VmFsdWWUk5Qp\ngZROfZSMBXZhbHVllE5zhpRijAlhbmltYXRpb26UTowFYXVkaW+UTowQYXV0aG9yX3NpZ25hdHVy\nZZROjAtib29zdF9hZGRlZJROjBZidXNpbmVzc19jb25uZWN0aW9uX2lklE6MB2NhcHRpb26UTowQ\nY2FwdGlvbl9lbnRpdGllc5QpjBRjaGFubmVsX2NoYXRfY3JlYXRlZJSJjBNjaGF0X2JhY2tncm91\nbmRfc2V0lE6MC2NoYXRfc2hhcmVklE6MEWNvbm5lY3RlZF93ZWJzaXRllE6MB2NvbnRhY3SUTowR\nZGVsZXRlX2NoYXRfcGhvdG+UiYwEZGljZZROjAhkb2N1bWVudJROjAllZGl0X2RhdGWUTowJZWZm\nZWN0X2lklE6MCGVudGl0aWVzlCmMDmV4dGVybmFsX3JlcGx5lE6MEmZvcnVtX3RvcGljX2Nsb3Nl\nZJROjBNmb3J1bV90b3BpY19jcmVhdGVklE6MEmZvcnVtX3RvcGljX2VkaXRlZJROjBRmb3J1bV90\nb3BpY19yZW9wZW5lZJROjA5mb3J3YXJkX29yaWdpbpROaC9oMSmBlH2UKGg0Tmg1Tmg2Tmg3TmgL\njANCb3SUaA1LEGg4iGg5Tmg6TmgPTmg8TmgZjAdkZmZfYm90lGgbiGgcSxCFlGgefZR1YowEZ2Ft\nZZROjBpnZW5lcmFsX2ZvcnVtX3RvcGljX2hpZGRlbpROjBxnZW5lcmFsX2ZvcnVtX3RvcGljX3Vu\naGlkZGVulE6MCGdpdmVhd2F5lE6MEmdpdmVhd2F5X2NvbXBsZXRlZJROjBBnaXZlYXdheV9jcmVh\ndGVklE6MEGdpdmVhd2F5X3dpbm5lcnOUTowSZ3JvdXBfY2hhdF9jcmVhdGVklImMEWhhc19tZWRp\nYV9zcG9pbGVylE6MFWhhc19wcm90ZWN0ZWRfY29udGVudJROjAdpbnZvaWNllE6MFGlzX2F1dG9t\nYXRpY19mb3J3YXJklE6MD2lzX2Zyb21fb2ZmbGluZZROjBBpc190b3BpY19tZXNzYWdllE6MEGxl\nZnRfY2hhdF9tZW1iZXKUTowUbGlua19wcmV2aWV3X29wdGlvbnOUTowIbG9jYXRpb26UjBh0ZWxl\nZ3JhbS5fZmlsZXMubG9jYXRpb26UjAhMb2NhdGlvbpSTlCmBlH2UKIwHaGVhZGluZ5ROjBNob3Jp\nem9udGFsX2FjY3VyYWN5lE6MCGxhdGl0dWRllEdATTc/UvwmV4wLbGl2ZV9wZXJpb2SUTowJbG9u\nZ2l0dWRllEdAO8r6Hj6vaIwWcHJveGltaXR5X2FsZXJ0X3JhZGl1c5ROaBuIaBxHQDvK+h4+r2hH\nQE03P1L8JleGlGgefZR1YowObWVkaWFfZ3JvdXBfaWSUTowhbWVzc2FnZV9hdXRvX2RlbGV0ZV90\naW1lcl9jaGFuZ2VklE6MEW1lc3NhZ2VfdGhyZWFkX2lklE6MFG1pZ3JhdGVfZnJvbV9jaGF0X2lk\nlE6MEm1pZ3JhdGVfdG9fY2hhdF9pZJROjBBuZXdfY2hhdF9tZW1iZXJzlCmMDm5ld19jaGF0X3Bo\nb3RvlCmMDm5ld19jaGF0X3RpdGxllE6MDXBhc3Nwb3J0X2RhdGGUTowFcGhvdG+UKYwOcGlubmVk\nX21lc3NhZ2WUTowEcG9sbJROjBlwcm94aW1pdHlfYWxlcnRfdHJpZ2dlcmVklE6MBXF1b3RllE6M\nDHJlcGx5X21hcmt1cJSMJXRlbGVncmFtLl9pbmxpbmUuaW5saW5la2V5Ym9hcmRtYXJrdXCUjBRJ\nbmxpbmVLZXlib2FyZE1hcmt1cJSTlCmBlH2UKIwPaW5saW5lX2tleWJvYXJklCiMJXRlbGVncmFt\nLl9pbmxpbmUuaW5saW5la2V5Ym9hcmRidXR0b26UjBRJbmxpbmVLZXlib2FyZEJ1dHRvbpSTlCmB\nlH2UKIwNY2FsbGJhY2tfZGF0YZSMCWZvcm1hdHRlZJSMDWNhbGxiYWNrX2dhbWWUTowJbG9naW5f\ndXJslE6MA3BheZROjBNzd2l0Y2hfaW5saW5lX3F1ZXJ5lE6MH3N3aXRjaF9pbmxpbmVfcXVlcnlf\nY2hvc2VuX2NoYXSUTowgc3dpdGNoX2lubGluZV9xdWVyeV9jdXJyZW50X2NoYXSUTowEdGV4dJSM\nFEN1dGUgZm9ybWF0dGVkIHRleHQhlIwDdXJslE6MB3dlYl9hcHCUTmgbiGgcKGivTk5op05OTk5O\ndJRoHn2UdWKFlGijKYGUfZQoaKaMC2F0dGFjaG1lbnRzlGioTmipTmiqTmirTmisTmitTmiujBVN\ndWx0aXBsZSBhdHRhY2htZW50cyGUaLBOaLFOaBuIaBwoaLhOTmi3Tk5OTk50lGgefZR1YoWUaKMp\ngZR9lChopowGc2VjcmV0lGioTmipTmiqTmirTmisTmitTmiujA1TZWNyZXQgaW1hZ2UhlGiwTmix\nTmgbiGgcKGi/Tk5ovk5OTk5OdJRoHn2UdWKFlGijKYGUfZQoaKZoLmioTmipTmiqTmirTmisTmit\nTmiujBhEb2N1bWVudCB3aXRoIHRodW1ibmFpbCGUaLBOaLFOaBuIaBwoaMVOTmguTk5OTk50lGge\nfZR1YoWUaKMpgZR9lChopowEaGFzaJRoqE5oqU5oqk5oq05orE5orU5orowcRmlyc3QgYXR0YWNo\nbWVudCBieXRlcyBoYXNoIZRosE5osU5oG4hoHChozE5OaMtOTk5OTnSUaB59lHVihZRooymBlH2U\nKGimjAdyZXN0YXJ0lGioTmipTmiqTmirTmisTmitTmiujAhSZXN0YXJ0IZRosE5osU5oG4hoHCho\n005OaNJOTk5OTnSUaB59lHViaKMpgZR9lChopowEcXVpdJRoqE5oqU5oqk5oq05orE5orU5orowF\nUXVpdCGUaLBOaLFOaBuIaBwoaNlOTmjYTk5OTk50lGgefZR1YoaUdJRoG4hoHGjdhZRoHn2UdWKM\nEHJlcGx5X3RvX21lc3NhZ2WUTowOcmVwbHlfdG9fc3RvcnmUTowSc2VuZGVyX2Jvb3N0X2NvdW50\nlE6ME3NlbmRlcl9idXNpbmVzc19ib3SUTowLc2VuZGVyX2NoYXSUTowYc2hvd19jYXB0aW9uX2Fi\nb3ZlX21lZGlhlE6MB3N0aWNrZXKUTowFc3RvcnmUTowSc3VjY2Vzc2Z1bF9wYXltZW50lE6MF3N1\ncGVyZ3JvdXBfY2hhdF9jcmVhdGVklIlork6MDHVzZXJzX3NoYXJlZJROjAV2ZW51ZZROjAd2aWFf\nYm90lE6MBXZpZGVvlE6MEHZpZGVvX2NoYXRfZW5kZWSUTowfdmlkZW9fY2hhdF9wYXJ0aWNpcGFu\ndHNfaW52aXRlZJROjBR2aWRlb19jaGF0X3NjaGVkdWxlZJROjBJ2aWRlb19jaGF0X3N0YXJ0ZWSU\nTowKdmlkZW9fbm90ZZROjAV2b2ljZZROjAx3ZWJfYXBwX2RhdGGUTowUd3JpdGVfYWNjZXNzX2Fs\nbG93ZWSUTowEY2hhdJRoCYwEZGF0ZZSMCGRhdGV0aW1llIwIZGF0ZXRpbWWUk5RDCgfoBRUTCSIA\nAACUjARweXR6lIwEX1VUQ5STlClSlIaUUpSMCm1lc3NhZ2VfaWSUSwhoG4hoHEsIaAmGlGgefZR1\nYmgbiGgcaECFlGgefZR1YowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2lu\nX3JlcXVlc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRl\nZF9idXNpbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRf\nY2hhbm5lbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROaEJOjBBtZXNz\nYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowObXlfY2hhdF9tZW1iZXKU\nTmiXTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6MEnJlbW92ZWRfY2hhdF9i\nb29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwhoG4hoHEsIhZRoHn2UdWIu\n" + }, + "response_message": { + "text": "Here's your document with tumbnail! Run /start command again to restart.", + "attachments": [ + { + "dff_attachment_type": "document", + "source": "https://github.com/deeppavlov/dialog_flow_framework/wiki/example_attachments/deeppavlov-article.pdf", + "use_cache": true, + "cached_filename": "/tmp/dff-cache-LongpollingInterface/ff2b4361-417f-5fa1-be67-79e68a3f2e80", + "id": null, + "caption": "DeepPavlov article", + "filename": "deeppavlov_article.pdf", + "thumbnail": "gASVySsAAAAAAABCwisAAIlQTkcNChoKAAAADUlIRFIAAADIAAAAyAgCAAAAIjo5yQAAK4lJREFU\neJzsnXdcFFfXx+/sbF/KsnSQLiiIUlSwgo+KYi9RAbvYS4wleZ7EqNFojEaTqOlqLLFh77F3jaCA\nCEgREJDeWbb394PwIiIus7NTFrPfj3/g7My9h+U3t557DlWj0QAjRrCGQrYBRj5MjMIyggtGYRnB\nBaOwjOCCUVhGcMEoLCO4YBSWEVwwCssILhiFZQQXqGQbgBIlf6+qYhHZVuAMbEOzP0NhdifbDjS0\n1xZLVbmSbBPwR1WuEsSQbQRK2quwgEZCtgWEoBGTbQFK2q2wjBg2RmEZwQWjsIzgglFYRnDBKCw0\n8GXsEhGPL2PrU4hcRX1a4Y6dUYZFe13H0s7DEu9tTycxYflgp8Ro76sQhOipx2Ve3yZEMWH5KNfY\nyZ1ua7nzUn7Q7ucjulrm7gz5FbWRNwv9l91fkDl1DuoSDJkPU1ilYh6DIt8QvD/65qdcunCoS8LG\nJ5OFCtZnAcddzCrOvex9raB7oHXWbJ+rmxPq9ZfF77Cgy8VyiYVGAzb13jvk3OYulnnPq10flnSh\nQqqvgw8czw515FQOd31yLCuExxBM9rrDl5mk1zg3VLcrddizKo/edmmhDsm704Z9HXywWMj74/mI\n9cEHm1t1JPM/D0u7MGH5V0EHM2s6XMzrNanjPZK+Idz5YLtCGqzqyC0Jc46/Vej/6YO5tqyavvap\n824vyxdYr4md8XHXs/vShqZVO5/L7ZNe4+zFLVjxYD4AQAMgCqQGQEOnKDtxC77scVitATFZoQo1\nvDF+MgDgh6cfmdFFzSs6md3vyIuBEzzurX88tUzC/Tsv6G6R76X8IImS3sKkblYvV/c4nFdnczwr\n1MO8JNz5ybGsAcR+K8TxYbZYTYgVTAum8GZhQHKVuylNYsuqiSvtXCs3+eT+Ig5NSgFqAMB837/N\naKIfnk4AAMSWek++umplwClvXsHauGl3Cv3rFGwf3qto76urHkUnlHfkyznBdi+aV5FV6xhkm/Gf\nDsn97FOTq9wjve5cyO39qNRnR8gvDTeoNRAF0mg0YF/6kCflncrEFiGOqTym0Ncyj6RvhQg+WGEV\nCS1/SxlxIifk0sjVpSIelyGY3OkOC5axqPX/1vQ8DEEaJ9MKAEB6tVNiRcchzvEAgP4OqSeHbWgo\n4VhW6Ibgv/akhQMAmFTFoq7nh1345que9b3bS75dvsCmTMzN4dt15BZtSYi8VeB37VWPdUH1n/Y5\nucOGXdPdOhsAcDqnz+K7S4tnRQoVzN3Ph18Yufa/D+sHVeVi82eV7jIV7XFZpyDbTLK/LeyB161b\nR7YNOpNUJLBWbtVyA5WigiDIhCZdH3zQw7w0xDGlQGjzoMS3g0mln3Wuv1XO+dzeVVKzYNuMvzLD\nxEpmgHXOZ4EnmLDcgV3dyaKwoZBO3MLYMu+JHvd9eK/sODU+vPwqqfmSbufYNHlcWSeJitnBpJIC\naUa7xVox6+4U+23svd+HV8BliJmwfIRrnA+vAADAospMaeJ+DmkMWOlrmXe/2HdOlyte3CKJkpFY\n4dXLLqNAaNPbLv19v0iB2FvNGsamwzh8i/gCta9zhQkFdRuu515IqxQvGIFJgb1Pbv8l9OfA162L\nAbInLXz14+VL+nb4dICLOas9dS/txtbcasmmG3kH4ksUKizfhEsjV5vSDXo/u1ai3Hgjb09c8ReD\nXJf2dyLbHKS0g1mhUqVefTnHc9M/e+KKsVUVAIDHFNIoKmzLxINSgfyTsy/cNj688aKabFsQYegt\n1vnUioWnMorr5GQbYhDk1UjD/ng6pBNvX4SPgzmDbHO0YbgtVoVQPn5f8ph9yUZVteBaZnWnzY9+\neVBAtiHaMFBh7Xtc7L0l9kxqBdmGGChCuWrJmRcDfk14Xiok25bWMThhVYrkkw+mRh9LrxIrtNym\n1iDb/2vnKFTaFhru5tQG73iy61GRSk2gTcgwLGHdf1nTdWvc0aSyNu88n9uLEIvIRKGCrxcEar9H\nJFfPP5kxdt+zaq3vIfEY0DrWqr+zt95+pVQjsodNlYY5JVix6vC3ixw0GpBY4ZlU2RHh/Xam9PPR\n3Xo6m+NsF1IMQlg1YsWMo2kX0irJNqR9w6RSNg33WB7qTLYhwCCElVkuGrsvOaO8vR5HMTSW9u+w\nbZQnDSZ5kEOysO69rBn95zO+tB0sUbYj+rtzL0T7kbsFRKaw9sYVLziZoUA2qDKiE64WzDuLAl14\nLLIMIEdYagDWXc7ZcONDdkgiHWcu88QM3yCShvMkCEupUn95Oee7268IrvdfiCWbejbar58bl/iq\nSRDWsrOZO+4XElzpvxZTBnw+2m9ARwuC6yVaWPNPpO+KLSayRiMsGuXvOf4Ea4vQSemS0xlGVRGP\nRKEevifpQW4NkZUSJ6z/Xcz65WERYdUZaY5EoR79Z3JCAXEbFQQJ69ubucbROrnUSJRDdydllImI\nqY4IYR14Urzq75cEVGREO1UixcDfEssEMgLqwl1Yj1/xF5z8AI83tVNKBPLwXUkiOe5bHfgKK7Nc\nNHx3klRpeO5C/2KSioXzTqTLcfbhwlFYApky8mBqlViJXxVG0HEksWzLLXy3PfASlkoN5p/ISCo2\nUMdZI19dyb2agaOfEl7C+vFe/tGnbTuCGiELDQBRh57nVuF1phIXYT15Vbf6cg4eJRvBkBqJctJf\nKTg5l2AvLIlCFXUoVaY0OsO0A+ILBeuv4tIEYC+sZWdf5ODWwBrBnK+v5z1+xce8WIyFdTWjyrgb\n2O6IPJgqUWC8soWlsKpE8jnH3xuRx4jBklstXXEuC9sysXSbWXAi/Y/22FypVeySZJqwTOQYqDSx\naf4JpJSZ5j9kVuXAMoGKaS4zcxS49FEzzcizFS9gCDxe1jOwA2a/GmbCupdTM+j3pwhPBRoU1k/2\nmL2KrZ+BQ3DRgM9lPLfGD9Qqu39+4pSlNr9ZRWOV95gtdvAnx1Y88XcwebS0B5OGTZA3bLpChUq9\n7NyL9qgqWFRl+lpVr18ylVnOraaPOMWJLVRVf79CYvfoF0algQZq04ekYuEvDzHz7MXmhNAfj4qe\nFrXLRXYNBQYQBWgaN86cLU1H9LTvwGX06GBWEF+5Pe7Nnc4uLr6+vjeuX5fL5X1Lz2/9JkahUqeW\nCp8VCwv5sttZNbXSdr95tf5a7pRAOzszDAIkYdAVVork3ltiK0WGFTsAOc4pR2gv6hsqFpt1/NQp\nb2/vhusymWxu9Ox/Hj4EAMyZO3fFZ5/S6fSE+PiICRMBAIdjjgb3ehM/Qq5SpxQLb2fX3M+tvZxR\nhXmAOMJY3Nfx5/Gd9S8HA2GtbZ8HubhMamSA7YI+jn4OpokJiTk52UOHDjUzb3lYKutFFpfLtbax\nbroya/qM+/furV67ZmZ0dKslK1TqI4mlx5LKr2RUtUd9PV0R5O9oqmch+naFxXzZd3fy9SyEYAId\nTRf1dZzZ07HpGHpg98DA7q3HdfH08mxxxdHREQCQnfXeYRYNpszo6TCjp0OZQLb19qtdsUUCWXs6\n6r3+2sszs/z0LETfFuvj05k/Yzfiw5t+buabhnv0d9frvMqd27dTklM6enYcNnw4kvsVKvWeuOLV\nl3Oq248HUeKKoAD9Gi29hFUqkDl9/bBdTAaDnM2+Dncf2smSLANEctX2e6++u51f1x4CVQzsaHFz\nYRuhubSjl7AWn8r49R9DP3hjxoQ3hnss6ONIegAWAMCrGunnl7JjnpYZ/rv4bGVQNwf0jRZ6YfGl\nSpu19+SGPf0Z2om3P9IHk/kzhlxKq1xwMqOQT8ShBtREBdgemeqL+nH0L/E313MNWVVUCrRrYucr\n8wIMTVUAgBE+Vokrg0Z3sSLbEG0cfVqWVYE+aBlKYSnVmt1xBrMtqFZRheX0mnxGTV7DP0+W9OHH\n3ef2ciTbsvdizaGfi/bbPMKDUfuKKqoAakMceP3+CP04B2VXeCSxdMrh56hr1R8av4hdlsoue04V\nV9FElZDmzR+mi2+XP/fvt7Iy6PagiatXrny2YqVIKpOb2Co51mIbH7G9n5JjEMYzqJSqDSEcVCmi\nUAor8Ic4cvZw1ErT/Fjuiyt0YWmrn/fr33/vgf0UCvnjdOQ8S3q2cN688vLypisSS8+aTsMk9t1I\ntaue3z7qtKBPBxQPohHW00JB4I+PUVSmJ5xXsVYpJ6jS97o7jhk7dsu2rVSqoedxeZfCgoIJ48ZX\nVr51bEbKdan0j5JZIg2cjAe9XMweLe2J4kE0b/aBeKJHV1Rhuf397+2e7NGiqtFjxnz3/bb2qCoA\nQAcnp1Nnzzg4ODS/yKzNd7yzhffsGKQkLelLbH7do7xaFA/qLCylWnOW2EwkjKoch3tb2eXafFND\nBwzYvPU7GG5/CSObcOzQ4fc9u1tsVkJAY5F93fbRzxQ5ac4jp5LR/Ll1Ftbl9Mr8GuIWYFhlaQ73\nttIk2mI7+fr6bv9pJ53eMrl3u8PHx+fnX39lMpktrnPK0+zv/0iRCUix6nRKOYrj+DoL62Ryuc6V\noIVZnmH/z06KWtsWm42NzW+7d5ma6rsbbyD06dtn9Vdr373OrM23f7gDaP0qcCK3WhpfoPMxHt2E\nJVOqL6dX6VoHOmiCUtvHu6C2vsodP/9kb29PjEnEEBkVNSli0rvXmTV5No93k2ER2BWr84KWbsJK\nKKirIMahT6O2jt9HlbURge6T5ct7BgURYQ+xrFm3zt3D493rpkUJJv/vSE0kt7J1DjOpm7CQ5OXC\nBIv0i6zqNk7oevv4fPzJUmLsIRgWi7Xz558gqJXUedaJByGllGB78qqlz4p0G+HpJqzrmUQkJKbI\nBOY5N9u4h0LZvnMHAcaQRWdv70VLlrx7naKScTOvEG/PZR1D0+ggrIwyUaYeu5LI4WZegeVthMpc\nsGihR0cyVw4JYM68ue7u7u9et3hxBaiIPmHwIFe38bsOwnpCSMxdSCExzX+o/R4nZ+ely5YRYAy5\nmJqafva//757HVIrTfP/IdiY6y+qq0Q6rNPqICxiFhpYFZnUthYD5y9c0E5X2HUlbOjQ3n36vHud\nU5RIsCVyleZ5qQ4Rl3UQVjIh4fk4JUnab+js7T1u/HgCLDEQlq9c8e5FZlU28b3h5QwdVpqQCiu9\nVJRXg/9kRKNhad26AQDMmh3NYBic7x5+BHbv7u/f8kQ/rJKxKl8QbEkaHi3Wy2oiQl5RheU0sbbX\nwsbGZviIEQRYYlAsXd7KgJImIjrT8a2cGhniANhIhXU3h4hMLLCijVlnRFQki0Vackey6NO3r5OT\nU4uLlLYmzpgjlKmQJ7ZAKqzCWiIW5WCtm80wDE+KiCDADEODSqV+NHFCi4uwhIg1xRZkI47ViHRu\ndVP3RX0UwFrngz2Dguzf9lgiHpXghFp0UcsNsNl0CnsQ5vWOHT9+5/YdavWbngjSkJCW4V5OzUfd\nbJDciUhYLyvF5UIi5iCQVnfWEaNGEmCDdjTyFLXwmJYbKKw+AGAvrA4dOvQMCoqLfbNR2Mp2D/5U\nId4pRiSsKjH5kWRodNrgsDCyrQAAdoAYAVpvwOscxKDBg5oLixSQZ4RAJCxDiILs69vV2tqabCsA\nlbsAcBeQUnW/kBAAviGl6iYyKjAdvCcUkuO72JzQ0FCyTSAZLy8vNptNrg0qNRAgiy+HqMWqM4BY\ndZ28MYgGpj+qugMqgbYxFsxdBHPwGguGDR1y7sxZnApHSEa5qKdzyyhi74JIWHyyhUWj0VrdMiMe\njSJHI7ml7Q6TMfjVHhgYSLqwXlZJMBPWS7LHWB09PU1MTMi1oRGqE8QM1nYDbItf5W6tedEQDMIB\nd/sQlo0NorUTAqCazwXmc8mqPSBQr5hVmFCAbKkc0eCd9GSW3fzIP2xOInm5uc+Skhpclkk/O4kw\nzF77iHFga4tj/2KwSCSSixcuTI2aPPg/A9PT0houurm5kWuVGllMhvbhLkej0cg2gVAqKipOHj8R\nc/RoUWHL+K5OLs7Z2WSmL0AY6rJtYUnwz3jeJtYGM8bCG4lE8v3WrTFHjkqlrQ9l7OxIPkRZK8Fo\nHYv0tQYAAJfLJdsE3MnLy1uz6stH/7R0Znd3d1+/cUPTaguX2/ZUH1cQ6qFtYRlCNEhDWWvAAZVK\ndfP6jZijR+/dvdv8OgzDYUOGRERF9g8JaX7dhOxgAgj10D7GWKRPhfCgurr67OnTMUdjXua8dTSX\nx+ONHjt2yrSprY7T28tX0T6EhTq085d/Z1/F9JDtwj6Os4P1DW2anZW1e9euy5f+Fovf8pj19PKa\nO2/ekPChWlpoDPNL4kr7EJZIhNINN7daiu0OeqkAfQw0pVJ58fyFYzFH45/EN9cHlUodNnz4lGlT\nu3fvDrUV5FIkJNojGR1tC8sEVWxTbOHzsc+GTSTV1dVHDh0+deJEQUFB8+s8Hi8iKnJSZOS7Lu3v\ng89HE18PQxDqoW1hmTLJb9XKyvQNRjKzpz266L8NJBTWxeajPAi+etWqvy9eqqt763Hfrl0jo6KG\njxxhZqZbttzSUoLisrwPHhuRHsgXDRJk71nUQc6m4R72emQS2HwrD7WwYo4cbfoZgqCh4eFz58/3\n80eZXutVPsm51syRNTTtQ1jV1SScSMEWM3Pz2XPmTJ4y2YLH06ecFlNI4oEpiLztEQnLnAnzSc1Z\nlfwsmcTa9aRnUM/IqKiRo0frv1Igk8kUCpLPH7QWtKsVEAnL3ZJFbsrn4iKUuTc6mDO62HIaUuvo\nY4AVh9ZQjhVH513Lo8eP61N1c1JTUrAqCjUOyEYUiITlYckmV1g5OTkymQxFyIbvRnl+N6plilQU\nzAl2nKP38pX+vMjMJNsE4GGJ6CQ6ImEhnAjgh0wmi330KHTAAMxLlkqlL3NyGg6C0mg0Ty8vAtKl\nFBYW1tY0HgB2cHTkIR51paam4mkXItwxFBabRv5SVkZ6OrbCevjgwYF9+588fiwQvFlBtbGxCRkQ\nOmPWrKZc9hhSXV198MCBy39fzs7KaroIQZB/QMC48eMmToqg0dvoZ69eJiFIZAu8bThIbkP0dvo7\nkr8HfO/uPayKqigvX7p4yYyp027dvCkQCKhUqourq6ubG5VKLS8vP3n8xISx47Z8++37HFfQcfHC\nhWFhQ37asbNBVRYWFp5enjweT6PRPE1MXLt6zbgxY5KfPWv12ZI6WWM7V0vy6igEAJeNaJSJqMXy\nsUUkUlx5lpRUV1en63Liu7zMyZkxdVpJSQmDwZgwaeL0mTPNzMzOnjmjUqpGjRktkUgOHvjr+LGY\n3X/sSkxI/H3XH3quDjTw7Tff/Ll7DwDAz98/Iipy7LhxTXk0FArF6VOnYg4fSUlJmTBu/A87to8c\nNar5s2dSyiMPpu6N8FanthHwlwA6WiEN9YOoxTIjb/F9dqTgt01VENBIpdLrV6/pWVpeXl7kpIiS\nkpKQ0NCbd++s37DBxcUlcuLELZu+3fbddyPCh1lZWa3f8PWtu3eDe/dKiI+fEhkll+ubIOnrdev+\n3L2HzeHs+PmnU2fPTIqIaJ6dhUajRURGnrlwftPmzVQqddnHS4/HxDR9uvZKzvj9KUq1Rq7S3Lh2\nXU9L9KeHE1KnHUTC8rThcFkkaGvx9LoVc4QhQfIfv6qBIM2li9rCvCCBTqezmMyZ0bP2HthvZ2fX\nMNLKz2tcyxYKBNevXgUA2Nvb/3Xo0JixYyEKRf8O0dLS0tzc/PS5syNGajvIOiky4ujxY6ampqrX\nmWvUAET8lbLhep4ZA742P2CkKzU+Pl5PS/THgoV0tQWRXCiv8+WfTiE06dfi6XWLpjfu5Hu5KV0c\nlU8eP66qrLTUI3Wqg4PDqbNnrJrFgHBxdaXT6U3NkrOLS8MPMAxv+/EHkUikv4/h4o8/njJ1KtfC\nos07/fz9H8Q+4nA4ZQL58N1JiUUCPweTmGm+nW04e/7YJZORn5y8rytS/1WkU2snLqFhP0eHiRdO\na1RVVS20aLVFXiFNIpFc1LvRsno7soirq+vylSs4HA6DwZg1Ozq4V6+mjyAIwspzFYmqGuBw6oez\n4/clJxYJLNnUMzO7dX49Czt96hQmluhJZ8SjbaTCCvVA+tXoj7uzYu0n/IatA6kMTF9umVfY2AIf\n2Lcf8z2NufPnP05MiE96+uWaNdiWjJqTM7t6WLKqxMqPDiQX82WJCYkvXhAdyvZdGFTIG3NheVoR\nFOcEhjVbV9Wy/j9l3+qt5nkFb/r1V/n5N65jP4ZlMBgGFdrU3oyRsCJopLfl0yJhjx8ff/bjfrIt\nqmeAhwUL8YomUmF525o4mhGRaXJ0mKRzx8ZzILcfMS7faSnovXv2NI+Y+KFizqQem951RahTiUB+\n2zJc0AFNYmZs8bXTYdUJqbBgCvDRpVx0MBia6EmNm5JyOdj6eyuT26eJT69euYq3JYYAmw5/P9or\nnJaloVCVLOKGIu9jaCdL5DfrsC/2UVfcT42G9hC6Ozf658RcYOcXtT65/XnnTrwtMRD+efgwK2aL\n85UvLLL0XcPTEwgCvvY6TGV0EFZvxFNN1Ezo9ibfyZkr7x30ZGZk7NlFTq5RIlEoFN9u/AYAQCMj\n8nYLBna00MkFVwdhdXMwdeW1zIONITCkGuka1/BzYirtRa62Id3O7dtLiovxM8YQ2L93X3p6Gwlg\nCKOfm26H0XVbT/+Ph8W+6hIdTUJKkE0GldI4Kk/JaGOFVywWf7pi5eGYozgZQwxqeYZaeF6jyNYo\nXwF1HQTbAKoDhdkLZg8qKFbt+PFHsg18w0gf3daldRPW1O52+57gJaxQxzf+x0+etT0DjYuNPX3q\n1PiPPsLJHlxRS5+oqjepxZebX2w4aqiu26uE6JkJ7mymSCol32Hp9fIH3d9Rt+1/3ZzaermYmzPx\n+lU7mLzJOlRWiaiWLz//orlvUztBoaz8QlE4sIWq3kIj7x+YcWlfxZAQ8gOh17/z7lyqju6Put3O\npsNhXhi4kbQO9N7/vA+FQrFk0eKKCkI3MfVCLZUXR6lqfwSg7f0DM1PN1i9royeRHwt9fm+d3bJ1\ndsNFmEqFMLKzslYuW65Ukh9rCQmKypUasQ7bnVQYLJstDA8ls91yMKP3cdU5jJTOwprgZ2tnSsQS\nPHL+efhw7ZerybaibVSCE+q6P3V9CobBuhV8SwvSjt+N6WJN17UjRCEsKgUa44tLuhil+o0xpia6\nfY/Hjx37et06HIzCDrVIWbUW3aOmHM2SGaR1iONR9VFoTqRMCbRD8VSbpFa9CQfVK0Bnv82/9h/Y\ntuU7rI3CDJXwIlDmon58fLjEzpqE7r6LLWcwqlE1GmH1d7fwssbeF+Dqq+5NP3u6ofkSf//tt7Wr\n16hV5AdNfReV6Lw+j1OpYEAvEhz95gSjTBCJ8gzd8hBndA9qoUBoWyZuHCSGBMnsrNHo48ihQ4sX\nLRIKyTxe2yptJEpBgI8X0YfrYQhM64Eyli5KYc3sac/UfUDXJmdeNoZwhWEQPgDlVOj61WsfjR2n\nf+QjjFHrm6LWxZHornB2sIOl7iEFGkApDiYNnhOMfVzo/Sn/afp5yliRqQlKv6uc7OzhQ4ZeuqCX\nH7NYrhLK6v/pU0gDapVQqGAKFUypEn3AeksLor3QPu6HNBzcu6BvdT4f5IZ59ti0XM6dR41b6A62\n6qjR6MMi8vn85Z98surzL1B3iyG/JJiuumO66o5K7z9oeoXGas8pqz2nIq+uQl2IWEJott5hnXk6\n+cm0AL2wHM0Zk/wxXixV0Tnb95oq/7+NmDdZ6OyAvv1Xq9XHY2LGjBx55/Ztfayqk+o7uGnK5kCB\n0Is0v5DQE3irBuuVW0WvcdK3Izrq8/i7qBimWbm0/ScaXVVZTLBjXTUV1itOcH5e/pxZ0XOjZyPY\nVVQCIH99pA+83r9q/HKuvdDXHepKRlXDD/Yc9EUVlRG3Id3L2UxXP5kW6CUsNx4rKgDT9ElUhgpm\n7NxnmpLR+HZ6uat+2VjdPGy9h4fH77t37T1woE/fvsgLvn3rVnjYkGUfLy0pafDOkKtEV5UVKxUl\nkbK8TrJs5ut/JrJsM1k2u/7nHPN+vEMNzy46lXEtswr173QsqWzzrcYzsSH26ANc3biPozNcCzbr\n3WRAesYNzygT+X0fJ1dhFnzc6fIXdHGFvY1y95ZqN6fGHuTvW8zV27gyef0g4+DhQ71fS0omk4X2\n7VdZWYm8cEsLVXiodOFsDwtWUps5Fh6Vdh589juVprGdgCBgb0qnNAtoZ8aEfe1MhnlbTgm0o8GU\nrArxTw8KnhYJCmplqtfJ19QaTUmdvKkaDlXyfMocOzaawB5PntFmrnxrw6POLaQicDqKotpkYEeL\nmwv1TYyob7fd2ZYzr5fjzw9bJqlCjYrNBeKKknLq0rUWf2yudrCt75gCfOUOtsrc1+fAmP9/TovB\nYAwcNOj4MW0Zmpvo6KqYPEY8Llz8OlLQUySP9LbLmO1zedfzxnPxGg0ornt7P4AP0srEx5+Vv6yS\nTPSz7fNTvPYp5Ajz8+hUpdaAXw8Sl+nkqyEYZK7DYC1q1WBXDGPBK9iN7+XLAtr8z3kl5ZQaPrRg\nFS/3/08X7ty+XSJpXOKi0dveDre3UW78tPbUH5URo8RtxZ9qyQ/9/ljc9RyH2saK2jc38uafSNei\nKopMwEs9lXn4ak4+mjf5xEXW4ySCTqJH+NuEYHE4GYOJhr0Z438DXdZceal/UfXAb/74LwtokxZa\nmXA0r4rf2Hn/3v2Tx49PmzGjzTDdNJpmyljR4ulCNgtlT02lqL/vt+t/gcfSa5wzapyqpGYaTWNX\nqAGgSmp2vaB7Nt9RrQGPXgfrhpQyVkUGvbYA0rwWmUYDywT0uiIGv4CilAkBZeGXFod3VFlb6jA3\njHtK3/IbQRm/WDTKhnAPTIrCZga7ItR5/5MShGmotaOivjVErebD1e9kpTDnWjR4+V1//6loF0fl\n1ytre3TDYBvEhs23YaeEOrYy7lao4YmXV195FQRey8jhzhYm/5WWoopKqVM+sfxpfU0nD0TLKBdv\nMr/eYd4wuCSA//7HxdMamyPv2AiLTYe3juo4fj8GMX0VHOv3fdS7T28nJ+d+If2HjxhRP3PZtIn/\nngh3vQJl276ssTDHPZ8RjaL6LPCEs2lFQgrtZZpQu6oaKCqlzlhpOWuicE6kSEt87vJKyva9pueu\nsRA60+qPE5fx6QDMtoD1nRU2Z/Kh1KNP9d2hY1a+cLzbuvfL2Qvnfbt2BQBUVlRu2rjx/Llzrd42\nOkz87f+Izr0jkYLpyy3TsnRwgTThqKMnCXsFyrt1VjTNNWVyEJvIuBvLOH6J3dTttgrms8KbCwIG\nemLmd46lsAprpQE/PK4U6dX70GvynW5taPWjhYsXWfB4D+7de3D/wfvCN0SMEq39BGVuEj1RqcC0\nZZbP0tG417JZag5bU1tHUSiQtk/YCmtyoO3hKb5YlYaxsAAAB+NLph9N06cESCF1O78EXes/anB9\nW4UwdQIeCITQvC94yai0pSsYCsvRjJG4MsjGBEuzMXZ9mdbDXk/HZQ2NqTBB46Havats/QoyVfXa\no1rz84ZqF0eSs5Loyh8TO2OrKuyFBQDYPdHbxgS9c8jrHUOdN9XtrFXbv6phGMAhD0uuZuuqWiaj\n3QRaig6yH6HjKWckYC8saxO6nr211FK3jSoqrNn6ZQ2Payg5bbt0Uq6cS/5hQCR4WDJ/Ht8Jj5Jx\nSe8x2Iu3JswV9eMS68463T9ppDjQ17B6n4jR4uAALPMP4AGLRjkzyw95kD6dwCtvzBeDXAd7otwZ\nUHJ0aJmteaolM9E3D2K913SFoubDusY/EkwB/50vYNB1a0RRZKHShz2TvLvq4cqnHbyExaLB+6N8\nEGaKaoHCxFbBQrqgMm+y0NwUZSf4LI02bIbNzYfo/5z7jnPGz7fKL6rXE9X2L6rN701faeeOytFh\nYuRF+XTpcvn6tb79dPAF0ofFfR0n43OMrwEcM105mjPPzOrGoeteBQQpTBC5eXHNVJGjdfjjNaeq\nBprzP15lNbz0K4vLt3V2ddJowE/7TbbtMisqpc5cYQm438Cmk2CzaVT7kwBqbAbmRgnbdM5pILhX\nr5gTx52dnXfv3dvFF8v1pFbp78b9YYwXrlXgm0Ktq73J4Sm+KFYAxPbdkNw2f4oQdRI4SwvNgqkN\n7vDQp99YfL7ZHHmA/tIKSvSnvN8PNbqyzJwoBMI/gaq6vhPkDKc5xQF6vf2OdupxQ9vua1d+9tnh\nmKNsNhsAEPvoURbOkbfdecwzs7rSYXz/9Ljn5hvja71lpM7uiFKee5v3UGHN+GF6DZFmR4g+ia6D\nKfWNyoUb7CFTbY6cY/PrtL0IxWWUnftMhs+wefyM8bpt1Xy+iD9jghgoX8oLBwNlaf13SvdgOMfC\n1jsAzWPCiPc2qAwGY9z48ddu3li4eFHDlevXri9esFD/7D1asDGh3VoUaMnBfWEG45X39/H5xawt\nt9veoH2DRuN8ZRVNrC0+0eC+kh3rMUizdvwia/OvbzwITDjqIf2lQX4ydxcVk6GhUTVCMSSRQk+e\n0VMy6HfjGE1beEyGZv3y2pGDm83+qB40+yMURlOGerVKeOnbHxLjnyQIBHXVVdVMJtPaxsbe3r5P\nv77Dhg+3sXlzGuXk8RNfrVmDPK8JipV3Dh2+Pt+/t+6hY1BAkLAAAFGHUmN02aK2jt9vlv9Ayw2b\n/lszZgg2U/rMHOoXW8wzX+rwHnu5KTZ8Wuvb6R3vF8iEarkR5s5B7jnC5/N/3Pb9oYMHdbBYd2Gx\naZQjU33H+L7XeQRbiBOWSg0iDyafTEYaJI1TmGAX99v7P9c8vVyqq0eoFtRqcOEm6/eDJs2dClvF\n3kY5f4pwzBCJltoheleq5UYKZ5B2eUml0nNnzn6/bVt1lc6HNXQSFgRAzDTfSf6YnnzRCnFH1WAK\nODzFV6ZMuZCG6PiDyMFPyeRSpa13dl07KzBUVf3AiALGhElGDpQkZ9Cu32dm5VKT0uhiSeMYlGeu\n8vFSuDsrB/aRBXaVtznw1chTFCVjANUVNp0EMfwlmkEmpm+8QIsKC+Pi4uJiY2/duFlTo+/R+zaB\nADg+3XeCH3GqIlRYAAA6lXJiRtfIgylnUxFoi0IV2fuZ595t9cPOHrgstcMwCOiiCOiiaGjDauvq\nR1cmHA3KpTJlnqrmu/pZwnLLogpnCx5PrVaXFBfX1RHn2ANB4ECkD8GqImJW2AIGlXJierepyJbm\nhI7d3/cRujhHOkGhAB5X42inRr0A24S7s7K0tDQ9LS0zI4NIVVEp0MnpXVFHjNEHooX1epkAOjCl\ny+ygtn9bqa2Pktn6OYIunoa1Oagdax4JIbtM6PDfc/zQxePTHxKE1VDrngifTcPbXqyq9Rza6nU3\np/YRzbYB4q3lsakPlnQP0yWtEraQI6wGvhjktjfCm03TZkOdW381pZWBoLmZoTjJIMEWVRA51Pg7\nmCStDPZzJO6M67uQKSwAwKwgh2vzA7Q4BmpoLIFTL2KNwh5TDnGvwfDOltfnBzhxiQv00CokCwsA\n0NeNm/xpr27v99+o6TJWQ9QRKJwgzGF69WDXC3P8rbD2M0YB+cKq7ylM6XGf9JzXq/U4qioWV+Dc\nvhstKf5hablM6rlZ3TYM86AYxjtoEMJ6HXuS8sdE74OTfXjsVkZUtZ2Ga6C3TMVzoxZ7qmqw99JU\nN/vbBTmbJa4IGk3Udg0SDEVYDUztbv9gSY8+72TcVJjZ891Cm18pLDWItFgIKSzBQVg0VkMnu3qw\n662FgW6ofCrxw7CE9TqrOefhxz02hLvT4bfa9NrOw1W0N2EFMnIw3dDBmZcF2O9wqJjm7pbM+4u7\nbxjmwcEu2g9WGJywGlgd5pa0Mrhvs6ZLxbKo7jK26b/J6e1JWDV8zL9naNmIwLT/9u6rX0BH/DBQ\nYTU0XQ8+7vHLeK+mUON1riEy08YBfjGBATn1J+4pltM0H7+A0xcurJ8/kYFDqH2sMFzLGljU1+n5\nZ8GzguxhCgRgakXgdA1UL6l/4gk90KIPFVUUvgCb18CCx1v99cbz505369oFkwLxw9CF9XoxgrE3\nwufhku4DO1rIrDrWufYDAEhklLQsQl0zUHMvDoN3gMnmTJkx89qt2zOnT8HCKNxpH38bAECwi/nN\nhYE3s6qXnYD5RzLpwtIzV9g+nuQEltGJK/f0WgSnUKnhI0Z99tlKpw46pzklEeI8SLFCrQaXHzzZ\ntW1TWUHC3RPlZJvTBlU1lJCJNuiCp8FU2pjx42fPndvJE5vwjUTS/oTVgFqtvnX7jrPJZhfLe2Tb\noo29xzjf79Yt/3t9P0JnTIyMmhU9y90V+yxrxNBehdWEVJSqqNpKkZykwgaXplClAn3H2wpEOgxk\nbRw6RERGzps/l2UIoXP0oN0LqwGVUiSu+AkSHaSBHLJteUPMedaGncjWmSAoZOCgydOmDx7QH3ez\nCOEDEVYTgpoEWH5Jzf+FRiE6DGkLpDIQPs2morqNhQbvbv6TJ0cNGxbONde5xzRkPjRhNVFXeRWS\n3wOSK1TVc9TH8PVhy2+mf51q3RfIxNSsq5/f4LCwoeHhdrYGtHOMIR+ssJoQ8p8D6TW1+AakTKND\nJcRU+iKXGrnYqnl8dogCe3h6+gd2Dw7uGRYWZsLBJpy6wfLhC6s5UmGyVBgPSf6mQ3lKSTqdhst4\nXyyBJi2yzC2gmfOsnJw6dPMPCAsb7Onp+aE2Tq3y7xJWc6RSPlWTIxZmaqSJGlkCiy4W8DNNWSij\njKhUQKp2YHNsJQrH/MretfJe9ra2HTu6w6R0wwbAv1dYrVInKGFSSqmwhi8oA6pKJk0sEpZSNLVQ\ns8yoSjWDzrCm0y3FcjbLxJFJ54hldCrTncn4wHs3nTAKywgu/EsbaiN4YxSWEVwwCssILhiFZQQX\njMIyggtGYRnBBaOwjOCCUVhGcOH/AgAA//+S+QX6OV9s5wAAAABJRU5ErkJggpQu\n", + "__pickled_extra_fields__": [ + "thumbnail" + ] + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your document with tumbnail! Run /start command again to restart.\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)", + "send_document(42, '08a7a36671950baba722d94a87dea286f03d7a6f7d0c32d5707d877cd211739a', caption='DeepPavlov article', parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, thumbnail='9f39f64560e6415032325cae1fec1ca06b3cc1a3549208a8a35564c0d3749062', message_effect_id=None, reply_to_message_id=None, filename='deeppavlov_article.pdf')" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 22, 19, 53, 42, tzinfo=UTC), delete_chat_photo=False, entities=(MessageEntity(length=6, offset=0, type=MessageEntityType.BOT_COMMAND),), from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=9, supergroup_chat_created=False, text='/start'), update_id=9)", + "received_message": { + "text": "/start", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVXwsAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5SMF3RlbGVncmFtLl9tZXNzYWdlZW50aXR5lIwNTWVzc2FnZUVudGl0eZSTlCmB\nlH2UKIwPY3VzdG9tX2Vtb2ppX2lklE6MCGxhbmd1YWdllE6MBmxlbmd0aJRLBowGb2Zmc2V0lEsA\naBJoE4wRTWVzc2FnZUVudGl0eVR5cGWUk5SMC2JvdF9jb21tYW5klIWUUpSMA3VybJROjAR1c2Vy\nlE5oG4hoHGhdSwBLBoeUaB59lHVihZSMDmV4dGVybmFsX3JlcGx5lE6MEmZvcnVtX3RvcGljX2Ns\nb3NlZJROjBNmb3J1bV90b3BpY19jcmVhdGVklE6MEmZvcnVtX3RvcGljX2VkaXRlZJROjBRmb3J1\nbV90b3BpY19yZW9wZW5lZJROjA5mb3J3YXJkX29yaWdpbpROjAlmcm9tX3VzZXKUjA50ZWxlZ3Jh\nbS5fdXNlcpRoEJOUKYGUfZQojBhhZGRlZF90b19hdHRhY2htZW50X21lbnWUTowXY2FuX2Nvbm5l\nY3RfdG9fYnVzaW5lc3OUTowPY2FuX2pvaW5fZ3JvdXBzlE6MG2Nhbl9yZWFkX2FsbF9ncm91cF9t\nZXNzYWdlc5ROaAtoDGgNSyqMBmlzX2JvdJSJjAppc19wcmVtaXVtlE6MDWxhbmd1YWdlX2NvZGWU\njAJlbpRoD2gQjBdzdXBwb3J0c19pbmxpbmVfcXVlcmllc5ROaBloGmgbiGgcSyqFlGgefZR1YowE\nZ2FtZZROjBpnZW5lcmFsX2ZvcnVtX3RvcGljX2hpZGRlbpROjBxnZW5lcmFsX2ZvcnVtX3RvcGlj\nX3VuaGlkZGVulE6MCGdpdmVhd2F5lE6MEmdpdmVhd2F5X2NvbXBsZXRlZJROjBBnaXZlYXdheV9j\ncmVhdGVklE6MEGdpdmVhd2F5X3dpbm5lcnOUTowSZ3JvdXBfY2hhdF9jcmVhdGVklImMEWhhc19t\nZWRpYV9zcG9pbGVylE6MFWhhc19wcm90ZWN0ZWRfY29udGVudJROjAdpbnZvaWNllE6MFGlzX2F1\ndG9tYXRpY19mb3J3YXJklE6MD2lzX2Zyb21fb2ZmbGluZZROjBBpc190b3BpY19tZXNzYWdllE6M\nEGxlZnRfY2hhdF9tZW1iZXKUTowUbGlua19wcmV2aWV3X29wdGlvbnOUTowIbG9jYXRpb26UTowO\nbWVkaWFfZ3JvdXBfaWSUTowhbWVzc2FnZV9hdXRvX2RlbGV0ZV90aW1lcl9jaGFuZ2VklE6MEW1l\nc3NhZ2VfdGhyZWFkX2lklE6MFG1pZ3JhdGVfZnJvbV9jaGF0X2lklE6MEm1pZ3JhdGVfdG9fY2hh\ndF9pZJROjBBuZXdfY2hhdF9tZW1iZXJzlCmMDm5ld19jaGF0X3Bob3RvlCmMDm5ld19jaGF0X3Rp\ndGxllE6MDXBhc3Nwb3J0X2RhdGGUTowFcGhvdG+UKYwOcGlubmVkX21lc3NhZ2WUTowEcG9sbJRO\njBlwcm94aW1pdHlfYWxlcnRfdHJpZ2dlcmVklE6MBXF1b3RllE6MDHJlcGx5X21hcmt1cJROjBBy\nZXBseV90b19tZXNzYWdllE6MDnJlcGx5X3RvX3N0b3J5lE6MEnNlbmRlcl9ib29zdF9jb3VudJRO\njBNzZW5kZXJfYnVzaW5lc3NfYm90lE6MC3NlbmRlcl9jaGF0lE6MGHNob3dfY2FwdGlvbl9hYm92\nZV9tZWRpYZROjAdzdGlja2VylE6MBXN0b3J5lE6MEnN1Y2Nlc3NmdWxfcGF5bWVudJROjBdzdXBl\ncmdyb3VwX2NoYXRfY3JlYXRlZJSJjAR0ZXh0lIwGL3N0YXJ0lIwMdXNlcnNfc2hhcmVklE6MBXZl\nbnVllE6MB3ZpYV9ib3SUTowFdmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0\nX3BhcnRpY2lwYW50c19pbnZpdGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2No\nYXRfc3RhcnRlZJROjAp2aWRlb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0\nZV9hY2Nlc3NfYWxsb3dlZJROjARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZST\nlEMKB+gFFhM1KgAAAJSMBHB5dHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLCWgbiGgc\nSwloCYaUaB59lHVijBBtZXNzYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSU\nTowObXlfY2hhdF9tZW1iZXKUTmiVTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5\nlE6MEnJlbW92ZWRfY2hhdF9ib29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwlo\nG4hoHEsJhZRoHn2UdWIu\n" + }, + "response_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "location", + "longitude": 27.792887, + "latitude": 58.43161, + "reply_markup": "gASV4gMAAAAAAACMJXRlbGVncmFtLl9pbmxpbmUuaW5saW5la2V5Ym9hcmRtYXJrdXCUjBRJbmxp\nbmVLZXlib2FyZE1hcmt1cJSTlCmBlH2UKIwPaW5saW5lX2tleWJvYXJklCiMJXRlbGVncmFtLl9p\nbmxpbmUuaW5saW5la2V5Ym9hcmRidXR0b26UjBRJbmxpbmVLZXlib2FyZEJ1dHRvbpSTlCmBlH2U\nKIwNY2FsbGJhY2tfZGF0YZSMCWZvcm1hdHRlZJSMDWNhbGxiYWNrX2dhbWWUTowJbG9naW5fdXJs\nlE6MA3BheZROjBNzd2l0Y2hfaW5saW5lX3F1ZXJ5lE6MH3N3aXRjaF9pbmxpbmVfcXVlcnlfY2hv\nc2VuX2NoYXSUTowgc3dpdGNoX2lubGluZV9xdWVyeV9jdXJyZW50X2NoYXSUTowEdGV4dJSMFEN1\ndGUgZm9ybWF0dGVkIHRleHQhlIwDdXJslE6MB3dlYl9hcHCUTowHX2Zyb3plbpSIjAlfaWRfYXR0\ncnOUKGgUTk5oDE5OTk5OdJSMCmFwaV9rd2FyZ3OUfZR1YoWUaAgpgZR9lChoC4wLYXR0YWNobWVu\ndHOUaA1OaA5OaA9OaBBOaBFOaBJOaBOMFU11bHRpcGxlIGF0dGFjaG1lbnRzIZRoFU5oFk5oF4ho\nGChoIE5OaB9OTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAZzZWNyZXSUaA1OaA5OaA9OaBBOaBFO\naBJOaBOMDVNlY3JldCBpbWFnZSGUaBVOaBZOaBeIaBgoaCdOTmgmTk5OTk50lGgafZR1YoWUaAgp\ngZR9lChoC4wJdGh1bWJuYWlslGgNTmgOTmgPTmgQTmgRTmgSTmgTjBhEb2N1bWVudCB3aXRoIHRo\ndW1ibmFpbCGUaBVOaBZOaBeIaBgoaC5OTmgtTk5OTk50lGgafZR1YoWUaAgpgZR9lChoC4wEaGFz\naJRoDU5oDk5oD05oEE5oEU5oEk5oE4wcRmlyc3QgYXR0YWNobWVudCBieXRlcyBoYXNoIZRoFU5o\nFk5oF4hoGChoNU5OaDROTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAdyZXN0YXJ0lGgNTmgOTmgP\nTmgQTmgRTmgSTmgTjAhSZXN0YXJ0IZRoFU5oFk5oF4hoGChoPE5OaDtOTk5OTnSUaBp9lHViaAgp\ngZR9lChoC4wEcXVpdJRoDU5oDk5oD05oEE5oEU5oEk5oE4wFUXVpdCGUaBVOaBZOaBeIaBgoaEJO\nTmhBTk5OTk50lGgafZR1YoaUdJRoF4hoGGhGhZRoGn2UdWIu\n", + "__pickled_extra_fields__": [ + "reply_markup" + ] + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_location(42, 58.43161, 27.792887, horizontal_accuracy=None, disable_notification=None, protect_content=None, reply_markup=InlineKeyboardMarkup(inline_keyboard=((InlineKeyboardButton(callback_data='formatted', text='Cute formatted text!'),), (InlineKeyboardButton(callback_data='attachments', text='Multiple attachments!'),), (InlineKeyboardButton(callback_data='secret', text='Secret image!'),), (InlineKeyboardButton(callback_data='thumbnail', text='Document with thumbnail!'),), (InlineKeyboardButton(callback_data='hash', text='First attachment bytes hash!'),), (InlineKeyboardButton(callback_data='restart', text='Restart!'), InlineKeyboardButton(callback_data='quit', text='Quit!')))), message_effect_id=None, reply_to_message_id=None)" + ] + }, + { + "update": "Update(callback_query=CallbackQuery(chat_instance='-1', data='hash', from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), id='9', message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 22, 19, 53, 42, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Bot', id=6601664672, is_bot=True, username='dff_bot'), group_chat_created=False, location=Location(latitude=58.43162, longitude=27.792879), message_id=10, reply_markup=InlineKeyboardMarkup(inline_keyboard=((InlineKeyboardButton(callback_data='formatted', text='Cute formatted text!'),), (InlineKeyboardButton(callback_data='attachments', text='Multiple attachments!'),), (InlineKeyboardButton(callback_data='secret', text='Secret image!'),), (InlineKeyboardButton(callback_data='thumbnail', text='Document with thumbnail!'),), (InlineKeyboardButton(callback_data='hash', text='First attachment bytes hash!'),), (InlineKeyboardButton(callback_data='restart', text='Restart!'), InlineKeyboardButton(callback_data='quit', text='Quit!')))), supergroup_chat_created=False)), update_id=10)", + "received_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "callback_query", + "query_string": "hash" + } + ], + "annotations": null, + "misc": null, + "original_message": "gASVBBAAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUjBd0ZWxlZ3JhbS5fY2FsbGJhY2txdWVyeZSMDUNhbGxiYWNrUXVlcnmUk5QpgZR9\nlCiMDWNoYXRfaW5zdGFuY2WUjAItMZSMBGRhdGGUjARoYXNolIwJZnJvbV91c2VylIwOdGVsZWdy\nYW0uX3VzZXKUaBCTlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25u\nZWN0X3RvX2J1c2luZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBf\nbWVzc2FnZXOUTmgLaAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2Rl\nlIwCZW6UaA9oEIwXc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKM\nD2dhbWVfc2hvcnRfbmFtZZROaA2MATmUjBFpbmxpbmVfbWVzc2FnZV9pZJROjAdtZXNzYWdllIwR\ndGVsZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1l\nbnSUjBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2U\njAV2YWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowL\nYm9vc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRp\nb25fZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3Nl\ndJROjAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0\nZV9jaGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9p\nZJROjAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowT\nZm9ydW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNf\ncmVvcGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTmgvaDEpgZR9lChoNE5oNU5oNk5oN05oC4wDQm90\nlGgNigWgaH2JAWg4iGg5Tmg6TmgPTmg8TmgZjAdkZmZfYm90lGgbiGgcigWgaH2JAYWUaB59lHVi\njARnYW1llE6MGmdlbmVyYWxfZm9ydW1fdG9waWNfaGlkZGVulE6MHGdlbmVyYWxfZm9ydW1fdG9w\naWNfdW5oaWRkZW6UTowIZ2l2ZWF3YXmUTowSZ2l2ZWF3YXlfY29tcGxldGVklE6MEGdpdmVhd2F5\nX2NyZWF0ZWSUTowQZ2l2ZWF3YXlfd2lubmVyc5ROjBJncm91cF9jaGF0X2NyZWF0ZWSUiYwRaGFz\nX21lZGlhX3Nwb2lsZXKUTowVaGFzX3Byb3RlY3RlZF9jb250ZW50lE6MB2ludm9pY2WUTowUaXNf\nYXV0b21hdGljX2ZvcndhcmSUTowPaXNfZnJvbV9vZmZsaW5llE6MEGlzX3RvcGljX21lc3NhZ2WU\nTowQbGVmdF9jaGF0X21lbWJlcpROjBRsaW5rX3ByZXZpZXdfb3B0aW9uc5ROjAhsb2NhdGlvbpSM\nGHRlbGVncmFtLl9maWxlcy5sb2NhdGlvbpSMCExvY2F0aW9ulJOUKYGUfZQojAdoZWFkaW5nlE6M\nE2hvcml6b250YWxfYWNjdXJhY3mUTowIbGF0aXR1ZGWUR0BNNz9S/CZXjAtsaXZlX3BlcmlvZJRO\njAlsb25naXR1ZGWUR0A7yvoePq9ojBZwcm94aW1pdHlfYWxlcnRfcmFkaXVzlE5oG4hoHEdAO8r6\nHj6vaEdATTc/UvwmV4aUaB59lHVijA5tZWRpYV9ncm91cF9pZJROjCFtZXNzYWdlX2F1dG9fZGVs\nZXRlX3RpbWVyX2NoYW5nZWSUTowRbWVzc2FnZV90aHJlYWRfaWSUTowUbWlncmF0ZV9mcm9tX2No\nYXRfaWSUTowSbWlncmF0ZV90b19jaGF0X2lklE6MEG5ld19jaGF0X21lbWJlcnOUKYwObmV3X2No\nYXRfcGhvdG+UKYwObmV3X2NoYXRfdGl0bGWUTowNcGFzc3BvcnRfZGF0YZROjAVwaG90b5QpjA5w\naW5uZWRfbWVzc2FnZZROjARwb2xslE6MGXByb3hpbWl0eV9hbGVydF90cmlnZ2VyZWSUTowFcXVv\ndGWUTowMcmVwbHlfbWFya3VwlIwldGVsZWdyYW0uX2lubGluZS5pbmxpbmVrZXlib2FyZG1hcmt1\ncJSMFElubGluZUtleWJvYXJkTWFya3VwlJOUKYGUfZQojA9pbmxpbmVfa2V5Ym9hcmSUKIwldGVs\nZWdyYW0uX2lubGluZS5pbmxpbmVrZXlib2FyZGJ1dHRvbpSMFElubGluZUtleWJvYXJkQnV0dG9u\nlJOUKYGUfZQojA1jYWxsYmFja19kYXRhlIwJZm9ybWF0dGVklIwNY2FsbGJhY2tfZ2FtZZROjAls\nb2dpbl91cmyUTowDcGF5lE6ME3N3aXRjaF9pbmxpbmVfcXVlcnmUTowfc3dpdGNoX2lubGluZV9x\ndWVyeV9jaG9zZW5fY2hhdJROjCBzd2l0Y2hfaW5saW5lX3F1ZXJ5X2N1cnJlbnRfY2hhdJROjAR0\nZXh0lIwUQ3V0ZSBmb3JtYXR0ZWQgdGV4dCGUjAN1cmyUTowHd2ViX2FwcJROaBuIaBwoaK9OTmin\nTk5OTk50lGgefZR1YoWUaKMpgZR9lChopowLYXR0YWNobWVudHOUaKhOaKlOaKpOaKtOaKxOaK1O\naK6MFU11bHRpcGxlIGF0dGFjaG1lbnRzIZRosE5osU5oG4hoHChouE5OaLdOTk5OTnSUaB59lHVi\nhZRooymBlH2UKGimjAZzZWNyZXSUaKhOaKlOaKpOaKtOaKxOaK1OaK6MDVNlY3JldCBpbWFnZSGU\naLBOaLFOaBuIaBwoaL9OTmi+Tk5OTk50lGgefZR1YoWUaKMpgZR9lChopowJdGh1bWJuYWlslGio\nTmipTmiqTmirTmisTmitTmiujBhEb2N1bWVudCB3aXRoIHRodW1ibmFpbCGUaLBOaLFOaBuIaBwo\naMZOTmjFTk5OTk50lGgefZR1YoWUaKMpgZR9lChopmguaKhOaKlOaKpOaKtOaKxOaK1OaK6MHEZp\ncnN0IGF0dGFjaG1lbnQgYnl0ZXMgaGFzaCGUaLBOaLFOaBuIaBwoaMxOTmguTk5OTk50lGgefZR1\nYoWUaKMpgZR9lChopowHcmVzdGFydJRoqE5oqU5oqk5oq05orE5orU5orowIUmVzdGFydCGUaLBO\naLFOaBuIaBwoaNNOTmjSTk5OTk50lGgefZR1YmijKYGUfZQoaKaMBHF1aXSUaKhOaKlOaKpOaKtO\naKxOaK1OaK6MBVF1aXQhlGiwTmixTmgbiGgcKGjZTk5o2E5OTk5OdJRoHn2UdWKGlHSUaBuIaBxo\n3YWUaB59lHVijBByZXBseV90b19tZXNzYWdllE6MDnJlcGx5X3RvX3N0b3J5lE6MEnNlbmRlcl9i\nb29zdF9jb3VudJROjBNzZW5kZXJfYnVzaW5lc3NfYm90lE6MC3NlbmRlcl9jaGF0lE6MGHNob3df\nY2FwdGlvbl9hYm92ZV9tZWRpYZROjAdzdGlja2VylE6MBXN0b3J5lE6MEnN1Y2Nlc3NmdWxfcGF5\nbWVudJROjBdzdXBlcmdyb3VwX2NoYXRfY3JlYXRlZJSJaK5OjAx1c2Vyc19zaGFyZWSUTowFdmVu\ndWWUTowHdmlhX2JvdJROjAV2aWRlb5ROjBB2aWRlb19jaGF0X2VuZGVklE6MH3ZpZGVvX2NoYXRf\ncGFydGljaXBhbnRzX2ludml0ZWSUTowUdmlkZW9fY2hhdF9zY2hlZHVsZWSUTowSdmlkZW9fY2hh\ndF9zdGFydGVklE6MCnZpZGVvX25vdGWUTowFdm9pY2WUTowMd2ViX2FwcF9kYXRhlE6MFHdyaXRl\nX2FjY2Vzc19hbGxvd2VklE6MBGNoYXSUaAmMBGRhdGWUjAhkYXRldGltZZSMCGRhdGV0aW1llJOU\nQwoH6AUWEzUqAAAAlIwEcHl0epSMBF9VVEOUk5QpUpSGlFKUjAptZXNzYWdlX2lklEsKaBuIaBxL\nCmgJhpRoHn2UdWJoG4hoHGhAhZRoHn2UdWKMDGNoYW5uZWxfcG9zdJROjApjaGF0X2Jvb3N0lE6M\nEWNoYXRfam9pbl9yZXF1ZXN0lE6MC2NoYXRfbWVtYmVylE6MFGNob3Nlbl9pbmxpbmVfcmVzdWx0\nlE6MGWRlbGV0ZWRfYnVzaW5lc3NfbWVzc2FnZXOUTowXZWRpdGVkX2J1c2luZXNzX21lc3NhZ2WU\nTowTZWRpdGVkX2NoYW5uZWxfcG9zdJROjA5lZGl0ZWRfbWVzc2FnZZROjAxpbmxpbmVfcXVlcnmU\nTmhCTowQbWVzc2FnZV9yZWFjdGlvbpROjBZtZXNzYWdlX3JlYWN0aW9uX2NvdW50lE6MDm15X2No\nYXRfbWVtYmVylE5ol06MC3BvbGxfYW5zd2VylE6MEnByZV9jaGVja291dF9xdWVyeZROjBJyZW1v\ndmVkX2NoYXRfYm9vc3SUTowOc2hpcHBpbmdfcXVlcnmUTowJdXBkYXRlX2lklEsKaBuIaBxLCoWU\naB59lHViLg==\n" + }, + "response_message": { + "text": "Alright! Now send me a message with data attachment (audio, video, animation, image, sticker or document)!", + "attachments": null, + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, 'Alright! Now send me a message with data attachment (audio, video, animation, image, sticker or document)!', parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 22, 20, 12, 23, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=12, sticker=Sticker(api_kwargs={'thumb': {'file_id': 'AAMCAgADGQEAAgS0Zk5Rpz6PkZu6Ef3Ef7GwnxAZYocAAiwCAAJHBkMF0YsKl8FLgq8BAAdtAAM1BA', 'file_unique_id': 'AQADLAIAAkcGQwVy', 'file_size': 5416, 'width': 128, 'height': 128}}, emoji='\ud83d\udc68', file_id='CAACAgIAAxkBAAIEtGZOUac-j5GbuhH9xH-xsJ8QGWKHAAIsAgACRwZDBdGLCpfBS4KvNQQ', file_size=29492, file_unique_id='AgADLAIAAkcGQwU', height=512, is_animated=False, is_video=False, set_name='citati_prosto', thumbnail=PhotoSize(file_id='AAMCAgADGQEAAgS0Zk5Rpz6PkZu6Ef3Ef7GwnxAZYocAAiwCAAJHBkMF0YsKl8FLgq8BAAdtAAM1BA', file_size=5416, file_unique_id='AQADLAIAAkcGQwVy', height=128, width=128), type=StickerType.REGULAR, width=512), supergroup_chat_created=False), update_id=11)", + "received_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "sticker", + "source": null, + "use_cache": true, + "cached_filename": "/tmp/dff-cache-LongpollingInterface/7733311b-05ed-5102-8885-67c2530e446e", + "id": "CAACAgIAAxkBAAIEtGZOUac-j5GbuhH9xH-xsJ8QGWKHAAIsAgACRwZDBdGLCpfBS4KvNQQ", + "is_animated": false, + "is_video": false, + "type": "regular" + } + ], + "annotations": null, + "misc": null, + "original_message": "gASVDg0AAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpSMF3RlbGVncmFtLl9maWxlcy5zdGlja2VylIwHU3RpY2tlcpSTlCmBlH2UKIwPY3Vz\ndG9tX2Vtb2ppX2lklE6MBWVtb2pplIwE8J+RqJSMBmhlaWdodJRNAAKMC2lzX2FuaW1hdGVklImM\nCGlzX3ZpZGVvlImMDW1hc2tfcG9zaXRpb26UTowQbmVlZHNfcmVwYWludGluZ5ROjBFwcmVtaXVt\nX2FuaW1hdGlvbpROjAhzZXRfbmFtZZSMDWNpdGF0aV9wcm9zdG+UaBJoE4wLU3RpY2tlclR5cGWU\nk5SMB3JlZ3VsYXKUhZRSlIwFd2lkdGiUTQACjAl0aHVtYm5haWyUjBl0ZWxlZ3JhbS5fZmlsZXMu\ncGhvdG9zaXpllIwJUGhvdG9TaXpllJOUKYGUfZQoaJVLgGiiS4CMB2ZpbGVfaWSUjE5BQU1DQWdB\nREdRRUFBZ1MwWms1UnB6NlBrWnU2RWYzRWY3R3dueEFaWW9jQUFpd0NBQUpIQmtNRjBZc0tsOEZM\nZ3E4QkFBZHRBQU0xQkGUjAlmaWxlX3NpemWUTSgVjA5maWxlX3VuaXF1ZV9pZJSMEEFRQURMQUlB\nQWtjR1F3VnmUaBuIaBxorYWUaB59lHViaKmMR0NBQUNBZ0lBQXhrQkFBSUV0R1pPVWFjLWo1R2J1\naEg5eEgteHNKOFFHV0tIQUFJc0FnQUNSd1pEQmRHTENwZkJTNEt2TlFRlGirTTRzaKyMD0FnQURM\nQUlBQWtjR1F3VZRoG4hoHGixhZRoHn2UjAV0aHVtYpR9lChoqWiqaKxorWirTSgVaKJLgGiVS4B1\nc3VijAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0X2NyZWF0\nZWSUiYwEdGV4dJROjAx1c2Vyc19zaGFyZWSUTowFdmVudWWUTowHdmlhX2JvdJROjAV2aWRlb5RO\njBB2aWRlb19jaGF0X2VuZGVklE6MH3ZpZGVvX2NoYXRfcGFydGljaXBhbnRzX2ludml0ZWSUTowU\ndmlkZW9fY2hhdF9zY2hlZHVsZWSUTowSdmlkZW9fY2hhdF9zdGFydGVklE6MCnZpZGVvX25vdGWU\nTowFdm9pY2WUTowMd2ViX2FwcF9kYXRhlE6MFHdyaXRlX2FjY2Vzc19hbGxvd2VklE6MBGNoYXSU\naAmMBGRhdGWUjAhkYXRldGltZZSMCGRhdGV0aW1llJOUQwoH6AUWFAwXAAAAlIwEcHl0epSMBF9V\nVEOUk5QpUpSGlFKUjAptZXNzYWdlX2lklEsMaBuIaBxLDGgJhpRoHn2UdWKMEG1lc3NhZ2VfcmVh\nY3Rpb26UTowWbWVzc2FnZV9yZWFjdGlvbl9jb3VudJROjA5teV9jaGF0X21lbWJlcpROaIJOjAtw\nb2xsX2Fuc3dlcpROjBJwcmVfY2hlY2tvdXRfcXVlcnmUTowScmVtb3ZlZF9jaGF0X2Jvb3N0lE6M\nDnNoaXBwaW5nX3F1ZXJ5lE6MCXVwZGF0ZV9pZJRLC2gbiGgcSwuFlGgefZR1Yi4=\n" + }, + "response_message": { + "text": "Here's your previous request first attachment sha256 hash: `75681742958b21061e6d5ebb80340d62de4c7348e71fb8c1d2c356a2239b2334`!\nRun /start command again to restart.", + "attachments": null, + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, \"Here's your previous request first attachment sha256 hash: `75681742958b21061e6d5ebb80340d62de4c7348e71fb8c1d2c356a2239b2334`!\\nRun /start command again to restart.\", parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 21, 19, 9, 39, tzinfo=UTC), delete_chat_photo=False, entities=(MessageEntity(length=6, offset=0, type=MessageEntityType.BOT_COMMAND),), from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=12, supergroup_chat_created=False, text='/start'), update_id=12)", + "received_message": { + "text": "/start", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVXwsAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5SMF3RlbGVncmFtLl9tZXNzYWdlZW50aXR5lIwNTWVzc2FnZUVudGl0eZSTlCmB\nlH2UKIwPY3VzdG9tX2Vtb2ppX2lklE6MCGxhbmd1YWdllE6MBmxlbmd0aJRLBowGb2Zmc2V0lEsA\naBJoE4wRTWVzc2FnZUVudGl0eVR5cGWUk5SMC2JvdF9jb21tYW5klIWUUpSMA3VybJROjAR1c2Vy\nlE5oG4hoHGhdSwBLBoeUaB59lHVihZSMDmV4dGVybmFsX3JlcGx5lE6MEmZvcnVtX3RvcGljX2Ns\nb3NlZJROjBNmb3J1bV90b3BpY19jcmVhdGVklE6MEmZvcnVtX3RvcGljX2VkaXRlZJROjBRmb3J1\nbV90b3BpY19yZW9wZW5lZJROjA5mb3J3YXJkX29yaWdpbpROjAlmcm9tX3VzZXKUjA50ZWxlZ3Jh\nbS5fdXNlcpRoEJOUKYGUfZQojBhhZGRlZF90b19hdHRhY2htZW50X21lbnWUTowXY2FuX2Nvbm5l\nY3RfdG9fYnVzaW5lc3OUTowPY2FuX2pvaW5fZ3JvdXBzlE6MG2Nhbl9yZWFkX2FsbF9ncm91cF9t\nZXNzYWdlc5ROaAtoDGgNSyqMBmlzX2JvdJSJjAppc19wcmVtaXVtlE6MDWxhbmd1YWdlX2NvZGWU\njAJlbpRoD2gQjBdzdXBwb3J0c19pbmxpbmVfcXVlcmllc5ROaBloGmgbiGgcSyqFlGgefZR1YowE\nZ2FtZZROjBpnZW5lcmFsX2ZvcnVtX3RvcGljX2hpZGRlbpROjBxnZW5lcmFsX2ZvcnVtX3RvcGlj\nX3VuaGlkZGVulE6MCGdpdmVhd2F5lE6MEmdpdmVhd2F5X2NvbXBsZXRlZJROjBBnaXZlYXdheV9j\ncmVhdGVklE6MEGdpdmVhd2F5X3dpbm5lcnOUTowSZ3JvdXBfY2hhdF9jcmVhdGVklImMEWhhc19t\nZWRpYV9zcG9pbGVylE6MFWhhc19wcm90ZWN0ZWRfY29udGVudJROjAdpbnZvaWNllE6MFGlzX2F1\ndG9tYXRpY19mb3J3YXJklE6MD2lzX2Zyb21fb2ZmbGluZZROjBBpc190b3BpY19tZXNzYWdllE6M\nEGxlZnRfY2hhdF9tZW1iZXKUTowUbGlua19wcmV2aWV3X29wdGlvbnOUTowIbG9jYXRpb26UTowO\nbWVkaWFfZ3JvdXBfaWSUTowhbWVzc2FnZV9hdXRvX2RlbGV0ZV90aW1lcl9jaGFuZ2VklE6MEW1l\nc3NhZ2VfdGhyZWFkX2lklE6MFG1pZ3JhdGVfZnJvbV9jaGF0X2lklE6MEm1pZ3JhdGVfdG9fY2hh\ndF9pZJROjBBuZXdfY2hhdF9tZW1iZXJzlCmMDm5ld19jaGF0X3Bob3RvlCmMDm5ld19jaGF0X3Rp\ndGxllE6MDXBhc3Nwb3J0X2RhdGGUTowFcGhvdG+UKYwOcGlubmVkX21lc3NhZ2WUTowEcG9sbJRO\njBlwcm94aW1pdHlfYWxlcnRfdHJpZ2dlcmVklE6MBXF1b3RllE6MDHJlcGx5X21hcmt1cJROjBBy\nZXBseV90b19tZXNzYWdllE6MDnJlcGx5X3RvX3N0b3J5lE6MEnNlbmRlcl9ib29zdF9jb3VudJRO\njBNzZW5kZXJfYnVzaW5lc3NfYm90lE6MC3NlbmRlcl9jaGF0lE6MGHNob3dfY2FwdGlvbl9hYm92\nZV9tZWRpYZROjAdzdGlja2VylE6MBXN0b3J5lE6MEnN1Y2Nlc3NmdWxfcGF5bWVudJROjBdzdXBl\ncmdyb3VwX2NoYXRfY3JlYXRlZJSJjAR0ZXh0lIwGL3N0YXJ0lIwMdXNlcnNfc2hhcmVklE6MBXZl\nbnVllE6MB3ZpYV9ib3SUTowFdmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0\nX3BhcnRpY2lwYW50c19pbnZpdGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2No\nYXRfc3RhcnRlZJROjAp2aWRlb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0\nZV9hY2Nlc3NfYWxsb3dlZJROjARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZST\nlEMKB+gFFRMJJwAAAJSMBHB5dHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLDGgbiGgc\nSwxoCYaUaB59lHVijBBtZXNzYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSU\nTowObXlfY2hhdF9tZW1iZXKUTmiVTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5\nlE6MEnJlbW92ZWRfY2hhdF9ib29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSwxo\nG4hoHEsMhZRoHn2UdWIu\n" + }, + "response_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "location", + "longitude": 27.792887, + "latitude": 58.43161, + "reply_markup": "gASV4gMAAAAAAACMJXRlbGVncmFtLl9pbmxpbmUuaW5saW5la2V5Ym9hcmRtYXJrdXCUjBRJbmxp\nbmVLZXlib2FyZE1hcmt1cJSTlCmBlH2UKIwPaW5saW5lX2tleWJvYXJklCiMJXRlbGVncmFtLl9p\nbmxpbmUuaW5saW5la2V5Ym9hcmRidXR0b26UjBRJbmxpbmVLZXlib2FyZEJ1dHRvbpSTlCmBlH2U\nKIwNY2FsbGJhY2tfZGF0YZSMCWZvcm1hdHRlZJSMDWNhbGxiYWNrX2dhbWWUTowJbG9naW5fdXJs\nlE6MA3BheZROjBNzd2l0Y2hfaW5saW5lX3F1ZXJ5lE6MH3N3aXRjaF9pbmxpbmVfcXVlcnlfY2hv\nc2VuX2NoYXSUTowgc3dpdGNoX2lubGluZV9xdWVyeV9jdXJyZW50X2NoYXSUTowEdGV4dJSMFEN1\ndGUgZm9ybWF0dGVkIHRleHQhlIwDdXJslE6MB3dlYl9hcHCUTowHX2Zyb3plbpSIjAlfaWRfYXR0\ncnOUKGgUTk5oDE5OTk5OdJSMCmFwaV9rd2FyZ3OUfZR1YoWUaAgpgZR9lChoC4wLYXR0YWNobWVu\ndHOUaA1OaA5OaA9OaBBOaBFOaBJOaBOMFU11bHRpcGxlIGF0dGFjaG1lbnRzIZRoFU5oFk5oF4ho\nGChoIE5OaB9OTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAZzZWNyZXSUaA1OaA5OaA9OaBBOaBFO\naBJOaBOMDVNlY3JldCBpbWFnZSGUaBVOaBZOaBeIaBgoaCdOTmgmTk5OTk50lGgafZR1YoWUaAgp\ngZR9lChoC4wJdGh1bWJuYWlslGgNTmgOTmgPTmgQTmgRTmgSTmgTjBhEb2N1bWVudCB3aXRoIHRo\ndW1ibmFpbCGUaBVOaBZOaBeIaBgoaC5OTmgtTk5OTk50lGgafZR1YoWUaAgpgZR9lChoC4wEaGFz\naJRoDU5oDk5oD05oEE5oEU5oEk5oE4wcRmlyc3QgYXR0YWNobWVudCBieXRlcyBoYXNoIZRoFU5o\nFk5oF4hoGChoNU5OaDROTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAdyZXN0YXJ0lGgNTmgOTmgP\nTmgQTmgRTmgSTmgTjAhSZXN0YXJ0IZRoFU5oFk5oF4hoGChoPE5OaDtOTk5OTnSUaBp9lHViaAgp\ngZR9lChoC4wEcXVpdJRoDU5oDk5oD05oEE5oEU5oEk5oE4wFUXVpdCGUaBVOaBZOaBeIaBgoaEJO\nTmhBTk5OTk50lGgafZR1YoaUdJRoF4hoGGhGhZRoGn2UdWIu\n", + "__pickled_extra_fields__": [ + "reply_markup" + ] + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_location(42, 58.43161, 27.792887, horizontal_accuracy=None, disable_notification=None, protect_content=None, reply_markup=InlineKeyboardMarkup(inline_keyboard=((InlineKeyboardButton(callback_data='formatted', text='Cute formatted text!'),), (InlineKeyboardButton(callback_data='attachments', text='Multiple attachments!'),), (InlineKeyboardButton(callback_data='secret', text='Secret image!'),), (InlineKeyboardButton(callback_data='thumbnail', text='Document with thumbnail!'),), (InlineKeyboardButton(callback_data='hash', text='First attachment bytes hash!'),), (InlineKeyboardButton(callback_data='restart', text='Restart!'), InlineKeyboardButton(callback_data='quit', text='Quit!')))), message_effect_id=None, reply_to_message_id=None)" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 21, 19, 9, 57, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=13, supergroup_chat_created=False, text='some text'), update_id=13)", + "received_message": { + "text": "some text", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVrAoAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1bV90b3BpY19jbG9zZWSUTowTZm9y\ndW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0ZWSUTowUZm9ydW1fdG9waWNfcmVv\ncGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTowJZnJvbV91c2VylIwOdGVsZWdyYW0uX3VzZXKUaBCT\nlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25uZWN0X3RvX2J1c2lu\nZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBfbWVzc2FnZXOUTmgL\naAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2RllIwCZW6UaA9oEIwX\nc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKMBGdhbWWUTowaZ2Vu\nZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9mb3J1bV90b3BpY191bmhpZGRlbpRO\njAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQZ2l2ZWF3YXlfY3JlYXRlZJROjBBn\naXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRlZJSJjBFoYXNfbWVkaWFfc3BvaWxl\ncpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2ljZZROjBRpc19hdXRvbWF0aWNfZm9y\nd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNfbWVzc2FnZZROjBBsZWZ0X2NoYXRf\nbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxvY2F0aW9ulE6MDm1lZGlhX2dyb3Vw\nX2lklE6MIW1lc3NhZ2VfYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVh\nZF9pZJROjBRtaWdyYXRlX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3\nX2NoYXRfbWVtYmVyc5QpjA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNz\ncG9ydF9kYXRhlE6MBXBob3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5\nX2FsZXJ0X3RyaWdnZXJlZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUTowQcmVwbHlfdG9fbWVz\nc2FnZZROjA5yZXBseV90b19zdG9yeZROjBJzZW5kZXJfYm9vc3RfY291bnSUTowTc2VuZGVyX2J1\nc2luZXNzX2JvdJROjAtzZW5kZXJfY2hhdJROjBhzaG93X2NhcHRpb25fYWJvdmVfbWVkaWGUTowH\nc3RpY2tlcpROjAVzdG9yeZROjBJzdWNjZXNzZnVsX3BheW1lbnSUTowXc3VwZXJncm91cF9jaGF0\nX2NyZWF0ZWSUiYwEdGV4dJSMCXNvbWUgdGV4dJSMDHVzZXJzX3NoYXJlZJROjAV2ZW51ZZROjAd2\naWFfYm90lE6MBXZpZGVvlE6MEHZpZGVvX2NoYXRfZW5kZWSUTowfdmlkZW9fY2hhdF9wYXJ0aWNp\ncGFudHNfaW52aXRlZJROjBR2aWRlb19jaGF0X3NjaGVkdWxlZJROjBJ2aWRlb19jaGF0X3N0YXJ0\nZWSUTowKdmlkZW9fbm90ZZROjAV2b2ljZZROjAx3ZWJfYXBwX2RhdGGUTowUd3JpdGVfYWNjZXNz\nX2FsbG93ZWSUTowEY2hhdJRoCYwEZGF0ZZSMCGRhdGV0aW1llIwIZGF0ZXRpbWWUk5RDCgfoBRUT\nCTkAAACUjARweXR6lIwEX1VUQ5STlClSlIaUUpSMCm1lc3NhZ2VfaWSUSw1oG4hoHEsNaAmGlGge\nfZR1YowQbWVzc2FnZV9yZWFjdGlvbpROjBZtZXNzYWdlX3JlYWN0aW9uX2NvdW50lE6MDm15X2No\nYXRfbWVtYmVylE5ogk6MC3BvbGxfYW5zd2VylE6MEnByZV9jaGVja291dF9xdWVyeZROjBJyZW1v\ndmVkX2NoYXRfYm9vc3SUTowOc2hpcHBpbmdfcXVlcnmUTowJdXBkYXRlX2lklEsNaBuIaBxLDYWU\naB59lHViLg==\n" + }, + "response_message": { + "text": "Bot has entered unrecoverable state:/\nRun /start command again to restart.", + "attachments": null, + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, 'Bot has entered unrecoverable state:/\\nRun /start command again to restart.', parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)" + ] + }, + { + "update": "Update(message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 21, 19, 9, 59, tzinfo=UTC), delete_chat_photo=False, entities=(MessageEntity(length=6, offset=0, type=MessageEntityType.BOT_COMMAND),), from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), group_chat_created=False, message_id=14, supergroup_chat_created=False, text='/start'), update_id=14)", + "received_message": { + "text": "/start", + "attachments": [], + "annotations": null, + "misc": null, + "original_message": "gASVXwsAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUTowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9vc3SUTowRY2hhdF9qb2luX3JlcXVl\nc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9yZXN1bHSUTowZZGVsZXRlZF9idXNp\nbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVzc2FnZZROjBNlZGl0ZWRfY2hhbm5l\nbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9xdWVyeZROjAdtZXNzYWdllIwRdGVs\nZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVfZWZmZWN0aXZlX2F0dGFjaG1lbnSU\njBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVmYXVsdFZhbHVllJOUKYGUTn2UjAV2\nYWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1dGhvcl9zaWduYXR1cmWUTowLYm9v\nc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJROjAdjYXB0aW9ulE6MEGNhcHRpb25f\nZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwTY2hhdF9iYWNrZ3JvdW5kX3NldJRO\njAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZROjAdjb250YWN0lE6MEWRlbGV0ZV9j\naGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRpdF9kYXRllE6MCWVmZmVjdF9pZJRO\njAhlbnRpdGllc5SMF3RlbGVncmFtLl9tZXNzYWdlZW50aXR5lIwNTWVzc2FnZUVudGl0eZSTlCmB\nlH2UKIwPY3VzdG9tX2Vtb2ppX2lklE6MCGxhbmd1YWdllE6MBmxlbmd0aJRLBowGb2Zmc2V0lEsA\naBJoE4wRTWVzc2FnZUVudGl0eVR5cGWUk5SMC2JvdF9jb21tYW5klIWUUpSMA3VybJROjAR1c2Vy\nlE5oG4hoHGhdSwBLBoeUaB59lHVihZSMDmV4dGVybmFsX3JlcGx5lE6MEmZvcnVtX3RvcGljX2Ns\nb3NlZJROjBNmb3J1bV90b3BpY19jcmVhdGVklE6MEmZvcnVtX3RvcGljX2VkaXRlZJROjBRmb3J1\nbV90b3BpY19yZW9wZW5lZJROjA5mb3J3YXJkX29yaWdpbpROjAlmcm9tX3VzZXKUjA50ZWxlZ3Jh\nbS5fdXNlcpRoEJOUKYGUfZQojBhhZGRlZF90b19hdHRhY2htZW50X21lbnWUTowXY2FuX2Nvbm5l\nY3RfdG9fYnVzaW5lc3OUTowPY2FuX2pvaW5fZ3JvdXBzlE6MG2Nhbl9yZWFkX2FsbF9ncm91cF9t\nZXNzYWdlc5ROaAtoDGgNSyqMBmlzX2JvdJSJjAppc19wcmVtaXVtlE6MDWxhbmd1YWdlX2NvZGWU\njAJlbpRoD2gQjBdzdXBwb3J0c19pbmxpbmVfcXVlcmllc5ROaBloGmgbiGgcSyqFlGgefZR1YowE\nZ2FtZZROjBpnZW5lcmFsX2ZvcnVtX3RvcGljX2hpZGRlbpROjBxnZW5lcmFsX2ZvcnVtX3RvcGlj\nX3VuaGlkZGVulE6MCGdpdmVhd2F5lE6MEmdpdmVhd2F5X2NvbXBsZXRlZJROjBBnaXZlYXdheV9j\ncmVhdGVklE6MEGdpdmVhd2F5X3dpbm5lcnOUTowSZ3JvdXBfY2hhdF9jcmVhdGVklImMEWhhc19t\nZWRpYV9zcG9pbGVylE6MFWhhc19wcm90ZWN0ZWRfY29udGVudJROjAdpbnZvaWNllE6MFGlzX2F1\ndG9tYXRpY19mb3J3YXJklE6MD2lzX2Zyb21fb2ZmbGluZZROjBBpc190b3BpY19tZXNzYWdllE6M\nEGxlZnRfY2hhdF9tZW1iZXKUTowUbGlua19wcmV2aWV3X29wdGlvbnOUTowIbG9jYXRpb26UTowO\nbWVkaWFfZ3JvdXBfaWSUTowhbWVzc2FnZV9hdXRvX2RlbGV0ZV90aW1lcl9jaGFuZ2VklE6MEW1l\nc3NhZ2VfdGhyZWFkX2lklE6MFG1pZ3JhdGVfZnJvbV9jaGF0X2lklE6MEm1pZ3JhdGVfdG9fY2hh\ndF9pZJROjBBuZXdfY2hhdF9tZW1iZXJzlCmMDm5ld19jaGF0X3Bob3RvlCmMDm5ld19jaGF0X3Rp\ndGxllE6MDXBhc3Nwb3J0X2RhdGGUTowFcGhvdG+UKYwOcGlubmVkX21lc3NhZ2WUTowEcG9sbJRO\njBlwcm94aW1pdHlfYWxlcnRfdHJpZ2dlcmVklE6MBXF1b3RllE6MDHJlcGx5X21hcmt1cJROjBBy\nZXBseV90b19tZXNzYWdllE6MDnJlcGx5X3RvX3N0b3J5lE6MEnNlbmRlcl9ib29zdF9jb3VudJRO\njBNzZW5kZXJfYnVzaW5lc3NfYm90lE6MC3NlbmRlcl9jaGF0lE6MGHNob3dfY2FwdGlvbl9hYm92\nZV9tZWRpYZROjAdzdGlja2VylE6MBXN0b3J5lE6MEnN1Y2Nlc3NmdWxfcGF5bWVudJROjBdzdXBl\ncmdyb3VwX2NoYXRfY3JlYXRlZJSJjAR0ZXh0lIwGL3N0YXJ0lIwMdXNlcnNfc2hhcmVklE6MBXZl\nbnVllE6MB3ZpYV9ib3SUTowFdmlkZW+UTowQdmlkZW9fY2hhdF9lbmRlZJROjB92aWRlb19jaGF0\nX3BhcnRpY2lwYW50c19pbnZpdGVklE6MFHZpZGVvX2NoYXRfc2NoZWR1bGVklE6MEnZpZGVvX2No\nYXRfc3RhcnRlZJROjAp2aWRlb19ub3RllE6MBXZvaWNllE6MDHdlYl9hcHBfZGF0YZROjBR3cml0\nZV9hY2Nlc3NfYWxsb3dlZJROjARjaGF0lGgJjARkYXRllIwIZGF0ZXRpbWWUjAhkYXRldGltZZST\nlEMKB+gFFRMJOwAAAJSMBHB5dHqUjARfVVRDlJOUKVKUhpRSlIwKbWVzc2FnZV9pZJRLDmgbiGgc\nSw5oCYaUaB59lHVijBBtZXNzYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSU\nTowObXlfY2hhdF9tZW1iZXKUTmiVTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5\nlE6MEnJlbW92ZWRfY2hhdF9ib29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSw5o\nG4hoHEsOhZRoHn2UdWIu\n" + }, + "response_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "location", + "longitude": 27.792887, + "latitude": 58.43161, + "reply_markup": "gASV4gMAAAAAAACMJXRlbGVncmFtLl9pbmxpbmUuaW5saW5la2V5Ym9hcmRtYXJrdXCUjBRJbmxp\nbmVLZXlib2FyZE1hcmt1cJSTlCmBlH2UKIwPaW5saW5lX2tleWJvYXJklCiMJXRlbGVncmFtLl9p\nbmxpbmUuaW5saW5la2V5Ym9hcmRidXR0b26UjBRJbmxpbmVLZXlib2FyZEJ1dHRvbpSTlCmBlH2U\nKIwNY2FsbGJhY2tfZGF0YZSMCWZvcm1hdHRlZJSMDWNhbGxiYWNrX2dhbWWUTowJbG9naW5fdXJs\nlE6MA3BheZROjBNzd2l0Y2hfaW5saW5lX3F1ZXJ5lE6MH3N3aXRjaF9pbmxpbmVfcXVlcnlfY2hv\nc2VuX2NoYXSUTowgc3dpdGNoX2lubGluZV9xdWVyeV9jdXJyZW50X2NoYXSUTowEdGV4dJSMFEN1\ndGUgZm9ybWF0dGVkIHRleHQhlIwDdXJslE6MB3dlYl9hcHCUTowHX2Zyb3plbpSIjAlfaWRfYXR0\ncnOUKGgUTk5oDE5OTk5OdJSMCmFwaV9rd2FyZ3OUfZR1YoWUaAgpgZR9lChoC4wLYXR0YWNobWVu\ndHOUaA1OaA5OaA9OaBBOaBFOaBJOaBOMFU11bHRpcGxlIGF0dGFjaG1lbnRzIZRoFU5oFk5oF4ho\nGChoIE5OaB9OTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAZzZWNyZXSUaA1OaA5OaA9OaBBOaBFO\naBJOaBOMDVNlY3JldCBpbWFnZSGUaBVOaBZOaBeIaBgoaCdOTmgmTk5OTk50lGgafZR1YoWUaAgp\ngZR9lChoC4wJdGh1bWJuYWlslGgNTmgOTmgPTmgQTmgRTmgSTmgTjBhEb2N1bWVudCB3aXRoIHRo\ndW1ibmFpbCGUaBVOaBZOaBeIaBgoaC5OTmgtTk5OTk50lGgafZR1YoWUaAgpgZR9lChoC4wEaGFz\naJRoDU5oDk5oD05oEE5oEU5oEk5oE4wcRmlyc3QgYXR0YWNobWVudCBieXRlcyBoYXNoIZRoFU5o\nFk5oF4hoGChoNU5OaDROTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAdyZXN0YXJ0lGgNTmgOTmgP\nTmgQTmgRTmgSTmgTjAhSZXN0YXJ0IZRoFU5oFk5oF4hoGChoPE5OaDtOTk5OTnSUaBp9lHViaAgp\ngZR9lChoC4wEcXVpdJRoDU5oDk5oD05oEE5oEU5oEk5oE4wFUXVpdCGUaBVOaBZOaBeIaBgoaEJO\nTmhBTk5OTk50lGgafZR1YoaUdJRoF4hoGGhGhZRoGn2UdWIu\n", + "__pickled_extra_fields__": [ + "reply_markup" + ] + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_location(42, 58.43161, 27.792887, horizontal_accuracy=None, disable_notification=None, protect_content=None, reply_markup=InlineKeyboardMarkup(inline_keyboard=((InlineKeyboardButton(callback_data='formatted', text='Cute formatted text!'),), (InlineKeyboardButton(callback_data='attachments', text='Multiple attachments!'),), (InlineKeyboardButton(callback_data='secret', text='Secret image!'),), (InlineKeyboardButton(callback_data='thumbnail', text='Document with thumbnail!'),), (InlineKeyboardButton(callback_data='hash', text='First attachment bytes hash!'),), (InlineKeyboardButton(callback_data='restart', text='Restart!'), InlineKeyboardButton(callback_data='quit', text='Quit!')))), message_effect_id=None, reply_to_message_id=None)" + ] + }, + { + "update": "Update(callback_query=CallbackQuery(chat_instance='-1', data='restart', from_user=User(first_name='AlexaTestnder', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), id='14', message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 21, 19, 9, 59, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Bot', id=16, is_bot=True, username='dff_bot'), group_chat_created=False, location=Location(latitude=58.43162, longitude=27.792879), message_id=15, reply_markup=InlineKeyboardMarkup(inline_keyboard=((InlineKeyboardButton(callback_data='formatted', text='Cute formatted text!'),), (InlineKeyboardButton(callback_data='attachments', text='Multiple attachments!'),), (InlineKeyboardButton(callback_data='secret', text='Secret image!'),), (InlineKeyboardButton(callback_data='thumbnail', text='Document with thumbnail!'),), (InlineKeyboardButton(callback_data='hash', text='First attachment bytes hash!'),), (InlineKeyboardButton(callback_data='restart', text='Restart!'), InlineKeyboardButton(callback_data='quit', text='Quit!')))), supergroup_chat_created=False)), update_id=15)", + "received_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "callback_query", + "query_string": "restart" + } + ], + "annotations": null, + "misc": null, + "original_message": "gASVCRAAAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUjBd0ZWxlZ3JhbS5fY2FsbGJhY2txdWVyeZSMDUNhbGxiYWNrUXVlcnmUk5QpgZR9\nlCiMDWNoYXRfaW5zdGFuY2WUjAItMZSMBGRhdGGUjAdyZXN0YXJ0lIwJZnJvbV91c2VylIwOdGVs\nZWdyYW0uX3VzZXKUaBCTlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9j\nb25uZWN0X3RvX2J1c2luZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3Jv\ndXBfbWVzc2FnZXOUTmgLjA1BbGV4YVRlc3RuZGVylGgNSyqMBmlzX2JvdJSJjAppc19wcmVtaXVt\nlE6MDWxhbmd1YWdlX2NvZGWUjAJlbpRoD2gQjBdzdXBwb3J0c19pbmxpbmVfcXVlcmllc5ROaBlo\nGmgbiGgcSyqFlGgefZR1YowPZ2FtZV9zaG9ydF9uYW1llE5oDYwCMTSUjBFpbmxpbmVfbWVzc2Fn\nZV9pZJROjAdtZXNzYWdllIwRdGVsZWdyYW0uX21lc3NhZ2WUjAdNZXNzYWdllJOUKYGUfZQojBVf\nZWZmZWN0aXZlX2F0dGFjaG1lbnSUjBx0ZWxlZ3JhbS5fdXRpbHMuZGVmYXVsdHZhbHVllIwMRGVm\nYXVsdFZhbHVllJOUKYGUTn2UjAV2YWx1ZZROc4aUYowJYW5pbWF0aW9ulE6MBWF1ZGlvlE6MEGF1\ndGhvcl9zaWduYXR1cmWUTowLYm9vc3RfYWRkZWSUTowWYnVzaW5lc3NfY29ubmVjdGlvbl9pZJRO\njAdjYXB0aW9ulE6MEGNhcHRpb25fZW50aXRpZXOUKYwUY2hhbm5lbF9jaGF0X2NyZWF0ZWSUiYwT\nY2hhdF9iYWNrZ3JvdW5kX3NldJROjAtjaGF0X3NoYXJlZJROjBFjb25uZWN0ZWRfd2Vic2l0ZZRO\njAdjb250YWN0lE6MEWRlbGV0ZV9jaGF0X3Bob3RvlImMBGRpY2WUTowIZG9jdW1lbnSUTowJZWRp\ndF9kYXRllE6MCWVmZmVjdF9pZJROjAhlbnRpdGllc5QpjA5leHRlcm5hbF9yZXBseZROjBJmb3J1\nbV90b3BpY19jbG9zZWSUTowTZm9ydW1fdG9waWNfY3JlYXRlZJROjBJmb3J1bV90b3BpY19lZGl0\nZWSUTowUZm9ydW1fdG9waWNfcmVvcGVuZWSUTowOZm9yd2FyZF9vcmlnaW6UTmgvaDEpgZR9lCho\nNE5oNU5oNk5oN05oC4wDQm90lGgNSxBoOYhoOk5oO05oD05oPU5oGYwHZGZmX2JvdJRoG4hoHEsQ\nhZRoHn2UdWKMBGdhbWWUTowaZ2VuZXJhbF9mb3J1bV90b3BpY19oaWRkZW6UTowcZ2VuZXJhbF9m\nb3J1bV90b3BpY191bmhpZGRlbpROjAhnaXZlYXdheZROjBJnaXZlYXdheV9jb21wbGV0ZWSUTowQ\nZ2l2ZWF3YXlfY3JlYXRlZJROjBBnaXZlYXdheV93aW5uZXJzlE6MEmdyb3VwX2NoYXRfY3JlYXRl\nZJSJjBFoYXNfbWVkaWFfc3BvaWxlcpROjBVoYXNfcHJvdGVjdGVkX2NvbnRlbnSUTowHaW52b2lj\nZZROjBRpc19hdXRvbWF0aWNfZm9yd2FyZJROjA9pc19mcm9tX29mZmxpbmWUTowQaXNfdG9waWNf\nbWVzc2FnZZROjBBsZWZ0X2NoYXRfbWVtYmVylE6MFGxpbmtfcHJldmlld19vcHRpb25zlE6MCGxv\nY2F0aW9ulIwYdGVsZWdyYW0uX2ZpbGVzLmxvY2F0aW9ulIwITG9jYXRpb26Uk5QpgZR9lCiMB2hl\nYWRpbmeUTowTaG9yaXpvbnRhbF9hY2N1cmFjeZROjAhsYXRpdHVkZZRHQE03P1L8JleMC2xpdmVf\ncGVyaW9klE6MCWxvbmdpdHVkZZRHQDvK+h4+r2iMFnByb3hpbWl0eV9hbGVydF9yYWRpdXOUTmgb\niGgcR0A7yvoePq9oR0BNNz9S/CZXhpRoHn2UdWKMDm1lZGlhX2dyb3VwX2lklE6MIW1lc3NhZ2Vf\nYXV0b19kZWxldGVfdGltZXJfY2hhbmdlZJROjBFtZXNzYWdlX3RocmVhZF9pZJROjBRtaWdyYXRl\nX2Zyb21fY2hhdF9pZJROjBJtaWdyYXRlX3RvX2NoYXRfaWSUTowQbmV3X2NoYXRfbWVtYmVyc5Qp\njA5uZXdfY2hhdF9waG90b5QpjA5uZXdfY2hhdF90aXRsZZROjA1wYXNzcG9ydF9kYXRhlE6MBXBo\nb3RvlCmMDnBpbm5lZF9tZXNzYWdllE6MBHBvbGyUTowZcHJveGltaXR5X2FsZXJ0X3RyaWdnZXJl\nZJROjAVxdW90ZZROjAxyZXBseV9tYXJrdXCUjCV0ZWxlZ3JhbS5faW5saW5lLmlubGluZWtleWJv\nYXJkbWFya3VwlIwUSW5saW5lS2V5Ym9hcmRNYXJrdXCUk5QpgZR9lCiMD2lubGluZV9rZXlib2Fy\nZJQojCV0ZWxlZ3JhbS5faW5saW5lLmlubGluZWtleWJvYXJkYnV0dG9ulIwUSW5saW5lS2V5Ym9h\ncmRCdXR0b26Uk5QpgZR9lCiMDWNhbGxiYWNrX2RhdGGUjAlmb3JtYXR0ZWSUjA1jYWxsYmFja19n\nYW1llE6MCWxvZ2luX3VybJROjANwYXmUTowTc3dpdGNoX2lubGluZV9xdWVyeZROjB9zd2l0Y2hf\naW5saW5lX3F1ZXJ5X2Nob3Nlbl9jaGF0lE6MIHN3aXRjaF9pbmxpbmVfcXVlcnlfY3VycmVudF9j\naGF0lE6MBHRleHSUjBRDdXRlIGZvcm1hdHRlZCB0ZXh0IZSMA3VybJROjAd3ZWJfYXBwlE5oG4ho\nHChosE5OaKhOTk5OTnSUaB59lHVihZRopCmBlH2UKGinjAthdHRhY2htZW50c5RoqU5oqk5oq05o\nrE5orU5ork5or4wVTXVsdGlwbGUgYXR0YWNobWVudHMhlGixTmiyTmgbiGgcKGi5Tk5ouE5OTk5O\ndJRoHn2UdWKFlGikKYGUfZQoaKeMBnNlY3JldJRoqU5oqk5oq05orE5orU5ork5or4wNU2VjcmV0\nIGltYWdlIZRosU5osk5oG4hoHChowE5OaL9OTk5OTnSUaB59lHVihZRopCmBlH2UKGinjAl0aHVt\nYm5haWyUaKlOaKpOaKtOaKxOaK1OaK5OaK+MGERvY3VtZW50IHdpdGggdGh1bWJuYWlsIZRosU5o\nsk5oG4hoHChox05OaMZOTk5OTnSUaB59lHVihZRopCmBlH2UKGinjARoYXNolGipTmiqTmirTmis\nTmitTmiuTmivjBxGaXJzdCBhdHRhY2htZW50IGJ5dGVzIGhhc2ghlGixTmiyTmgbiGgcKGjOTk5o\nzU5OTk5OdJRoHn2UdWKFlGikKYGUfZQoaKdoLmipTmiqTmirTmisTmitTmiuTmivjAhSZXN0YXJ0\nIZRosU5osk5oG4hoHCho1E5OaC5OTk5OTnSUaB59lHViaKQpgZR9lChop4wEcXVpdJRoqU5oqk5o\nq05orE5orU5ork5or4wFUXVpdCGUaLFOaLJOaBuIaBwoaNpOTmjZTk5OTk50lGgefZR1YoaUdJRo\nG4hoHGjehZRoHn2UdWKMEHJlcGx5X3RvX21lc3NhZ2WUTowOcmVwbHlfdG9fc3RvcnmUTowSc2Vu\nZGVyX2Jvb3N0X2NvdW50lE6ME3NlbmRlcl9idXNpbmVzc19ib3SUTowLc2VuZGVyX2NoYXSUTowY\nc2hvd19jYXB0aW9uX2Fib3ZlX21lZGlhlE6MB3N0aWNrZXKUTowFc3RvcnmUTowSc3VjY2Vzc2Z1\nbF9wYXltZW50lE6MF3N1cGVyZ3JvdXBfY2hhdF9jcmVhdGVklIlor06MDHVzZXJzX3NoYXJlZJRO\njAV2ZW51ZZROjAd2aWFfYm90lE6MBXZpZGVvlE6MEHZpZGVvX2NoYXRfZW5kZWSUTowfdmlkZW9f\nY2hhdF9wYXJ0aWNpcGFudHNfaW52aXRlZJROjBR2aWRlb19jaGF0X3NjaGVkdWxlZJROjBJ2aWRl\nb19jaGF0X3N0YXJ0ZWSUTowKdmlkZW9fbm90ZZROjAV2b2ljZZROjAx3ZWJfYXBwX2RhdGGUTowU\nd3JpdGVfYWNjZXNzX2FsbG93ZWSUTowEY2hhdJRoCYwEZGF0ZZSMCGRhdGV0aW1llIwIZGF0ZXRp\nbWWUk5RDCgfoBRUTCTsAAACUjARweXR6lIwEX1VUQ5STlClSlIaUUpSMCm1lc3NhZ2VfaWSUSw9o\nG4hoHEsPaAmGlGgefZR1YmgbiGgcaEGFlGgefZR1YowMY2hhbm5lbF9wb3N0lE6MCmNoYXRfYm9v\nc3SUTowRY2hhdF9qb2luX3JlcXVlc3SUTowLY2hhdF9tZW1iZXKUTowUY2hvc2VuX2lubGluZV9y\nZXN1bHSUTowZZGVsZXRlZF9idXNpbmVzc19tZXNzYWdlc5ROjBdlZGl0ZWRfYnVzaW5lc3NfbWVz\nc2FnZZROjBNlZGl0ZWRfY2hhbm5lbF9wb3N0lE6MDmVkaXRlZF9tZXNzYWdllE6MDGlubGluZV9x\ndWVyeZROaENOjBBtZXNzYWdlX3JlYWN0aW9ulE6MFm1lc3NhZ2VfcmVhY3Rpb25fY291bnSUTowO\nbXlfY2hhdF9tZW1iZXKUTmiYTowLcG9sbF9hbnN3ZXKUTowScHJlX2NoZWNrb3V0X3F1ZXJ5lE6M\nEnJlbW92ZWRfY2hhdF9ib29zdJROjA5zaGlwcGluZ19xdWVyeZROjAl1cGRhdGVfaWSUSw9oG4ho\nHEsPhZRoHn2UdWIu\n" + }, + "response_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "location", + "longitude": 27.792887, + "latitude": 58.43161, + "reply_markup": "gASV4gMAAAAAAACMJXRlbGVncmFtLl9pbmxpbmUuaW5saW5la2V5Ym9hcmRtYXJrdXCUjBRJbmxp\nbmVLZXlib2FyZE1hcmt1cJSTlCmBlH2UKIwPaW5saW5lX2tleWJvYXJklCiMJXRlbGVncmFtLl9p\nbmxpbmUuaW5saW5la2V5Ym9hcmRidXR0b26UjBRJbmxpbmVLZXlib2FyZEJ1dHRvbpSTlCmBlH2U\nKIwNY2FsbGJhY2tfZGF0YZSMCWZvcm1hdHRlZJSMDWNhbGxiYWNrX2dhbWWUTowJbG9naW5fdXJs\nlE6MA3BheZROjBNzd2l0Y2hfaW5saW5lX3F1ZXJ5lE6MH3N3aXRjaF9pbmxpbmVfcXVlcnlfY2hv\nc2VuX2NoYXSUTowgc3dpdGNoX2lubGluZV9xdWVyeV9jdXJyZW50X2NoYXSUTowEdGV4dJSMFEN1\ndGUgZm9ybWF0dGVkIHRleHQhlIwDdXJslE6MB3dlYl9hcHCUTowHX2Zyb3plbpSIjAlfaWRfYXR0\ncnOUKGgUTk5oDE5OTk5OdJSMCmFwaV9rd2FyZ3OUfZR1YoWUaAgpgZR9lChoC4wLYXR0YWNobWVu\ndHOUaA1OaA5OaA9OaBBOaBFOaBJOaBOMFU11bHRpcGxlIGF0dGFjaG1lbnRzIZRoFU5oFk5oF4ho\nGChoIE5OaB9OTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAZzZWNyZXSUaA1OaA5OaA9OaBBOaBFO\naBJOaBOMDVNlY3JldCBpbWFnZSGUaBVOaBZOaBeIaBgoaCdOTmgmTk5OTk50lGgafZR1YoWUaAgp\ngZR9lChoC4wJdGh1bWJuYWlslGgNTmgOTmgPTmgQTmgRTmgSTmgTjBhEb2N1bWVudCB3aXRoIHRo\ndW1ibmFpbCGUaBVOaBZOaBeIaBgoaC5OTmgtTk5OTk50lGgafZR1YoWUaAgpgZR9lChoC4wEaGFz\naJRoDU5oDk5oD05oEE5oEU5oEk5oE4wcRmlyc3QgYXR0YWNobWVudCBieXRlcyBoYXNoIZRoFU5o\nFk5oF4hoGChoNU5OaDROTk5OTnSUaBp9lHVihZRoCCmBlH2UKGgLjAdyZXN0YXJ0lGgNTmgOTmgP\nTmgQTmgRTmgSTmgTjAhSZXN0YXJ0IZRoFU5oFk5oF4hoGChoPE5OaDtOTk5OTnSUaBp9lHViaAgp\ngZR9lChoC4wEcXVpdJRoDU5oDk5oD05oEE5oEU5oEk5oE4wFUXVpdCGUaBVOaBZOaBeIaBgoaEJO\nTmhBTk5OTk50lGgafZR1YoaUdJRoF4hoGGhGhZRoGn2UdWIu\n", + "__pickled_extra_fields__": [ + "reply_markup" + ] + } + ], + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_location(42, 58.43161, 27.792887, horizontal_accuracy=None, disable_notification=None, protect_content=None, reply_markup=InlineKeyboardMarkup(inline_keyboard=((InlineKeyboardButton(callback_data='formatted', text='Cute formatted text!'),), (InlineKeyboardButton(callback_data='attachments', text='Multiple attachments!'),), (InlineKeyboardButton(callback_data='secret', text='Secret image!'),), (InlineKeyboardButton(callback_data='thumbnail', text='Document with thumbnail!'),), (InlineKeyboardButton(callback_data='hash', text='First attachment bytes hash!'),), (InlineKeyboardButton(callback_data='restart', text='Restart!'), InlineKeyboardButton(callback_data='quit', text='Quit!')))), message_effect_id=None, reply_to_message_id=None)" + ] + }, + { + "update": "Update(callback_query=CallbackQuery(chat_instance='-1', data='quit', from_user=User(first_name='Test', id=42, is_bot=False, language_code='en', last_name='User', username='test_user'), id='15', message=Message(channel_chat_created=False, chat=Chat(first_name='Test', id=42, last_name='User', type=ChatType.PRIVATE, username='test_user'), date=datetime.datetime(2024, 5, 21, 19, 10, 1, tzinfo=UTC), delete_chat_photo=False, from_user=User(first_name='Bot', id=16, is_bot=True, username='dff_bot'), group_chat_created=False, location=Location(latitude=58.43162, longitude=27.792879), message_id=16, reply_markup=InlineKeyboardMarkup(inline_keyboard=((InlineKeyboardButton(callback_data='formatted', text='Cute formatted text!'),), (InlineKeyboardButton(callback_data='attachments', text='Multiple attachments!'),), (InlineKeyboardButton(callback_data='secret', text='Secret image!'),), (InlineKeyboardButton(callback_data='thumbnail', text='Document with thumbnail!'),), (InlineKeyboardButton(callback_data='hash', text='First attachment bytes hash!'),), (InlineKeyboardButton(callback_data='restart', text='Restart!'), InlineKeyboardButton(callback_data='quit', text='Quit!')))), supergroup_chat_created=False)), update_id=16)", + "received_message": { + "text": null, + "attachments": [ + { + "dff_attachment_type": "callback_query", + "query_string": "quit" + } + ], + "annotations": null, + "misc": null, + "original_message": "gASV+w8AAAAAAACMEHRlbGVncmFtLl91cGRhdGWUjAZVcGRhdGWUk5QpgZR9lCiMD19lZmZlY3Rp\ndmVfY2hhdJSMDnRlbGVncmFtLl9jaGF0lIwEQ2hhdJSTlCmBlH2UKIwKZmlyc3RfbmFtZZSMBFRl\nc3SUjAJpZJRLKowIaXNfZm9ydW2UTowJbGFzdF9uYW1llIwEVXNlcpSMBXRpdGxllE6MBHR5cGWU\njBJ0ZWxlZ3JhbS5jb25zdGFudHOUjAhDaGF0VHlwZZSTlIwHcHJpdmF0ZZSFlFKUjAh1c2VybmFt\nZZSMCXRlc3RfdXNlcpSMB19mcm96ZW6UiIwJX2lkX2F0dHJzlEsqhZSMCmFwaV9rd2FyZ3OUfZR1\nYowSX2VmZmVjdGl2ZV9tZXNzYWdllE6MEV9lZmZlY3RpdmVfc2VuZGVylE6MD19lZmZlY3RpdmVf\ndXNlcpROjBNidXNpbmVzc19jb25uZWN0aW9ulE6MEGJ1c2luZXNzX21lc3NhZ2WUTowOY2FsbGJh\nY2tfcXVlcnmUjBd0ZWxlZ3JhbS5fY2FsbGJhY2txdWVyeZSMDUNhbGxiYWNrUXVlcnmUk5QpgZR9\nlCiMDWNoYXRfaW5zdGFuY2WUjAItMZSMBGRhdGGUjARxdWl0lIwJZnJvbV91c2VylIwOdGVsZWdy\nYW0uX3VzZXKUaBCTlCmBlH2UKIwYYWRkZWRfdG9fYXR0YWNobWVudF9tZW51lE6MF2Nhbl9jb25u\nZWN0X3RvX2J1c2luZXNzlE6MD2Nhbl9qb2luX2dyb3Vwc5ROjBtjYW5fcmVhZF9hbGxfZ3JvdXBf\nbWVzc2FnZXOUTmgLaAxoDUsqjAZpc19ib3SUiYwKaXNfcHJlbWl1bZROjA1sYW5ndWFnZV9jb2Rl\nlIwCZW6UaA9oEIwXc3VwcG9ydHNfaW5saW5lX3F1ZXJpZXOUTmgZaBpoG4hoHEsqhZRoHn2UdWKM\nD2dhbWVfc2hvcnRfbmFtZZROaA2MAjE1lIwRaW5saW5lX21lc3NhZ2VfaWSUTowHbWVzc2FnZZSM\nEXRlbGVncmFtLl9tZXNzYWdllIwHTWVzc2FnZZSTlCmBlH2UKIwVX2VmZmVjdGl2ZV9hdHRhY2ht\nZW50lIwcdGVsZWdyYW0uX3V0aWxzLmRlZmF1bHR2YWx1ZZSMDERlZmF1bHRWYWx1ZZSTlCmBlE59\nlIwFdmFsdWWUTnOGlGKMCWFuaW1hdGlvbpROjAVhdWRpb5ROjBBhdXRob3Jfc2lnbmF0dXJllE6M\nC2Jvb3N0X2FkZGVklE6MFmJ1c2luZXNzX2Nvbm5lY3Rpb25faWSUTowHY2FwdGlvbpROjBBjYXB0\naW9uX2VudGl0aWVzlCmMFGNoYW5uZWxfY2hhdF9jcmVhdGVklImME2NoYXRfYmFja2dyb3VuZF9z\nZXSUTowLY2hhdF9zaGFyZWSUTowRY29ubmVjdGVkX3dlYnNpdGWUTowHY29udGFjdJROjBFkZWxl\ndGVfY2hhdF9waG90b5SJjARkaWNllE6MCGRvY3VtZW50lE6MCWVkaXRfZGF0ZZROjAllZmZlY3Rf\naWSUTowIZW50aXRpZXOUKYwOZXh0ZXJuYWxfcmVwbHmUTowSZm9ydW1fdG9waWNfY2xvc2VklE6M\nE2ZvcnVtX3RvcGljX2NyZWF0ZWSUTowSZm9ydW1fdG9waWNfZWRpdGVklE6MFGZvcnVtX3RvcGlj\nX3Jlb3BlbmVklE6MDmZvcndhcmRfb3JpZ2lulE5oL2gxKYGUfZQoaDROaDVOaDZOaDdOaAuMA0Jv\ndJRoDUsQaDiIaDlOaDpOaA9OaDxOaBmMB2RmZl9ib3SUaBuIaBxLEIWUaB59lHVijARnYW1llE6M\nGmdlbmVyYWxfZm9ydW1fdG9waWNfaGlkZGVulE6MHGdlbmVyYWxfZm9ydW1fdG9waWNfdW5oaWRk\nZW6UTowIZ2l2ZWF3YXmUTowSZ2l2ZWF3YXlfY29tcGxldGVklE6MEGdpdmVhd2F5X2NyZWF0ZWSU\nTowQZ2l2ZWF3YXlfd2lubmVyc5ROjBJncm91cF9jaGF0X2NyZWF0ZWSUiYwRaGFzX21lZGlhX3Nw\nb2lsZXKUTowVaGFzX3Byb3RlY3RlZF9jb250ZW50lE6MB2ludm9pY2WUTowUaXNfYXV0b21hdGlj\nX2ZvcndhcmSUTowPaXNfZnJvbV9vZmZsaW5llE6MEGlzX3RvcGljX21lc3NhZ2WUTowQbGVmdF9j\naGF0X21lbWJlcpROjBRsaW5rX3ByZXZpZXdfb3B0aW9uc5ROjAhsb2NhdGlvbpSMGHRlbGVncmFt\nLl9maWxlcy5sb2NhdGlvbpSMCExvY2F0aW9ulJOUKYGUfZQojAdoZWFkaW5nlE6ME2hvcml6b250\nYWxfYWNjdXJhY3mUTowIbGF0aXR1ZGWUR0BNNz9S/CZXjAtsaXZlX3BlcmlvZJROjAlsb25naXR1\nZGWUR0A7yvoePq9ojBZwcm94aW1pdHlfYWxlcnRfcmFkaXVzlE5oG4hoHEdAO8r6Hj6vaEdATTc/\nUvwmV4aUaB59lHVijA5tZWRpYV9ncm91cF9pZJROjCFtZXNzYWdlX2F1dG9fZGVsZXRlX3RpbWVy\nX2NoYW5nZWSUTowRbWVzc2FnZV90aHJlYWRfaWSUTowUbWlncmF0ZV9mcm9tX2NoYXRfaWSUTowS\nbWlncmF0ZV90b19jaGF0X2lklE6MEG5ld19jaGF0X21lbWJlcnOUKYwObmV3X2NoYXRfcGhvdG+U\nKYwObmV3X2NoYXRfdGl0bGWUTowNcGFzc3BvcnRfZGF0YZROjAVwaG90b5QpjA5waW5uZWRfbWVz\nc2FnZZROjARwb2xslE6MGXByb3hpbWl0eV9hbGVydF90cmlnZ2VyZWSUTowFcXVvdGWUTowMcmVw\nbHlfbWFya3VwlIwldGVsZWdyYW0uX2lubGluZS5pbmxpbmVrZXlib2FyZG1hcmt1cJSMFElubGlu\nZUtleWJvYXJkTWFya3VwlJOUKYGUfZQojA9pbmxpbmVfa2V5Ym9hcmSUKIwldGVsZWdyYW0uX2lu\nbGluZS5pbmxpbmVrZXlib2FyZGJ1dHRvbpSMFElubGluZUtleWJvYXJkQnV0dG9ulJOUKYGUfZQo\njA1jYWxsYmFja19kYXRhlIwJZm9ybWF0dGVklIwNY2FsbGJhY2tfZ2FtZZROjAlsb2dpbl91cmyU\nTowDcGF5lE6ME3N3aXRjaF9pbmxpbmVfcXVlcnmUTowfc3dpdGNoX2lubGluZV9xdWVyeV9jaG9z\nZW5fY2hhdJROjCBzd2l0Y2hfaW5saW5lX3F1ZXJ5X2N1cnJlbnRfY2hhdJROjAR0ZXh0lIwUQ3V0\nZSBmb3JtYXR0ZWQgdGV4dCGUjAN1cmyUTowHd2ViX2FwcJROaBuIaBwoaK9OTminTk5OTk50lGge\nfZR1YoWUaKMpgZR9lChopowLYXR0YWNobWVudHOUaKhOaKlOaKpOaKtOaKxOaK1OaK6MFU11bHRp\ncGxlIGF0dGFjaG1lbnRzIZRosE5osU5oG4hoHChouE5OaLdOTk5OTnSUaB59lHVihZRooymBlH2U\nKGimjAZzZWNyZXSUaKhOaKlOaKpOaKtOaKxOaK1OaK6MDVNlY3JldCBpbWFnZSGUaLBOaLFOaBuI\naBwoaL9OTmi+Tk5OTk50lGgefZR1YoWUaKMpgZR9lChopowJdGh1bWJuYWlslGioTmipTmiqTmir\nTmisTmitTmiujBhEb2N1bWVudCB3aXRoIHRodW1ibmFpbCGUaLBOaLFOaBuIaBwoaMZOTmjFTk5O\nTk50lGgefZR1YoWUaKMpgZR9lChopowEaGFzaJRoqE5oqU5oqk5oq05orE5orU5orowcRmlyc3Qg\nYXR0YWNobWVudCBieXRlcyBoYXNoIZRosE5osU5oG4hoHChozU5OaMxOTk5OTnSUaB59lHVihZRo\noymBlH2UKGimjAdyZXN0YXJ0lGioTmipTmiqTmirTmisTmitTmiujAhSZXN0YXJ0IZRosE5osU5o\nG4hoHCho1E5OaNNOTk5OTnSUaB59lHViaKMpgZR9lChopmguaKhOaKlOaKpOaKtOaKxOaK1OaK6M\nBVF1aXQhlGiwTmixTmgbiGgcKGjZTk5oLk5OTk5OdJRoHn2UdWKGlHSUaBuIaBxo3YWUaB59lHVi\njBByZXBseV90b19tZXNzYWdllE6MDnJlcGx5X3RvX3N0b3J5lE6MEnNlbmRlcl9ib29zdF9jb3Vu\ndJROjBNzZW5kZXJfYnVzaW5lc3NfYm90lE6MC3NlbmRlcl9jaGF0lE6MGHNob3dfY2FwdGlvbl9h\nYm92ZV9tZWRpYZROjAdzdGlja2VylE6MBXN0b3J5lE6MEnN1Y2Nlc3NmdWxfcGF5bWVudJROjBdz\ndXBlcmdyb3VwX2NoYXRfY3JlYXRlZJSJaK5OjAx1c2Vyc19zaGFyZWSUTowFdmVudWWUTowHdmlh\nX2JvdJROjAV2aWRlb5ROjBB2aWRlb19jaGF0X2VuZGVklE6MH3ZpZGVvX2NoYXRfcGFydGljaXBh\nbnRzX2ludml0ZWSUTowUdmlkZW9fY2hhdF9zY2hlZHVsZWSUTowSdmlkZW9fY2hhdF9zdGFydGVk\nlE6MCnZpZGVvX25vdGWUTowFdm9pY2WUTowMd2ViX2FwcF9kYXRhlE6MFHdyaXRlX2FjY2Vzc19h\nbGxvd2VklE6MBGNoYXSUaAmMBGRhdGWUjAhkYXRldGltZZSMCGRhdGV0aW1llJOUQwoH6AUVEwoB\nAAAAlIwEcHl0epSMBF9VVEOUk5QpUpSGlFKUjAptZXNzYWdlX2lklEsQaBuIaBxLEGgJhpRoHn2U\ndWJoG4hoHGhAhZRoHn2UdWKMDGNoYW5uZWxfcG9zdJROjApjaGF0X2Jvb3N0lE6MEWNoYXRfam9p\nbl9yZXF1ZXN0lE6MC2NoYXRfbWVtYmVylE6MFGNob3Nlbl9pbmxpbmVfcmVzdWx0lE6MGWRlbGV0\nZWRfYnVzaW5lc3NfbWVzc2FnZXOUTowXZWRpdGVkX2J1c2luZXNzX21lc3NhZ2WUTowTZWRpdGVk\nX2NoYW5uZWxfcG9zdJROjA5lZGl0ZWRfbWVzc2FnZZROjAxpbmxpbmVfcXVlcnmUTmhCTowQbWVz\nc2FnZV9yZWFjdGlvbpROjBZtZXNzYWdlX3JlYWN0aW9uX2NvdW50lE6MDm15X2NoYXRfbWVtYmVy\nlE5ol06MC3BvbGxfYW5zd2VylE6MEnByZV9jaGVja291dF9xdWVyeZROjBJyZW1vdmVkX2NoYXRf\nYm9vc3SUTowOc2hpcHBpbmdfcXVlcnmUTowJdXBkYXRlX2lklEsQaBuIaBxLEIWUaB59lHViLg==\n" + }, + "response_message": { + "text": "Bot has entered unrecoverable state:/\nRun /start command again to restart.", + "attachments": null, + "annotations": null, + "misc": null, + "original_message": null + }, + "response_functions": [ + "send_message(42, 'Bot has entered unrecoverable state:/\\nRun /start command again to restart.', parse_mode=None, disable_notification=None, protect_content=None, reply_markup=None, message_effect_id=None, reply_to_message_id=None, disable_web_page_preview=None)" + ] + } + ] +} \ No newline at end of file diff --git a/tests/messengers/telegram/test_tutorials.py b/tests/messengers/telegram/test_tutorials.py index 0443fac5b..8cd39000a 100644 --- a/tests/messengers/telegram/test_tutorials.py +++ b/tests/messengers/telegram/test_tutorials.py @@ -1,59 +1,40 @@ -""" -These tests check that pipelines defined in tutorials follow `happy_path` defined in the same tutorials. -""" - -import importlib -import logging +from importlib import import_module +from json import loads +from pathlib import Path import pytest -try: - import telebot # noqa: F401 - import telethon # noqa: F401 -except ImportError: - pytest.skip(reason="`telegram` is not available", allow_module_level=True) - +from dff.messengers.telegram import telegram_available +from dff.script.core.message import DataAttachment from tests.test_utils import get_path_from_tests_to_current_dir -from dff.utils.testing.common import check_happy_path -from dff.utils.testing.telegram import TelegramTesting, replace_click_button - -dot_path_to_addon = get_path_from_tests_to_current_dir(__file__, separator=".") +if telegram_available: + from tests.messengers.telegram.utils import cast_dict_to_happy_step, MockApplication -@pytest.mark.parametrize( - "tutorial_module_name", - [ - "1_basic", - "2_buttons", - "3_buttons_with_callback", - ], -) -def test_client_tutorials_without_telegram(tutorial_module_name, env_vars): - tutorial_module = importlib.import_module(f"tutorials.{dot_path_to_addon}.{tutorial_module_name}") - pipeline = tutorial_module.pipeline - happy_path = tutorial_module.happy_path - check_happy_path(pipeline, replace_click_button(happy_path)) +dot_path_to_addon = get_path_from_tests_to_current_dir(__file__, separator=".") +happy_paths_file = Path(__file__).parent / "test_happy_paths.json" -@pytest.mark.asyncio +@pytest.mark.skipif(not telegram_available, reason="Telegram dependencies missing") @pytest.mark.parametrize( "tutorial_module_name", - [ - "1_basic", - "2_buttons", - "3_buttons_with_callback", - "4_conditions", - "5_conditions_with_media", - "7_polling_setup", - ], + ["1_basic", "2_attachments", "3_advanced"], ) -@pytest.mark.telegram -async def test_client_tutorials(tutorial_module_name, api_credentials, bot_user, session_file): - tutorial_module = importlib.import_module(f"tutorials.{dot_path_to_addon}.{tutorial_module_name}") - pipeline = tutorial_module.pipeline - happy_path = tutorial_module.happy_path - test_helper = TelegramTesting( - pipeline=pipeline, api_credentials=api_credentials, session_file=session_file, bot=bot_user - ) - logging.info("Test start") - await test_helper.check_happy_path(happy_path) +def test_tutorials(tutorial_module_name: str, monkeypatch): + def patched_data_attachment_eq(self: DataAttachment, other: DataAttachment): + first_copy = self.model_copy() + if first_copy.cached_filename is not None: + first_copy.cached_filename = first_copy.cached_filename.name + second_copy = other.model_copy() + if second_copy.cached_filename is not None: + second_copy.cached_filename = second_copy.cached_filename.name + return super(DataAttachment, first_copy).__eq__(second_copy) + + monkeypatch.setattr(DataAttachment, "__eq__", patched_data_attachment_eq) + + monkeypatch.setenv("TG_BOT_TOKEN", "token") + happy_path_data = loads(happy_paths_file.read_text())[tutorial_module_name] + happy_path_steps = cast_dict_to_happy_step(happy_path_data) + module = import_module(f"tutorials.{dot_path_to_addon}.{tutorial_module_name}") + module.interface.application = MockApplication.create(module.interface, happy_path_steps) + module.pipeline.run() diff --git a/tests/messengers/telegram/test_types.py b/tests/messengers/telegram/test_types.py deleted file mode 100644 index e5ecb184e..000000000 --- a/tests/messengers/telegram/test_types.py +++ /dev/null @@ -1,222 +0,0 @@ -import json -from io import IOBase -from pathlib import Path - -import pytest - -try: - import telebot # noqa: F401 - import telethon # noqa: F401 -except ImportError: - pytest.skip(reason="`telegram` is not available", allow_module_level=True) - -from pydantic import ValidationError -from telebot import types - -from dff.messengers.telegram.message import ( - TelegramMessage, - TelegramUI, - RemoveKeyboard, - ParseMode, -) -from dff.script import Message -from dff.script.core.message import Attachments, Keyboard, Button, Image, Location, Audio, Video, Attachment, Document -from dff.messengers.telegram.utils import open_io, close_io, batch_open_io - -from dff.utils.testing.telegram import TelegramTesting - -image = Image( - source="https://gist.githubusercontent.com/scotthaleen/32f76a413e0dfd4b4d79c2a534d49c0b/raw" - "/6c1036b1eca90b341caf06d4056d36f64fc11e88/tiny.jpg" -) -audio = Audio(source="https://github.com/mathiasbynens/small/raw/master/mp3.mp3") -video = Video(source="https://github.com/mathiasbynens/small/raw/master/Mpeg4.mp4") -document = Document(source="https://github.com/mathiasbynens/small/raw/master/pdf.pdf") - - -@pytest.mark.asyncio -@pytest.mark.telegram -async def test_text(pipeline_instance, api_credentials, bot_user, session_file): - telegram_response = TelegramMessage(text="test") - test_helper = TelegramTesting( - pipeline=pipeline_instance, api_credentials=api_credentials, session_file=session_file, bot=bot_user - ) - await test_helper.send_and_check(telegram_response) - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - ["ui", "markup_type", "button_type"], - [ - ( - Keyboard( - buttons=[ - Button(text="button 1", payload=json.dumps({"text": "1", "other_prop": "4"})), - Button(text="button 2", payload=json.dumps({"text": "2", "other_prop": "3"})), - Button(text="button 3", payload=json.dumps({"text": "3", "other_prop": "2"})), - Button(text="button 4", payload=json.dumps({"text": "4", "other_prop": "1"})), - ] - ), - types.InlineKeyboardMarkup, - types.InlineKeyboardButton, - ), - ( - TelegramUI( - is_inline=False, - buttons=[ - Button(text="button 1"), - Button(text="button 2"), - Button(text="button 3"), - Button(text="button 4"), - ], - ), - types.ReplyKeyboardMarkup, - types.KeyboardButton, - ), - ], -) -@pytest.mark.telegram -async def test_buttons(ui, button_type, markup_type, pipeline_instance, api_credentials, bot_user, session_file): - telegram_response = TelegramMessage(text="test", ui=ui) - test_helper = TelegramTesting( - pipeline=pipeline_instance, api_credentials=api_credentials, session_file=session_file, bot=bot_user - ) - await test_helper.send_and_check(telegram_response) - - -@pytest.mark.asyncio -@pytest.mark.telegram -async def test_keyboard_remove(pipeline_instance, api_credentials, bot_user, session_file): - telegram_response = TelegramMessage(text="test", ui=RemoveKeyboard()) - test_helper = TelegramTesting( - pipeline=pipeline_instance, api_credentials=api_credentials, session_file=session_file, bot=bot_user - ) - await test_helper.send_and_check(telegram_response) - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - ["generic_response"], - [ - ( - Message( - text="test", - attachments=Attachments(files=[image]), - ), - ), - ( - Message( - text="test", - attachments=Attachments(files=[audio]), - ), - ), - ( - Message( - text="test", - attachments=Attachments(files=[video]), - ), - ), - (Message("test", attachments=Attachments(files=[document])),), - ], -) -@pytest.mark.telegram -async def test_telegram_attachment(generic_response, pipeline_instance, api_credentials, bot_user, session_file): - telegram_response = TelegramMessage.model_validate(generic_response) - test_helper = TelegramTesting( - pipeline=pipeline_instance, api_credentials=api_credentials, session_file=session_file, bot=bot_user - ) - await test_helper.send_and_check(telegram_response) - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - ["attachments"], - [ - ( - Message( - text="test", - attachments=Attachments(files=2 * [image]), - ), - ), - ( - Message( - text="test", - attachments=Attachments(files=2 * [audio]), - ), - ), - ( - Message( - text="test", - attachments=Attachments(files=2 * [video]), - ), - ), - (Message("test", attachments=Attachments(files=2 * [document])),), - ], -) -@pytest.mark.telegram -async def test_attachments(attachments, pipeline_instance, api_credentials, bot_user, session_file): - telegram_response = TelegramMessage.model_validate(attachments) - test_helper = TelegramTesting( - pipeline=pipeline_instance, api_credentials=api_credentials, session_file=session_file, bot=bot_user - ) - await test_helper.send_and_check(telegram_response) - - -@pytest.mark.asyncio -@pytest.mark.telegram -async def test_location(pipeline_instance, api_credentials, bot_user, session_file): - telegram_response = TelegramMessage(text="location", location=Location(longitude=39.0, latitude=43.0)) - test_helper = TelegramTesting( - pipeline=pipeline_instance, api_credentials=api_credentials, session_file=session_file, bot=bot_user - ) - await test_helper.send_and_check(telegram_response) - - -@pytest.mark.asyncio -@pytest.mark.telegram -async def test_parsed_text(pipeline_instance, api_credentials, bot_user, session_file): - telegram_response = TelegramMessage(text="[inline URL](http://www.example.com/)", parse_mode=ParseMode.MARKDOWN) - test_helper = TelegramTesting( - pipeline=pipeline_instance, api_credentials=api_credentials, session_file=session_file, bot=bot_user - ) - await test_helper.send_and_check(telegram_response) - - -def test_missing_error(): - with pytest.raises(ValidationError) as e: - _ = Attachment(source="http://google.com", id="123") - assert e - - with pytest.raises(ValidationError) as e: - _ = Attachment(source="/etc/missing_file") - assert e - - -def test_attachment_error(): - with pytest.raises(ValidationError) as e: - _ = Attachments(files=["a", "b"]) - assert e - - -def test_empty_keyboard(): - with pytest.raises(ValidationError) as e: - _ = TelegramUI(buttons=[]) - assert e - - -def test_non_inline_keyboard_with_payload(): - with pytest.raises(ValidationError) as error: - TelegramUI(buttons=[Button(text="", payload="")], is_inline=False) - assert error - - -def test_io(document): - tele_doc = types.InputMediaDocument(media=Path(document)) - opened_doc = open_io(tele_doc) - print(type(opened_doc.media)) - assert isinstance(opened_doc.media, IOBase) - close_io(opened_doc) - assert opened_doc.media.closed - with batch_open_io(tele_doc) as med: - assert isinstance(med.media, IOBase) - assert tele_doc.media.closed diff --git a/tests/messengers/telegram/utils.py b/tests/messengers/telegram/utils.py new file mode 100644 index 000000000..0f06a78b2 --- /dev/null +++ b/tests/messengers/telegram/utils.py @@ -0,0 +1,130 @@ +from asyncio import get_event_loop +from contextlib import contextmanager +from importlib import import_module +from hashlib import sha256 +from typing import Any, Dict, Hashable, Iterator, List, Optional, Tuple, Union + +from pydantic import BaseModel +from telegram import InputFile, InputMedia, Update +from typing_extensions import TypeAlias + +from dff.messengers.telegram.abstract import _AbstractTelegramInterface +from dff.script import Message +from dff.script.core.context import Context + +PathStep: TypeAlias = Tuple[Update, Message, Message, List[str]] + + +def cast_dict_to_happy_step(dictionary: Dict, update_only: bool = False) -> Union[List["PathStep"]]: + imports = globals().copy() + imports.update(import_module("telegram").__dict__) + imports.update(import_module("telegram.ext").__dict__) + imports.update(import_module("telegram.constants").__dict__) + + path_steps = list() + for step in dictionary: + update = eval(step["update"], imports) + if not update_only: + received = Message.model_validate(step["received_message"]) + received.original_message = update + response = Message.model_validate(step["response_message"]) + path_steps += [(update, received, response, step["response_functions"])] + else: + path_steps += [(update, Message(), Message(), list())] + return path_steps + + +class MockBot(BaseModel, arbitrary_types_allowed=True): + latest_trace: List[str] = list() + + @staticmethod + def representation(any: Any) -> str: + if isinstance(any, InputFile): + return sha256(any.input_file_content).hexdigest() + elif isinstance(any, InputMedia): + data = MockBot.representation(any.media) if isinstance(any.media, InputFile) else "<>" + return f"{type(any).__name__}(data='{data}', type={any.type.__repr__()})" + elif isinstance(any, bytes): + return sha256(any).hexdigest().__repr__() + elif isinstance(any, list): + return f"[{', '.join([MockBot.representation(a) for a in any])}]" + else: + return any.__repr__() + + def __getattribute__(self, name: str) -> Any: + async def set_trace(*args, **kwargs): + joined_args = ", ".join([self.representation(a) for a in args]) + joined_kwargs = ", ".join([f"{k}={self.representation(v)}" for k, v in kwargs.items()]) + arguments = ", ".join([joined_args, joined_kwargs]) + self.latest_trace += [f"{name}({arguments})"] + + try: + return object.__getattribute__(self, name) + except AttributeError: + return set_trace + + +class MockApplication(BaseModel, arbitrary_types_allowed=True): + bot: MockBot + happy_path: List[PathStep] + interface: _AbstractTelegramInterface + latest_ctx: Optional[Context] = None + + @classmethod + def create(cls, interface: _AbstractTelegramInterface, happy_path: List[PathStep]) -> "MockApplication": + instance = cls(bot=MockBot(), happy_path=happy_path, interface=interface) + return instance + + @contextmanager + def _check_context_and_trace( + self, last_request: Message, last_response: Message, last_trace: List[str] + ) -> Iterator[None]: + self.bot.latest_trace = list() + self.latest_ctx = None + yield + assert self.latest_ctx is not None, "During pipeline runner execution, no context was produced!" + assert self.latest_ctx.last_request == last_request, "Expected request message is not equal to expected!" + assert self.latest_ctx.last_response == last_response, "Expected response message is not equal to expected!" + assert self.bot.latest_trace == last_trace, "Expected trace is not equal to expected!" + + @contextmanager + def _wrap_pipeline_runner(self) -> Iterator[None]: + original_pipeline_runner = self.interface._pipeline_runner + + async def wrapped_pipeline_runner( + message: Message, ctx_id: Optional[Hashable] = None, update_ctx_misc: Optional[dict] = None + ) -> Context: + self.latest_ctx = await original_pipeline_runner(message, ctx_id, update_ctx_misc) + return self.latest_ctx + + self.interface._pipeline_runner = wrapped_pipeline_runner + yield + self.interface._pipeline_runner = original_pipeline_runner + + @contextmanager + def _wrap_get_attachment_bytes(self) -> Iterator[None]: + async def wrapped_get_attachment_bytes(source: str) -> bytes: + return source.encode() + + original_populate_attachment = self.interface.get_attachment_bytes + self.interface.get_attachment_bytes = wrapped_get_attachment_bytes + yield + self.interface.get_attachment_bytes = original_populate_attachment + + def _run_bot(self) -> None: + loop = get_event_loop() + with self._wrap_pipeline_runner(), self._wrap_get_attachment_bytes(): + for update, received, response, trace in self.happy_path: + with self._check_context_and_trace(received, response, trace): + if update.message is not None: + loop.run_until_complete(self.interface.on_message(update, None)) # type: ignore + elif update.callback_query is not None: + loop.run_until_complete(self.interface.on_callback(update, None)) # type: ignore + else: + raise RuntimeError(f"Update {update} type unknown!") + + def run_polling(self, poll_interval: float, timeout: int, allowed_updates: List[str]) -> None: + return self._run_bot() + + def run_webhook(self, listen: str, port: str, allowed_updates: List[str]) -> None: + return self._run_bot() diff --git a/tests/pipeline/test_messenger_interface.py b/tests/pipeline/test_messenger_interface.py index c85384b09..c5f3daef0 100644 --- a/tests/pipeline/test_messenger_interface.py +++ b/tests/pipeline/test_messenger_interface.py @@ -3,7 +3,8 @@ import pathlib from dff.script import RESPONSE, TRANSITIONS, Message -from dff.messengers.common import CLIMessengerInterface, CallbackMessengerInterface +from dff.messengers.console import CLIMessengerInterface +from dff.messengers.common import CallbackMessengerInterface from dff.pipeline import Pipeline import dff.script.conditions as cnd diff --git a/tests/script/conditions/test_conditions.py b/tests/script/conditions/test_conditions.py index 60035c728..46160a720 100644 --- a/tests/script/conditions/test_conditions.py +++ b/tests/script/conditions/test_conditions.py @@ -16,7 +16,7 @@ def test_conditions(): assert cnd.exact_match("text")(ctx, pipeline) assert cnd.exact_match(Message("text", misc={}))(ctx, pipeline) - assert not cnd.exact_match(Message("text", misc={1: 1}))(ctx, pipeline) + assert not cnd.exact_match(Message("text", misc={"one": 1}))(ctx, pipeline) assert not cnd.exact_match("text1")(ctx, pipeline) assert cnd.exact_match(Message())(ctx, pipeline) assert not cnd.exact_match(Message(), skip_none=False)(ctx, pipeline) diff --git a/tests/script/core/test_message.py b/tests/script/core/test_message.py index b846c38dd..ec4145c6b 100644 --- a/tests/script/core/test_message.py +++ b/tests/script/core/test_message.py @@ -1,49 +1,135 @@ +from os import urandom +from pathlib import Path +from random import randint +from shutil import rmtree +from typing import Hashable, Optional, TextIO +from urllib.request import urlopen + import pytest +from pydantic import ValidationError, HttpUrl, FilePath -from dff.script.core.message import Location, Attachment - - -def test_location(): - loc1 = Location(longitude=-0.1, latitude=-0.1) - loc2 = Location(longitude=-0.09999, latitude=-0.09998) - loc3 = Location(longitude=-0.10002, latitude=-0.10001) - - assert loc1 == loc2 - assert loc3 == loc1 - assert loc2 != loc3 - - assert loc1 != 1 - - -@pytest.mark.parametrize( - "attachment1,attachment2,equal", - [ - ( - Attachment(source="https://github.com/mathiasbynens/small/raw/master/pdf.pdf", title="File"), - Attachment(source="https://raw.githubusercontent.com/mathiasbynens/small/master/pdf.pdf", title="File"), - True, - ), - ( - Attachment(source="https://github.com/mathiasbynens/small/raw/master/pdf.pdf", title="1"), - Attachment(source="https://raw.githubusercontent.com/mathiasbynens/small/master/pdf.pdf", title="2"), - False, - ), - ( - Attachment(source=__file__, title="File"), - Attachment(source=__file__, title="File"), - True, - ), - ( - Attachment(source=__file__, title="1"), - Attachment(source=__file__, title="2"), - False, - ), - ( - Attachment(id="1", title="File"), - Attachment(id="2", title="File"), - False, - ), - ], +from dff.messengers.common.interface import MessengerInterfaceWithAttachments +from dff.messengers.console import CLIMessengerInterface +from dff.script.core.message import ( + Animation, + Audio, + CallbackQuery, + Contact, + Document, + Image, + Invoice, + Location, + DataAttachment, + Message, + Poll, + PollOption, + Sticker, + Video, ) -def test_attachment(attachment1, attachment2, equal): - assert (attachment1 == attachment2) == equal + +EXAMPLE_SOURCE = "https://github.com/deeppavlov/dialog_flow_framework/wiki/example_attachments" + + +class UnserializableObject: + def __init__(self, number: int, string: bytes) -> None: + self.number = number + self.bytes = string + + def __eq__(self, value: object) -> bool: + if isinstance(value, UnserializableObject): + return self.number == value.number and self.bytes == value.bytes + else: + return False + + +class DFFCLIMessengerInterface(CLIMessengerInterface, MessengerInterfaceWithAttachments): + supported_response_attachment_types = {Document} + + def __init__(self, attachments_directory: Optional[Path] = None): + MessengerInterfaceWithAttachments.__init__(self, attachments_directory) + self._ctx_id: Optional[Hashable] = None + self._intro: Optional[str] = None + self._prompt_request: str = "request: " + self._prompt_response: str = "response: " + self._descriptor: Optional[TextIO] = None + + async def get_attachment_bytes(self, attachment: str) -> bytes: + with urlopen(f"{EXAMPLE_SOURCE}/{attachment}") as url: + return url.read() + + +class TestMessage: + @pytest.fixture + def random_original_message(self) -> UnserializableObject: + return UnserializableObject(randint(0, 256), urandom(32)) + + def clear_and_create_dir(self, dir: Path) -> Path: + rmtree(dir, ignore_errors=True) + dir.mkdir() + return dir + + @pytest.mark.parametrize( + "attachment", + [ + CallbackQuery(query_string="some_callback_query_data"), + Location(longitude=53.055955, latitude=102.891407), + Contact(phone_number="8-900-555-35-35", first_name="Hope", last_name="Credit"), + Invoice(title="Payment", description="No comment", currency="USD", amount=300), + Poll(question="Which?", options=[PollOption(text="1", votes=2), PollOption(text="2", votes=5)]), + Audio(source="https://example.com/some_audio.mp3"), + Video(source="https://example.com/some_video.mp4"), + Animation(source="https://example.com/some_animation.gif"), + Image(source="https://example.com/some_image.png"), + Sticker(id="some_sticker_identifier"), + Document(source="https://example.com/some_document.pdf"), + ], + ) + def test_attachment_serialize(self, attachment: DataAttachment): + message = Message(attachments=[attachment]) + serialized = message.model_dump_json() + validated = Message.model_validate_json(serialized) + assert message == validated + + def test_field_serializable(self, random_original_message: UnserializableObject): + message = Message(text="sample message") + message.misc = {"answer": 42, "unserializable": random_original_message} + message.original_message = random_original_message + message.some_extra_field = random_original_message + message.other_extra_field = {"unserializable": random_original_message} + serialized = message.model_dump_json() + validated = Message.model_validate_json(serialized) + assert message == validated + + @pytest.mark.asyncio + async def test_getting_attachment_bytes(self, tmp_path): + local_path = self.clear_and_create_dir(tmp_path / "local") + + local_document = local_path / "pre-saved-document.pdf" + cli_iface = DFFCLIMessengerInterface(self.clear_and_create_dir(tmp_path / "cache")) + + document_name = "deeppavlov-article.pdf" + remote_document_url = f"{EXAMPLE_SOURCE}/{document_name}" + with urlopen(remote_document_url) as url: + document_bytes = url.read() + local_document.write_bytes(document_bytes) + + remote_document_att = Document(source=str(remote_document_url)) + local_document_att = Document(source=str(local_document)) + iface_document_att = Document(id=document_name) + + for document in (remote_document_att, local_document_att, iface_document_att): + read_bytes = await document.get_bytes(cli_iface) + assert document_bytes == read_bytes + if not isinstance(document.source, Path): + assert document.cached_filename is not None + cached_bytes = document.cached_filename.read_bytes() + assert document_bytes == cached_bytes + + def test_missing_error(self): + with pytest.raises(ValidationError) as e: + _ = DataAttachment(source=HttpUrl("http://google.com"), id="123") + assert e + + with pytest.raises(ValidationError) as e: + _ = DataAttachment(source=FilePath("/etc/missing_file")) + assert e diff --git a/tests/utils/test_serialization.py b/tests/utils/test_serialization.py new file mode 100644 index 000000000..334b8f14a --- /dev/null +++ b/tests/utils/test_serialization.py @@ -0,0 +1,115 @@ +from typing import Optional + +import pytest +from pydantic import BaseModel + +import dff.utils.devel.json_serialization as json_ser + + +class UnserializableClass: + def __init__(self): + self.exc = RuntimeError("exception") + + def __eq__(self, other): + if not isinstance(other, UnserializableClass): + return False + return type(self.exc) == type(other.exc) and self.exc.args == other.exc.args # noqa: E721 + + +class PydanticClass(BaseModel, arbitrary_types_allowed=True): + field: Optional[UnserializableClass] + + +class TestJSONPickleSerialization: + @pytest.fixture(scope="function") + def unserializable_obj(self): + return UnserializableClass() + + ######################### + # DICT-RELATED FIXTURES # + ######################### + + @pytest.fixture(scope="function") + def unserializable_dict(self, unserializable_obj): + return { + "bytes": b"123", + "non_pydantic_non_serializable": unserializable_obj, + "non_pydantic_serializable": "string", + "pydantic_non_serializable": PydanticClass(field=unserializable_obj), + "pydantic_serializable": PydanticClass(field=None), + } + + @pytest.fixture(scope="function") + def non_serializable_fields(self): + return ["bytes", "non_pydantic_non_serializable", "pydantic_non_serializable"] + + @pytest.fixture(scope="function") + def deserialized_dict(self, unserializable_obj): + return { + "bytes": b"123", + "non_pydantic_non_serializable": unserializable_obj, + "non_pydantic_serializable": "string", + "pydantic_non_serializable": PydanticClass(field=unserializable_obj), + "pydantic_serializable": {"field": None}, + } + + ######################### + ######################### + ######################### + + def test_pickle(self, unserializable_obj): + serialized = json_ser.pickle_serializer(unserializable_obj) + assert isinstance(serialized, str) + assert json_ser.pickle_validator(serialized) == unserializable_obj + + def test_json_pickle(self, unserializable_dict, non_serializable_fields, deserialized_dict): + serialized = json_ser.json_pickle_serializer(unserializable_dict) + + assert serialized[json_ser._JSON_EXTRA_FIELDS_KEYS] == non_serializable_fields + assert all(isinstance(serialized[field], str) for field in non_serializable_fields) + assert serialized["non_pydantic_serializable"] == "string" + assert serialized["pydantic_serializable"] == {"field": None} + + deserialized = json_ser.json_pickle_validator(serialized) + assert deserialized == deserialized_dict + + def test_serializable_value(self, unserializable_obj): + class Class(BaseModel): + field: Optional[json_ser.PickleEncodedValue] = None + + obj = Class() + obj.field = unserializable_obj + + dump = obj.model_dump(mode="json") + + assert isinstance(dump["field"], str) + + reconstructed_obj = Class.model_validate(dump) + + assert reconstructed_obj.field == unserializable_obj + + def test_serializable_dict(self, unserializable_dict, non_serializable_fields, deserialized_dict): + class Class(BaseModel): + field: json_ser.JSONSerializableDict + + obj = Class(field=unserializable_dict) + + dump = obj.model_dump(mode="json") + assert dump["field"][json_ser._JSON_EXTRA_FIELDS_KEYS] == non_serializable_fields + + reconstructed_obj = Class.model_validate(dump) + + assert reconstructed_obj.field == deserialized_dict + + def test_serializable_extras(self, unserializable_dict, non_serializable_fields, deserialized_dict): + class Class(json_ser.JSONSerializableExtras): + pass + + obj = Class(**unserializable_dict) + + dump = obj.model_dump(mode="json") + assert dump[json_ser._JSON_EXTRA_FIELDS_KEYS] == non_serializable_fields + + reconstructed_obj = Class.model_validate(dump) + + assert reconstructed_obj.__pydantic_extra__ == deserialized_dict diff --git a/tutorials/messengers/telegram/1_basic.py b/tutorials/messengers/telegram/1_basic.py index 7d804eafe..11d20b1fd 100644 --- a/tutorials/messengers/telegram/1_basic.py +++ b/tutorials/messengers/telegram/1_basic.py @@ -5,8 +5,8 @@ The following tutorial shows how to run a regular DFF script in Telegram. It asks users for the '/start' command and then loops in one place. -Here, %mddoclink(api,messengers.telegram.interface,PollingTelegramInterface) -class and [telebot](https://pytba.readthedocs.io/en/latest/index.html) +Here, %mddoclink(api,messengers.telegram.interface,LongpollingInterface) +class and [python-telegram-bot](https://docs.python-telegram-bot.org/) library are used for accessing telegram API in polling mode. Telegram API token is required to access telegram API. @@ -20,23 +20,30 @@ class and [telebot](https://pytba.readthedocs.io/en/latest/index.html) from dff.script import conditions as cnd from dff.script import labels as lbl from dff.script import RESPONSE, TRANSITIONS, Message -from dff.messengers.telegram import PollingTelegramInterface +from dff.messengers.telegram import LongpollingInterface from dff.pipeline import Pipeline from dff.utils.testing.common import is_interactive_mode # %% [markdown] """ -In order to integrate your script with Telegram, you need an instance of -`TelegramMessenger` class and one of the following interfaces: -`PollingMessengerInterface` or `WebhookMessengerInterface`. - -`TelegramMessenger` encapsulates the bot logic. Like Telebot, -`TelegramMessenger` only requires a token to run. However, all parameters -from the Telebot class can be passed as keyword arguments. - -The two interfaces connect the bot to Telegram. They can be passed directly -to the DFF `Pipeline` instance. +In order to integrate your script with Telegram, you need an instance of the +%mddoclink(api,messengers.telegram.abstract,_AbstractTelegramInterface) class. +Two of its child subclasses that can be instantiated +are %mddoclink(api,messengers.telegram.interface,LongpollingInterface) and +%mddoclink(api,messengers.telegram.interface,WebhookInterface). +The latter requires a webserver, so here we use long polling interface. + +%mddoclink(api,messengers.telegram.abstract,_AbstractTelegramInterface) +encapsulates the bot logic. The only required +argument for a bot to run is a token. Some other parameters +(such as host, port, interval, etc.) can be passed as keyword arguments +(for their specs see [documentations of the child subclasses]( +%doclink(api,messengers.telegram.interface) +). + +Either of the two interfaces connect the bot to Telegram. +They can be passed directly to the DFF `Pipeline` instance. """ @@ -57,16 +64,9 @@ class and [telebot](https://pytba.readthedocs.io/en/latest/index.html) } } -# this variable is only for testing -happy_path = ( - (Message("/start"), Message("Hi")), - (Message("Hi"), Message("Hi")), - (Message("Bye"), Message("Hi")), -) - # %% -interface = PollingTelegramInterface(token=os.environ["TG_BOT_TOKEN"]) +interface = LongpollingInterface(token=os.environ["TG_BOT_TOKEN"]) # %% @@ -79,10 +79,7 @@ class and [telebot](https://pytba.readthedocs.io/en/latest/index.html) ) -def main(): - pipeline.run() - - -if __name__ == "__main__" and is_interactive_mode(): - # prevent run during doc building - main() +if __name__ == "__main__": + if is_interactive_mode(): + # prevent run during doc building + pipeline.run() diff --git a/tutorials/messengers/telegram/2_attachments.py b/tutorials/messengers/telegram/2_attachments.py new file mode 100644 index 000000000..749c262f1 --- /dev/null +++ b/tutorials/messengers/telegram/2_attachments.py @@ -0,0 +1,274 @@ +# %% [markdown] +""" +# Telegram: 2. Attachments + +The following tutorial shows how to send different attachments using +telegram interfaces. + +Here, %mddoclink(api,messengers.telegram.interface,LongpollingInterface) +class and [python-telegram-bot](https://docs.python-telegram-bot.org/) +library are used for accessing telegram API in polling mode. + +Telegram API token is required to access telegram API. +""" + +# %pip install dff[telegram] + +# %% +import os + +from pydantic import HttpUrl + +from dff.script import conditions as cnd +from dff.script import GLOBAL, RESPONSE, TRANSITIONS, Message +from dff.messengers.telegram import LongpollingInterface +from dff.pipeline import Pipeline +from dff.script.core.message import ( + Animation, + Audio, + Contact, + Document, + Location, + Image, + MediaGroup, + Poll, + PollOption, + Sticker, + Video, + VideoMessage, + VoiceMessage, +) +from dff.utils.testing.common import is_interactive_mode + + +# %% [markdown] +""" +Example attachment data is specified below in form of dictionaries. +List of attachments that telegram messenger interface can send can +be found here: +%mddoclink(api,messengers.telegram.abstract,_AbstractTelegramInterface.supported_request_attachment_types). +""" + +# %% + +EXAMPLE_ATTACHMENT_SOURCE = ( + "https://github.com/deeppavlov/" + + "dialog_flow_framework/wiki/example_attachments" +) + +location_data = {"latitude": 50.65, "longitude": 3.916667} + +contact_data = { + "phone_number": "8-900-555-35-35", + "first_name": "Hope", + "last_name": "Credit", +} + +sticker_data = { + "id": ( + "CAACAgIAAxkBAAErAAFXZibO5ksphCKS" + + "XSe1CYiw5588yqsAAkEAAzyKVxogmx2BPCogYDQE" + ), + "caption": "A sticker I've just found", +} + +audio_data = { + "source": HttpUrl( + f"{EXAMPLE_ATTACHMENT_SOURCE}/separation-william-king.mp3" + ), + "caption": "Separation melody by William King", + "filename": "separation-william-king.mp3", +} + +video_data = { + "source": HttpUrl( + f"{EXAMPLE_ATTACHMENT_SOURCE}/crownfall-lags-nkognit0.mp4" + ), + "caption": "Epic Dota2 gameplay by Nkognit0", + "filename": "crownfall-lags-nkognit0.mp4", +} + +animation_data = { + # For some reason, if we don't define filename explicitly, + # animation is sent as file. + "source": HttpUrl( + f"{EXAMPLE_ATTACHMENT_SOURCE}/hong-kong-simplyart4794.gif" + ), + "caption": "Hong Kong skyscraper views by Simplyart4794", + "filename": "hong-kong-simplyart4794.gif", +} + +image_data = { + "source": HttpUrl(f"{EXAMPLE_ATTACHMENT_SOURCE}/deeppavlov.png"), + "caption": "DeepPavlov logo", + "filename": "deeppavlov.png", +} + +document_data = { + "source": HttpUrl(f"{EXAMPLE_ATTACHMENT_SOURCE}/deeppavlov-article.pdf"), + "caption": "DeepPavlov article", + "filename": "deeppavlov-article.pdf", +} + +ATTACHMENTS = [ + "location", + "contact", + "poll", + "sticker", + "audio", + "video", + "animation", + "image", + "document", + "voice_message", + "video_message", + "media_group", +] + +QUOTED_ATTACHMENTS = [f'"{attachment}"' for attachment in ATTACHMENTS] + + +# %% [markdown] +""" +The bot below sends different attachments on request. + +[Here](%doclink(api,script.core.message)) you can find +all the attachment options available. +""" + +# %% +script = { + GLOBAL: { + TRANSITIONS: { + ("main_flow", f"{attachment}_node"): cnd.exact_match(attachment) + for attachment in ATTACHMENTS + } + }, + "main_flow": { + "start_node": { + TRANSITIONS: {"intro_node": cnd.exact_match("/start")}, + }, + "intro_node": { + RESPONSE: Message( + f'Type {", ".join(QUOTED_ATTACHMENTS[:-1])}' + f" or {QUOTED_ATTACHMENTS[-1]}" + f" to receive a corresponding attachment!" + ), + }, + "location_node": { + RESPONSE: Message( + "Here's your location!", + attachments=[Location(**location_data)], + ), + }, + "contact_node": { + RESPONSE: Message( + "Here's your contact!", + attachments=[Contact(**contact_data)], + ), + }, + "poll_node": { + RESPONSE: Message( + "Here's your poll!", + attachments=[ + Poll( + question="What is the poll question?", + options=[ + PollOption(text="This one!"), + PollOption(text="Not this one :("), + ], + ), + ], + ), + }, + "sticker_node": { + RESPONSE: Message( + "Here's your sticker!", + attachments=[Sticker(**sticker_data)], + ), + }, + "audio_node": { + RESPONSE: Message( + "Here's your audio!", + attachments=[Audio(**audio_data)], + ), + }, + "video_node": { + RESPONSE: Message( + "Here's your video!", + attachments=[Video(**video_data)], + ), + }, + "animation_node": { + RESPONSE: Message( + "Here's your animation!", + attachments=[Animation(**animation_data)], + ), + }, + "image_node": { + RESPONSE: Message( + "Here's your image!", + attachments=[Image(**image_data)], + ), + }, + "document_node": { + RESPONSE: Message( + "Here's your document!", + attachments=[Document(**document_data)], + ), + }, + "voice_message_node": { + RESPONSE: Message( + "Here's your voice message!", + attachments=[VoiceMessage(source=audio_data["source"])], + ), + }, + "video_message_node": { + RESPONSE: Message( + "Here's your video message!", + attachments=[VideoMessage(source=video_data["source"])], + ), + }, + "media_group_node": { + RESPONSE: Message( + "Here's your media group!", + attachments=[ + MediaGroup( + group=[ + Image(**image_data), + Video(**video_data), + ], + ) + ], + ), + }, + "fallback_node": { + RESPONSE: Message( + f"Unknown attachment type, try again! " + f"Supported attachments are: " + f'{", ".join(QUOTED_ATTACHMENTS[:-1])} ' + f"and {QUOTED_ATTACHMENTS[-1]}." + ), + }, + }, +} + + +# %% +interface = LongpollingInterface(token=os.environ["TG_BOT_TOKEN"]) + + +# %% +pipeline = Pipeline.from_script( + script=script, + start_label=("main_flow", "start_node"), + fallback_label=("main_flow", "fallback_node"), + messenger_interface=interface, + # The interface can be passed as a pipeline argument. +) + + +if __name__ == "__main__": + if is_interactive_mode(): + # prevent run during doc building + pipeline.run() diff --git a/tutorials/messengers/telegram/2_buttons.py b/tutorials/messengers/telegram/2_buttons.py deleted file mode 100644 index 6e5817fe0..000000000 --- a/tutorials/messengers/telegram/2_buttons.py +++ /dev/null @@ -1,193 +0,0 @@ -# %% [markdown] -""" -# Telegram: 2. Buttons - -This tutorial shows how to display and hide a basic keyboard in Telegram. - -Here, %mddoclink(api,messengers.telegram.message,TelegramMessage) -class is used to represent telegram message, -%mddoclink(api,messengers.telegram.message,TelegramUI) and -%mddoclink(api,messengers.telegram.message,RemoveKeyboard) -classes are used for configuring additional telegram message features. - -Different %mddoclink(api,script.core.message,message) -classes are used for representing different common message features, -like Attachment, Audio, Button, Image, etc. -""" - - -# %pip install dff[telegram] - -# %% -import os - -import dff.script.conditions as cnd -from dff.script import TRANSITIONS, RESPONSE -from dff.script.core.message import Button -from dff.pipeline import Pipeline -from dff.messengers.telegram import ( - PollingTelegramInterface, - TelegramUI, - TelegramMessage, - RemoveKeyboard, -) -from dff.utils.testing.common import is_interactive_mode - - -# %% [markdown] -""" -To display or hide a keyboard, you can utilize the `ui` field of the -`TelegramMessage` class. It can be initialized either with -a `TelegramUI` instance or with a custom telebot keyboard. - -Passing an instance of `RemoveKeyboard` to the `ui` field -will indicate that the keyboard should be removed. -""" - - -# %% -script = { - "root": { - "start": { - TRANSITIONS: { - ("general", "native_keyboard"): ( - lambda ctx, _: ctx.last_request.text - in ("/start", "/restart") - ), - }, - }, - "fallback": { - RESPONSE: TelegramMessage( - text="Finishing test, send /restart command to restart" - ), - TRANSITIONS: { - ("general", "native_keyboard"): ( - lambda ctx, _: ctx.last_request.text - in ("/start", "/restart") - ), - }, - }, - }, - "general": { - "native_keyboard": { - RESPONSE: TelegramMessage( - text="Question: What's 2 + 2?", - # In this case, we use telegram-specific classes. - # They derive from the generic ones and include more options, - # e.g. simple keyboard or inline keyboard. - ui=TelegramUI( - buttons=[ - Button(text="5"), - Button(text="4"), - ], - is_inline=False, - row_width=4, - ), - ), - TRANSITIONS: { - ("general", "success"): cnd.exact_match( - TelegramMessage(text="4") - ), - ("general", "fail"): cnd.true(), - }, - }, - "success": { - RESPONSE: TelegramMessage( - **{"text": "Success!", "ui": RemoveKeyboard()} - ), - TRANSITIONS: {("root", "fallback"): cnd.true()}, - }, - "fail": { - RESPONSE: TelegramMessage( - **{ - "text": "Incorrect answer, type anything to try again", - "ui": RemoveKeyboard(), - } - ), - TRANSITIONS: {("general", "native_keyboard"): cnd.true()}, - }, - }, -} - -interface = PollingTelegramInterface(token=os.environ["TG_BOT_TOKEN"]) - -# this variable is only for testing -happy_path = ( - ( - TelegramMessage(text="/start"), - TelegramMessage( - text="Question: What's 2 + 2?", - ui=TelegramUI( - buttons=[ - Button(text="5"), - Button(text="4"), - ], - is_inline=False, - row_width=4, - ), - ), - ), - ( - TelegramMessage(text="5"), - TelegramMessage( - text="Incorrect answer, type anything to try again", - ui=RemoveKeyboard(), - ), - ), - ( - TelegramMessage(text="ok"), - TelegramMessage( - text="Question: What's 2 + 2?", - ui=TelegramUI( - buttons=[ - Button(text="5"), - Button(text="4"), - ], - is_inline=False, - row_width=4, - ), - ), - ), - ( - TelegramMessage(text="4"), - TelegramMessage(text="Success!", ui=RemoveKeyboard()), - ), - ( - TelegramMessage(text="Yay!"), - TelegramMessage( - text="Finishing test, send /restart command to restart" - ), - ), - ( - TelegramMessage(text="/start"), - TelegramMessage( - text="Question: What's 2 + 2?", - ui=TelegramUI( - buttons=[ - Button(text="5"), - Button(text="4"), - ], - is_inline=False, - row_width=4, - ), - ), - ), -) - - -# %% -pipeline = Pipeline.from_script( - script=script, - start_label=("root", "start"), - fallback_label=("root", "fallback"), - messenger_interface=interface, -) - - -def main(): - pipeline.run() - - -if __name__ == "__main__" and is_interactive_mode(): - # prevent run during doc building - main() diff --git a/tutorials/messengers/telegram/3_advanced.py b/tutorials/messengers/telegram/3_advanced.py new file mode 100644 index 000000000..0f7fb2823 --- /dev/null +++ b/tutorials/messengers/telegram/3_advanced.py @@ -0,0 +1,263 @@ +# %% [markdown] +""" +# Telegram: 3. Advanced + +The following tutorial shows several advanced cases of user-to-bot interaction. + +Here, %mddoclink(api,messengers.telegram.interface,LongpollingInterface) +class and [python-telegram-bot](https://docs.python-telegram-bot.org/) +library are used for accessing telegram API in polling mode. + +Telegram API token is required to access telegram API. +""" + +# %pip install dff[telegram] + +# %% +import os +from hashlib import sha256 +from urllib.request import urlopen + +from pydantic import HttpUrl +from telegram import InlineKeyboardButton, InlineKeyboardMarkup +from telegram.constants import ParseMode + +from dff.script import conditions as cnd +from dff.script import RESPONSE, TRANSITIONS, Message +from dff.messengers.telegram import LongpollingInterface +from dff.pipeline import Pipeline +from dff.script.core.context import Context +from dff.script.core.keywords import GLOBAL +from dff.script.core.message import ( + DataAttachment, + Document, + Image, + Location, + Sticker, +) +from dff.utils.testing.common import is_interactive_mode + + +# %% [markdown] +""" +This bot shows different special telegram messenger interface use cases, +such as: + +1. Interactive keyboard with buttons. +2. Text formatted with Markdown V2. +3. Multiple attachments of different kind handling. +4. Image with a spoiler. +5. Document with a thumbnail. +6. Attachment bytes hash. + +Check out +[this](https://docs.python-telegram-bot.org/en/latest/telegram.bot.html#telegram.Bot) +class for information about different arguments +for sending attachments, `send_...` methods. + +Last option ("Raw attachments!") button might be especially interesting, +because it shows how bot percepts different telegram attachments sent by user +in terms and datastructures of Dialog Flow Framework. +""" + +# %% + +EXAMPLE_ATTACHMENT_SOURCE = ( + "https://github.com/deeppavlov/" + + "dialog_flow_framework/wiki/example_attachments" +) + +image_url = HttpUrl(f"{EXAMPLE_ATTACHMENT_SOURCE}/deeppavlov.png") + +formatted_text = """ +Visit [this link](https://core.telegram.org/bots/api#formatting-options) +for more information about formatting options in telegram\. + +Run /start command again to restart\. +""" # noqa: W605 + +location_data = {"latitude": 59.9386, "longitude": 30.3141} + +sticker_data = { + "id": ( + "CAACAgIAAxkBAAErBZ1mKAbZvEOmhscojaIL5q0u8v" + + "gp1wACRygAAiSjCUtLa7RHZy76ezQE" + ), +} + +image_data = { + "source": image_url, + "caption": "DeepPavlov logo", + "has_spoiler": True, + "filename": "deeppavlov_logo.png", +} + +document_data = { + "source": HttpUrl(f"{EXAMPLE_ATTACHMENT_SOURCE}/deeppavlov-article.pdf"), + "caption": "DeepPavlov article", + "filename": "deeppavlov_article.pdf", + "thumbnail": urlopen(str(image_url)).read(), +} + + +# %% +async def hash_data_attachment_request(ctx: Context, pipe: Pipeline) -> Message: + attachment = [ + a for a in ctx.last_request.attachments if isinstance(a, DataAttachment) + ] + if len(attachment) > 0: + attachment_bytes = await attachment[0].get_bytes( + pipe.messenger_interface + ) + attachment_hash = sha256(attachment_bytes).hexdigest() + resp_format = ( + "Here's your previous request first attachment sha256 hash: `{}`!\n" + + "Run /start command again to restart." + ) + return Message( + resp_format.format( + attachment_hash, parse_mode=ParseMode.MARKDOWN_V2 + ) + ) + else: + return Message( + "Last request did not contain any data attachment!\n" + + "Run /start command again to restart." + ) + + +# %% +script = { + GLOBAL: { + TRANSITIONS: { + ("main_flow", "main_node"): cnd.exact_match("/start"), + } + }, + "main_flow": { + "start_node": {}, + "main_node": { + RESPONSE: Message( + attachments=[ + Location( + latitude=58.431610, + longitude=27.792887, + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + "Cute formatted text!", + callback_data="formatted", + ), + ], + [ + InlineKeyboardButton( + "Multiple attachments!", + callback_data="attachments", + ), + ], + [ + InlineKeyboardButton( + "Secret image!", callback_data="secret" + ), + ], + [ + InlineKeyboardButton( + "Document with thumbnail!", + callback_data="thumbnail", + ), + ], + [ + InlineKeyboardButton( + "First attachment bytes hash!", + callback_data="hash", + ), + ], + [ + InlineKeyboardButton( + "Restart!", callback_data="restart" + ), + InlineKeyboardButton( + "Quit!", callback_data="quit" + ), + ], + ], + ), + ), + ], + ), + TRANSITIONS: { + "formatted_node": cnd.has_callback_query("formatted"), + "attachments_node": cnd.has_callback_query("attachments"), + "secret_node": cnd.has_callback_query("secret"), + "thumbnail_node": cnd.has_callback_query("thumbnail"), + "hash_init_node": cnd.has_callback_query("hash"), + "main_node": cnd.has_callback_query("restart"), + "fallback_node": cnd.has_callback_query("quit"), + }, + }, + "formatted_node": { + RESPONSE: Message(formatted_text, parse_mode=ParseMode.MARKDOWN_V2), + }, + "attachments_node": { + RESPONSE: Message( + "Here's your message with multiple attachments " + + "(a location and a sticker)!\n" + + "Run /start command again to restart.", + attachments=[ + Location(**location_data), + Sticker(**sticker_data), + ], + ), + }, + "secret_node": { + RESPONSE: Message( + "Here's your secret image! " + + "Run /start command again to restart.", + attachments=[Image(**image_data)], + ), + }, + "thumbnail_node": { + RESPONSE: Message( + "Here's your document with tumbnail! " + + "Run /start command again to restart.", + attachments=[Document(**document_data)], + ), + }, + "hash_init_node": { + RESPONSE: Message( + "Alright! Now send me a message with data attachment " + + "(audio, video, animation, image, sticker or document)!" + ), + TRANSITIONS: {"hash_request_node": cnd.true()}, + }, + "hash_request_node": { + RESPONSE: hash_data_attachment_request, + }, + "fallback_node": { + RESPONSE: Message( + "Bot has entered unrecoverable state:" + + "/\nRun /start command again to restart." + ), + }, + }, +} + + +# %% +interface = LongpollingInterface(token=os.environ["TG_BOT_TOKEN"]) + + +# %% +pipeline = Pipeline.from_script( + script=script, + start_label=("main_flow", "start_node"), + fallback_label=("main_flow", "fallback_node"), + messenger_interface=interface, + # The interface can be passed as a pipeline argument. +) + + +if __name__ == "__main__": + if is_interactive_mode(): + # prevent run during doc building + pipeline.run() diff --git a/tutorials/messengers/telegram/3_buttons_with_callback.py b/tutorials/messengers/telegram/3_buttons_with_callback.py deleted file mode 100644 index 10d54927f..000000000 --- a/tutorials/messengers/telegram/3_buttons_with_callback.py +++ /dev/null @@ -1,181 +0,0 @@ -# %% [markdown] -""" -# Telegram: 3. Buttons with Callback - -This tutorial demonstrates, how to add an inline keyboard and utilize -inline queries. - -Here, %mddoclink(api,messengers.telegram.message,TelegramMessage) -class is used to represent telegram message, -%mddoclink(api,messengers.telegram.message,TelegramUI) and -%mddoclink(api,messengers.telegram.message,RemoveKeyboard) -classes are used for configuring additional telegram message features. - -Different %mddoclink(api,script.core.message,message) -classes are used for representing different common message features, -like Attachment, Audio, Button, Image, etc. -""" - - -# %pip install dff[telegram] - -# %% -import os - -import dff.script.conditions as cnd -from dff.script import TRANSITIONS, RESPONSE -from dff.pipeline import Pipeline -from dff.script.core.message import Button -from dff.messengers.telegram import ( - PollingTelegramInterface, - TelegramUI, - TelegramMessage, -) -from dff.messengers.telegram.message import _ClickButton -from dff.utils.testing.common import is_interactive_mode - - -# %% [markdown] -""" -If you want to send an inline keyboard to your Telegram chat, -set `is_inline` field of the `TelegramUI` instance to `True` -(note that it is inline by default, so you could also omit it). - -Pushing a button of an inline keyboard results in a callback -query being sent to your bot. The data of the query -is stored in the `callback_query` field of a user `TelegramMessage`. -""" - - -# %% -script = { - "root": { - "start": { - TRANSITIONS: { - ("general", "keyboard"): ( - lambda ctx, _: ctx.last_request.text - in ("/start", "/restart") - ), - }, - }, - "fallback": { - RESPONSE: TelegramMessage( - text="Finishing test, send /restart command to restart" - ), - TRANSITIONS: { - ("general", "keyboard"): ( - lambda ctx, _: ctx.last_request.text - in ("/start", "/restart") - ) - }, - }, - }, - "general": { - "keyboard": { - RESPONSE: TelegramMessage( - **{ - "text": "Starting test! What's 9 + 10?", - "ui": TelegramUI( - buttons=[ - Button(text="19", payload="correct"), - Button(text="21", payload="wrong"), - ], - is_inline=True, - ), - } - ), - TRANSITIONS: { - ("general", "success"): cnd.exact_match( - TelegramMessage(callback_query="correct") - ), - ("general", "fail"): cnd.exact_match( - TelegramMessage(callback_query="wrong") - ), - }, - }, - "success": { - RESPONSE: TelegramMessage(text="Success!"), - TRANSITIONS: {("root", "fallback"): cnd.true()}, - }, - "fail": { - RESPONSE: TelegramMessage( - text="Incorrect answer, type anything to try again" - ), - TRANSITIONS: {("general", "keyboard"): cnd.true()}, - }, - }, -} - -# this variable is only for testing -happy_path = ( - ( - TelegramMessage(text="/start"), - TelegramMessage( - text="Starting test! What's 9 + 10?", - ui=TelegramUI( - buttons=[ - Button(text="19", payload="correct"), - Button(text="21", payload="wrong"), - ], - ), - ), - ), - ( - TelegramMessage(callback_query=_ClickButton(button_index=1)), - TelegramMessage(text="Incorrect answer, type anything to try again"), - ), - ( - TelegramMessage(text="try again"), - TelegramMessage( - text="Starting test! What's 9 + 10?", - ui=TelegramUI( - buttons=[ - Button(text="19", payload="correct"), - Button(text="21", payload="wrong"), - ], - ), - ), - ), - ( - TelegramMessage(callback_query=_ClickButton(button_index=0)), - TelegramMessage(text="Success!"), - ), - ( - TelegramMessage(text="Yay!"), - TelegramMessage( - text="Finishing test, send /restart command to restart" - ), - ), - ( - TelegramMessage(text="/restart"), - TelegramMessage( - text="Starting test! What's 9 + 10?", - ui=TelegramUI( - buttons=[ - Button(text="19", payload="correct"), - Button(text="21", payload="wrong"), - ], - ), - ), - ), -) - -interface = PollingTelegramInterface(token=os.environ["TG_BOT_TOKEN"]) - - -# %% -pipeline = Pipeline.from_script( - script=script, - start_label=("root", "start"), - fallback_label=("root", "fallback"), - messenger_interface=interface, -) - - -def main(): - pipeline.run() - - -if __name__ == "__main__" and is_interactive_mode(): - # prevent run during doc building - main() diff --git a/tutorials/messengers/telegram/4_conditions.py b/tutorials/messengers/telegram/4_conditions.py deleted file mode 100644 index d856e3056..000000000 --- a/tutorials/messengers/telegram/4_conditions.py +++ /dev/null @@ -1,147 +0,0 @@ -# %% [markdown] -""" -# Telegram: 4. Conditions - -This tutorial shows how to process Telegram updates in your script -and reuse handler triggers from the `pytelegrambotapi` library. - -Here, %mddoclink(api,messengers.telegram.messenger,telegram_condition) -function is used for graph navigation according to Telegram events. -""" - - -# %pip install dff[telegram] - -# %% -import os - -from dff.script import TRANSITIONS, RESPONSE - -from dff.messengers.telegram import ( - PollingTelegramInterface, - telegram_condition, - UpdateType, -) -from dff.pipeline import Pipeline -from dff.messengers.telegram import TelegramMessage -from dff.utils.testing.common import is_interactive_mode - - -# %% [markdown] -""" -In our Telegram module, we adopted the system of filters -available in the `pytelegrambotapi` library. - -You can use `telegram_condition` to filter -text messages from telegram in various ways. - -- Setting the `update_type` will allow filtering by update type: - if you want the condition to trigger only on updates of the type - `edited_message`, set it to `UpdateType.EDITED_MESSAGE`. - The field defaults to `message`. -- Setting the `command` argument will cause - the telegram_condition to only react to listed commands. -- `func` argument on the other hand allows you to define arbitrary conditions. -- `regexp` creates a regular expression filter, etc. - -Note: -It is possible to use `cnd.exact_match` as a condition -(as seen in previous tutorials). However, the functionality -of that approach is lacking: - -At this moment only two fields of `Message` are set during update processing: - -- `text` stores the `text` field of `message` updates -- `callback_query` stores the `data` field of `callback_query` updates - -For more information see tutorial `3_buttons_with_callback.py`. -""" - - -# %% -script = { - "greeting_flow": { - "start_node": { - TRANSITIONS: { - "node1": telegram_condition(commands=["start", "restart"]) - }, - }, - "node1": { - RESPONSE: TelegramMessage(text="Hi, how are you?"), - TRANSITIONS: { - "node2": telegram_condition( - update_type=UpdateType.MESSAGE, regexp="fine" - ) - }, - # this is the same as - # TRANSITIONS: {"node2": telegram_condition(regexp="fine")}, - }, - "node2": { - RESPONSE: TelegramMessage( - text="Good. What do you want to talk about?" - ), - TRANSITIONS: { - "node3": telegram_condition( - func=lambda msg: "music" in msg.text - ) - }, - }, - "node3": { - RESPONSE: TelegramMessage( - text="Sorry, I can not talk about music now." - ), - TRANSITIONS: { - "node4": telegram_condition(update_type=UpdateType.ALL) - }, - # This condition is true for any type of update - }, - "node4": { - RESPONSE: TelegramMessage(text="bye"), - TRANSITIONS: {"node1": telegram_condition()}, - # This condition is true if the last update is of type `message` - }, - "fallback_node": { - RESPONSE: TelegramMessage(text="Ooops"), - TRANSITIONS: { - "node1": telegram_condition(commands=["start", "restart"]) - }, - }, - } -} - -# this variable is only for testing -happy_path = ( - (TelegramMessage(text="/start"), TelegramMessage(text="Hi, how are you?")), - ( - TelegramMessage(text="I'm fine"), - TelegramMessage(text="Good. What do you want to talk about?"), - ), - ( - TelegramMessage(text="About music"), - TelegramMessage(text="Sorry, I can not talk about music now."), - ), - (TelegramMessage(text="ok"), TelegramMessage(text="bye")), - (TelegramMessage(text="bye"), TelegramMessage(text="Hi, how are you?")), -) - - -# %% -interface = PollingTelegramInterface(token=os.environ["TG_BOT_TOKEN"]) - - -# %% -pipeline = Pipeline.from_script( - script=script, - start_label=("greeting_flow", "start_node"), - fallback_label=("greeting_flow", "fallback_node"), - messenger_interface=interface, -) - - -def main(): - pipeline.run() - - -if __name__ == "__main__" and is_interactive_mode(): - # prevent run during doc building - main() diff --git a/tutorials/messengers/telegram/5_conditions_with_media.py b/tutorials/messengers/telegram/5_conditions_with_media.py deleted file mode 100644 index 144ef9c32..000000000 --- a/tutorials/messengers/telegram/5_conditions_with_media.py +++ /dev/null @@ -1,204 +0,0 @@ -# %% [markdown] -""" -# Telegram: 5. Conditions with Media - -This tutorial shows how to use media-related logic in your script. - -Here, %mddoclink(api,messengers.telegram.messenger,telegram_condition) -function is used for graph navigation according to Telegram events. - -Different %mddoclink(api,script.core.message,message) -classes are used for representing different common message features, -like Attachment, Audio, Button, Image, etc. -""" - - -# %pip install dff[telegram] - -# %% -import os - -from telebot.types import Message - -import dff.script.conditions as cnd -from dff.script import Context, TRANSITIONS, RESPONSE -from dff.script.core.message import Image, Attachments -from dff.messengers.telegram import ( - PollingTelegramInterface, - TelegramMessage, - telegram_condition, -) -from dff.pipeline import Pipeline -from dff.utils.testing.common import is_interactive_mode - - -# %% - -picture_url = "https://avatars.githubusercontent.com/u/29918795?s=200&v=4" - - -# %% [markdown] -""" -To filter user messages depending on whether or not media files were sent, -you can use the `content_types` parameter of the `telegram_condition`. -""" - - -# %% -interface = PollingTelegramInterface(token=os.environ["TG_BOT_TOKEN"]) - - -# %% -script = { - "root": { - "start": { - TRANSITIONS: { - ("pics", "ask_picture"): telegram_condition( - commands=["start", "restart"] - ) - }, - }, - "fallback": { - RESPONSE: TelegramMessage( - text="Finishing test, send /restart command to restart" - ), - TRANSITIONS: { - ("pics", "ask_picture"): telegram_condition( - commands=["start", "restart"] - ) - }, - }, - }, - "pics": { - "ask_picture": { - RESPONSE: TelegramMessage(text="Send me a picture"), - TRANSITIONS: { - ("pics", "send_one"): cnd.any( - [ - # Telegram can put photos - # both in 'photo' and 'document' fields. - # We should consider both cases - # when we check the message for media. - telegram_condition(content_types=["photo"]), - telegram_condition( - func=lambda message: ( - # check attachments in message properties - message.document - and message.document.mime_type == "image/jpeg" - ), - content_types=["document"], - ), - ] - ), - ("pics", "send_many"): telegram_condition( - content_types=["text"] - ), - ("pics", "ask_picture"): cnd.true(), - }, - }, - "send_one": { - # An HTTP path or a path to a local file can be used here. - RESPONSE: TelegramMessage( - text="Here's my picture!", - attachments=Attachments(files=[Image(source=picture_url)]), - ), - TRANSITIONS: {("root", "fallback"): cnd.true()}, - }, - "send_many": { - RESPONSE: TelegramMessage( - text="Look at my pictures!", - # An HTTP path or a path to a local file can be used here. - attachments=Attachments(files=[Image(source=picture_url)] * 2), - ), - TRANSITIONS: {("root", "fallback"): cnd.true()}, - }, - }, -} - - -# testing -happy_path = ( - ( - TelegramMessage(text="/start"), - TelegramMessage(text="Send me a picture"), - ), - ( - TelegramMessage( - attachments=Attachments(files=[Image(source=picture_url)]) - ), - TelegramMessage( - text="Here's my picture!", - attachments=Attachments(files=[Image(source=picture_url)]), - ), - ), - ( - TelegramMessage(text="ok"), - TelegramMessage( - text="Finishing test, send /restart command to restart" - ), - ), - ( - TelegramMessage(text="/restart"), - TelegramMessage(text="Send me a picture"), - ), - ( - TelegramMessage(text="No"), - TelegramMessage( - text="Look at my pictures!", - attachments=Attachments(files=[Image(source=picture_url)] * 2), - ), - ), - ( - TelegramMessage(text="ok"), - TelegramMessage( - text="Finishing test, send /restart command to restart" - ), - ), - ( - TelegramMessage(text="/restart"), - TelegramMessage(text="Send me a picture"), - ), -) - - -# %% -def extract_data(ctx: Context, _: Pipeline): # A function to extract data with - message = ctx.last_request - if message is None: - return - update = getattr(message, "update", None) - if update is None: - return - if not isinstance(update, Message): - return - if ( - # check attachments in update properties - not update.photo - and not (update.document and update.document.mime_type == "image/jpeg") - ): - return - photo = update.document or update.photo[-1] - file = interface.messenger.get_file(photo.file_id) - result = interface.messenger.download_file(file.file_path) - with open("photo.jpg", "wb+") as new_file: - new_file.write(result) - return - - -# %% -pipeline = Pipeline.from_script( - script=script, - start_label=("root", "start"), - fallback_label=("root", "fallback"), - messenger_interface=interface, - pre_services=[extract_data], -) - - -def main(): - pipeline.run() - - -if __name__ == "__main__" and is_interactive_mode(): - # prevent run during doc building - main() diff --git a/tutorials/messengers/telegram/6_conditions_extras.py b/tutorials/messengers/telegram/6_conditions_extras.py deleted file mode 100644 index c154a2ed7..000000000 --- a/tutorials/messengers/telegram/6_conditions_extras.py +++ /dev/null @@ -1,126 +0,0 @@ -# %% [markdown] -""" -# Telegram: 6. Conditions Extras - -This tutorial shows how to use additional update filters -inherited from the `pytelegrambotapi` library. - -%mddoclink(api,messengers.telegram.messenger,telegram_condition) -function and different types of -%mddoclink(api,messengers.telegram.messenger,UpdateType) -are used for telegram message type checking. -""" - - -# %pip install dff[telegram] - -# %% -import os - -from dff.script import TRANSITIONS, RESPONSE, GLOBAL -import dff.script.conditions as cnd -from dff.messengers.telegram import ( - PollingTelegramInterface, - TelegramMessage, - telegram_condition, - UpdateType, -) -from dff.pipeline import Pipeline -from dff.utils.testing.common import is_interactive_mode - - -# %% [markdown] -""" -In our Telegram module, we adopted the system of filters -available in the `pytelegrambotapi` library. - -Aside from `MESSAGE` you can use -other triggers to interact with the api. In this tutorial, we use -handlers of other type as global conditions that trigger a response -from the bot. - -Here, we use the following triggers: - -* `chat_join_request`: join request is sent to the chat where the bot is. -* `my_chat_member`: triggered when the bot is invited to a chat. -* `inline_query`: triggered when an inline query is being sent to the bot. - -The other available conditions are: - -* `channel_post`: new post is created in a channel the bot is subscribed to; -* `edited_channel_post`: post is edited in a channel the bot is subscribed to; -* `shipping_query`: shipping query is sent by the user; -* `pre_checkout_query`: order confirmation is sent by the user; -* `poll`: poll is sent to the chat; -* `poll_answer`: users answered the poll sent by the bot. - -You can read more on those in the Telegram documentation -or in the docs for the `telebot` library. -""" - - -# %% -script = { - GLOBAL: { - TRANSITIONS: { - ("greeting_flow", "node1"): cnd.any( - [ - # say hi when invited to a chat - telegram_condition( - update_type=UpdateType.CHAT_JOIN_REQUEST, - func=lambda x: True, - ), - # say hi when someone enters the chat - telegram_condition( - update_type=UpdateType.MY_CHAT_MEMBER, - func=lambda x: True, - ), - ] - ), - # send a message when inline query is received - ("greeting_flow", "node2"): telegram_condition( - update_type=UpdateType.INLINE_QUERY, - ), - }, - }, - "greeting_flow": { - "start_node": { - TRANSITIONS: { - "node1": telegram_condition(commands=["start", "restart"]) - }, - }, - "node1": { - RESPONSE: TelegramMessage(text="Hi"), - TRANSITIONS: {"start_node": cnd.true()}, - }, - "node2": { - RESPONSE: TelegramMessage(text="Inline query received."), - TRANSITIONS: {"start_node": cnd.true()}, - }, - "fallback_node": { - RESPONSE: TelegramMessage(text="Ooops"), - }, - }, -} - - -# %% -interface = PollingTelegramInterface(token=os.environ["TG_BOT_TOKEN"]) - - -# %% -pipeline = Pipeline.from_script( - script=script, - start_label=("greeting_flow", "start_node"), - fallback_label=("greeting_flow", "fallback_node"), - messenger_interface=interface, -) - - -def main(): - pipeline.run() - - -if __name__ == "__main__" and is_interactive_mode(): - # prevent run during doc building - main() diff --git a/tutorials/messengers/telegram/7_polling_setup.py b/tutorials/messengers/telegram/7_polling_setup.py deleted file mode 100644 index d070e4728..000000000 --- a/tutorials/messengers/telegram/7_polling_setup.py +++ /dev/null @@ -1,64 +0,0 @@ -# %% [markdown] -""" -# Telegram: 7. Polling Setup - -The following tutorial shows how to configure `PollingTelegramInterface`. - -See %mddoclink(api,messengers.telegram.interface,PollingTelegramInterface) -for more information. -""" - -# %pip install dff[telegram] - -# %% -import os - -from dff.messengers.telegram.interface import PollingTelegramInterface -from dff.pipeline import Pipeline - -from dff.utils.testing.common import is_interactive_mode -from dff.utils.testing.toy_script import TOY_SCRIPT_ARGS, HAPPY_PATH -from telebot.util import update_types - - -# %% [markdown] -""" -`PollingTelegramInterface` can be configured with the same parameters -that are used in the `pytelegrambotapi` library, specifically: - -* interval - time between calls to the API. -* allowed updates - updates that should be fetched. -* timeout - general timeout. -* long polling timeout - timeout for polling. -""" - - -# %% -interface = PollingTelegramInterface( - token=os.environ["TG_BOT_TOKEN"], - interval=2, - allowed_updates=update_types, - timeout=30, - long_polling_timeout=30, -) - - -# testing -happy_path = HAPPY_PATH - - -# %% -pipeline = Pipeline.from_script( - *TOY_SCRIPT_ARGS, - messenger_interface=interface, - # The interface can be passed as a pipeline argument -) - - -def main(): - pipeline.run() - - -if __name__ == "__main__" and is_interactive_mode(): - # prevent run during doc building - main() diff --git a/tutorials/messengers/telegram/8_webhook_setup.py b/tutorials/messengers/telegram/8_webhook_setup.py deleted file mode 100644 index a7f4fd68f..000000000 --- a/tutorials/messengers/telegram/8_webhook_setup.py +++ /dev/null @@ -1,61 +0,0 @@ -# %% [markdown] -""" -# Telegram: 8. Webhook Setup - -The following tutorial shows how to use `CallbackTelegramInterface` -that makes your bot accessible through a public webhook. - -See %mddoclink(api,messengers.common.interface,CallbackMessengerInterface) -for more information. -""" - -# %pip install dff[telegram] flask - -# %% -import os - -from dff.messengers.telegram import ( - CallbackTelegramInterface, -) -from dff.pipeline import Pipeline -from dff.utils.testing.toy_script import TOY_SCRIPT_ARGS, HAPPY_PATH -from dff.utils.testing.common import is_interactive_mode - - -# %% [markdown] -""" -To set up a webhook, you need a messenger and a web application instance. -This class can be configured with the following parameters: - -* app - Flask application. You can pass an application with an arbitrary - number of pre-configured routes. Created automatically if not set. -* host - application host. -* port - application port. -* endpoint - bot access endpoint. -* full_uri - full public address of the endpoint. HTTPS should be enabled - for successful configuration. -""" - - -# %% -interface = CallbackTelegramInterface(token=os.environ["TG_BOT_TOKEN"]) - - -# %% -pipeline = Pipeline.from_script( - *TOY_SCRIPT_ARGS, - messenger_interface=interface, - # The interface can be passed as a pipeline argument -) - -# testing -happy_path = HAPPY_PATH - - -def main(): - pipeline.run() - - -if __name__ == "__main__" and is_interactive_mode(): - # prevent run during doc building - main() diff --git a/tutorials/pipeline/2_pre_and_post_processors.py b/tutorials/pipeline/2_pre_and_post_processors.py index bc8fe5625..7037d63da 100644 --- a/tutorials/pipeline/2_pre_and_post_processors.py +++ b/tutorials/pipeline/2_pre_and_post_processors.py @@ -14,7 +14,7 @@ # %% import logging -from dff.messengers.common import CLIMessengerInterface +from dff.messengers.console import CLIMessengerInterface from dff.script import Context, Message from dff.pipeline import Pipeline diff --git a/tutorials/pipeline/3_pipeline_dict_with_services_full.py b/tutorials/pipeline/3_pipeline_dict_with_services_full.py index 0503d12a2..ef00dff5c 100644 --- a/tutorials/pipeline/3_pipeline_dict_with_services_full.py +++ b/tutorials/pipeline/3_pipeline_dict_with_services_full.py @@ -19,7 +19,7 @@ import urllib.request from dff.script import Context -from dff.messengers.common import CLIMessengerInterface +from dff.messengers.console import CLIMessengerInterface from dff.pipeline import Service, Pipeline, ServiceRuntimeInfo, ACTOR from dff.utils.testing.common import ( check_happy_path, diff --git a/tutorials/script/responses/2_buttons.py b/tutorials/script/responses/2_buttons.py deleted file mode 100644 index faa9f60bc..000000000 --- a/tutorials/script/responses/2_buttons.py +++ /dev/null @@ -1,259 +0,0 @@ -# %% [markdown] -""" -# Responses: 2. Buttons - -In this tutorial %mddoclink(api,script.core.message,Button) -class is demonstrated. -Buttons are one of %mddoclink(api,script.core.message,Message) fields. -They can be attached to any message but will only work if the chosen -[messenger interface](%doclink(api,index_messenger_interfaces)) supports them. -""" - - -# %pip install dff - -# %% -import dff.script.conditions as cnd -import dff.script.labels as lbl -from dff.script import Context, TRANSITIONS, RESPONSE - -from dff.script.core.message import Button, Keyboard, Message -from dff.pipeline import Pipeline -from dff.utils.testing import ( - check_happy_path, - is_interactive_mode, - run_interactive_mode, -) - - -# %% -def check_button_payload(value: str): - def payload_check_inner(ctx: Context, _: Pipeline): - if ctx.last_request.misc is not None: - return ctx.last_request.misc.get("payload") == value - else: - return False - - return payload_check_inner - - -# %% -toy_script = { - "root": { - "start": { - RESPONSE: Message(""), - TRANSITIONS: { - ("general", "question_1"): cnd.true(), - }, - }, - "fallback": {RESPONSE: Message("Finishing test")}, - }, - "general": { - "question_1": { - RESPONSE: Message( - **{ - "text": "Starting test! What's 2 + 2?" - " (type in the index of the correct option)", - "misc": { - "ui": Keyboard( - buttons=[ - Button(text="5", payload="5"), - Button(text="4", payload="4"), - ] - ), - }, - } - ), - TRANSITIONS: { - lbl.forward(): check_button_payload("4"), - ("general", "question_1"): check_button_payload("5"), - }, - }, - "question_2": { - RESPONSE: Message( - **{ - "text": "Next question: what's 6 * 8?" - " (type in the index of the correct option)", - "misc": { - "ui": Keyboard( - buttons=[ - Button(text="38", payload="38"), - Button(text="48", payload="48"), - ] - ), - }, - } - ), - TRANSITIONS: { - lbl.forward(): check_button_payload("48"), - ("general", "question_2"): check_button_payload("38"), - }, - }, - "question_3": { - RESPONSE: Message( - **{ - "text": "What's 114 + 115? " - "(type in the index of the correct option)", - "misc": { - "ui": Keyboard( - buttons=[ - Button(text="229", payload="229"), - Button(text="283", payload="283"), - ] - ), - }, - } - ), - TRANSITIONS: { - lbl.forward(): check_button_payload("229"), - ("general", "question_3"): check_button_payload("283"), - }, - }, - "success": { - RESPONSE: Message("Success!"), - TRANSITIONS: {("root", "fallback"): cnd.true()}, - }, - }, -} - -happy_path = ( - ( - Message("Hi"), - Message( - **{ - "text": "Starting test! What's 2 + 2? " - "(type in the index of the correct option)", - "misc": { - "ui": Keyboard( - buttons=[ - Button(text="5", payload="5"), - Button(text="4", payload="4"), - ] - ) - }, - } - ), - ), - ( - Message("0"), - Message( - **{ - "text": "Starting test! What's 2 + 2? " - "(type in the index of the correct option)", - "misc": { - "ui": Keyboard( - buttons=[ - Button(text="5", payload="5"), - Button(text="4", payload="4"), - ] - ), - }, - } - ), - ), - ( - Message("1"), - Message( - **{ - "text": "Next question: what's 6 * 8? " - "(type in the index of the correct option)", - "misc": { - "ui": Keyboard( - buttons=[ - Button(text="38", payload="38"), - Button(text="48", payload="48"), - ] - ), - }, - } - ), - ), - ( - Message("0"), - Message( - **{ - "text": "Next question: what's 6 * 8? " - "(type in the index of the correct option)", - "misc": { - "ui": Keyboard( - buttons=[ - Button(text="38", payload="38"), - Button(text="48", payload="48"), - ] - ), - }, - } - ), - ), - ( - Message("1"), - Message( - **{ - "text": "What's 114 + 115? " - "(type in the index of the correct option)", - "misc": { - "ui": Keyboard( - buttons=[ - Button(text="229", payload="229"), - Button(text="283", payload="283"), - ] - ), - }, - } - ), - ), - ( - Message("1"), - Message( - **{ - "text": "What's 114 + 115? " - "(type in the index of the correct option)", - "misc": { - "ui": Keyboard( - buttons=[ - Button(text="229", payload="229"), - Button(text="283", payload="283"), - ] - ), - }, - } - ), - ), - (Message("0"), Message("Success!")), - (Message("ok"), Message("Finishing test")), -) - - -def process_request(ctx: Context): - ui = ( - ctx.last_response - and ctx.last_response.misc - and ctx.last_response.misc.get("ui") - ) - if ui and ui.buttons: - try: - chosen_button = ui.buttons[int(ctx.last_request.text)] - except (IndexError, ValueError): - raise ValueError( - "Type in the index of the correct option " - "to choose from the buttons." - ) - ctx.last_request = Message(misc={"payload": chosen_button.payload}) - - -# %% -pipeline = Pipeline.from_script( - toy_script, - start_label=("root", "start"), - fallback_label=("root", "fallback"), - pre_services=[process_request], -) - -if __name__ == "__main__": - check_happy_path( - pipeline, - happy_path, - ) # For response object with `happy_path` string comparing, - # a special `generics_comparer` comparator is used - if is_interactive_mode(): - run_interactive_mode(pipeline) diff --git a/tutorials/script/responses/3_media.py b/tutorials/script/responses/2_media.py similarity index 88% rename from tutorials/script/responses/3_media.py rename to tutorials/script/responses/2_media.py index 412363c14..0179a35ef 100644 --- a/tutorials/script/responses/3_media.py +++ b/tutorials/script/responses/2_media.py @@ -1,8 +1,8 @@ # %% [markdown] """ -# Responses: 3. Media +# Responses: 2. Media -Here, %mddoclink(api,script.core.message,Attachments) class is shown. +Here, %mddoclink(api,script.core.message,Attachment) class is shown. Attachments can be used for attaching different media elements (such as %mddoclink(api,script.core.message,Image), %mddoclink(api,script.core.message,Document) @@ -18,7 +18,7 @@ from dff.script import RESPONSE, TRANSITIONS from dff.script.conditions import std_conditions as cnd -from dff.script.core.message import Attachments, Image, Message +from dff.script.core.message import Image, Message from dff.pipeline import Pipeline from dff.utils.testing import ( @@ -57,14 +57,14 @@ "send_one": { RESPONSE: Message( text="here's my picture!", - attachments=Attachments(files=[Image(source=img_url)]), + attachments=[Image(source=img_url)], ), TRANSITIONS: {("root", "fallback"): cnd.true()}, }, "send_many": { RESPONSE: Message( text="Look at my pictures", - attachments=Attachments(files=[Image(source=img_url)] * 10), + attachments=[Image(source=img_url)], ), TRANSITIONS: {("root", "fallback"): cnd.true()}, }, @@ -93,7 +93,7 @@ Message(img_url), Message( text="here's my picture!", - attachments=Attachments(files=[Image(source=img_url)]), + attachments=[Image(source=img_url)], ), ), ( @@ -105,7 +105,7 @@ Message(f"{img_url} repeat 10 times"), Message( text="Look at my pictures", - attachments=Attachments(files=[Image(source=img_url)] * 10), + attachments=[Image(source=img_url)], ), ), ( diff --git a/tutorials/script/responses/4_multi_message.py b/tutorials/script/responses/3_multi_message.py similarity index 99% rename from tutorials/script/responses/4_multi_message.py rename to tutorials/script/responses/3_multi_message.py index bfed3313b..7736b1980 100644 --- a/tutorials/script/responses/4_multi_message.py +++ b/tutorials/script/responses/3_multi_message.py @@ -1,6 +1,6 @@ # %% [markdown] """ -# Responses: 4. Multi Message +# Responses: 3. Multi Message This tutorial shows how to store several messages inside a single one. This might be useful if you want DFF Pipeline to send `response` candidates diff --git a/utils/test_data_generators/__init__.py b/utils/test_data_generators/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/utils/test_data_generators/telegram_tutorial_data.py b/utils/test_data_generators/telegram_tutorial_data.py new file mode 100644 index 000000000..c1767f73a --- /dev/null +++ b/utils/test_data_generators/telegram_tutorial_data.py @@ -0,0 +1,67 @@ +""" +Telegram tutorial test data +--------------------------- + +Generate telegram tutorial test data. + +.. code:: bash + + python utils/test_data_generators/telegram_tutorial_data.py +""" + +from importlib import import_module +import importlib.machinery +from json import loads, dump +from typing import List +from pathlib import Path +import os +from contextlib import contextmanager + +from dff.script import Message + + +ROOT = Path(__file__).parent.parent.parent +TG_TUTORIALS = ROOT / "tutorials" / "telegram" +TG_TESTS = ROOT / "tests" / "messengers" / "telegram" +HAPPY_PATH_FILE = TG_TESTS / "test_happy_paths.json" + + +test_utils = importlib.machinery.SourceFileLoader(fullname="utils", path=str(TG_TESTS / "utils.py")).load_module() + +MockApplication = test_utils.MockApplication +cast_dict_to_happy_step = test_utils.cast_dict_to_happy_step + + +if __name__ == "__main__": + happy_path_data = loads(HAPPY_PATH_FILE.read_text()) + + os.environ["TG_BOT_TOKEN"] = "token" + + for tutorial in ["1_basic", "2_attachments", "3_advanced"]: + happy_path_update = [] + + @contextmanager + def _check_context_and_trace_patch(self, last_request: Message, last_response: Message, last_trace: List[str]): + self.bot.latest_trace = list() + self.latest_ctx = None + yield + happy_path_update.append( + { + "received_message": self.latest_ctx.last_request.model_dump(mode="json"), + "response_message": self.latest_ctx.last_response.model_dump(mode="json"), + "response_functions": self.bot.latest_trace, + } + ) + + MockApplication._check_context_and_trace = _check_context_and_trace_patch + + happy_path_steps = cast_dict_to_happy_step(happy_path_data[tutorial], update_only=True) + module = import_module(f"tutorials.messengers.telegram.{tutorial}") + module.interface.application = MockApplication.create(module.interface, happy_path_steps) + module.pipeline.run() + + for value, update in zip(happy_path_data[tutorial], happy_path_update): + value.update(update) + + with open(HAPPY_PATH_FILE, "w", encoding="utf-8") as fp: + dump(happy_path_data, fp, indent=4) From a2fe683568fbc445489bb5040d4e39b3e1d52755 Mon Sep 17 00:00:00 2001 From: Roman Zlobin Date: Wed, 3 Jul 2024 01:48:54 +0300 Subject: [PATCH 23/31] Merge slots (#36) Add slots feature --------- Co-authored-by: Denis Kuznetsov Co-authored-by: ruthenian8 Co-authored-by: pseusys --- compose.yml | 12 + dff/pipeline/pipeline/actor.py | 2 +- dff/pipeline/pipeline/pipeline.py | 10 + dff/pipeline/service/extra.py | 3 +- dff/pipeline/service/service.py | 3 +- dff/pipeline/service/utils.py | 19 +- dff/script/core/context.py | 3 + dff/script/core/normalization.py | 4 +- dff/slots/__init__.py | 7 + dff/slots/conditions.py | 32 ++ dff/slots/processing.py | 98 +++++ dff/slots/response.py | 34 ++ dff/slots/slots.py | 418 ++++++++++++++++++++ dff/utils/devel/__init__.py | 1 + dff/utils/devel/async_helpers.py | 24 ++ dff/utils/devel/json_serialization.py | 2 + docs/source/conf.py | 2 + docs/source/user_guides.rst | 9 + docs/source/user_guides/slot_extraction.rst | 176 +++++++++ poetry.lock | 21 +- pyproject.toml | 2 + tests/slots/__init__.py | 0 tests/slots/conftest.py | 28 ++ tests/slots/test_slot_manager.py | 262 ++++++++++++ tests/slots/test_slot_types.py | 161 ++++++++ tests/slots/test_tutorials.py | 20 + tests/utils/test_serialization.py | 27 +- tutorials/slots/1_basic_example.py | 236 +++++++++++ 28 files changed, 1586 insertions(+), 30 deletions(-) create mode 100644 dff/slots/__init__.py create mode 100644 dff/slots/conditions.py create mode 100644 dff/slots/processing.py create mode 100644 dff/slots/response.py create mode 100644 dff/slots/slots.py create mode 100644 dff/utils/devel/async_helpers.py create mode 100644 docs/source/user_guides/slot_extraction.rst create mode 100644 tests/slots/__init__.py create mode 100644 tests/slots/conftest.py create mode 100644 tests/slots/test_slot_manager.py create mode 100644 tests/slots/test_slot_types.py create mode 100644 tests/slots/test_tutorials.py create mode 100644 tutorials/slots/1_basic_example.py diff --git a/compose.yml b/compose.yml index 273e49bb7..dc477fd78 100644 --- a/compose.yml +++ b/compose.yml @@ -91,6 +91,18 @@ services: retries: 5 start_period: 30s + ner: + image: deeppavlov/deeppavlov:latest + profiles: + - extras + environment: + - CONFIG=ner_conll2003_bert + restart: unless-stopped + ports: + - 5000:5000 + volumes: + - ~/.deeppavlov:/root/.deeppavlov/ + - ~/.cache:/root/.cache/ dashboard: env_file: [.env_file] build: diff --git a/dff/pipeline/pipeline/actor.py b/dff/pipeline/pipeline/actor.py index c4f49a082..33a3d2daa 100644 --- a/dff/pipeline/pipeline/actor.py +++ b/dff/pipeline/pipeline/actor.py @@ -37,7 +37,7 @@ from dff.script.core.script import Script, Node from dff.script.core.normalization import normalize_label, normalize_response from dff.script.core.keywords import GLOBAL, LOCAL -from dff.pipeline.service.utils import wrap_sync_function_in_async +from dff.utils.devel.async_helpers import wrap_sync_function_in_async logger = logging.getLogger(__name__) diff --git a/dff/pipeline/pipeline/pipeline.py b/dff/pipeline/pipeline/pipeline.py index a96b7b814..b036c2dc0 100644 --- a/dff/pipeline/pipeline/pipeline.py +++ b/dff/pipeline/pipeline/pipeline.py @@ -25,6 +25,7 @@ from dff.messengers.console import CLIMessengerInterface from dff.messengers.common import MessengerInterface +from dff.slots.slots import GroupSlot from ..service.group import ServiceGroup from ..types import ( ServiceBuilder, @@ -56,6 +57,7 @@ class Pipeline: :param label_priority: Default priority value for all actor :py:const:`labels ` where there is no priority. Defaults to `1.0`. :param condition_handler: Handler that processes a call of actor condition functions. Defaults to `None`. + :param slots: Slots configuration. :param handlers: This variable is responsible for the usage of external handlers on the certain stages of work of :py:class:`~dff.script.Actor`. @@ -89,6 +91,7 @@ def __init__( fallback_label: Optional[NodeLabel2Type] = None, label_priority: float = 1.0, condition_handler: Optional[Callable] = None, + slots: Optional[Union[GroupSlot, Dict]] = None, handlers: Optional[Dict[ActorStage, List[Callable]]] = None, messenger_interface: Optional[MessengerInterface] = None, context_storage: Optional[Union[DBContextStorage, Dict]] = None, @@ -101,6 +104,7 @@ def __init__( self.actor: Actor = None self.messenger_interface = CLIMessengerInterface() if messenger_interface is None else messenger_interface self.context_storage = {} if context_storage is None else context_storage + self.slots = GroupSlot.model_validate(slots) if slots is not None else None self._services_pipeline = ServiceGroup( components, before_handler=before_handler, @@ -208,6 +212,7 @@ def from_script( fallback_label: Optional[NodeLabel2Type] = None, label_priority: float = 1.0, condition_handler: Optional[Callable] = None, + slots: Optional[Union[GroupSlot, Dict]] = None, parallelize_processing: bool = False, handlers: Optional[Dict[ActorStage, List[Callable]]] = None, context_storage: Optional[Union[DBContextStorage, Dict]] = None, @@ -229,6 +234,7 @@ def from_script( :param label_priority: Default priority value for all actor :py:const:`labels ` where there is no priority. Defaults to `1.0`. :param condition_handler: Handler that processes a call of actor condition functions. Defaults to `None`. + :param slots: Slots configuration. :param parallelize_processing: This flag determines whether or not the functions defined in the ``PRE_RESPONSE_PROCESSING`` and ``PRE_TRANSITIONS_PROCESSING`` sections of the script should be parallelized over respective groups. @@ -257,6 +263,7 @@ def from_script( fallback_label=fallback_label, label_priority=label_priority, condition_handler=condition_handler, + slots=slots, parallelize_processing=parallelize_processing, handlers=handlers, messenger_interface=messenger_interface, @@ -320,6 +327,9 @@ async def _run_pipeline( if update_ctx_misc is not None: ctx.misc.update(update_ctx_misc) + if self.slots is not None: + ctx.framework_data.slot_manager.set_root_slot(self.slots) + ctx.add_request(request) result = await self._services_pipeline(ctx, self) diff --git a/dff/pipeline/service/extra.py b/dff/pipeline/service/extra.py index caebbd58c..f9194ec4f 100644 --- a/dff/pipeline/service/extra.py +++ b/dff/pipeline/service/extra.py @@ -14,7 +14,8 @@ from dff.script import Context -from .utils import collect_defined_constructor_parameters_to_dict, _get_attrs_with_updates, wrap_sync_function_in_async +from .utils import collect_defined_constructor_parameters_to_dict, _get_attrs_with_updates +from dff.utils.devel.async_helpers import wrap_sync_function_in_async from ..types import ( ServiceRuntimeInfo, ExtraHandlerType, diff --git a/dff/pipeline/service/service.py b/dff/pipeline/service/service.py index c0834fee4..9eae76468 100644 --- a/dff/pipeline/service/service.py +++ b/dff/pipeline/service/service.py @@ -17,7 +17,8 @@ from dff.script import Context -from .utils import wrap_sync_function_in_async, collect_defined_constructor_parameters_to_dict, _get_attrs_with_updates +from .utils import collect_defined_constructor_parameters_to_dict, _get_attrs_with_updates +from dff.utils.devel.async_helpers import wrap_sync_function_in_async from ..types import ( ServiceBuilder, StartConditionCheckerFunction, diff --git a/dff/pipeline/service/utils.py b/dff/pipeline/service/utils.py index b92b952e9..06d168ad2 100644 --- a/dff/pipeline/service/utils.py +++ b/dff/pipeline/service/utils.py @@ -5,24 +5,7 @@ These functions provide a variety of utility functionality. """ -import asyncio -from typing import Callable, Any, Optional, Tuple, Mapping - - -async def wrap_sync_function_in_async(func: Callable, *args, **kwargs) -> Any: - """ - Utility function, that wraps both functions and coroutines in coroutines. - Invokes `func` if it is just a callable and awaits, if this is a coroutine. - - :param func: Callable to wrap. - :param \\*args: Function args. - :param \\**kwargs: Function kwargs. - :return: What function returns. - """ - if asyncio.iscoroutinefunction(func): - return await func(*args, **kwargs) - else: - return func(*args, **kwargs) +from typing import Any, Optional, Tuple, Mapping def _get_attrs_with_updates( diff --git a/dff/script/core/context.py b/dff/script/core/context.py index 03c2cae5e..c84e5eee4 100644 --- a/dff/script/core/context.py +++ b/dff/script/core/context.py @@ -27,6 +27,7 @@ from dff.script.core.message import Message from dff.script.core.types import NodeLabel2Type from dff.pipeline.types import ComponentExecutionState +from dff.slots.slots import SlotManager if TYPE_CHECKING: from dff.script.core.script import Node @@ -56,6 +57,8 @@ class FrameworkData(BaseModel): "Actor service data. Cleared at the end of every turn." stats: Dict[str, Any] = Field(default_factory=dict) "Enables complex stats collection across multiple turns." + slot_manager: SlotManager = Field(default_factory=SlotManager) + "Stores extracted slots." class Context(BaseModel): diff --git a/dff/script/core/normalization.py b/dff/script/core/normalization.py index e6926227d..2784b2647 100644 --- a/dff/script/core/normalization.py +++ b/dff/script/core/normalization.py @@ -33,9 +33,11 @@ def normalize_label(label: Label, default_flow_label: LabelType = "") -> Label: """ if callable(label): - def get_label_handler(ctx: Context, pipeline: Pipeline) -> ConstLabel: + def get_label_handler(ctx: Context, pipeline: Pipeline) -> Optional[ConstLabel]: try: new_label = label(ctx, pipeline) + if new_label is None: + return None new_label = normalize_label(new_label, default_flow_label) flow_label, node_label, _ = new_label node = pipeline.script.get(flow_label, {}).get(node_label) diff --git a/dff/slots/__init__.py b/dff/slots/__init__.py new file mode 100644 index 000000000..7579a8523 --- /dev/null +++ b/dff/slots/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# flake8: noqa: F401 + +from dff.slots.slots import GroupSlot, ValueSlot, RegexpSlot, FunctionSlot +from dff.slots.conditions import slots_extracted +from dff.slots.processing import extract, extract_all, unset, unset_all, fill_template +from dff.slots.response import filled_template diff --git a/dff/slots/conditions.py b/dff/slots/conditions.py new file mode 100644 index 000000000..80ebdf222 --- /dev/null +++ b/dff/slots/conditions.py @@ -0,0 +1,32 @@ +""" +Conditions +--------------------------- +Provides slot-related conditions. +""" + +from __future__ import annotations +from typing import TYPE_CHECKING, Literal + +if TYPE_CHECKING: + from dff.script import Context + from dff.slots.slots import SlotName + from dff.pipeline import Pipeline + + +def slots_extracted(*slots: SlotName, mode: Literal["any", "all"] = "all"): + """ + Conditions that checks if slots are extracted. + + :param slots: Names for slots that need to be checked. + :param mode: Whether to check if all slots are extracted or any slot is extracted. + """ + + def check_slot_state(ctx: Context, pipeline: Pipeline) -> bool: + manager = ctx.framework_data.slot_manager + if mode == "all": + return all(manager.is_slot_extracted(slot) for slot in slots) + elif mode == "any": + return any(manager.is_slot_extracted(slot) for slot in slots) + raise ValueError(f"{mode!r} not in ['any', 'all'].") + + return check_slot_state diff --git a/dff/slots/processing.py b/dff/slots/processing.py new file mode 100644 index 000000000..1f99c4c23 --- /dev/null +++ b/dff/slots/processing.py @@ -0,0 +1,98 @@ +""" +Processing +--------------------------- +This module provides wrappers for :py:class:`~dff.slots.slots.SlotManager`'s API. +""" + +from __future__ import annotations + +import logging +from typing import Awaitable, Callable, TYPE_CHECKING + +if TYPE_CHECKING: + from dff.slots.slots import SlotName + from dff.script import Context + from dff.pipeline import Pipeline + +logger = logging.getLogger(__name__) + + +def extract(*slots: SlotName) -> Callable[[Context, Pipeline], Awaitable[None]]: + """ + Extract slots listed slots. + This will override all slots even if they are already extracted. + + :param slots: List of slot names to extract. + """ + + async def inner(ctx: Context, pipeline: Pipeline) -> None: + manager = ctx.framework_data.slot_manager + for slot in slots: # todo: maybe gather + await manager.extract_slot(slot, ctx, pipeline) + + return inner + + +def extract_all(): + """ + Extract all slots defined in the pipeline. + """ + + async def inner(ctx: Context, pipeline: Pipeline): + manager = ctx.framework_data.slot_manager + await manager.extract_all(ctx, pipeline) + + return inner + + +def unset(*slots: SlotName) -> Callable[[Context, Pipeline], None]: + """ + Mark specified slots as not extracted and clear extracted values. + + :param slots: List of slot names to extract. + """ + + def unset_inner(ctx: Context, pipeline: Pipeline) -> None: + manager = ctx.framework_data.slot_manager + for slot in slots: + manager.unset_slot(slot) + + return unset_inner + + +def unset_all(): + """ + Mark all slots as not extracted and clear all extracted values. + """ + + def inner(ctx: Context, pipeline: Pipeline): + manager = ctx.framework_data.slot_manager + manager.unset_all_slots() + + return inner + + +def fill_template() -> Callable[[Context, Pipeline], None]: + """ + Fill the response template in the current node. + + Response message of the current node should be a format-string: e.g. "Your username is {profile.username}". + """ + + def inner(ctx: Context, pipeline: Pipeline) -> None: + manager = ctx.framework_data.slot_manager + # get current node response + response = ctx.current_node.response + + if response is None: + return + + if callable(response): + response = response(ctx, pipeline) + + new_text = manager.fill_template(response.text) + + response.text = new_text + ctx.current_node.response = response + + return inner diff --git a/dff/slots/response.py b/dff/slots/response.py new file mode 100644 index 000000000..152b79ddb --- /dev/null +++ b/dff/slots/response.py @@ -0,0 +1,34 @@ +""" +Response +--------------------------- +Slot-related DFF responses. +""" + +from __future__ import annotations +from typing import Callable, TYPE_CHECKING + +if TYPE_CHECKING: + from dff.script import Context, Message + from dff.pipeline import Pipeline + + +def filled_template(template: Message) -> Callable[[Context, Pipeline], Message]: + """ + Fill template with slot values. + The `text` attribute of the template message should be a format-string: + e.g. "Your username is {profile.username}". + + For the example above, if ``profile.username`` slot has value "admin", + it would return a copy of the message with the following text: + "Your username is admin". + + :param template: Template message with a format-string text. + """ + + def fill_inner(ctx: Context, pipeline: Pipeline) -> Message: + message = template.model_copy() + new_text = ctx.framework_data.slot_manager.fill_template(template.text) + message.text = new_text + return message + + return fill_inner diff --git a/dff/slots/slots.py b/dff/slots/slots.py new file mode 100644 index 000000000..536501751 --- /dev/null +++ b/dff/slots/slots.py @@ -0,0 +1,418 @@ +""" +Slots +----- +This module defines base classes for slots and some concrete implementations of them. +""" + +from __future__ import annotations + +import asyncio +import re +from abc import ABC, abstractmethod +from typing import Callable, Any, Awaitable, TYPE_CHECKING, Union +from typing_extensions import TypeAlias +import logging +from functools import reduce + +from pydantic import BaseModel, model_validator, Field + +from dff.utils.devel.async_helpers import wrap_sync_function_in_async +from dff.utils.devel.json_serialization import PickleEncodedValue + +if TYPE_CHECKING: + from dff.script import Context, Message + from dff.pipeline.pipeline.pipeline import Pipeline + + +logger = logging.getLogger(__name__) + + +SlotName: TypeAlias = str +""" +A string to identify slots. + +Top-level slots are identified by their key in a :py:class:`~.GroupSlot`. + +E.g. + +.. code:: python + + GroupSlot( + user=RegexpSlot(), + password=FunctionSlot, + ) + +Has two slots with names "user" and "password". + +For nested group slots use dots to separate names: + +.. code:: python + + GroupSlot( + user=GroupSlot( + name=FunctionSlot, + password=FunctionSlot, + ) + ) + +Has two slots with names "user.name" and "user.password". +""" + + +def recursive_getattr(obj, slot_name: SlotName): + def two_arg_getattr(__o, name): + # pydantic handles exception when accessing a non-existing extra-field on its own + # return None by default to avoid that + return getattr(__o, name, None) + + return reduce(two_arg_getattr, [obj, *slot_name.split(".")]) + + +def recursive_setattr(obj, slot_name: SlotName, value): + parent_slot, _, slot = slot_name.rpartition(".") + + if parent_slot: + setattr(recursive_getattr(obj, parent_slot), slot, value) + else: + setattr(obj, slot, value) + + +class SlotNotExtracted(Exception): + """This exception can be returned or raised by slot extractor if slot extraction is unsuccessful.""" + + pass + + +class ExtractedSlot(BaseModel, ABC): + """ + Represents value of an extracted slot. + + Instances of this class are managed by framework and + are stored in :py:attr:`~dff.script.core.context.FrameworkData.slot_manager`. + They can be accessed via the ``ctx.framework_data.slot_manager.get_extracted_slot`` method. + """ + + @property + @abstractmethod + def __slot_extracted__(self) -> bool: + """Whether the slot is extracted.""" + raise NotImplementedError + + def __unset__(self): + """Mark slot as not extracted and clear extracted data (except for default value).""" + raise NotImplementedError + + @abstractmethod + def __str__(self): + """String representation is used to fill templates.""" + raise NotImplementedError + + +class ExtractedValueSlot(ExtractedSlot): + """Value extracted from :py:class:`~.ValueSlot`.""" + + is_slot_extracted: bool + extracted_value: PickleEncodedValue + default_value: PickleEncodedValue = None + + @property + def __slot_extracted__(self) -> bool: + return self.is_slot_extracted + + def __unset__(self): + self.is_slot_extracted = False + self.extracted_value = SlotNotExtracted("Slot manually unset.") + + @property + def value(self): + """Extracted value or the default value if the slot is not extracted.""" + return self.extracted_value if self.is_slot_extracted else self.default_value + + def __str__(self): + return str(self.value) + + +class ExtractedGroupSlot(ExtractedSlot, extra="allow"): + __pydantic_extra__: dict[str, Union["ExtractedValueSlot", "ExtractedGroupSlot"]] + + @property + def __slot_extracted__(self) -> bool: + return all([slot.__slot_extracted__ for slot in self.__pydantic_extra__.values()]) + + def __unset__(self): + for child in self.__pydantic_extra__.values(): + child.__unset__() + + def __str__(self): + return str({key: str(value) for key, value in self.__pydantic_extra__.items()}) + + def update(self, old: "ExtractedGroupSlot"): + """ + Rebase this extracted groups slot on top of another one. + This is required to merge slot storage in-context + with a potentially different slot configuration passed to pipeline. + + :param old: An instance of :py:class:`~.ExtractedGroupSlot` stored in-context. + Extracted values will be transferred to this object. + """ + for slot in old.__pydantic_extra__: + if slot in self.__pydantic_extra__: + new_slot = self.__pydantic_extra__[slot] + old_slot = old.__pydantic_extra__[slot] + if isinstance(new_slot, ExtractedGroupSlot) and isinstance(old_slot, ExtractedGroupSlot): + new_slot.update(old_slot) + if isinstance(new_slot, ExtractedValueSlot) and isinstance(old_slot, ExtractedValueSlot): + self.__pydantic_extra__[slot] = old_slot + + +class BaseSlot(BaseModel, frozen=True): + """ + BaseSlot is a base class for all slots. + """ + + @abstractmethod + async def get_value(self, ctx: Context, pipeline: Pipeline) -> ExtractedSlot: + """ + Extract slot value from :py:class:`~.Context` and return an instance of :py:class:`~.ExtractedSlot`. + """ + raise NotImplementedError + + @abstractmethod + def init_value(self) -> ExtractedSlot: + """ + Provide an initial value to fill slot storage with. + """ + raise NotImplementedError + + +class ValueSlot(BaseSlot, frozen=True): + """ + Value slot is a base class for all slots that are designed to extract concrete values. + Subclass it, if you want to declare your own slot type. + """ + + default_value: Any = None + + @abstractmethod + async def extract_value(self, ctx: Context, pipeline: Pipeline) -> Union[Any, SlotNotExtracted]: + """ + Return value extracted from context. + + Return :py:exc:`~.SlotNotExtracted` to mark extraction as unsuccessful. + + Raising exceptions is also allowed and will result in an unsuccessful extraction as well. + """ + raise NotImplementedError + + async def get_value(self, ctx: Context, pipeline: Pipeline) -> ExtractedValueSlot: + """Wrapper for :py:meth:`~.ValueSlot.extract_value` to handle exceptions.""" + extracted_value = SlotNotExtracted("Caught an exit exception.") + is_slot_extracted = False + + try: + extracted_value = await self.extract_value(ctx, pipeline) + is_slot_extracted = not isinstance(extracted_value, SlotNotExtracted) + except Exception as error: + logger.exception(f"Exception occurred during {self.__class__.__name__!r} extraction.", exc_info=error) + extracted_value = error + finally: + return ExtractedValueSlot.model_construct( + is_slot_extracted=is_slot_extracted, + extracted_value=extracted_value, + default_value=self.default_value, + ) + + def init_value(self) -> ExtractedValueSlot: + return ExtractedValueSlot.model_construct( + is_slot_extracted=False, + extracted_value=SlotNotExtracted("Initial slot extraction."), + default_value=self.default_value, + ) + + +class GroupSlot(BaseSlot, extra="allow", frozen=True): + """ + Base class for :py:class:`~.RootSlot` and :py:class:`~.GroupSlot`. + """ + + __pydantic_extra__: dict[str, Union["ValueSlot", "GroupSlot"]] + + def __init__(self, **kwargs): # supress unexpected argument warnings + super().__init__(**kwargs) + + @model_validator(mode="after") + def __check_extra_field_names__(self): + """ + Extra field names cannot be dunder names or contain dots. + """ + for field in self.__pydantic_extra__.keys(): + if "." in field: + raise ValueError(f"Extra field name cannot contain dots: {field!r}") + if field.startswith("__") and field.endswith("__"): + raise ValueError(f"Extra field names cannot be dunder: {field!r}") + return self + + async def get_value(self, ctx: Context, pipeline: Pipeline) -> ExtractedGroupSlot: + child_values = await asyncio.gather( + *(child.get_value(ctx, pipeline) for child in self.__pydantic_extra__.values()) + ) + return ExtractedGroupSlot( + **{child_name: child_value for child_value, child_name in zip(child_values, self.__pydantic_extra__.keys())} + ) + + def init_value(self) -> ExtractedGroupSlot: + return ExtractedGroupSlot( + **{child_name: child.init_value() for child_name, child in self.__pydantic_extra__.items()} + ) + + +class RegexpSlot(ValueSlot, frozen=True): + """ + RegexpSlot is a slot type that extracts its value using a regular expression. + You can pass a compiled or a non-compiled pattern to the `regexp` argument. + If you want to extract a particular group, but not the full match, + change the `match_group_idx` parameter. + """ + + regexp: str + match_group_idx: int = 0 + "Index of the group to match." + + async def extract_value(self, ctx: Context, _: Pipeline) -> Union[str, SlotNotExtracted]: + request_text = ctx.last_request.text + search = re.search(self.regexp, request_text) + return ( + search.group(self.match_group_idx) + if search + else SlotNotExtracted(f"Failed to match pattern {self.regexp!r} in {request_text!r}.") + ) + + +class FunctionSlot(ValueSlot, frozen=True): + """ + A simpler version of :py:class:`~.ValueSlot`. + + Uses a user-defined `func` to extract slot value from the :py:attr:`~.Context.last_request` Message. + """ + + func: Callable[[Message], Union[Awaitable[Union[Any, SlotNotExtracted]], Any, SlotNotExtracted]] + + async def extract_value(self, ctx: Context, _: Pipeline) -> Union[Any, SlotNotExtracted]: + return await wrap_sync_function_in_async(self.func, ctx.last_request) + + +class SlotManager(BaseModel): + """ + Provides API for managing slots. + + An instance of this class can be accessed via ``ctx.framework_data.slot_manager``. + """ + + slot_storage: ExtractedGroupSlot = Field(default_factory=ExtractedGroupSlot) + """Slot storage. Stored inside ctx.framework_data.""" + root_slot: GroupSlot = Field(default_factory=GroupSlot, exclude=True) + """Slot configuration passed during pipeline initialization.""" + + def set_root_slot(self, root_slot: GroupSlot): + """ + Set root_slot configuration from pipeline. + Update extracted slots with the new configuration: + + New slots are added with their :py:meth:`~.BaseSlot.init_value`. + Old extracted slot values are preserved only if their configuration did not change. + That is if they are still present in the config and if their fundamental type did not change + (i.e. `GroupSlot` did not turn into a `ValueSlot` or vice versa). + + This method is called by pipeline and is not supposed to be used otherwise. + """ + self.root_slot = root_slot + new_slot_storage = root_slot.init_value() + new_slot_storage.update(self.slot_storage) + self.slot_storage = new_slot_storage + + def get_slot(self, slot_name: SlotName) -> BaseSlot: + """ + Get slot configuration from the slot name. + + :raises KeyError: If the slot with the specified name does not exist. + """ + try: + slot = recursive_getattr(self.root_slot, slot_name) + if isinstance(slot, BaseSlot): + return slot + except (AttributeError, KeyError): + pass + raise KeyError(f"Could not find slot {slot_name!r}.") + + async def extract_slot(self, slot_name: SlotName, ctx: Context, pipeline: Pipeline) -> None: + """ + Extract slot `slot_name` and store extracted value in `slot_storage`. + + :raises KeyError: If the slot with the specified name does not exist. + """ + slot = self.get_slot(slot_name) + value = await slot.get_value(ctx, pipeline) + + recursive_setattr(self.slot_storage, slot_name, value) + + async def extract_all(self, ctx: Context, pipeline: Pipeline): + """ + Extract all slots from slot configuration `root_slot` and set `slot_storage` to the extracted value. + """ + self.slot_storage = await self.root_slot.get_value(ctx, pipeline) + + def get_extracted_slot(self, slot_name: SlotName) -> ExtractedSlot: + """ + Retrieve extracted value from `slot_storage`. + + :raises KeyError: If the slot with the specified name does not exist. + """ + try: + slot = recursive_getattr(self.slot_storage, slot_name) + if isinstance(slot, ExtractedSlot): + return slot + except (AttributeError, KeyError): + pass + raise KeyError(f"Could not find slot {slot_name!r}.") + + def is_slot_extracted(self, slot_name: str) -> bool: + """ + Return if the specified slot is extracted. + + :raises KeyError: If the slot with the specified name does not exist. + """ + return self.get_extracted_slot(slot_name).__slot_extracted__ + + def all_slots_extracted(self) -> bool: + """ + Return if all slots are extracted. + """ + return self.slot_storage.__slot_extracted__ + + def unset_slot(self, slot_name: SlotName) -> None: + """ + Mark specified slot as not extracted and clear extracted value. + + :raises KeyError: If the slot with the specified name does not exist. + """ + self.get_extracted_slot(slot_name).__unset__() + + def unset_all_slots(self) -> None: + """ + Mark all slots as not extracted and clear all extracted values. + """ + self.slot_storage.__unset__() + + def fill_template(self, template: str) -> str: + """ + Fill `template` string with extracted slot values and return a formatted string. + + `template` should be a format-string: + + E.g. "Your username is {profile.username}". + + For the example above, if ``profile.username`` slot has value "admin", + it would return the following text: + "Your username is admin". + """ + return template.format(**dict(self.slot_storage.__pydantic_extra__.items())) diff --git a/dff/utils/devel/__init__.py b/dff/utils/devel/__init__.py index 08ff1afbc..affbce004 100644 --- a/dff/utils/devel/__init__.py +++ b/dff/utils/devel/__init__.py @@ -11,3 +11,4 @@ JSONSerializableExtras, ) from .extra_field_helpers import grab_extra_fields +from .async_helpers import wrap_sync_function_in_async diff --git a/dff/utils/devel/async_helpers.py b/dff/utils/devel/async_helpers.py new file mode 100644 index 000000000..13cbc640b --- /dev/null +++ b/dff/utils/devel/async_helpers.py @@ -0,0 +1,24 @@ +""" +Async Helpers +------------- +Tools to help with async. +""" + +import asyncio +from typing import Callable, Any + + +async def wrap_sync_function_in_async(func: Callable, *args, **kwargs) -> Any: + """ + Utility function, that wraps both functions and coroutines in coroutines. + Invokes `func` if it is just a callable and awaits, if this is a coroutine. + + :param func: Callable to wrap. + :param \\*args: Function args. + :param \\**kwargs: Function kwargs. + :return: What function returns. + """ + if asyncio.iscoroutinefunction(func): + return await func(*args, **kwargs) + else: + return func(*args, **kwargs) diff --git a/dff/utils/devel/json_serialization.py b/dff/utils/devel/json_serialization.py index 017fc791e..f198dc47c 100644 --- a/dff/utils/devel/json_serialization.py +++ b/dff/utils/devel/json_serialization.py @@ -141,6 +141,8 @@ class MyClass(BaseModel): my_obj = MyClass() # the field cannot be set during init my_obj.my_field = unserializable_object # can be set manually to avoid validation +Alternatively, ``BaseModel.model_construct`` may be used to bypass validation, +though it would bypass validation of all fields. """ JSONPickleSerializer = PlainSerializer(json_pickle_serializer, when_used="json") diff --git a/docs/source/conf.py b/docs/source/conf.py index a4b65beb8..dd7c92bab 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -183,6 +183,7 @@ def setup(_): ("responses", "Responses"), ], ), + ("tutorials.slots", "Slots"), ("tutorials.utils", "Utils"), ("tutorials.stats", "Stats"), ] @@ -193,6 +194,7 @@ def setup(_): ("dff.messengers", "Messenger Interfaces"), ("dff.pipeline", "Pipeline"), ("dff.script", "Script"), + ("dff.slots", "Slots"), ("dff.stats", "Stats"), ("dff.utils.testing", "Testing Utils"), ("dff.utils.turn_caching", "Caching"), diff --git a/docs/source/user_guides.rst b/docs/source/user_guides.rst index 0cb1a1531..635ebb031 100644 --- a/docs/source/user_guides.rst +++ b/docs/source/user_guides.rst @@ -9,6 +9,14 @@ those include but are not limited to: dialog graph creation, specifying start an setting transitions and conditions, using ``Context`` object in order to receive information about current script execution. +:doc:`Slot extraction <./user_guides/slot_extraction>` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``slot extraction`` guide demonstrates the slot extraction functionality +currently integrated in the library. ``DFF`` only provides basic building blocks for this task, +which can be trivially extended to support any NLU engine or slot extraction model +of your liking. + :doc:`Context guide <./user_guides/context_guide>` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -34,6 +42,7 @@ and to locate and remove performance bottlenecks. :hidden: user_guides/basic_conceptions + user_guides/slot_extraction user_guides/context_guide user_guides/superset_guide user_guides/optimization_guide diff --git a/docs/source/user_guides/slot_extraction.rst b/docs/source/user_guides/slot_extraction.rst new file mode 100644 index 000000000..fc2b697e3 --- /dev/null +++ b/docs/source/user_guides/slot_extraction.rst @@ -0,0 +1,176 @@ +Slot Extraction +--------------- + +Introduction +~~~~~~~~~~~~ + +Extracting and filling slots is an essential part of any conversational service +that comprises the inherent business logic. Like most frameworks, DFF +provides components that address this task as a part of its ``slots`` module. +These can be easily customized to leverage neural networks specifically designed +for slot extraction or any other logic you might want to integrate. + +API overview +~~~~~~~~~~~~ + +Defining slots +============== + +The basic building block of the API is the +`BaseSlot <../apiref/dff.slots.slots.html#dff.slots.slots.BaseSlot>`_ class +and its descendants that vary depending on the value extraction logic. +Each slot has a name by which it can be accessed and a method for extracting values. +Below, we demonstrate the most basic class that extracts values +from user utterances using a regular expression: +`RegexpSlot <../apiref/dff.slots.slots.html#dff.slots.types.RegexpSlot>`_. + +.. code-block:: python + + from dff.slots import RegexpSlot + ... + email_slot = RegexpSlot(regexp=r"[a-z@\.A-Z]+") + +The slots can implement arbitrary logic including requests to external services. +For instance, Deeppavlov library includes a number of models that may be of use for slot +extraction task. In particular, we will demonstrate the use of the following +`NER model `_ +that was trained and validated on the conll_2003 dataset. + +.. code-block:: shell + + docker pull deeppavlov/deeppavlov:latest + docker run -d --name=ner \ + -e CONFIG=ner_conll2003_bert \ + -p 5000:5000 \ + -v ~/.deeppavlov:/root/deeppavlov \ + -v ~/.cache:/root/cache \ + deeppavlov/deeppavlov:latest + +Now that you have a Deeppavlov docker image running on port 5000, you can take the following steps to take +full advantage of its predictions. + +.. code-block:: python + + import requests + from dff.slots import FunctionSlot + from dff.script import Message + + # we assume that there is a 'NER' service running on port 5000 + def extract_first_name(utterance: Message) -> str: + """Return the first entity of type B-PER (first name) found in the utterance.""" + ner_request = requests.post( + "http://localhost:5000/model", + json={"x": [utterance.text]} + ) + ner_tuple = ner_request.json() + if "B-PER" not in ner_tuple[1][0]: + return "" + return ner_tuple[0][0][ner_tuple[1][0].index("B-PER")] + + name_slot = FunctionSlot(func=extract_first_name) + +Individual slots can be grouped allowing the developer to access them together +as a namespace. This can be achieved using the +`GroupSlot <../apiref/dff.slots.slots.html#dff.slots.slots.GroupSlot>`_ +component that is initialized with other slot instances as its children. +The group slots also allows for arbitrary nesting, i.e. it is possible to include +group slots in other group slots. + +.. code-block:: python + + from dff.slots import GroupSlot + + profile_slot = GroupSlot(name=name_slot, email=email_slot) + +After defining all your slots, pass ``GroupSlot`` as pipeline's `slots` argument. +That slot is a root slot: it contains all other group and value slots. + +.. code-block:: python + + from dff.pipeline import Pipeline + + pipeline = Pipeline.from_script(..., slots=profile_slot) + +Slot names +========== + +Any slot can be accessed by a slot name: +A dot-separated string that acts as a path from the root slot to the needed slot. + +In the example above ``name_slot`` would have the name "name" +because that is the key used to store it in the ``profile_slot``. + +If you have a nested structure (of ``GroupSlots``) separate the names with dots: + +.. code-block:: python + + from dff.slots import GroupSlot + + root_slot = GroupSlot(profile=GroupSlot(name=name_slot, email=email_slot)) + +In this example ``name_slot`` would be accessible by the "profile.name" name. + +Using slots +=========== + +Slots can be extracted at the ``PRE_TRANSITIONS_PROCESSING`` stage +using the `extract <../apiref/dff.slots.processing.html#dff.slots.processing.extract>`_ +function from the `processing` submodule. +You can pass any number of names of the slots that you want to extract to this function. + +.. code-block:: python + + from dff.slots.processing import extract + + PRE_TRANSITIONS_PROCESSING: {"extract_first_name": extract("name", "email")} + +The `conditions` submodule provides a function for checking if specific slots have been extracted. + +.. code-block:: python + + from dff.slots.conditions import slots_extracted + + TRANSITIONS: {"all_information": slots_extracted("name", "email", mode="all")} + TRANSITIONS: {"partial_information": slots_extracted("name", "email", mode="any")} + +.. note:: + + You can combine ``slots_extracted`` with the + `negation <../apiref/dff.script.conditions.std_conditions.html#dff.script.conditions.std_conditions.negation>`_ + condition to make a transition to an extractor node if a slot has not been extracted yet. + +Both `processing` and `response` submodules provide functions for filling templates with +extracted slot values. +Choose whichever one you like, there's not much difference between them at the moment. + +.. code-block:: python + + from dff.slots.processing import fill_template + from dff.slots.response import filled_template + + PRE_RESPONSE_PROCESSING: {"fill_response_slots": slot_procs.fill_template()} + RESPONSE: Message(text="Your first name: {name}") + + + RESPONSE: filled_template(Message(text="Your first name: {name}")) + +Some real examples of scripts utilizing slot extraction can be found in the +`tutorials section <../tutorials/tutorials.slots.1_basic_example.html>`_. + +Further reading +=============== + +All of the functions described in the previous sections call methods of the +`SlotManager <../apiref/dff.slots.slots.html#dff.slots.slots.SlotManager>`_ +class under the hood. + +An instance of this class can be accessed in runtime via ``ctx.framework_data.slot_manager``. + +This class allows for more detailed access to the slots API. +For example, you can access exceptions that occurred during slot extraction: + +.. code-block:: python + + slot_manager = ctx.framework_data.slot_manager + extracted_value = slot_manager.get_extracted_slot("name") + exception = extracted_value.extracted_value if not extracted_value.is_slot_extracted else None diff --git a/poetry.lock b/poetry.lock index 5f1b51b77..eadc0df50 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1486,6 +1486,20 @@ files = [ dnspython = ">=2.0.0" idna = ">=2.0.0" +[[package]] +name = "eval-type-backport" +version = "0.2.0" +description = "Like `typing._eval_type`, but lets older Python versions use newer typing features." +optional = false +python-versions = ">=3.8" +files = [ + {file = "eval_type_backport-0.2.0-py3-none-any.whl", hash = "sha256:ac2f73d30d40c5a30a80b8739a789d6bb5e49fdffa66d7912667e2015d9c9933"}, + {file = "eval_type_backport-0.2.0.tar.gz", hash = "sha256:68796cfbc7371ebf923f03bdf7bef415f3ec098aeced24e054b253a0e78f7b37"}, +] + +[package.extras] +tests = ["pytest"] + [[package]] name = "exceptiongroup" version = "1.2.1" @@ -1821,8 +1835,8 @@ files = [ [package.dependencies] cffi = {version = ">=1.12.2", markers = "platform_python_implementation == \"CPython\" and sys_platform == \"win32\""} greenlet = [ - {version = ">=3.0rc3", markers = "platform_python_implementation == \"CPython\" and python_version >= \"3.11\""}, {version = ">=2.0.0", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""}, + {version = ">=3.0rc3", markers = "platform_python_implementation == \"CPython\" and python_version >= \"3.11\""}, ] "zope.event" = "*" "zope.interface" = "*" @@ -3880,8 +3894,8 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, {version = ">=1.20.3", markers = "python_version < \"3.10\""}, + {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" @@ -5032,7 +5046,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -7254,4 +7267,4 @@ ydb = ["six", "ydb"] [metadata] lock-version = "2.0" python-versions = "^3.8.1,!=3.9.7" -content-hash = "0fea55ff020381487754e65f4630de8bfaedc65c37b6d071763d427f1667b7b3" +content-hash = "a4e53a8b58504d6e4f877ac5e7901d5aa8451003bf9edf55ebfb4df7af8424ab" diff --git a/pyproject.toml b/pyproject.toml index a7ac29fb4..948809258 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,6 +55,7 @@ python = "^3.8.1,!=3.9.7" # `streamlit` package does not support python 3.9.7, pydantic = ">=2.0" # `pydantic` version more than 2 required nest-asyncio = "*" typing-extensions = "*" +eval_type_backport = "*" wrapt = "*" colorama = "*" ydb = { version = "*", optional = true } @@ -212,6 +213,7 @@ markers = [ "all: reserved by allow-skip", "none: reserved by allow-skip", ] +asyncio_mode = "auto" [tool.coverage.run] diff --git a/tests/slots/__init__.py b/tests/slots/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/slots/conftest.py b/tests/slots/conftest.py new file mode 100644 index 000000000..a75b6fa69 --- /dev/null +++ b/tests/slots/conftest.py @@ -0,0 +1,28 @@ +import pytest + +from dff.script import Message, TRANSITIONS, RESPONSE, Context +from dff.script import conditions as cnd +from dff.pipeline import Pipeline +from dff.slots.slots import SlotNotExtracted + + +@pytest.fixture(scope="function", autouse=True) +def patch_exception_equality(monkeypatch): + monkeypatch.setattr( + SlotNotExtracted, "__eq__", lambda self, other: type(self) is type(other) and self.args == other.args + ) + yield + + +@pytest.fixture(scope="function") +def pipeline(): + script = {"flow": {"node": {RESPONSE: Message(), TRANSITIONS: {"node": cnd.true()}}}} + pipeline = Pipeline.from_script(script=script, start_label=("flow", "node")) + return pipeline + + +@pytest.fixture(scope="function") +def context(): + ctx = Context() + ctx.add_request(Message(text="Hi")) + return ctx diff --git a/tests/slots/test_slot_manager.py b/tests/slots/test_slot_manager.py new file mode 100644 index 000000000..12f786038 --- /dev/null +++ b/tests/slots/test_slot_manager.py @@ -0,0 +1,262 @@ +import pytest + +from dff.slots.slots import ( + SlotManager, + RegexpSlot, + GroupSlot, + FunctionSlot, + ExtractedGroupSlot, + ExtractedValueSlot, + SlotNotExtracted, +) +from dff.script import Message + + +def faulty_func(_): + raise SlotNotExtracted("Error.") + + +init_value_slot = ExtractedValueSlot.model_construct( + is_slot_extracted=False, + extracted_value=SlotNotExtracted("Initial slot extraction."), + default_value=None, +) + + +root_slot = GroupSlot( + person=GroupSlot( + name=RegexpSlot(regexp=r"(?<=am ).+?(?=\.)"), + surname=FunctionSlot(func=faulty_func), + email=RegexpSlot(regexp=r"[a-zA-Z\.]+@[a-zA-Z\.]+"), + ), + msg_len=FunctionSlot(func=lambda msg: len(msg.text)), +) + + +extracted_slot_values = { + "person.name": ExtractedValueSlot.model_construct( + is_slot_extracted=True, extracted_value="Bot", default_value=None + ), + "person.surname": ExtractedValueSlot.model_construct( + is_slot_extracted=False, extracted_value=SlotNotExtracted("Error."), default_value=None + ), + "person.email": ExtractedValueSlot.model_construct( + is_slot_extracted=True, extracted_value="bot@bot", default_value=None + ), + "msg_len": ExtractedValueSlot.model_construct(is_slot_extracted=True, extracted_value=29, default_value=None), +} + + +extracted_slot_values["person"] = ExtractedGroupSlot( + name=extracted_slot_values["person.name"], + surname=extracted_slot_values["person.surname"], + email=extracted_slot_values["person.email"], +) + + +unset_slot = ExtractedValueSlot.model_construct( + is_slot_extracted=False, extracted_value=SlotNotExtracted("Slot manually unset."), default_value=None +) + + +init_slot_storage = ExtractedGroupSlot( + person=ExtractedGroupSlot( + name=init_value_slot, + surname=init_value_slot, + email=init_value_slot, + ), + msg_len=init_value_slot, +) + + +unset_slot_storage = ExtractedGroupSlot( + person=ExtractedGroupSlot( + name=unset_slot, + surname=unset_slot, + email=unset_slot, + ), + msg_len=unset_slot, +) + + +full_slot_storage = ExtractedGroupSlot( + person=ExtractedGroupSlot( + name=extracted_slot_values["person.name"], + surname=extracted_slot_values["person.surname"], + email=extracted_slot_values["person.email"], + ), + msg_len=extracted_slot_values["msg_len"], +) + + +class TestSlotManager: + @pytest.fixture(scope="function") + def context_with_request(self, context): + new_ctx = context.model_copy(deep=True) + new_ctx.add_request(Message(text="I am Bot. My email is bot@bot")) + return new_ctx + + async def test_init_slot_storage(self): + assert root_slot.init_value() == init_slot_storage + + @pytest.fixture(scope="function") + def empty_slot_manager(self): + manager = SlotManager() + manager.set_root_slot(root_slot) + return manager + + @pytest.fixture(scope="function") + def extracted_slot_manager(self): + slot_storage = full_slot_storage.model_copy(deep=True) + return SlotManager(root_slot=root_slot, slot_storage=slot_storage) + + @pytest.fixture(scope="function") + def fully_extracted_slot_manager(self): + slot_storage = full_slot_storage.model_copy(deep=True) + slot_storage.person.surname = ExtractedValueSlot.model_construct( + extracted_value="Bot", is_slot_extracted=True, default_value=None + ) + return SlotManager(root_slot=root_slot, slot_storage=slot_storage) + + def test_get_slot_by_name(self, empty_slot_manager): + assert empty_slot_manager.get_slot("person.name").regexp == r"(?<=am ).+?(?=\.)" + assert empty_slot_manager.get_slot("person.email").regexp == r"[a-zA-Z\.]+@[a-zA-Z\.]+" + assert isinstance(empty_slot_manager.get_slot("person"), GroupSlot) + assert isinstance(empty_slot_manager.get_slot("msg_len"), FunctionSlot) + + with pytest.raises(KeyError): + empty_slot_manager.get_slot("person.birthday") + + with pytest.raises(KeyError): + empty_slot_manager.get_slot("intent") + + @pytest.mark.parametrize( + "slot_name,expected_slot_storage", + [ + ( + "person.name", + ExtractedGroupSlot( + person=ExtractedGroupSlot( + name=extracted_slot_values["person.name"], + surname=init_value_slot, + email=init_value_slot, + ), + msg_len=init_value_slot, + ), + ), + ( + "person", + ExtractedGroupSlot( + person=ExtractedGroupSlot( + name=extracted_slot_values["person.name"], + surname=extracted_slot_values["person.surname"], + email=extracted_slot_values["person.email"], + ), + msg_len=init_value_slot, + ), + ), + ( + "msg_len", + ExtractedGroupSlot( + person=ExtractedGroupSlot( + name=init_value_slot, + surname=init_value_slot, + email=init_value_slot, + ), + msg_len=extracted_slot_values["msg_len"], + ), + ), + ], + ) + async def test_slot_extraction( + self, slot_name, expected_slot_storage, empty_slot_manager, context_with_request, pipeline + ): + await empty_slot_manager.extract_slot(slot_name, context_with_request, pipeline) + assert empty_slot_manager.slot_storage == expected_slot_storage + + async def test_extract_all(self, empty_slot_manager, context_with_request, pipeline): + await empty_slot_manager.extract_all(context_with_request, pipeline) + assert empty_slot_manager.slot_storage == full_slot_storage + + @pytest.mark.parametrize( + "slot_name, expected_slot_storage", + [ + ( + "person.name", + ExtractedGroupSlot( + person=ExtractedGroupSlot( + name=unset_slot, + surname=extracted_slot_values["person.surname"], + email=extracted_slot_values["person.email"], + ), + msg_len=extracted_slot_values["msg_len"], + ), + ), + ( + "person", + ExtractedGroupSlot( + person=ExtractedGroupSlot( + name=unset_slot, + surname=unset_slot, + email=unset_slot, + ), + msg_len=extracted_slot_values["msg_len"], + ), + ), + ( + "msg_len", + ExtractedGroupSlot( + person=ExtractedGroupSlot( + name=extracted_slot_values["person.name"], + surname=extracted_slot_values["person.surname"], + email=extracted_slot_values["person.email"], + ), + msg_len=unset_slot, + ), + ), + ], + ) + def test_unset_slot(self, extracted_slot_manager, slot_name, expected_slot_storage): + extracted_slot_manager.unset_slot(slot_name) + assert extracted_slot_manager.slot_storage == expected_slot_storage + + def test_unset_all(self, extracted_slot_manager): + extracted_slot_manager.unset_all_slots() + assert extracted_slot_manager.slot_storage == unset_slot_storage + + @pytest.mark.parametrize("slot_name", ["person.name", "person", "msg_len"]) + def test_get_extracted_slot(self, extracted_slot_manager, slot_name): + assert extracted_slot_manager.get_extracted_slot(slot_name) == extracted_slot_values[slot_name] + + def test_get_extracted_slot_raises(self, extracted_slot_manager): + with pytest.raises(KeyError): + extracted_slot_manager.get_extracted_slot("none") + + def test_slot_extracted(self, fully_extracted_slot_manager, empty_slot_manager): + assert fully_extracted_slot_manager.is_slot_extracted("person.name") is True + assert fully_extracted_slot_manager.is_slot_extracted("person") is True + with pytest.raises(KeyError): + fully_extracted_slot_manager.is_slot_extracted("none") + assert fully_extracted_slot_manager.all_slots_extracted() is True + + assert empty_slot_manager.is_slot_extracted("person.name") is False + assert empty_slot_manager.is_slot_extracted("person") is False + with pytest.raises(KeyError): + empty_slot_manager.is_slot_extracted("none") + assert empty_slot_manager.all_slots_extracted() is False + + @pytest.mark.parametrize( + "template,filled_value", + [ + ( + "Your name is {person.name} {person.surname}, your email: {person.email}.", + "Your name is Bot None, your email: bot@bot.", + ), + ], + ) + def test_template_filling(self, extracted_slot_manager, template, filled_value): + assert extracted_slot_manager.fill_template(template) == filled_value + + def test_serializable(self): + serialized = full_slot_storage.model_dump_json() + assert full_slot_storage == ExtractedGroupSlot.model_validate_json(serialized) diff --git a/tests/slots/test_slot_types.py b/tests/slots/test_slot_types.py new file mode 100644 index 000000000..396d7b168 --- /dev/null +++ b/tests/slots/test_slot_types.py @@ -0,0 +1,161 @@ +import pytest +from pydantic import ValidationError + +from dff.script import Message +from dff.slots.slots import ( + RegexpSlot, + GroupSlot, + FunctionSlot, + SlotNotExtracted, + ExtractedValueSlot, + ExtractedGroupSlot, +) + + +@pytest.mark.parametrize( + ("user_request", "regexp", "expected"), + [ + ( + Message(text="My name is Bot"), + "(?<=name is ).+", + ExtractedValueSlot.model_construct(extracted_value="Bot", is_slot_extracted=True, default_value=None), + ), + ( + Message(text="I won't tell you my name"), + "(?<=name is ).+$", + ExtractedValueSlot.model_construct( + extracted_value=SlotNotExtracted( + "Failed to match pattern {regexp!r} in {request_text!r}.".format( + regexp="(?<=name is ).+$", request_text="I won't tell you my name" + ) + ), + is_slot_extracted=False, + default_value=None, + ), + ), + ], +) +async def test_regexp(user_request, regexp, expected, context, pipeline): + context.add_request(user_request) + slot = RegexpSlot(regexp=regexp) + result = await slot.get_value(context, pipeline) + assert result == expected + + +@pytest.mark.parametrize( + ("user_request", "func", "expected"), + [ + ( + Message(text="I am bot"), + lambda msg: msg.text.split(" ")[2], + ExtractedValueSlot.model_construct(extracted_value="bot", is_slot_extracted=True, default_value=None), + ), + ( + Message(text="My email is bot@bot"), + lambda msg: [i for i in msg.text.split(" ") if "@" in i][0], + ExtractedValueSlot.model_construct(extracted_value="bot@bot", is_slot_extracted=True, default_value=None), + ), + ], +) +async def test_function(user_request, func, expected, context, pipeline): + context.add_request(user_request) + slot = FunctionSlot(func=func) + result = await slot.get_value(context, pipeline) + assert result == expected + + async def async_func(*args, **kwargs): + return func(*args, **kwargs) + + slot = FunctionSlot(func=async_func) + result = await slot.get_value(context, pipeline) + assert result == expected + + +async def test_function_exception(context, pipeline): + def func(msg: Message): + raise RuntimeError("error") + + slot = FunctionSlot(func=func) + result = await slot.get_value(context, pipeline) + assert result.is_slot_extracted is False + assert isinstance(result.extracted_value, RuntimeError) + + +@pytest.mark.parametrize( + ("user_request", "slot", "expected", "is_extracted"), + [ + ( + Message(text="I am Bot. My email is bot@bot"), + GroupSlot( + name=RegexpSlot(regexp=r"(?<=am ).+?(?=\.)"), + email=RegexpSlot(regexp=r"[a-zA-Z\.]+@[a-zA-Z\.]+"), + ), + ExtractedGroupSlot( + name=ExtractedValueSlot.model_construct( + is_slot_extracted=True, extracted_value="Bot", default_value=None + ), + email=ExtractedValueSlot.model_construct( + is_slot_extracted=True, extracted_value="bot@bot", default_value=None + ), + ), + True, + ), + ( + Message(text="I am Bot. I won't tell you my email"), + GroupSlot( + name=RegexpSlot(regexp=r"(?<=am ).+?(?=\.)"), + email=RegexpSlot(regexp=r"[a-zA-Z\.]+@[a-zA-Z\.]+"), + ), + ExtractedGroupSlot( + name=ExtractedValueSlot.model_construct( + is_slot_extracted=True, extracted_value="Bot", default_value=None + ), + email=ExtractedValueSlot.model_construct( + is_slot_extracted=False, + extracted_value=SlotNotExtracted( + "Failed to match pattern {regexp!r} in {request_text!r}.".format( + regexp=r"[a-zA-Z\.]+@[a-zA-Z\.]+", request_text="I am Bot. I won't tell you my email" + ) + ), + default_value=None, + ), + ), + False, + ), + ], +) +async def test_group_slot_extraction(user_request, slot, expected, is_extracted, context, pipeline): + context.add_request(user_request) + result = await slot.get_value(context, pipeline) + assert result == expected + assert result.__slot_extracted__ == is_extracted + + +@pytest.mark.parametrize("forbidden_name", ["__dunder__", "contains.dot"]) +def test_group_subslot_name_validation(forbidden_name): + with pytest.raises(ValidationError): + GroupSlot(**{forbidden_name: RegexpSlot(regexp="")}) + + +async def test_str_representation(): + assert ( + str(ExtractedValueSlot.model_construct(is_slot_extracted=True, extracted_value="hello", default_value=None)) + == "hello" + ) + assert ( + str(ExtractedValueSlot.model_construct(is_slot_extracted=False, extracted_value=None, default_value="hello")) + == "hello" + ) + assert ( + str( + ExtractedGroupSlot( + first_name=ExtractedValueSlot.model_construct( + is_slot_extracted=True, extracted_value="Tom", default_value="John" + ), + last_name=ExtractedValueSlot.model_construct( + is_slot_extracted=False, extracted_value=None, default_value="Smith" + ), + ) + ) + == "{'first_name': 'Tom', 'last_name': 'Smith'}" + ) diff --git a/tests/slots/test_tutorials.py b/tests/slots/test_tutorials.py new file mode 100644 index 000000000..f85649eb8 --- /dev/null +++ b/tests/slots/test_tutorials.py @@ -0,0 +1,20 @@ +import importlib +import pytest +from tests.test_utils import get_path_from_tests_to_current_dir +from dff.utils.testing.common import check_happy_path + + +dot_path_to_addon = get_path_from_tests_to_current_dir(__file__, separator=".") + + +@pytest.mark.parametrize( + "tutorial_module_name", + [ + "1_basic_example", + ], +) +def test_examples(tutorial_module_name): + module = importlib.import_module(f"tutorials.{dot_path_to_addon}.{tutorial_module_name}") + pipeline = getattr(module, "pipeline") + happy_path = getattr(module, "HAPPY_PATH") + check_happy_path(pipeline, happy_path) diff --git a/tests/utils/test_serialization.py b/tests/utils/test_serialization.py index 334b8f14a..7e1dc0518 100644 --- a/tests/utils/test_serialization.py +++ b/tests/utils/test_serialization.py @@ -2,6 +2,7 @@ import pytest from pydantic import BaseModel +from copy import deepcopy import dff.utils.devel.json_serialization as json_ser @@ -63,7 +64,11 @@ def test_pickle(self, unserializable_obj): assert json_ser.pickle_validator(serialized) == unserializable_obj def test_json_pickle(self, unserializable_dict, non_serializable_fields, deserialized_dict): - serialized = json_ser.json_pickle_serializer(unserializable_dict) + dict_copy = deepcopy(unserializable_dict) + + serialized = json_ser.json_pickle_serializer(dict_copy) + + assert dict_copy == unserializable_dict, "Dict changed by serializer" assert serialized[json_ser._JSON_EXTRA_FIELDS_KEYS] == non_serializable_fields assert all(isinstance(serialized[field], str) for field in non_serializable_fields) @@ -80,7 +85,11 @@ class Class(BaseModel): obj = Class() obj.field = unserializable_obj - dump = obj.model_dump(mode="json") + obj_copy = obj.model_copy(deep=True) + + dump = obj_copy.model_dump(mode="json") + + assert obj == obj_copy, "Object changed by serializer" assert isinstance(dump["field"], str) @@ -94,7 +103,12 @@ class Class(BaseModel): obj = Class(field=unserializable_dict) - dump = obj.model_dump(mode="json") + obj_copy = obj.model_copy(deep=True) + + dump = obj_copy.model_dump(mode="json") + + assert obj == obj_copy, "Object changed by serializer" + assert dump["field"][json_ser._JSON_EXTRA_FIELDS_KEYS] == non_serializable_fields reconstructed_obj = Class.model_validate(dump) @@ -107,7 +121,12 @@ class Class(json_ser.JSONSerializableExtras): obj = Class(**unserializable_dict) - dump = obj.model_dump(mode="json") + obj_copy = obj.model_copy(deep=True) + + dump = obj_copy.model_dump(mode="json") + + assert obj == obj_copy, "Object changed by serializer" + assert dump[json_ser._JSON_EXTRA_FIELDS_KEYS] == non_serializable_fields reconstructed_obj = Class.model_validate(dump) diff --git a/tutorials/slots/1_basic_example.py b/tutorials/slots/1_basic_example.py new file mode 100644 index 000000000..bc07b32b5 --- /dev/null +++ b/tutorials/slots/1_basic_example.py @@ -0,0 +1,236 @@ +# %% [markdown] +""" +# 1. Basic Example + +The following tutorial shows basic usage of slots extraction +module packaged with `dff`. +""" + +# %pip install dff + +# %% +from dff.script import conditions as cnd +from dff.script import ( + RESPONSE, + TRANSITIONS, + PRE_TRANSITIONS_PROCESSING, + PRE_RESPONSE_PROCESSING, + GLOBAL, + LOCAL, + Message, +) + +from dff.pipeline import Pipeline +from dff.slots import GroupSlot, RegexpSlot +from dff.slots import processing as slot_procs +from dff.slots import response as slot_rsp +from dff.slots import conditions as slot_cnd + +from dff.utils.testing import ( + check_happy_path, + is_interactive_mode, + run_interactive_mode, +) + +# %% [markdown] +""" +The slots fall into the following category groups: + +- Value slots can be used to extract slot values from user utterances. +- Group slots can be used to split value slots into groups + with an arbitrary level of nesting. + +You can build the slot tree by passing the child slot instances as extra fields +of the parent slot. In the following cell, we define two slot groups: + + Group 1: person.username, person.email + Group 2: friend.first_name, friend.last_name + +Currently there are two types of value slots: + +- %mddoclink(api,slots.slots,RegexpSlot): + Extracts slot values via regexp. +- %mddoclink(api,slots.slots,FunctionSlot): + Extracts slot values with the help of a user-defined function. +""" + +# %% +SLOTS = GroupSlot( + person=GroupSlot( + username=RegexpSlot( + regexp=r"username is ([a-zA-Z]+)", + match_group_idx=1, + ), + email=RegexpSlot( + regexp=r"email is ([a-z@\.A-Z]+)", + match_group_idx=1, + ), + ), + friend=GroupSlot( + first_name=RegexpSlot(regexp=r"^[A-Z][a-z]+?(?= )"), + last_name=RegexpSlot(regexp=r"(?<= )[A-Z][a-z]+"), + ), +) + +# %% [markdown] +""" +The slots module provides several functions for managing slots in-script: + +- %mddoclink(api,slots.conditions,slots_extracted): + Condition for checking if specified slots are extracted. +- %mddoclink(api,slots.processing,extract): + A processing function that extracts specified slots. +- %mddoclink(api,slots.processing,extract_all): + A processing function that extracts all slots. +- %mddoclink(api,slots.processing,unset): + A processing function that marks specified slots as not extracted, + effectively resetting their state. +- %mddoclink(api,slots.processing,unset_all): + A processing function that marks all slots as not extracted. +- %mddoclink(api,slots.processing,fill_template): + A processing function that fills the `response` + Message text with extracted slot values. +- %mddoclink(api,slots.response,filled_template): + A response function that takes a Message with a + format-string text and returns Message + with its text string filled with extracted slot values. + +The usage of all the above functions is shown in the following script: +""" + +# %% +script = { + GLOBAL: {TRANSITIONS: {("username_flow", "ask"): cnd.regexp(r"^[sS]tart")}}, + "username_flow": { + LOCAL: { + PRE_TRANSITIONS_PROCESSING: { + "get_slot": slot_procs.extract("person.username") + }, + TRANSITIONS: { + ("email_flow", "ask", 1.2): slot_cnd.slots_extracted( + "person.username" + ), + ("username_flow", "repeat_question", 0.8): cnd.true(), + }, + }, + "ask": { + RESPONSE: Message(text="Write your username (my username is ...):"), + }, + "repeat_question": { + RESPONSE: Message( + text="Please, type your username again (my username is ...):" + ) + }, + }, + "email_flow": { + LOCAL: { + PRE_TRANSITIONS_PROCESSING: { + "get_slot": slot_procs.extract("person.email") + }, + TRANSITIONS: { + ("friend_flow", "ask", 1.2): slot_cnd.slots_extracted( + "person.username", "person.email" + ), + ("email_flow", "repeat_question", 0.8): cnd.true(), + }, + }, + "ask": { + RESPONSE: Message(text="Write your email (my email is ...):"), + }, + "repeat_question": { + RESPONSE: Message( + text="Please, write your email again (my email is ...):" + ) + }, + }, + "friend_flow": { + LOCAL: { + PRE_TRANSITIONS_PROCESSING: { + "get_slots": slot_procs.extract("friend") + }, + TRANSITIONS: { + ("root", "utter", 1.2): slot_cnd.slots_extracted( + "friend.first_name", "friend.last_name", mode="any" + ), + ("friend_flow", "repeat_question", 0.8): cnd.true(), + }, + }, + "ask": { + RESPONSE: Message( + text="Please, name me one of your friends: (John Doe)" + ) + }, + "repeat_question": { + RESPONSE: Message( + text="Please, name me one of your friends again: (John Doe)" + ) + }, + }, + "root": { + "start": { + RESPONSE: Message(text=""), + TRANSITIONS: {("username_flow", "ask"): cnd.true()}, + }, + "fallback": { + RESPONSE: Message(text="Finishing query"), + TRANSITIONS: {("username_flow", "ask"): cnd.true()}, + }, + "utter": { + RESPONSE: slot_rsp.filled_template( + Message( + text="Your friend is {friend.first_name} {friend.last_name}" + ) + ), + TRANSITIONS: {("root", "utter_alternative"): cnd.true()}, + }, + "utter_alternative": { + RESPONSE: Message( + text="Your username is {person.username}. " + "Your email is {person.email}." + ), + PRE_RESPONSE_PROCESSING: {"fill": slot_procs.fill_template()}, + TRANSITIONS: {("root", "fallback"): cnd.true()}, + }, + }, +} + +# %% +HAPPY_PATH = [ + ( + Message(text="hi"), + Message(text="Write your username (my username is ...):"), + ), + ( + Message(text="my username is groot"), + Message(text="Write your email (my email is ...):"), + ), + ( + Message(text="my email is groot@gmail.com"), + Message(text="Please, name me one of your friends: (John Doe)"), + ), + (Message(text="Bob Page"), Message(text="Your friend is Bob Page")), + ( + Message(text="ok"), + Message(text="Your username is groot. Your email is groot@gmail.com."), + ), + (Message(text="ok"), Message(text="Finishing query")), +] + +# %% +pipeline = Pipeline.from_script( + script, + start_label=("root", "start"), + fallback_label=("root", "fallback"), + slots=SLOTS, +) + +if __name__ == "__main__": + check_happy_path( + pipeline, HAPPY_PATH + ) # This is a function for automatic tutorial running + # (testing) with HAPPY_PATH + + # This runs tutorial in interactive mode if not in IPython env + # and if `DISABLE_INTERACTIVE_MODE` is not set + if is_interactive_mode(): + run_interactive_mode(pipeline) From a2ba8fcfdf13e10d1fa407a758cbe2df425a6234 Mon Sep 17 00:00:00 2001 From: Roman Zlobin Date: Wed, 3 Jul 2024 14:48:42 +0300 Subject: [PATCH 24/31] Replace dff with chatsky (#368) --- .github/workflows/update_dashboard.yml | 6 +- CONTRIBUTING.md | 10 +- README.md | 80 +++++------ {dff => chatsky}/__init__.py | 6 +- chatsky/__rebuild_pydantic_models__.py | 9 ++ {dff => chatsky}/config/README.md | 4 +- .../Current_topic_slot_bar_chart_4.yaml | 0 ...Current_topic_time_series_bar_chart_2.yaml | 0 .../charts/Flow_visit_ratio_monitor_13.yaml | 0 .../charts/Node_Visits_7.yaml | 0 .../charts/Node_counts_3.yaml | 0 .../charts/Node_visit_ratio_monitor_8.yaml | 0 .../charts/Node_visits_ratio_6.yaml | 0 .../charts/Node_visits_sunburst_5.yaml | 0 .../charts/Rating_slot_line_chart_1.yaml | 0 .../charts/Requests_17.yaml | 0 .../charts/Responses_16.yaml | 0 .../charts/Service_load_users_9.yaml | 0 .../superset_dashboard/charts/Table_14.yaml | 0 .../charts/Terminal_labels_15.yaml | 0 .../charts/Transition_counts_12.yaml | 0 .../charts/Transition_layout_10.yaml | 0 .../charts/Transition_ratio_chord_11.yaml | 0 .../chatsky_statistics_dashboard_1.yaml | 10 +- .../databases/chatsky_database.yaml | 2 +- .../chatsky_database/chatsky_final_nodes.yaml | 2 +- .../chatsky_database/chatsky_node_stats.yaml | 2 +- .../chatsky_database/chatsky_stats.yaml | 2 +- .../config/superset_dashboard/metadata.yaml | 0 {dff => chatsky}/context_storages/__init__.py | 0 {dff => chatsky}/context_storages/database.py | 4 +- {dff => chatsky}/context_storages/json.py | 4 +- {dff => chatsky}/context_storages/mongo.py | 4 +- {dff => chatsky}/context_storages/pickle.py | 4 +- {dff => chatsky}/context_storages/protocol.py | 8 +- .../context_storages/protocols.json | 0 {dff => chatsky}/context_storages/redis.py | 4 +- {dff => chatsky}/context_storages/shelve.py | 4 +- {dff => chatsky}/context_storages/sql.py | 4 +- {dff => chatsky}/context_storages/ydb.py | 4 +- {dff => chatsky}/messengers/__init__.py | 0 .../messengers/common/__init__.py | 0 .../messengers/common/interface.py | 20 +-- {dff => chatsky}/messengers/common/types.py | 2 +- {dff => chatsky}/messengers/console.py | 10 +- .../messengers/telegram/__init__.py | 0 .../messengers/telegram/abstract.py | 24 ++-- .../messengers/telegram/interface.py | 2 +- {dff => chatsky}/pipeline/__init__.py | 0 {dff => chatsky}/pipeline/conditions.py | 4 +- .../pipeline/pipeline/__init__.py | 0 {dff => chatsky}/pipeline/pipeline/actor.py | 32 ++--- .../pipeline/pipeline/component.py | 8 +- .../pipeline/pipeline/pipeline.py | 44 +++--- {dff => chatsky}/pipeline/pipeline/utils.py | 0 {dff => chatsky}/pipeline/service/__init__.py | 0 {dff => chatsky}/pipeline/service/extra.py | 6 +- {dff => chatsky}/pipeline/service/group.py | 4 +- {dff => chatsky}/pipeline/service/service.py | 6 +- {dff => chatsky}/pipeline/service/utils.py | 2 +- {dff => chatsky}/pipeline/types.py | 16 +-- {dff => chatsky}/script/__init__.py | 0 .../script/conditions/__init__.py | 0 .../script/conditions/std_conditions.py | 6 +- {dff => chatsky}/script/core/__init__.py | 0 {dff => chatsky}/script/core/context.py | 14 +- {dff => chatsky}/script/core/keywords.py | 8 +- {dff => chatsky}/script/core/message.py | 40 +++--- {dff => chatsky}/script/core/normalization.py | 4 +- {dff => chatsky}/script/core/script.py | 6 +- {dff => chatsky}/script/core/types.py | 2 +- {dff => chatsky}/script/extras/__init__.py | 0 .../script/extras/conditions/__init__.py | 0 .../script/extras/slots/__init__.py | 0 {dff => chatsky}/script/labels/__init__.py | 0 {dff => chatsky}/script/labels/std_labels.py | 40 +++--- {dff => chatsky}/script/responses/__init__.py | 0 .../script/responses/std_responses.py | 4 +- chatsky/slots/__init__.py | 7 + {dff => chatsky}/slots/conditions.py | 6 +- {dff => chatsky}/slots/processing.py | 8 +- {dff => chatsky}/slots/response.py | 6 +- {dff => chatsky}/slots/slots.py | 10 +- {dff => chatsky}/stats/__init__.py | 0 {dff => chatsky}/stats/__main__.py | 4 +- {dff => chatsky}/stats/cli.py | 28 ++-- {dff => chatsky}/stats/default_extractors.py | 4 +- {dff => chatsky}/stats/instrumentor.py | 22 +-- {dff => chatsky}/stats/utils.py | 8 +- {dff => chatsky}/utils/__init__.py | 0 chatsky/utils/db_benchmark/__init__.py | 11 ++ .../utils/db_benchmark/basic_config.py | 4 +- .../utils/db_benchmark/benchmark.py | 16 +-- {dff => chatsky}/utils/db_benchmark/report.py | 2 +- {dff => chatsky}/utils/devel/__init__.py | 0 {dff => chatsky}/utils/devel/async_helpers.py | 0 .../utils/devel/extra_field_helpers.py | 0 .../utils/devel/json_serialization.py | 0 chatsky/utils/docker/README.md | 11 ++ .../utils/docker/dockerfile_stats | 0 .../utils/docker/entrypoint_stats.sh | 0 .../utils/docker/superset_config_docker.py | 0 .../utils/otel/otelcol-config-extras.yml | 0 .../utils/otel/otelcol-config.yml | 0 {dff => chatsky}/utils/parser/__init__.py | 0 {dff => chatsky}/utils/testing/__init__.py | 2 +- {dff => chatsky}/utils/testing/cleanup_db.py | 2 +- {dff => chatsky}/utils/testing/common.py | 6 +- .../utils/testing/response_comparers.py | 2 +- {dff => chatsky}/utils/testing/toy_script.py | 6 +- .../utils/turn_caching/__init__.py | 0 .../turn_caching/singleton_turn_caching.py | 0 {dff => chatsky}/utils/viewer/__init__.py | 0 compose.yml | 6 +- dff/__rebuild_pydantic_models__.py | 9 -- dff/slots/__init__.py | 7 - dff/utils/db_benchmark/__init__.py | 11 -- dff/utils/docker/README.md | 11 -- docs/source/_templates/example-links.html | 4 +- docs/source/_templates/source-links.html | 2 +- docs/source/about_us.rst | 2 +- docs/source/community.rst | 16 +-- docs/source/conf.py | 30 ++-- docs/source/development.rst | 12 +- .../{dfe => core}/user_actor.drawio | 0 docs/source/get_started.rst | 42 +++--- docs/source/index.rst | 18 +-- docs/source/tutorials.rst | 12 +- docs/source/user_guides.rst | 8 +- docs/source/user_guides/basic_conceptions.rst | 44 +++--- docs/source/user_guides/context_guide.rst | 38 ++--- .../source/user_guides/optimization_guide.rst | 8 +- docs/source/user_guides/slot_extraction.rst | 34 ++--- docs/source/user_guides/superset_guide.rst | 34 ++--- docs/source/utils/notebook.py | 10 +- poetry.lock | 82 +++++------ pyproject.toml | 22 +-- scripts/codestyle.py | 2 +- scripts/doc.py | 2 +- scripts/misc.py | 2 +- scripts/test.py | 2 +- tests/context_storages/conftest.py | 2 +- tests/context_storages/test_dbs.py | 14 +- .../messengers/telegram/test_happy_paths.json | 132 +++++++++--------- tests/messengers/telegram/test_tutorials.py | 4 +- tests/messengers/telegram/utils.py | 6 +- tests/pipeline/test_messenger_interface.py | 12 +- tests/pipeline/test_parallel_processing.py | 4 +- tests/pipeline/test_pipeline.py | 8 +- tests/pipeline/test_update_ctx_misc.py | 4 +- tests/script/conditions/test_conditions.py | 6 +- tests/script/core/test_actor.py | 8 +- tests/script/core/test_context.py | 2 +- tests/script/core/test_message.py | 12 +- tests/script/core/test_normalization.py | 10 +- tests/script/core/test_script.py | 4 +- tests/script/core/test_validation.py | 6 +- tests/script/labels/test_labels.py | 6 +- tests/script/responses/test_responses.py | 6 +- tests/slots/conftest.py | 8 +- tests/slots/test_slot_manager.py | 4 +- tests/slots/test_slot_types.py | 4 +- tests/slots/test_tutorials.py | 2 +- tests/stats/conftest.py | 4 +- tests/stats/test_defaults.py | 12 +- tests/stats/test_instrumentation.py | 4 +- tests/stats/test_main.py | 24 ++-- tests/stats/test_tutorials.py | 14 +- tests/tutorials/test_format.py | 25 ++-- tests/tutorials/test_tutorials.py | 10 +- tests/tutorials/test_utils.py | 2 +- tests/utils/test_benchmark.py | 10 +- tests/utils/test_serialization.py | 2 +- tutorials/context_storages/1_basics.py | 10 +- tutorials/context_storages/2_postgresql.py | 12 +- tutorials/context_storages/3_mongodb.py | 12 +- tutorials/context_storages/4_redis.py | 12 +- tutorials/context_storages/5_mysql.py | 12 +- tutorials/context_storages/6_sqlite.py | 12 +- .../context_storages/7_yandex_database.py | 12 +- .../context_storages/8_db_benchmarking.py | 10 +- tutorials/messengers/telegram/1_basic.py | 18 +-- .../messengers/telegram/2_attachments.py | 17 ++- tutorials/messengers/telegram/3_advanced.py | 23 ++- .../messengers/web_api_interface/1_fastapi.py | 12 +- .../web_api_interface/2_websocket_chat.py | 10 +- .../3_load_testing_with_locust.py | 8 +- .../web_api_interface/4_streamlit_chat.py | 10 +- tutorials/pipeline/1_basics.py | 12 +- .../pipeline/2_pre_and_post_processors.py | 12 +- .../3_pipeline_dict_with_services_basic.py | 8 +- .../3_pipeline_dict_with_services_full.py | 12 +- .../pipeline/4_groups_and_conditions_basic.py | 8 +- .../pipeline/4_groups_and_conditions_full.py | 8 +- ..._asynchronous_groups_and_services_basic.py | 8 +- ...5_asynchronous_groups_and_services_full.py | 10 +- tutorials/pipeline/6_extra_handlers_basic.py | 15 +- tutorials/pipeline/6_extra_handlers_full.py | 10 +- .../7_extra_handlers_and_extensions.py | 8 +- tutorials/script/core/1_basics.py | 12 +- tutorials/script/core/2_conditions.py | 16 +-- tutorials/script/core/3_responses.py | 14 +- tutorials/script/core/4_transitions.py | 16 +-- tutorials/script/core/5_global_transitions.py | 14 +- .../script/core/6_context_serialization.py | 12 +- .../script/core/7_pre_response_processing.py | 14 +- tutorials/script/core/8_misc.py | 14 +- .../core/9_pre_transitions_processing.py | 14 +- tutorials/script/responses/1_basics.py | 12 +- tutorials/script/responses/2_media.py | 12 +- tutorials/script/responses/3_multi_message.py | 12 +- tutorials/slots/1_basic_example.py | 20 +-- tutorials/stats/1_extractor_functions.py | 22 +-- tutorials/stats/2_pipeline_integration.py | 26 ++-- tutorials/utils/1_cache.py | 14 +- tutorials/utils/2_lru_cache.py | 14 +- utils/db_benchmark/benchmark_dbs.py | 2 +- utils/db_benchmark/benchmark_streamlit.py | 2 +- utils/stats/sample_data_provider.py | 16 +-- .../telegram_tutorial_data.py | 2 +- 220 files changed, 1035 insertions(+), 1029 deletions(-) rename {dff => chatsky}/__init__.py (56%) create mode 100644 chatsky/__rebuild_pydantic_models__.py rename {dff => chatsky}/config/README.md (73%) rename {dff => chatsky}/config/superset_dashboard/charts/Current_topic_slot_bar_chart_4.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Current_topic_time_series_bar_chart_2.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Flow_visit_ratio_monitor_13.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Node_Visits_7.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Node_counts_3.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Node_visit_ratio_monitor_8.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Node_visits_ratio_6.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Node_visits_sunburst_5.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Rating_slot_line_chart_1.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Requests_17.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Responses_16.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Service_load_users_9.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Table_14.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Terminal_labels_15.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Transition_counts_12.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Transition_layout_10.yaml (100%) rename {dff => chatsky}/config/superset_dashboard/charts/Transition_ratio_chord_11.yaml (100%) rename dff/config/superset_dashboard/dashboards/DFF_statistics_dashboard_1.yaml => chatsky/config/superset_dashboard/dashboards/chatsky_statistics_dashboard_1.yaml (99%) rename dff/config/superset_dashboard/databases/dff_database.yaml => chatsky/config/superset_dashboard/databases/chatsky_database.yaml (91%) rename dff/config/superset_dashboard/datasets/dff_database/dff_final_nodes.yaml => chatsky/config/superset_dashboard/datasets/chatsky_database/chatsky_final_nodes.yaml (98%) rename dff/config/superset_dashboard/datasets/dff_database/dff_node_stats.yaml => chatsky/config/superset_dashboard/datasets/chatsky_database/chatsky_node_stats.yaml (98%) rename dff/config/superset_dashboard/datasets/dff_database/dff_stats.yaml => chatsky/config/superset_dashboard/datasets/chatsky_database/chatsky_stats.yaml (99%) rename {dff => chatsky}/config/superset_dashboard/metadata.yaml (100%) rename {dff => chatsky}/context_storages/__init__.py (100%) rename {dff => chatsky}/context_storages/database.py (98%) rename {dff => chatsky}/context_storages/json.py (97%) rename {dff => chatsky}/context_storages/mongo.py (97%) rename {dff => chatsky}/context_storages/pickle.py (96%) rename {dff => chatsky}/context_storages/protocol.py (86%) rename {dff => chatsky}/context_storages/protocols.json (100%) rename {dff => chatsky}/context_storages/redis.py (96%) rename {dff => chatsky}/context_storages/shelve.py (94%) rename {dff => chatsky}/context_storages/sql.py (98%) rename {dff => chatsky}/context_storages/ydb.py (98%) rename {dff => chatsky}/messengers/__init__.py (100%) rename {dff => chatsky}/messengers/common/__init__.py (100%) rename {dff => chatsky}/messengers/common/interface.py (89%) rename {dff => chatsky}/messengers/common/types.py (94%) rename {dff => chatsky}/messengers/console.py (84%) rename {dff => chatsky}/messengers/telegram/__init__.py (100%) rename {dff => chatsky}/messengers/telegram/abstract.py (97%) rename {dff => chatsky}/messengers/telegram/interface.py (97%) rename {dff => chatsky}/pipeline/__init__.py (100%) rename {dff => chatsky}/pipeline/conditions.py (97%) rename {dff => chatsky}/pipeline/pipeline/__init__.py (100%) rename {dff => chatsky}/pipeline/pipeline/actor.py (93%) rename {dff => chatsky}/pipeline/pipeline/component.py (97%) rename {dff => chatsky}/pipeline/pipeline/pipeline.py (91%) rename {dff => chatsky}/pipeline/pipeline/utils.py (100%) rename {dff => chatsky}/pipeline/service/__init__.py (100%) rename {dff => chatsky}/pipeline/service/extra.py (98%) rename {dff => chatsky}/pipeline/service/group.py (99%) rename {dff => chatsky}/pipeline/service/service.py (98%) rename {dff => chatsky}/pipeline/service/utils.py (98%) rename {dff => chatsky}/pipeline/types.py (94%) rename {dff => chatsky}/script/__init__.py (100%) rename {dff => chatsky}/script/conditions/__init__.py (100%) rename {dff => chatsky}/script/conditions/std_conditions.py (98%) rename {dff => chatsky}/script/core/__init__.py (100%) rename {dff => chatsky}/script/core/context.py (96%) rename {dff => chatsky}/script/core/keywords.py (93%) rename {dff => chatsky}/script/core/message.py (87%) rename {dff => chatsky}/script/core/normalization.py (97%) rename {dff => chatsky}/script/core/script.py (98%) rename {dff => chatsky}/script/core/types.py (97%) rename {dff => chatsky}/script/extras/__init__.py (100%) rename {dff => chatsky}/script/extras/conditions/__init__.py (100%) rename {dff => chatsky}/script/extras/slots/__init__.py (100%) rename {dff => chatsky}/script/labels/__init__.py (100%) rename {dff => chatsky}/script/labels/std_labels.py (82%) rename {dff => chatsky}/script/responses/__init__.py (100%) rename {dff => chatsky}/script/responses/std_responses.py (91%) create mode 100644 chatsky/slots/__init__.py rename {dff => chatsky}/slots/conditions.py (87%) rename {dff => chatsky}/slots/processing.py (91%) rename {dff => chatsky}/slots/response.py (88%) rename {dff => chatsky}/slots/slots.py (97%) rename {dff => chatsky}/stats/__init__.py (100%) rename {dff => chatsky}/stats/__main__.py (98%) rename {dff => chatsky}/stats/cli.py (93%) rename {dff => chatsky}/stats/default_extractors.py (96%) rename {dff => chatsky}/stats/instrumentor.py (93%) rename {dff => chatsky}/stats/utils.py (97%) rename {dff => chatsky}/utils/__init__.py (100%) create mode 100644 chatsky/utils/db_benchmark/__init__.py rename {dff => chatsky}/utils/db_benchmark/basic_config.py (98%) rename {dff => chatsky}/utils/db_benchmark/benchmark.py (97%) rename {dff => chatsky}/utils/db_benchmark/report.py (96%) rename {dff => chatsky}/utils/devel/__init__.py (100%) rename {dff => chatsky}/utils/devel/async_helpers.py (100%) rename {dff => chatsky}/utils/devel/extra_field_helpers.py (100%) rename {dff => chatsky}/utils/devel/json_serialization.py (100%) create mode 100644 chatsky/utils/docker/README.md rename {dff => chatsky}/utils/docker/dockerfile_stats (100%) rename {dff => chatsky}/utils/docker/entrypoint_stats.sh (100%) rename {dff => chatsky}/utils/docker/superset_config_docker.py (100%) rename {dff => chatsky}/utils/otel/otelcol-config-extras.yml (100%) rename {dff => chatsky}/utils/otel/otelcol-config.yml (100%) rename {dff => chatsky}/utils/parser/__init__.py (100%) rename {dff => chatsky}/utils/testing/__init__.py (79%) rename {dff => chatsky}/utils/testing/cleanup_db.py (98%) rename {dff => chatsky}/utils/testing/common.py (96%) rename {dff => chatsky}/utils/testing/response_comparers.py (93%) rename {dff => chatsky}/utils/testing/toy_script.py (96%) rename {dff => chatsky}/utils/turn_caching/__init__.py (100%) rename {dff => chatsky}/utils/turn_caching/singleton_turn_caching.py (100%) rename {dff => chatsky}/utils/viewer/__init__.py (100%) delete mode 100644 dff/__rebuild_pydantic_models__.py delete mode 100644 dff/slots/__init__.py delete mode 100644 dff/utils/db_benchmark/__init__.py delete mode 100644 dff/utils/docker/README.md rename docs/source/drawio_src/{dfe => core}/user_actor.drawio (100%) diff --git a/.github/workflows/update_dashboard.yml b/.github/workflows/update_dashboard.yml index 72042885f..34e447967 100644 --- a/.github/workflows/update_dashboard.yml +++ b/.github/workflows/update_dashboard.yml @@ -5,7 +5,7 @@ on: branches: - 'master' paths: - - 'dff/utils/docker/**' + - 'chatsky/utils/docker/**' workflow_dispatch: concurrency: @@ -41,7 +41,7 @@ jobs: - name: Build and upload image uses: docker/build-push-action@v5 with: - context: dff/utils/docker - file: dff/utils/docker/dockerfile_stats + context: chatsky/utils/docker + file: chatsky/utils/docker/dockerfile_stats tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 75347a0dc..80cfe0fe9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,10 +1,10 @@ ## Introduction We will be glad to receive your pull requests (PRs) and issues for adding new features if you are missing something. -We always look forward to your contributions to the Dialog Flow Framework (DFF). +We always look forward to your contributions to Chatsky. ## Rules for submitting a PR -All PRs are reviewed by DFF developers team. +All PRs are reviewed by Chatsky developers team. In order to make the job of reviewing easier and increase the chance that your PR will be accepted, please add a short description with information about why this PR is needed and what changes will be made. Please use the following rules to write the names of branches and commit messages. @@ -83,11 +83,11 @@ to the local documentation and verified during build. - `%pip install {args}` This directive generates dependency installation cell, adds a comment and sets up "quiet" flag. - It should be used in tutorials, like this: `# %pip install dff[...]`. + It should be used in tutorials, like this: `# %pip install chatsky[...]`. - `%doclink({args})` This directive generates a documentation link. It supports 2 or three arguments and the generated link will look like: `ARG1/ARG2#ARG3`. - The first argument can be either `api` for DFF codebase, `tutorial` for tutorials or `guide` for user guides. + The first argument can be either `api` for Chatsky codebase, `tutorial` for tutorials or `guide` for user guides. - `%mddoclink({args})` This directive is a shortcut for `%doclink` that generates a markdown format link instead. @@ -133,7 +133,7 @@ poetry run poe format Tests are configured via [`.env_file`](.env_file). ### Docker -DFF uses docker images for two purposes: +Chatsky uses docker images for two purposes: 1. Database images for integration testing. 2. Images for statistics collection. diff --git a/README.md b/README.md index 6b54cf43f..1358f08bb 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,35 @@ -# Dialog Flow Framework +# Chatsky -[![Documentation Status](https://github.com/deeppavlov/dialog_flow_framework/workflows/build_and_publish_docs/badge.svg?branch=dev)](https://deeppavlov.github.io/dialog_flow_framework) -[![Codestyle](https://github.com/deeppavlov/dialog_flow_framework/workflows/codestyle/badge.svg?branch=dev)](https://github.com/deeppavlov/dialog_flow_framework/actions/workflows/codestyle.yml) -[![Tests](https://github.com/deeppavlov/dialog_flow_framework/workflows/test_coverage/badge.svg?branch=dev)](https://github.com/deeppavlov/dialog_flow_framework/actions/workflows/test_coverage.yml) -[![License Apache 2.0](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/deeppavlov/dialog_flow_framework/blob/master/LICENSE) +[![Documentation Status](https://github.com/deeppavlov/chatsky/workflows/build_and_publish_docs/badge.svg?branch=dev)](https://deeppavlov.github.io/chatsky) +[![Codestyle](https://github.com/deeppavlov/chatsky/workflows/codestyle/badge.svg?branch=dev)](https://github.com/deeppavlov/chatsky/actions/workflows/codestyle.yml) +[![Tests](https://github.com/deeppavlov/chatsky/workflows/test_coverage/badge.svg?branch=dev)](https://github.com/deeppavlov/chatsky/actions/workflows/test_coverage.yml) +[![License Apache 2.0](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/deeppavlov/chatsky/blob/master/LICENSE) ![Python 3.8, 3.9, 3.10, 3.11](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11-green.svg) -[![PyPI](https://img.shields.io/pypi/v/dff)](https://pypi.org/project/dff/) -[![Downloads](https://pepy.tech/badge/dff)](https://pepy.tech/project/dff) +[![PyPI](https://img.shields.io/pypi/v/chatsky)](https://pypi.org/project/chatsky/) +[![Downloads](https://pepy.tech/badge/chatsky)](https://pepy.tech/project/chatsky) -The Dialog Flow Framework (DFF) allows you to develop conversational services. -DFF offers a specialized domain-specific language (DSL) for quickly writing dialogs in pure Python. The service is created by defining a special dialog graph that determines the behavior of the dialog agent. The latter is then leveraged in the DFF pipeline. +Chatsky allows you to develop conversational services. +Chatsky offers a specialized domain-specific language (DSL) for quickly writing dialogs in pure Python. The service is created by defining a special dialog graph that determines the behavior of the dialog agent. The latter is then leveraged in the Chatsky pipeline. You can use the framework in various services such as social networks, call centers, websites, personal assistants, etc. -DFF, a versatile Python-based conversational service framework, can be deployed across a spectrum of platforms, +Chatsky, a versatile Python-based conversational service framework, can be deployed across a spectrum of platforms, ensuring flexibility for both novice and seasoned developers: -- Cloud platforms like AWS, Azure, and GCP offer scalable environments for DFF, +- Cloud platforms like AWS, Azure, and GCP offer scalable environments for Chatsky, with options such as AWS Lambda and Azure Functions providing serverless execution. -- For containerized deployment, Docker and Kubernetes streamline the orchestration of DFF applications. +- For containerized deployment, Docker and Kubernetes streamline the orchestration of Chatsky applications. - Furthermore, the framework's adaptability extends to IoT ecosystems, making it suitable for integration with edge devices in scenarios like smart homes or industrial automation. Whether deployed on cloud platforms, containerized environments, or directly on IoT devices, -DFF's accessibility and customization options make it a robust choice for developing conversational services +Chatsky's accessibility and customization options make it a robust choice for developing conversational services in the evolving landscape of Python applications and IoT connectivity. -## Why choose DFF +## Why choose Chatsky * Written in pure Python, the framework is easily accessible for both beginners and experienced developers. -* For the same reason, all the abstractions used in DFF can be easily customized and extended using regular language synthax. -* DFF offers easy and straightforward tools for state management which is as easy as setting values of a Python dictionary. +* For the same reason, all the abstractions used in Chatsky can be easily customized and extended using regular language synthax. +* Chatsky offers easy and straightforward tools for state management which is as easy as setting values of a Python dictionary. * The framework is being actively maintained and thoroughly tested. The team is open to suggestions and quickly reacts to bug reports. # Quick Start @@ -44,31 +44,31 @@ in the evolving landscape of Python applications and IoT connectivity. ## Installation -DFF can be installed via pip: +Chatsky can be installed via pip: ```bash -pip install dff +pip install chatsky ``` -The above command will set the minimum dependencies to start working with DFF. +The above command will set the minimum dependencies to start working with Chatsky. The installation process allows the user to choose from different packages based on their dependencies, which are: ```bash -pip install dff[json] # dependencies for using JSON -pip install dff[pickle] # dependencies for using Pickle -pip install dff[redis] # dependencies for using Redis -pip install dff[mongodb] # dependencies for using MongoDB -pip install dff[mysql] # dependencies for using MySQL -pip install dff[postgresql] # dependencies for using PostgreSQL -pip install dff[sqlite] # dependencies for using SQLite -pip install dff[ydb] # dependencies for using Yandex Database -pip install dff[telegram] # dependencies for using Telegram -pip install dff[benchmark] # dependencies for benchmarking +pip install chatsky[json] # dependencies for using JSON +pip install chatsky[pickle] # dependencies for using Pickle +pip install chatsky[redis] # dependencies for using Redis +pip install chatsky[mongodb] # dependencies for using MongoDB +pip install chatsky[mysql] # dependencies for using MySQL +pip install chatsky[postgresql] # dependencies for using PostgreSQL +pip install chatsky[sqlite] # dependencies for using SQLite +pip install chatsky[ydb] # dependencies for using Yandex Database +pip install chatsky[telegram] # dependencies for using Telegram +pip install chatsky[benchmark] # dependencies for benchmarking ``` For example, if you are going to use one of the database backends, you can specify the corresponding requirements yourself. Multiple dependencies can be installed at once, e.g. ```bash -pip install dff[postgresql,mysql] +pip install chatsky[postgresql,mysql] ``` ## Basic example @@ -76,12 +76,12 @@ pip install dff[postgresql,mysql] The following code snippet builds a simplistic chat bot that replies with messages ``Hi!`` and ``OK`` depending on user input, which only takes a few lines of code. All the abstractions used in this example are thoroughly explained in the dedicated -[user guide](https://deeppavlov.github.io/dialog_flow_framework/user_guides/basic_conceptions.html). +[user guide](https://deeppavlov.github.io/chatsky/user_guides/basic_conceptions.html). ```python -from dff.script import GLOBAL, TRANSITIONS, RESPONSE, Message -from dff.pipeline import Pipeline -import dff.script.conditions.std_conditions as cnd +from chatsky.script import GLOBAL, TRANSITIONS, RESPONSE, Message +from chatsky.pipeline import Pipeline +import chatsky.script.conditions.std_conditions as cnd # create a dialog script script = { @@ -129,19 +129,19 @@ Response: OK ``` More advanced examples are available as a part of documentation: -[tutorials](https://deeppavlov.github.io/dialog_flow_framework/tutorials.html). +[tutorials](https://deeppavlov.github.io/chatsky/tutorials.html). ## Further steps -To further explore the API of the framework, you can make use of the [detailed documentation](https://deeppavlov.github.io/dialog_flow_framework/index.html). -Broken down into several sections to highlight all the aspects of development with DFF, +To further explore the API of the framework, you can make use of the [detailed documentation](https://deeppavlov.github.io/chatsky/index.html). +Broken down into several sections to highlight all the aspects of development with Chatsky, the documentation for the library is constantly available online. -# Contributing to the Dialog Flow Framework +# Contributing to Chatsky We are open to accepting pull requests and bug reports. -Please refer to [CONTRIBUTING.md](https://github.com/deeppavlov/dialog_flow_framework/blob/master/CONTRIBUTING.md). +Please refer to [CONTRIBUTING.md](https://github.com/deeppavlov/chatsky/blob/master/CONTRIBUTING.md). # License -DFF is distributed under the terms of the [Apache License 2.0](https://github.com/deeppavlov/dialog_flow_framework/blob/master/LICENSE). +Chatsky is distributed under the terms of the [Apache License 2.0](https://github.com/deeppavlov/chatsky/blob/master/LICENSE). diff --git a/dff/__init__.py b/chatsky/__init__.py similarity index 56% rename from dff/__init__.py rename to chatsky/__init__.py index 37b06376e..539647405 100644 --- a/dff/__init__.py +++ b/chatsky/__init__.py @@ -10,7 +10,7 @@ nest_asyncio.apply() -from dff.pipeline import Pipeline -from dff.script import Context, Script +from chatsky.pipeline import Pipeline +from chatsky.script import Context, Script -import dff.__rebuild_pydantic_models__ +import chatsky.__rebuild_pydantic_models__ diff --git a/chatsky/__rebuild_pydantic_models__.py b/chatsky/__rebuild_pydantic_models__.py new file mode 100644 index 000000000..6d4c5dd92 --- /dev/null +++ b/chatsky/__rebuild_pydantic_models__.py @@ -0,0 +1,9 @@ +# flake8: noqa: F401 + +from chatsky.pipeline import Pipeline +from chatsky.pipeline.types import ExtraHandlerRuntimeInfo +from chatsky.script import Context, Script + +Script.model_rebuild() +Context.model_rebuild() +ExtraHandlerRuntimeInfo.model_rebuild() diff --git a/dff/config/README.md b/chatsky/config/README.md similarity index 73% rename from dff/config/README.md rename to chatsky/config/README.md index f060b14d6..4a4c9f5e0 100644 --- a/dff/config/README.md +++ b/chatsky/config/README.md @@ -5,6 +5,6 @@ This directory provides yaml files for Superset dashboard configuration. The files inside are not supposed to be edited manually for lest of compatibility breaks. Placeholders inside the files will be filled automatically when you use the -`dff.stats` CLI command to generate a configuration archive. +`chatsky.stats` CLI command to generate a configuration archive. -Use `dff.stats -h` for more info. \ No newline at end of file +Use `chatsky.stats -h` for more info. \ No newline at end of file diff --git a/dff/config/superset_dashboard/charts/Current_topic_slot_bar_chart_4.yaml b/chatsky/config/superset_dashboard/charts/Current_topic_slot_bar_chart_4.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Current_topic_slot_bar_chart_4.yaml rename to chatsky/config/superset_dashboard/charts/Current_topic_slot_bar_chart_4.yaml diff --git a/dff/config/superset_dashboard/charts/Current_topic_time_series_bar_chart_2.yaml b/chatsky/config/superset_dashboard/charts/Current_topic_time_series_bar_chart_2.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Current_topic_time_series_bar_chart_2.yaml rename to chatsky/config/superset_dashboard/charts/Current_topic_time_series_bar_chart_2.yaml diff --git a/dff/config/superset_dashboard/charts/Flow_visit_ratio_monitor_13.yaml b/chatsky/config/superset_dashboard/charts/Flow_visit_ratio_monitor_13.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Flow_visit_ratio_monitor_13.yaml rename to chatsky/config/superset_dashboard/charts/Flow_visit_ratio_monitor_13.yaml diff --git a/dff/config/superset_dashboard/charts/Node_Visits_7.yaml b/chatsky/config/superset_dashboard/charts/Node_Visits_7.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Node_Visits_7.yaml rename to chatsky/config/superset_dashboard/charts/Node_Visits_7.yaml diff --git a/dff/config/superset_dashboard/charts/Node_counts_3.yaml b/chatsky/config/superset_dashboard/charts/Node_counts_3.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Node_counts_3.yaml rename to chatsky/config/superset_dashboard/charts/Node_counts_3.yaml diff --git a/dff/config/superset_dashboard/charts/Node_visit_ratio_monitor_8.yaml b/chatsky/config/superset_dashboard/charts/Node_visit_ratio_monitor_8.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Node_visit_ratio_monitor_8.yaml rename to chatsky/config/superset_dashboard/charts/Node_visit_ratio_monitor_8.yaml diff --git a/dff/config/superset_dashboard/charts/Node_visits_ratio_6.yaml b/chatsky/config/superset_dashboard/charts/Node_visits_ratio_6.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Node_visits_ratio_6.yaml rename to chatsky/config/superset_dashboard/charts/Node_visits_ratio_6.yaml diff --git a/dff/config/superset_dashboard/charts/Node_visits_sunburst_5.yaml b/chatsky/config/superset_dashboard/charts/Node_visits_sunburst_5.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Node_visits_sunburst_5.yaml rename to chatsky/config/superset_dashboard/charts/Node_visits_sunburst_5.yaml diff --git a/dff/config/superset_dashboard/charts/Rating_slot_line_chart_1.yaml b/chatsky/config/superset_dashboard/charts/Rating_slot_line_chart_1.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Rating_slot_line_chart_1.yaml rename to chatsky/config/superset_dashboard/charts/Rating_slot_line_chart_1.yaml diff --git a/dff/config/superset_dashboard/charts/Requests_17.yaml b/chatsky/config/superset_dashboard/charts/Requests_17.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Requests_17.yaml rename to chatsky/config/superset_dashboard/charts/Requests_17.yaml diff --git a/dff/config/superset_dashboard/charts/Responses_16.yaml b/chatsky/config/superset_dashboard/charts/Responses_16.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Responses_16.yaml rename to chatsky/config/superset_dashboard/charts/Responses_16.yaml diff --git a/dff/config/superset_dashboard/charts/Service_load_users_9.yaml b/chatsky/config/superset_dashboard/charts/Service_load_users_9.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Service_load_users_9.yaml rename to chatsky/config/superset_dashboard/charts/Service_load_users_9.yaml diff --git a/dff/config/superset_dashboard/charts/Table_14.yaml b/chatsky/config/superset_dashboard/charts/Table_14.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Table_14.yaml rename to chatsky/config/superset_dashboard/charts/Table_14.yaml diff --git a/dff/config/superset_dashboard/charts/Terminal_labels_15.yaml b/chatsky/config/superset_dashboard/charts/Terminal_labels_15.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Terminal_labels_15.yaml rename to chatsky/config/superset_dashboard/charts/Terminal_labels_15.yaml diff --git a/dff/config/superset_dashboard/charts/Transition_counts_12.yaml b/chatsky/config/superset_dashboard/charts/Transition_counts_12.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Transition_counts_12.yaml rename to chatsky/config/superset_dashboard/charts/Transition_counts_12.yaml diff --git a/dff/config/superset_dashboard/charts/Transition_layout_10.yaml b/chatsky/config/superset_dashboard/charts/Transition_layout_10.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Transition_layout_10.yaml rename to chatsky/config/superset_dashboard/charts/Transition_layout_10.yaml diff --git a/dff/config/superset_dashboard/charts/Transition_ratio_chord_11.yaml b/chatsky/config/superset_dashboard/charts/Transition_ratio_chord_11.yaml similarity index 100% rename from dff/config/superset_dashboard/charts/Transition_ratio_chord_11.yaml rename to chatsky/config/superset_dashboard/charts/Transition_ratio_chord_11.yaml diff --git a/dff/config/superset_dashboard/dashboards/DFF_statistics_dashboard_1.yaml b/chatsky/config/superset_dashboard/dashboards/chatsky_statistics_dashboard_1.yaml similarity index 99% rename from dff/config/superset_dashboard/dashboards/DFF_statistics_dashboard_1.yaml rename to chatsky/config/superset_dashboard/dashboards/chatsky_statistics_dashboard_1.yaml index ce8e32496..a32c1c91d 100644 --- a/dff/config/superset_dashboard/dashboards/DFF_statistics_dashboard_1.yaml +++ b/chatsky/config/superset_dashboard/dashboards/chatsky_statistics_dashboard_1.yaml @@ -1,7 +1,7 @@ -dashboard_title: DFF statistics dashboard +dashboard_title: Chatsky statistics dashboard description: null css: '' -slug: dff-stats +slug: chatsky-stats uuid: 68bce374-99bc-4890-b8c2-cb172409b894 position: CHART-91whs_IaiF: @@ -297,7 +297,7 @@ position: HEADER_ID: id: HEADER_ID meta: - text: DFF statistics dashboard + text: Chatsky statistics dashboard type: HEADER MARKDOWN-8Q9BhcEwva: children: [] @@ -378,7 +378,7 @@ position: To make them available in the dashboard, you need to define a custom extractor - function for them (see the [Extractor functions](https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.stats.1_extractor_functions.html) ). + function for them (see the [Extractor functions](https://deeppavlov.github.io/chatsky/tutorials/tutorials.stats.1_extractor_functions.html) ). The output of that function will then be persisted to the `data` column of the logs table, while the name of the function will be available in the `data key` column. That makes it easy to filter the relevant log entries and use @@ -621,7 +621,7 @@ position: ## Service users - This plot aggregates the count of unique users querying the DFF service at + This plot aggregates the count of unique users querying the Chatsky service at any given point in time. The time periods to aggregate over can be changed using the filter on the left. diff --git a/dff/config/superset_dashboard/databases/dff_database.yaml b/chatsky/config/superset_dashboard/databases/chatsky_database.yaml similarity index 91% rename from dff/config/superset_dashboard/databases/dff_database.yaml rename to chatsky/config/superset_dashboard/databases/chatsky_database.yaml index b178a0f80..851fa9d33 100644 --- a/dff/config/superset_dashboard/databases/dff_database.yaml +++ b/chatsky/config/superset_dashboard/databases/chatsky_database.yaml @@ -1,4 +1,4 @@ -database_name: dff_database +database_name: chatsky_database sqlalchemy_uri: clickhousedb+connect://username:XXXXXXXXXX@clickhouse:8123/test cache_timeout: null expose_in_sqllab: true diff --git a/dff/config/superset_dashboard/datasets/dff_database/dff_final_nodes.yaml b/chatsky/config/superset_dashboard/datasets/chatsky_database/chatsky_final_nodes.yaml similarity index 98% rename from dff/config/superset_dashboard/datasets/dff_database/dff_final_nodes.yaml rename to chatsky/config/superset_dashboard/datasets/chatsky_database/chatsky_final_nodes.yaml index 4a8628298..8cce16f6a 100644 --- a/dff/config/superset_dashboard/datasets/dff_database/dff_final_nodes.yaml +++ b/chatsky/config/superset_dashboard/datasets/chatsky_database/chatsky_final_nodes.yaml @@ -1,4 +1,4 @@ -table_name: dff_final_nodes +table_name: chatsky_final_nodes main_dttm_col: null description: null default_endpoint: null diff --git a/dff/config/superset_dashboard/datasets/dff_database/dff_node_stats.yaml b/chatsky/config/superset_dashboard/datasets/chatsky_database/chatsky_node_stats.yaml similarity index 98% rename from dff/config/superset_dashboard/datasets/dff_database/dff_node_stats.yaml rename to chatsky/config/superset_dashboard/datasets/chatsky_database/chatsky_node_stats.yaml index 4e2cc5792..88196bf50 100644 --- a/dff/config/superset_dashboard/datasets/dff_database/dff_node_stats.yaml +++ b/chatsky/config/superset_dashboard/datasets/chatsky_database/chatsky_node_stats.yaml @@ -1,4 +1,4 @@ -table_name: dff_node_stats +table_name: chatsky_node_stats main_dttm_col: null description: null default_endpoint: null diff --git a/dff/config/superset_dashboard/datasets/dff_database/dff_stats.yaml b/chatsky/config/superset_dashboard/datasets/chatsky_database/chatsky_stats.yaml similarity index 99% rename from dff/config/superset_dashboard/datasets/dff_database/dff_stats.yaml rename to chatsky/config/superset_dashboard/datasets/chatsky_database/chatsky_stats.yaml index 6f1efe683..a33d97261 100644 --- a/dff/config/superset_dashboard/datasets/dff_database/dff_stats.yaml +++ b/chatsky/config/superset_dashboard/datasets/chatsky_database/chatsky_stats.yaml @@ -1,4 +1,4 @@ -table_name: dff_stats +table_name: chatsky_stats main_dttm_col: null description: null default_endpoint: null diff --git a/dff/config/superset_dashboard/metadata.yaml b/chatsky/config/superset_dashboard/metadata.yaml similarity index 100% rename from dff/config/superset_dashboard/metadata.yaml rename to chatsky/config/superset_dashboard/metadata.yaml diff --git a/dff/context_storages/__init__.py b/chatsky/context_storages/__init__.py similarity index 100% rename from dff/context_storages/__init__.py rename to chatsky/context_storages/__init__.py diff --git a/dff/context_storages/database.py b/chatsky/context_storages/database.py similarity index 98% rename from dff/context_storages/database.py rename to chatsky/context_storages/database.py index 0602a0597..3d3a857d1 100644 --- a/dff/context_storages/database.py +++ b/chatsky/context_storages/database.py @@ -21,7 +21,7 @@ class DBContextStorage(ABC): r""" - An abstract interface for `dff` DB context storages. + An abstract interface for `chatsky` DB context storages. It includes the most essential methods of the python `dict` class. Can not be instantiated. @@ -224,5 +224,5 @@ def context_storage_factory(path: str, **kwargs) -> DBContextStorage: For more information, see the function doc:\n{context_storage_factory.__doc__} """ _class, module = PROTOCOLS[prefix]["class"], PROTOCOLS[prefix]["module"] - target_class = getattr(importlib.import_module(f".{module}", package="dff.context_storages"), _class) + target_class = getattr(importlib.import_module(f".{module}", package="chatsky.context_storages"), _class) return target_class(path, **kwargs) diff --git a/dff/context_storages/json.py b/chatsky/context_storages/json.py similarity index 97% rename from dff/context_storages/json.py rename to chatsky/context_storages/json.py index 9c24f2208..9ecc44b63 100644 --- a/dff/context_storages/json.py +++ b/chatsky/context_storages/json.py @@ -2,7 +2,7 @@ JSON ---- The JSON module provides a json-based version of the :py:class:`.DBContextStorage` class. -This class is used to store and retrieve context data in a JSON. It allows the DFF to easily +This class is used to store and retrieve context data in a JSON. It allows Chatsky to easily store and retrieve context data. """ @@ -20,7 +20,7 @@ from pydantic import BaseModel, model_validator from .database import DBContextStorage, threadsafe_method -from dff.script import Context +from chatsky.script import Context class SerializableStorage(BaseModel, extra="allow"): diff --git a/dff/context_storages/mongo.py b/chatsky/context_storages/mongo.py similarity index 97% rename from dff/context_storages/mongo.py rename to chatsky/context_storages/mongo.py index 6789adf8a..166045a12 100644 --- a/dff/context_storages/mongo.py +++ b/chatsky/context_storages/mongo.py @@ -3,7 +3,7 @@ ----- The Mongo module provides a MongoDB-based version of the :py:class:`.DBContextStorage` class. This class is used to store and retrieve context data in a MongoDB. -It allows the DFF to easily store and retrieve context data in a format that is highly scalable +It allows Chatsky to easily store and retrieve context data in a format that is highly scalable and easy to work with. MongoDB is a widely-used, open-source NoSQL database that is known for its scalability and performance. @@ -26,7 +26,7 @@ import json -from dff.script import Context +from chatsky.script import Context from .database import DBContextStorage, threadsafe_method from .protocol import get_protocol_install_suggestion diff --git a/dff/context_storages/pickle.py b/chatsky/context_storages/pickle.py similarity index 96% rename from dff/context_storages/pickle.py rename to chatsky/context_storages/pickle.py index 0fb30e504..9f72a22c3 100644 --- a/dff/context_storages/pickle.py +++ b/chatsky/context_storages/pickle.py @@ -3,7 +3,7 @@ ------ The Pickle module provides a pickle-based version of the :py:class:`.DBContextStorage` class. This class is used to store and retrieve context data in a pickle format. -It allows the DFF to easily store and retrieve context data in a format that is efficient +It allows Chatsky to easily store and retrieve context data in a format that is efficient for serialization and deserialization and can be easily used in python. Pickle is a python library that allows to serialize and deserialize python objects. @@ -24,7 +24,7 @@ pickle_available = False from .database import DBContextStorage, threadsafe_method -from dff.script import Context +from chatsky.script import Context class PickleContextStorage(DBContextStorage): diff --git a/dff/context_storages/protocol.py b/chatsky/context_storages/protocol.py similarity index 86% rename from dff/context_storages/protocol.py rename to chatsky/context_storages/protocol.py index 0d4d54f54..05f04f5b9 100644 --- a/dff/context_storages/protocol.py +++ b/chatsky/context_storages/protocol.py @@ -1,15 +1,15 @@ """ Protocol -------- -The Protocol module contains the base code for the different communication protocols used in the DFF. -It defines the :py:data:`.PROTOCOLS` constant, which lists all the supported protocols in the DFF. +The Protocol module contains the base code for the different communication protocols used in Chatsky. +It defines the :py:data:`.PROTOCOLS` constant, which lists all the supported protocols in Chatsky. The module also includes a function :py:func:`.get_protocol_install_suggestion()` that is used to provide suggestions for installing the necessary dependencies for a specific protocol. This function takes the name of the desired protocol as an argument and returns a string containing the necessary installation commands for that protocol. -The DFF supports a variety of communication protocols, +Chatsky supports a variety of communication protocols, which allows it to communicate with different types of databases. """ @@ -31,5 +31,5 @@ def get_protocol_install_suggestion(protocol_name: str) -> str: protocol = PROTOCOLS.get(protocol_name, {}) slug = protocol.get("slug") if slug: - return f"Try to run `pip install dff[{slug}]`" + return f"Try to run `pip install chatsky[{slug}]`" return "" diff --git a/dff/context_storages/protocols.json b/chatsky/context_storages/protocols.json similarity index 100% rename from dff/context_storages/protocols.json rename to chatsky/context_storages/protocols.json diff --git a/dff/context_storages/redis.py b/chatsky/context_storages/redis.py similarity index 96% rename from dff/context_storages/redis.py rename to chatsky/context_storages/redis.py index 9ef5401a9..7334097c7 100644 --- a/dff/context_storages/redis.py +++ b/chatsky/context_storages/redis.py @@ -3,7 +3,7 @@ ----- The Redis module provides a Redis-based version of the :py:class:`.DBContextStorage` class. This class is used to store and retrieve context data in a Redis. -It allows the DFF to easily store and retrieve context data in a format that is highly scalable +It allows Chatsky to easily store and retrieve context data in a format that is highly scalable and easy to work with. Redis is an open-source, in-memory data structure store that is known for its @@ -23,7 +23,7 @@ except ImportError: redis_available = False -from dff.script import Context +from chatsky.script import Context from .database import DBContextStorage, threadsafe_method from .protocol import get_protocol_install_suggestion diff --git a/dff/context_storages/shelve.py b/chatsky/context_storages/shelve.py similarity index 94% rename from dff/context_storages/shelve.py rename to chatsky/context_storages/shelve.py index fa59dbcc2..de2e97ea5 100644 --- a/dff/context_storages/shelve.py +++ b/chatsky/context_storages/shelve.py @@ -3,7 +3,7 @@ ------ The Shelve module provides a shelve-based version of the :py:class:`.DBContextStorage` class. This class is used to store and retrieve context data in a shelve format. -It allows the DFF to easily store and retrieve context data in a format that is efficient +It allows Chatsky to easily store and retrieve context data in a format that is efficient for serialization and deserialization and can be easily used in python. Shelve is a python library that allows to store and retrieve python objects. @@ -17,7 +17,7 @@ from shelve import DbfilenameShelf from typing import Hashable -from dff.script import Context +from chatsky.script import Context from .database import DBContextStorage diff --git a/dff/context_storages/sql.py b/chatsky/context_storages/sql.py similarity index 98% rename from dff/context_storages/sql.py rename to chatsky/context_storages/sql.py index c43af3356..677c1648d 100644 --- a/dff/context_storages/sql.py +++ b/chatsky/context_storages/sql.py @@ -3,7 +3,7 @@ --- The SQL module provides a SQL-based version of the :py:class:`.DBContextStorage` class. This class is used to store and retrieve context data from SQL databases. -It allows the DFF to easily store and retrieve context data in a format that is highly scalable +It allows Chatsky to easily store and retrieve context data in a format that is highly scalable and easy to work with. The SQL module provides the ability to choose the backend of your choice from @@ -18,7 +18,7 @@ import json from typing import Hashable -from dff.script import Context +from chatsky.script import Context from .database import DBContextStorage, threadsafe_method from .protocol import get_protocol_install_suggestion diff --git a/dff/context_storages/ydb.py b/chatsky/context_storages/ydb.py similarity index 98% rename from dff/context_storages/ydb.py rename to chatsky/context_storages/ydb.py index ed58a3b27..ff50f5b7b 100644 --- a/dff/context_storages/ydb.py +++ b/chatsky/context_storages/ydb.py @@ -6,7 +6,7 @@ operate, and scale high-performance and high-availability databases for your applications. The Yandex DB module uses the Yandex Cloud SDK, which is a python library that allows you to work -with Yandex Cloud services using python. This allows the DFF to easily integrate with the Yandex DataBase and +with Yandex Cloud services using python. This allows Chatsky to easily integrate with the Yandex DataBase and take advantage of the scalability and high-availability features provided by the service. """ @@ -16,7 +16,7 @@ from urllib.parse import urlsplit -from dff.script import Context +from chatsky.script import Context from .database import DBContextStorage from .protocol import get_protocol_install_suggestion diff --git a/dff/messengers/__init__.py b/chatsky/messengers/__init__.py similarity index 100% rename from dff/messengers/__init__.py rename to chatsky/messengers/__init__.py diff --git a/dff/messengers/common/__init__.py b/chatsky/messengers/common/__init__.py similarity index 100% rename from dff/messengers/common/__init__.py rename to chatsky/messengers/common/__init__.py diff --git a/dff/messengers/common/interface.py b/chatsky/messengers/common/interface.py similarity index 89% rename from dff/messengers/common/interface.py rename to chatsky/messengers/common/interface.py index 8037c0408..634fad973 100644 --- a/dff/messengers/common/interface.py +++ b/chatsky/messengers/common/interface.py @@ -2,7 +2,7 @@ Message Interfaces ------------------ The Message Interfaces module contains several basic classes that define the message interfaces. -These classes provide a way to define the structure of the messengers that are used to communicate with the DFF. +These classes provide a way to define the structure of the messengers that are used to communicate with Chatsky. """ from __future__ import annotations @@ -14,10 +14,10 @@ from typing import Optional, Any, List, Tuple, Hashable, TYPE_CHECKING, Type if TYPE_CHECKING: - from dff.script import Context, Message - from dff.pipeline.types import PipelineRunnerFunction - from dff.messengers.common.types import PollingInterfaceLoopFunction - from dff.script.core.message import Attachment + from chatsky.script import Context, Message + from chatsky.pipeline.types import PipelineRunnerFunction + from chatsky.messengers.common.types import PollingInterfaceLoopFunction + from chatsky.script.core.message import Attachment logger = logging.getLogger(__name__) @@ -35,7 +35,7 @@ async def connect(self, pipeline_runner: PipelineRunnerFunction): May be used for sending an introduction message or displaying general bot information. :param pipeline_runner: A function that should process user request and return context; - usually it's a :py:meth:`~dff.pipeline.pipeline.pipeline.Pipeline._run_pipeline` function. + usually it's a :py:meth:`~chatsky.pipeline.pipeline.pipeline.Pipeline._run_pipeline` function. """ raise NotImplementedError @@ -68,7 +68,7 @@ def __init__(self, attachments_directory: Optional[Path] = None) -> None: warning_start = f"Attachments directory for {type(self).__name__} messenger interface" warning_end = "attachment data won't be cached locally!" if attachments_directory is None: - self.attachments_directory = Path(tempdir) / f"dff-cache-{type(self).__name__}" + self.attachments_directory = Path(tempdir) / f"chatsky-cache-{type(self).__name__}" logger.info(f"{warning_start} is None, so will be set to tempdir and {warning_end}") else: self.attachments_directory = attachments_directory @@ -150,7 +150,7 @@ async def connect( for most cases the loop itself shouldn't be overridden. :param pipeline_runner: A function that should process user request and return context; - usually it's a :py:meth:`~dff.pipeline.pipeline.pipeline.Pipeline._run_pipeline` function. + usually it's a :py:meth:`~chatsky.pipeline.pipeline.pipeline.Pipeline._run_pipeline` function. :param loop: a function that determines whether polling should be continued; called in each cycle, should return `True` to continue polling or `False` to stop. :param timeout: a time interval between polls (in seconds). @@ -180,7 +180,7 @@ async def on_request_async( ) -> Context: """ Method that should be invoked on user input. - This method has the same signature as :py:class:`~dff.pipeline.types.PipelineRunnerFunction`. + This method has the same signature as :py:class:`~chatsky.pipeline.types.PipelineRunnerFunction`. """ return await self._pipeline_runner(request, ctx_id, update_ctx_misc) @@ -189,6 +189,6 @@ def on_request( ) -> Context: """ Method that should be invoked on user input. - This method has the same signature as :py:class:`~dff.pipeline.types.PipelineRunnerFunction`. + This method has the same signature as :py:class:`~chatsky.pipeline.types.PipelineRunnerFunction`. """ return asyncio.run(self.on_request_async(request, ctx_id, update_ctx_misc)) diff --git a/dff/messengers/common/types.py b/chatsky/messengers/common/types.py similarity index 94% rename from dff/messengers/common/types.py rename to chatsky/messengers/common/types.py index 516e84331..35696805e 100644 --- a/dff/messengers/common/types.py +++ b/chatsky/messengers/common/types.py @@ -1,7 +1,7 @@ """ Types ----- -The Types module contains special types that are used throughout the `DFF Messengers`. +The Types module contains special types that are used throughout `Chatsky Messengers`. """ from typing import Callable diff --git a/dff/messengers/console.py b/chatsky/messengers/console.py similarity index 84% rename from dff/messengers/console.py rename to chatsky/messengers/console.py index 12d3ee669..a0fe8c690 100644 --- a/dff/messengers/console.py +++ b/chatsky/messengers/console.py @@ -1,9 +1,9 @@ from typing import Any, Hashable, List, Optional, TextIO, Tuple from uuid import uuid4 -from dff.messengers.common.interface import PollingMessengerInterface -from dff.pipeline.types import PipelineRunnerFunction -from dff.script.core.context import Context -from dff.script.core.message import Message +from chatsky.messengers.common.interface import PollingMessengerInterface +from chatsky.pipeline.types import PipelineRunnerFunction +from chatsky.script.core.context import Context +from chatsky.script.core.message import Message class CLIMessengerInterface(PollingMessengerInterface): @@ -40,7 +40,7 @@ async def connect(self, pipeline_runner: PipelineRunnerFunction, **kwargs): The CLIProvider generates new dialog id used to user identification on each `connect` call. :param pipeline_runner: A function that should process user request and return context; - usually it's a :py:meth:`~dff.pipeline.pipeline.pipeline.Pipeline._run_pipeline` function. + usually it's a :py:meth:`~chatsky.pipeline.pipeline.pipeline.Pipeline._run_pipeline` function. :param \\**kwargs: argument, added for compatibility with super class, it shouldn't be used normally. """ self._ctx_id = uuid4() diff --git a/dff/messengers/telegram/__init__.py b/chatsky/messengers/telegram/__init__.py similarity index 100% rename from dff/messengers/telegram/__init__.py rename to chatsky/messengers/telegram/__init__.py diff --git a/dff/messengers/telegram/abstract.py b/chatsky/messengers/telegram/abstract.py similarity index 97% rename from dff/messengers/telegram/abstract.py rename to chatsky/messengers/telegram/abstract.py index e0e192d4e..30742579d 100644 --- a/dff/messengers/telegram/abstract.py +++ b/chatsky/messengers/telegram/abstract.py @@ -8,11 +8,11 @@ from pathlib import Path from typing import Any, Callable, Optional -from dff.utils.devel.extra_field_helpers import grab_extra_fields +from chatsky.utils.devel.extra_field_helpers import grab_extra_fields -from dff.messengers.common import MessengerInterfaceWithAttachments -from dff.pipeline.types import PipelineRunnerFunction -from dff.script.core.message import ( +from chatsky.messengers.common import MessengerInterfaceWithAttachments +from chatsky.pipeline.types import PipelineRunnerFunction +from chatsky.script.core.message import ( Animation, Audio, CallbackQuery, @@ -90,7 +90,7 @@ class _AbstractTelegramInterface(MessengerInterfaceWithAttachments): def __init__(self, token: str, attachments_directory: Optional[Path] = None) -> None: super().__init__(attachments_directory) if not telegram_available: - raise ImportError("`python-telegram-bot` package is missing.\nTry to run `pip install dff[telegram]`.") + raise ImportError("`python-telegram-bot` package is missing.\nTry to run `pip install chatsky[telegram]`.") self.application = Application.builder().token(token).build() self.application.add_handler(MessageHandler(ALL, self.on_message)) @@ -103,11 +103,11 @@ async def get_attachment_bytes(self, source: str) -> bytes: def extract_message_from_telegram(self, update: TelegramMessage) -> Message: """ - Convert Telegram update to DFF message. + Convert Telegram update to Chatsky message. Extract text and supported attachments. :param update: Telegram update object. - :return: DFF message object. + :return: Chatsky message object. """ message = Message() @@ -261,7 +261,7 @@ def extract_message_from_telegram(self, update: TelegramMessage) -> Message: async def cast_message_to_telegram_and_send(self, bot: ExtBot, chat_id: int, message: Message) -> None: """ - Send DFF message to Telegram. + Send Chatsky message to Telegram. Sometimes, if several attachments included into message can not be sent as one update, several Telegram updates will be produced. Sometimes, if no text and none of the supported attachments are included, @@ -269,7 +269,7 @@ async def cast_message_to_telegram_and_send(self, bot: ExtBot, chat_id: int, mes :param bot: Telegram bot, that is used for connection to Telegram API. :param chat_id: Telegram dialog ID that the message will be sent to. - :param message: DFF message that will be processed into Telegram updates. + :param message: Chatsky message that will be processed into Telegram updates. """ if message.text is not None: @@ -621,7 +621,7 @@ async def _on_event(self, update: Update, _: Any, create_message: Callable[[Upda Process Telegram update, run pipeline and send response to Telegram. :param update: Telegram update that will be processed. - :param create_message: function that converts Telegram update to DFF message. + :param create_message: function that converts Telegram update to Chatsky message. """ data_available = update.message is not None or update.callback_query is not None @@ -636,7 +636,7 @@ async def _on_event(self, update: Update, _: Any, create_message: Callable[[Upda async def on_message(self, update: Update, _: Any) -> None: """ - Process normal Telegram update, extracting DFF message from it + Process normal Telegram update, extracting Chatsky message from it using :py:meth:`~._AbstractTelegramInterface.extract_message_from_telegram`. :param update: Telegram update that will be processed. @@ -646,7 +646,7 @@ async def on_message(self, update: Update, _: Any) -> None: async def on_callback(self, update: Update, _: Any) -> None: """ - Process Telegram callback update, creating empty DFF message + Process Telegram callback update, creating empty Chatsky message with only one callback query attachment from `callback_query.data` field. :param update: Telegram update that will be processed. diff --git a/dff/messengers/telegram/interface.py b/chatsky/messengers/telegram/interface.py similarity index 97% rename from dff/messengers/telegram/interface.py rename to chatsky/messengers/telegram/interface.py index bcfabb0c1..5015fbf2f 100644 --- a/dff/messengers/telegram/interface.py +++ b/chatsky/messengers/telegram/interface.py @@ -8,7 +8,7 @@ from pathlib import Path from typing import Any, Optional -from dff.pipeline.types import PipelineRunnerFunction +from chatsky.pipeline.types import PipelineRunnerFunction from .abstract import _AbstractTelegramInterface diff --git a/dff/pipeline/__init__.py b/chatsky/pipeline/__init__.py similarity index 100% rename from dff/pipeline/__init__.py rename to chatsky/pipeline/__init__.py diff --git a/dff/pipeline/conditions.py b/chatsky/pipeline/conditions.py similarity index 97% rename from dff/pipeline/conditions.py rename to chatsky/pipeline/conditions.py index 3fd14dde6..01a5acb45 100644 --- a/dff/pipeline/conditions.py +++ b/chatsky/pipeline/conditions.py @@ -9,7 +9,7 @@ from __future__ import annotations from typing import Optional, TYPE_CHECKING -from dff.script import Context +from chatsky.script import Context from .types import ( StartConditionCheckerFunction, @@ -18,7 +18,7 @@ ) if TYPE_CHECKING: - from dff.pipeline.pipeline.pipeline import Pipeline + from chatsky.pipeline.pipeline.pipeline import Pipeline def always_start_condition(_: Context, __: Pipeline) -> bool: diff --git a/dff/pipeline/pipeline/__init__.py b/chatsky/pipeline/pipeline/__init__.py similarity index 100% rename from dff/pipeline/pipeline/__init__.py rename to chatsky/pipeline/pipeline/__init__.py diff --git a/dff/pipeline/pipeline/actor.py b/chatsky/pipeline/pipeline/actor.py similarity index 93% rename from dff/pipeline/pipeline/actor.py rename to chatsky/pipeline/pipeline/actor.py index 33a3d2daa..87e627e6b 100644 --- a/dff/pipeline/pipeline/actor.py +++ b/chatsky/pipeline/pipeline/actor.py @@ -29,41 +29,41 @@ from typing import Union, Callable, Optional, Dict, List, TYPE_CHECKING import copy -from dff.utils.turn_caching import cache_clear -from dff.script.core.types import ActorStage, NodeLabel2Type, NodeLabel3Type, LabelType -from dff.script.core.message import Message +from chatsky.utils.turn_caching import cache_clear +from chatsky.script.core.types import ActorStage, NodeLabel2Type, NodeLabel3Type, LabelType +from chatsky.script.core.message import Message -from dff.script.core.context import Context -from dff.script.core.script import Script, Node -from dff.script.core.normalization import normalize_label, normalize_response -from dff.script.core.keywords import GLOBAL, LOCAL -from dff.utils.devel.async_helpers import wrap_sync_function_in_async +from chatsky.script.core.context import Context +from chatsky.script.core.script import Script, Node +from chatsky.script.core.normalization import normalize_label, normalize_response +from chatsky.script.core.keywords import GLOBAL, LOCAL +from chatsky.utils.devel.async_helpers import wrap_sync_function_in_async logger = logging.getLogger(__name__) if TYPE_CHECKING: - from dff.pipeline.pipeline.pipeline import Pipeline + from chatsky.pipeline.pipeline.pipeline import Pipeline class Actor: """ - The class which is used to process :py:class:`~dff.script.Context` - according to the :py:class:`~dff.script.Script`. + The class which is used to process :py:class:`~chatsky.script.Context` + according to the :py:class:`~chatsky.script.Script`. :param script: The dialog scenario: a graph described by the :py:class:`.Keywords`. While the graph is being initialized, it is validated and then used for the dialog. - :param start_label: The start node of :py:class:`~dff.script.Script`. The execution begins with it. - :param fallback_label: The label of :py:class:`~dff.script.Script`. + :param start_label: The start node of :py:class:`~chatsky.script.Script`. The execution begins with it. + :param fallback_label: The label of :py:class:`~chatsky.script.Script`. Dialog comes into that label if all other transitions failed, or there was an error while executing the scenario. Defaults to `None`. - :param label_priority: Default priority value for all :py:const:`labels ` + :param label_priority: Default priority value for all :py:const:`labels ` where there is no priority. Defaults to `1.0`. :param condition_handler: Handler that processes a call of condition functions. Defaults to `None`. :param handlers: This variable is responsible for the usage of external handlers on - the certain stages of work of :py:class:`~dff.script.Actor`. + the certain stages of work of :py:class:`~chatsky.script.Actor`. - - key (:py:class:`~dff.script.ActorStage`) - Stage in which the handler is called. + - key (:py:class:`~chatsky.script.ActorStage`) - Stage in which the handler is called. - value (List[Callable]) - The list of called handlers for each stage. Defaults to an empty `dict`. """ diff --git a/dff/pipeline/pipeline/component.py b/chatsky/pipeline/pipeline/component.py similarity index 97% rename from dff/pipeline/pipeline/component.py rename to chatsky/pipeline/pipeline/component.py index 7384578b7..ab37426ea 100644 --- a/dff/pipeline/pipeline/component.py +++ b/chatsky/pipeline/pipeline/component.py @@ -15,7 +15,7 @@ import asyncio from typing import Optional, Awaitable, TYPE_CHECKING -from dff.script import Context +from chatsky.script import Context from ..service.extra import BeforeHandler, AfterHandler from ..conditions import always_start_condition @@ -32,7 +32,7 @@ logger = logging.getLogger(__name__) if TYPE_CHECKING: - from dff.pipeline.pipeline.pipeline import Pipeline + from chatsky.pipeline.pipeline.pipeline import Pipeline class PipelineComponent(abc.ABC): @@ -93,7 +93,7 @@ def __init__( self.path = path """ Dot-separated path to component (is universally unique). - This attribute is set in :py:func:`~dff.pipeline.pipeline.utils.finalize_service_group`. + This attribute is set in :py:func:`~chatsky.pipeline.pipeline.utils.finalize_service_group`. """ self.before_handler = BeforeHandler([] if before_handler is None else before_handler) @@ -204,7 +204,7 @@ def _get_runtime_info(self, ctx: Context) -> ServiceRuntimeInfo: Method for retrieving runtime info about this component. :param ctx: Current dialog :py:class:`~.Context`. - :return: :py:class:`~.dff.script.typing.ServiceRuntimeInfo` + :return: :py:class:`~.chatsky.script.typing.ServiceRuntimeInfo` object where all not set fields are replaced with `[None]`. """ return ServiceRuntimeInfo( diff --git a/dff/pipeline/pipeline/pipeline.py b/chatsky/pipeline/pipeline/pipeline.py similarity index 91% rename from dff/pipeline/pipeline/pipeline.py rename to chatsky/pipeline/pipeline/pipeline.py index b036c2dc0..92d62f684 100644 --- a/dff/pipeline/pipeline/pipeline.py +++ b/chatsky/pipeline/pipeline/pipeline.py @@ -2,7 +2,7 @@ Pipeline -------- The Pipeline module contains the :py:class:`.Pipeline` class, -which is a fundamental element of the DFF. The Pipeline class is responsible +which is a fundamental element of Chatsky. The Pipeline class is responsible for managing and executing the various components (:py:class:`.PipelineComponent`)which make up the processing of messages from and to users. It provides a way to organize and structure the messages processing flow. @@ -18,14 +18,14 @@ import logging from typing import Union, List, Dict, Optional, Hashable, Callable -from dff.context_storages import DBContextStorage -from dff.script import Script, Context, ActorStage -from dff.script import NodeLabel2Type, Message -from dff.utils.turn_caching import cache_clear +from chatsky.context_storages import DBContextStorage +from chatsky.script import Script, Context, ActorStage +from chatsky.script import NodeLabel2Type, Message +from chatsky.utils.turn_caching import cache_clear -from dff.messengers.console import CLIMessengerInterface -from dff.messengers.common import MessengerInterface -from dff.slots.slots import GroupSlot +from chatsky.messengers.console import CLIMessengerInterface +from chatsky.messengers.common import MessengerInterface +from chatsky.slots.slots import GroupSlot from ..service.group import ServiceGroup from ..types import ( ServiceBuilder, @@ -36,7 +36,7 @@ ExtraHandlerBuilder, ) from .utils import finalize_service_group, pretty_format_component_info_dict -from dff.pipeline.pipeline.actor import Actor +from chatsky.pipeline.pipeline.actor import Actor logger = logging.getLogger(__name__) @@ -54,14 +54,14 @@ class Pipeline: :param script: (required) A :py:class:`~.Script` instance (object or dict). :param start_label: (required) Actor start label. :param fallback_label: Actor fallback label. - :param label_priority: Default priority value for all actor :py:const:`labels ` + :param label_priority: Default priority value for all actor :py:const:`labels ` where there is no priority. Defaults to `1.0`. :param condition_handler: Handler that processes a call of actor condition functions. Defaults to `None`. :param slots: Slots configuration. :param handlers: This variable is responsible for the usage of external handlers on - the certain stages of work of :py:class:`~dff.script.Actor`. + the certain stages of work of :py:class:`~chatsky.script.Actor`. - - key: :py:class:`~dff.script.ActorStage` - Stage in which the handler is called. + - key: :py:class:`~chatsky.script.ActorStage` - Stage in which the handler is called. - value: List[Callable] - The list of called handlers for each stage. Defaults to an empty `dict`. :param messenger_interface: An `AbsMessagingInterface` instance for this pipeline. @@ -231,7 +231,7 @@ def from_script( :param script: (required) A :py:class:`~.Script` instance (object or dict). :param start_label: (required) Actor start label. :param fallback_label: Actor fallback label. - :param label_priority: Default priority value for all actor :py:const:`labels ` + :param label_priority: Default priority value for all actor :py:const:`labels ` where there is no priority. Defaults to `1.0`. :param condition_handler: Handler that processes a call of actor condition functions. Defaults to `None`. :param slots: Slots configuration. @@ -239,9 +239,9 @@ def from_script( defined in the ``PRE_RESPONSE_PROCESSING`` and ``PRE_TRANSITIONS_PROCESSING`` sections of the script should be parallelized over respective groups. :param handlers: This variable is responsible for the usage of external handlers on - the certain stages of work of :py:class:`~dff.script.Actor`. + the certain stages of work of :py:class:`~chatsky.script.Actor`. - - key: :py:class:`~dff.script.ActorStage` - Stage in which the handler is called. + - key: :py:class:`~chatsky.script.ActorStage` - Stage in which the handler is called. - value: List[Callable] - The list of called handlers for each stage. Defaults to an empty `dict`. :param context_storage: An :py:class:`~.DBContextStorage` instance for this pipeline @@ -286,17 +286,17 @@ def set_actor( :param script: (required) A :py:class:`~.Script` instance (object or dict). :param start_label: (required) Actor start label. - The start node of :py:class:`~dff.script.Script`. The execution begins with it. - :param fallback_label: Actor fallback label. The label of :py:class:`~dff.script.Script`. + The start node of :py:class:`~chatsky.script.Script`. The execution begins with it. + :param fallback_label: Actor fallback label. The label of :py:class:`~chatsky.script.Script`. Dialog comes into that label if all other transitions failed, or there was an error while executing the scenario. - :param label_priority: Default priority value for all actor :py:const:`labels ` + :param label_priority: Default priority value for all actor :py:const:`labels ` where there is no priority. Defaults to `1.0`. :param condition_handler: Handler that processes a call of actor condition functions. Defaults to `None`. :param handlers: This variable is responsible for the usage of external handlers on - the certain stages of work of :py:class:`~dff.script.Actor`. + the certain stages of work of :py:class:`~chatsky.script.Actor`. - - key :py:class:`~dff.script.ActorStage` - Stage in which the handler is called. + - key :py:class:`~chatsky.script.ActorStage` - Stage in which the handler is called. - value List[Callable] - The list of called handlers for each stage. Defaults to an empty `dict`. """ self.actor = Actor(script, start_label, fallback_label, label_priority, condition_handler, handlers) @@ -315,7 +315,7 @@ async def _run_pipeline( ) -> Context: """ Method that should be invoked on user input. - This method has the same signature as :py:class:`~dff.pipeline.types.PipelineRunnerFunction`. + This method has the same signature as :py:class:`~chatsky.pipeline.types.PipelineRunnerFunction`. """ if ctx_id is None: ctx = Context() @@ -365,7 +365,7 @@ def __call__( Basically, it is a shortcut for `_run_pipeline`. NB! When pipeline is executed this way, `messenger_interface` won't be initiated nor connected. - This method has the same signature as :py:class:`~dff.pipeline.types.PipelineRunnerFunction`. + This method has the same signature as :py:class:`~chatsky.pipeline.types.PipelineRunnerFunction`. """ return asyncio.run(self._run_pipeline(request, ctx_id, update_ctx_misc)) diff --git a/dff/pipeline/pipeline/utils.py b/chatsky/pipeline/pipeline/utils.py similarity index 100% rename from dff/pipeline/pipeline/utils.py rename to chatsky/pipeline/pipeline/utils.py diff --git a/dff/pipeline/service/__init__.py b/chatsky/pipeline/service/__init__.py similarity index 100% rename from dff/pipeline/service/__init__.py rename to chatsky/pipeline/service/__init__.py diff --git a/dff/pipeline/service/extra.py b/chatsky/pipeline/service/extra.py similarity index 98% rename from dff/pipeline/service/extra.py rename to chatsky/pipeline/service/extra.py index f9194ec4f..8a8a65a9b 100644 --- a/dff/pipeline/service/extra.py +++ b/chatsky/pipeline/service/extra.py @@ -12,10 +12,10 @@ import inspect from typing import Optional, List, TYPE_CHECKING -from dff.script import Context +from chatsky.script import Context from .utils import collect_defined_constructor_parameters_to_dict, _get_attrs_with_updates -from dff.utils.devel.async_helpers import wrap_sync_function_in_async +from chatsky.utils.devel.async_helpers import wrap_sync_function_in_async from ..types import ( ServiceRuntimeInfo, ExtraHandlerType, @@ -27,7 +27,7 @@ logger = logging.getLogger(__name__) if TYPE_CHECKING: - from dff.pipeline.pipeline.pipeline import Pipeline + from chatsky.pipeline.pipeline.pipeline import Pipeline class _ComponentExtraHandler: diff --git a/dff/pipeline/service/group.py b/chatsky/pipeline/service/group.py similarity index 99% rename from dff/pipeline/service/group.py rename to chatsky/pipeline/service/group.py index 13e412663..22b8bae0d 100644 --- a/dff/pipeline/service/group.py +++ b/chatsky/pipeline/service/group.py @@ -13,7 +13,7 @@ import logging from typing import Optional, List, Union, Awaitable, TYPE_CHECKING -from dff.script import Context +from chatsky.script import Context from .utils import collect_defined_constructor_parameters_to_dict, _get_attrs_with_updates from ..pipeline.component import PipelineComponent @@ -32,7 +32,7 @@ logger = logging.getLogger(__name__) if TYPE_CHECKING: - from dff.pipeline.pipeline.pipeline import Pipeline + from chatsky.pipeline.pipeline.pipeline import Pipeline class ServiceGroup(PipelineComponent): diff --git a/dff/pipeline/service/service.py b/chatsky/pipeline/service/service.py similarity index 98% rename from dff/pipeline/service/service.py rename to chatsky/pipeline/service/service.py index 9eae76468..fdf43f0bb 100644 --- a/dff/pipeline/service/service.py +++ b/chatsky/pipeline/service/service.py @@ -15,10 +15,10 @@ import inspect from typing import Optional, TYPE_CHECKING -from dff.script import Context +from chatsky.script import Context from .utils import collect_defined_constructor_parameters_to_dict, _get_attrs_with_updates -from dff.utils.devel.async_helpers import wrap_sync_function_in_async +from chatsky.utils.devel.async_helpers import wrap_sync_function_in_async from ..types import ( ServiceBuilder, StartConditionCheckerFunction, @@ -31,7 +31,7 @@ logger = logging.getLogger(__name__) if TYPE_CHECKING: - from dff.pipeline.pipeline.pipeline import Pipeline + from chatsky.pipeline.pipeline.pipeline import Pipeline class Service(PipelineComponent): diff --git a/dff/pipeline/service/utils.py b/chatsky/pipeline/service/utils.py similarity index 98% rename from dff/pipeline/service/utils.py rename to chatsky/pipeline/service/utils.py index 06d168ad2..651f89b92 100644 --- a/dff/pipeline/service/utils.py +++ b/chatsky/pipeline/service/utils.py @@ -1,7 +1,7 @@ """ Utility Functions ----------------- -The Utility Functions module contains several utility functions that are commonly used throughout the DFF. +The Utility Functions module contains several utility functions that are commonly used throughout Chatsky. These functions provide a variety of utility functionality. """ diff --git a/dff/pipeline/types.py b/chatsky/pipeline/types.py similarity index 94% rename from dff/pipeline/types.py rename to chatsky/pipeline/types.py index aafec8393..118532559 100644 --- a/dff/pipeline/types.py +++ b/chatsky/pipeline/types.py @@ -1,7 +1,7 @@ """ Types ----- -The Types module contains several classes and special types that are used throughout the `DFF Pipeline`. +The Types module contains several classes and special types that are used throughout `Chatsky Pipeline`. The classes and special types in this module can include data models, data structures, and other types that are defined for type hinting. """ @@ -14,13 +14,13 @@ if TYPE_CHECKING: - from dff.pipeline.pipeline.pipeline import Pipeline - from dff.pipeline.service.service import Service - from dff.pipeline.service.group import ServiceGroup - from dff.pipeline.service.extra import _ComponentExtraHandler - from dff.messengers.common.interface import MessengerInterface - from dff.context_storages import DBContextStorage - from dff.script import Context, ActorStage, NodeLabel2Type, Script, Message + from chatsky.pipeline.pipeline.pipeline import Pipeline + from chatsky.pipeline.service.service import Service + from chatsky.pipeline.service.group import ServiceGroup + from chatsky.pipeline.service.extra import _ComponentExtraHandler + from chatsky.messengers.common.interface import MessengerInterface + from chatsky.context_storages import DBContextStorage + from chatsky.script import Context, ActorStage, NodeLabel2Type, Script, Message class PipelineRunnerFunction(Protocol): diff --git a/dff/script/__init__.py b/chatsky/script/__init__.py similarity index 100% rename from dff/script/__init__.py rename to chatsky/script/__init__.py diff --git a/dff/script/conditions/__init__.py b/chatsky/script/conditions/__init__.py similarity index 100% rename from dff/script/conditions/__init__.py rename to chatsky/script/conditions/__init__.py diff --git a/dff/script/conditions/std_conditions.py b/chatsky/script/conditions/std_conditions.py similarity index 98% rename from dff/script/conditions/std_conditions.py rename to chatsky/script/conditions/std_conditions.py index 8568a98ce..7a5479f9a 100644 --- a/dff/script/conditions/std_conditions.py +++ b/chatsky/script/conditions/std_conditions.py @@ -15,9 +15,9 @@ from pydantic import validate_call -from dff.pipeline import Pipeline -from dff.script import NodeLabel2Type, Context, Message -from dff.script.core.message import CallbackQuery +from chatsky.pipeline import Pipeline +from chatsky.script import NodeLabel2Type, Context, Message +from chatsky.script.core.message import CallbackQuery logger = logging.getLogger(__name__) diff --git a/dff/script/core/__init__.py b/chatsky/script/core/__init__.py similarity index 100% rename from dff/script/core/__init__.py rename to chatsky/script/core/__init__.py diff --git a/dff/script/core/context.py b/chatsky/script/core/context.py similarity index 96% rename from dff/script/core/context.py rename to chatsky/script/core/context.py index c84e5eee4..30c589a96 100644 --- a/dff/script/core/context.py +++ b/chatsky/script/core/context.py @@ -24,13 +24,13 @@ from pydantic import BaseModel, Field, field_validator -from dff.script.core.message import Message -from dff.script.core.types import NodeLabel2Type -from dff.pipeline.types import ComponentExecutionState -from dff.slots.slots import SlotManager +from chatsky.script.core.message import Message +from chatsky.script.core.types import NodeLabel2Type +from chatsky.pipeline.types import ComponentExecutionState +from chatsky.slots.slots import SlotManager if TYPE_CHECKING: - from dff.script.core.script import Node + from chatsky.script.core.script import Node logger = logging.getLogger(__name__) @@ -98,7 +98,7 @@ class Context(BaseModel): misc: Dict[str, Any] = Field(default_factory=dict) """ `misc` stores any custom data. The scripting doesn't use this dictionary by default, - so storage of any data won't reflect on the work on the internal Dialog Flow Scripting functions. + so storage of any data won't reflect on the work on the internal Chatsky Scripting functions. Avoid storing unserializable data in order for context storages to work. @@ -263,7 +263,7 @@ def last_request(self, request: Optional[Message]): @property def current_node(self) -> Optional[Node]: """ - Return current :py:class:`~dff.script.core.script.Node`. + Return current :py:class:`~chatsky.script.core.script.Node`. """ actor_data = self.framework_data.actor_data node = ( diff --git a/dff/script/core/keywords.py b/chatsky/script/core/keywords.py similarity index 93% rename from dff/script/core/keywords.py rename to chatsky/script/core/keywords.py index 761b71a32..c2ff5baec 100644 --- a/dff/script/core/keywords.py +++ b/chatsky/script/core/keywords.py @@ -11,7 +11,7 @@ class Keywords(str, Enum): """ - Keywords used to define the dialog script (:py:class:`~dff.script.Script`). + Keywords used to define the dialog script (:py:class:`~chatsky.script.Script`). The data type `dict` is used to describe the scenario. `Enums` of this class are used as keys in this `dict`. Different keys correspond to the different value types aimed at different purposes. @@ -23,7 +23,7 @@ class Keywords(str, Enum): The value that corresponds to this key has the `dict` type with keywords: `{TRANSITIONS:..., RESPONSE:..., PRE_RESPONSE_PROCESSING:..., MISC:...}`. - There can be only one global node in a script :py:class:`~dff.script.Script`. + There can be only one global node in a script :py:class:`~chatsky.script.Script`. The global node is defined at the flow level as opposed to regular nodes. This node allows to define default global values for all nodes. @@ -65,7 +65,7 @@ class Keywords(str, Enum): `{"PRE_RESPONSE_PROC_0": pre_response_proc_func_0, ..., "PRE_RESPONSE_PROC_N": pre_response_proc__func_N}`, where `"PRE_RESPONSE_PROC_i"` is an arbitrary name of the preprocessing stage in the pipeline. - Unless the :py:class:`~dff.pipeline.pipeline.Pipeline`'s `parallelize_processing` flag + Unless the :py:class:`~chatsky.pipeline.pipeline.Pipeline`'s `parallelize_processing` flag is set to `True`, calls to `pre_response_proc__func_i` are made in-order. PRE_TRANSITIONS_PROCESSING: Enum(auto) @@ -76,7 +76,7 @@ class Keywords(str, Enum): "PRE_TRANSITIONS_PROC_N": pre_transitions_proc_func_N}`, where `"PRE_TRANSITIONS_PROC_i"` is an arbitrary name of the preprocessing stage in the pipeline. - Unless the :py:class:`~dff.pipeline.pipeline.Pipeline`'s `parallelize_processing` flag + Unless the :py:class:`~chatsky.pipeline.pipeline.Pipeline`'s `parallelize_processing` flag is set to `True`, calls to `pre_transitions_proc_func_i` are made in-order. """ diff --git a/dff/script/core/message.py b/chatsky/script/core/message.py similarity index 87% rename from dff/script/core/message.py rename to chatsky/script/core/message.py index 6fdf18977..79120598c 100644 --- a/dff/script/core/message.py +++ b/chatsky/script/core/message.py @@ -2,7 +2,7 @@ Message ------- The :py:class:`.Message` class is a universal data model for representing a message that should be supported by -DFF. It only contains types and properties that are compatible with most messaging services. +Chatsky. It only contains types and properties that are compatible with most messaging services. """ from typing import Literal, Optional, List, Union @@ -14,8 +14,8 @@ from pydantic import Field, FilePath, HttpUrl, model_validator from pydantic_core import Url -from dff.messengers.common.interface import MessengerInterfaceWithAttachments -from dff.utils.devel import JSONSerializableDict, PickleEncodedValue, JSONSerializableExtras +from chatsky.messengers.common.interface import MessengerInterfaceWithAttachments +from chatsky.utils.devel import JSONSerializableDict, PickleEncodedValue, JSONSerializableExtras class DataModel(JSONSerializableExtras): @@ -28,11 +28,11 @@ class DataModel(JSONSerializableExtras): class Attachment(DataModel, abc.ABC): """ - DFF Message attachment base class. + Chatsky Message attachment base class. It is capable of serializing and validating all the model fields to JSON. """ - dff_attachment_type: str + chatsky_attachment_type: str class CallbackQuery(Attachment): @@ -43,7 +43,7 @@ class CallbackQuery(Attachment): """ query_string: Optional[str] - dff_attachment_type: Literal["callback_query"] = "callback_query" + chatsky_attachment_type: Literal["callback_query"] = "callback_query" class Location(Attachment): @@ -57,7 +57,7 @@ class Location(Attachment): longitude: float latitude: float - dff_attachment_type: Literal["location"] = "location" + chatsky_attachment_type: Literal["location"] = "location" class Contact(Attachment): @@ -69,7 +69,7 @@ class Contact(Attachment): phone_number: str first_name: str last_name: Optional[str] - dff_attachment_type: Literal["contact"] = "contact" + chatsky_attachment_type: Literal["contact"] = "contact" class Invoice(Attachment): @@ -82,7 +82,7 @@ class Invoice(Attachment): description: str currency: str amount: int - dff_attachment_type: Literal["invoice"] = "invoice" + chatsky_attachment_type: Literal["invoice"] = "invoice" class PollOption(DataModel): @@ -93,7 +93,7 @@ class PollOption(DataModel): text: str votes: int = Field(default=0) - dff_attachment_type: Literal["poll_option"] = "poll_option" + chatsky_attachment_type: Literal["poll_option"] = "poll_option" class Poll(Attachment): @@ -104,7 +104,7 @@ class Poll(Attachment): question: str options: List[PollOption] - dff_attachment_type: Literal["poll"] = "poll" + chatsky_attachment_type: Literal["poll"] = "poll" class DataAttachment(Attachment): @@ -187,49 +187,49 @@ def validate_source_or_id(cls, values: dict): class Audio(DataAttachment): """Represents an audio file attachment.""" - dff_attachment_type: Literal["audio"] = "audio" + chatsky_attachment_type: Literal["audio"] = "audio" class Video(DataAttachment): """Represents a video file attachment.""" - dff_attachment_type: Literal["video"] = "video" + chatsky_attachment_type: Literal["video"] = "video" class Animation(DataAttachment): """Represents an animation file attachment.""" - dff_attachment_type: Literal["animation"] = "animation" + chatsky_attachment_type: Literal["animation"] = "animation" class Image(DataAttachment): """Represents an image file attachment.""" - dff_attachment_type: Literal["image"] = "image" + chatsky_attachment_type: Literal["image"] = "image" class Sticker(DataAttachment): """Represents a sticker as a file attachment.""" - dff_attachment_type: Literal["sticker"] = "sticker" + chatsky_attachment_type: Literal["sticker"] = "sticker" class Document(DataAttachment): """Represents a document file attachment.""" - dff_attachment_type: Literal["document"] = "document" + chatsky_attachment_type: Literal["document"] = "document" class VoiceMessage(DataAttachment): """Represents a voice message.""" - dff_attachment_type: Literal["voice_message"] = "voice_message" + chatsky_attachment_type: Literal["voice_message"] = "voice_message" class VideoMessage(DataAttachment): """Represents a video message.""" - dff_attachment_type: Literal["video_message"] = "video_message" + chatsky_attachment_type: Literal["video_message"] = "video_message" class MediaGroup(Attachment): @@ -243,7 +243,7 @@ class MediaGroup(Attachment): """ group: List[Union[Audio, Video, Image, Document, DataAttachment]] = Field(default_factory=list) - dff_attachment_type: Literal["media_group"] = "media_group" + chatsky_attachment_type: Literal["media_group"] = "media_group" class Message(DataModel): diff --git a/dff/script/core/normalization.py b/chatsky/script/core/normalization.py similarity index 97% rename from dff/script/core/normalization.py rename to chatsky/script/core/normalization.py index 2784b2647..39b7dde8c 100644 --- a/dff/script/core/normalization.py +++ b/chatsky/script/core/normalization.py @@ -16,7 +16,7 @@ from .message import Message if TYPE_CHECKING: - from dff.pipeline.pipeline.pipeline import Pipeline + from chatsky.pipeline.pipeline.pipeline import Pipeline logger = logging.getLogger(__name__) @@ -24,7 +24,7 @@ def normalize_label(label: Label, default_flow_label: LabelType = "") -> Label: """ The function that is used for normalization of - :py:const:`label `. + :py:const:`label `. :param label: If label is Callable the function is wrapped into try/except and normalization is used on the result of the function call with the name label. diff --git a/dff/script/core/script.py b/chatsky/script/core/script.py similarity index 98% rename from dff/script/core/script.py rename to chatsky/script/core/script.py index 3c7fde9b5..985d6d30f 100644 --- a/dff/script/core/script.py +++ b/chatsky/script/core/script.py @@ -21,8 +21,8 @@ from .normalization import normalize_condition, normalize_label if TYPE_CHECKING: - from dff.script.core.context import Context - from dff.pipeline.pipeline.pipeline import Pipeline + from chatsky.script.core.context import Context + from chatsky.pipeline.pipeline.pipeline import Pipeline logger = logging.getLogger(__name__) @@ -64,7 +64,7 @@ def _types_equal(signature_type: Any, expected_type: str) -> bool: def _validate_callable(callable: Callable, func_type: UserFunctionType, flow_label: str, node_label: str) -> List: """ - This function validates a function during :py:class:`~dff.script.Script` validation. + This function validates a function during :py:class:`~chatsky.script.Script` validation. It checks parameter number (unconditionally), parameter types (if specified) and return type (if specified). :param callable: Function to validate. diff --git a/dff/script/core/types.py b/chatsky/script/core/types.py similarity index 97% rename from dff/script/core/types.py rename to chatsky/script/core/types.py index 413159174..8655c96ad 100644 --- a/dff/script/core/types.py +++ b/chatsky/script/core/types.py @@ -14,7 +14,7 @@ from .keywords import Keywords LabelType: TypeAlias = Union[str, Keywords] -"""Label can be a casual string or :py:class:`~dff.script.Keywords`.""" +"""Label can be a casual string or :py:class:`~chatsky.script.Keywords`.""" # todo: rename these to identifiers NodeLabel1Type: TypeAlias = Tuple[str, float] diff --git a/dff/script/extras/__init__.py b/chatsky/script/extras/__init__.py similarity index 100% rename from dff/script/extras/__init__.py rename to chatsky/script/extras/__init__.py diff --git a/dff/script/extras/conditions/__init__.py b/chatsky/script/extras/conditions/__init__.py similarity index 100% rename from dff/script/extras/conditions/__init__.py rename to chatsky/script/extras/conditions/__init__.py diff --git a/dff/script/extras/slots/__init__.py b/chatsky/script/extras/slots/__init__.py similarity index 100% rename from dff/script/extras/slots/__init__.py rename to chatsky/script/extras/slots/__init__.py diff --git a/dff/script/labels/__init__.py b/chatsky/script/labels/__init__.py similarity index 100% rename from dff/script/labels/__init__.py rename to chatsky/script/labels/__init__.py diff --git a/dff/script/labels/std_labels.py b/chatsky/script/labels/std_labels.py similarity index 82% rename from dff/script/labels/std_labels.py rename to chatsky/script/labels/std_labels.py index 6f58c4411..a52aa37fc 100644 --- a/dff/script/labels/std_labels.py +++ b/chatsky/script/labels/std_labels.py @@ -1,28 +1,28 @@ """ Labels ------ -:py:const:`Labels ` are one of the important components of the dialog graph, +:py:const:`Labels ` are one of the important components of the dialog graph, which determine the targeted node name of the transition. They are used to identify the next step in the conversation. Labels can also be used in combination with other conditions, such as the current context or user data, to create more complex and dynamic conversations. -This module contains a standard set of scripting :py:const:`labels ` that +This module contains a standard set of scripting :py:const:`labels ` that can be used by developers to define the conversation flow. """ from __future__ import annotations from typing import Optional, Callable, TYPE_CHECKING -from dff.script import Context, ConstLabel +from chatsky.script import Context, ConstLabel if TYPE_CHECKING: - from dff.pipeline.pipeline.pipeline import Pipeline + from chatsky.pipeline.pipeline.pipeline import Pipeline def repeat(priority: Optional[float] = None) -> Callable[[Context, Pipeline], ConstLabel]: """ Returns transition handler that takes :py:class:`.Context`, - :py:class:`~dff.pipeline.Pipeline` and :py:const:`priority `. + :py:class:`~chatsky.pipeline.Pipeline` and :py:const:`priority `. This handler returns a :py:const:`label ` to the last node with a given :py:const:`priority `. If the priority is not given, `Pipeline.actor.label_priority` is used as default. @@ -43,9 +43,9 @@ def repeat_transition_handler(ctx: Context, pipeline: Pipeline) -> ConstLabel: def previous(priority: Optional[float] = None) -> Callable[[Context, Pipeline], ConstLabel]: """ - Returns transition handler that takes :py:class:`~dff.script.Context`, - :py:class:`~dff.pipeline.Pipeline` and :py:const:`priority `. - This handler returns a :py:const:`label ` + Returns transition handler that takes :py:class:`~chatsky.script.Context`, + :py:class:`~chatsky.pipeline.Pipeline` and :py:const:`priority `. + This handler returns a :py:const:`label ` to the previous node with a given :py:const:`priority `. If the priority is not given, `Pipeline.actor.label_priority` is used as default. If the current node is the start node, fallback is returned. @@ -68,9 +68,9 @@ def previous_transition_handler(ctx: Context, pipeline: Pipeline) -> ConstLabel: def to_start(priority: Optional[float] = None) -> Callable[[Context, Pipeline], ConstLabel]: """ - Returns transition handler that takes :py:class:`~dff.script.Context`, - :py:class:`~dff.pipeline.Pipeline` and :py:const:`priority `. - This handler returns a :py:const:`label ` + Returns transition handler that takes :py:class:`~chatsky.script.Context`, + :py:class:`~chatsky.pipeline.Pipeline` and :py:const:`priority `. + This handler returns a :py:const:`label ` to the start node with a given :py:const:`priority `. If the priority is not given, `Pipeline.actor.label_priority` is used as default. @@ -86,9 +86,9 @@ def to_start_transition_handler(ctx: Context, pipeline: Pipeline) -> ConstLabel: def to_fallback(priority: Optional[float] = None) -> Callable[[Context, Pipeline], ConstLabel]: """ - Returns transition handler that takes :py:class:`~dff.script.Context`, - :py:class:`~dff.pipeline.Pipeline` and :py:const:`priority `. - This handler returns a :py:const:`label ` + Returns transition handler that takes :py:class:`~chatsky.script.Context`, + :py:class:`~chatsky.pipeline.Pipeline` and :py:const:`priority `. + This handler returns a :py:const:`label ` to the fallback node with a given :py:const:`priority `. If the priority is not given, `Pipeline.actor.label_priority` is used as default. @@ -141,9 +141,9 @@ def forward( priority: Optional[float] = None, cyclicality_flag: bool = True ) -> Callable[[Context, Pipeline], ConstLabel]: """ - Returns transition handler that takes :py:class:`~dff.script.Context`, - :py:class:`~dff.pipeline.Pipeline` and :py:const:`priority `. - This handler returns a :py:const:`label ` + Returns transition handler that takes :py:class:`~chatsky.script.Context`, + :py:class:`~chatsky.pipeline.Pipeline` and :py:const:`priority `. + This handler returns a :py:const:`label ` to the forward node with a given :py:const:`priority ` and :py:const:`cyclicality_flag `. If the priority is not given, `Pipeline.actor.label_priority` is used as default. @@ -164,9 +164,9 @@ def backward( priority: Optional[float] = None, cyclicality_flag: bool = True ) -> Callable[[Context, Pipeline], ConstLabel]: """ - Returns transition handler that takes :py:class:`~dff.script.Context`, - :py:class:`~dff.pipeline.Pipeline` and :py:const:`priority `. - This handler returns a :py:const:`label ` + Returns transition handler that takes :py:class:`~chatsky.script.Context`, + :py:class:`~chatsky.pipeline.Pipeline` and :py:const:`priority `. + This handler returns a :py:const:`label ` to the backward node with a given :py:const:`priority ` and :py:const:`cyclicality_flag `. If the priority is not given, `Pipeline.actor.label_priority` is used as default. diff --git a/dff/script/responses/__init__.py b/chatsky/script/responses/__init__.py similarity index 100% rename from dff/script/responses/__init__.py rename to chatsky/script/responses/__init__.py diff --git a/dff/script/responses/std_responses.py b/chatsky/script/responses/std_responses.py similarity index 91% rename from dff/script/responses/std_responses.py rename to chatsky/script/responses/std_responses.py index b80fbe46c..060b6e264 100644 --- a/dff/script/responses/std_responses.py +++ b/chatsky/script/responses/std_responses.py @@ -12,8 +12,8 @@ import random from typing import List -from dff.pipeline import Pipeline -from dff.script import Context, Message +from chatsky.pipeline import Pipeline +from chatsky.script import Context, Message def choice(responses: List[Message]): diff --git a/chatsky/slots/__init__.py b/chatsky/slots/__init__.py new file mode 100644 index 000000000..c0a22623c --- /dev/null +++ b/chatsky/slots/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# flake8: noqa: F401 + +from chatsky.slots.slots import GroupSlot, ValueSlot, RegexpSlot, FunctionSlot +from chatsky.slots.conditions import slots_extracted +from chatsky.slots.processing import extract, extract_all, unset, unset_all, fill_template +from chatsky.slots.response import filled_template diff --git a/dff/slots/conditions.py b/chatsky/slots/conditions.py similarity index 87% rename from dff/slots/conditions.py rename to chatsky/slots/conditions.py index 80ebdf222..d2e3f9d33 100644 --- a/dff/slots/conditions.py +++ b/chatsky/slots/conditions.py @@ -8,9 +8,9 @@ from typing import TYPE_CHECKING, Literal if TYPE_CHECKING: - from dff.script import Context - from dff.slots.slots import SlotName - from dff.pipeline import Pipeline + from chatsky.script import Context + from chatsky.slots.slots import SlotName + from chatsky.pipeline import Pipeline def slots_extracted(*slots: SlotName, mode: Literal["any", "all"] = "all"): diff --git a/dff/slots/processing.py b/chatsky/slots/processing.py similarity index 91% rename from dff/slots/processing.py rename to chatsky/slots/processing.py index 1f99c4c23..df3df43f9 100644 --- a/dff/slots/processing.py +++ b/chatsky/slots/processing.py @@ -1,7 +1,7 @@ """ Processing --------------------------- -This module provides wrappers for :py:class:`~dff.slots.slots.SlotManager`'s API. +This module provides wrappers for :py:class:`~chatsky.slots.slots.SlotManager`'s API. """ from __future__ import annotations @@ -10,9 +10,9 @@ from typing import Awaitable, Callable, TYPE_CHECKING if TYPE_CHECKING: - from dff.slots.slots import SlotName - from dff.script import Context - from dff.pipeline import Pipeline + from chatsky.slots.slots import SlotName + from chatsky.script import Context + from chatsky.pipeline import Pipeline logger = logging.getLogger(__name__) diff --git a/dff/slots/response.py b/chatsky/slots/response.py similarity index 88% rename from dff/slots/response.py rename to chatsky/slots/response.py index 152b79ddb..473960704 100644 --- a/dff/slots/response.py +++ b/chatsky/slots/response.py @@ -1,15 +1,15 @@ """ Response --------------------------- -Slot-related DFF responses. +Slot-related Chatsky responses. """ from __future__ import annotations from typing import Callable, TYPE_CHECKING if TYPE_CHECKING: - from dff.script import Context, Message - from dff.pipeline import Pipeline + from chatsky.script import Context, Message + from chatsky.pipeline import Pipeline def filled_template(template: Message) -> Callable[[Context, Pipeline], Message]: diff --git a/dff/slots/slots.py b/chatsky/slots/slots.py similarity index 97% rename from dff/slots/slots.py rename to chatsky/slots/slots.py index 536501751..29dc44b9a 100644 --- a/dff/slots/slots.py +++ b/chatsky/slots/slots.py @@ -16,12 +16,12 @@ from pydantic import BaseModel, model_validator, Field -from dff.utils.devel.async_helpers import wrap_sync_function_in_async -from dff.utils.devel.json_serialization import PickleEncodedValue +from chatsky.utils.devel.async_helpers import wrap_sync_function_in_async +from chatsky.utils.devel.json_serialization import PickleEncodedValue if TYPE_CHECKING: - from dff.script import Context, Message - from dff.pipeline.pipeline.pipeline import Pipeline + from chatsky.script import Context, Message + from chatsky.pipeline.pipeline.pipeline import Pipeline logger = logging.getLogger(__name__) @@ -88,7 +88,7 @@ class ExtractedSlot(BaseModel, ABC): Represents value of an extracted slot. Instances of this class are managed by framework and - are stored in :py:attr:`~dff.script.core.context.FrameworkData.slot_manager`. + are stored in :py:attr:`~chatsky.script.core.context.FrameworkData.slot_manager`. They can be accessed via the ``ctx.framework_data.slot_manager.get_extracted_slot`` method. """ diff --git a/dff/stats/__init__.py b/chatsky/stats/__init__.py similarity index 100% rename from dff/stats/__init__.py rename to chatsky/stats/__init__.py diff --git a/dff/stats/__main__.py b/chatsky/stats/__main__.py similarity index 98% rename from dff/stats/__main__.py rename to chatsky/stats/__main__.py index 0b1b206cf..e22220119 100644 --- a/dff/stats/__main__.py +++ b/chatsky/stats/__main__.py @@ -13,7 +13,7 @@ # Create and import a configuration archive. # The import overrides existing dashboard configurations. - dff.stats config.yaml \\ + chatsky.stats config.yaml \\ -U superset_user \\ -P superset_password \\ -dP database_password \\ @@ -47,7 +47,7 @@ def main(parsed_args: Optional[argparse.Namespace] = None): The function accepts a yaml file; also, all of the options can also be overridden via the command line. Setting passwords interactively is supported. - dff.stats config.yaml \\ + chatsky.stats config.yaml \\ -U superset_user \\ -P superset_password \\ -dP database_password \\ diff --git a/dff/stats/cli.py b/chatsky/stats/cli.py similarity index 93% rename from dff/stats/cli.py rename to chatsky/stats/cli.py index 3d862a96e..ede565cb6 100644 --- a/dff/stats/cli.py +++ b/chatsky/stats/cli.py @@ -20,26 +20,26 @@ from omegaconf import OmegaConf from .utils import get_superset_session, drop_superset_assets except ImportError: - raise ImportError("Some packages are not found. Run `pip install dff[stats]`") + raise ImportError("Some packages are not found. Run `pip install chatsky[stats]`") logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -DFF_DIR = Path(__file__).absolute().parent.parent +CHATSKY_DIR = Path(__file__).absolute().parent.parent """ -Root directory of the local `dff` installation. +Root directory of the local `chatsky` installation. :meta hide-value: """ -DASHBOARD_DIR = str(DFF_DIR / "config" / "superset_dashboard") +DASHBOARD_DIR = str(CHATSKY_DIR / "config" / "superset_dashboard") """ Local path to superset dashboard files to import. :meta hide-value: """ -DASHBOARD_SLUG = "dff-stats" +DASHBOARD_SLUG = "chatsky-stats" """ -This variable stores a slug used for building the http address of the DFF dashboard. +This variable stores a slug used for building the http address of the Chatsky dashboard. """ DEFAULT_SUPERSET_URL = parse.urlunsplit(("http", "localhost:8088", "/", "", "")) """ @@ -59,7 +59,7 @@ :meta hide-value: """ -DFF_NODE_STATS_STATEMENT = """ +CHATSKY_NODE_STATS_STATEMENT = """ WITH main AS ( SELECT DISTINCT {table}.LogAttributes['context_id'] as context_id, toUInt64OrNull({table}.LogAttributes['request_id']) as request_id, @@ -85,7 +85,7 @@ node_label FROM main """ -DFF_STATS_STATEMENT = """ +CHATSKY_STATS_STATEMENT = """ WITH main AS ( SELECT DISTINCT {table}.LogAttributes['context_id'] as context_id, toUInt64OrNull({table}.LogAttributes['request_id']) as request_id, @@ -111,7 +111,7 @@ node_label FROM main """ -DFF_FINAL_NODES_STATEMENT = """ +CHATSKY_FINAL_NODES_STATEMENT = """ WITH main AS ( SELECT LogAttributes['context_id'] AS context_id, max(toUInt64OrNull(LogAttributes['request_id'])) AS max_history @@ -133,9 +133,9 @@ """ SQL_STATEMENT_MAPPING = { - "dff_stats.yaml": DFF_STATS_STATEMENT, - "dff_node_stats.yaml": DFF_NODE_STATS_STATEMENT, - "dff_final_nodes.yaml": DFF_FINAL_NODES_STATEMENT, + "chatsky_stats.yaml": CHATSKY_STATS_STATEMENT, + "chatsky_node_stats.yaml": CHATSKY_NODE_STATS_STATEMENT, + "chatsky_final_nodes.yaml": CHATSKY_FINAL_NODES_STATEMENT, } """ Select statements for dashboard configuration with names and types represented as placeholders. @@ -171,7 +171,7 @@ def import_dashboard(parsed_args: Optional[argparse.Namespace] = None, zip_file: import_dashboard_url, headers=headers, data={ - "passwords": '{"databases/dff_database.yaml":"' + db_password + '"}', + "passwords": '{"databases/chatsky_database.yaml":"' + db_password + '"}', "overwrite": "true", }, files=[("formData", (zip_filename, f, "application/zip"))], @@ -236,7 +236,7 @@ def make_zip_config(parsed_args: argparse.Namespace) -> Path: shutil.copytree(DASHBOARD_DIR, nested_temp_dir) database_dir = Path(os.path.join(nested_temp_dir, "databases")) - dataset_dir = Path(os.path.join(nested_temp_dir, "datasets/dff_database")) + dataset_dir = Path(os.path.join(nested_temp_dir, "datasets/chatsky_database")) logger.info("Overriding the initial configuration.") # overwrite sqlalchemy uri diff --git a/dff/stats/default_extractors.py b/chatsky/stats/default_extractors.py similarity index 96% rename from dff/stats/default_extractors.py rename to chatsky/stats/default_extractors.py index 9b3856e2a..e390148f5 100644 --- a/dff/stats/default_extractors.py +++ b/chatsky/stats/default_extractors.py @@ -13,8 +13,8 @@ from datetime import datetime -from dff.script import Context -from dff.pipeline import ExtraHandlerRuntimeInfo, Pipeline +from chatsky.script import Context +from chatsky.pipeline import ExtraHandlerRuntimeInfo, Pipeline from .utils import get_extra_handler_name diff --git a/dff/stats/instrumentor.py b/chatsky/stats/instrumentor.py similarity index 93% rename from dff/stats/instrumentor.py rename to chatsky/stats/instrumentor.py index 30f7cd20f..a395c7b4c 100644 --- a/dff/stats/instrumentor.py +++ b/chatsky/stats/instrumentor.py @@ -3,7 +3,7 @@ ------------- This modules contains the :py:class:`~OtelInstrumentor` class that implements Opentelemetry's `BaseInstrumentor` interface and allows for automated -instrumentation of Dialog Flow Framework applications, +instrumentation of Chatsky applications, e.g. for automated logging and log export. For detailed reference, see `~OtelInstrumentor` class. @@ -26,23 +26,23 @@ from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter -from dff.script.core.context import get_last_index -from dff.stats.utils import ( +from chatsky.script.core.context import get_last_index +from chatsky.stats.utils import ( resource, get_extra_handler_name, set_logger_destination, set_meter_destination, set_tracer_destination, ) -from dff.stats import default_extractors +from chatsky.stats import default_extractors -INSTRUMENTS = ["dff"] +INSTRUMENTS = ["chatsky"] class OtelInstrumentor(BaseInstrumentor): """ - Utility class for instrumenting DFF-related functions + Utility class for instrumenting Chatsky-related functions that implements the :py:class:`~BaseInstrumentor` interface. :py:meth:`~instrument` and :py:meth:`~uninstrument` methods are available to apply and revert the instrumentation effects, @@ -50,9 +50,9 @@ class OtelInstrumentor(BaseInstrumentor): .. code-block:: - dff_instrumentor = OtelInstrumentor() - dff_instrumentor.instrument() - dff_instrumentor.uninstrument() + chatsky_instrumentor = OtelInstrumentor() + chatsky_instrumentor.instrument() + chatsky_instrumentor.uninstrument() Opentelemetry provider instances can be optionally passed to the class constructor. Otherwise, the global logger, tracer and meter providers are leveraged. @@ -62,7 +62,7 @@ class OtelInstrumentor(BaseInstrumentor): .. code-block:: - @dff_instrumentor + @chatsky_instrumentor async def function(context, pipeline, runtime_info): ... @@ -145,7 +145,7 @@ def _configure_providers(self, logger_provider, tracer_provider, meter_provider) @decorator async def __call__(self, wrapped, _, args, kwargs): """ - Regular functions that match the :py:class:`~dff.pipeline.types.ExtraHandlerFunction` + Regular functions that match the :py:class:`~chatsky.pipeline.types.ExtraHandlerFunction` signature can be decorated with the class instance to log the returned value. This method implements the logging procedure. The returned value is assumed to be `dict` or `NoneType`. diff --git a/dff/stats/utils.py b/chatsky/stats/utils.py similarity index 97% rename from dff/stats/utils.py rename to chatsky/stats/utils.py index 7e2152ccd..51ac9ad4d 100644 --- a/dff/stats/utils.py +++ b/chatsky/stats/utils.py @@ -33,9 +33,9 @@ from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter, LogExporter from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter, MetricExporter -from dff.pipeline import ExtraHandlerRuntimeInfo +from chatsky.pipeline import ExtraHandlerRuntimeInfo -SERVICE_NAME = "dialog_flow_framework" +SERVICE_NAME = "chatsky" resource = Resource.create({"service.name": SERVICE_NAME}) """ @@ -43,11 +43,11 @@ """ tracer_provider = TracerProvider(resource=resource) """ -Global tracer provider bound to the DFF resource. +Global tracer provider bound to the Chatsky resource. """ logger_provider = LoggerProvider(resource=resource) """ -Global logger provider bound to the DFF resource. +Global logger provider bound to the Chatsky resource. """ set_logger_provider(logger_provider) set_tracer_provider(tracer_provider) diff --git a/dff/utils/__init__.py b/chatsky/utils/__init__.py similarity index 100% rename from dff/utils/__init__.py rename to chatsky/utils/__init__.py diff --git a/chatsky/utils/db_benchmark/__init__.py b/chatsky/utils/db_benchmark/__init__.py new file mode 100644 index 000000000..9b464f464 --- /dev/null +++ b/chatsky/utils/db_benchmark/__init__.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +from chatsky.utils.db_benchmark.benchmark import ( + time_context_read_write, + DBFactory, + BenchmarkConfig, + BenchmarkCase, + save_results_to_file, + benchmark_all, +) +from chatsky.utils.db_benchmark.report import report +from chatsky.utils.db_benchmark.basic_config import BasicBenchmarkConfig, basic_configurations diff --git a/dff/utils/db_benchmark/basic_config.py b/chatsky/utils/db_benchmark/basic_config.py similarity index 98% rename from dff/utils/db_benchmark/basic_config.py rename to chatsky/utils/db_benchmark/basic_config.py index f4d590c35..11e744dd0 100644 --- a/dff/utils/db_benchmark/basic_config.py +++ b/chatsky/utils/db_benchmark/basic_config.py @@ -15,8 +15,8 @@ from humanize import naturalsize from pympler import asizeof -from dff.script import Message, Context -from dff.utils.db_benchmark.benchmark import BenchmarkConfig +from chatsky.script import Message, Context +from chatsky.utils.db_benchmark.benchmark import BenchmarkConfig def get_dict(dimensions: Tuple[int, ...]): diff --git a/dff/utils/db_benchmark/benchmark.py b/chatsky/utils/db_benchmark/benchmark.py similarity index 97% rename from dff/utils/db_benchmark/benchmark.py rename to chatsky/utils/db_benchmark/benchmark.py index 8e1eab523..f1132d283 100644 --- a/dff/utils/db_benchmark/benchmark.py +++ b/chatsky/utils/db_benchmark/benchmark.py @@ -12,10 +12,10 @@ Wrappers use :py:class:`~.BenchmarkConfig` interface to configure benchmarks. A simple configuration class as well as a configuration set are provided by -:py:mod:`dff.utils.db_benchmark.basic_config`. +:py:mod:`chatsky.utils.db_benchmark.basic_config`. To view files generated by :py:func:`~.save_results_to_file` use either -:py:func:`~dff.utils.db_benchmark.report.report` or +:py:func:`~chatsky.utils.db_benchmark.report.report` or `our streamlit app <../_misc/benchmark_streamlit.py>`_. """ @@ -32,8 +32,8 @@ from pydantic import BaseModel, Field from tqdm.auto import tqdm -from dff.context_storages import DBContextStorage -from dff.script import Context +from chatsky.context_storages import DBContextStorage +from chatsky.script import Context def time_context_read_write( @@ -60,7 +60,7 @@ def time_context_read_write( (to emulate context updating during dialog). The function should return `None` to stop updating contexts. For an example of such function, see implementation of - :py:meth:`dff.utils.db_benchmark.basic_config.BasicBenchmarkConfig.context_updater`. + :py:meth:`chatsky.utils.db_benchmark.basic_config.BasicBenchmarkConfig.context_updater`. To avoid keeping many contexts in memory, this function will be called repeatedly at least `context_num` times. @@ -134,7 +134,7 @@ class DBFactory(BaseModel): uri: str """URI of the context storage.""" - factory_module: str = "dff.context_storages" + factory_module: str = "chatsky.context_storages" """A module containing `factory`.""" factory: str = "context_storage_factory" """Name of the context storage factory. (function that creates context storages from URIs)""" @@ -155,7 +155,7 @@ class BenchmarkConfig(BaseModel, abc.ABC, frozen=True): Also defines a method (`info`) for displaying information about this configuration. A simple way to configure benchmarks is provided by - :py:class:`~.dff.utils.db_benchmark.basic_config.BasicBenchmarkConfig`. + :py:class:`~.chatsky.utils.db_benchmark.basic_config.BasicBenchmarkConfig`. Inherit from this class only if `BasicBenchmarkConfig` is not enough for your benchmarking needs. """ @@ -344,7 +344,7 @@ def save_results_to_file( Result are saved in json format with this schema: `utils/db_benchmark/benchmark_schema.json <../_misc/benchmark_schema.json>`_. - Files created by this function cen be viewed either by using :py:func:`~dff.utils.db_benchmark.report.report` or + Files created by this function cen be viewed either by using :py:func:`~chatsky.utils.db_benchmark.report.report` or streamlit app located in the utils directory: `utils/db_benchmark/benchmark_streamlit.py <../_misc/benchmark_streamlit.py>`_. diff --git a/dff/utils/db_benchmark/report.py b/chatsky/utils/db_benchmark/report.py similarity index 96% rename from dff/utils/db_benchmark/report.py rename to chatsky/utils/db_benchmark/report.py index 4de986c26..1bccf777a 100644 --- a/dff/utils/db_benchmark/report.py +++ b/chatsky/utils/db_benchmark/report.py @@ -21,7 +21,7 @@ def report( :param file: File with benchmark results generated by - :py:func:`~dff.utils.db_benchmark.benchmark.save_results_to_file`. + :py:func:`~chatsky.utils.db_benchmark.benchmark.save_results_to_file`. :param display: A set of objects to display in results. Values allowed inside the set: diff --git a/dff/utils/devel/__init__.py b/chatsky/utils/devel/__init__.py similarity index 100% rename from dff/utils/devel/__init__.py rename to chatsky/utils/devel/__init__.py diff --git a/dff/utils/devel/async_helpers.py b/chatsky/utils/devel/async_helpers.py similarity index 100% rename from dff/utils/devel/async_helpers.py rename to chatsky/utils/devel/async_helpers.py diff --git a/dff/utils/devel/extra_field_helpers.py b/chatsky/utils/devel/extra_field_helpers.py similarity index 100% rename from dff/utils/devel/extra_field_helpers.py rename to chatsky/utils/devel/extra_field_helpers.py diff --git a/dff/utils/devel/json_serialization.py b/chatsky/utils/devel/json_serialization.py similarity index 100% rename from dff/utils/devel/json_serialization.py rename to chatsky/utils/devel/json_serialization.py diff --git a/chatsky/utils/docker/README.md b/chatsky/utils/docker/README.md new file mode 100644 index 000000000..5b4457a54 --- /dev/null +++ b/chatsky/utils/docker/README.md @@ -0,0 +1,11 @@ +# Chatsky Docker utils + +## Description + +This directory provides Docker files, necessary for deployment +of various Chatsky utilities. + +## Contents + +* dockerfile_stats - Dockerfile for Chatsky statistics dashboard. +* entrypoint_stats.sh - Entrypoint script for Chatsky statistics dashboard. \ No newline at end of file diff --git a/dff/utils/docker/dockerfile_stats b/chatsky/utils/docker/dockerfile_stats similarity index 100% rename from dff/utils/docker/dockerfile_stats rename to chatsky/utils/docker/dockerfile_stats diff --git a/dff/utils/docker/entrypoint_stats.sh b/chatsky/utils/docker/entrypoint_stats.sh similarity index 100% rename from dff/utils/docker/entrypoint_stats.sh rename to chatsky/utils/docker/entrypoint_stats.sh diff --git a/dff/utils/docker/superset_config_docker.py b/chatsky/utils/docker/superset_config_docker.py similarity index 100% rename from dff/utils/docker/superset_config_docker.py rename to chatsky/utils/docker/superset_config_docker.py diff --git a/dff/utils/otel/otelcol-config-extras.yml b/chatsky/utils/otel/otelcol-config-extras.yml similarity index 100% rename from dff/utils/otel/otelcol-config-extras.yml rename to chatsky/utils/otel/otelcol-config-extras.yml diff --git a/dff/utils/otel/otelcol-config.yml b/chatsky/utils/otel/otelcol-config.yml similarity index 100% rename from dff/utils/otel/otelcol-config.yml rename to chatsky/utils/otel/otelcol-config.yml diff --git a/dff/utils/parser/__init__.py b/chatsky/utils/parser/__init__.py similarity index 100% rename from dff/utils/parser/__init__.py rename to chatsky/utils/parser/__init__.py diff --git a/dff/utils/testing/__init__.py b/chatsky/utils/testing/__init__.py similarity index 79% rename from dff/utils/testing/__init__.py rename to chatsky/utils/testing/__init__.py index 4e1de7c35..2e13da083 100644 --- a/dff/utils/testing/__init__.py +++ b/chatsky/utils/testing/__init__.py @@ -6,6 +6,6 @@ try: import pytest - pytest.register_assert_rewrite("dff.utils.testing.telegram") + pytest.register_assert_rewrite("chatsky.utils.testing.telegram") except ImportError: ... diff --git a/dff/utils/testing/cleanup_db.py b/chatsky/utils/testing/cleanup_db.py similarity index 98% rename from dff/utils/testing/cleanup_db.py rename to chatsky/utils/testing/cleanup_db.py index a9bdff792..fdc8f4635 100644 --- a/dff/utils/testing/cleanup_db.py +++ b/chatsky/utils/testing/cleanup_db.py @@ -7,7 +7,7 @@ import os -from dff.context_storages import ( +from chatsky.context_storages import ( JSONContextStorage, MongoContextStorage, PickleContextStorage, diff --git a/dff/utils/testing/common.py b/chatsky/utils/testing/common.py similarity index 96% rename from dff/utils/testing/common.py rename to chatsky/utils/testing/common.py index 77310b2b6..6f8890ff8 100644 --- a/dff/utils/testing/common.py +++ b/chatsky/utils/testing/common.py @@ -8,9 +8,9 @@ from typing import Callable, Tuple, Optional, Union from uuid import uuid4 -from dff.script import Context, Message -from dff.pipeline import Pipeline -from dff.utils.testing.response_comparers import default_comparer +from chatsky.script import Context, Message +from chatsky.pipeline import Pipeline +from chatsky.utils.testing.response_comparers import default_comparer def is_interactive_mode() -> bool: # pragma: no cover diff --git a/dff/utils/testing/response_comparers.py b/chatsky/utils/testing/response_comparers.py similarity index 93% rename from dff/utils/testing/response_comparers.py rename to chatsky/utils/testing/response_comparers.py index b5c86af22..dd6c9189a 100644 --- a/dff/utils/testing/response_comparers.py +++ b/chatsky/utils/testing/response_comparers.py @@ -6,7 +6,7 @@ from typing import Any, Optional -from dff.script import Context, Message +from chatsky.script import Context, Message def default_comparer(candidate: Message, reference: Message, _: Context) -> Optional[Any]: diff --git a/dff/utils/testing/toy_script.py b/chatsky/utils/testing/toy_script.py similarity index 96% rename from dff/utils/testing/toy_script.py rename to chatsky/utils/testing/toy_script.py index ee56a7ecf..1f0c38dd4 100644 --- a/dff/utils/testing/toy_script.py +++ b/chatsky/utils/testing/toy_script.py @@ -5,8 +5,8 @@ in tutorials. """ -from dff.script.conditions import exact_match -from dff.script import TRANSITIONS, RESPONSE, Message +from chatsky.script.conditions import exact_match +from chatsky.script import TRANSITIONS, RESPONSE, Message TOY_SCRIPT = { "greeting_flow": { @@ -41,7 +41,7 @@ TOY_SCRIPT_ARGS = (TOY_SCRIPT, ("greeting_flow", "start_node"), ("greeting_flow", "fallback_node")) """ -Arguments to pass to :py:meth:`~dff.pipeline.pipeline.pipeline.Pipeline.from_script` in order to +Arguments to pass to :py:meth:`~chatsky.pipeline.pipeline.pipeline.Pipeline.from_script` in order to use :py:data:`~.TOY_SCRIPT`: .. code-block:: diff --git a/dff/utils/turn_caching/__init__.py b/chatsky/utils/turn_caching/__init__.py similarity index 100% rename from dff/utils/turn_caching/__init__.py rename to chatsky/utils/turn_caching/__init__.py diff --git a/dff/utils/turn_caching/singleton_turn_caching.py b/chatsky/utils/turn_caching/singleton_turn_caching.py similarity index 100% rename from dff/utils/turn_caching/singleton_turn_caching.py rename to chatsky/utils/turn_caching/singleton_turn_caching.py diff --git a/dff/utils/viewer/__init__.py b/chatsky/utils/viewer/__init__.py similarity index 100% rename from dff/utils/viewer/__init__.py rename to chatsky/utils/viewer/__init__.py diff --git a/compose.yml b/compose.yml index dc477fd78..dd3f17c53 100644 --- a/compose.yml +++ b/compose.yml @@ -106,7 +106,7 @@ services: dashboard: env_file: [.env_file] build: - context: ./dff/utils/docker + context: ./chatsky/utils/docker dockerfile: dockerfile_stats image: ghcr.io/deeppavlov/superset_df_dashboard:latest depends_on: @@ -169,8 +169,8 @@ services: clickhouse: condition: service_healthy volumes: - - ./dff/utils/otel/otelcol-config.yml:/etc/otelcol-config.yml:ro - - ./dff/utils/otel/otelcol-config-extras.yml:/etc/otelcol-config-extras.yml:ro + - ./chatsky/utils/otel/otelcol-config.yml:/etc/otelcol-config.yml:ro + - ./chatsky/utils/otel/otelcol-config-extras.yml:/etc/otelcol-config-extras.yml:ro ports: - "4317:4317" # OTLP over gRPC receiver - "4318:4318" # OTLP over HTTP receiver diff --git a/dff/__rebuild_pydantic_models__.py b/dff/__rebuild_pydantic_models__.py deleted file mode 100644 index 6702006b7..000000000 --- a/dff/__rebuild_pydantic_models__.py +++ /dev/null @@ -1,9 +0,0 @@ -# flake8: noqa: F401 - -from dff.pipeline import Pipeline -from dff.pipeline.types import ExtraHandlerRuntimeInfo -from dff.script import Context, Script - -Script.model_rebuild() -Context.model_rebuild() -ExtraHandlerRuntimeInfo.model_rebuild() diff --git a/dff/slots/__init__.py b/dff/slots/__init__.py deleted file mode 100644 index 7579a8523..000000000 --- a/dff/slots/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# -*- coding: utf-8 -*- -# flake8: noqa: F401 - -from dff.slots.slots import GroupSlot, ValueSlot, RegexpSlot, FunctionSlot -from dff.slots.conditions import slots_extracted -from dff.slots.processing import extract, extract_all, unset, unset_all, fill_template -from dff.slots.response import filled_template diff --git a/dff/utils/db_benchmark/__init__.py b/dff/utils/db_benchmark/__init__.py deleted file mode 100644 index 6d02f7a8d..000000000 --- a/dff/utils/db_benchmark/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -from dff.utils.db_benchmark.benchmark import ( - time_context_read_write, - DBFactory, - BenchmarkConfig, - BenchmarkCase, - save_results_to_file, - benchmark_all, -) -from dff.utils.db_benchmark.report import report -from dff.utils.db_benchmark.basic_config import BasicBenchmarkConfig, basic_configurations diff --git a/dff/utils/docker/README.md b/dff/utils/docker/README.md deleted file mode 100644 index 6caf4490f..000000000 --- a/dff/utils/docker/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# DFF Docker utils - -## Description - -This directory provides Docker files, necessary for deployment -of various DFF utilities. - -## Contents - -* dockerfile_stats - Dockerfile for DFF statistics dashboard. -* entrypoint_stats.sh - Entrypoint script for DFF statistics dashboard. \ No newline at end of file diff --git a/docs/source/_templates/example-links.html b/docs/source/_templates/example-links.html index 6e03f6b22..5ba1edc8f 100644 --- a/docs/source/_templates/example-links.html +++ b/docs/source/_templates/example-links.html @@ -1,8 +1,8 @@ {% if meta is defined and meta is not none and 'tutorial_name' in meta %} {% set repo_path = "/".join(meta['tutorial_name'].split("/")[-1].split(".")) %} - {% set github_link = 'https://github.com/deeppavlov/dialog_flow_framework/blob/master/' ~ repo_path ~ '.py' %} + {% set github_link = 'https://github.com/deeppavlov/chatsky/blob/master/' ~ repo_path ~ '.py' %} {% set notebook_link = '../' ~ meta['tutorial_name'] ~ '.ipynb' %} - {% set colab_link = 'https://colab.research.google.com/github/deeppavlov/dialog_flow_framework/blob/gh-pages/' ~ meta['tutorial_name'] ~ '.ipynb' %} + {% set colab_link = 'https://colab.research.google.com/github/deeppavlov/chatsky/blob/gh-pages/' ~ meta['tutorial_name'] ~ '.ipynb' %}