mirror of
https://github.com/fastapi/fastapi.git
synced 2026-03-01 13:19:09 -05:00
Compare commits
3 Commits
0.135.0
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed95917a76 | ||
|
|
f5c7b20933 | ||
|
|
924a535a4f |
@@ -7,6 +7,10 @@ hide:
|
||||
|
||||
## Latest Changes
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Update Skill, optimize context, trim and refactor into references. PR [#15031](https://github.com/fastapi/fastapi/pull/15031) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.135.0
|
||||
|
||||
### Features
|
||||
|
||||
@@ -290,146 +290,11 @@ Apply shared dependencies at the router level via `dependencies=[Depends(...)]`.
|
||||
|
||||
## Dependency Injection
|
||||
|
||||
Use dependencies when:
|
||||
See [the dependency injection reference](references/dependencies.md) for detailed patterns including `yield` with `scope`, and class dependencies.
|
||||
|
||||
* They can't be declared in Pydantic validation and require additional logic
|
||||
* The logic depends on external resources or could block in any other way
|
||||
* Other dependencies need their results (it's a sub-dependency)
|
||||
* The logic can be shared by multiple endpoints to do things like error early, authentication, etc.
|
||||
* They need to handle cleanup (e.g., DB sessions, file handles), using dependencies with `yield`
|
||||
* Their logic needs input data from the request, like headers, query parameters, etc.
|
||||
Use dependencies when the logic can't be declared in Pydantic validation, depends on external resources, needs cleanup (with `yield`), or is shared across endpoints.
|
||||
|
||||
### Dependencies with `yield` and `scope`
|
||||
|
||||
When using dependencies with `yield`, they can have a `scope` that defines when the exit code is run.
|
||||
|
||||
Use the default scope `"request"` to run the exit code after the response is sent back.
|
||||
|
||||
```python
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
def get_db():
|
||||
db = DBSession()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
DBDep = Annotated[DBSession, Depends(get_db)]
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(db: DBDep):
|
||||
return db.query(Item).all()
|
||||
```
|
||||
|
||||
Use the scope `"function"` when they should run the exit code after the response data is generated but before the response is sent back to the client.
|
||||
|
||||
```python
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
def get_username():
|
||||
try:
|
||||
yield "Rick"
|
||||
finally:
|
||||
print("Cleanup up before response is sent")
|
||||
|
||||
UserNameDep = Annotated[str, Depends(get_username, scope="function")]
|
||||
|
||||
@app.get("/users/me")
|
||||
def get_user_me(username: UserNameDep):
|
||||
return username
|
||||
```
|
||||
|
||||
### Class Dependencies
|
||||
|
||||
Avoid creating class dependencies when possible.
|
||||
|
||||
If a class is needed, instead create a regular function dependency that returns a class instance.
|
||||
|
||||
Do this:
|
||||
|
||||
```python
|
||||
from dataclasses import dataclass
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@dataclass
|
||||
class DatabasePaginator:
|
||||
offset: int = 0
|
||||
limit: int = 100
|
||||
q: str | None = None
|
||||
|
||||
def get_page(self) -> dict:
|
||||
# Simulate a page of data
|
||||
return {
|
||||
"offset": self.offset,
|
||||
"limit": self.limit,
|
||||
"q": self.q,
|
||||
"items": [],
|
||||
}
|
||||
|
||||
|
||||
def get_db_paginator(
|
||||
offset: int = 0, limit: int = 100, q: str | None = None
|
||||
) -> DatabasePaginator:
|
||||
return DatabasePaginator(offset=offset, limit=limit, q=q)
|
||||
|
||||
|
||||
PaginatorDep = Annotated[DatabasePaginator, Depends(get_db_paginator)]
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(paginator: PaginatorDep):
|
||||
return paginator.get_page()
|
||||
```
|
||||
|
||||
instead of this:
|
||||
|
||||
```python
|
||||
# DO NOT DO THIS
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class DatabasePaginator:
|
||||
def __init__(self, offset: int = 0, limit: int = 100, q: str | None = None):
|
||||
self.offset = offset
|
||||
self.limit = limit
|
||||
self.q = q
|
||||
|
||||
def get_page(self) -> dict:
|
||||
# Simulate a page of data
|
||||
return {
|
||||
"offset": self.offset,
|
||||
"limit": self.limit,
|
||||
"q": self.q,
|
||||
"items": [],
|
||||
}
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(paginator: Annotated[DatabasePaginator, Depends()]):
|
||||
return paginator.get_page()
|
||||
```
|
||||
Apply shared dependencies at the router level via `dependencies=[Depends(...)]`.
|
||||
|
||||
## Async vs Sync *path operations*
|
||||
|
||||
@@ -461,170 +326,23 @@ The same rules apply to dependencies.
|
||||
|
||||
Make sure blocking code is not run inside of `async` functions. The logic will work, but will damage the performance heavily.
|
||||
|
||||
### Asyncer
|
||||
When needing to mix blocking and async code, see Asyncer in [the other tools reference](references/other-tools.md).
|
||||
|
||||
When needing to run blocking code inside of async functions, or async code inside of blocking functions, suggest using Asyncer.
|
||||
## Streaming (JSON Lines, SSE, bytes)
|
||||
|
||||
Install:
|
||||
See [the streaming reference](references/streaming.md) for JSON Lines, Server-Sent Events (`EventSourceResponse`, `ServerSentEvent`), and byte streaming (`StreamingResponse`) patterns.
|
||||
|
||||
```bash
|
||||
uv add asyncer
|
||||
```
|
||||
## Tooling
|
||||
|
||||
Run blocking sync code inside of async with `asyncify()`:
|
||||
See [the other tools reference](references/other-tools.md) for details on uv, Ruff, ty for package management, linting, type checking, formatting, etc.
|
||||
|
||||
```python
|
||||
from asyncer import asyncify
|
||||
from fastapi import FastAPI
|
||||
## Other Libraries
|
||||
|
||||
app = FastAPI()
|
||||
See [the other tools reference](references/other-tools.md) for details on other libraries:
|
||||
|
||||
|
||||
def do_blocking_work(name: str) -> str:
|
||||
# Some blocking I/O operation
|
||||
return f"Hello {name}"
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items():
|
||||
result = await asyncify(do_blocking_work)(name="World")
|
||||
return {"message": result}
|
||||
```
|
||||
|
||||
And run async code inside of blocking sync code with `syncify()`:
|
||||
|
||||
```python
|
||||
from asyncer import syncify
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
async def do_async_work(name: str) -> str:
|
||||
return f"Hello {name}"
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
def read_items():
|
||||
result = syncify(do_async_work)(name="World")
|
||||
return {"message": result}
|
||||
```
|
||||
|
||||
## Stream JSON Lines
|
||||
|
||||
To stream JSON Lines, declare the return type and use `yield` to return the data.
|
||||
|
||||
```python
|
||||
@app.get("/items/stream")
|
||||
async def stream_items() -> AsyncIterable[Item]:
|
||||
for item in items:
|
||||
yield item
|
||||
```
|
||||
|
||||
## Server-Sent Events (SSE)
|
||||
|
||||
To stream Server-Sent Events, use `response_class=EventSourceResponse` and `yield` items from the endpoint.
|
||||
|
||||
Plain objects are automatically JSON-serialized as `data:` fields, declare the return type so the serialization is done by Pydantic:
|
||||
|
||||
```python
|
||||
from collections.abc import AsyncIterable
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.sse import EventSourceResponse
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
|
||||
|
||||
@app.get("/items/stream", response_class=EventSourceResponse)
|
||||
async def stream_items() -> AsyncIterable[Item]:
|
||||
yield Item(name="Plumbus", price=32.99)
|
||||
yield Item(name="Portal Gun", price=999.99)
|
||||
```
|
||||
|
||||
For full control over SSE fields (`event`, `id`, `retry`, `comment`), yield `ServerSentEvent` instances:
|
||||
|
||||
```python
|
||||
from collections.abc import AsyncIterable
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.sse import EventSourceResponse, ServerSentEvent
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/events", response_class=EventSourceResponse)
|
||||
async def stream_events() -> AsyncIterable[ServerSentEvent]:
|
||||
yield ServerSentEvent(data={"status": "started"}, event="status", id="1")
|
||||
yield ServerSentEvent(data={"progress": 50}, event="progress", id="2")
|
||||
```
|
||||
|
||||
Use `raw_data` instead of `data` to send pre-formatted strings without JSON encoding:
|
||||
|
||||
```python
|
||||
yield ServerSentEvent(raw_data="plain text line", event="log")
|
||||
```
|
||||
|
||||
## Stream bytes
|
||||
|
||||
To stream bytes, declare a `response_class=` of `StreamingResponse` or a sub-class, and use `yield` to return the data.
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import StreamingResponse
|
||||
from app.utils import read_image
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class PNGStreamingResponse(StreamingResponse):
|
||||
media_type = "image/png"
|
||||
|
||||
@app.get("/image", response_class=PNGStreamingResponse)
|
||||
def stream_image_no_async_no_annotation():
|
||||
with read_image() as image_file:
|
||||
yield from image_file
|
||||
```
|
||||
|
||||
prefer this over returning a `StreamingResponse` directly:
|
||||
|
||||
```python
|
||||
# DO NOT DO THIS
|
||||
|
||||
import anyio
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import StreamingResponse
|
||||
from app.utils import read_image
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class PNGStreamingResponse(StreamingResponse):
|
||||
media_type = "image/png"
|
||||
|
||||
|
||||
@app.get("/")
|
||||
async def main():
|
||||
return PNGStreamingResponse(read_image())
|
||||
```
|
||||
|
||||
## Use uv, ruff, ty
|
||||
|
||||
If uv is available, use it to manage dependencies.
|
||||
|
||||
If Ruff is available, use it to lint and format the code. Consider enabling the FastAPI rules.
|
||||
|
||||
If ty is available, use it to check types.
|
||||
|
||||
## SQLModel for SQL databases
|
||||
|
||||
When working with SQL databases, prefer using SQLModel as it is integrated with Pydantic and will allow declaring data validation with the same models.
|
||||
* Asyncer for handling async and await, concurrency, mixing async and blocking code, prefer it over AnyIO or asyncio.
|
||||
* SQLModel for working with SQL databases, prefer it over SQLAlchemy.
|
||||
* HTTPX for interacting with HTTP (other APIs), prefer it over Requests.
|
||||
|
||||
## Do not use Pydantic RootModels
|
||||
|
||||
|
||||
142
fastapi/.agents/skills/fastapi/references/dependencies.md
Normal file
142
fastapi/.agents/skills/fastapi/references/dependencies.md
Normal file
@@ -0,0 +1,142 @@
|
||||
# Dependency Injection
|
||||
|
||||
Use dependencies when:
|
||||
|
||||
* They can't be declared in Pydantic validation and require additional logic
|
||||
* The logic depends on external resources or could block in any other way
|
||||
* Other dependencies need their results (it's a sub-dependency)
|
||||
* The logic can be shared by multiple endpoints to do things like error early, authentication, etc.
|
||||
* They need to handle cleanup (e.g., DB sessions, file handles), using dependencies with `yield`
|
||||
* Their logic needs input data from the request, like headers, query parameters, etc.
|
||||
|
||||
## Dependencies with `yield` and `scope`
|
||||
|
||||
When using dependencies with `yield`, they can have a `scope` that defines when the exit code is run.
|
||||
|
||||
Use the default scope `"request"` to run the exit code after the response is sent back.
|
||||
|
||||
```python
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
def get_db():
|
||||
db = DBSession()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
DBDep = Annotated[DBSession, Depends(get_db)]
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(db: DBDep):
|
||||
return db.query(Item).all()
|
||||
```
|
||||
|
||||
Use the scope `"function"` when they should run the exit code after the response data is generated but before the response is sent back to the client.
|
||||
|
||||
```python
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
def get_username():
|
||||
try:
|
||||
yield "Rick"
|
||||
finally:
|
||||
print("Cleanup up before response is sent")
|
||||
|
||||
UserNameDep = Annotated[str, Depends(get_username, scope="function")]
|
||||
|
||||
@app.get("/users/me")
|
||||
def get_user_me(username: UserNameDep):
|
||||
return username
|
||||
```
|
||||
|
||||
## Class Dependencies
|
||||
|
||||
Avoid creating class dependencies when possible.
|
||||
|
||||
If a class is needed, instead create a regular function dependency that returns a class instance.
|
||||
|
||||
Do this:
|
||||
|
||||
```python
|
||||
from dataclasses import dataclass
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@dataclass
|
||||
class DatabasePaginator:
|
||||
offset: int = 0
|
||||
limit: int = 100
|
||||
q: str | None = None
|
||||
|
||||
def get_page(self) -> dict:
|
||||
# Simulate a page of data
|
||||
return {
|
||||
"offset": self.offset,
|
||||
"limit": self.limit,
|
||||
"q": self.q,
|
||||
"items": [],
|
||||
}
|
||||
|
||||
|
||||
def get_db_paginator(
|
||||
offset: int = 0, limit: int = 100, q: str | None = None
|
||||
) -> DatabasePaginator:
|
||||
return DatabasePaginator(offset=offset, limit=limit, q=q)
|
||||
|
||||
|
||||
PaginatorDep = Annotated[DatabasePaginator, Depends(get_db_paginator)]
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(paginator: PaginatorDep):
|
||||
return paginator.get_page()
|
||||
```
|
||||
|
||||
instead of this:
|
||||
|
||||
```python
|
||||
# DO NOT DO THIS
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class DatabasePaginator:
|
||||
def __init__(self, offset: int = 0, limit: int = 100, q: str | None = None):
|
||||
self.offset = offset
|
||||
self.limit = limit
|
||||
self.q = q
|
||||
|
||||
def get_page(self) -> dict:
|
||||
# Simulate a page of data
|
||||
return {
|
||||
"offset": self.offset,
|
||||
"limit": self.limit,
|
||||
"q": self.q,
|
||||
"items": [],
|
||||
}
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(paginator: Annotated[DatabasePaginator, Depends()]):
|
||||
return paginator.get_page()
|
||||
```
|
||||
76
fastapi/.agents/skills/fastapi/references/other-tools.md
Normal file
76
fastapi/.agents/skills/fastapi/references/other-tools.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Other Tools
|
||||
|
||||
## uv
|
||||
|
||||
If uv is available, use it to manage dependencies.
|
||||
|
||||
## Ruff
|
||||
|
||||
If Ruff is available, use it to lint and format the code. Consider enabling the FastAPI rules.
|
||||
|
||||
## ty
|
||||
|
||||
If ty is available, use it to check types.
|
||||
|
||||
## Asyncer
|
||||
|
||||
When needing to run blocking code inside of async functions, or async code inside of blocking functions, suggest using Asyncer.
|
||||
|
||||
Prefer it over AnyIO or asyncio.
|
||||
|
||||
Install:
|
||||
|
||||
```bash
|
||||
uv add asyncer
|
||||
```
|
||||
|
||||
Run blocking sync code inside of async with `asyncify()`:
|
||||
|
||||
```python
|
||||
from asyncer import asyncify
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
def do_blocking_work(name: str) -> str:
|
||||
# Some blocking I/O operation
|
||||
return f"Hello {name}"
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items():
|
||||
result = await asyncify(do_blocking_work)(name="World")
|
||||
return {"message": result}
|
||||
```
|
||||
|
||||
And run async code inside of blocking sync code with `syncify()`:
|
||||
|
||||
```python
|
||||
from asyncer import syncify
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
async def do_async_work(name: str) -> str:
|
||||
return f"Hello {name}"
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
def read_items():
|
||||
result = syncify(do_async_work)(name="World")
|
||||
return {"message": result}
|
||||
```
|
||||
|
||||
## SQLModel for SQL databases
|
||||
|
||||
When working with SQL databases, prefer using SQLModel as it is integrated with Pydantic and will allow declaring data validation with the same models.
|
||||
|
||||
Prefer it over SQLAlchemy.
|
||||
|
||||
## HTTPX
|
||||
|
||||
Use HTTPX for handling HTTP communication (e.g. with other APIs). It support sync and async usage.
|
||||
|
||||
Prefer it over Requests.
|
||||
105
fastapi/.agents/skills/fastapi/references/streaming.md
Normal file
105
fastapi/.agents/skills/fastapi/references/streaming.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# Streaming
|
||||
|
||||
## Stream JSON Lines
|
||||
|
||||
To stream JSON Lines, declare the return type and use `yield` to return the data.
|
||||
|
||||
```python
|
||||
@app.get("/items/stream")
|
||||
async def stream_items() -> AsyncIterable[Item]:
|
||||
for item in items:
|
||||
yield item
|
||||
```
|
||||
|
||||
## Server-Sent Events (SSE)
|
||||
|
||||
To stream Server-Sent Events, use `response_class=EventSourceResponse` and `yield` items from the endpoint.
|
||||
|
||||
Plain objects are automatically JSON-serialized as `data:` fields, declare the return type so the serialization is done by Pydantic:
|
||||
|
||||
```python
|
||||
from collections.abc import AsyncIterable
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.sse import EventSourceResponse
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
|
||||
|
||||
@app.get("/items/stream", response_class=EventSourceResponse)
|
||||
async def stream_items() -> AsyncIterable[Item]:
|
||||
yield Item(name="Plumbus", price=32.99)
|
||||
yield Item(name="Portal Gun", price=999.99)
|
||||
```
|
||||
|
||||
For full control over SSE fields (`event`, `id`, `retry`, `comment`), yield `ServerSentEvent` instances:
|
||||
|
||||
```python
|
||||
from collections.abc import AsyncIterable
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.sse import EventSourceResponse, ServerSentEvent
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/events", response_class=EventSourceResponse)
|
||||
async def stream_events() -> AsyncIterable[ServerSentEvent]:
|
||||
yield ServerSentEvent(data={"status": "started"}, event="status", id="1")
|
||||
yield ServerSentEvent(data={"progress": 50}, event="progress", id="2")
|
||||
```
|
||||
|
||||
Use `raw_data` instead of `data` to send pre-formatted strings without JSON encoding:
|
||||
|
||||
```python
|
||||
yield ServerSentEvent(raw_data="plain text line", event="log")
|
||||
```
|
||||
|
||||
## Stream bytes
|
||||
|
||||
To stream bytes, declare a `response_class=` of `StreamingResponse` or a sub-class, and use `yield` to return the data.
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import StreamingResponse
|
||||
from app.utils import read_image
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class PNGStreamingResponse(StreamingResponse):
|
||||
media_type = "image/png"
|
||||
|
||||
@app.get("/image", response_class=PNGStreamingResponse)
|
||||
def stream_image_no_async_no_annotation():
|
||||
with read_image() as image_file:
|
||||
yield from image_file
|
||||
```
|
||||
|
||||
prefer this over returning a `StreamingResponse` directly:
|
||||
|
||||
```python
|
||||
# DO NOT DO THIS
|
||||
|
||||
import anyio
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import StreamingResponse
|
||||
from app.utils import read_image
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class PNGStreamingResponse(StreamingResponse):
|
||||
media_type = "image/png"
|
||||
|
||||
|
||||
@app.get("/")
|
||||
async def main():
|
||||
return PNGStreamingResponse(read_image())
|
||||
```
|
||||
30
uv.lock
generated
30
uv.lock
generated
@@ -4406,28 +4406,28 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "pytest-codspeed"
|
||||
version = "4.2.0"
|
||||
version = "4.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cffi" },
|
||||
{ name = "pytest" },
|
||||
{ name = "rich" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e2/e8/27fcbe6516a1c956614a4b61a7fccbf3791ea0b992e07416e8948184327d/pytest_codspeed-4.2.0.tar.gz", hash = "sha256:04b5d0bc5a1851ba1504d46bf9d7dbb355222a69f2cd440d54295db721b331f7", size = 113263, upload-time = "2025-10-24T09:02:55.704Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/98/ab/eca41967d11c95392829a8b4bfa9220a51cffc4a33ec4653358000356918/pytest_codspeed-4.3.0.tar.gz", hash = "sha256:5230d9d65f39063a313ed1820df775166227ec5c20a1122968f85653d5efee48", size = 124745, upload-time = "2026-02-09T15:23:34.745Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/b8/d599a466c50af3f04001877ae8b17c12b803f3b358235736b91a0769de0d/pytest_codspeed-4.2.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:609828b03972966b75b9b7416fa2570c4a0f6124f67e02d35cd3658e64312a7b", size = 261943, upload-time = "2025-10-24T09:02:37.962Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/19/ccc1a2fcd28357a8db08ba6b60f381832088a3850abc262c8e0b3406491a/pytest_codspeed-4.2.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23a0c0fbf8bb4de93a3454fd9e5efcdca164c778aaef0a9da4f233d85cb7f5b8", size = 250782, upload-time = "2025-10-24T09:02:39.617Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/2d/f0083a2f14ecf008d961d40439a71da0ae0d568e5f8dc2fccd3e8a2ab3e4/pytest_codspeed-4.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2de87bde9fbc6fd53f0fd21dcf2599c89e0b8948d49f9bad224edce51c47e26b", size = 261960, upload-time = "2025-10-24T09:02:40.665Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/0c/1f514c553db4ea5a69dfbe2706734129acd0eca8d5101ec16f1dd00dbc0f/pytest_codspeed-4.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95aeb2479ca383f6b18e2cc9ebcd3b03ab184980a59a232aea6f370bbf59a1e3", size = 250808, upload-time = "2025-10-24T09:02:42.07Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/04/479905bd6653bc981c0554fcce6df52d7ae1594e1eefd53e6cf31810ec7f/pytest_codspeed-4.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d4fefbd4ae401e2c60f6be920a0be50eef0c3e4a1f0a1c83962efd45be38b39", size = 262084, upload-time = "2025-10-24T09:02:43.155Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/46/d6f345d7907bac6cbb6224bd697ecbc11cf7427acc9e843c3618f19e3476/pytest_codspeed-4.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:309b4227f57fcbb9df21e889ea1ae191d0d1cd8b903b698fdb9ea0461dbf1dfe", size = 251100, upload-time = "2025-10-24T09:02:44.168Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/dc/e864f45e994a50390ff49792256f1bdcbf42f170e3bc0470ee1a7d2403f3/pytest_codspeed-4.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72aab8278452a6d020798b9e4f82780966adb00f80d27a25d1274272c54630d5", size = 262057, upload-time = "2025-10-24T09:02:45.791Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/1c/f1d2599784486879cf6579d8d94a3e22108f0e1f130033dab8feefd29249/pytest_codspeed-4.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:684fcd9491d810ded653a8d38de4835daa2d001645f4a23942862950664273f8", size = 251013, upload-time = "2025-10-24T09:02:46.937Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/fd/eafd24db5652a94b4d00fe9b309b607de81add0f55f073afb68a378a24b6/pytest_codspeed-4.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:50794dabea6ec90d4288904452051e2febace93e7edf4ca9f2bce8019dd8cd37", size = 262065, upload-time = "2025-10-24T09:02:48.018Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/14/8d9340d7dc0ae647991b28a396e16b3403e10def883cde90d6b663d3f7ec/pytest_codspeed-4.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0ebd87f2a99467a1cfd8e83492c4712976e43d353ee0b5f71cbb057f1393aca", size = 251057, upload-time = "2025-10-24T09:02:49.102Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/39/48cf6afbca55bc7c8c93c3d4ae926a1068bcce3f0241709db19b078d5418/pytest_codspeed-4.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dbbb2d61b85bef8fc7e2193f723f9ac2db388a48259d981bbce96319043e9830", size = 267983, upload-time = "2025-10-24T09:02:50.558Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/86/4407341efb5dceb3e389635749ce1d670542d6ca148bd34f9d5334295faf/pytest_codspeed-4.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:748411c832147bfc85f805af78a1ab1684f52d08e14aabe22932bbe46c079a5f", size = 256732, upload-time = "2025-10-24T09:02:51.603Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/25/0e/8cb71fd3ed4ed08c07aec1245aea7bc1b661ba55fd9c392db76f1978d453/pytest_codspeed-4.2.0-py3-none-any.whl", hash = "sha256:e81bbb45c130874ef99aca97929d72682733527a49f84239ba575b5cb843bab0", size = 113726, upload-time = "2025-10-24T09:02:54.785Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/64/800bdaeabd3eb126aff7e3e22dc45b2826305f61cbfd093284caf8d9ca01/pytest_codspeed-4.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2acecc4126658abebc683b38121adec405a46e18a619d49d6154c6e60c5deb2", size = 347077, upload-time = "2026-02-09T15:23:17.2Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/f1/d69707440829adab86d078d5f1c8c070df116b1624f8eae4ff36933ba612/pytest_codspeed-4.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:619120775e92a3f43fb4ff4c256a251b1554c904d95e2154a382484283f0388a", size = 342234, upload-time = "2026-02-09T15:23:18.407Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/15/ec0ac1f022173b3134c9638f2a35f21fbb3142c75da066d9e49e5a8bb4bd/pytest_codspeed-4.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dbeff1eb2f2e36df088658b556fa993e6937bf64ffb07406de4db16fd2b26874", size = 347076, upload-time = "2026-02-09T15:23:19.989Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/e8/1fe375794ad02b7835f378a7bcfa8fbac9acadefe600a782a7c4a7064db7/pytest_codspeed-4.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:878aad5e4bb7b401ad8d82f3af5186030cd2bd0d0446782e10dabb9db8827466", size = 342215, upload-time = "2026-02-09T15:23:20.954Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/09/58/50df94e9a78e1c77818a492c90557eeb1309af025120c9a21e6375950c52/pytest_codspeed-4.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527a3a02eaa3e4d4583adc4ba2327eef79628f3e1c682a4b959439551a72588e", size = 347395, upload-time = "2026-02-09T15:23:21.986Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/56/7dfbd3eefd112a14e6fb65f9ff31dacf2e9c381cb94b27332b81d2b13f8d/pytest_codspeed-4.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9858c2a6e1f391d5696757e7b6e9484749a7376c46f8b4dd9aebf093479a9667", size = 342625, upload-time = "2026-02-09T15:23:23.035Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/53/7255f6a25bc56ff1745b254b21545dfe0be2268f5b91ce78f7e8a908f0ad/pytest_codspeed-4.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:34f2fd8497456eefbd325673f677ea80d93bb1bc08a578c1fa43a09cec3d1879", size = 347325, upload-time = "2026-02-09T15:23:23.998Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/f8/82ae570d8b9ad30f33c9d4002a7a1b2740de0e090540c69a28e4f711ebe2/pytest_codspeed-4.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df6a36a2a9da1406bc50428437f657f0bd8c842ae54bee5fb3ad30e01d50c0f5", size = 342558, upload-time = "2026-02-09T15:23:25.656Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/e1/55cfe9474f91d174c7a4b04d257b5fc6d4d06f3d3680f2da672ee59ccc10/pytest_codspeed-4.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bec30f4fc9c4973143cd80f0d33fa780e9fa3e01e4dbe8cedf229e72f1212c62", size = 347383, upload-time = "2026-02-09T15:23:26.68Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/3b/8fd781d959bbe789b3de8ce4c50d5706a684a0df377147dfb27b200c20c1/pytest_codspeed-4.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e6584e641cadf27d894ae90b87c50377232a97cbfd76ee0c7ecd0c056fa3f7f4", size = 342481, upload-time = "2026-02-09T15:23:27.686Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/0c/368045133c6effa2c665b1634b7b8a9c88b307f877fa31f1f8df47885b51/pytest_codspeed-4.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df0d1f6ea594f29b745c634d66d5f5f1caa1c3abd2af82fea49d656038e8fc77", size = 353680, upload-time = "2026-02-09T15:23:28.726Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/21/e543abcd72244294e25ae88ec3a9311ade24d6913f8c8f42569d671700bc/pytest_codspeed-4.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2f5bb6d8898bea7db45e3c8b916ee48e36905b929477bb511b79c5a3ccacda4", size = 347888, upload-time = "2026-02-09T15:23:30.443Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/d9/b8a53c20cf5b41042c205bb9d36d37da00418d30fd1a94bf9eb147820720/pytest_codspeed-4.3.0-py3-none-any.whl", hash = "sha256:05baff2a61dc9f3e92b92b9c2ab5fb45d9b802438f5373073f5766a91319ed7a", size = 125224, upload-time = "2026-02-09T15:23:33.774Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in New Issue
Block a user