di-flask 0.1.4__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.
- di_flask-0.1.4/.github/workflows/build_and_publish.yml +62 -0
- di_flask-0.1.4/.gitignore +11 -0
- di_flask-0.1.4/.python-version +1 -0
- di_flask-0.1.4/CHANGELOG.md +8 -0
- di_flask-0.1.4/LICENSE +21 -0
- di_flask-0.1.4/PKG-INFO +115 -0
- di_flask-0.1.4/README.md +81 -0
- di_flask-0.1.4/pyproject.toml +30 -0
- di_flask-0.1.4/src/flask_di/__init__.py +4 -0
- di_flask-0.1.4/src/flask_di/core.py +114 -0
- di_flask-0.1.4/src/flask_di/dependency.py +20 -0
- di_flask-0.1.4/tests/test_basic.py +22 -0
- di_flask-0.1.4/uv.lock +254 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: Build and Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
name: Build wheels (Linux, macOS, Windows)
|
|
11
|
+
runs-on: ${{ matrix.os }}
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Install uv
|
|
22
|
+
uses: astral-sh/setup-uv@v2
|
|
23
|
+
|
|
24
|
+
- name: Set up Python
|
|
25
|
+
uses: actions/setup-python@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.12"
|
|
28
|
+
|
|
29
|
+
- name: Install build dependencies
|
|
30
|
+
run: uv sync
|
|
31
|
+
|
|
32
|
+
- name: Build wheel and sdist
|
|
33
|
+
run: uv build
|
|
34
|
+
|
|
35
|
+
- name: Upload artifacts
|
|
36
|
+
uses: actions/upload-artifact@v4
|
|
37
|
+
with:
|
|
38
|
+
name: dist-${{ matrix.os }}
|
|
39
|
+
path: dist/*
|
|
40
|
+
|
|
41
|
+
publish:
|
|
42
|
+
name: Publish to PyPI
|
|
43
|
+
needs: build
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
environment:
|
|
46
|
+
name: pypi
|
|
47
|
+
url: https://pypi.org/p/flask-di/
|
|
48
|
+
permissions:
|
|
49
|
+
id-token: write
|
|
50
|
+
contents: read
|
|
51
|
+
|
|
52
|
+
steps:
|
|
53
|
+
- uses: actions/download-artifact@v4
|
|
54
|
+
with:
|
|
55
|
+
path: dist
|
|
56
|
+
merge-multiple: true
|
|
57
|
+
|
|
58
|
+
- name: Publish to PyPI
|
|
59
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
60
|
+
with:
|
|
61
|
+
skip-existing: true
|
|
62
|
+
packages-dir: dist/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
di_flask-0.1.4/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 razorblade23
|
|
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.
|
di_flask-0.1.4/PKG-INFO
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: di-flask
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Summary: FastAPI-style dependency injection for Flask using Annotated and Python 3.12 features.
|
|
5
|
+
Project-URL: Homepage, https://github.com/razorblade23/di-flask
|
|
6
|
+
Project-URL: Issues, https://github.com/razorblade23/di-flask/issues
|
|
7
|
+
Author-email: razorblade23 <contact@razorblade23.dev>
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2025 razorblade23
|
|
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: annotated,dependency-injection,di,fastapi,flask
|
|
31
|
+
Requires-Python: >=3.12
|
|
32
|
+
Requires-Dist: flask>=2.3
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# Flask-DI
|
|
36
|
+
|
|
37
|
+
A minimal and clean FastAPI-style dependency injection system for Flask.
|
|
38
|
+
|
|
39
|
+
## Features
|
|
40
|
+
|
|
41
|
+
- FastAPI-style `Depends()`
|
|
42
|
+
- Automatic injection (no decorators required)
|
|
43
|
+
- Nested dependencies
|
|
44
|
+
- Override system for testing
|
|
45
|
+
- Per-request caching
|
|
46
|
+
- Pure Python and lightweight
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install flask-di
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Usage
|
|
55
|
+
> [!NOTE]
|
|
56
|
+
> For automatic injection of dependecies we need to wrap Flask class
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from flask_di import DIFlask, Depends
|
|
60
|
+
|
|
61
|
+
app = DIFlask(__name__)
|
|
62
|
+
|
|
63
|
+
def get_db():
|
|
64
|
+
return {"session": "db-session"}
|
|
65
|
+
|
|
66
|
+
def get_user(db=Depends(get_db)):
|
|
67
|
+
return {"username": "alice", "db": db}
|
|
68
|
+
|
|
69
|
+
@app.route("/info")
|
|
70
|
+
def info(user=Depends(get_user)):
|
|
71
|
+
return user
|
|
72
|
+
```
|
|
73
|
+
> [!TIP]
|
|
74
|
+
> Flask-DI also supports `Annotated` type alias for declaring dependecies just like FastAPI does.
|
|
75
|
+
>
|
|
76
|
+
> ```python
|
|
77
|
+
> from flask_di import DIFlask, Depends
|
|
78
|
+
> from typing import Annotated
|
|
79
|
+
>
|
|
80
|
+
> app = DIFlask(__name__)
|
|
81
|
+
>
|
|
82
|
+
> def get_db():
|
|
83
|
+
> return {"session": "db-session"}
|
|
84
|
+
>
|
|
85
|
+
> SessionDep = Annotated(dict, Depends(get_db))
|
|
86
|
+
>
|
|
87
|
+
> def get_user(session: SessionDep):
|
|
88
|
+
> return {"username": "alice", "session": session}
|
|
89
|
+
>
|
|
90
|
+
> UserDep = Annotated(dict, Depends(get_user))
|
|
91
|
+
>
|
|
92
|
+
> @app.route("/info")
|
|
93
|
+
> def info(user: UserDep):
|
|
94
|
+
> return user
|
|
95
|
+
> ```
|
|
96
|
+
|
|
97
|
+
## Overrides
|
|
98
|
+
Flask-DI supports overrides for easy mocking and testing of dependacies.
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
def override_db():
|
|
102
|
+
return {"session": "test-db"}
|
|
103
|
+
|
|
104
|
+
app.dependency_overrides[get_db] = override_db
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Disclaimer
|
|
108
|
+
This is my snippet of code that I use for my Flask project.
|
|
109
|
+
|
|
110
|
+
Just wanted to share as its dead simple, lightweight and pure python.
|
|
111
|
+
|
|
112
|
+
## Contribution
|
|
113
|
+
You are free to contribute to the project in any way you want.
|
|
114
|
+
|
|
115
|
+
The goal of the project is to be on-par with FastAPI DI style. Please keep it simple, concise and with clear code comments.
|
di_flask-0.1.4/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Flask-DI
|
|
2
|
+
|
|
3
|
+
A minimal and clean FastAPI-style dependency injection system for Flask.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- FastAPI-style `Depends()`
|
|
8
|
+
- Automatic injection (no decorators required)
|
|
9
|
+
- Nested dependencies
|
|
10
|
+
- Override system for testing
|
|
11
|
+
- Per-request caching
|
|
12
|
+
- Pure Python and lightweight
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install flask-di
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
> [!NOTE]
|
|
22
|
+
> For automatic injection of dependecies we need to wrap Flask class
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from flask_di import DIFlask, Depends
|
|
26
|
+
|
|
27
|
+
app = DIFlask(__name__)
|
|
28
|
+
|
|
29
|
+
def get_db():
|
|
30
|
+
return {"session": "db-session"}
|
|
31
|
+
|
|
32
|
+
def get_user(db=Depends(get_db)):
|
|
33
|
+
return {"username": "alice", "db": db}
|
|
34
|
+
|
|
35
|
+
@app.route("/info")
|
|
36
|
+
def info(user=Depends(get_user)):
|
|
37
|
+
return user
|
|
38
|
+
```
|
|
39
|
+
> [!TIP]
|
|
40
|
+
> Flask-DI also supports `Annotated` type alias for declaring dependecies just like FastAPI does.
|
|
41
|
+
>
|
|
42
|
+
> ```python
|
|
43
|
+
> from flask_di import DIFlask, Depends
|
|
44
|
+
> from typing import Annotated
|
|
45
|
+
>
|
|
46
|
+
> app = DIFlask(__name__)
|
|
47
|
+
>
|
|
48
|
+
> def get_db():
|
|
49
|
+
> return {"session": "db-session"}
|
|
50
|
+
>
|
|
51
|
+
> SessionDep = Annotated(dict, Depends(get_db))
|
|
52
|
+
>
|
|
53
|
+
> def get_user(session: SessionDep):
|
|
54
|
+
> return {"username": "alice", "session": session}
|
|
55
|
+
>
|
|
56
|
+
> UserDep = Annotated(dict, Depends(get_user))
|
|
57
|
+
>
|
|
58
|
+
> @app.route("/info")
|
|
59
|
+
> def info(user: UserDep):
|
|
60
|
+
> return user
|
|
61
|
+
> ```
|
|
62
|
+
|
|
63
|
+
## Overrides
|
|
64
|
+
Flask-DI supports overrides for easy mocking and testing of dependacies.
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
def override_db():
|
|
68
|
+
return {"session": "test-db"}
|
|
69
|
+
|
|
70
|
+
app.dependency_overrides[get_db] = override_db
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Disclaimer
|
|
74
|
+
This is my snippet of code that I use for my Flask project.
|
|
75
|
+
|
|
76
|
+
Just wanted to share as its dead simple, lightweight and pure python.
|
|
77
|
+
|
|
78
|
+
## Contribution
|
|
79
|
+
You are free to contribute to the project in any way you want.
|
|
80
|
+
|
|
81
|
+
The goal of the project is to be on-par with FastAPI DI style. Please keep it simple, concise and with clear code comments.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "di-flask"
|
|
3
|
+
version = "0.1.4"
|
|
4
|
+
description = "FastAPI-style dependency injection for Flask using Annotated and Python 3.12 features."
|
|
5
|
+
authors = [{ name = "razorblade23", email = "contact@razorblade23.dev" }]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
license = { file = "LICENSE" }
|
|
8
|
+
requires-python = ">=3.12"
|
|
9
|
+
keywords = ["flask", "dependency-injection", "fastapi", "annotated", "di"]
|
|
10
|
+
|
|
11
|
+
dependencies = [
|
|
12
|
+
"flask>=2.3"
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[project.urls]
|
|
16
|
+
Homepage = "https://github.com/razorblade23/di-flask"
|
|
17
|
+
Issues = "https://github.com/razorblade23/di-flask/issues"
|
|
18
|
+
|
|
19
|
+
[build-system]
|
|
20
|
+
requires = ["hatchling"]
|
|
21
|
+
build-backend = "hatchling.build"
|
|
22
|
+
|
|
23
|
+
[tool.hatch.build.targets.wheel]
|
|
24
|
+
packages = ["src/flask_di"]
|
|
25
|
+
|
|
26
|
+
[dependency-groups]
|
|
27
|
+
dev = [
|
|
28
|
+
"hatchling>=1.28.0",
|
|
29
|
+
"pytest>=9.0.1",
|
|
30
|
+
]
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
from typing import Annotated, get_args, get_origin, get_type_hints
|
|
3
|
+
|
|
4
|
+
from flask import Flask, g
|
|
5
|
+
|
|
6
|
+
from flask_di.dependency import Depends
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DIFlask(Flask):
|
|
10
|
+
"""
|
|
11
|
+
Flask subclass that provides FastAPI-style dependency injection using Annotated.
|
|
12
|
+
|
|
13
|
+
Supports:
|
|
14
|
+
- Annotated[T, Depends(...)]
|
|
15
|
+
- Nested dependencies
|
|
16
|
+
- Override system
|
|
17
|
+
- Per-request caching
|
|
18
|
+
- Type-alias dependencies like:
|
|
19
|
+
BackendAPIDep = Annotated[BackendAPI, Depends(get_backend_api)]
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, *args, **kwargs):
|
|
23
|
+
super().__init__(*args, **kwargs)
|
|
24
|
+
self.dependency_overrides = {}
|
|
25
|
+
|
|
26
|
+
# -------------------------------------------------------------------------
|
|
27
|
+
# Wrap view functions so DI happens automatically
|
|
28
|
+
# -------------------------------------------------------------------------
|
|
29
|
+
def add_url_rule(self, rule, *args, **kwargs):
|
|
30
|
+
# Keyword "view_func"
|
|
31
|
+
if "view_func" in kwargs and kwargs["view_func"]:
|
|
32
|
+
kwargs["view_func"] = self._wrap_view(kwargs["view_func"])
|
|
33
|
+
|
|
34
|
+
# Positional view_func (args[1])
|
|
35
|
+
if len(args) >= 2 and args[1]:
|
|
36
|
+
args = list(args)
|
|
37
|
+
args[1] = self._wrap_view(args[1])
|
|
38
|
+
return super().add_url_rule(rule, *args, **kwargs)
|
|
39
|
+
|
|
40
|
+
return super().add_url_rule(rule, *args, **kwargs)
|
|
41
|
+
|
|
42
|
+
# -------------------------------------------------------------------------
|
|
43
|
+
# Build wrapper that injects Annotated dependencies
|
|
44
|
+
# -------------------------------------------------------------------------
|
|
45
|
+
def _wrap_view(self, view_func):
|
|
46
|
+
sig = inspect.signature(view_func)
|
|
47
|
+
type_hints = get_type_hints(view_func, include_extras=True)
|
|
48
|
+
|
|
49
|
+
dependency_map = self._extract_dependencies(sig, type_hints)
|
|
50
|
+
|
|
51
|
+
def wrapper(*args, **kwargs):
|
|
52
|
+
injected = {}
|
|
53
|
+
|
|
54
|
+
for param_name, depends_obj in dependency_map.items():
|
|
55
|
+
injected[param_name] = self._resolve_dependency(depends_obj)
|
|
56
|
+
|
|
57
|
+
return view_func(*args, **injected, **kwargs)
|
|
58
|
+
|
|
59
|
+
wrapper.__name__ = view_func.__name__
|
|
60
|
+
wrapper.__doc__ = view_func.__doc__
|
|
61
|
+
return wrapper
|
|
62
|
+
|
|
63
|
+
# -------------------------------------------------------------------------
|
|
64
|
+
# Parse Annotated parameters and extract Depends objects
|
|
65
|
+
# -------------------------------------------------------------------------
|
|
66
|
+
def _extract_dependencies(self, sig, type_hints):
|
|
67
|
+
dependency_map = {}
|
|
68
|
+
|
|
69
|
+
for name, param in sig.parameters.items():
|
|
70
|
+
annotation = type_hints.get(name)
|
|
71
|
+
|
|
72
|
+
# Must be Annotated[T, metadata...]
|
|
73
|
+
if get_origin(annotation) is Annotated:
|
|
74
|
+
ann_type, *metadata = get_args(annotation)
|
|
75
|
+
depends_obj = next(
|
|
76
|
+
(m for m in metadata if isinstance(m, Depends)), None
|
|
77
|
+
)
|
|
78
|
+
if depends_obj:
|
|
79
|
+
dependency_map[name] = depends_obj
|
|
80
|
+
|
|
81
|
+
return dependency_map
|
|
82
|
+
|
|
83
|
+
# -------------------------------------------------------------------------
|
|
84
|
+
# Resolve a dependency function
|
|
85
|
+
# -------------------------------------------------------------------------
|
|
86
|
+
def _resolve_dependency(self, depends_obj: Depends):
|
|
87
|
+
dep_func = depends_obj.dependency
|
|
88
|
+
|
|
89
|
+
# Apply override if present
|
|
90
|
+
if dep_func in self.dependency_overrides:
|
|
91
|
+
dep_func = self.dependency_overrides[dep_func]
|
|
92
|
+
|
|
93
|
+
# Request-scoped caching
|
|
94
|
+
cache_key = f"_dep_{dep_func.__name__}" # type: ignore
|
|
95
|
+
if hasattr(g, cache_key):
|
|
96
|
+
return getattr(g, cache_key)
|
|
97
|
+
|
|
98
|
+
# Collect nested dependencies
|
|
99
|
+
sig = inspect.signature(dep_func) # type: ignore
|
|
100
|
+
type_hints = get_type_hints(dep_func, include_extras=True)
|
|
101
|
+
|
|
102
|
+
kwargs = {}
|
|
103
|
+
dependency_map = self._extract_dependencies(sig, type_hints)
|
|
104
|
+
|
|
105
|
+
for name, nested_dep in dependency_map.items():
|
|
106
|
+
kwargs[name] = self._resolve_dependency(nested_dep)
|
|
107
|
+
|
|
108
|
+
# Execute dependency factory
|
|
109
|
+
value = dep_func(**kwargs) # type: ignore
|
|
110
|
+
|
|
111
|
+
# Cache result
|
|
112
|
+
setattr(g, cache_key, value)
|
|
113
|
+
|
|
114
|
+
return value
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from typing import Callable, Optional
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Depends[T]:
|
|
5
|
+
def __init__(
|
|
6
|
+
self,
|
|
7
|
+
dependency: Optional[Callable] = None,
|
|
8
|
+
return_type: Optional[type] = None,
|
|
9
|
+
):
|
|
10
|
+
self.dependency = dependency
|
|
11
|
+
self.return_type = return_type
|
|
12
|
+
|
|
13
|
+
def __class_getitem__(cls, return_type: type):
|
|
14
|
+
# Enables Depends[T]
|
|
15
|
+
return cls(dependency=None, return_type=return_type)
|
|
16
|
+
|
|
17
|
+
def __call__(self, dependency: Callable):
|
|
18
|
+
# Enables Depends[T](func)
|
|
19
|
+
self.dependency = dependency
|
|
20
|
+
return self
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
3
|
+
from flask_di import Depends, DIFlask
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def dep1():
|
|
7
|
+
return 42
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
IntDep = Annotated[int, Depends(dep1)]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_basic_injection():
|
|
14
|
+
app = DIFlask(__name__)
|
|
15
|
+
|
|
16
|
+
@app.route("/test")
|
|
17
|
+
def test_route(v: IntDep):
|
|
18
|
+
return str(v)
|
|
19
|
+
|
|
20
|
+
client = app.test_client()
|
|
21
|
+
resp = client.get("/test")
|
|
22
|
+
assert resp.data == b"42"
|
di_flask-0.1.4/uv.lock
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
version = 1
|
|
2
|
+
revision = 3
|
|
3
|
+
requires-python = ">=3.12"
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "blinker"
|
|
7
|
+
version = "1.9.0"
|
|
8
|
+
source = { registry = "https://pypi.org/simple" }
|
|
9
|
+
sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" }
|
|
10
|
+
wheels = [
|
|
11
|
+
{ url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" },
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[[package]]
|
|
15
|
+
name = "click"
|
|
16
|
+
version = "8.3.1"
|
|
17
|
+
source = { registry = "https://pypi.org/simple" }
|
|
18
|
+
dependencies = [
|
|
19
|
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
20
|
+
]
|
|
21
|
+
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
|
|
22
|
+
wheels = [
|
|
23
|
+
{ url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[[package]]
|
|
27
|
+
name = "colorama"
|
|
28
|
+
version = "0.4.6"
|
|
29
|
+
source = { registry = "https://pypi.org/simple" }
|
|
30
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
|
31
|
+
wheels = [
|
|
32
|
+
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[[package]]
|
|
36
|
+
name = "di-flask"
|
|
37
|
+
version = "0.1.4"
|
|
38
|
+
source = { editable = "." }
|
|
39
|
+
dependencies = [
|
|
40
|
+
{ name = "flask" },
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[package.dev-dependencies]
|
|
44
|
+
dev = [
|
|
45
|
+
{ name = "hatchling" },
|
|
46
|
+
{ name = "pytest" },
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
[package.metadata]
|
|
50
|
+
requires-dist = [{ name = "flask", specifier = ">=2.3" }]
|
|
51
|
+
|
|
52
|
+
[package.metadata.requires-dev]
|
|
53
|
+
dev = [
|
|
54
|
+
{ name = "hatchling", specifier = ">=1.28.0" },
|
|
55
|
+
{ name = "pytest", specifier = ">=9.0.1" },
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[[package]]
|
|
59
|
+
name = "flask"
|
|
60
|
+
version = "3.1.2"
|
|
61
|
+
source = { registry = "https://pypi.org/simple" }
|
|
62
|
+
dependencies = [
|
|
63
|
+
{ name = "blinker" },
|
|
64
|
+
{ name = "click" },
|
|
65
|
+
{ name = "itsdangerous" },
|
|
66
|
+
{ name = "jinja2" },
|
|
67
|
+
{ name = "markupsafe" },
|
|
68
|
+
{ name = "werkzeug" },
|
|
69
|
+
]
|
|
70
|
+
sdist = { url = "https://files.pythonhosted.org/packages/dc/6d/cfe3c0fcc5e477df242b98bfe186a4c34357b4847e87ecaef04507332dab/flask-3.1.2.tar.gz", hash = "sha256:bf656c15c80190ed628ad08cdfd3aaa35beb087855e2f494910aa3774cc4fd87", size = 720160, upload-time = "2025-08-19T21:03:21.205Z" }
|
|
71
|
+
wheels = [
|
|
72
|
+
{ url = "https://files.pythonhosted.org/packages/ec/f9/7f9263c5695f4bd0023734af91bedb2ff8209e8de6ead162f35d8dc762fd/flask-3.1.2-py3-none-any.whl", hash = "sha256:ca1d8112ec8a6158cc29ea4858963350011b5c846a414cdb7a954aa9e967d03c", size = 103308, upload-time = "2025-08-19T21:03:19.499Z" },
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
[[package]]
|
|
76
|
+
name = "hatchling"
|
|
77
|
+
version = "1.28.0"
|
|
78
|
+
source = { registry = "https://pypi.org/simple" }
|
|
79
|
+
dependencies = [
|
|
80
|
+
{ name = "packaging" },
|
|
81
|
+
{ name = "pathspec" },
|
|
82
|
+
{ name = "pluggy" },
|
|
83
|
+
{ name = "trove-classifiers" },
|
|
84
|
+
]
|
|
85
|
+
sdist = { url = "https://files.pythonhosted.org/packages/0b/8e/e480359492affde4119a131da729dd26da742c2c9b604dff74836e47eef9/hatchling-1.28.0.tar.gz", hash = "sha256:4d50b02aece6892b8cd0b3ce6c82cb218594d3ec5836dbde75bf41a21ab004c8", size = 55365, upload-time = "2025-11-27T00:31:13.766Z" }
|
|
86
|
+
wheels = [
|
|
87
|
+
{ url = "https://files.pythonhosted.org/packages/0d/a5/48cb7efb8b4718b1a4c0c331e3364a3a33f614ff0d6afd2b93ee883d3c47/hatchling-1.28.0-py3-none-any.whl", hash = "sha256:dc48722b68b3f4bbfa3ff618ca07cdea6750e7d03481289ffa8be1521d18a961", size = 76075, upload-time = "2025-11-27T00:31:12.544Z" },
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
[[package]]
|
|
91
|
+
name = "iniconfig"
|
|
92
|
+
version = "2.3.0"
|
|
93
|
+
source = { registry = "https://pypi.org/simple" }
|
|
94
|
+
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
|
|
95
|
+
wheels = [
|
|
96
|
+
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
[[package]]
|
|
100
|
+
name = "itsdangerous"
|
|
101
|
+
version = "2.2.0"
|
|
102
|
+
source = { registry = "https://pypi.org/simple" }
|
|
103
|
+
sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" }
|
|
104
|
+
wheels = [
|
|
105
|
+
{ url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" },
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
[[package]]
|
|
109
|
+
name = "jinja2"
|
|
110
|
+
version = "3.1.6"
|
|
111
|
+
source = { registry = "https://pypi.org/simple" }
|
|
112
|
+
dependencies = [
|
|
113
|
+
{ name = "markupsafe" },
|
|
114
|
+
]
|
|
115
|
+
sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" }
|
|
116
|
+
wheels = [
|
|
117
|
+
{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
[[package]]
|
|
121
|
+
name = "markupsafe"
|
|
122
|
+
version = "3.0.3"
|
|
123
|
+
source = { registry = "https://pypi.org/simple" }
|
|
124
|
+
sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" }
|
|
125
|
+
wheels = [
|
|
126
|
+
{ url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" },
|
|
127
|
+
{ url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" },
|
|
128
|
+
{ url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" },
|
|
129
|
+
{ url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" },
|
|
130
|
+
{ url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" },
|
|
131
|
+
{ url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" },
|
|
132
|
+
{ url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" },
|
|
133
|
+
{ url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" },
|
|
134
|
+
{ url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" },
|
|
135
|
+
{ url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" },
|
|
136
|
+
{ url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" },
|
|
137
|
+
{ url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" },
|
|
138
|
+
{ url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" },
|
|
139
|
+
{ url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" },
|
|
140
|
+
{ url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" },
|
|
141
|
+
{ url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" },
|
|
142
|
+
{ url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" },
|
|
143
|
+
{ url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" },
|
|
144
|
+
{ url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" },
|
|
145
|
+
{ url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" },
|
|
146
|
+
{ url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" },
|
|
147
|
+
{ url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" },
|
|
148
|
+
{ url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" },
|
|
149
|
+
{ url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" },
|
|
150
|
+
{ url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" },
|
|
151
|
+
{ url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" },
|
|
152
|
+
{ url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" },
|
|
153
|
+
{ url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" },
|
|
154
|
+
{ url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" },
|
|
155
|
+
{ url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" },
|
|
156
|
+
{ url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" },
|
|
157
|
+
{ url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" },
|
|
158
|
+
{ url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" },
|
|
159
|
+
{ url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" },
|
|
160
|
+
{ url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" },
|
|
161
|
+
{ url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" },
|
|
162
|
+
{ url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" },
|
|
163
|
+
{ url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" },
|
|
164
|
+
{ url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" },
|
|
165
|
+
{ url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" },
|
|
166
|
+
{ url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" },
|
|
167
|
+
{ url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" },
|
|
168
|
+
{ url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" },
|
|
169
|
+
{ url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" },
|
|
170
|
+
{ url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" },
|
|
171
|
+
{ url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" },
|
|
172
|
+
{ url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" },
|
|
173
|
+
{ url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" },
|
|
174
|
+
{ url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" },
|
|
175
|
+
{ url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" },
|
|
176
|
+
{ url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" },
|
|
177
|
+
{ url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" },
|
|
178
|
+
{ url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" },
|
|
179
|
+
{ url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" },
|
|
180
|
+
{ url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" },
|
|
181
|
+
]
|
|
182
|
+
|
|
183
|
+
[[package]]
|
|
184
|
+
name = "packaging"
|
|
185
|
+
version = "25.0"
|
|
186
|
+
source = { registry = "https://pypi.org/simple" }
|
|
187
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
|
|
188
|
+
wheels = [
|
|
189
|
+
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
|
|
190
|
+
]
|
|
191
|
+
|
|
192
|
+
[[package]]
|
|
193
|
+
name = "pathspec"
|
|
194
|
+
version = "0.12.1"
|
|
195
|
+
source = { registry = "https://pypi.org/simple" }
|
|
196
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" }
|
|
197
|
+
wheels = [
|
|
198
|
+
{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" },
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
[[package]]
|
|
202
|
+
name = "pluggy"
|
|
203
|
+
version = "1.6.0"
|
|
204
|
+
source = { registry = "https://pypi.org/simple" }
|
|
205
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
|
|
206
|
+
wheels = [
|
|
207
|
+
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
|
208
|
+
]
|
|
209
|
+
|
|
210
|
+
[[package]]
|
|
211
|
+
name = "pygments"
|
|
212
|
+
version = "2.19.2"
|
|
213
|
+
source = { registry = "https://pypi.org/simple" }
|
|
214
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
|
|
215
|
+
wheels = [
|
|
216
|
+
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
|
217
|
+
]
|
|
218
|
+
|
|
219
|
+
[[package]]
|
|
220
|
+
name = "pytest"
|
|
221
|
+
version = "9.0.1"
|
|
222
|
+
source = { registry = "https://pypi.org/simple" }
|
|
223
|
+
dependencies = [
|
|
224
|
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
225
|
+
{ name = "iniconfig" },
|
|
226
|
+
{ name = "packaging" },
|
|
227
|
+
{ name = "pluggy" },
|
|
228
|
+
{ name = "pygments" },
|
|
229
|
+
]
|
|
230
|
+
sdist = { url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size = 1564125, upload-time = "2025-11-12T13:05:09.333Z" }
|
|
231
|
+
wheels = [
|
|
232
|
+
{ url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size = 373668, upload-time = "2025-11-12T13:05:07.379Z" },
|
|
233
|
+
]
|
|
234
|
+
|
|
235
|
+
[[package]]
|
|
236
|
+
name = "trove-classifiers"
|
|
237
|
+
version = "2025.11.14.15"
|
|
238
|
+
source = { registry = "https://pypi.org/simple" }
|
|
239
|
+
sdist = { url = "https://files.pythonhosted.org/packages/bf/a9/880cccf76af9e7b322112f52e4e2dbb3534cbe671197b8f443a42189dfc7/trove_classifiers-2025.11.14.15.tar.gz", hash = "sha256:6b60f49d40bbd895bc61d8dc414fc2f2286d70eb72ed23548db8cf94f62804ca", size = 16995, upload-time = "2025-11-14T15:23:13.78Z" }
|
|
240
|
+
wheels = [
|
|
241
|
+
{ url = "https://files.pythonhosted.org/packages/49/f6/73c4aa003d1237ee9bea8a46f49dc38c45dfe95af4f0da7e60678d388011/trove_classifiers-2025.11.14.15-py3-none-any.whl", hash = "sha256:d1dac259c1e908939862e3331177931c6df0a37af2c1a8debcc603d9115fcdd9", size = 14191, upload-time = "2025-11-14T15:23:12.467Z" },
|
|
242
|
+
]
|
|
243
|
+
|
|
244
|
+
[[package]]
|
|
245
|
+
name = "werkzeug"
|
|
246
|
+
version = "3.1.4"
|
|
247
|
+
source = { registry = "https://pypi.org/simple" }
|
|
248
|
+
dependencies = [
|
|
249
|
+
{ name = "markupsafe" },
|
|
250
|
+
]
|
|
251
|
+
sdist = { url = "https://files.pythonhosted.org/packages/45/ea/b0f8eeb287f8df9066e56e831c7824ac6bab645dd6c7a8f4b2d767944f9b/werkzeug-3.1.4.tar.gz", hash = "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e", size = 864687, upload-time = "2025-11-29T02:15:22.841Z" }
|
|
252
|
+
wheels = [
|
|
253
|
+
{ url = "https://files.pythonhosted.org/packages/2f/f9/9e082990c2585c744734f85bec79b5dae5df9c974ffee58fe421652c8e91/werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905", size = 224960, upload-time = "2025-11-29T02:15:21.13Z" },
|
|
254
|
+
]
|