fastapi-task-manager 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastapi_task_manager-0.3.0/.gitignore +56 -0
- fastapi_task_manager-0.3.0/.pre-commit-config.yaml +73 -0
- fastapi_task_manager-0.3.0/LICENSE +21 -0
- fastapi_task_manager-0.3.0/PKG-INFO +50 -0
- fastapi_task_manager-0.3.0/README.md +2 -0
- fastapi_task_manager-0.3.0/pre_commit_prune_stale_tags.py +44 -0
- fastapi_task_manager-0.3.0/pyproject.toml +144 -0
- fastapi_task_manager-0.3.0/src/fastapi_task_manager/__init__.py +2 -0
- fastapi_task_manager-0.3.0/src/fastapi_task_manager/config.py +18 -0
- fastapi_task_manager-0.3.0/src/fastapi_task_manager/force_acquire_semaphore.py +20 -0
- fastapi_task_manager-0.3.0/src/fastapi_task_manager/runner.py +151 -0
- fastapi_task_manager-0.3.0/src/fastapi_task_manager/schema/__init__.py +0 -0
- fastapi_task_manager-0.3.0/src/fastapi_task_manager/schema/task.py +22 -0
- fastapi_task_manager-0.3.0/src/fastapi_task_manager/task_manager.py +97 -0
- fastapi_task_manager-0.3.0/uv.lock +291 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# IDE ignores
|
|
7
|
+
.idea
|
|
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
|
+
.vscode/launch.json
|
|
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
|
+
# Environments
|
|
55
|
+
.env
|
|
56
|
+
.venv
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
default_install_hook_types: [ pre-commit, pre-push ]
|
|
2
|
+
default_language_version:
|
|
3
|
+
python: "3.13"
|
|
4
|
+
repos:
|
|
5
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
6
|
+
rev: v5.0.0
|
|
7
|
+
hooks:
|
|
8
|
+
- id: check-added-large-files
|
|
9
|
+
stages:
|
|
10
|
+
- pre-commit
|
|
11
|
+
- id: check-merge-conflict
|
|
12
|
+
stages:
|
|
13
|
+
- pre-commit
|
|
14
|
+
- id: end-of-file-fixer
|
|
15
|
+
stages:
|
|
16
|
+
- pre-commit
|
|
17
|
+
- id: mixed-line-ending
|
|
18
|
+
stages:
|
|
19
|
+
- pre-commit
|
|
20
|
+
|
|
21
|
+
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
|
22
|
+
rev: v1.5.5
|
|
23
|
+
hooks:
|
|
24
|
+
- id: remove-tabs
|
|
25
|
+
stages:
|
|
26
|
+
- pre-commit
|
|
27
|
+
|
|
28
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
29
|
+
rev: v1.15.0
|
|
30
|
+
hooks:
|
|
31
|
+
- id: mypy
|
|
32
|
+
additional_dependencies: [ "types-toml", "types-redis"]
|
|
33
|
+
stages:
|
|
34
|
+
- pre-commit
|
|
35
|
+
|
|
36
|
+
- repo: local
|
|
37
|
+
hooks:
|
|
38
|
+
- id: ruff_format
|
|
39
|
+
name: ruff_format
|
|
40
|
+
entry: ruff format
|
|
41
|
+
language: python
|
|
42
|
+
types: [ python ]
|
|
43
|
+
additional_dependencies: [ "ruff" ]
|
|
44
|
+
stages:
|
|
45
|
+
- pre-commit
|
|
46
|
+
require_serial: true
|
|
47
|
+
- id: ruff_check
|
|
48
|
+
name: ruff_check
|
|
49
|
+
entry: ruff check
|
|
50
|
+
args: [ "--fix", "--unsafe-fixes" ]
|
|
51
|
+
language: python
|
|
52
|
+
types: [ python ]
|
|
53
|
+
additional_dependencies: [ "ruff" ]
|
|
54
|
+
stages:
|
|
55
|
+
- pre-commit
|
|
56
|
+
require_serial: true
|
|
57
|
+
- id: vermin
|
|
58
|
+
name: vermin
|
|
59
|
+
entry: vermin --no-tips -t="3.13-" --violations
|
|
60
|
+
language: python
|
|
61
|
+
types: [ python ]
|
|
62
|
+
additional_dependencies: [ "vermin" ]
|
|
63
|
+
stages:
|
|
64
|
+
- pre-commit
|
|
65
|
+
- id: prune_stale_tags
|
|
66
|
+
name: prune_stale_tags
|
|
67
|
+
entry: python pre_commit_prune_stale_tags.py
|
|
68
|
+
language: python
|
|
69
|
+
pass_filenames: false
|
|
70
|
+
always_run: true
|
|
71
|
+
types: [ python ]
|
|
72
|
+
stages:
|
|
73
|
+
- pre-commit
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Morando Matteo
|
|
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.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fastapi-task-manager
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: A task manager for Fastapi. Robust Scheduling, Distributed Safety
|
|
5
|
+
Project-URL: Homepage, https://github.com/Morry98/fastapi-task-manager
|
|
6
|
+
Project-URL: Bug Tracker, https://github.com/Morry98/fastapi-task-manager/repo/issues
|
|
7
|
+
Author-email: Matteo Morando <matteo.morando98@gmail.com>
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2025 Morando Matteo
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Keywords: distributed,fastapi,robust,safety,task-manager,task-scheduler
|
|
31
|
+
Classifier: Development Status :: 3 - Alpha
|
|
32
|
+
Classifier: Framework :: FastAPI
|
|
33
|
+
Classifier: Intended Audience :: Developers
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Operating System :: OS Independent
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
42
|
+
Requires-Python: >=3.10
|
|
43
|
+
Requires-Dist: cronexpr>=0.30.0
|
|
44
|
+
Requires-Dist: fastapi>=0.115.13
|
|
45
|
+
Requires-Dist: pydantic>=2.11.7
|
|
46
|
+
Requires-Dist: redis>=6.2.0
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
|
+
|
|
49
|
+
# Fastapi Task Manager
|
|
50
|
+
A task manager for Fastapi. Robust Scheduling, Distributed Safety
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_local_tags():
|
|
7
|
+
"""Return a set of all local tag names."""
|
|
8
|
+
out = subprocess.check_output(["git", "tag", "-l"], text=True, stderr=subprocess.DEVNULL) # noqa: S607
|
|
9
|
+
return {line.strip() for line in out.splitlines() if line.strip()}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_remote_tags():
|
|
13
|
+
"""Return a set of all remote tag names on 'origin'."""
|
|
14
|
+
out = subprocess.check_output(["git", "ls-remote", "--tags", "origin"], text=True, stderr=subprocess.DEVNULL) # noqa: S607
|
|
15
|
+
tags = set()
|
|
16
|
+
for line in out.splitlines():
|
|
17
|
+
# each line is "<hash>\\trefs/tags/<tagname>" or "<hash>\\trefs/tags/<tagname>^{}"
|
|
18
|
+
parts = line.split()
|
|
19
|
+
if len(parts) != 2: # noqa: PLR2004
|
|
20
|
+
continue
|
|
21
|
+
ref = parts[1]
|
|
22
|
+
if not ref.startswith("refs/tags/"):
|
|
23
|
+
continue
|
|
24
|
+
tag = ref[len("refs/tags/") :]
|
|
25
|
+
# strip off ^{} that marks peeled (annotated) tags
|
|
26
|
+
if tag.endswith("^{}"):
|
|
27
|
+
tag = tag[:-3]
|
|
28
|
+
tags.add(tag)
|
|
29
|
+
return tags
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def prune_stale_tags():
|
|
33
|
+
local = get_local_tags()
|
|
34
|
+
remote = get_remote_tags()
|
|
35
|
+
to_delete = sorted(local - remote)
|
|
36
|
+
if not to_delete:
|
|
37
|
+
return remote
|
|
38
|
+
# Bulk-delete them:
|
|
39
|
+
subprocess.check_output(["git", "tag", "-d", *to_delete], text=True) # noqa: S603, S607
|
|
40
|
+
return remote
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == "__main__":
|
|
44
|
+
prune_stale_tags()
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "fastapi-task-manager"
|
|
3
|
+
version = "0.3.0"
|
|
4
|
+
description = "A task manager for Fastapi. Robust Scheduling, Distributed Safety"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Matteo Morando", email = "matteo.morando98@gmail.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
|
+
keywords = [
|
|
11
|
+
"fastapi",
|
|
12
|
+
"task-manager",
|
|
13
|
+
"task-scheduler",
|
|
14
|
+
"distributed",
|
|
15
|
+
"safety",
|
|
16
|
+
"robust",
|
|
17
|
+
]
|
|
18
|
+
license = { file = "LICENSE" }
|
|
19
|
+
urls = { "Homepage" = "https://github.com/Morry98/fastapi-task-manager", "Bug Tracker" = "https://github.com/Morry98/fastapi-task-manager/repo/issues" }
|
|
20
|
+
classifiers = [
|
|
21
|
+
"Development Status :: 3 - Alpha",
|
|
22
|
+
"Intended Audience :: Developers",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
29
|
+
"Programming Language :: Python :: 3.14",
|
|
30
|
+
"Framework :: FastAPI",
|
|
31
|
+
"Operating System :: OS Independent",
|
|
32
|
+
]
|
|
33
|
+
dependencies = [
|
|
34
|
+
"cronexpr>=0.30.0",
|
|
35
|
+
"fastapi>=0.115.13",
|
|
36
|
+
"pydantic>=2.11.7",
|
|
37
|
+
"redis>=6.2.0",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
fastapi-task-manager = "fastapi_task_manager:main"
|
|
42
|
+
|
|
43
|
+
[build-system]
|
|
44
|
+
requires = ["hatchling"]
|
|
45
|
+
build-backend = "hatchling.build"
|
|
46
|
+
|
|
47
|
+
[[tool.uv.index]]
|
|
48
|
+
name = "testpypi"
|
|
49
|
+
url = "https://test.pypi.org/simple/"
|
|
50
|
+
publish-url = "https://test.pypi.org/legacy/"
|
|
51
|
+
explicit = true
|
|
52
|
+
|
|
53
|
+
[tool.ruff]
|
|
54
|
+
show-fixes = true
|
|
55
|
+
line-length = 120
|
|
56
|
+
|
|
57
|
+
[tool.ruff.lint]
|
|
58
|
+
# see https://docs.astral.sh/ruff/rules/ for more info
|
|
59
|
+
select = [
|
|
60
|
+
"F", # Pyflakes
|
|
61
|
+
"E", # pycodestyle errors
|
|
62
|
+
"W", # pycodestyle warnings
|
|
63
|
+
"C90", # mccabe
|
|
64
|
+
"I", # isort
|
|
65
|
+
"N", # pep8-naming
|
|
66
|
+
"S", # flake8-bandit
|
|
67
|
+
"B", # flake8-bugbear
|
|
68
|
+
# "D", # pydocstyle
|
|
69
|
+
"UP", # pyupgrade
|
|
70
|
+
"YTT", # flake8-2020
|
|
71
|
+
# "ANN", # flake8-annotations
|
|
72
|
+
# "BLE", # flake8-blind-except
|
|
73
|
+
# "FBT", # flake8-boolean-trap
|
|
74
|
+
"A", # flake8-builtins
|
|
75
|
+
"COM", # flake8-commas
|
|
76
|
+
"C4", # flake8-comprehensions
|
|
77
|
+
"T10", # flake8-debugger
|
|
78
|
+
"EXE", # flake8-executable
|
|
79
|
+
# "DTZ", # flake8-datetimez
|
|
80
|
+
"DJ", # flake8-django
|
|
81
|
+
"EM", # flake8-errmsg
|
|
82
|
+
"ISC", # flake8-implicit-str-concat
|
|
83
|
+
"ICN", # flake8-import-conventions
|
|
84
|
+
"G", # flake8-logging-format
|
|
85
|
+
# "INP", # flake8-no-pep420
|
|
86
|
+
"PIE", # flake8-pie
|
|
87
|
+
"T20", # flake8-print
|
|
88
|
+
"PYI", # flake8-pyi
|
|
89
|
+
"PT", # flake8-pytest-style
|
|
90
|
+
"Q", # flake8-quotes
|
|
91
|
+
"RSE", # flake8-raise
|
|
92
|
+
"RET", # flake8-return
|
|
93
|
+
"SLF", # flake8-self
|
|
94
|
+
"SIM", # flake8-simplify
|
|
95
|
+
"TID", # flake8-tidy-imports
|
|
96
|
+
"TCH", # flake8-type-checking
|
|
97
|
+
"INT", # flake8-gettext
|
|
98
|
+
"ARG", # flake8-unused-arguments
|
|
99
|
+
# "PTH", # flake8-use-pathlib
|
|
100
|
+
"ERA", # eradicate
|
|
101
|
+
# "PD", # pandas-vet
|
|
102
|
+
# "PGH", # pygrep-hooks
|
|
103
|
+
"PL", # Pylint
|
|
104
|
+
"TRY", # tryceratops
|
|
105
|
+
"NPY", # NumPy-specific rules
|
|
106
|
+
"RUF", # Ruff-specific rules
|
|
107
|
+
]
|
|
108
|
+
ignore = [
|
|
109
|
+
"B008",
|
|
110
|
+
"N801",
|
|
111
|
+
"N806",
|
|
112
|
+
"PD003",
|
|
113
|
+
"PD011",
|
|
114
|
+
"Q000",
|
|
115
|
+
"S101",
|
|
116
|
+
"S113",
|
|
117
|
+
"S501",
|
|
118
|
+
"RUF012",
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
[tool.ruff.lint.flake8-quotes]
|
|
122
|
+
inline-quotes = "double"
|
|
123
|
+
|
|
124
|
+
[tool.ruff.lint.mccabe]
|
|
125
|
+
max-complexity = 12
|
|
126
|
+
|
|
127
|
+
[tool.ruff.lint.per-file-ignores]
|
|
128
|
+
"__init__.py" = ["F401"]
|
|
129
|
+
"tmp*.py" = ["T201"]
|
|
130
|
+
"test_*.py" = ["E402", "PLR2004", "SLF001", "ARG001"]
|
|
131
|
+
|
|
132
|
+
[tool.ruff.lint.pylint]
|
|
133
|
+
max-args = 8
|
|
134
|
+
|
|
135
|
+
[tool.mypy]
|
|
136
|
+
no_implicit_optional = true
|
|
137
|
+
check_untyped_defs = true
|
|
138
|
+
warn_redundant_casts = true
|
|
139
|
+
warn_unused_ignores = true
|
|
140
|
+
warn_no_return = true
|
|
141
|
+
warn_unreachable = true
|
|
142
|
+
pretty = true
|
|
143
|
+
ignore_missing_imports = true
|
|
144
|
+
plugins = []
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from pydantic import BaseModel
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Config(BaseModel):
|
|
5
|
+
# --------- Logging config variables ---------
|
|
6
|
+
level: str = "WARNING"
|
|
7
|
+
# --------- End of logging config variables ---------
|
|
8
|
+
|
|
9
|
+
# --------- App config variables ---------
|
|
10
|
+
concurrent_tasks: int = 2
|
|
11
|
+
# --------- End of app config variables ---------
|
|
12
|
+
|
|
13
|
+
# --------- Redis config variables ---------
|
|
14
|
+
redis_host: str | None = None
|
|
15
|
+
redis_port: int = 6379
|
|
16
|
+
redis_password: str | None = None
|
|
17
|
+
redis_db: int = 1 # Default Redis database to use
|
|
18
|
+
# --------- End of redis config variables ---------
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from contextlib import asynccontextmanager
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ForceAcquireSemaphore(asyncio.Semaphore):
|
|
6
|
+
@asynccontextmanager
|
|
7
|
+
async def force_acquire(self):
|
|
8
|
+
# bypass the normal acquire() wait and
|
|
9
|
+
# decrement the counter even if it goes < 0
|
|
10
|
+
self._value -= 1
|
|
11
|
+
try:
|
|
12
|
+
yield
|
|
13
|
+
finally:
|
|
14
|
+
if self._value < 0:
|
|
15
|
+
# if the value is negative, we increment it back
|
|
16
|
+
self._value += 1
|
|
17
|
+
else:
|
|
18
|
+
# if the value is not negative, we just release normally
|
|
19
|
+
# this is to ensure that the semaphore can be used normally after force_acquire
|
|
20
|
+
self.release()
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
|
+
from uuid import uuid4
|
|
6
|
+
|
|
7
|
+
from cronexpr import next_fire
|
|
8
|
+
from redis.asyncio import Redis
|
|
9
|
+
|
|
10
|
+
from fastapi_task_manager.force_acquire_semaphore import ForceAcquireSemaphore
|
|
11
|
+
from fastapi_task_manager.schema.task import Task
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger("fastapi.task-manager")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Runner:
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
redis_client: Redis,
|
|
20
|
+
concurrent_tasks: int,
|
|
21
|
+
):
|
|
22
|
+
self._uuid: str = str(uuid4().int)
|
|
23
|
+
self._redis_client = redis_client
|
|
24
|
+
self._running_thread: asyncio.Task | None = None
|
|
25
|
+
self._tasks: list[Task] = []
|
|
26
|
+
self._semaphore = ForceAcquireSemaphore(concurrent_tasks)
|
|
27
|
+
|
|
28
|
+
async def start(self) -> None:
|
|
29
|
+
if self._running_thread:
|
|
30
|
+
msg = "Runner is already running."
|
|
31
|
+
logger.warning(msg)
|
|
32
|
+
return
|
|
33
|
+
try:
|
|
34
|
+
pong = await self._redis_client.ping()
|
|
35
|
+
except Exception as e:
|
|
36
|
+
msg = f"Redis ping failed: {e!r}"
|
|
37
|
+
raise ConnectionError(msg) from e
|
|
38
|
+
if not pong:
|
|
39
|
+
msg = "Redis ping returned falsy response"
|
|
40
|
+
raise ConnectionError(msg)
|
|
41
|
+
|
|
42
|
+
self._running_thread = asyncio.create_task(self._run(), name="Runner")
|
|
43
|
+
logger.info("Runner started successfully.")
|
|
44
|
+
|
|
45
|
+
async def stop(self) -> None:
|
|
46
|
+
if not self._running_thread:
|
|
47
|
+
msg = "Runner is not running."
|
|
48
|
+
logger.warning(msg)
|
|
49
|
+
return
|
|
50
|
+
for task in self._tasks:
|
|
51
|
+
if task.running_thread:
|
|
52
|
+
await stop_thread(task.running_thread)
|
|
53
|
+
task.running_thread = None
|
|
54
|
+
await stop_thread(self._running_thread)
|
|
55
|
+
self._running_thread = None
|
|
56
|
+
logger.info("Stopped TaskManager.")
|
|
57
|
+
|
|
58
|
+
def add_task(self, task: Task) -> None:
|
|
59
|
+
for t in self._tasks:
|
|
60
|
+
if t.name == task.name:
|
|
61
|
+
msg = f"Task with name {task.name} already exists."
|
|
62
|
+
raise RuntimeError(msg)
|
|
63
|
+
self._tasks.append(task)
|
|
64
|
+
|
|
65
|
+
async def _run(self):
|
|
66
|
+
while True:
|
|
67
|
+
await asyncio.sleep(0.1)
|
|
68
|
+
try:
|
|
69
|
+
for task in self._tasks:
|
|
70
|
+
if task.running_thread is not None:
|
|
71
|
+
if not task.running_thread.done():
|
|
72
|
+
continue
|
|
73
|
+
# If the task is done, remove it from the running tasks list
|
|
74
|
+
task.running_thread = None
|
|
75
|
+
elif task.next_run <= datetime.now(timezone.utc):
|
|
76
|
+
task.next_run = next_fire(task.expression)
|
|
77
|
+
task.running_thread = asyncio.create_task(self._queue_task(task), name=task.name)
|
|
78
|
+
except asyncio.CancelledError:
|
|
79
|
+
logger.info("Runner task was cancelled.")
|
|
80
|
+
return
|
|
81
|
+
except Exception:
|
|
82
|
+
logger.exception("Error in Runner task loop.")
|
|
83
|
+
continue
|
|
84
|
+
|
|
85
|
+
async def _queue_task(self, task: Task):
|
|
86
|
+
if task.high_priority:
|
|
87
|
+
async with self._semaphore.force_acquire():
|
|
88
|
+
await self._run_task(task)
|
|
89
|
+
else:
|
|
90
|
+
async with self._semaphore:
|
|
91
|
+
await self._run_task(task)
|
|
92
|
+
|
|
93
|
+
async def _run_task(self, task: Task) -> None:
|
|
94
|
+
try:
|
|
95
|
+
redis_key_exists = await self._redis_client.exists(task.name + "_valid")
|
|
96
|
+
if redis_key_exists:
|
|
97
|
+
return
|
|
98
|
+
|
|
99
|
+
redis_uuid_exists = await self._redis_client.exists(task.name + "_runner_uuid")
|
|
100
|
+
if not redis_uuid_exists:
|
|
101
|
+
await self._redis_client.set(task.name + "_runner_uuid", self._uuid, ex=5)
|
|
102
|
+
await asyncio.sleep(0.2)
|
|
103
|
+
redis_uuid_b = await self._redis_client.get(task.name + "_runner_uuid")
|
|
104
|
+
if redis_uuid_b is None:
|
|
105
|
+
return
|
|
106
|
+
if redis_uuid_b.decode("utf-8") != self._uuid:
|
|
107
|
+
return
|
|
108
|
+
|
|
109
|
+
thread = asyncio.create_task(run_function(task.function))
|
|
110
|
+
while not thread.done():
|
|
111
|
+
await self._redis_client.set(task.name + "_runner_uuid", self._uuid, ex=1)
|
|
112
|
+
await asyncio.sleep(0.1)
|
|
113
|
+
|
|
114
|
+
task.next_run = next_fire(task.expression)
|
|
115
|
+
ex = int((task.next_run - datetime.now(timezone.utc)).total_seconds())
|
|
116
|
+
if ex <= 0:
|
|
117
|
+
return
|
|
118
|
+
await self._redis_client.set(
|
|
119
|
+
task.name + "_valid",
|
|
120
|
+
1,
|
|
121
|
+
ex=ex,
|
|
122
|
+
)
|
|
123
|
+
await self._redis_client.delete(task.name + "_runner_uuid")
|
|
124
|
+
|
|
125
|
+
except asyncio.CancelledError:
|
|
126
|
+
msg = f"Task {task.name} was cancelled."
|
|
127
|
+
logger.info(msg)
|
|
128
|
+
except Exception:
|
|
129
|
+
logger.exception("Failed to run task.")
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
async def stop_thread(running_task: asyncio.Task) -> None:
|
|
133
|
+
if not running_task.done():
|
|
134
|
+
running_task.cancel()
|
|
135
|
+
try:
|
|
136
|
+
await running_task
|
|
137
|
+
except asyncio.CancelledError:
|
|
138
|
+
return
|
|
139
|
+
except Exception:
|
|
140
|
+
msg = "Error stopping Runner"
|
|
141
|
+
logger.exception(msg)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
async def run_function(function: Callable):
|
|
145
|
+
try:
|
|
146
|
+
if asyncio.iscoroutinefunction(function):
|
|
147
|
+
await function()
|
|
148
|
+
else:
|
|
149
|
+
await asyncio.to_thread(function)
|
|
150
|
+
except Exception:
|
|
151
|
+
logger.exception("Error running function.")
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Task(BaseModel):
|
|
9
|
+
"""Schema for a task in the task manager."""
|
|
10
|
+
|
|
11
|
+
model_config = {
|
|
12
|
+
"arbitrary_types_allowed": True,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function: Callable
|
|
16
|
+
expression: str
|
|
17
|
+
name: str
|
|
18
|
+
description: str | None = None
|
|
19
|
+
tags: list[str] | None = None
|
|
20
|
+
high_priority: bool = False
|
|
21
|
+
next_run: datetime = datetime.min.replace(tzinfo=timezone.utc)
|
|
22
|
+
running_thread: asyncio.Task | None = None
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
from contextlib import asynccontextmanager
|
|
4
|
+
|
|
5
|
+
from fastapi import FastAPI
|
|
6
|
+
from redis.asyncio import Redis
|
|
7
|
+
|
|
8
|
+
from fastapi_task_manager.config import Config
|
|
9
|
+
from fastapi_task_manager.runner import Runner
|
|
10
|
+
from fastapi_task_manager.schema.task import Task
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger("fastapi.task-manager")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TaskManager:
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
app: FastAPI,
|
|
19
|
+
redis_client: Redis,
|
|
20
|
+
config: Config | None = None,
|
|
21
|
+
):
|
|
22
|
+
self._config = config or Config()
|
|
23
|
+
self._app = app
|
|
24
|
+
self._running = False
|
|
25
|
+
self._runner = Runner(
|
|
26
|
+
redis_client=redis_client,
|
|
27
|
+
concurrent_tasks=self._config.concurrent_tasks,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
logger.setLevel(self._config.level.upper().strip())
|
|
31
|
+
|
|
32
|
+
self.append_to_app_lifecycle(app)
|
|
33
|
+
|
|
34
|
+
def append_to_app_lifecycle(self, app: FastAPI) -> None:
|
|
35
|
+
"""Automatically start/stop with app lifecycle."""
|
|
36
|
+
|
|
37
|
+
# Check if app already has a lifespan
|
|
38
|
+
existing_lifespan = getattr(app.router, "lifespan_context", None)
|
|
39
|
+
|
|
40
|
+
@asynccontextmanager
|
|
41
|
+
async def lifespan(app):
|
|
42
|
+
await self.start()
|
|
43
|
+
try:
|
|
44
|
+
if existing_lifespan:
|
|
45
|
+
# If there's an existing lifespan, run it
|
|
46
|
+
async with existing_lifespan(app):
|
|
47
|
+
yield
|
|
48
|
+
else:
|
|
49
|
+
yield
|
|
50
|
+
finally:
|
|
51
|
+
await self.stop()
|
|
52
|
+
|
|
53
|
+
# Set the new lifespan
|
|
54
|
+
app.router.lifespan_context = lifespan
|
|
55
|
+
|
|
56
|
+
async def start(self) -> None:
|
|
57
|
+
if self._running:
|
|
58
|
+
logger.warning("TaskManager is already running.")
|
|
59
|
+
return
|
|
60
|
+
self._running = True
|
|
61
|
+
logger.info("Starting TaskManager...")
|
|
62
|
+
await self._runner.start()
|
|
63
|
+
logger.info("Started TaskManager.")
|
|
64
|
+
|
|
65
|
+
async def stop(self) -> None:
|
|
66
|
+
if not self._running:
|
|
67
|
+
logger.warning("TaskManager is not running.")
|
|
68
|
+
return
|
|
69
|
+
self._running = False
|
|
70
|
+
logger.info("Stopping TaskManager...")
|
|
71
|
+
await self._runner.stop()
|
|
72
|
+
logger.info("Stopped TaskManager.")
|
|
73
|
+
|
|
74
|
+
def manager(
|
|
75
|
+
self,
|
|
76
|
+
expr: str,
|
|
77
|
+
tags: list[str] | None = None,
|
|
78
|
+
name: str | None = None,
|
|
79
|
+
description: str | None = None,
|
|
80
|
+
high_priority: bool = False,
|
|
81
|
+
):
|
|
82
|
+
"""Decorator for creating task."""
|
|
83
|
+
|
|
84
|
+
def wrapper(func: Callable):
|
|
85
|
+
task = Task(
|
|
86
|
+
function=func,
|
|
87
|
+
expression=expr,
|
|
88
|
+
name=name or func.__name__,
|
|
89
|
+
description=description,
|
|
90
|
+
tags=tags,
|
|
91
|
+
high_priority=high_priority,
|
|
92
|
+
)
|
|
93
|
+
self._runner.add_task(task)
|
|
94
|
+
|
|
95
|
+
return func
|
|
96
|
+
|
|
97
|
+
return wrapper
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
version = 1
|
|
2
|
+
revision = 1
|
|
3
|
+
requires-python = ">=3.10"
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "annotated-types"
|
|
7
|
+
version = "0.7.0"
|
|
8
|
+
source = { registry = "https://pypi.org/simple" }
|
|
9
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 }
|
|
10
|
+
wheels = [
|
|
11
|
+
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 },
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[[package]]
|
|
15
|
+
name = "anyio"
|
|
16
|
+
version = "4.9.0"
|
|
17
|
+
source = { registry = "https://pypi.org/simple" }
|
|
18
|
+
dependencies = [
|
|
19
|
+
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
|
20
|
+
{ name = "idna" },
|
|
21
|
+
{ name = "sniffio" },
|
|
22
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
|
23
|
+
]
|
|
24
|
+
sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949 }
|
|
25
|
+
wheels = [
|
|
26
|
+
{ url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916 },
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[[package]]
|
|
30
|
+
name = "async-timeout"
|
|
31
|
+
version = "5.0.1"
|
|
32
|
+
source = { registry = "https://pypi.org/simple" }
|
|
33
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274 }
|
|
34
|
+
wheels = [
|
|
35
|
+
{ url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233 },
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[[package]]
|
|
39
|
+
name = "cronexpr"
|
|
40
|
+
version = "0.30.0"
|
|
41
|
+
source = { registry = "https://pypi.org/simple" }
|
|
42
|
+
sdist = { url = "https://files.pythonhosted.org/packages/01/2a/72d9b939fa00a9e77c613e7d7cee361a81d9df2d036493a522517d083a46/cronexpr-0.30.0.tar.gz", hash = "sha256:994660fdf9195bc2456e69fa447fb06d8256cdfd7fe8829be82add10b9f3e9ac", size = 9350 }
|
|
43
|
+
wheels = [
|
|
44
|
+
{ url = "https://files.pythonhosted.org/packages/78/22/da06c70e633d7939c7f0b596835a70c0c2061e8f1bce1937626560368bee/cronexpr-0.30.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae2c90b6240a3be1a4e6ee118055b1212338369ad4524c9e56b7f1ba1495884d", size = 58617 },
|
|
45
|
+
{ url = "https://files.pythonhosted.org/packages/ce/1a/007ef33feeaf8e84da091b1440ceb938e7d551eea8a5684863ec5da3427a/cronexpr-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3faa4a3e0416f7ada2285af2134b52e4c1958f5bb4838202ff639c7392fcf443", size = 55633 },
|
|
46
|
+
{ url = "https://files.pythonhosted.org/packages/94/c4/ee667eaf1605ce132f23cb4649ee5320467c3a627c1a73dc3645d60a409a/cronexpr-0.30.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8336da63137deca455f5170162fd27a016043e6f5ad1a83d884ad17510d5e80", size = 93074 },
|
|
47
|
+
{ url = "https://files.pythonhosted.org/packages/a2/3a/995d76d3b00588f2c509e704606fec063c59341125f5230912485f42e79b/cronexpr-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ba3c473a7fcced90334931702aca389c058f7aa60f999847a2bff76906f1649", size = 86902 },
|
|
48
|
+
{ url = "https://files.pythonhosted.org/packages/5a/ef/1eab22c6cf02b2e10b63a1648030cbf31e8ff31a1e485a76d05e9fb1f7c4/cronexpr-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c40467180ea05dd7dc5ce191a02a4873e01e0f3297dfe4215eac99c93acd5060", size = 1159329 },
|
|
49
|
+
{ url = "https://files.pythonhosted.org/packages/b5/66/31eef1d473bd3fa4401eacb3a59f9448cddb74525fee4becb0c326254f4d/cronexpr-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:281bce47793fddba003f246858aae0b8263d028128e96c1e6fa99484870ae86f", size = 1061752 },
|
|
50
|
+
{ url = "https://files.pythonhosted.org/packages/eb/85/d046fc7f717123aec290c709cc7bcadb6ea10259abc8fbbfc8a492920e58/cronexpr-0.30.0-cp310-cp310-win32.whl", hash = "sha256:3cfcc338cfcc9b69e09bdb2ba11a0aaa1603c52e431cfd26e92e227831daa22b", size = 58659 },
|
|
51
|
+
{ url = "https://files.pythonhosted.org/packages/e7/7b/0499b2c5484305606d9244d90adb354021a92bdb8748e62a956ec6694b23/cronexpr-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad6e6e0616fa731dbdb755e6fa54d28a0bf7915e9fe8ea30b8f2c497d35e00f0", size = 63256 },
|
|
52
|
+
{ url = "https://files.pythonhosted.org/packages/2f/d5/ce627a6d1e4a268e6d88811f01e4edbc5d4bedfb8f3ff41fa10182692f7a/cronexpr-0.30.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:617ad204f1db8c09ab57e5e15698b29d8e83634569e953c22b4ca2fb1a631a63", size = 59958 },
|
|
53
|
+
{ url = "https://files.pythonhosted.org/packages/49/fa/751bf123fb0c5e10d37220b690991aa617cebd96e2bbc23851a79b043b46/cronexpr-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f4b10220ed3e63a4bbaffa835faa1104c1e8a13c905e9413a958ed3c566da268", size = 56983 },
|
|
54
|
+
{ url = "https://files.pythonhosted.org/packages/3c/21/8291ad371c9e4bef2b7f88817e66c287344b5dd35cc5fb69317f4940b6fe/cronexpr-0.30.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6504804326fd99362e20a127e61c031b512c7437a929377c624fb5f4675351c", size = 94254 },
|
|
55
|
+
{ url = "https://files.pythonhosted.org/packages/45/06/08eb634f5e9ee07063db2ccd793dfda46f7bb245a0ef5ed66420f733e402/cronexpr-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45bde59a340c6c0019ac83cbc0719f618dd7ec6f293f7c888a43c579ee47c644", size = 88478 },
|
|
56
|
+
{ url = "https://files.pythonhosted.org/packages/16/08/56338ba97756e6f380c9cbb1671f504584e660c3315f55879b1cd1be1b10/cronexpr-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:02b69b6fbd4b0b1e862aa5b7cc7f7fd07462804d04036bc493b03a28cda0fa06", size = 1160044 },
|
|
57
|
+
{ url = "https://files.pythonhosted.org/packages/e8/11/09f1f0c13842ad4866c2c0dc698a570ffd3118961193bbcf9674600cd646/cronexpr-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2f88a6320956d5b98793d1b82753556c766a113db25cef53429ac30cb09f9e4a", size = 1062723 },
|
|
58
|
+
{ url = "https://files.pythonhosted.org/packages/6d/74/40a91b2c3e735a5d1f8aa5826700dbcaecdb1e654dffde777007f7110e16/cronexpr-0.30.0-cp311-cp311-win32.whl", hash = "sha256:f3f05a53541af3b646912dced6fa0b160435a847a9666bf88783de02474d903f", size = 59856 },
|
|
59
|
+
{ url = "https://files.pythonhosted.org/packages/aa/84/e9eabcc97939546535739d5f40013bed80014d3ad5df13d3983c82c3c15d/cronexpr-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:1cf831566fbda55fc5083d101c957921fda0f0cfef4e4e415b21d86bc6a57964", size = 64358 },
|
|
60
|
+
{ url = "https://files.pythonhosted.org/packages/3d/6b/7c4d19220b96cd61d9e2b0f0874e8f5c79a26ea473f4728a2fcc2ec908ef/cronexpr-0.30.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b59f8991ff1e2cdfceca780104cf49411ee5706b03abc22aa7ce2133a36109dc", size = 59114 },
|
|
61
|
+
{ url = "https://files.pythonhosted.org/packages/88/1b/0bab92c881b06b8c910d277cea132a3db61f0662eb8977da0428884f2bb4/cronexpr-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a6cfbd0d440f9072c9af0fc1891f671ef7930c2bd033af409844fb37a8e58f9b", size = 56261 },
|
|
62
|
+
{ url = "https://files.pythonhosted.org/packages/2a/65/1e12be06033577ff8b5c3f1680de59ebf39f5147f1672a5675a5b677aa74/cronexpr-0.30.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0ba6cfa84429af7374f4d0fa824d16928b725de7996ec08ec69873dc9584e4df", size = 93894 },
|
|
63
|
+
{ url = "https://files.pythonhosted.org/packages/38/6a/d074ca8bf64c42ae9693f4f34554794b9ecbea4d6558143c87e24b548a2a/cronexpr-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba3567d992504372edc3ab97b40985e40b29e0b54354c46cdb6fdb46cdb4f75f", size = 88055 },
|
|
64
|
+
{ url = "https://files.pythonhosted.org/packages/74/9d/1f72e5bf4a9fcc868ffab9ac1ca52b6b1014a657545f0dd9a713dd2453cf/cronexpr-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8ac28315c1650173d6bc2aac1fd802963f8120196fd070a9ad747e458d3ea7d2", size = 1159197 },
|
|
65
|
+
{ url = "https://files.pythonhosted.org/packages/bb/5b/6c432619c401bc4e582441cb88819e1607c40aaaba2c6b07f66337b01899/cronexpr-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee616c723fbb129c7e7aaa0d6158c043d4dfc90df4dc7d35f1f257b7ab1c1954", size = 1062002 },
|
|
66
|
+
{ url = "https://files.pythonhosted.org/packages/88/5e/15344b0763b5510658293b819f56472b2b35032149c4d09d5078312226d0/cronexpr-0.30.0-cp312-cp312-win32.whl", hash = "sha256:7b1fbdd2eee6ed709320a2a20f63283a53b3b391fdc61e5275c7299daadf7ae3", size = 60061 },
|
|
67
|
+
{ url = "https://files.pythonhosted.org/packages/f4/59/210fd2810429df7964f692b349deb82fff50db2742d9d639b87e4dc9cfeb/cronexpr-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:45fe11c95c83d800e9558a03a77a91b78af34898ce30dae895c06a31975b2a3c", size = 64438 },
|
|
68
|
+
{ url = "https://files.pythonhosted.org/packages/3d/1b/a0a5ac3cc99268cda3a438ca9b55d12567180cc26d3191291b4343a8ee06/cronexpr-0.30.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc186d1a3b99cbaed6363c1ee79b5eeff724835cc4c12f39188b6db981681d1f", size = 59131 },
|
|
69
|
+
{ url = "https://files.pythonhosted.org/packages/d8/1f/27b43b778594d86c6b419ff4cd2b015c49c0ff204796b47e9626acdf1f87/cronexpr-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:da9db9656be179baa3b30f4484998faa8d7a9f491b467b4a620daba5ea29a2d0", size = 56335 },
|
|
70
|
+
{ url = "https://files.pythonhosted.org/packages/6c/7b/4249bb448829498c3e7783e66d188993c085b4294c8d5f9808071e163e60/cronexpr-0.30.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7038afad7d188ddc98caca3891640d556425f6c10de97de0da64dd7a9126974", size = 93819 },
|
|
71
|
+
{ url = "https://files.pythonhosted.org/packages/4b/71/1516e363a4b1386c0c35d716e0b798272415c1da215c9b2c6bdf0a99516e/cronexpr-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac76e65edc8491048c4a86d1785f12952a80f1df1bdf6662114573856a2ea921", size = 88083 },
|
|
72
|
+
{ url = "https://files.pythonhosted.org/packages/05/81/8c00fbeda05eff7fb226563f5ae6beb57da122b4729d5bb8961e9c0eaae3/cronexpr-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:99aefb61623915657fe29db28d0b407e2f748776d25acf31d4d45b2289947f8f", size = 1159363 },
|
|
73
|
+
{ url = "https://files.pythonhosted.org/packages/ae/a6/44d54958f03a147a64169f534733f38e056bdad967e4ca38188b49f1ec97/cronexpr-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:11ee708ff4da288a1e22757f4425e031809603efac6437fd33a4f91bff0993e9", size = 1062004 },
|
|
74
|
+
{ url = "https://files.pythonhosted.org/packages/bd/fa/c6cf80efef0e15e969c6aace48fcbee8c9bdfe51c14cb9a24f3a1f7e0a8d/cronexpr-0.30.0-cp313-cp313-win32.whl", hash = "sha256:591719b48ccf6c95b3aa784f3de9e0f9e8d720ed76d4ae52a39d94f173dd0413", size = 60132 },
|
|
75
|
+
{ url = "https://files.pythonhosted.org/packages/7b/74/721872a84b05e0a424ac24c2dce09571605d72c9b32947545bdaecbc43e5/cronexpr-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:866aad7bd871bf9dec694f2b747861d3dc3681debc3bf2ef0bc78346418da574", size = 64461 },
|
|
76
|
+
{ url = "https://files.pythonhosted.org/packages/7c/f3/e727a8389514088b8e4474f122da0886d97c113a68480a8244f7c730d86b/cronexpr-0.30.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5f1368730689b749e8cebb6bfa3ac0fafa65529fb7df7d05c8b59924b2d647", size = 59428 },
|
|
77
|
+
{ url = "https://files.pythonhosted.org/packages/bd/45/1987d2a75ce51aff6b0565f052f429ac47d517a776f5322d57d8120d82f3/cronexpr-0.30.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ef7ac0861c1149cb39f2768b49921e3736f38fc4f81d03a885041b64b35f6d2d", size = 56020 },
|
|
78
|
+
{ url = "https://files.pythonhosted.org/packages/23/77/d06d4584f3d8d757044418eedd477030b5d4429f060d74cd837a58ad3f0c/cronexpr-0.30.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acc48680bd667abe56b3d3cccfad2153e2bb38bb02c801ae9743cac9837d37d8", size = 92924 },
|
|
79
|
+
{ url = "https://files.pythonhosted.org/packages/99/aa/77046ee80228448541165e0a2ee9b491f2b5722274aa146786f32278229b/cronexpr-0.30.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f381e2f40e54df5676401e4226b3908273ea6cb195cc687204b1029933836717", size = 86940 },
|
|
80
|
+
{ url = "https://files.pythonhosted.org/packages/e1/a0/5d266c0d370aec62a49003fed1648518e2c24908f9719a7563e2a689c05c/cronexpr-0.30.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1e1117188c05595e2bb404601cb122d62773eb087d52dd2f905bea7f5690145f", size = 63497 },
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
[[package]]
|
|
84
|
+
name = "exceptiongroup"
|
|
85
|
+
version = "1.3.0"
|
|
86
|
+
source = { registry = "https://pypi.org/simple" }
|
|
87
|
+
dependencies = [
|
|
88
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
|
89
|
+
]
|
|
90
|
+
sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749 }
|
|
91
|
+
wheels = [
|
|
92
|
+
{ url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674 },
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
[[package]]
|
|
96
|
+
name = "fastapi"
|
|
97
|
+
version = "0.115.13"
|
|
98
|
+
source = { registry = "https://pypi.org/simple" }
|
|
99
|
+
dependencies = [
|
|
100
|
+
{ name = "pydantic" },
|
|
101
|
+
{ name = "starlette" },
|
|
102
|
+
{ name = "typing-extensions" },
|
|
103
|
+
]
|
|
104
|
+
sdist = { url = "https://files.pythonhosted.org/packages/20/64/ec0788201b5554e2a87c49af26b77a4d132f807a0fa9675257ac92c6aa0e/fastapi-0.115.13.tar.gz", hash = "sha256:55d1d25c2e1e0a0a50aceb1c8705cd932def273c102bff0b1c1da88b3c6eb307", size = 295680 }
|
|
105
|
+
wheels = [
|
|
106
|
+
{ url = "https://files.pythonhosted.org/packages/59/4a/e17764385382062b0edbb35a26b7cf76d71e27e456546277a42ba6545c6e/fastapi-0.115.13-py3-none-any.whl", hash = "sha256:0a0cab59afa7bab22f5eb347f8c9864b681558c278395e94035a741fc10cd865", size = 95315 },
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
[[package]]
|
|
110
|
+
name = "fastapi-task-manager"
|
|
111
|
+
version = "0.1.4"
|
|
112
|
+
source = { editable = "." }
|
|
113
|
+
dependencies = [
|
|
114
|
+
{ name = "cronexpr" },
|
|
115
|
+
{ name = "fastapi" },
|
|
116
|
+
{ name = "pydantic" },
|
|
117
|
+
{ name = "redis" },
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
[package.metadata]
|
|
121
|
+
requires-dist = [
|
|
122
|
+
{ name = "cronexpr", specifier = ">=0.30.0" },
|
|
123
|
+
{ name = "fastapi", specifier = ">=0.115.13" },
|
|
124
|
+
{ name = "pydantic", specifier = ">=2.11.7" },
|
|
125
|
+
{ name = "redis", specifier = ">=6.2.0" },
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
[[package]]
|
|
129
|
+
name = "idna"
|
|
130
|
+
version = "3.10"
|
|
131
|
+
source = { registry = "https://pypi.org/simple" }
|
|
132
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 }
|
|
133
|
+
wheels = [
|
|
134
|
+
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
|
|
135
|
+
]
|
|
136
|
+
|
|
137
|
+
[[package]]
|
|
138
|
+
name = "pydantic"
|
|
139
|
+
version = "2.11.7"
|
|
140
|
+
source = { registry = "https://pypi.org/simple" }
|
|
141
|
+
dependencies = [
|
|
142
|
+
{ name = "annotated-types" },
|
|
143
|
+
{ name = "pydantic-core" },
|
|
144
|
+
{ name = "typing-extensions" },
|
|
145
|
+
{ name = "typing-inspection" },
|
|
146
|
+
]
|
|
147
|
+
sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350 }
|
|
148
|
+
wheels = [
|
|
149
|
+
{ url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782 },
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
[[package]]
|
|
153
|
+
name = "pydantic-core"
|
|
154
|
+
version = "2.33.2"
|
|
155
|
+
source = { registry = "https://pypi.org/simple" }
|
|
156
|
+
dependencies = [
|
|
157
|
+
{ name = "typing-extensions" },
|
|
158
|
+
]
|
|
159
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195 }
|
|
160
|
+
wheels = [
|
|
161
|
+
{ url = "https://files.pythonhosted.org/packages/e5/92/b31726561b5dae176c2d2c2dc43a9c5bfba5d32f96f8b4c0a600dd492447/pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8", size = 2028817 },
|
|
162
|
+
{ url = "https://files.pythonhosted.org/packages/a3/44/3f0b95fafdaca04a483c4e685fe437c6891001bf3ce8b2fded82b9ea3aa1/pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d", size = 1861357 },
|
|
163
|
+
{ url = "https://files.pythonhosted.org/packages/30/97/e8f13b55766234caae05372826e8e4b3b96e7b248be3157f53237682e43c/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d", size = 1898011 },
|
|
164
|
+
{ url = "https://files.pythonhosted.org/packages/9b/a3/99c48cf7bafc991cc3ee66fd544c0aae8dc907b752f1dad2d79b1b5a471f/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572", size = 1982730 },
|
|
165
|
+
{ url = "https://files.pythonhosted.org/packages/de/8e/a5b882ec4307010a840fb8b58bd9bf65d1840c92eae7534c7441709bf54b/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02", size = 2136178 },
|
|
166
|
+
{ url = "https://files.pythonhosted.org/packages/e4/bb/71e35fc3ed05af6834e890edb75968e2802fe98778971ab5cba20a162315/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b", size = 2736462 },
|
|
167
|
+
{ url = "https://files.pythonhosted.org/packages/31/0d/c8f7593e6bc7066289bbc366f2235701dcbebcd1ff0ef8e64f6f239fb47d/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2", size = 2005652 },
|
|
168
|
+
{ url = "https://files.pythonhosted.org/packages/d2/7a/996d8bd75f3eda405e3dd219ff5ff0a283cd8e34add39d8ef9157e722867/pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a", size = 2113306 },
|
|
169
|
+
{ url = "https://files.pythonhosted.org/packages/ff/84/daf2a6fb2db40ffda6578a7e8c5a6e9c8affb251a05c233ae37098118788/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac", size = 2073720 },
|
|
170
|
+
{ url = "https://files.pythonhosted.org/packages/77/fb/2258da019f4825128445ae79456a5499c032b55849dbd5bed78c95ccf163/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a", size = 2244915 },
|
|
171
|
+
{ url = "https://files.pythonhosted.org/packages/d8/7a/925ff73756031289468326e355b6fa8316960d0d65f8b5d6b3a3e7866de7/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b", size = 2241884 },
|
|
172
|
+
{ url = "https://files.pythonhosted.org/packages/0b/b0/249ee6d2646f1cdadcb813805fe76265745c4010cf20a8eba7b0e639d9b2/pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22", size = 1910496 },
|
|
173
|
+
{ url = "https://files.pythonhosted.org/packages/66/ff/172ba8f12a42d4b552917aa65d1f2328990d3ccfc01d5b7c943ec084299f/pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640", size = 1955019 },
|
|
174
|
+
{ url = "https://files.pythonhosted.org/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584 },
|
|
175
|
+
{ url = "https://files.pythonhosted.org/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071 },
|
|
176
|
+
{ url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823 },
|
|
177
|
+
{ url = "https://files.pythonhosted.org/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792 },
|
|
178
|
+
{ url = "https://files.pythonhosted.org/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338 },
|
|
179
|
+
{ url = "https://files.pythonhosted.org/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998 },
|
|
180
|
+
{ url = "https://files.pythonhosted.org/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200 },
|
|
181
|
+
{ url = "https://files.pythonhosted.org/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890 },
|
|
182
|
+
{ url = "https://files.pythonhosted.org/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359 },
|
|
183
|
+
{ url = "https://files.pythonhosted.org/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883 },
|
|
184
|
+
{ url = "https://files.pythonhosted.org/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074 },
|
|
185
|
+
{ url = "https://files.pythonhosted.org/packages/e0/ed/55532bb88f674d5d8f67ab121a2a13c385df382de2a1677f30ad385f7438/pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51", size = 1910538 },
|
|
186
|
+
{ url = "https://files.pythonhosted.org/packages/fe/1b/25b7cccd4519c0b23c2dd636ad39d381abf113085ce4f7bec2b0dc755eb1/pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab", size = 1952909 },
|
|
187
|
+
{ url = "https://files.pythonhosted.org/packages/49/a9/d809358e49126438055884c4366a1f6227f0f84f635a9014e2deb9b9de54/pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65", size = 1897786 },
|
|
188
|
+
{ url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000 },
|
|
189
|
+
{ url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996 },
|
|
190
|
+
{ url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957 },
|
|
191
|
+
{ url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199 },
|
|
192
|
+
{ url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296 },
|
|
193
|
+
{ url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109 },
|
|
194
|
+
{ url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028 },
|
|
195
|
+
{ url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044 },
|
|
196
|
+
{ url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881 },
|
|
197
|
+
{ url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034 },
|
|
198
|
+
{ url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187 },
|
|
199
|
+
{ url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628 },
|
|
200
|
+
{ url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866 },
|
|
201
|
+
{ url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894 },
|
|
202
|
+
{ url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688 },
|
|
203
|
+
{ url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808 },
|
|
204
|
+
{ url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580 },
|
|
205
|
+
{ url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859 },
|
|
206
|
+
{ url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810 },
|
|
207
|
+
{ url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498 },
|
|
208
|
+
{ url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611 },
|
|
209
|
+
{ url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924 },
|
|
210
|
+
{ url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196 },
|
|
211
|
+
{ url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389 },
|
|
212
|
+
{ url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223 },
|
|
213
|
+
{ url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473 },
|
|
214
|
+
{ url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269 },
|
|
215
|
+
{ url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921 },
|
|
216
|
+
{ url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162 },
|
|
217
|
+
{ url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560 },
|
|
218
|
+
{ url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777 },
|
|
219
|
+
{ url = "https://files.pythonhosted.org/packages/30/68/373d55e58b7e83ce371691f6eaa7175e3a24b956c44628eb25d7da007917/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa", size = 2023982 },
|
|
220
|
+
{ url = "https://files.pythonhosted.org/packages/a4/16/145f54ac08c96a63d8ed6442f9dec17b2773d19920b627b18d4f10a061ea/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29", size = 1858412 },
|
|
221
|
+
{ url = "https://files.pythonhosted.org/packages/41/b1/c6dc6c3e2de4516c0bb2c46f6a373b91b5660312342a0cf5826e38ad82fa/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d", size = 1892749 },
|
|
222
|
+
{ url = "https://files.pythonhosted.org/packages/12/73/8cd57e20afba760b21b742106f9dbdfa6697f1570b189c7457a1af4cd8a0/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e", size = 2067527 },
|
|
223
|
+
{ url = "https://files.pythonhosted.org/packages/e3/d5/0bb5d988cc019b3cba4a78f2d4b3854427fc47ee8ec8e9eaabf787da239c/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c", size = 2108225 },
|
|
224
|
+
{ url = "https://files.pythonhosted.org/packages/f1/c5/00c02d1571913d496aabf146106ad8239dc132485ee22efe08085084ff7c/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec", size = 2069490 },
|
|
225
|
+
{ url = "https://files.pythonhosted.org/packages/22/a8/dccc38768274d3ed3a59b5d06f59ccb845778687652daa71df0cab4040d7/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052", size = 2237525 },
|
|
226
|
+
{ url = "https://files.pythonhosted.org/packages/d4/e7/4f98c0b125dda7cf7ccd14ba936218397b44f50a56dd8c16a3091df116c3/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c", size = 2238446 },
|
|
227
|
+
{ url = "https://files.pythonhosted.org/packages/ce/91/2ec36480fdb0b783cd9ef6795753c1dea13882f2e68e73bce76ae8c21e6a/pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808", size = 2066678 },
|
|
228
|
+
{ url = "https://files.pythonhosted.org/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200 },
|
|
229
|
+
{ url = "https://files.pythonhosted.org/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123 },
|
|
230
|
+
{ url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852 },
|
|
231
|
+
{ url = "https://files.pythonhosted.org/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484 },
|
|
232
|
+
{ url = "https://files.pythonhosted.org/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896 },
|
|
233
|
+
{ url = "https://files.pythonhosted.org/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475 },
|
|
234
|
+
{ url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013 },
|
|
235
|
+
{ url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715 },
|
|
236
|
+
{ url = "https://files.pythonhosted.org/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757 },
|
|
237
|
+
]
|
|
238
|
+
|
|
239
|
+
[[package]]
|
|
240
|
+
name = "redis"
|
|
241
|
+
version = "6.2.0"
|
|
242
|
+
source = { registry = "https://pypi.org/simple" }
|
|
243
|
+
dependencies = [
|
|
244
|
+
{ name = "async-timeout", marker = "python_full_version < '3.11.3'" },
|
|
245
|
+
]
|
|
246
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ea/9a/0551e01ba52b944f97480721656578c8a7c46b51b99d66814f85fe3a4f3e/redis-6.2.0.tar.gz", hash = "sha256:e821f129b75dde6cb99dd35e5c76e8c49512a5a0d8dfdc560b2fbd44b85ca977", size = 4639129 }
|
|
247
|
+
wheels = [
|
|
248
|
+
{ url = "https://files.pythonhosted.org/packages/13/67/e60968d3b0e077495a8fee89cf3f2373db98e528288a48f1ee44967f6e8c/redis-6.2.0-py3-none-any.whl", hash = "sha256:c8ddf316ee0aab65f04a11229e94a64b2618451dab7a67cb2f77eb799d872d5e", size = 278659 },
|
|
249
|
+
]
|
|
250
|
+
|
|
251
|
+
[[package]]
|
|
252
|
+
name = "sniffio"
|
|
253
|
+
version = "1.3.1"
|
|
254
|
+
source = { registry = "https://pypi.org/simple" }
|
|
255
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
|
|
256
|
+
wheels = [
|
|
257
|
+
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
|
|
258
|
+
]
|
|
259
|
+
|
|
260
|
+
[[package]]
|
|
261
|
+
name = "starlette"
|
|
262
|
+
version = "0.46.2"
|
|
263
|
+
source = { registry = "https://pypi.org/simple" }
|
|
264
|
+
dependencies = [
|
|
265
|
+
{ name = "anyio" },
|
|
266
|
+
]
|
|
267
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846 }
|
|
268
|
+
wheels = [
|
|
269
|
+
{ url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037 },
|
|
270
|
+
]
|
|
271
|
+
|
|
272
|
+
[[package]]
|
|
273
|
+
name = "typing-extensions"
|
|
274
|
+
version = "4.14.0"
|
|
275
|
+
source = { registry = "https://pypi.org/simple" }
|
|
276
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423 }
|
|
277
|
+
wheels = [
|
|
278
|
+
{ url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839 },
|
|
279
|
+
]
|
|
280
|
+
|
|
281
|
+
[[package]]
|
|
282
|
+
name = "typing-inspection"
|
|
283
|
+
version = "0.4.1"
|
|
284
|
+
source = { registry = "https://pypi.org/simple" }
|
|
285
|
+
dependencies = [
|
|
286
|
+
{ name = "typing-extensions" },
|
|
287
|
+
]
|
|
288
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726 }
|
|
289
|
+
wheels = [
|
|
290
|
+
{ url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552 },
|
|
291
|
+
]
|