├── marque ├── py.typed ├── __init__.py ├── helpers.py ├── logging.py ├── util.py ├── scope.py ├── storage.py └── flow.py ├── .vscode └── settings.json ├── .github └── workflows │ ├── publish.yml │ └── ci.yml ├── LICENSE ├── pyproject.toml ├── README.md ├── .gitignore └── poetry.lock /marque/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[python]": { 3 | "editor.formatOnSave": true, 4 | "editor.codeActionsOnSave": { 5 | "source.fixAll": "explicit", 6 | "source.organizeImports": "explicit" 7 | }, 8 | "editor.defaultFormatter": "charliermarsh.ruff" 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /marque/__init__.py: -------------------------------------------------------------------------------- 1 | from marque.flow import Flow 2 | from marque.helpers import repeat, retry 3 | from marque.scope import Scope 4 | from marque.storage import JsonStorage, MemoryStorage, PolarsStorage 5 | 6 | __all__ = ["Flow", "Scope", "repeat", "retry", "MemoryStorage", "PolarsStorage", "JsonStorage"] 7 | 8 | from loguru import logger 9 | 10 | logger.disable("marque") 11 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Build and Publish 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | jobs: 8 | build-and-publish: 9 | environment: protected 10 | permissions: 11 | contents: read 12 | id-token: write 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Set up Python 20 | uses: actions/setup-python@v2 21 | with: 22 | python-version: '3.9' 23 | 24 | - name: Setup Poetry 25 | uses: abatilo/actions-poetry@v2 26 | 27 | - name: Configure local .venv 28 | run: | 29 | poetry config virtualenvs.create true --local 30 | poetry config virtualenvs.in-project true --local 31 | 32 | - uses: actions/cache@v3 33 | name: Cache Dependencies 34 | with: 35 | path: ./.venv 36 | key: venv-${{ hashFiles('poetry.lock') }} 37 | 38 | - name: Install dependencies 39 | run: poetry install 40 | 41 | - name: Build package 42 | run: poetry build 43 | 44 | - name: Publish to PyPI 45 | uses: pypa/gh-action-pypi-publish@release/v1 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 dreadnode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Lint, Typecheck, and Test 2 | 3 | on: 4 | push: 5 | branches: [ main, dev ] 6 | pull_request: 7 | branches: [ main, dev ] 8 | 9 | jobs: 10 | ci: 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | python-version: ["3.9", "3.10", "3.11"] 15 | 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - name: Set up Python 22 | uses: actions/setup-python@v2 23 | with: 24 | python-version: ${{ matrix.python-version }} 25 | 26 | - name: Setup Poetry 27 | uses: abatilo/actions-poetry@v2 28 | 29 | - name: Configure local .venv 30 | run: | 31 | poetry config virtualenvs.create true --local 32 | poetry config virtualenvs.in-project true --local 33 | 34 | - uses: actions/cache@v3 35 | name: Cache Dependencies 36 | with: 37 | path: ./.venv 38 | key: venv-${{ hashFiles('poetry.lock') }} 39 | 40 | - name: Install dependencies 41 | run: poetry install 42 | 43 | - name: Linting 44 | run: poetry run ruff -v marque/ 45 | 46 | - name: Typecheck 47 | run: poetry run mypy -v marque/ -------------------------------------------------------------------------------- /marque/helpers.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import traceback 3 | 4 | from marque.flow import Flow, StepFunc 5 | 6 | 7 | def repeat(step: StepFunc | list[StepFunc], times: int) -> list[StepFunc]: 8 | steps = step if isinstance(step, list) else [step] 9 | return steps * times 10 | 11 | 12 | # TODO: We should probably integrate this better with the flow 13 | # management and handle storing errored scopes for inspection 14 | # if we need them. 15 | 16 | 17 | def retry(step: StepFunc, max_times: int) -> StepFunc: 18 | @functools.wraps(step) 19 | def _retry(flow: Flow) -> None: 20 | max_times_str = "inf" if max_times == -1 else str(max_times) 21 | i = 0 22 | while max_times == -1 or i < max_times: 23 | try: 24 | flow.log(f" |: Attempting {step.__name__} [{i+1}/{max_times_str}]") 25 | return step(flow) 26 | except Exception: 27 | if max_times != -1 and i == max_times - 1: 28 | flow.error(f" |: Exceeded max attempts ({max_times}) for {step.__name__}") 29 | raise 30 | flow.error(f" |: {traceback.format_exc()}") 31 | pass 32 | i += 1 33 | 34 | return _retry 35 | -------------------------------------------------------------------------------- /marque/logging.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | import sys 3 | import typing as t 4 | 5 | from loguru import logger 6 | 7 | g_configured: bool = False 8 | 9 | LogLevelList = ["trace", "debug", "info", "success", "warning", "error", "critical"] 10 | LogLevelLiteral = t.Literal["trace", "debug", "info", "success", "warning", "error", "critical"] 11 | 12 | 13 | def configure_logging( 14 | log_level: str, 15 | log_file: pathlib.Path | None = None, 16 | log_file_level: LogLevelLiteral = "debug", 17 | ) -> None: 18 | global g_configured 19 | 20 | if g_configured: 21 | return 22 | 23 | logger.enable("marque") 24 | 25 | logger.level("TRACE", color="", icon="[T]") 26 | logger.level("DEBUG", color="", icon="[_]") 27 | logger.level("INFO", color="", icon="[=]") 28 | logger.level("SUCCESS", color="", icon="[+]") 29 | logger.level("WARNING", color="", icon="[-]") 30 | logger.level("ERROR", color="", icon="[!]") 31 | logger.level("CRITICAL", color="", icon="[x]") 32 | 33 | # Default format: 34 | # "{time:YYYY-MM-DD HH:mm:ss.SSS} | " 35 | # "{level: <8} | " 36 | # "{name}:{function}:{line} - {message}", 37 | 38 | custom_format = "{time:HH:mm:ss.SSS} | {level.icon} {message}" 39 | 40 | logger.remove() 41 | logger.add(sys.stderr, format=custom_format, level=log_level.upper()) 42 | 43 | if log_file is not None: 44 | logger.add(log_file, format=custom_format, level=log_file_level.upper()) 45 | logger.info(f"Logging to {log_file}") 46 | 47 | g_configured = True 48 | -------------------------------------------------------------------------------- /marque/util.py: -------------------------------------------------------------------------------- 1 | import builtins 2 | import typing as t 3 | from contextlib import contextmanager 4 | from datetime import timedelta 5 | 6 | import orjson 7 | from pydantic import BaseModel 8 | 9 | 10 | def json_serialize(obj: t.Any) -> str: 11 | def custom_serializer(obj: t.Any) -> t.Any: 12 | if isinstance(obj, BaseModel): 13 | return obj.dict() 14 | return obj 15 | 16 | return orjson.dumps(obj, default=custom_serializer).decode() 17 | 18 | 19 | def json_deserialize(obj: str) -> t.Any: 20 | return orjson.loads(obj) 21 | 22 | 23 | # https://stackoverflow.com/questions/538666/format-timedelta-to-string 24 | def format_timedelta(td_object: timedelta) -> str: 25 | # Convert the entire timedelta to milliseconds 26 | total_milliseconds = ( 27 | td_object.days * 24 * 60 * 60 * 1000 + td_object.seconds * 1000 + td_object.microseconds // 1000 28 | ) 29 | 30 | periods = [ 31 | ("yr", 60 * 60 * 24 * 365 * 1000), 32 | ("mo", 60 * 60 * 24 * 30 * 1000), 33 | ("d", 60 * 60 * 24 * 1000), 34 | ("hr", 60 * 60 * 1000), 35 | ("m", 60 * 1000), 36 | ("s", 1000), 37 | ("ms", 1), 38 | ] 39 | 40 | strings = [] 41 | for period_name, period_milliseconds in periods: 42 | if total_milliseconds >= period_milliseconds: 43 | period_value, total_milliseconds = divmod(total_milliseconds, period_milliseconds) 44 | strings.append(f"{period_value}{period_name}") 45 | 46 | return " ".join(strings) if strings else "~0ms" 47 | 48 | 49 | @contextmanager 50 | def PrintHook(log_func: t.Callable[[str], None]) -> t.Iterator[None]: 51 | original_print = builtins.print 52 | 53 | def custom_print(*args: t.Any, **kwargs: t.Any) -> None: 54 | log_message = " ".join(str(arg) for arg in args) 55 | log_func(log_message) 56 | 57 | builtins.print = custom_print 58 | 59 | try: 60 | yield 61 | finally: 62 | builtins.print = original_print 63 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "marque" 3 | version = "0.1.1" 4 | description = "Minimal workflows" 5 | authors = ["Nick Landers "] 6 | readme = "README.md" 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.10" 10 | polars = "^0.20.5" 11 | orjson = "^3.9.12" 12 | coolname = "^2.2.0" 13 | loguru = "^0.7.2" 14 | pydantic = "^2.6.4" 15 | 16 | [tool.poetry.group.dev.dependencies] 17 | mypy = "^1.8.0" 18 | ruff = "^0.1.14" 19 | ipykernel = "^6.29.0" 20 | 21 | [build-system] 22 | requires = ["poetry-core"] 23 | build-backend = "poetry.core.masonry.api" 24 | 25 | [tool.mypy] 26 | strict=true 27 | 28 | [tool.ruff] 29 | select = [ 30 | "E", # pycodestyle errors 31 | "W", # pycodestyle warnings 32 | "F", # pyflakes 33 | "I", # isort 34 | "C", # flake8-comprehensions 35 | "B", # flake8-bugbear 36 | "UP", # pyupgrade 37 | "NPY", # numpydoc 38 | "TCH", # typecheck 39 | "A", # flake8-annotations 40 | ] 41 | ignore = [ 42 | "E501", # line too long, handled by black 43 | "B008", # do not perform function calls in argument defaults 44 | "C901", # too complex 45 | "W191", # indentation contains tabs 46 | "F722", # syntax error in forward annotation 47 | ] 48 | 49 | exclude = [ 50 | ".bzr", 51 | ".direnv", 52 | ".eggs", 53 | ".git", 54 | ".git-rewrite", 55 | ".hg", 56 | ".mypy_cache", 57 | ".nox", 58 | ".pants.d", 59 | ".pytype", 60 | ".ruff_cache", 61 | ".svn", 62 | ".tox", 63 | ".venv", 64 | "__pypackages__", 65 | "_build", 66 | "buck-out", 67 | "build", 68 | "dist", 69 | "node_modules", 70 | "venv", 71 | ] 72 | 73 | line-length = 120 74 | indent-width = 4 75 | target-version = "py310" 76 | 77 | [tool.ruff.lint] 78 | fixable = ["ALL"] 79 | unfixable = ["B"] 80 | 81 | dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" 82 | 83 | [tool.ruff.format] 84 | quote-style = "double" 85 | indent-style = "space" 86 | skip-magic-trailing-comma = false 87 | line-ending = "auto" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # marque 2 | 3 | marque (mark) is a minimal library for building workflows and pipelines in python. It has basic primitives for storing long-term data (`keep()/recall()`), passing runtime context (`put()/get()`), and dynamically extending the flow as it's executing (`push()`). 4 | 5 | - `Flow`: Defines the workflow and orchestrates it 6 | - `Context`: Runtime object storage for flexible dependencies 7 | - `Step`: Individual function in the workflow 8 | - `Scope`: A storage object provided to each step for artifacts/tagging 9 | - `Tag`: A `str, float | None` pair you can use to label a scope 10 | - `Artifact`: Arbitrary data you want to keep and recall later 11 | 12 | The output of a flow is essentially a set of `Scope` objects which represent all the important data generated during the workflow run. You can use the `search()` function to find prior scopes and use their data to prepare new steps. 13 | 14 | Here is a basic example: 15 | 16 | ```python 17 | from random import Random 18 | 19 | from marque import Flow, repeat 20 | from marque.storage import PolarsStorage 21 | 22 | 23 | def add(flow: Flow): 24 | a, b = flow.get(int, ["a", "b"]) # pull values from the current context 25 | flow.tag(f"{a} + {b}") # add tags for faster analytics/filtering 26 | flow.keep("data", {"answer": a + b}) # persist data to recall later 27 | 28 | def sub(flow: Flow): 29 | a, b = flow.get(int, ["a", "b"]) 30 | flow.tag(f"{a} - {b}") 31 | flow.keep("data", {"answer": a - b}) 32 | 33 | def simple_math(flow: Flow): 34 | random = flow.get(Random) # pull context values using only types 35 | 36 | a = random.randint(10, 100) 37 | b = random.randint(10, 100) 38 | 39 | flow.push( 40 | random.choice([add, sub]), # extend the workflow with a new step 41 | a=a, b=b # pass required context values 42 | ) 43 | 44 | def inspect_add(flow: Flow): 45 | for scope in flow.search( # search prior scopes and filter 46 | "*", # glob syntax is supported 47 | where=lambda tag: "+" in tag.content 48 | ): 49 | for tag in scope.tags: 50 | flow.log(tag.content) 51 | 52 | def inspect_sub(flow: Flow): 53 | for scope in flow.search(sub): # or just pass the function 54 | flow.log(scope.recall("data")["answer"]) # and pull data from the scope 55 | 56 | flow = ( 57 | Flow("test", PolarsStorage("test.parquet")) # persist data to a parquet file 58 | .fail_fast() # don't ignore errors 59 | .put(random=Random(42)) # prepare a seeded random generator 60 | .push(repeat(simple_math, 5)) # add 5 steps for simple_math 61 | .push([inspect_add, inspect_sub]) # run after everything else 62 | ) 63 | 64 | flow() # Execute our flow 65 | 66 | print(flow.run) # The run id (2-part slug) 67 | print(flow.logs) # list of any logs 68 | print(flow.scopes) # list of all scopes 69 | print(flow.errors) # any errors if we don't fail_fast 70 | 71 | ``` -------------------------------------------------------------------------------- /marque/scope.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import typing as t 3 | from dataclasses import dataclass 4 | from datetime import timedelta 5 | 6 | from pydantic import TypeAdapter 7 | 8 | 9 | @dataclass 10 | class Tag: 11 | content: str 12 | value: float | None = None 13 | 14 | def __repr__(self) -> str: 15 | return f"" 16 | 17 | 18 | @dataclass 19 | class Artifact: 20 | name: str 21 | value: dict[str, t.Any] 22 | 23 | def __repr__(self) -> str: 24 | return f"" 25 | 26 | 27 | class Scope: 28 | def __init__(self, id_: str): 29 | self.id = id_ 30 | self.tags: list[Tag] = [] 31 | self.artifacts: list[Artifact] = [] 32 | self.error: str | None = None 33 | self.duration: timedelta | None = None 34 | 35 | def __repr__(self) -> str: 36 | return f"" 37 | 38 | # TODO: This could probably get pulled out to the utils 39 | # module and rework these as BaseModels or dataclasses 40 | 41 | def to_json(self) -> dict[str, t.Any]: 42 | artifact_adapter = TypeAdapter(Artifact) 43 | tag_adapter = TypeAdapter(Tag) 44 | 45 | return { 46 | "id": self.id, 47 | "tags": [tag_adapter.dump_python(tag) for tag in self.tags], 48 | "artifacts": [artifact_adapter.dump_python(artifact) for artifact in self.artifacts], 49 | "error": self.error, 50 | "duration": self.duration.microseconds if self.duration else None, 51 | } 52 | 53 | @classmethod 54 | def from_json(cls, data: dict[str, t.Any]) -> "Scope": 55 | artifact_adapter = TypeAdapter(Artifact) 56 | tag_adapter = TypeAdapter(Tag) 57 | 58 | scope = cls(data["id"]) 59 | scope.tags = [tag_adapter.validate_python(tag) for tag in data["tags"]] 60 | scope.artifacts = [artifact_adapter.validate_python(artifact) for artifact in data["artifacts"]] 61 | scope.error = data["error"] 62 | scope.duration = datetime.timedelta(microseconds=data["duration"]) if data["duration"] else None 63 | 64 | return scope 65 | 66 | def keep(self, name: str, value: dict[str, t.Any], overwrite: bool = False) -> "Scope": 67 | if not isinstance(value, dict): 68 | raise TypeError(f"{value} is not a dict.") 69 | 70 | for existing in self.artifacts: 71 | if existing.name == name: 72 | if overwrite: 73 | existing.value = value 74 | break 75 | else: 76 | raise KeyError(f"{name} already exists.") 77 | else: 78 | self.artifacts.append(Artifact(name, value)) 79 | 80 | return self 81 | 82 | def recall(self, name: str) -> dict[str, t.Any]: 83 | for existing in self.artifacts: 84 | if existing.name == name: 85 | return existing.value 86 | raise KeyError(name) 87 | 88 | def tag(self, content: str, value: float | None = None) -> "Scope": 89 | # Should we force uniqueness? 90 | # for mname, _ in self.tags: 91 | # if mname == name: 92 | # raise KeyError(f"{name} marker already stored.") 93 | self.tags.append(Tag(content, value)) 94 | return self 95 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | -------------------------------------------------------------------------------- /marque/storage.py: -------------------------------------------------------------------------------- 1 | import abc 2 | import fnmatch 3 | import pathlib 4 | import typing as t 5 | 6 | import orjson 7 | import polars as pl 8 | 9 | from marque.scope import Scope 10 | from marque.util import json_deserialize, json_serialize 11 | 12 | 13 | class Storage(abc.ABC): 14 | @abc.abstractmethod 15 | def save(self, scope: Scope) -> None: 16 | ... 17 | 18 | @abc.abstractmethod 19 | def load(self, id_: str) -> Scope: 20 | ... 21 | 22 | @abc.abstractmethod 23 | def get_ids(self) -> list[str]: 24 | ... 25 | 26 | @abc.abstractmethod 27 | def flush(self) -> None: 28 | ... 29 | 30 | @t.overload 31 | def search( 32 | self, pattern: str, only_latest: bool = True, only_ids: t.Literal[False] = False 33 | ) -> t.Generator[Scope, None, None]: 34 | ... 35 | 36 | @t.overload 37 | def search(self, pattern: str, only_latest: bool, only_ids: t.Literal[True]) -> list[str]: 38 | ... 39 | 40 | def search( 41 | self, pattern: str, only_latest: bool = True, only_ids: bool = False 42 | ) -> list[str] | t.Generator[Scope, None, None]: 43 | ids = [id_ for id_ in reversed(self.get_ids()) if fnmatch.fnmatch(id_, pattern)] 44 | if not ids: 45 | return [] 46 | 47 | if only_latest: 48 | _, _, run_n, _ = ids[0].split(".") 49 | ids = [id_ for id_ in ids if id_.split(".")[2] == run_n] 50 | if only_ids: 51 | return ids 52 | return (self.load(id_) for id_ in ids) 53 | 54 | 55 | class MemoryStorage(Storage): 56 | def __init__(self) -> None: 57 | self.scope: dict[str, Scope] = {} 58 | 59 | def save(self, scope: Scope) -> None: 60 | self.scope[scope.id] = scope 61 | 62 | def load(self, id_: str) -> Scope: 63 | return self.scope[id_] 64 | 65 | def get_ids(self) -> list[str]: 66 | return list(self.scope.keys()) 67 | 68 | def flush(self) -> None: 69 | pass 70 | 71 | 72 | class PolarsStorage(Storage): 73 | _schema: dict[str, type[pl.DataType]] = { 74 | "id": pl.String, 75 | # TODO: Using an Enum here would be preferred, but they get converted to categorical columns 76 | # when the file is pulled back from disk - no idea why 77 | "part": pl.String, 78 | "scope_duration": pl.Duration, 79 | "scope_error": pl.String, 80 | "artifact_name": pl.String, 81 | "artifact_value": pl.String, 82 | "tag_content": pl.String, 83 | "tag_value": pl.Float64, 84 | } 85 | 86 | def __init__(self, path: pathlib.Path | str): 87 | path = pathlib.Path(path) 88 | if path.suffix != ".parquet": 89 | raise ValueError(f"{path} should end in .parquet") 90 | 91 | self.path = path 92 | if self.path.exists(): 93 | self.df = pl.read_parquet(self.path) 94 | else: 95 | self.df = pl.DataFrame(schema=self._schema) 96 | 97 | def flush(self) -> None: 98 | # We did a lot of isolated row writing - optimize for reading later 99 | self.df.rechunk() 100 | self.df.write_parquet(self.path) 101 | 102 | def save(self, scope: Scope) -> None: 103 | rows: list[dict[str, t.Any]] = [ 104 | { 105 | "id": scope.id, 106 | "part": "scope", 107 | "scope_duration": scope.duration, 108 | "scope_error": scope.error, 109 | "artifact_name": None, 110 | "artifact_value": None, 111 | "tag_content": None, 112 | "tag_value": None, 113 | } 114 | ] 115 | 116 | for artifact in scope.artifacts: 117 | rows.append( 118 | { 119 | "id": scope.id, 120 | "part": "artifact", 121 | "scope_duration": None, 122 | "scope_error": None, 123 | "artifact_name": artifact.name, 124 | "artifact_value": json_serialize(artifact.value), 125 | "tag_content": None, 126 | "tag_value": None, 127 | } 128 | ) 129 | 130 | for tag in scope.tags: 131 | rows.append( 132 | { 133 | "id": scope.id, 134 | "part": "tag", 135 | "scope_duration": None, 136 | "scope_error": None, 137 | "artifact_name": None, 138 | "artifact_value": None, 139 | "tag_content": tag.content, 140 | "tag_value": tag.value, 141 | } 142 | ) 143 | 144 | row_df = pl.DataFrame(rows, schema=self._schema) 145 | self.df.vstack(row_df, in_place=True) 146 | 147 | def load(self, id_: str) -> Scope: 148 | search = self.df.filter(pl.col("id") == id_) 149 | if search.is_empty(): 150 | raise KeyError(id_) 151 | 152 | scope = Scope(id_) 153 | for ( 154 | _, 155 | part, 156 | scope_duration, 157 | scope_error, 158 | artifact_name, 159 | artifact_value, 160 | tag_content, 161 | tag_value, 162 | ) in search.iter_rows(): 163 | if part == "scope": 164 | scope.duration = scope_duration 165 | scope.error = scope_error 166 | elif part == "artifact": 167 | scope.keep(artifact_name, json_deserialize(artifact_value), overwrite=True) 168 | elif part == "tag": 169 | scope.tag(tag_content, tag_value) 170 | return scope 171 | 172 | def get_ids(self) -> list[str]: 173 | return list(set(self.df["id"].to_list())) 174 | 175 | 176 | class JsonStorage(Storage): 177 | def __init__(self, path: pathlib.Path | str): 178 | self.path = pathlib.Path(path) 179 | self.path.mkdir(parents=True, exist_ok=True) 180 | 181 | def save(self, scope: Scope) -> None: 182 | file_path = self.path / f"{scope.id}.json" 183 | with file_path.open("wb") as f: 184 | f.write(orjson.dumps(scope.to_json())) 185 | 186 | def load(self, id_: str) -> Scope: 187 | file_path = self.path / f"{id_}.json" 188 | if not file_path.exists(): 189 | raise KeyError(id_) 190 | 191 | with file_path.open("rb") as f: 192 | data = t.cast(dict[str, t.Any], orjson.loads(f.read())) 193 | 194 | return Scope.from_json(data) 195 | 196 | def get_ids(self) -> list[str]: 197 | return [file.stem for file in self.path.glob("*.json")] 198 | 199 | def flush(self) -> None: 200 | pass 201 | -------------------------------------------------------------------------------- /marque/flow.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import traceback 3 | import typing as t 4 | from contextlib import ExitStack 5 | from dataclasses import dataclass 6 | from datetime import datetime 7 | 8 | import coolname # type: ignore [import-untyped] 9 | from loguru import logger 10 | 11 | from marque.logging import LogLevelLiteral, configure_logging 12 | from marque.scope import Scope, Tag 13 | from marque.storage import MemoryStorage, Storage 14 | from marque.util import PrintHook, format_timedelta 15 | 16 | T = t.TypeVar("T") 17 | 18 | StepFunc = t.Callable[["Flow"], None] 19 | 20 | 21 | class Context: 22 | def __init__(self, parent: t.Optional["Context"] = None) -> None: 23 | self.objects: list[tuple[type, t.Any, str | None]] = [] 24 | self.parent = parent 25 | 26 | def put(self, **values: t.Any) -> "Context": 27 | cache = self 28 | for key, value in values.items(): 29 | cache = cache._put(type(value), value, key) 30 | return cache 31 | 32 | def _put(self, type_: type[T], obj: T, id_: str | None = None) -> "Context": 33 | if not isinstance(obj, type_): 34 | raise TypeError(f"{obj} is not a {type_.__name__}.") 35 | 36 | for otype, _, oname in self.objects: 37 | if otype == type_ and (id_ is None or oname == id_): 38 | new_cache = Context(self) 39 | new_cache._put(type_, obj, id_) 40 | return new_cache 41 | 42 | self.objects.append((type_, obj, id_)) 43 | return self 44 | 45 | @t.overload 46 | def get(self, type_: type[T], id_: str | None = None, strict: t.Literal[True] = True) -> T: 47 | ... 48 | 49 | @t.overload 50 | def get(self, type_: type[T], id_: str | None = None, strict: t.Literal[False] = ...) -> T | None: 51 | ... 52 | 53 | @t.overload 54 | def get(self, type_: type[T], id_: list[str], strict: t.Literal[True] = True) -> tuple[T, ...]: 55 | ... 56 | 57 | @t.overload 58 | def get(self, type_: type[T], id_: list[str], strict: t.Literal[False] = ...) -> tuple[T | None, ...]: 59 | ... 60 | 61 | def get( 62 | self, type_: type[T], id_: str | list[str] | None = None, strict: bool = True 63 | ) -> T | None | tuple[T | None, ...]: 64 | if isinstance(id_, list): 65 | return tuple(self._get(type_, single_id, strict) for single_id in id_) 66 | else: 67 | return self._get(type_, id_, strict) 68 | 69 | def _get(self, type_: type[T], id_: str | None = None, strict: bool = True) -> T | None: 70 | matching = [(oid, oval) for otype, oval, oid in self.objects if issubclass(otype, type_)] 71 | if len(matching) == 0: 72 | if self.parent is not None: 73 | return self.parent._get(type_, id_) 74 | elif strict: 75 | raise KeyError(f"{type_.__name__} with id '{id_}'" or type.__name__) 76 | else: 77 | return None 78 | 79 | if id_ is None: 80 | if len(matching) == 1: 81 | return matching[0][1] # type: ignore 82 | else: 83 | raise ValueError( 84 | f"Multiple {type_.__name__} objects exist. Use a specific id to get one of the values." 85 | ) 86 | 87 | for tid, tval in matching: 88 | if tid == id_: 89 | return tval # type: ignore 90 | if self.parent is not None: 91 | return self.parent._get(type_, id_) 92 | elif strict: 93 | raise KeyError(f"{type.__name__} with id '{id_}'") 94 | else: 95 | return None 96 | 97 | 98 | @dataclass 99 | class Step: 100 | func: StepFunc 101 | context: Context 102 | scope: Scope 103 | logs: list[tuple[LogLevelLiteral, str]] 104 | ref_scope: Scope | None = None 105 | 106 | @property 107 | def name(self) -> str: 108 | return self.func.__name__ 109 | 110 | def __init__(self, func: StepFunc, context: Context, get_scope_id: t.Callable[["Step"], str]): 111 | self.func = func 112 | self.context = context 113 | self.logs = [] 114 | self.scope = Scope(get_scope_id(self)) 115 | 116 | def __repr__(self) -> str: 117 | return f"" 118 | 119 | 120 | class Flow: 121 | def __init__(self, name: str, storage: Storage | None = None, log_level: LogLevelLiteral = "info"): 122 | self.name = name 123 | self.run = coolname.generate_slug(2) 124 | self.state: t.Literal["pending", "running", "finished"] = "pending" 125 | self.storage = storage or MemoryStorage() 126 | self.context: Context = Context() 127 | self.tags: list[Tag] = [] 128 | self.steps: list[list[Step]] = [] 129 | self.step_idx = 0 130 | self.group_idx = 0 131 | self.current: Step | None = None 132 | self.ignore_errors: bool = True 133 | self.log_level = log_level 134 | 135 | def _validate_step_func(self, step: StepFunc) -> None: 136 | signature = inspect.signature(step) 137 | if len(signature.parameters) != 1 or list(signature.parameters.values())[0].annotation != Flow: 138 | raise ValueError(f"Step functions must take exactly one argument (a Flow object) ({step.__name__}).") 139 | if signature.return_annotation not in [None, inspect.Signature.empty]: 140 | raise ValueError(f"Step functions must not return any values ({step.__name__}).") 141 | 142 | @property 143 | def errors(self) -> list[tuple[str, str]]: 144 | if self.state != "finished": 145 | raise RuntimeError(f"Flow is not finished yet (state={self.state}).") 146 | return [(step.scope.id, step.scope.error) for group in self.steps for step in group if step.scope.error] 147 | 148 | @property 149 | def scopes(self) -> list[Scope]: 150 | return [step.scope for group in self.steps for step in group] 151 | 152 | @property 153 | def logs(self) -> list[str]: 154 | return [log[1] for log in self.raw_logs] 155 | 156 | @property 157 | def raw_logs(self) -> list[tuple[LogLevelLiteral, str]]: 158 | return [log for group in self.steps for step in group for log in step.logs] 159 | 160 | def put(self, **values: t.Any) -> "Flow": 161 | context = self.current.context if self.current is not None else self.context 162 | context.put(**values) 163 | return self 164 | 165 | @t.overload 166 | def get(self, type_: type[T], id_: str | None = None, strict: t.Literal[True] = True) -> T: 167 | ... 168 | 169 | @t.overload 170 | def get(self, type_: type[T], id_: str | None = None, strict: t.Literal[False] = ...) -> T | None: 171 | ... 172 | 173 | @t.overload 174 | def get(self, type_: type[T], id_: list[str], strict: t.Literal[True] = True) -> tuple[T, ...]: 175 | ... 176 | 177 | @t.overload 178 | def get(self, type_: type[T], id_: list[str], strict: t.Literal[False] = ...) -> tuple[T | None, ...]: 179 | ... 180 | 181 | def get( 182 | self, type_: type[T], id_: str | list[str] | None = None, strict: bool = True 183 | ) -> T | None | tuple[T | None, ...]: 184 | context = self.current.context if self.current is not None else self.context 185 | return context.get(type_, id_, strict) # type: ignore 186 | 187 | def keep(self, name: str, artifact: dict[str, t.Any], overwrite: bool = False) -> "Flow": 188 | if self.current is None: 189 | raise RuntimeError("Cannot keep() outside of a running step.") 190 | self.current.scope.keep(name, artifact, overwrite) 191 | return self 192 | 193 | def recall(self, name: str) -> dict[str, t.Any]: 194 | if self.current is None: 195 | raise RuntimeError("Cannot recall() outside of a running step.") 196 | scope = self.current.ref_scope or self.current.scope 197 | return scope.recall(name) 198 | 199 | def log(self, msg: str, level: LogLevelLiteral = "info") -> "Flow": 200 | if self.current is None: 201 | raise RuntimeError("Cannot log() outside of a running step.") 202 | logger.log(level.upper(), msg) 203 | self.current.logs.append((level, msg)) 204 | return self 205 | 206 | def success(self, message: str) -> None: 207 | self.log(message, level="success") 208 | 209 | def warning(self, message: str) -> None: 210 | self.log(message, level="warning") 211 | 212 | def error(self, message: str) -> None: 213 | self.log(message, level="error") 214 | 215 | def tag(self, content: str, value: float | None = None) -> "Flow": 216 | if self.current is None: 217 | self.tags.append(Tag(content, value)) 218 | else: 219 | self.current.scope.tag(content, value) 220 | return self 221 | 222 | def push_with_scope(self, step: StepFunc | list[StepFunc], scope: Scope | None = None, **context: t.Any) -> "Flow": 223 | step_objects: list[Step] = [] 224 | for step_func in step if isinstance(step, list) else [step]: 225 | self._validate_step_func(step_func) 226 | step_obj = Step( 227 | step_func, 228 | Context(self.context).put(**context) if context else self.context, 229 | lambda step: f"{self.name}.{step.name}.{self.run}.{coolname.generate_slug(2)}", 230 | ) 231 | step_obj.ref_scope = scope 232 | step_objects.append(step_obj) 233 | 234 | if self.current is not None: 235 | self.steps[self.group_idx] += step_objects 236 | for step_obj in step_objects: 237 | logger.info(f" |+ New '{step_obj.name}' step added") 238 | else: 239 | self.steps.append(step_objects) 240 | 241 | return self 242 | 243 | def push(self, step: StepFunc | list[StepFunc], **context: t.Any) -> "Flow": 244 | return self.push_with_scope(step, scope=None, **context) 245 | 246 | def search( 247 | self, pattern_or_step: str | StepFunc, where: t.Callable[[Tag], bool] | None = None 248 | ) -> t.Generator[Scope, None, None]: 249 | pattern = pattern_or_step if isinstance(pattern_or_step, str) else f"{self.name}.{pattern_or_step.__name__}.*" 250 | for scope in self.storage.search(pattern): 251 | if where is None or any(where(tag) for tag in scope.tags): 252 | yield scope 253 | 254 | def fail_fast(self) -> "Flow": 255 | self.ignore_errors = False 256 | return self 257 | 258 | def __call__(self) -> Scope | None: 259 | if self.state != "pending": 260 | raise RuntimeError(f"Flow is already in '{self.state}' state.") 261 | 262 | if len(self.steps) == 0: 263 | raise RuntimeError("No steps were added to the flow.") 264 | 265 | configure_logging(self.log_level) 266 | 267 | logger.success("") 268 | logger.success(f"Starting flow '{self.name}' / '{self.run}'") 269 | logger.success("") 270 | 271 | self.state = "running" 272 | 273 | def _log(message: str) -> None: 274 | self.log(message, level="info") 275 | 276 | while self.group_idx < len(self.steps): 277 | self.step_idx = 0 278 | while self.step_idx < len(self.steps[self.group_idx]): 279 | self.current = self.steps[self.group_idx][self.step_idx] 280 | logger.info(f"> Step '{self.current.name}' ({self.group_idx}:{self.step_idx})") 281 | 282 | start = datetime.now() 283 | 284 | try: 285 | with ExitStack() as stack: 286 | stack.enter_context(PrintHook(_log)) 287 | self.current.func(self) 288 | except Exception: 289 | if self.ignore_errors: 290 | self.current.scope.error = traceback.format_exc() 291 | logger.error(f" |: {self.current.scope.error}") 292 | else: 293 | raise 294 | 295 | self.current.scope.duration = datetime.now() - start 296 | logger.info(f" |- in {format_timedelta(self.current.scope.duration)}") 297 | logger.info("") 298 | self.storage.save(self.current.scope) 299 | 300 | self.step_idx += 1 301 | self.group_idx += 1 302 | 303 | if self.current is None: 304 | raise RuntimeError("No steps were executed in the flow.") 305 | 306 | self.storage.flush() 307 | self.state = "finished" 308 | 309 | logger.success("") 310 | logger.success(f"Finished flow '{self.name}' / '{self.run}'") 311 | logger.success("") 312 | 313 | return self.current.scope 314 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "annotated-types" 5 | version = "0.6.0" 6 | description = "Reusable constraint types to use with typing.Annotated" 7 | optional = false 8 | python-versions = ">=3.8" 9 | files = [ 10 | {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, 11 | {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, 12 | ] 13 | 14 | [[package]] 15 | name = "appnope" 16 | version = "0.1.3" 17 | description = "Disable App Nap on macOS >= 10.9" 18 | optional = false 19 | python-versions = "*" 20 | files = [ 21 | {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, 22 | {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, 23 | ] 24 | 25 | [[package]] 26 | name = "asttokens" 27 | version = "2.4.1" 28 | description = "Annotate AST trees with source code positions" 29 | optional = false 30 | python-versions = "*" 31 | files = [ 32 | {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, 33 | {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, 34 | ] 35 | 36 | [package.dependencies] 37 | six = ">=1.12.0" 38 | 39 | [package.extras] 40 | astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] 41 | test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] 42 | 43 | [[package]] 44 | name = "cffi" 45 | version = "1.16.0" 46 | description = "Foreign Function Interface for Python calling C code." 47 | optional = false 48 | python-versions = ">=3.8" 49 | files = [ 50 | {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, 51 | {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, 52 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, 53 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, 54 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, 55 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, 56 | {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, 57 | {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, 58 | {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, 59 | {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, 60 | {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, 61 | {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, 62 | {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, 63 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, 64 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, 65 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, 66 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, 67 | {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, 68 | {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, 69 | {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, 70 | {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, 71 | {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, 72 | {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, 73 | {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, 74 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, 75 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, 76 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, 77 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, 78 | {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, 79 | {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, 80 | {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, 81 | {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, 82 | {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, 83 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, 84 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, 85 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, 86 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, 87 | {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, 88 | {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, 89 | {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, 90 | {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, 91 | {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, 92 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, 93 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, 94 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, 95 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, 96 | {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, 97 | {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, 98 | {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, 99 | {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, 100 | {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, 101 | {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, 102 | ] 103 | 104 | [package.dependencies] 105 | pycparser = "*" 106 | 107 | [[package]] 108 | name = "colorama" 109 | version = "0.4.6" 110 | description = "Cross-platform colored terminal text." 111 | optional = false 112 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 113 | files = [ 114 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 115 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 116 | ] 117 | 118 | [[package]] 119 | name = "comm" 120 | version = "0.2.1" 121 | description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." 122 | optional = false 123 | python-versions = ">=3.8" 124 | files = [ 125 | {file = "comm-0.2.1-py3-none-any.whl", hash = "sha256:87928485c0dfc0e7976fd89fc1e187023cf587e7c353e4a9b417555b44adf021"}, 126 | {file = "comm-0.2.1.tar.gz", hash = "sha256:0bc91edae1344d39d3661dcbc36937181fdaddb304790458f8b044dbc064b89a"}, 127 | ] 128 | 129 | [package.dependencies] 130 | traitlets = ">=4" 131 | 132 | [package.extras] 133 | test = ["pytest"] 134 | 135 | [[package]] 136 | name = "coolname" 137 | version = "2.2.0" 138 | description = "Random name and slug generator" 139 | optional = false 140 | python-versions = "*" 141 | files = [ 142 | {file = "coolname-2.2.0-py2.py3-none-any.whl", hash = "sha256:4d1563186cfaf71b394d5df4c744f8c41303b6846413645e31d31915cdeb13e8"}, 143 | {file = "coolname-2.2.0.tar.gz", hash = "sha256:6c5d5731759104479e7ca195a9b64f7900ac5bead40183c09323c7d0be9e75c7"}, 144 | ] 145 | 146 | [[package]] 147 | name = "debugpy" 148 | version = "1.8.0" 149 | description = "An implementation of the Debug Adapter Protocol for Python" 150 | optional = false 151 | python-versions = ">=3.8" 152 | files = [ 153 | {file = "debugpy-1.8.0-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:7fb95ca78f7ac43393cd0e0f2b6deda438ec7c5e47fa5d38553340897d2fbdfb"}, 154 | {file = "debugpy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef9ab7df0b9a42ed9c878afd3eaaff471fce3fa73df96022e1f5c9f8f8c87ada"}, 155 | {file = "debugpy-1.8.0-cp310-cp310-win32.whl", hash = "sha256:a8b7a2fd27cd9f3553ac112f356ad4ca93338feadd8910277aff71ab24d8775f"}, 156 | {file = "debugpy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:5d9de202f5d42e62f932507ee8b21e30d49aae7e46d5b1dd5c908db1d7068637"}, 157 | {file = "debugpy-1.8.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:ef54404365fae8d45cf450d0544ee40cefbcb9cb85ea7afe89a963c27028261e"}, 158 | {file = "debugpy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60009b132c91951354f54363f8ebdf7457aeb150e84abba5ae251b8e9f29a8a6"}, 159 | {file = "debugpy-1.8.0-cp311-cp311-win32.whl", hash = "sha256:8cd0197141eb9e8a4566794550cfdcdb8b3db0818bdf8c49a8e8f8053e56e38b"}, 160 | {file = "debugpy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:a64093656c4c64dc6a438e11d59369875d200bd5abb8f9b26c1f5f723622e153"}, 161 | {file = "debugpy-1.8.0-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:b05a6b503ed520ad58c8dc682749113d2fd9f41ffd45daec16e558ca884008cd"}, 162 | {file = "debugpy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c6fb41c98ec51dd010d7ed650accfd07a87fe5e93eca9d5f584d0578f28f35f"}, 163 | {file = "debugpy-1.8.0-cp38-cp38-win32.whl", hash = "sha256:46ab6780159eeabb43c1495d9c84cf85d62975e48b6ec21ee10c95767c0590aa"}, 164 | {file = "debugpy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:bdc5ef99d14b9c0fcb35351b4fbfc06ac0ee576aeab6b2511702e5a648a2e595"}, 165 | {file = "debugpy-1.8.0-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:61eab4a4c8b6125d41a34bad4e5fe3d2cc145caecd63c3fe953be4cc53e65bf8"}, 166 | {file = "debugpy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:125b9a637e013f9faac0a3d6a82bd17c8b5d2c875fb6b7e2772c5aba6d082332"}, 167 | {file = "debugpy-1.8.0-cp39-cp39-win32.whl", hash = "sha256:57161629133113c97b387382045649a2b985a348f0c9366e22217c87b68b73c6"}, 168 | {file = "debugpy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:e3412f9faa9ade82aa64a50b602544efcba848c91384e9f93497a458767e6926"}, 169 | {file = "debugpy-1.8.0-py2.py3-none-any.whl", hash = "sha256:9c9b0ac1ce2a42888199df1a1906e45e6f3c9555497643a85e0bf2406e3ffbc4"}, 170 | {file = "debugpy-1.8.0.zip", hash = "sha256:12af2c55b419521e33d5fb21bd022df0b5eb267c3e178f1d374a63a2a6bdccd0"}, 171 | ] 172 | 173 | [[package]] 174 | name = "decorator" 175 | version = "5.1.1" 176 | description = "Decorators for Humans" 177 | optional = false 178 | python-versions = ">=3.5" 179 | files = [ 180 | {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, 181 | {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, 182 | ] 183 | 184 | [[package]] 185 | name = "exceptiongroup" 186 | version = "1.2.0" 187 | description = "Backport of PEP 654 (exception groups)" 188 | optional = false 189 | python-versions = ">=3.7" 190 | files = [ 191 | {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, 192 | {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, 193 | ] 194 | 195 | [package.extras] 196 | test = ["pytest (>=6)"] 197 | 198 | [[package]] 199 | name = "executing" 200 | version = "2.0.1" 201 | description = "Get the currently executing AST node of a frame, and other information" 202 | optional = false 203 | python-versions = ">=3.5" 204 | files = [ 205 | {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, 206 | {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, 207 | ] 208 | 209 | [package.extras] 210 | tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] 211 | 212 | [[package]] 213 | name = "ipykernel" 214 | version = "6.29.0" 215 | description = "IPython Kernel for Jupyter" 216 | optional = false 217 | python-versions = ">=3.8" 218 | files = [ 219 | {file = "ipykernel-6.29.0-py3-none-any.whl", hash = "sha256:076663ca68492576f051e4af7720d33f34383e655f2be0d544c8b1c9de915b2f"}, 220 | {file = "ipykernel-6.29.0.tar.gz", hash = "sha256:b5dd3013cab7b330df712891c96cd1ab868c27a7159e606f762015e9bf8ceb3f"}, 221 | ] 222 | 223 | [package.dependencies] 224 | appnope = {version = "*", markers = "platform_system == \"Darwin\""} 225 | comm = ">=0.1.1" 226 | debugpy = ">=1.6.5" 227 | ipython = ">=7.23.1" 228 | jupyter-client = ">=6.1.12" 229 | jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" 230 | matplotlib-inline = ">=0.1" 231 | nest-asyncio = "*" 232 | packaging = "*" 233 | psutil = "*" 234 | pyzmq = ">=24" 235 | tornado = ">=6.1" 236 | traitlets = ">=5.4.0" 237 | 238 | [package.extras] 239 | cov = ["coverage[toml]", "curio", "matplotlib", "pytest-cov", "trio"] 240 | docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] 241 | pyqt5 = ["pyqt5"] 242 | pyside6 = ["pyside6"] 243 | test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (==0.23.2)", "pytest-cov", "pytest-timeout"] 244 | 245 | [[package]] 246 | name = "ipython" 247 | version = "8.20.0" 248 | description = "IPython: Productive Interactive Computing" 249 | optional = false 250 | python-versions = ">=3.10" 251 | files = [ 252 | {file = "ipython-8.20.0-py3-none-any.whl", hash = "sha256:bc9716aad6f29f36c449e30821c9dd0c1c1a7b59ddcc26931685b87b4c569619"}, 253 | {file = "ipython-8.20.0.tar.gz", hash = "sha256:2f21bd3fc1d51550c89ee3944ae04bbc7bc79e129ea0937da6e6c68bfdbf117a"}, 254 | ] 255 | 256 | [package.dependencies] 257 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 258 | decorator = "*" 259 | exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} 260 | jedi = ">=0.16" 261 | matplotlib-inline = "*" 262 | pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} 263 | prompt-toolkit = ">=3.0.41,<3.1.0" 264 | pygments = ">=2.4.0" 265 | stack-data = "*" 266 | traitlets = ">=5" 267 | 268 | [package.extras] 269 | all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.23)", "pandas", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] 270 | black = ["black"] 271 | doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] 272 | kernel = ["ipykernel"] 273 | nbconvert = ["nbconvert"] 274 | nbformat = ["nbformat"] 275 | notebook = ["ipywidgets", "notebook"] 276 | parallel = ["ipyparallel"] 277 | qtconsole = ["qtconsole"] 278 | test = ["pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] 279 | test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath", "trio"] 280 | 281 | [[package]] 282 | name = "jedi" 283 | version = "0.19.1" 284 | description = "An autocompletion tool for Python that can be used for text editors." 285 | optional = false 286 | python-versions = ">=3.6" 287 | files = [ 288 | {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, 289 | {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, 290 | ] 291 | 292 | [package.dependencies] 293 | parso = ">=0.8.3,<0.9.0" 294 | 295 | [package.extras] 296 | docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] 297 | qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] 298 | testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] 299 | 300 | [[package]] 301 | name = "jupyter-client" 302 | version = "8.6.0" 303 | description = "Jupyter protocol implementation and client libraries" 304 | optional = false 305 | python-versions = ">=3.8" 306 | files = [ 307 | {file = "jupyter_client-8.6.0-py3-none-any.whl", hash = "sha256:909c474dbe62582ae62b758bca86d6518c85234bdee2d908c778db6d72f39d99"}, 308 | {file = "jupyter_client-8.6.0.tar.gz", hash = "sha256:0642244bb83b4764ae60d07e010e15f0e2d275ec4e918a8f7b80fbbef3ca60c7"}, 309 | ] 310 | 311 | [package.dependencies] 312 | jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" 313 | python-dateutil = ">=2.8.2" 314 | pyzmq = ">=23.0" 315 | tornado = ">=6.2" 316 | traitlets = ">=5.3" 317 | 318 | [package.extras] 319 | docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] 320 | test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] 321 | 322 | [[package]] 323 | name = "jupyter-core" 324 | version = "5.7.1" 325 | description = "Jupyter core package. A base package on which Jupyter projects rely." 326 | optional = false 327 | python-versions = ">=3.8" 328 | files = [ 329 | {file = "jupyter_core-5.7.1-py3-none-any.whl", hash = "sha256:c65c82126453a723a2804aa52409930434598fd9d35091d63dfb919d2b765bb7"}, 330 | {file = "jupyter_core-5.7.1.tar.gz", hash = "sha256:de61a9d7fc71240f688b2fb5ab659fbb56979458dc66a71decd098e03c79e218"}, 331 | ] 332 | 333 | [package.dependencies] 334 | platformdirs = ">=2.5" 335 | pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} 336 | traitlets = ">=5.3" 337 | 338 | [package.extras] 339 | docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] 340 | test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] 341 | 342 | [[package]] 343 | name = "loguru" 344 | version = "0.7.2" 345 | description = "Python logging made (stupidly) simple" 346 | optional = false 347 | python-versions = ">=3.5" 348 | files = [ 349 | {file = "loguru-0.7.2-py3-none-any.whl", hash = "sha256:003d71e3d3ed35f0f8984898359d65b79e5b21943f78af86aa5491210429b8eb"}, 350 | {file = "loguru-0.7.2.tar.gz", hash = "sha256:e671a53522515f34fd406340ee968cb9ecafbc4b36c679da03c18fd8d0bd51ac"}, 351 | ] 352 | 353 | [package.dependencies] 354 | colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} 355 | win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} 356 | 357 | [package.extras] 358 | dev = ["Sphinx (==7.2.5)", "colorama (==0.4.5)", "colorama (==0.4.6)", "exceptiongroup (==1.1.3)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v1.4.1)", "mypy (==v1.5.1)", "pre-commit (==3.4.0)", "pytest (==6.1.2)", "pytest (==7.4.0)", "pytest-cov (==2.12.1)", "pytest-cov (==4.1.0)", "pytest-mypy-plugins (==1.9.3)", "pytest-mypy-plugins (==3.0.0)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.3.0)", "tox (==3.27.1)", "tox (==4.11.0)"] 359 | 360 | [[package]] 361 | name = "matplotlib-inline" 362 | version = "0.1.6" 363 | description = "Inline Matplotlib backend for Jupyter" 364 | optional = false 365 | python-versions = ">=3.5" 366 | files = [ 367 | {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, 368 | {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, 369 | ] 370 | 371 | [package.dependencies] 372 | traitlets = "*" 373 | 374 | [[package]] 375 | name = "mypy" 376 | version = "1.9.0" 377 | description = "Optional static typing for Python" 378 | optional = false 379 | python-versions = ">=3.8" 380 | files = [ 381 | {file = "mypy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8a67616990062232ee4c3952f41c779afac41405806042a8126fe96e098419f"}, 382 | {file = "mypy-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d357423fa57a489e8c47b7c85dfb96698caba13d66e086b412298a1a0ea3b0ed"}, 383 | {file = "mypy-1.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49c87c15aed320de9b438ae7b00c1ac91cd393c1b854c2ce538e2a72d55df150"}, 384 | {file = "mypy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:48533cdd345c3c2e5ef48ba3b0d3880b257b423e7995dada04248725c6f77374"}, 385 | {file = "mypy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:4d3dbd346cfec7cb98e6cbb6e0f3c23618af826316188d587d1c1bc34f0ede03"}, 386 | {file = "mypy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:653265f9a2784db65bfca694d1edd23093ce49740b2244cde583aeb134c008f3"}, 387 | {file = "mypy-1.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a3c007ff3ee90f69cf0a15cbcdf0995749569b86b6d2f327af01fd1b8aee9dc"}, 388 | {file = "mypy-1.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2418488264eb41f69cc64a69a745fad4a8f86649af4b1041a4c64ee61fc61129"}, 389 | {file = "mypy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:68edad3dc7d70f2f17ae4c6c1b9471a56138ca22722487eebacfd1eb5321d612"}, 390 | {file = "mypy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:85ca5fcc24f0b4aeedc1d02f93707bccc04733f21d41c88334c5482219b1ccb3"}, 391 | {file = "mypy-1.9.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aceb1db093b04db5cd390821464504111b8ec3e351eb85afd1433490163d60cd"}, 392 | {file = "mypy-1.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0235391f1c6f6ce487b23b9dbd1327b4ec33bb93934aa986efe8a9563d9349e6"}, 393 | {file = "mypy-1.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4d5ddc13421ba3e2e082a6c2d74c2ddb3979c39b582dacd53dd5d9431237185"}, 394 | {file = "mypy-1.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:190da1ee69b427d7efa8aa0d5e5ccd67a4fb04038c380237a0d96829cb157913"}, 395 | {file = "mypy-1.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:fe28657de3bfec596bbeef01cb219833ad9d38dd5393fc649f4b366840baefe6"}, 396 | {file = "mypy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e54396d70be04b34f31d2edf3362c1edd023246c82f1730bbf8768c28db5361b"}, 397 | {file = "mypy-1.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5e6061f44f2313b94f920e91b204ec600982961e07a17e0f6cd83371cb23f5c2"}, 398 | {file = "mypy-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a10926e5473c5fc3da8abb04119a1f5811a236dc3a38d92015cb1e6ba4cb9e"}, 399 | {file = "mypy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b685154e22e4e9199fc95f298661deea28aaede5ae16ccc8cbb1045e716b3e04"}, 400 | {file = "mypy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:5d741d3fc7c4da608764073089e5f58ef6352bedc223ff58f2f038c2c4698a89"}, 401 | {file = "mypy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:587ce887f75dd9700252a3abbc9c97bbe165a4a630597845c61279cf32dfbf02"}, 402 | {file = "mypy-1.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f88566144752999351725ac623471661c9d1cd8caa0134ff98cceeea181789f4"}, 403 | {file = "mypy-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61758fabd58ce4b0720ae1e2fea5cfd4431591d6d590b197775329264f86311d"}, 404 | {file = "mypy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e49499be624dead83927e70c756970a0bc8240e9f769389cdf5714b0784ca6bf"}, 405 | {file = "mypy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:571741dc4194b4f82d344b15e8837e8c5fcc462d66d076748142327626a1b6e9"}, 406 | {file = "mypy-1.9.0-py3-none-any.whl", hash = "sha256:a260627a570559181a9ea5de61ac6297aa5af202f06fd7ab093ce74e7181e43e"}, 407 | {file = "mypy-1.9.0.tar.gz", hash = "sha256:3cc5da0127e6a478cddd906068496a97a7618a21ce9b54bde5bf7e539c7af974"}, 408 | ] 409 | 410 | [package.dependencies] 411 | mypy-extensions = ">=1.0.0" 412 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 413 | typing-extensions = ">=4.1.0" 414 | 415 | [package.extras] 416 | dmypy = ["psutil (>=4.0)"] 417 | install-types = ["pip"] 418 | mypyc = ["setuptools (>=50)"] 419 | reports = ["lxml"] 420 | 421 | [[package]] 422 | name = "mypy-extensions" 423 | version = "1.0.0" 424 | description = "Type system extensions for programs checked with the mypy type checker." 425 | optional = false 426 | python-versions = ">=3.5" 427 | files = [ 428 | {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, 429 | {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, 430 | ] 431 | 432 | [[package]] 433 | name = "nest-asyncio" 434 | version = "1.6.0" 435 | description = "Patch asyncio to allow nested event loops" 436 | optional = false 437 | python-versions = ">=3.5" 438 | files = [ 439 | {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, 440 | {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, 441 | ] 442 | 443 | [[package]] 444 | name = "orjson" 445 | version = "3.9.12" 446 | description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" 447 | optional = false 448 | python-versions = ">=3.8" 449 | files = [ 450 | {file = "orjson-3.9.12-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6b4e2bed7d00753c438e83b613923afdd067564ff7ed696bfe3a7b073a236e07"}, 451 | {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd1b8ec63f0bf54a50b498eedeccdca23bd7b658f81c524d18e410c203189365"}, 452 | {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab8add018a53665042a5ae68200f1ad14c7953fa12110d12d41166f111724656"}, 453 | {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12756a108875526b76e505afe6d6ba34960ac6b8c5ec2f35faf73ef161e97e07"}, 454 | {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:890e7519c0c70296253660455f77e3a194554a3c45e42aa193cdebc76a02d82b"}, 455 | {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d664880d7f016efbae97c725b243b33c2cbb4851ddc77f683fd1eec4a7894146"}, 456 | {file = "orjson-3.9.12-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cfdaede0fa5b500314ec7b1249c7e30e871504a57004acd116be6acdda3b8ab3"}, 457 | {file = "orjson-3.9.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6492ff5953011e1ba9ed1bf086835fd574bd0a3cbe252db8e15ed72a30479081"}, 458 | {file = "orjson-3.9.12-cp310-none-win32.whl", hash = "sha256:29bf08e2eadb2c480fdc2e2daae58f2f013dff5d3b506edd1e02963b9ce9f8a9"}, 459 | {file = "orjson-3.9.12-cp310-none-win_amd64.whl", hash = "sha256:0fc156fba60d6b50743337ba09f052d8afc8b64595112996d22f5fce01ab57da"}, 460 | {file = "orjson-3.9.12-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2849f88a0a12b8d94579b67486cbd8f3a49e36a4cb3d3f0ab352c596078c730c"}, 461 | {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3186b18754befa660b31c649a108a915493ea69b4fc33f624ed854ad3563ac65"}, 462 | {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbbf313c9fb9d4f6cf9c22ced4b6682230457741daeb3d7060c5d06c2e73884a"}, 463 | {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99e8cd005b3926c3db9b63d264bd05e1bf4451787cc79a048f27f5190a9a0311"}, 464 | {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59feb148392d9155f3bfed0a2a3209268e000c2c3c834fb8fe1a6af9392efcbf"}, 465 | {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4ae815a172a1f073b05b9e04273e3b23e608a0858c4e76f606d2d75fcabde0c"}, 466 | {file = "orjson-3.9.12-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed398f9a9d5a1bf55b6e362ffc80ac846af2122d14a8243a1e6510a4eabcb71e"}, 467 | {file = "orjson-3.9.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d3cfb76600c5a1e6be91326b8f3b83035a370e727854a96d801c1ea08b708073"}, 468 | {file = "orjson-3.9.12-cp311-none-win32.whl", hash = "sha256:a2b6f5252c92bcab3b742ddb3ac195c0fa74bed4319acd74f5d54d79ef4715dc"}, 469 | {file = "orjson-3.9.12-cp311-none-win_amd64.whl", hash = "sha256:c95488e4aa1d078ff5776b58f66bd29d628fa59adcb2047f4efd3ecb2bd41a71"}, 470 | {file = "orjson-3.9.12-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d6ce2062c4af43b92b0221ed4f445632c6bf4213f8a7da5396a122931377acd9"}, 471 | {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:950951799967558c214cd6cceb7ceceed6f81d2c3c4135ee4a2c9c69f58aa225"}, 472 | {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2dfaf71499d6fd4153f5c86eebb68e3ec1bf95851b030a4b55c7637a37bbdee4"}, 473 | {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:659a8d7279e46c97661839035a1a218b61957316bf0202674e944ac5cfe7ed83"}, 474 | {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af17fa87bccad0b7f6fd8ac8f9cbc9ee656b4552783b10b97a071337616db3e4"}, 475 | {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd52dec9eddf4c8c74392f3fd52fa137b5f2e2bed1d9ae958d879de5f7d7cded"}, 476 | {file = "orjson-3.9.12-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:640e2b5d8e36b970202cfd0799d11a9a4ab46cf9212332cd642101ec952df7c8"}, 477 | {file = "orjson-3.9.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:daa438bd8024e03bcea2c5a92cd719a663a58e223fba967296b6ab9992259dbf"}, 478 | {file = "orjson-3.9.12-cp312-none-win_amd64.whl", hash = "sha256:1bb8f657c39ecdb924d02e809f992c9aafeb1ad70127d53fb573a6a6ab59d549"}, 479 | {file = "orjson-3.9.12-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f4098c7674901402c86ba6045a551a2ee345f9f7ed54eeffc7d86d155c8427e5"}, 480 | {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5586a533998267458fad3a457d6f3cdbddbcce696c916599fa8e2a10a89b24d3"}, 481 | {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54071b7398cd3f90e4bb61df46705ee96cb5e33e53fc0b2f47dbd9b000e238e1"}, 482 | {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:67426651faa671b40443ea6f03065f9c8e22272b62fa23238b3efdacd301df31"}, 483 | {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4a0cd56e8ee56b203abae7d482ac0d233dbfb436bb2e2d5cbcb539fe1200a312"}, 484 | {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a84a0c3d4841a42e2571b1c1ead20a83e2792644c5827a606c50fc8af7ca4bee"}, 485 | {file = "orjson-3.9.12-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:09d60450cda3fa6c8ed17770c3a88473a16460cd0ff2ba74ef0df663b6fd3bb8"}, 486 | {file = "orjson-3.9.12-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bc82a4db9934a78ade211cf2e07161e4f068a461c1796465d10069cb50b32a80"}, 487 | {file = "orjson-3.9.12-cp38-none-win32.whl", hash = "sha256:61563d5d3b0019804d782137a4f32c72dc44c84e7d078b89d2d2a1adbaa47b52"}, 488 | {file = "orjson-3.9.12-cp38-none-win_amd64.whl", hash = "sha256:410f24309fbbaa2fab776e3212a81b96a1ec6037259359a32ea79fbccfcf76aa"}, 489 | {file = "orjson-3.9.12-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e773f251258dd82795fd5daeac081d00b97bacf1548e44e71245543374874bcf"}, 490 | {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b159baecfda51c840a619948c25817d37733a4d9877fea96590ef8606468b362"}, 491 | {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:975e72e81a249174840d5a8df977d067b0183ef1560a32998be340f7e195c730"}, 492 | {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06e42e899dde61eb1851a9fad7f1a21b8e4be063438399b63c07839b57668f6c"}, 493 | {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c157e999e5694475a5515942aebeed6e43f7a1ed52267c1c93dcfde7d78d421"}, 494 | {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dde1bc7c035f2d03aa49dc8642d9c6c9b1a81f2470e02055e76ed8853cfae0c3"}, 495 | {file = "orjson-3.9.12-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b0e9d73cdbdad76a53a48f563447e0e1ce34bcecef4614eb4b146383e6e7d8c9"}, 496 | {file = "orjson-3.9.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:96e44b21fe407b8ed48afbb3721f3c8c8ce17e345fbe232bd4651ace7317782d"}, 497 | {file = "orjson-3.9.12-cp39-none-win32.whl", hash = "sha256:cbd0f3555205bf2a60f8812133f2452d498dbefa14423ba90fe89f32276f7abf"}, 498 | {file = "orjson-3.9.12-cp39-none-win_amd64.whl", hash = "sha256:03ea7ee7e992532c2f4a06edd7ee1553f0644790553a118e003e3c405add41fa"}, 499 | {file = "orjson-3.9.12.tar.gz", hash = "sha256:da908d23a3b3243632b523344403b128722a5f45e278a8343c2bb67538dff0e4"}, 500 | ] 501 | 502 | [[package]] 503 | name = "packaging" 504 | version = "23.2" 505 | description = "Core utilities for Python packages" 506 | optional = false 507 | python-versions = ">=3.7" 508 | files = [ 509 | {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, 510 | {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, 511 | ] 512 | 513 | [[package]] 514 | name = "parso" 515 | version = "0.8.3" 516 | description = "A Python Parser" 517 | optional = false 518 | python-versions = ">=3.6" 519 | files = [ 520 | {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, 521 | {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, 522 | ] 523 | 524 | [package.extras] 525 | qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] 526 | testing = ["docopt", "pytest (<6.0.0)"] 527 | 528 | [[package]] 529 | name = "pexpect" 530 | version = "4.9.0" 531 | description = "Pexpect allows easy control of interactive console applications." 532 | optional = false 533 | python-versions = "*" 534 | files = [ 535 | {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, 536 | {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, 537 | ] 538 | 539 | [package.dependencies] 540 | ptyprocess = ">=0.5" 541 | 542 | [[package]] 543 | name = "platformdirs" 544 | version = "4.1.0" 545 | description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 546 | optional = false 547 | python-versions = ">=3.8" 548 | files = [ 549 | {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, 550 | {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, 551 | ] 552 | 553 | [package.extras] 554 | docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] 555 | test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] 556 | 557 | [[package]] 558 | name = "polars" 559 | version = "0.20.5" 560 | description = "Blazingly fast DataFrame library" 561 | optional = false 562 | python-versions = ">=3.8" 563 | files = [ 564 | {file = "polars-0.20.5-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:19693d0815e7be757b2320a5ed988a209f9a505562ed937084b0c7d59109f6b7"}, 565 | {file = "polars-0.20.5-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:6b8674a18b4915207ae46855e72b188391e341e519a72f24b9591ce5164b837d"}, 566 | {file = "polars-0.20.5-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa5d8139020688b0a8f4cdf765df17fe9fa4c8defac6361412bd4bc80a12433c"}, 567 | {file = "polars-0.20.5-cp38-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:d9d069bb4e0cad8efbd7e6211d68e65698d50e77e72490565e52ff035236c08e"}, 568 | {file = "polars-0.20.5-cp38-abi3-win_amd64.whl", hash = "sha256:4d614503f963cd5a8cea3240e7fd9f56b6e574d00ef80091e8689bb6defaf880"}, 569 | {file = "polars-0.20.5.tar.gz", hash = "sha256:fa4abc22cee024b5872961ddcd8a13a0a76150df345e21ce4308c2b1a36b47aa"}, 570 | ] 571 | 572 | [package.extras] 573 | adbc = ["adbc_driver_sqlite"] 574 | all = ["polars[adbc,cloudpickle,connectorx,deltalake,fsspec,gevent,numpy,pandas,plot,pyarrow,pydantic,pyiceberg,sqlalchemy,timezone,xlsx2csv,xlsxwriter]"] 575 | cloudpickle = ["cloudpickle"] 576 | connectorx = ["connectorx (>=0.3.2)"] 577 | deltalake = ["deltalake (>=0.14.0)"] 578 | fsspec = ["fsspec"] 579 | gevent = ["gevent"] 580 | matplotlib = ["matplotlib"] 581 | numpy = ["numpy (>=1.16.0)"] 582 | openpyxl = ["openpyxl (>=3.0.0)"] 583 | pandas = ["pandas", "pyarrow (>=7.0.0)"] 584 | plot = ["hvplot (>=0.9.1)"] 585 | pyarrow = ["pyarrow (>=7.0.0)"] 586 | pydantic = ["pydantic"] 587 | pyiceberg = ["pyiceberg (>=0.5.0)"] 588 | pyxlsb = ["pyxlsb (>=1.0)"] 589 | sqlalchemy = ["pandas", "sqlalchemy"] 590 | timezone = ["backports.zoneinfo", "tzdata"] 591 | xlsx2csv = ["xlsx2csv (>=0.8.0)"] 592 | xlsxwriter = ["xlsxwriter"] 593 | 594 | [[package]] 595 | name = "prompt-toolkit" 596 | version = "3.0.43" 597 | description = "Library for building powerful interactive command lines in Python" 598 | optional = false 599 | python-versions = ">=3.7.0" 600 | files = [ 601 | {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, 602 | {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, 603 | ] 604 | 605 | [package.dependencies] 606 | wcwidth = "*" 607 | 608 | [[package]] 609 | name = "psutil" 610 | version = "5.9.8" 611 | description = "Cross-platform lib for process and system monitoring in Python." 612 | optional = false 613 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" 614 | files = [ 615 | {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, 616 | {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, 617 | {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, 618 | {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, 619 | {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, 620 | {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, 621 | {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, 622 | {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, 623 | {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, 624 | {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"}, 625 | {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, 626 | {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, 627 | {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, 628 | {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, 629 | {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, 630 | {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, 631 | ] 632 | 633 | [package.extras] 634 | test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] 635 | 636 | [[package]] 637 | name = "ptyprocess" 638 | version = "0.7.0" 639 | description = "Run a subprocess in a pseudo terminal" 640 | optional = false 641 | python-versions = "*" 642 | files = [ 643 | {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, 644 | {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, 645 | ] 646 | 647 | [[package]] 648 | name = "pure-eval" 649 | version = "0.2.2" 650 | description = "Safely evaluate AST nodes without side effects" 651 | optional = false 652 | python-versions = "*" 653 | files = [ 654 | {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, 655 | {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, 656 | ] 657 | 658 | [package.extras] 659 | tests = ["pytest"] 660 | 661 | [[package]] 662 | name = "pycparser" 663 | version = "2.21" 664 | description = "C parser in Python" 665 | optional = false 666 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 667 | files = [ 668 | {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, 669 | {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, 670 | ] 671 | 672 | [[package]] 673 | name = "pydantic" 674 | version = "2.6.4" 675 | description = "Data validation using Python type hints" 676 | optional = false 677 | python-versions = ">=3.8" 678 | files = [ 679 | {file = "pydantic-2.6.4-py3-none-any.whl", hash = "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5"}, 680 | {file = "pydantic-2.6.4.tar.gz", hash = "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6"}, 681 | ] 682 | 683 | [package.dependencies] 684 | annotated-types = ">=0.4.0" 685 | pydantic-core = "2.16.3" 686 | typing-extensions = ">=4.6.1" 687 | 688 | [package.extras] 689 | email = ["email-validator (>=2.0.0)"] 690 | 691 | [[package]] 692 | name = "pydantic-core" 693 | version = "2.16.3" 694 | description = "" 695 | optional = false 696 | python-versions = ">=3.8" 697 | files = [ 698 | {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, 699 | {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, 700 | {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, 701 | {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, 702 | {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, 703 | {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, 704 | {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, 705 | {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, 706 | {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, 707 | {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, 708 | {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, 709 | {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, 710 | {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, 711 | {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, 712 | {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, 713 | {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, 714 | {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, 715 | {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, 716 | {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, 717 | {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, 718 | {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, 719 | {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, 720 | {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, 721 | {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, 722 | {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, 723 | {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, 724 | {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, 725 | {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, 726 | {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, 727 | {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, 728 | {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, 729 | {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, 730 | {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, 731 | {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, 732 | {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, 733 | {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, 734 | {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, 735 | {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, 736 | {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, 737 | {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, 738 | {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, 739 | {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, 740 | {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, 741 | {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, 742 | {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, 743 | {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, 744 | {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, 745 | {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, 746 | {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, 747 | {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, 748 | {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, 749 | {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, 750 | {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, 751 | {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, 752 | {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, 753 | {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, 754 | {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, 755 | {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, 756 | {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, 757 | {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, 758 | {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, 759 | {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, 760 | {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, 761 | {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, 762 | {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, 763 | {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, 764 | {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, 765 | {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, 766 | {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, 767 | {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, 768 | {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, 769 | {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, 770 | {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, 771 | {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, 772 | {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, 773 | {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, 774 | {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, 775 | {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, 776 | {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, 777 | ] 778 | 779 | [package.dependencies] 780 | typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" 781 | 782 | [[package]] 783 | name = "pygments" 784 | version = "2.17.2" 785 | description = "Pygments is a syntax highlighting package written in Python." 786 | optional = false 787 | python-versions = ">=3.7" 788 | files = [ 789 | {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, 790 | {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, 791 | ] 792 | 793 | [package.extras] 794 | plugins = ["importlib-metadata"] 795 | windows-terminal = ["colorama (>=0.4.6)"] 796 | 797 | [[package]] 798 | name = "python-dateutil" 799 | version = "2.8.2" 800 | description = "Extensions to the standard Python datetime module" 801 | optional = false 802 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 803 | files = [ 804 | {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, 805 | {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, 806 | ] 807 | 808 | [package.dependencies] 809 | six = ">=1.5" 810 | 811 | [[package]] 812 | name = "pywin32" 813 | version = "306" 814 | description = "Python for Window Extensions" 815 | optional = false 816 | python-versions = "*" 817 | files = [ 818 | {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, 819 | {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, 820 | {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, 821 | {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, 822 | {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, 823 | {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, 824 | {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, 825 | {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, 826 | {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, 827 | {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, 828 | {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, 829 | {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, 830 | {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, 831 | {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, 832 | ] 833 | 834 | [[package]] 835 | name = "pyzmq" 836 | version = "25.1.2" 837 | description = "Python bindings for 0MQ" 838 | optional = false 839 | python-versions = ">=3.6" 840 | files = [ 841 | {file = "pyzmq-25.1.2-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:e624c789359f1a16f83f35e2c705d07663ff2b4d4479bad35621178d8f0f6ea4"}, 842 | {file = "pyzmq-25.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:49151b0efece79f6a79d41a461d78535356136ee70084a1c22532fc6383f4ad0"}, 843 | {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9a5f194cf730f2b24d6af1f833c14c10f41023da46a7f736f48b6d35061e76e"}, 844 | {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:faf79a302f834d9e8304fafdc11d0d042266667ac45209afa57e5efc998e3872"}, 845 | {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f51a7b4ead28d3fca8dda53216314a553b0f7a91ee8fc46a72b402a78c3e43d"}, 846 | {file = "pyzmq-25.1.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:0ddd6d71d4ef17ba5a87becf7ddf01b371eaba553c603477679ae817a8d84d75"}, 847 | {file = "pyzmq-25.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:246747b88917e4867e2367b005fc8eefbb4a54b7db363d6c92f89d69abfff4b6"}, 848 | {file = "pyzmq-25.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:00c48ae2fd81e2a50c3485de1b9d5c7c57cd85dc8ec55683eac16846e57ac979"}, 849 | {file = "pyzmq-25.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5a68d491fc20762b630e5db2191dd07ff89834086740f70e978bb2ef2668be08"}, 850 | {file = "pyzmq-25.1.2-cp310-cp310-win32.whl", hash = "sha256:09dfe949e83087da88c4a76767df04b22304a682d6154de2c572625c62ad6886"}, 851 | {file = "pyzmq-25.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:fa99973d2ed20417744fca0073390ad65ce225b546febb0580358e36aa90dba6"}, 852 | {file = "pyzmq-25.1.2-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:82544e0e2d0c1811482d37eef297020a040c32e0687c1f6fc23a75b75db8062c"}, 853 | {file = "pyzmq-25.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:01171fc48542348cd1a360a4b6c3e7d8f46cdcf53a8d40f84db6707a6768acc1"}, 854 | {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc69c96735ab501419c432110016329bf0dea8898ce16fab97c6d9106dc0b348"}, 855 | {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e124e6b1dd3dfbeb695435dff0e383256655bb18082e094a8dd1f6293114642"}, 856 | {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7598d2ba821caa37a0f9d54c25164a4fa351ce019d64d0b44b45540950458840"}, 857 | {file = "pyzmq-25.1.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d1299d7e964c13607efd148ca1f07dcbf27c3ab9e125d1d0ae1d580a1682399d"}, 858 | {file = "pyzmq-25.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4e6f689880d5ad87918430957297c975203a082d9a036cc426648fcbedae769b"}, 859 | {file = "pyzmq-25.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cc69949484171cc961e6ecd4a8911b9ce7a0d1f738fcae717177c231bf77437b"}, 860 | {file = "pyzmq-25.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9880078f683466b7f567b8624bfc16cad65077be046b6e8abb53bed4eeb82dd3"}, 861 | {file = "pyzmq-25.1.2-cp311-cp311-win32.whl", hash = "sha256:4e5837af3e5aaa99a091302df5ee001149baff06ad22b722d34e30df5f0d9097"}, 862 | {file = "pyzmq-25.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:25c2dbb97d38b5ac9fd15586e048ec5eb1e38f3d47fe7d92167b0c77bb3584e9"}, 863 | {file = "pyzmq-25.1.2-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:11e70516688190e9c2db14fcf93c04192b02d457b582a1f6190b154691b4c93a"}, 864 | {file = "pyzmq-25.1.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:313c3794d650d1fccaaab2df942af9f2c01d6217c846177cfcbc693c7410839e"}, 865 | {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b3cbba2f47062b85fe0ef9de5b987612140a9ba3a9c6d2543c6dec9f7c2ab27"}, 866 | {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc31baa0c32a2ca660784d5af3b9487e13b61b3032cb01a115fce6588e1bed30"}, 867 | {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02c9087b109070c5ab0b383079fa1b5f797f8d43e9a66c07a4b8b8bdecfd88ee"}, 868 | {file = "pyzmq-25.1.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:f8429b17cbb746c3e043cb986328da023657e79d5ed258b711c06a70c2ea7537"}, 869 | {file = "pyzmq-25.1.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5074adeacede5f810b7ef39607ee59d94e948b4fd954495bdb072f8c54558181"}, 870 | {file = "pyzmq-25.1.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7ae8f354b895cbd85212da245f1a5ad8159e7840e37d78b476bb4f4c3f32a9fe"}, 871 | {file = "pyzmq-25.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b264bf2cc96b5bc43ce0e852be995e400376bd87ceb363822e2cb1964fcdc737"}, 872 | {file = "pyzmq-25.1.2-cp312-cp312-win32.whl", hash = "sha256:02bbc1a87b76e04fd780b45e7f695471ae6de747769e540da909173d50ff8e2d"}, 873 | {file = "pyzmq-25.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:ced111c2e81506abd1dc142e6cd7b68dd53747b3b7ae5edbea4578c5eeff96b7"}, 874 | {file = "pyzmq-25.1.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7b6d09a8962a91151f0976008eb7b29b433a560fde056ec7a3db9ec8f1075438"}, 875 | {file = "pyzmq-25.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:967668420f36878a3c9ecb5ab33c9d0ff8d054f9c0233d995a6d25b0e95e1b6b"}, 876 | {file = "pyzmq-25.1.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5edac3f57c7ddaacdb4d40f6ef2f9e299471fc38d112f4bc6d60ab9365445fb0"}, 877 | {file = "pyzmq-25.1.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0dabfb10ef897f3b7e101cacba1437bd3a5032ee667b7ead32bbcdd1a8422fe7"}, 878 | {file = "pyzmq-25.1.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:2c6441e0398c2baacfe5ba30c937d274cfc2dc5b55e82e3749e333aabffde561"}, 879 | {file = "pyzmq-25.1.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:16b726c1f6c2e7625706549f9dbe9b06004dfbec30dbed4bf50cbdfc73e5b32a"}, 880 | {file = "pyzmq-25.1.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:a86c2dd76ef71a773e70551a07318b8e52379f58dafa7ae1e0a4be78efd1ff16"}, 881 | {file = "pyzmq-25.1.2-cp36-cp36m-win32.whl", hash = "sha256:359f7f74b5d3c65dae137f33eb2bcfa7ad9ebefd1cab85c935f063f1dbb245cc"}, 882 | {file = "pyzmq-25.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:55875492f820d0eb3417b51d96fea549cde77893ae3790fd25491c5754ea2f68"}, 883 | {file = "pyzmq-25.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b8c8a419dfb02e91b453615c69568442e897aaf77561ee0064d789705ff37a92"}, 884 | {file = "pyzmq-25.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8807c87fa893527ae8a524c15fc505d9950d5e856f03dae5921b5e9aa3b8783b"}, 885 | {file = "pyzmq-25.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5e319ed7d6b8f5fad9b76daa0a68497bc6f129858ad956331a5835785761e003"}, 886 | {file = "pyzmq-25.1.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3c53687dde4d9d473c587ae80cc328e5b102b517447456184b485587ebd18b62"}, 887 | {file = "pyzmq-25.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9add2e5b33d2cd765ad96d5eb734a5e795a0755f7fc49aa04f76d7ddda73fd70"}, 888 | {file = "pyzmq-25.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e690145a8c0c273c28d3b89d6fb32c45e0d9605b2293c10e650265bf5c11cfec"}, 889 | {file = "pyzmq-25.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:00a06faa7165634f0cac1abb27e54d7a0b3b44eb9994530b8ec73cf52e15353b"}, 890 | {file = "pyzmq-25.1.2-cp37-cp37m-win32.whl", hash = "sha256:0f97bc2f1f13cb16905a5f3e1fbdf100e712d841482b2237484360f8bc4cb3d7"}, 891 | {file = "pyzmq-25.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6cc0020b74b2e410287e5942e1e10886ff81ac77789eb20bec13f7ae681f0fdd"}, 892 | {file = "pyzmq-25.1.2-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:bef02cfcbded83473bdd86dd8d3729cd82b2e569b75844fb4ea08fee3c26ae41"}, 893 | {file = "pyzmq-25.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e10a4b5a4b1192d74853cc71a5e9fd022594573926c2a3a4802020360aa719d8"}, 894 | {file = "pyzmq-25.1.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8c5f80e578427d4695adac6fdf4370c14a2feafdc8cb35549c219b90652536ae"}, 895 | {file = "pyzmq-25.1.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5dde6751e857910c1339890f3524de74007958557593b9e7e8c5f01cd919f8a7"}, 896 | {file = "pyzmq-25.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea1608dd169da230a0ad602d5b1ebd39807ac96cae1845c3ceed39af08a5c6df"}, 897 | {file = "pyzmq-25.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0f513130c4c361201da9bc69df25a086487250e16b5571ead521b31ff6b02220"}, 898 | {file = "pyzmq-25.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:019744b99da30330798bb37df33549d59d380c78e516e3bab9c9b84f87a9592f"}, 899 | {file = "pyzmq-25.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2e2713ef44be5d52dd8b8e2023d706bf66cb22072e97fc71b168e01d25192755"}, 900 | {file = "pyzmq-25.1.2-cp38-cp38-win32.whl", hash = "sha256:07cd61a20a535524906595e09344505a9bd46f1da7a07e504b315d41cd42eb07"}, 901 | {file = "pyzmq-25.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb7e49a17fb8c77d3119d41a4523e432eb0c6932187c37deb6fbb00cc3028088"}, 902 | {file = "pyzmq-25.1.2-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:94504ff66f278ab4b7e03e4cba7e7e400cb73bfa9d3d71f58d8972a8dc67e7a6"}, 903 | {file = "pyzmq-25.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6dd0d50bbf9dca1d0bdea219ae6b40f713a3fb477c06ca3714f208fd69e16fd8"}, 904 | {file = "pyzmq-25.1.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:004ff469d21e86f0ef0369717351073e0e577428e514c47c8480770d5e24a565"}, 905 | {file = "pyzmq-25.1.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c0b5ca88a8928147b7b1e2dfa09f3b6c256bc1135a1338536cbc9ea13d3b7add"}, 906 | {file = "pyzmq-25.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c9a79f1d2495b167119d02be7448bfba57fad2a4207c4f68abc0bab4b92925b"}, 907 | {file = "pyzmq-25.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:518efd91c3d8ac9f9b4f7dd0e2b7b8bf1a4fe82a308009016b07eaa48681af82"}, 908 | {file = "pyzmq-25.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1ec23bd7b3a893ae676d0e54ad47d18064e6c5ae1fadc2f195143fb27373f7f6"}, 909 | {file = "pyzmq-25.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db36c27baed588a5a8346b971477b718fdc66cf5b80cbfbd914b4d6d355e44e2"}, 910 | {file = "pyzmq-25.1.2-cp39-cp39-win32.whl", hash = "sha256:39b1067f13aba39d794a24761e385e2eddc26295826530a8c7b6c6c341584289"}, 911 | {file = "pyzmq-25.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:8e9f3fabc445d0ce320ea2c59a75fe3ea591fdbdeebec5db6de530dd4b09412e"}, 912 | {file = "pyzmq-25.1.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a8c1d566344aee826b74e472e16edae0a02e2a044f14f7c24e123002dcff1c05"}, 913 | {file = "pyzmq-25.1.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:759cfd391a0996345ba94b6a5110fca9c557ad4166d86a6e81ea526c376a01e8"}, 914 | {file = "pyzmq-25.1.2-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c61e346ac34b74028ede1c6b4bcecf649d69b707b3ff9dc0fab453821b04d1e"}, 915 | {file = "pyzmq-25.1.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cb8fc1f8d69b411b8ec0b5f1ffbcaf14c1db95b6bccea21d83610987435f1a4"}, 916 | {file = "pyzmq-25.1.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3c00c9b7d1ca8165c610437ca0c92e7b5607b2f9076f4eb4b095c85d6e680a1d"}, 917 | {file = "pyzmq-25.1.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:df0c7a16ebb94452d2909b9a7b3337940e9a87a824c4fc1c7c36bb4404cb0cde"}, 918 | {file = "pyzmq-25.1.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:45999e7f7ed5c390f2e87ece7f6c56bf979fb213550229e711e45ecc7d42ccb8"}, 919 | {file = "pyzmq-25.1.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ac170e9e048b40c605358667aca3d94e98f604a18c44bdb4c102e67070f3ac9b"}, 920 | {file = "pyzmq-25.1.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1b604734bec94f05f81b360a272fc824334267426ae9905ff32dc2be433ab96"}, 921 | {file = "pyzmq-25.1.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:a793ac733e3d895d96f865f1806f160696422554e46d30105807fdc9841b9f7d"}, 922 | {file = "pyzmq-25.1.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0806175f2ae5ad4b835ecd87f5f85583316b69f17e97786f7443baaf54b9bb98"}, 923 | {file = "pyzmq-25.1.2-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ef12e259e7bc317c7597d4f6ef59b97b913e162d83b421dd0db3d6410f17a244"}, 924 | {file = "pyzmq-25.1.2-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea253b368eb41116011add00f8d5726762320b1bda892f744c91997b65754d73"}, 925 | {file = "pyzmq-25.1.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b9b1f2ad6498445a941d9a4fee096d387fee436e45cc660e72e768d3d8ee611"}, 926 | {file = "pyzmq-25.1.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:8b14c75979ce932c53b79976a395cb2a8cd3aaf14aef75e8c2cb55a330b9b49d"}, 927 | {file = "pyzmq-25.1.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:889370d5174a741a62566c003ee8ddba4b04c3f09a97b8000092b7ca83ec9c49"}, 928 | {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a18fff090441a40ffda8a7f4f18f03dc56ae73f148f1832e109f9bffa85df15"}, 929 | {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99a6b36f95c98839ad98f8c553d8507644c880cf1e0a57fe5e3a3f3969040882"}, 930 | {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4345c9a27f4310afbb9c01750e9461ff33d6fb74cd2456b107525bbeebcb5be3"}, 931 | {file = "pyzmq-25.1.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3516e0b6224cf6e43e341d56da15fd33bdc37fa0c06af4f029f7d7dfceceabbc"}, 932 | {file = "pyzmq-25.1.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:146b9b1f29ead41255387fb07be56dc29639262c0f7344f570eecdcd8d683314"}, 933 | {file = "pyzmq-25.1.2.tar.gz", hash = "sha256:93f1aa311e8bb912e34f004cf186407a4e90eec4f0ecc0efd26056bf7eda0226"}, 934 | ] 935 | 936 | [package.dependencies] 937 | cffi = {version = "*", markers = "implementation_name == \"pypy\""} 938 | 939 | [[package]] 940 | name = "ruff" 941 | version = "0.1.14" 942 | description = "An extremely fast Python linter and code formatter, written in Rust." 943 | optional = false 944 | python-versions = ">=3.7" 945 | files = [ 946 | {file = "ruff-0.1.14-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:96f76536df9b26622755c12ed8680f159817be2f725c17ed9305b472a757cdbb"}, 947 | {file = "ruff-0.1.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ab3f71f64498c7241123bb5a768544cf42821d2a537f894b22457a543d3ca7a9"}, 948 | {file = "ruff-0.1.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7060156ecc572b8f984fd20fd8b0fcb692dd5d837b7606e968334ab7ff0090ab"}, 949 | {file = "ruff-0.1.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a53d8e35313d7b67eb3db15a66c08434809107659226a90dcd7acb2afa55faea"}, 950 | {file = "ruff-0.1.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bea9be712b8f5b4ebed40e1949379cfb2a7d907f42921cf9ab3aae07e6fba9eb"}, 951 | {file = "ruff-0.1.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2270504d629a0b064247983cbc495bed277f372fb9eaba41e5cf51f7ba705a6a"}, 952 | {file = "ruff-0.1.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80258bb3b8909b1700610dfabef7876423eed1bc930fe177c71c414921898efa"}, 953 | {file = "ruff-0.1.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:653230dd00aaf449eb5ff25d10a6e03bc3006813e2cb99799e568f55482e5cae"}, 954 | {file = "ruff-0.1.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b3acc6c4e6928459ba9eb7459dd4f0c4bf266a053c863d72a44c33246bfdbf"}, 955 | {file = "ruff-0.1.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6b3dadc9522d0eccc060699a9816e8127b27addbb4697fc0c08611e4e6aeb8b5"}, 956 | {file = "ruff-0.1.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1c8eca1a47b4150dc0fbec7fe68fc91c695aed798532a18dbb1424e61e9b721f"}, 957 | {file = "ruff-0.1.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:62ce2ae46303ee896fc6811f63d6dabf8d9c389da0f3e3f2bce8bc7f15ef5488"}, 958 | {file = "ruff-0.1.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b2027dde79d217b211d725fc833e8965dc90a16d0d3213f1298f97465956661b"}, 959 | {file = "ruff-0.1.14-py3-none-win32.whl", hash = "sha256:722bafc299145575a63bbd6b5069cb643eaa62546a5b6398f82b3e4403329cab"}, 960 | {file = "ruff-0.1.14-py3-none-win_amd64.whl", hash = "sha256:e3d241aa61f92b0805a7082bd89a9990826448e4d0398f0e2bc8f05c75c63d99"}, 961 | {file = "ruff-0.1.14-py3-none-win_arm64.whl", hash = "sha256:269302b31ade4cde6cf6f9dd58ea593773a37ed3f7b97e793c8594b262466b67"}, 962 | {file = "ruff-0.1.14.tar.gz", hash = "sha256:ad3f8088b2dfd884820289a06ab718cde7d38b94972212cc4ba90d5fbc9955f3"}, 963 | ] 964 | 965 | [[package]] 966 | name = "six" 967 | version = "1.16.0" 968 | description = "Python 2 and 3 compatibility utilities" 969 | optional = false 970 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 971 | files = [ 972 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 973 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 974 | ] 975 | 976 | [[package]] 977 | name = "stack-data" 978 | version = "0.6.3" 979 | description = "Extract data from python stack frames and tracebacks for informative displays" 980 | optional = false 981 | python-versions = "*" 982 | files = [ 983 | {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, 984 | {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, 985 | ] 986 | 987 | [package.dependencies] 988 | asttokens = ">=2.1.0" 989 | executing = ">=1.2.0" 990 | pure-eval = "*" 991 | 992 | [package.extras] 993 | tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] 994 | 995 | [[package]] 996 | name = "tomli" 997 | version = "2.0.1" 998 | description = "A lil' TOML parser" 999 | optional = false 1000 | python-versions = ">=3.7" 1001 | files = [ 1002 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 1003 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 1004 | ] 1005 | 1006 | [[package]] 1007 | name = "tornado" 1008 | version = "6.4" 1009 | description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." 1010 | optional = false 1011 | python-versions = ">= 3.8" 1012 | files = [ 1013 | {file = "tornado-6.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0"}, 1014 | {file = "tornado-6.4-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263"}, 1015 | {file = "tornado-6.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e"}, 1016 | {file = "tornado-6.4-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579"}, 1017 | {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"}, 1018 | {file = "tornado-6.4-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2"}, 1019 | {file = "tornado-6.4-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78"}, 1020 | {file = "tornado-6.4-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f"}, 1021 | {file = "tornado-6.4-cp38-abi3-win32.whl", hash = "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052"}, 1022 | {file = "tornado-6.4-cp38-abi3-win_amd64.whl", hash = "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63"}, 1023 | {file = "tornado-6.4.tar.gz", hash = "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee"}, 1024 | ] 1025 | 1026 | [[package]] 1027 | name = "traitlets" 1028 | version = "5.14.1" 1029 | description = "Traitlets Python configuration system" 1030 | optional = false 1031 | python-versions = ">=3.8" 1032 | files = [ 1033 | {file = "traitlets-5.14.1-py3-none-any.whl", hash = "sha256:2e5a030e6eff91737c643231bfcf04a65b0132078dad75e4936700b213652e74"}, 1034 | {file = "traitlets-5.14.1.tar.gz", hash = "sha256:8585105b371a04b8316a43d5ce29c098575c2e477850b62b848b964f1444527e"}, 1035 | ] 1036 | 1037 | [package.extras] 1038 | docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] 1039 | test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] 1040 | 1041 | [[package]] 1042 | name = "typing-extensions" 1043 | version = "4.9.0" 1044 | description = "Backported and Experimental Type Hints for Python 3.8+" 1045 | optional = false 1046 | python-versions = ">=3.8" 1047 | files = [ 1048 | {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, 1049 | {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, 1050 | ] 1051 | 1052 | [[package]] 1053 | name = "wcwidth" 1054 | version = "0.2.13" 1055 | description = "Measures the displayed width of unicode strings in a terminal" 1056 | optional = false 1057 | python-versions = "*" 1058 | files = [ 1059 | {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, 1060 | {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, 1061 | ] 1062 | 1063 | [[package]] 1064 | name = "win32-setctime" 1065 | version = "1.1.0" 1066 | description = "A small Python utility to set file creation time on Windows" 1067 | optional = false 1068 | python-versions = ">=3.5" 1069 | files = [ 1070 | {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, 1071 | {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, 1072 | ] 1073 | 1074 | [package.extras] 1075 | dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] 1076 | 1077 | [metadata] 1078 | lock-version = "2.0" 1079 | python-versions = "^3.10" 1080 | content-hash = "962ef71ea77492c90c870272a5c8fecacbc4323c851232ff37487cf47c6764cf" 1081 | --------------------------------------------------------------------------------