diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml
new file mode 100644
index 000000000..c7bd1003a
--- /dev/null
+++ b/.github/workflows/performance.yml
@@ -0,0 +1,34 @@
+name: performance-tests
+
+on:
+ push:
+ branches:
+ - "main" # or "master"
+ paths-ignore:
+ - "**/*.md"
+ pull_request:
+ workflow_dispatch:
+
+env:
+ TELEMETRY_ENABLED: false
+ NODE_OPTIONS: "--max_old_space_size=8192"
+ PR_TITLE: ${{ github.event.pull_request.title }}
+ APP_HARNESS_HEADLESS: 1
+ PYTHONUNBUFFERED: 1
+
+jobs:
+ benchmarks:
+ name: Run benchmarks
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: ./.github/actions/setup_build_env
+ with:
+ python-version: 3.12.8
+ run-poetry-install: true
+ create-venv-at-path: .venv
+ - name: Run benchmarks
+ uses: CodSpeedHQ/action@v3
+ with:
+ token: ${{ secrets.CODSPEED_TOKEN }}
+ run: poetry run pytest benchmarks/test_evaluate.py --codspeed
diff --git a/.gitignore b/.gitignore
index 0f7d9e5ff..29a868796 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@ assets/external/*
dist/*
examples/
.web
+.states
.idea
.vscode
.coverage
@@ -14,3 +15,4 @@ requirements.txt
.pyi_generator_last_run
.pyi_generator_diff
reflex.db
+.codspeed
\ No newline at end of file
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 54d8f3d72..dbe069ae8 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -28,7 +28,7 @@ repos:
entry: python3 scripts/make_pyi.py
- repo: https://github.com/RobertCraigie/pyright-python
- rev: v1.1.334
+ rev: v1.1.392
hooks:
- id: pyright
args: [reflex, tests]
diff --git a/benchmarks/test_benchmark_compile_components.py b/benchmarks/test_benchmark_compile_components.py
index ba7e9c571..9bcfbf85b 100644
--- a/benchmarks/test_benchmark_compile_components.py
+++ b/benchmarks/test_benchmark_compile_components.py
@@ -34,13 +34,13 @@ def render_component(num: int):
rx.box(
rx.accordion.root(
rx.accordion.item(
- header="Full Ingredients", # type: ignore
- content="Yes. It's built with accessibility in mind.", # type: ignore
+ header="Full Ingredients",
+ content="Yes. It's built with accessibility in mind.",
font_size="3em",
),
rx.accordion.item(
- header="Applications", # type: ignore
- content="Yes. It's unstyled by default, giving you freedom over the look and feel.", # type: ignore
+ header="Applications",
+ content="Yes. It's unstyled by default, giving you freedom over the look and feel.",
),
collapsible=True,
variant="ghost",
@@ -166,9 +166,9 @@ def app_with_10_components(
root=root,
app_source=functools.partial(
AppWithTenComponentsOnePage,
- render_component=render_component, # type: ignore
+ render_component=render_component, # pyright: ignore [reportCallIssue]
),
- ) # type: ignore
+ )
@pytest.fixture(scope="session")
@@ -189,9 +189,9 @@ def app_with_100_components(
root=root,
app_source=functools.partial(
AppWithHundredComponentOnePage,
- render_component=render_component, # type: ignore
+ render_component=render_component, # pyright: ignore [reportCallIssue]
),
- ) # type: ignore
+ )
@pytest.fixture(scope="session")
@@ -212,9 +212,9 @@ def app_with_1000_components(
root=root,
app_source=functools.partial(
AppWithThousandComponentsOnePage,
- render_component=render_component, # type: ignore
+ render_component=render_component, # pyright: ignore [reportCallIssue]
),
- ) # type: ignore
+ )
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
diff --git a/benchmarks/test_benchmark_compile_pages.py b/benchmarks/test_benchmark_compile_pages.py
index a5c85810e..149fc6130 100644
--- a/benchmarks/test_benchmark_compile_pages.py
+++ b/benchmarks/test_benchmark_compile_pages.py
@@ -28,7 +28,7 @@ def render_multiple_pages(app, num: int):
"""
from typing import Tuple
- from rxconfig import config # type: ignore
+ from rxconfig import config # pyright: ignore [reportMissingImports]
import reflex as rx
@@ -74,13 +74,13 @@ def render_multiple_pages(app, num: int):
rx.select(
["C", "PF", "SF", "PG", "SG"],
placeholder="Select a position. (All)",
- on_change=State.set_position, # type: ignore
+ on_change=State.set_position, # pyright: ignore [reportAttributeAccessIssue]
size="3",
),
rx.select(
college,
placeholder="Select a college. (All)",
- on_change=State.set_college, # type: ignore
+ on_change=State.set_college, # pyright: ignore [reportAttributeAccessIssue]
size="3",
),
),
@@ -95,7 +95,7 @@ def render_multiple_pages(app, num: int):
default_value=[18, 50],
min=18,
max=50,
- on_value_commit=State.set_age, # type: ignore
+ on_value_commit=State.set_age, # pyright: ignore [reportAttributeAccessIssue]
),
align_items="left",
width="100%",
@@ -110,7 +110,7 @@ def render_multiple_pages(app, num: int):
default_value=[0, 25000000],
min=0,
max=25000000,
- on_value_commit=State.set_salary, # type: ignore
+ on_value_commit=State.set_salary, # pyright: ignore [reportAttributeAccessIssue]
),
align_items="left",
width="100%",
@@ -130,7 +130,7 @@ def render_multiple_pages(app, num: int):
def AppWithOnePage():
"""A reflex app with one page."""
- from rxconfig import config # type: ignore
+ from rxconfig import config # pyright: ignore [reportMissingImports]
import reflex as rx
@@ -232,7 +232,7 @@ def app_with_ten_pages(
root=root,
app_source=functools.partial(
AppWithTenPages,
- render_comp=render_multiple_pages, # type: ignore
+ render_comp=render_multiple_pages, # pyright: ignore [reportCallIssue]
),
)
@@ -255,9 +255,9 @@ def app_with_hundred_pages(
root=root,
app_source=functools.partial(
AppWithHundredPages,
- render_comp=render_multiple_pages, # type: ignore
+ render_comp=render_multiple_pages, # pyright: ignore [reportCallIssue]
),
- ) # type: ignore
+ )
@pytest.fixture(scope="session")
@@ -278,9 +278,9 @@ def app_with_thousand_pages(
root=root,
app_source=functools.partial(
AppWithThousandPages,
- render_comp=render_multiple_pages, # type: ignore
+ render_comp=render_multiple_pages, # pyright: ignore [reportCallIssue]
),
- ) # type: ignore
+ )
@pytest.fixture(scope="session")
@@ -301,9 +301,9 @@ def app_with_ten_thousand_pages(
root=root,
app_source=functools.partial(
AppWithTenThousandPages,
- render_comp=render_multiple_pages, # type: ignore
+ render_comp=render_multiple_pages, # pyright: ignore [reportCallIssue]
),
- ) # type: ignore
+ )
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
diff --git a/benchmarks/test_evaluate.py b/benchmarks/test_evaluate.py
new file mode 100644
index 000000000..aa4c8237e
--- /dev/null
+++ b/benchmarks/test_evaluate.py
@@ -0,0 +1,231 @@
+from dataclasses import dataclass
+from typing import cast
+
+import pytest
+
+import reflex as rx
+
+
+class SideBarState(rx.State):
+ """State for the side bar."""
+
+ current_page: rx.Field[str] = rx.field("/")
+
+
+@dataclass(frozen=True)
+class SideBarPage:
+ """A page in the side bar."""
+
+ title: str
+ href: str
+
+
+@dataclass(frozen=True)
+class SideBarSection:
+ """A section in the side bar."""
+
+ name: str
+ icon: str
+ pages: tuple[SideBarPage, ...]
+
+
+@dataclass(frozen=True)
+class Category:
+ """A category in the side bar."""
+
+ name: str
+ href: str
+ sections: tuple[SideBarSection, ...]
+
+
+SIDE_BAR = (
+ Category(
+ name="General",
+ href="/",
+ sections=(
+ SideBarSection(
+ name="Home",
+ icon="home",
+ pages=(
+ SideBarPage(title="Home", href="/"),
+ SideBarPage(title="Contact", href="/contact"),
+ ),
+ ),
+ SideBarSection(
+ name="About",
+ icon="info",
+ pages=(
+ SideBarPage(title="About", href="/about"),
+ SideBarPage(title="FAQ", href="/faq"),
+ ),
+ ),
+ ),
+ ),
+ Category(
+ name="Projects",
+ href="/projects",
+ sections=(
+ SideBarSection(
+ name="Python",
+ icon="worm",
+ pages=(
+ SideBarPage(title="Python", href="/projects/python"),
+ SideBarPage(title="Django", href="/projects/django"),
+ SideBarPage(title="Flask", href="/projects/flask"),
+ SideBarPage(title="FastAPI", href="/projects/fastapi"),
+ SideBarPage(title="Pyramid", href="/projects/pyramid"),
+ SideBarPage(title="Tornado", href="/projects/tornado"),
+ SideBarPage(title="TurboGears", href="/projects/turbogears"),
+ SideBarPage(title="Web2py", href="/projects/web2py"),
+ SideBarPage(title="Zope", href="/projects/zope"),
+ SideBarPage(title="Plone", href="/projects/plone"),
+ SideBarPage(title="Quixote", href="/projects/quixote"),
+ SideBarPage(title="Bottle", href="/projects/bottle"),
+ SideBarPage(title="CherryPy", href="/projects/cherrypy"),
+ SideBarPage(title="Falcon", href="/projects/falcon"),
+ SideBarPage(title="Sanic", href="/projects/sanic"),
+ SideBarPage(title="Starlette", href="/projects/starlette"),
+ ),
+ ),
+ SideBarSection(
+ name="JavaScript",
+ icon="banana",
+ pages=(
+ SideBarPage(title="JavaScript", href="/projects/javascript"),
+ SideBarPage(title="Angular", href="/projects/angular"),
+ SideBarPage(title="React", href="/projects/react"),
+ SideBarPage(title="Vue", href="/projects/vue"),
+ SideBarPage(title="Ember", href="/projects/ember"),
+ SideBarPage(title="Backbone", href="/projects/backbone"),
+ SideBarPage(title="Meteor", href="/projects/meteor"),
+ SideBarPage(title="Svelte", href="/projects/svelte"),
+ SideBarPage(title="Preact", href="/projects/preact"),
+ SideBarPage(title="Mithril", href="/projects/mithril"),
+ SideBarPage(title="Aurelia", href="/projects/aurelia"),
+ SideBarPage(title="Polymer", href="/projects/polymer"),
+ SideBarPage(title="Knockout", href="/projects/knockout"),
+ SideBarPage(title="Dojo", href="/projects/dojo"),
+ SideBarPage(title="Riot", href="/projects/riot"),
+ SideBarPage(title="Alpine", href="/projects/alpine"),
+ SideBarPage(title="Stimulus", href="/projects/stimulus"),
+ SideBarPage(title="Marko", href="/projects/marko"),
+ SideBarPage(title="Sapper", href="/projects/sapper"),
+ SideBarPage(title="Nuxt", href="/projects/nuxt"),
+ SideBarPage(title="Next", href="/projects/next"),
+ SideBarPage(title="Gatsby", href="/projects/gatsby"),
+ SideBarPage(title="Gridsome", href="/projects/gridsome"),
+ SideBarPage(title="Nest", href="/projects/nest"),
+ SideBarPage(title="Express", href="/projects/express"),
+ SideBarPage(title="Koa", href="/projects/koa"),
+ SideBarPage(title="Hapi", href="/projects/hapi"),
+ SideBarPage(title="LoopBack", href="/projects/loopback"),
+ SideBarPage(title="Feathers", href="/projects/feathers"),
+ SideBarPage(title="Sails", href="/projects/sails"),
+ SideBarPage(title="Adonis", href="/projects/adonis"),
+ SideBarPage(title="Meteor", href="/projects/meteor"),
+ SideBarPage(title="Derby", href="/projects/derby"),
+ SideBarPage(title="Socket.IO", href="/projects/socketio"),
+ ),
+ ),
+ ),
+ ),
+)
+
+
+def side_bar_page(page: SideBarPage):
+ return rx.box(
+ rx.link(
+ page.title,
+ href=page.href,
+ )
+ )
+
+
+def side_bar_section(section: SideBarSection):
+ return rx.accordion.item(
+ rx.accordion.header(
+ rx.accordion.trigger(
+ rx.hstack(
+ rx.hstack(
+ rx.icon(section.icon),
+ section.name,
+ align="center",
+ ),
+ rx.accordion.icon(),
+ width="100%",
+ justify="between",
+ )
+ )
+ ),
+ rx.accordion.content(
+ rx.vstack(
+ *map(side_bar_page, section.pages),
+ ),
+ border_inline_start="1px solid",
+ padding_inline_start="1em",
+ margin_inline_start="1.5em",
+ ),
+ value=section.name,
+ width="100%",
+ variant="ghost",
+ )
+
+
+def side_bar_category(category: Category):
+ selected_section = cast(
+ rx.Var,
+ rx.match(
+ SideBarState.current_page,
+ *[
+ (
+ section.name,
+ section.name,
+ )
+ for section in category.sections
+ ],
+ None,
+ ),
+ )
+ return rx.vstack(
+ rx.heading(
+ rx.link(
+ category.name,
+ href=category.href,
+ ),
+ size="5",
+ ),
+ rx.accordion.root(
+ *map(side_bar_section, category.sections),
+ default_value=selected_section.to(str),
+ variant="ghost",
+ width="100%",
+ collapsible=True,
+ type="multiple",
+ ),
+ width="100%",
+ )
+
+
+def side_bar():
+ return rx.vstack(
+ *map(side_bar_category, SIDE_BAR),
+ width="fit-content",
+ )
+
+
+LOREM_IPSUM = "Lorem ipsum dolor sit amet, dolor ut dolore pariatur aliqua enim tempor sed. Labore excepteur sed exercitation. Ullamco aliquip lorem sunt enim in incididunt. Magna anim officia sint cillum labore. Ut eu non dolore minim nostrud magna eu, aute ex in incididunt irure eu. Fugiat et magna magna est excepteur eiusmod minim. Quis eiusmod et non pariatur dolor veniam incididunt, eiusmod irure enim sed dolor lorem pariatur do. Occaecat duis irure excepteur dolore. Proident ut laborum pariatur sit sit, nisi nostrud voluptate magna commodo laborum esse velit. Voluptate non minim deserunt adipiscing irure deserunt cupidatat. Laboris veniam commodo incididunt veniam lorem occaecat, fugiat ipsum dolor cupidatat. Ea officia sed eu excepteur culpa adipiscing, tempor consectetur ullamco eu. Anim ex proident nulla sunt culpa, voluptate veniam proident est adipiscing sint elit velit. Laboris adipiscing est culpa cillum magna. Sit veniam nulla nulla, aliqua eiusmod commodo lorem cupidatat commodo occaecat. Fugiat cillum dolor incididunt mollit eiusmod sint. Non lorem dolore labore excepteur minim laborum sed. Irure nisi do lorem nulla sunt commodo, deserunt quis mollit consectetur minim et esse est, proident nostrud officia enim sed reprehenderit. Magna cillum consequat aute reprehenderit duis sunt ullamco. Labore qui mollit voluptate. Duis dolor sint aute amet aliquip officia, est non mollit tempor enim quis fugiat, eu do culpa consectetur magna. Do ullamco aliqua voluptate culpa excepteur reprehenderit reprehenderit. Occaecat nulla sit est magna. Deserunt ea voluptate veniam cillum. Amet cupidatat duis est tempor fugiat ex eu, officia est sunt consectetur labore esse exercitation. Nisi cupidatat irure est nisi. Officia amet eu veniam reprehenderit. In amet incididunt tempor commodo ea labore. Mollit dolor aliquip excepteur, voluptate aute occaecat id officia proident. Ullamco est amet tempor. Proident aliquip proident mollit do aliquip ipsum, culpa quis aute id irure. Velit excepteur cillum cillum ut cupidatat. Occaecat qui elit esse nulla minim. Consequat velit id ad pariatur tempor. Eiusmod deserunt aliqua ex sed quis non. Dolor sint commodo ex in deserunt nostrud excepteur, pariatur ex aliqua anim adipiscing amet proident. Laboris eu laborum magna lorem ipsum fugiat velit."
+
+
+def complicated_page():
+ return rx.hstack(
+ side_bar(),
+ rx.box(
+ rx.heading("Complicated Page", size="1"),
+ rx.text(LOREM_IPSUM),
+ ),
+ )
+
+
+@pytest.mark.benchmark
+def test_component_init():
+ complicated_page()
diff --git a/poetry.lock b/poetry.lock
index f492584d0..0b4f489dc 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand.
+# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand.
[[package]]
name = "alembic"
@@ -6,6 +6,8 @@ version = "1.14.1"
description = "A database migration tool for SQLAlchemy."
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "alembic-1.14.1-py3-none-any.whl", hash = "sha256:1acdd7a3a478e208b0503cd73614d5e4c6efafa4e73518bb60e4f2846a37b1c5"},
{file = "alembic-1.14.1.tar.gz", hash = "sha256:496e888245a53adf1498fcab31713a469c65836f8de76e01399aa1c3e90dd213"},
@@ -25,6 +27,8 @@ version = "0.7.0"
description = "Reusable constraint types to use with typing.Annotated"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
@@ -36,6 +40,8 @@ version = "4.8.0"
description = "High level compatibility layer for multiple asynchronous event loop implementations"
optional = false
python-versions = ">=3.9"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"},
{file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"},
@@ -58,6 +64,8 @@ version = "5.0.1"
description = "Timeout context manager for asyncio programs"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_full_version < \"3.11.3\""
files = [
{file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"},
{file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"},
@@ -69,6 +77,8 @@ version = "0.13.0"
description = "Enhance the standard unittest package with features for testing asyncio libraries"
optional = false
python-versions = ">=3.5"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "asynctest-0.13.0-py3-none-any.whl", hash = "sha256:5da6118a7e6d6b54d83a8f7197769d046922a44d2a99c21382f0a6e4fadae676"},
{file = "asynctest-0.13.0.tar.gz", hash = "sha256:c27862842d15d83e6a34eb0b2866c323880eb3a75e4485b079ea11748fd77fac"},
@@ -76,13 +86,15 @@ files = [
[[package]]
name = "attrs"
-version = "24.3.0"
+version = "25.1.0"
description = "Classes Without Boilerplate"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
- {file = "attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"},
- {file = "attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff"},
+ {file = "attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"},
+ {file = "attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e"},
]
[package.extras]
@@ -99,6 +111,8 @@ version = "1.2.0"
description = "Backport of CPython tarfile module"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and python_version <= \"3.11\""
files = [
{file = "backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"},
{file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"},
@@ -114,6 +128,8 @@ version = "0.23.1"
description = "The bidirectional mapping library for Python."
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5"},
{file = "bidict-0.23.1.tar.gz", hash = "sha256:03069d763bc387bbd20e7d49914e75fc4132a41937fa3405417e1a5a2d006d71"},
@@ -125,6 +141,8 @@ version = "1.2.2.post1"
description = "A simple, correct Python build frontend"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "build-1.2.2.post1-py3-none-any.whl", hash = "sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5"},
{file = "build-1.2.2.post1.tar.gz", hash = "sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7"},
@@ -150,6 +168,8 @@ version = "2024.12.14"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"},
{file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"},
@@ -161,6 +181,7 @@ version = "1.17.1"
description = "Foreign Function Interface for Python calling C code."
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
files = [
{file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
{file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
@@ -230,6 +251,7 @@ files = [
{file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
{file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
]
+markers = {main = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\" and (python_version <= \"3.11\" or python_version >= \"3.12\")", dev = "python_version <= \"3.11\" or python_version >= \"3.12\""}
[package.dependencies]
pycparser = "*"
@@ -240,6 +262,8 @@ version = "3.4.0"
description = "Validate configuration and produce human readable error messages."
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"},
{file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
@@ -251,6 +275,8 @@ version = "3.4.1"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
python-versions = ">=3.7"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"},
{file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"},
@@ -352,6 +378,8 @@ version = "8.1.8"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.7"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"},
{file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"},
@@ -366,10 +394,12 @@ version = "0.4.6"
description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+groups = ["main", "dev"]
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
+markers = {main = "(platform_system == \"Windows\" or os_name == \"nt\") and (python_version <= \"3.11\" or python_version >= \"3.12\")", dev = "(python_version <= \"3.11\" or python_version >= \"3.12\") and sys_platform == \"win32\""}
[[package]]
name = "coverage"
@@ -377,6 +407,8 @@ version = "7.6.10"
description = "Code coverage measurement for Python"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78"},
{file = "coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c"},
@@ -454,6 +486,8 @@ version = "44.0.0"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
optional = false
python-versions = "!=3.9.0,!=3.9.1,>=3.7"
+groups = ["main"]
+markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\" and (python_version <= \"3.11\" or python_version >= \"3.12\")"
files = [
{file = "cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123"},
{file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092"},
@@ -505,6 +539,8 @@ version = "1.8.1"
description = "A utility for ensuring Google-style docstrings stay up to date with the source code."
optional = false
python-versions = ">=3.6,<4.0"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "darglint-1.8.1-py3-none-any.whl", hash = "sha256:5ae11c259c17b0701618a20c3da343a3eb98b3bc4b5a83d31cdd94f5ebdced8d"},
{file = "darglint-1.8.1.tar.gz", hash = "sha256:080d5106df149b199822e7ee7deb9c012b49891538f14a11be681044f0bb20da"},
@@ -516,6 +552,8 @@ version = "0.3.9"
description = "serialize all of Python"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"},
{file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"},
@@ -531,6 +569,8 @@ version = "0.3.9"
description = "Distribution utilities"
optional = false
python-versions = "*"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"},
{file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"},
@@ -542,6 +582,8 @@ version = "1.9.0"
description = "Distro - an OS platform information API"
optional = false
python-versions = ">=3.6"
+groups = ["main"]
+markers = "(python_version <= \"3.11\" or python_version >= \"3.12\") and sys_platform == \"linux\""
files = [
{file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"},
{file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"},
@@ -553,6 +595,8 @@ version = "0.21.2"
description = "Docutils -- Python Documentation Utilities"
optional = false
python-versions = ">=3.9"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"},
{file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"},
@@ -564,6 +608,8 @@ version = "1.2.2"
description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
+groups = ["main", "dev"]
+markers = "python_version < \"3.11\""
files = [
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
@@ -574,23 +620,25 @@ test = ["pytest (>=6)"]
[[package]]
name = "fastapi"
-version = "0.115.6"
+version = "0.115.7"
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
- {file = "fastapi-0.115.6-py3-none-any.whl", hash = "sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305"},
- {file = "fastapi-0.115.6.tar.gz", hash = "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654"},
+ {file = "fastapi-0.115.7-py3-none-any.whl", hash = "sha256:eb6a8c8bf7f26009e8147111ff15b5177a0e19bb4a45bc3486ab14804539d21e"},
+ {file = "fastapi-0.115.7.tar.gz", hash = "sha256:0f106da6c01d88a6786b3248fb4d7a940d071f6f488488898ad5d354b25ed015"},
]
[package.dependencies]
pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0"
-starlette = ">=0.40.0,<0.42.0"
+starlette = ">=0.40.0,<0.46.0"
typing-extensions = ">=4.8.0"
[package.extras]
-all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
-standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"]
+all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
+standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"]
[[package]]
name = "filelock"
@@ -598,6 +646,8 @@ version = "3.17.0"
description = "A platform independent file lock."
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338"},
{file = "filelock-3.17.0.tar.gz", hash = "sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e"},
@@ -614,6 +664,7 @@ version = "3.1.1"
description = "Lightweight in-process concurrent programming"
optional = false
python-versions = ">=3.7"
+groups = ["main", "dev"]
files = [
{file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"},
{file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"},
@@ -689,6 +740,7 @@ files = [
{file = "greenlet-3.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22"},
{file = "greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467"},
]
+markers = {main = "(python_version <= \"3.11\" or python_version >= \"3.12\") and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\") and python_version < \"3.14\"", dev = "python_version <= \"3.11\" or python_version >= \"3.12\""}
[package.extras]
docs = ["Sphinx", "furo"]
@@ -700,6 +752,8 @@ version = "23.0.0"
description = "WSGI HTTP Server for UNIX"
optional = false
python-versions = ">=3.7"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d"},
{file = "gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec"},
@@ -721,6 +775,8 @@ version = "0.14.0"
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
optional = false
python-versions = ">=3.7"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
@@ -732,6 +788,8 @@ version = "1.0.7"
description = "A minimal low-level HTTP client."
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"},
{file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"},
@@ -753,6 +811,8 @@ version = "0.28.1"
description = "The next generation HTTP client."
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"},
{file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"},
@@ -777,6 +837,8 @@ version = "1.5.0"
description = "A tool for generating OIDC identities"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "id-1.5.0-py3-none-any.whl", hash = "sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658"},
{file = "id-1.5.0.tar.gz", hash = "sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d"},
@@ -796,6 +858,8 @@ version = "2.6.6"
description = "File identification library for Python"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "identify-2.6.6-py2.py3-none-any.whl", hash = "sha256:cbd1810bce79f8b671ecb20f53ee0ae8e86ae84b557de31d89709dc2a48ba881"},
{file = "identify-2.6.6.tar.gz", hash = "sha256:7bec12768ed44ea4761efb47806f0a41f86e7c0a5fdf5950d4648c90eca7e251"},
@@ -810,6 +874,8 @@ version = "3.10"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.6"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
{file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
@@ -824,6 +890,8 @@ version = "8.6.1"
description = "Read metadata from Python packages"
optional = false
python-versions = ">=3.9"
+groups = ["main"]
+markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and python_version <= \"3.11\" or python_full_version < \"3.10.2\""
files = [
{file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"},
{file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"},
@@ -847,6 +915,8 @@ version = "2.0.0"
description = "brain-dead simple config-ini parsing"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
@@ -858,6 +928,8 @@ version = "3.4.0"
description = "Utility functions for Python class constructs"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "(python_version <= \"3.11\" or python_version >= \"3.12\") and (platform_machine != \"ppc64le\" and platform_machine != \"s390x\")"
files = [
{file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"},
{file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"},
@@ -876,6 +948,8 @@ version = "6.0.1"
description = "Useful decorators and context managers"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "(python_version <= \"3.11\" or python_version >= \"3.12\") and (platform_machine != \"ppc64le\" and platform_machine != \"s390x\")"
files = [
{file = "jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"},
{file = "jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3"},
@@ -894,6 +968,8 @@ version = "4.1.0"
description = "Functools like those found in stdlib"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "(python_version <= \"3.11\" or python_version >= \"3.12\") and (platform_machine != \"ppc64le\" and platform_machine != \"s390x\")"
files = [
{file = "jaraco.functools-4.1.0-py3-none-any.whl", hash = "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649"},
{file = "jaraco_functools-4.1.0.tar.gz", hash = "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d"},
@@ -916,6 +992,8 @@ version = "0.8.0"
description = "Low-level, pure Python DBus protocol wrapper."
optional = false
python-versions = ">=3.7"
+groups = ["main"]
+markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\" and (python_version <= \"3.11\" or python_version >= \"3.12\")"
files = [
{file = "jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"},
{file = "jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806"},
@@ -931,6 +1009,8 @@ version = "3.1.5"
description = "A very fast and expressive template engine."
optional = false
python-versions = ">=3.7"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"},
{file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"},
@@ -948,6 +1028,8 @@ version = "25.6.0"
description = "Store and access your passwords safely."
optional = false
python-versions = ">=3.9"
+groups = ["main"]
+markers = "(python_version <= \"3.11\" or python_version >= \"3.12\") and (platform_machine != \"ppc64le\" and platform_machine != \"s390x\")"
files = [
{file = "keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd"},
{file = "keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66"},
@@ -977,6 +1059,8 @@ version = "0.4"
description = "Makes it easy to load subpackages and functions on demand."
optional = false
python-versions = ">=3.7"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "lazy_loader-0.4-py3-none-any.whl", hash = "sha256:342aa8e14d543a154047afb4ba8ef17f5563baad3fc610d7b15b213b0f119efc"},
{file = "lazy_loader-0.4.tar.gz", hash = "sha256:47c75182589b91a4e1a85a136c074285a5ad4d9f39c63e0d7fb76391c4574cd1"},
@@ -996,6 +1080,8 @@ version = "1.3.8"
description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "Mako-1.3.8-py3-none-any.whl", hash = "sha256:42f48953c7eb91332040ff567eb7eea69b22e7a4affbc5ba8e845e8f730f6627"},
{file = "mako-1.3.8.tar.gz", hash = "sha256:577b97e414580d3e088d47c2dbbe9594aa7a5146ed2875d4dfa9075af2dd3cc8"},
@@ -1015,6 +1101,8 @@ version = "3.0.0"
description = "Python port of markdown-it. Markdown parsing, done right!"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
{file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
@@ -1039,6 +1127,8 @@ version = "3.0.2"
description = "Safely add untrusted strings to HTML/XML markup."
optional = false
python-versions = ">=3.9"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"},
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"},
@@ -1109,6 +1199,8 @@ version = "0.1.2"
description = "Markdown URL utilities"
optional = false
python-versions = ">=3.7"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
@@ -1120,6 +1212,8 @@ version = "10.6.0"
description = "More routines for operating on iterables, beyond itertools"
optional = false
python-versions = ">=3.9"
+groups = ["main"]
+markers = "(python_version <= \"3.11\" or python_version >= \"3.12\") and (platform_machine != \"ppc64le\" and platform_machine != \"s390x\")"
files = [
{file = "more-itertools-10.6.0.tar.gz", hash = "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b"},
{file = "more_itertools-10.6.0-py3-none-any.whl", hash = "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89"},
@@ -1131,6 +1225,8 @@ version = "0.2.20"
description = "Python binding to Ammonia HTML sanitizer Rust crate"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "nh3-0.2.20-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e1061a4ab6681f6bdf72b110eea0c4e1379d57c9de937db3be4202f7ad6043db"},
{file = "nh3-0.2.20-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb4254b1dac4a1ee49919a5b3f1caf9803ea8dada1816d9e8289e63d3cd0dd9a"},
@@ -1164,6 +1260,8 @@ version = "1.9.1"
description = "Node.js virtual environment builder"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"},
{file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"},
@@ -1175,6 +1273,8 @@ version = "2.2.2"
description = "Fundamental package for array computing in Python"
optional = false
python-versions = ">=3.10"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "numpy-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7079129b64cb78bdc8d611d1fd7e8002c0a2565da6a47c4df8062349fee90e3e"},
{file = "numpy-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ec6c689c61df613b783aeb21f945c4cbe6c51c28cb70aae8430577ab39f163e"},
@@ -1239,6 +1339,8 @@ version = "1.3.0.post0"
description = "Capture the outcome of Python function calls."
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "outcome-1.3.0.post0-py2.py3-none-any.whl", hash = "sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b"},
{file = "outcome-1.3.0.post0.tar.gz", hash = "sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8"},
@@ -1253,6 +1355,8 @@ version = "24.2"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"},
{file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"},
@@ -1264,6 +1368,8 @@ version = "2.2.3"
description = "Powerful data structures for data analysis, time series, and statistics"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5"},
{file = "pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348"},
@@ -1350,6 +1456,8 @@ version = "11.1.0"
description = "Python Imaging Library (Fork)"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pillow-11.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:e1abe69aca89514737465752b4bcaf8016de61b3be1397a8fc260ba33321b3a8"},
{file = "pillow-11.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c640e5a06869c75994624551f45e5506e4256562ead981cce820d5ab39ae2192"},
@@ -1432,41 +1540,14 @@ tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "ole
typing = ["typing-extensions"]
xmp = ["defusedxml"]
-[[package]]
-name = "pip"
-version = "24.3.1"
-description = "The PyPA recommended tool for installing Python packages."
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "pip-24.3.1-py3-none-any.whl", hash = "sha256:3790624780082365f47549d032f3770eeb2b1e8bd1f7b2e02dace1afa361b4ed"},
- {file = "pip-24.3.1.tar.gz", hash = "sha256:ebcb60557f2aefabc2e0f918751cd24ea0d56d8ec5445fe1807f1d2109660b99"},
-]
-
-[[package]]
-name = "pipdeptree"
-version = "2.16.2"
-description = "Command line utility to show dependency tree of packages."
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "pipdeptree-2.16.2-py3-none-any.whl", hash = "sha256:4b60a20f632aa3449880141d1cd0bc99cb5f93ed46d54d689fd1c9b95f0e53d0"},
- {file = "pipdeptree-2.16.2.tar.gz", hash = "sha256:96ecde8e6f40c95998491a385e4af56d387f94ff7d3b8f209aa34982a721bc43"},
-]
-
-[package.dependencies]
-pip = ">=23.1.2"
-
-[package.extras]
-graphviz = ["graphviz (>=0.20.1)"]
-test = ["covdefaults (>=2.3)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "virtualenv (>=20.25,<21)"]
-
[[package]]
name = "platformdirs"
version = "4.3.6"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"},
{file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"},
@@ -1483,6 +1564,8 @@ version = "1.49.1"
description = "A high-level API to automate web browsers"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "playwright-1.49.1-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:1041ffb45a0d0bc44d698d3a5aa3ac4b67c9bd03540da43a0b70616ad52592b8"},
{file = "playwright-1.49.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:9f38ed3d0c1f4e0a6d1c92e73dd9a61f8855133249d6f0cec28648d38a7137be"},
@@ -1503,6 +1586,8 @@ version = "5.24.1"
description = "An open-source, interactive data visualization library for Python"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "plotly-5.24.1-py3-none-any.whl", hash = "sha256:f67073a1e637eb0dc3e46324d9d51e2fe76e9727c892dde64ddf1e1b51f29089"},
{file = "plotly-5.24.1.tar.gz", hash = "sha256:dbc8ac8339d248a4bcc36e08a5659bacfe1b079390b8953533f4eb22169b4bae"},
@@ -1518,6 +1603,8 @@ version = "1.5.0"
description = "plugin and hook calling mechanisms for python"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
{file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
@@ -1533,6 +1620,8 @@ version = "4.1.0"
description = "A framework for managing and maintaining multi-language pre-commit hooks."
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b"},
{file = "pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4"},
@@ -1551,6 +1640,8 @@ version = "6.1.1"
description = "Cross-platform lib for process and system monitoring in Python."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "psutil-6.1.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9ccc4316f24409159897799b83004cb1e24f9819b0dcf9c0b68bdcb6cefee6a8"},
{file = "psutil-6.1.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ca9609c77ea3b8481ab005da74ed894035936223422dc591d6772b147421f777"},
@@ -1581,6 +1672,8 @@ version = "9.0.0"
description = "Get CPU info with pure Python"
optional = false
python-versions = "*"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690"},
{file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"},
@@ -1592,20 +1685,24 @@ version = "2.22"
description = "C parser in Python"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
files = [
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
]
+markers = {main = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\" and (python_version <= \"3.11\" or python_version >= \"3.12\")", dev = "python_version <= \"3.11\" or python_version >= \"3.12\""}
[[package]]
name = "pydantic"
-version = "2.10.5"
+version = "2.10.6"
description = "Data validation using Python type hints"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
- {file = "pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"},
- {file = "pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff"},
+ {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"},
+ {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"},
]
[package.dependencies]
@@ -1623,6 +1720,8 @@ version = "2.27.2"
description = "Core functionality for Pydantic validation and serialization"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"},
{file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"},
@@ -1735,6 +1834,8 @@ version = "12.0.0"
description = "A rough port of Node.js's EventEmitter to Python with a few tricks of its own"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pyee-12.0.0-py3-none-any.whl", hash = "sha256:7b14b74320600049ccc7d0e0b1becd3b4bd0a03c745758225e31a59f4095c990"},
{file = "pyee-12.0.0.tar.gz", hash = "sha256:c480603f4aa2927d4766eb41fa82793fe60a82cbfdb8d688e0d08c55a534e145"},
@@ -1752,6 +1853,8 @@ version = "2.19.1"
description = "Pygments is a syntax highlighting package written in Python."
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"},
{file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"},
@@ -1766,6 +1869,8 @@ version = "1.2.0"
description = "Wrappers to call pyproject.toml-based build backend hooks."
optional = false
python-versions = ">=3.7"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"},
{file = "pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8"},
@@ -1777,6 +1882,8 @@ version = "1.1.392.post0"
description = "Command line wrapper for pyright"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pyright-1.1.392.post0-py3-none-any.whl", hash = "sha256:252f84458a46fa2f0fd4e2f91fc74f50b9ca52c757062e93f6c250c0d8329eb2"},
{file = "pyright-1.1.392.post0.tar.gz", hash = "sha256:3b7f88de74a28dcfa90c7d90c782b6569a48c2be5f9d4add38472bdaac247ebd"},
@@ -1797,6 +1904,8 @@ version = "1.7.1"
description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information."
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "PySocks-1.7.1-py27-none-any.whl", hash = "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299"},
{file = "PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"},
@@ -1809,6 +1918,8 @@ version = "8.3.4"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"},
{file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"},
@@ -1827,13 +1938,15 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments
[[package]]
name = "pytest-asyncio"
-version = "0.25.2"
+version = "0.25.3"
description = "Pytest support for asyncio"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
- {file = "pytest_asyncio-0.25.2-py3-none-any.whl", hash = "sha256:0d0bb693f7b99da304a0634afc0a4b19e49d5e0de2d670f38dc4bfa5727c5075"},
- {file = "pytest_asyncio-0.25.2.tar.gz", hash = "sha256:3f8ef9a98f45948ea91a0ed3dc4268b5326c0e7bce73892acc654df4262ad45f"},
+ {file = "pytest_asyncio-0.25.3-py3-none-any.whl", hash = "sha256:9e89518e0f9bd08928f97a3482fdc4e244df17529460bc038291ccaf8f85c7c3"},
+ {file = "pytest_asyncio-0.25.3.tar.gz", hash = "sha256:fc1da2cf9f125ada7e710b4ddad05518d4cee187ae9412e9ac9271003497f07a"},
]
[package.dependencies]
@@ -1849,6 +1962,8 @@ version = "2.1.0"
description = "pytest plugin for URL based testing"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pytest_base_url-2.1.0-py3-none-any.whl", hash = "sha256:3ad15611778764d451927b2a53240c1a7a591b521ea44cebfe45849d2d2812e6"},
{file = "pytest_base_url-2.1.0.tar.gz", hash = "sha256:02748589a54f9e63fcbe62301d6b0496da0d10231b753e950c63e03aee745d45"},
@@ -1867,6 +1982,8 @@ version = "5.1.0"
description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer."
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pytest-benchmark-5.1.0.tar.gz", hash = "sha256:9ea661cdc292e8231f7cd4c10b0319e56a2118e2c09d9f50e1b3d150d2aca105"},
{file = "pytest_benchmark-5.1.0-py3-none-any.whl", hash = "sha256:922de2dfa3033c227c96da942d1878191afa135a29485fb942e85dff1c592c89"},
@@ -1881,12 +1998,47 @@ aspect = ["aspectlib"]
elasticsearch = ["elasticsearch"]
histogram = ["pygal", "pygaljs", "setuptools"]
+[[package]]
+name = "pytest-codspeed"
+version = "3.1.2"
+description = "Pytest plugin to create CodSpeed benchmarks"
+optional = false
+python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
+files = [
+ {file = "pytest_codspeed-3.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aed496f873670ce0ea8f980a7c1a2c6a08f415e0ebdf207bf651b2d922103374"},
+ {file = "pytest_codspeed-3.1.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee45b0b763f6b5fa5d74c7b91d694a9615561c428b320383660672f4471756e3"},
+ {file = "pytest_codspeed-3.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c84e591a7a0f67d45e2dc9fd05b276971a3aabcab7478fe43363ebefec1358f4"},
+ {file = "pytest_codspeed-3.1.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6ae6d094247156407770e6b517af70b98862dd59a3c31034aede11d5f71c32c"},
+ {file = "pytest_codspeed-3.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d0f264991de5b5cdc118b96fc671386cca3f0f34e411482939bf2459dc599097"},
+ {file = "pytest_codspeed-3.1.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c0695a4bcd5ff04e8379124dba5d9795ea5e0cadf38be7a0406432fc1467b555"},
+ {file = "pytest_codspeed-3.1.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6dc356c8dcaaa883af83310f397ac06c96fac9b8a1146e303d4b374b2cb46a18"},
+ {file = "pytest_codspeed-3.1.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cc8a5d0366322a75cf562f7d8d672d28c1cf6948695c4dddca50331e08f6b3d5"},
+ {file = "pytest_codspeed-3.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c5fe7a19b72f54f217480b3b527102579547b1de9fe3acd9e66cb4629ff46c8"},
+ {file = "pytest_codspeed-3.1.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b67205755a665593f6521a98317d02a9d07d6fdc593f6634de2c94dea47a3055"},
+ {file = "pytest_codspeed-3.1.2-py3-none-any.whl", hash = "sha256:5e7ed0315e33496c5c07dba262b50303b8d0bc4c3d10bf1d422a41e70783f1cb"},
+ {file = "pytest_codspeed-3.1.2.tar.gz", hash = "sha256:09c1733af3aab35e94a621aa510f2d2114f65591e6f644c42ca3f67547edad4b"},
+]
+
+[package.dependencies]
+cffi = ">=1.17.1"
+pytest = ">=3.8"
+rich = ">=13.8.1"
+
+[package.extras]
+compat = ["pytest-benchmark (>=5.0.0,<5.1.0)", "pytest-xdist (>=3.6.1,<3.7.0)"]
+lint = ["mypy (>=1.11.2,<1.12.0)", "ruff (>=0.6.5,<0.7.0)"]
+test = ["pytest (>=7.0,<8.0)", "pytest-cov (>=4.0.0,<4.1.0)"]
+
[[package]]
name = "pytest-cov"
version = "6.0.0"
description = "Pytest plugin for measuring coverage."
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"},
{file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"},
@@ -1905,6 +2057,8 @@ version = "3.14.0"
description = "Thin-wrapper around the mock package for easier use with pytest"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"},
{file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"},
@@ -1922,6 +2076,8 @@ version = "0.6.2"
description = "A pytest wrapper with fixtures for Playwright to automate web browsers"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pytest_playwright-0.6.2-py3-none-any.whl", hash = "sha256:0eff73bebe497b0158befed91e2f5fe94cfa17181f8b3acf575beed84e7e9043"},
{file = "pytest_playwright-0.6.2.tar.gz", hash = "sha256:ff4054b19aa05df096ac6f74f0572591566aaf0f6d97f6cb9674db8a4d4ed06c"},
@@ -1939,6 +2095,8 @@ version = "2.9.0.post0"
description = "Extensions to the standard Python datetime module"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
{file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
@@ -1953,6 +2111,8 @@ version = "4.11.2"
description = "Engine.IO server and client for Python"
optional = false
python-versions = ">=3.6"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "python_engineio-4.11.2-py3-none-any.whl", hash = "sha256:f0971ac4c65accc489154fe12efd88f53ca8caf04754c46a66e85f5102ef22ad"},
{file = "python_engineio-4.11.2.tar.gz", hash = "sha256:145bb0daceb904b4bb2d3eb2d93f7dbb7bb87a6a0c4f20a94cc8654dec977129"},
@@ -1972,6 +2132,8 @@ version = "0.0.20"
description = "A streaming multipart parser for Python"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104"},
{file = "python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13"},
@@ -1983,6 +2145,8 @@ version = "8.0.4"
description = "A Python slugify application that also handles Unicode"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856"},
{file = "python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8"},
@@ -2000,6 +2164,8 @@ version = "5.12.1"
description = "Socket.IO server and client for Python"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "python_socketio-5.12.1-py3-none-any.whl", hash = "sha256:24a0ea7cfff0e021eb28c68edbf7914ee4111bdf030b95e4d250c4dc9af7a386"},
{file = "python_socketio-5.12.1.tar.gz", hash = "sha256:0299ff1f470b676c09c1bfab1dead25405077d227b2c13cf217a34dadc68ba9c"},
@@ -2020,6 +2186,8 @@ version = "2024.2"
description = "World timezone definitions, modern and historical"
optional = false
python-versions = "*"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"},
{file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"},
@@ -2031,6 +2199,8 @@ version = "0.2.3"
description = "A (partial) reimplementation of pywin32 using ctypes/cffi"
optional = false
python-versions = ">=3.6"
+groups = ["main"]
+markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"win32\" and (python_version <= \"3.11\" or python_version >= \"3.12\")"
files = [
{file = "pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"},
{file = "pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"},
@@ -2042,6 +2212,8 @@ version = "6.0.2"
description = "YAML parser and emitter for Python"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
{file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
@@ -2104,6 +2276,8 @@ version = "44.0"
description = "readme_renderer is a library for rendering readme descriptions for Warehouse"
optional = false
python-versions = ">=3.9"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "readme_renderer-44.0-py3-none-any.whl", hash = "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151"},
{file = "readme_renderer-44.0.tar.gz", hash = "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1"},
@@ -2123,6 +2297,8 @@ version = "5.2.1"
description = "Python client for Redis database and key-value store"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "redis-5.2.1-py3-none-any.whl", hash = "sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4"},
{file = "redis-5.2.1.tar.gz", hash = "sha256:16f2e22dff21d5125e8481515e386711a34cbec50f0e44413dd7d9c060a54e0f"},
@@ -2137,27 +2313,26 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==23.2.1)", "requests (>=2.31.0)"
[[package]]
name = "reflex-hosting-cli"
-version = "0.1.32"
+version = "0.1.33"
description = "Reflex Hosting CLI"
optional = false
-python-versions = "<4.0,>=3.8"
+python-versions = "<4.0,>=3.9"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
- {file = "reflex_hosting_cli-0.1.32-py3-none-any.whl", hash = "sha256:86b4222f3e99d949a209be7de8c457ededebc1f12a721ee6669c6c35fdecc508"},
- {file = "reflex_hosting_cli-0.1.32.tar.gz", hash = "sha256:0b8e4b4b30d9261bf6d720265f1c428b2840bb630896e60a1a2faa095901ed59"},
+ {file = "reflex_hosting_cli-0.1.33-py3-none-any.whl", hash = "sha256:3fe72fc448a231c61de4ac646f42c936c70e91330f616a23aec658f905d53bc4"},
+ {file = "reflex_hosting_cli-0.1.33.tar.gz", hash = "sha256:81c4a896b106eea99f1cab53ea23a6e19802592ce0468cc38d93d440bc95263a"},
]
[package.dependencies]
charset-normalizer = ">=3.3.2,<4.0.0"
httpx = ">=0.25.1,<1.0"
-pipdeptree = ">=2.13.1,<2.17.0"
platformdirs = ">=3.10.0,<5.0"
pydantic = ">=1.10.2,<3.0"
-python-dateutil = ">=2.8.1"
pyyaml = ">=6.0.2,<7.0.0"
rich = ">=13.0.0,<14.0"
tabulate = ">=0.9.0,<0.10.0"
typer = ">=0.15.0,<1"
-websockets = ">=10.4"
[[package]]
name = "requests"
@@ -2165,6 +2340,8 @@ version = "2.32.3"
description = "Python HTTP for Humans."
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
@@ -2186,6 +2363,8 @@ version = "1.0.0"
description = "A utility belt for advanced users of python-requests"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"},
{file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"},
@@ -2200,6 +2379,8 @@ version = "2.0.0"
description = "Validating URI References per RFC 3986"
optional = false
python-versions = ">=3.7"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"},
{file = "rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"},
@@ -2214,6 +2395,8 @@ version = "13.9.4"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
optional = false
python-versions = ">=3.8.0"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"},
{file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"},
@@ -2233,6 +2416,8 @@ version = "0.8.2"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "ruff-0.8.2-py3-none-linux_armv6l.whl", hash = "sha256:c49ab4da37e7c457105aadfd2725e24305ff9bc908487a9bf8d548c6dad8bb3d"},
{file = "ruff-0.8.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ec016beb69ac16be416c435828be702ee694c0d722505f9c1f35e1b9c0cc1bf5"},
@@ -2260,6 +2445,8 @@ version = "3.3.3"
description = "Python bindings to FreeDesktop.org Secret Service API"
optional = false
python-versions = ">=3.6"
+groups = ["main"]
+markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\" and (python_version <= \"3.11\" or python_version >= \"3.12\")"
files = [
{file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"},
{file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"},
@@ -2271,13 +2458,15 @@ jeepney = ">=0.6"
[[package]]
name = "selenium"
-version = "4.28.0"
+version = "4.28.1"
description = "Official Python bindings for Selenium WebDriver"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
- {file = "selenium-4.28.0-py3-none-any.whl", hash = "sha256:3d6a2e8e1b850a1078884ea19f4e011ecdc12263434d87a0b78769836fb82dd8"},
- {file = "selenium-4.28.0.tar.gz", hash = "sha256:a9fae6eef48d470a1b0c6e45185d96f0dafb025e8da4b346cc41e4da3ac54fa0"},
+ {file = "selenium-4.28.1-py3-none-any.whl", hash = "sha256:4238847e45e24e4472cfcf3554427512c7aab9443396435b1623ef406fff1cc1"},
+ {file = "selenium-4.28.1.tar.gz", hash = "sha256:0072d08670d7ec32db901bd0107695a330cecac9f196e3afb3fa8163026e022a"},
]
[package.dependencies]
@@ -2294,6 +2483,8 @@ version = "75.8.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.9"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3"},
{file = "setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6"},
@@ -2314,6 +2505,8 @@ version = "1.5.4"
description = "Tool to Detect Surrounding Shell"
optional = false
python-versions = ">=3.7"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"},
{file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"},
@@ -2325,6 +2518,8 @@ version = "1.1.0"
description = "Simple WebSocket server and client for Python"
optional = false
python-versions = ">=3.6"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "simple_websocket-1.1.0-py3-none-any.whl", hash = "sha256:4af6069630a38ed6c561010f0e11a5bc0d4ca569b36306eb257cd9a192497c8c"},
{file = "simple_websocket-1.1.0.tar.gz", hash = "sha256:7939234e7aa067c534abdab3a9ed933ec9ce4691b0713c78acb195560aa52ae4"},
@@ -2343,6 +2538,8 @@ version = "1.17.0"
description = "Python 2 and 3 compatibility utilities"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
{file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
@@ -2354,6 +2551,8 @@ version = "1.3.1"
description = "Sniff out which async library your code is running under"
optional = false
python-versions = ">=3.7"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
@@ -2365,6 +2564,8 @@ version = "2.4.0"
description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set"
optional = false
python-versions = "*"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"},
{file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"},
@@ -2376,6 +2577,8 @@ version = "2.0.37"
description = "Database Abstraction Library"
optional = false
python-versions = ">=3.7"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "SQLAlchemy-2.0.37-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da36c3b0e891808a7542c5c89f224520b9a16c7f5e4d6a1156955605e54aef0e"},
{file = "SQLAlchemy-2.0.37-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e7402ff96e2b073a98ef6d6142796426d705addd27b9d26c3b32dbaa06d7d069"},
@@ -2457,6 +2660,8 @@ version = "0.0.22"
description = "SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness."
optional = false
python-versions = ">=3.7"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b"},
{file = "sqlmodel-0.0.22.tar.gz", hash = "sha256:7d37c882a30c43464d143e35e9ecaf945d88035e20117bf5ec2834a23cbe505e"},
@@ -2468,20 +2673,22 @@ SQLAlchemy = ">=2.0.14,<2.1.0"
[[package]]
name = "starlette"
-version = "0.41.3"
+version = "0.45.3"
description = "The little ASGI library that shines."
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
- {file = "starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7"},
- {file = "starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835"},
+ {file = "starlette-0.45.3-py3-none-any.whl", hash = "sha256:dfb6d332576f136ec740296c7e8bb8c8a7125044e7c6da30744718880cdd059d"},
+ {file = "starlette-0.45.3.tar.gz", hash = "sha256:2cbcba2a75806f8a41c722141486f37c28e30a0921c5f6fe4346cb0dcee1302f"},
]
[package.dependencies]
-anyio = ">=3.4.0,<5"
+anyio = ">=3.6.2,<5"
[package.extras]
-full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"]
+full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"]
[[package]]
name = "starlette-admin"
@@ -2489,6 +2696,8 @@ version = "0.14.1"
description = "Fast, beautiful and extensible administrative interface framework for Starlette/FastApi applications"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "starlette_admin-0.14.1-py3-none-any.whl", hash = "sha256:5b6260d7ed3db455585852d669feb7ed9a8c5f9a1e3d48d21a52912ec37e18f9"},
{file = "starlette_admin-0.14.1.tar.gz", hash = "sha256:45e2baa3b9a8deec7a6e8ca9295123f648bb0d2070abe68f27193c6d5e32cc38"},
@@ -2512,6 +2721,8 @@ version = "0.9.0"
description = "Pretty-print tabular data"
optional = false
python-versions = ">=3.7"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"},
{file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"},
@@ -2526,6 +2737,8 @@ version = "9.0.0"
description = "Retry code until it succeeds"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"},
{file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"},
@@ -2541,6 +2754,8 @@ version = "1.3"
description = "The most basic Text::Unidecode port"
optional = false
python-versions = "*"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"},
{file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"},
@@ -2552,6 +2767,8 @@ version = "0.10.2"
description = "Python Library for Tom's Obvious, Minimal Language"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
@@ -2563,6 +2780,8 @@ version = "2.2.1"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
+markers = "python_version < \"3.11\""
files = [
{file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
{file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
@@ -2604,6 +2823,8 @@ version = "0.13.2"
description = "Style preserving TOML library"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"},
{file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"},
@@ -2615,6 +2836,8 @@ version = "0.28.0"
description = "A friendly Python library for async concurrency and I/O"
optional = false
python-versions = ">=3.9"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "trio-0.28.0-py3-none-any.whl", hash = "sha256:56d58977acc1635735a96581ec70513cc781b8b6decd299c487d3be2a721cd94"},
{file = "trio-0.28.0.tar.gz", hash = "sha256:4e547896fe9e8a5658e54e4c7c5fa1db748cbbbaa7c965e7d40505b928c73c05"},
@@ -2635,6 +2858,8 @@ version = "0.11.1"
description = "WebSocket library for Trio"
optional = false
python-versions = ">=3.7"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "trio-websocket-0.11.1.tar.gz", hash = "sha256:18c11793647703c158b1f6e62de638acada927344d534e3c7628eedcb746839f"},
{file = "trio_websocket-0.11.1-py3-none-any.whl", hash = "sha256:520d046b0d030cf970b8b2b2e00c4c2245b3807853ecd44214acd33d74581638"},
@@ -2651,6 +2876,8 @@ version = "6.1.0"
description = "Collection of utilities for publishing packages on PyPI"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "twine-6.1.0-py3-none-any.whl", hash = "sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384"},
{file = "twine-6.1.0.tar.gz", hash = "sha256:be324f6272eff91d07ee93f251edf232fc647935dd585ac003539b42404a8dbd"},
@@ -2676,6 +2903,8 @@ version = "0.15.1"
description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
optional = false
python-versions = ">=3.7"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "typer-0.15.1-py3-none-any.whl", hash = "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847"},
{file = "typer-0.15.1.tar.gz", hash = "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a"},
@@ -2693,6 +2922,8 @@ version = "4.12.2"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
@@ -2704,6 +2935,8 @@ version = "2025.1"
description = "Provider of IANA time zone data"
optional = false
python-versions = ">=2"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"},
{file = "tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694"},
@@ -2715,6 +2948,8 @@ version = "2.3.0"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.9"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"},
{file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"},
@@ -2735,6 +2970,8 @@ version = "0.34.0"
description = "The lightning-fast ASGI server."
optional = false
python-versions = ">=3.9"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4"},
{file = "uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9"},
@@ -2754,6 +2991,8 @@ version = "20.29.1"
description = "Virtual Python Environment builder"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "virtualenv-20.29.1-py3-none-any.whl", hash = "sha256:4e4cb403c0b0da39e13b46b1b2476e505cb0046b25f242bee80f62bf990b2779"},
{file = "virtualenv-20.29.1.tar.gz", hash = "sha256:b8b8970138d32fb606192cb97f6cd4bb644fa486be9308fb9b63f81091b5dc35"},
@@ -2774,6 +3013,8 @@ version = "1.8.0"
description = "WebSocket client for Python with low level API options"
optional = false
python-versions = ">=3.8"
+groups = ["dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526"},
{file = "websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da"},
@@ -2784,90 +3025,14 @@ docs = ["Sphinx (>=6.0)", "myst-parser (>=2.0.0)", "sphinx-rtd-theme (>=1.1.0)"]
optional = ["python-socks", "wsaccel"]
test = ["websockets"]
-[[package]]
-name = "websockets"
-version = "14.2"
-description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
-optional = false
-python-versions = ">=3.9"
-files = [
- {file = "websockets-14.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e8179f95323b9ab1c11723e5d91a89403903f7b001828161b480a7810b334885"},
- {file = "websockets-14.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d8c3e2cdb38f31d8bd7d9d28908005f6fa9def3324edb9bf336d7e4266fd397"},
- {file = "websockets-14.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:714a9b682deb4339d39ffa674f7b674230227d981a37d5d174a4a83e3978a610"},
- {file = "websockets-14.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e53c72052f2596fb792a7acd9704cbc549bf70fcde8a99e899311455974ca3"},
- {file = "websockets-14.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3fbd68850c837e57373d95c8fe352203a512b6e49eaae4c2f4088ef8cf21980"},
- {file = "websockets-14.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b27ece32f63150c268593d5fdb82819584831a83a3f5809b7521df0685cd5d8"},
- {file = "websockets-14.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4daa0faea5424d8713142b33825fff03c736f781690d90652d2c8b053345b0e7"},
- {file = "websockets-14.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:bc63cee8596a6ec84d9753fd0fcfa0452ee12f317afe4beae6b157f0070c6c7f"},
- {file = "websockets-14.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a570862c325af2111343cc9b0257b7119b904823c675b22d4ac547163088d0d"},
- {file = "websockets-14.2-cp310-cp310-win32.whl", hash = "sha256:75862126b3d2d505e895893e3deac0a9339ce750bd27b4ba515f008b5acf832d"},
- {file = "websockets-14.2-cp310-cp310-win_amd64.whl", hash = "sha256:cc45afb9c9b2dc0852d5c8b5321759cf825f82a31bfaf506b65bf4668c96f8b2"},
- {file = "websockets-14.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3bdc8c692c866ce5fefcaf07d2b55c91d6922ac397e031ef9b774e5b9ea42166"},
- {file = "websockets-14.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c93215fac5dadc63e51bcc6dceca72e72267c11def401d6668622b47675b097f"},
- {file = "websockets-14.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c9b6535c0e2cf8a6bf938064fb754aaceb1e6a4a51a80d884cd5db569886910"},
- {file = "websockets-14.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a52a6d7cf6938e04e9dceb949d35fbdf58ac14deea26e685ab6368e73744e4c"},
- {file = "websockets-14.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f05702e93203a6ff5226e21d9b40c037761b2cfb637187c9802c10f58e40473"},
- {file = "websockets-14.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22441c81a6748a53bfcb98951d58d1af0661ab47a536af08920d129b4d1c3473"},
- {file = "websockets-14.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd9b868d78b194790e6236d9cbc46d68aba4b75b22497eb4ab64fa640c3af56"},
- {file = "websockets-14.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1a5a20d5843886d34ff8c57424cc65a1deda4375729cbca4cb6b3353f3ce4142"},
- {file = "websockets-14.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:34277a29f5303d54ec6468fb525d99c99938607bc96b8d72d675dee2b9f5bf1d"},
- {file = "websockets-14.2-cp311-cp311-win32.whl", hash = "sha256:02687db35dbc7d25fd541a602b5f8e451a238ffa033030b172ff86a93cb5dc2a"},
- {file = "websockets-14.2-cp311-cp311-win_amd64.whl", hash = "sha256:862e9967b46c07d4dcd2532e9e8e3c2825e004ffbf91a5ef9dde519ee2effb0b"},
- {file = "websockets-14.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1f20522e624d7ffbdbe259c6b6a65d73c895045f76a93719aa10cd93b3de100c"},
- {file = "websockets-14.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:647b573f7d3ada919fd60e64d533409a79dcf1ea21daeb4542d1d996519ca967"},
- {file = "websockets-14.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6af99a38e49f66be5a64b1e890208ad026cda49355661549c507152113049990"},
- {file = "websockets-14.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:091ab63dfc8cea748cc22c1db2814eadb77ccbf82829bac6b2fbe3401d548eda"},
- {file = "websockets-14.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b374e8953ad477d17e4851cdc66d83fdc2db88d9e73abf755c94510ebddceb95"},
- {file = "websockets-14.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a39d7eceeea35db85b85e1169011bb4321c32e673920ae9c1b6e0978590012a3"},
- {file = "websockets-14.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a6f3efd47ffd0d12080594f434faf1cd2549b31e54870b8470b28cc1d3817d9"},
- {file = "websockets-14.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:065ce275e7c4ffb42cb738dd6b20726ac26ac9ad0a2a48e33ca632351a737267"},
- {file = "websockets-14.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e9d0e53530ba7b8b5e389c02282f9d2aa47581514bd6049d3a7cffe1385cf5fe"},
- {file = "websockets-14.2-cp312-cp312-win32.whl", hash = "sha256:20e6dd0984d7ca3037afcb4494e48c74ffb51e8013cac71cf607fffe11df7205"},
- {file = "websockets-14.2-cp312-cp312-win_amd64.whl", hash = "sha256:44bba1a956c2c9d268bdcdf234d5e5ff4c9b6dc3e300545cbe99af59dda9dcce"},
- {file = "websockets-14.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f1372e511c7409a542291bce92d6c83320e02c9cf392223272287ce55bc224e"},
- {file = "websockets-14.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4da98b72009836179bb596a92297b1a61bb5a830c0e483a7d0766d45070a08ad"},
- {file = "websockets-14.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8a86a269759026d2bde227652b87be79f8a734e582debf64c9d302faa1e9f03"},
- {file = "websockets-14.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86cf1aaeca909bf6815ea714d5c5736c8d6dd3a13770e885aafe062ecbd04f1f"},
- {file = "websockets-14.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b0f6c3ba3b1240f602ebb3971d45b02cc12bd1845466dd783496b3b05783a5"},
- {file = "websockets-14.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669c3e101c246aa85bc8534e495952e2ca208bd87994650b90a23d745902db9a"},
- {file = "websockets-14.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eabdb28b972f3729348e632ab08f2a7b616c7e53d5414c12108c29972e655b20"},
- {file = "websockets-14.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2066dc4cbcc19f32c12a5a0e8cc1b7ac734e5b64ac0a325ff8353451c4b15ef2"},
- {file = "websockets-14.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ab95d357cd471df61873dadf66dd05dd4709cae001dd6342edafc8dc6382f307"},
- {file = "websockets-14.2-cp313-cp313-win32.whl", hash = "sha256:a9e72fb63e5f3feacdcf5b4ff53199ec8c18d66e325c34ee4c551ca748623bbc"},
- {file = "websockets-14.2-cp313-cp313-win_amd64.whl", hash = "sha256:b439ea828c4ba99bb3176dc8d9b933392a2413c0f6b149fdcba48393f573377f"},
- {file = "websockets-14.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7cd5706caec1686c5d233bc76243ff64b1c0dc445339bd538f30547e787c11fe"},
- {file = "websockets-14.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ec607328ce95a2f12b595f7ae4c5d71bf502212bddcea528290b35c286932b12"},
- {file = "websockets-14.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da85651270c6bfb630136423037dd4975199e5d4114cae6d3066641adcc9d1c7"},
- {file = "websockets-14.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ecadc7ce90accf39903815697917643f5b7cfb73c96702318a096c00aa71f5"},
- {file = "websockets-14.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1979bee04af6a78608024bad6dfcc0cc930ce819f9e10342a29a05b5320355d0"},
- {file = "websockets-14.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dddacad58e2614a24938a50b85969d56f88e620e3f897b7d80ac0d8a5800258"},
- {file = "websockets-14.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:89a71173caaf75fa71a09a5f614f450ba3ec84ad9fca47cb2422a860676716f0"},
- {file = "websockets-14.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6af6a4b26eea4fc06c6818a6b962a952441e0e39548b44773502761ded8cc1d4"},
- {file = "websockets-14.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:80c8efa38957f20bba0117b48737993643204645e9ec45512579132508477cfc"},
- {file = "websockets-14.2-cp39-cp39-win32.whl", hash = "sha256:2e20c5f517e2163d76e2729104abc42639c41cf91f7b1839295be43302713661"},
- {file = "websockets-14.2-cp39-cp39-win_amd64.whl", hash = "sha256:b4c8cef610e8d7c70dea92e62b6814a8cd24fbd01d7103cc89308d2bfe1659ef"},
- {file = "websockets-14.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d7d9cafbccba46e768be8a8ad4635fa3eae1ffac4c6e7cb4eb276ba41297ed29"},
- {file = "websockets-14.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c76193c1c044bd1e9b3316dcc34b174bbf9664598791e6fb606d8d29000e070c"},
- {file = "websockets-14.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd475a974d5352390baf865309fe37dec6831aafc3014ffac1eea99e84e83fc2"},
- {file = "websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c6c0097a41968b2e2b54ed3424739aab0b762ca92af2379f152c1aef0187e1c"},
- {file = "websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d7ff794c8b36bc402f2e07c0b2ceb4a2424147ed4785ff03e2a7af03711d60a"},
- {file = "websockets-14.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dec254fcabc7bd488dab64846f588fc5b6fe0d78f641180030f8ea27b76d72c3"},
- {file = "websockets-14.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bbe03eb853e17fd5b15448328b4ec7fb2407d45fb0245036d06a3af251f8e48f"},
- {file = "websockets-14.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3c4aa3428b904d5404a0ed85f3644d37e2cb25996b7f096d77caeb0e96a3b42"},
- {file = "websockets-14.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:577a4cebf1ceaf0b65ffc42c54856214165fb8ceeba3935852fc33f6b0c55e7f"},
- {file = "websockets-14.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad1c1d02357b7665e700eca43a31d52814ad9ad9b89b58118bdabc365454b574"},
- {file = "websockets-14.2-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f390024a47d904613577df83ba700bd189eedc09c57af0a904e5c39624621270"},
- {file = "websockets-14.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3c1426c021c38cf92b453cdf371228d3430acd775edee6bac5a4d577efc72365"},
- {file = "websockets-14.2-py3-none-any.whl", hash = "sha256:7a6ceec4ea84469f15cf15807a747e9efe57e369c384fa86e022b3bea679b79b"},
- {file = "websockets-14.2.tar.gz", hash = "sha256:5059ed9c54945efb321f097084b4c7e52c246f2c869815876a69d1efc4ad6eb5"},
-]
-
[[package]]
name = "wheel"
version = "0.45.1"
description = "A built-package format for Python"
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248"},
{file = "wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729"},
@@ -2882,6 +3047,8 @@ version = "1.17.2"
description = "Module for decorators, wrappers and monkey patching."
optional = false
python-versions = ">=3.8"
+groups = ["main"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984"},
{file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22"},
@@ -2970,6 +3137,8 @@ version = "1.2.0"
description = "WebSockets state-machine based protocol implementation"
optional = false
python-versions = ">=3.7.0"
+groups = ["main", "dev"]
+markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"},
{file = "wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065"},
@@ -2984,6 +3153,8 @@ version = "3.21.0"
description = "Backport of pathlib-compatible object wrapper for zip files"
optional = false
python-versions = ">=3.9"
+groups = ["main"]
+markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and python_version <= \"3.11\" or python_full_version < \"3.10.2\""
files = [
{file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"},
{file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"},
@@ -2998,6 +3169,6 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools",
type = ["pytest-mypy"]
[metadata]
-lock-version = "2.0"
-python-versions = "^3.10"
-content-hash = "06172aec112c6b3a49ffa42eadf09cb66408df76bcfcec8439396590f9a4c8d5"
+lock-version = "2.1"
+python-versions = ">=3.10, <4.0"
+content-hash = "822150bcbf41e5cbb61da0a059b41d8971e3c6c974c8af4be7ef55126648aea1"
diff --git a/pyproject.toml b/pyproject.toml
index ea3905f9c..966cc5e2a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -18,7 +18,7 @@ keywords = ["web", "framework"]
classifiers = ["Development Status :: 4 - Beta"]
[tool.poetry.dependencies]
-python = "^3.10"
+python = ">=3.10, <4.0"
fastapi = ">=0.96.0,!=0.111.0,!=0.111.1"
gunicorn = ">=20.1.0,<24.0"
jinja2 = ">=3.1.2,<4.0"
@@ -71,6 +71,7 @@ selenium = ">=4.11.0,<5.0"
pytest-benchmark = ">=4.0.0,<6.0"
playwright = ">=1.46.0"
pytest-playwright = ">=0.5.1"
+pytest-codspeed = "^3.1.2"
[tool.poetry.scripts]
reflex = "reflex.reflex:cli"
@@ -81,22 +82,21 @@ build-backend = "poetry.core.masonry.api"
[tool.pyright]
reportIncompatibleMethodOverride = false
-reportIncompatibleVariableOverride = false
[tool.ruff]
-target-version = "py39"
+target-version = "py310"
output-format = "concise"
lint.isort.split-on-trailing-comma = false
-lint.select = ["B", "C4", "D", "E", "ERA", "F", "FURB", "I", "N", "PERF", "PTH", "RUF", "SIM", "T", "TRY", "W"]
+lint.select = ["ANN001","B", "C4", "D", "E", "ERA", "F", "FURB", "I", "N", "PERF", "PGH", "PTH", "RUF", "SIM", "T", "TRY", "W"]
lint.ignore = ["B008", "D205", "E501", "F403", "SIM115", "RUF006", "RUF012", "TRY0"]
lint.pydocstyle.convention = "google"
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]
-"tests/*.py" = ["D100", "D103", "D104", "B018", "PERF", "T", "N"]
-"benchmarks/*.py" = ["D100", "D103", "D104", "B018", "PERF", "T", "N"]
+"tests/*.py" = ["ANN001", "D100", "D103", "D104", "B018", "PERF", "T", "N"]
+"benchmarks/*.py" = ["ANN001", "D100", "D103", "D104", "B018", "PERF", "T", "N"]
"reflex/.templates/*.py" = ["D100", "D103", "D104"]
-"*.pyi" = ["D301", "D415", "D417", "D418", "E742", "N"]
+"*.pyi" = ["D301", "D415", "D417", "D418", "E742", "N", "PGH"]
"pyi_generator.py" = ["N802"]
"reflex/constants/*.py" = ["N"]
"*/blank.py" = ["I001"]
diff --git a/reflex/.templates/web/utils/state.js b/reflex/.templates/web/utils/state.js
index e5161a6dd..33bae9416 100644
--- a/reflex/.templates/web/utils/state.js
+++ b/reflex/.templates/web/utils/state.js
@@ -106,6 +106,18 @@ export const getBackendURL = (url_str) => {
return endpoint;
};
+/**
+ * Check if the backend is disabled.
+ *
+ * @returns True if the backend is disabled, false otherwise.
+ */
+export const isBackendDisabled = () => {
+ const cookie = document.cookie
+ .split("; ")
+ .find((row) => row.startsWith("backend-enabled="));
+ return cookie !== undefined && cookie.split("=")[1] == "false";
+};
+
/**
* Determine if any event in the event queue is stateful.
*
@@ -405,7 +417,7 @@ export const connect = async (
socket.current = io(endpoint.href, {
path: endpoint["pathname"],
transports: transports,
- protocols: env.TEST_MODE ? undefined : [reflexEnvironment.version],
+ protocols: [reflexEnvironment.version],
autoUnref: false,
});
// Ensure undefined fields in events are sent as null instead of removed
@@ -812,7 +824,7 @@ export const useEventLoop = (
return;
}
// only use websockets if state is present
- if (Object.keys(initialState).length > 1) {
+ if (Object.keys(initialState).length > 1 && !isBackendDisabled()) {
// Initialize the websocket connection.
if (!socket.current) {
connect(
diff --git a/reflex/__init__.py b/reflex/__init__.py
index 72089aca0..3209b505e 100644
--- a/reflex/__init__.py
+++ b/reflex/__init__.py
@@ -84,6 +84,9 @@ In the example above, you will be able to do `rx.list`
from __future__ import annotations
+from types import ModuleType
+from typing import Any
+
from reflex.utils import (
compat, # for side-effects
lazy_loader,
@@ -365,5 +368,5 @@ getattr, __dir__, __all__ = lazy_loader.attach(
)
-def __getattr__(name):
+def __getattr__(name: ModuleType | Any):
return getattr(name)
diff --git a/reflex/__init__.pyi b/reflex/__init__.pyi
index 1f9b4ecd8..5c80269ad 100644
--- a/reflex/__init__.pyi
+++ b/reflex/__init__.pyi
@@ -131,7 +131,7 @@ from .components.radix.themes.layout.container import container as container
from .components.radix.themes.layout.flex import flex as flex
from .components.radix.themes.layout.grid import grid as grid
from .components.radix.themes.layout.list import list_item as list_item
-from .components.radix.themes.layout.list import list_ns as list # noqa
+from .components.radix.themes.layout.list import list_ns as list # noqa: F401
from .components.radix.themes.layout.list import ordered_list as ordered_list
from .components.radix.themes.layout.list import unordered_list as unordered_list
from .components.radix.themes.layout.section import section as section
diff --git a/reflex/app.py b/reflex/app.py
index 5ee424719..ad123a655 100644
--- a/reflex/app.py
+++ b/reflex/app.py
@@ -27,6 +27,7 @@ from typing import (
Dict,
Generic,
List,
+ MutableMapping,
Optional,
Set,
Type,
@@ -58,7 +59,11 @@ from reflex.components.component import (
ComponentStyle,
evaluate_style_namespaces,
)
-from reflex.components.core.banner import connection_pulser, connection_toaster
+from reflex.components.core.banner import (
+ backend_disabled,
+ connection_pulser,
+ connection_toaster,
+)
from reflex.components.core.breakpoints import set_breakpoints
from reflex.components.core.client_side_routing import (
Default404Page,
@@ -145,7 +150,7 @@ def default_backend_exception_handler(exception: Exception) -> EventSpec:
position="top-center",
id="backend_error",
style={"width": "500px"},
- ) # type: ignore
+ ) # pyright: ignore [reportReturnType]
else:
error_message.insert(0, "An error occurred.")
return window_alert("\n".join(error_message))
@@ -157,9 +162,12 @@ def default_overlay_component() -> Component:
Returns:
The default overlay_component, which is a connection_modal.
"""
+ config = get_config()
+
return Fragment.create(
connection_pulser(),
connection_toaster(),
+ *([backend_disabled()] if config.is_reflex_cloud else []),
*codespaces.codespaces_auto_redirect(),
)
@@ -405,7 +413,36 @@ class App(MiddlewareMixin, LifespanMixin):
self.sio.register_namespace(self.event_namespace)
# Mount the socket app with the API.
if self.api:
- self.api.mount(str(constants.Endpoint.EVENT), socket_app)
+
+ class HeaderMiddleware:
+ def __init__(self, app: ASGIApp):
+ self.app = app
+
+ async def __call__(
+ self, scope: MutableMapping[str, Any], receive: Any, send: Callable
+ ):
+ original_send = send
+
+ async def modified_send(message: dict):
+ if message["type"] == "websocket.accept":
+ if scope.get("subprotocols"):
+ # The following *does* say "subprotocol" instead of "subprotocols", intentionally.
+ message["subprotocol"] = scope["subprotocols"][0]
+
+ headers = dict(message.get("headers", []))
+ header_key = b"sec-websocket-protocol"
+ if subprotocol := headers.get(header_key):
+ message["headers"] = [
+ *message.get("headers", []),
+ (header_key, subprotocol),
+ ]
+
+ return await original_send(message)
+
+ return await self.app(scope, receive, modified_send)
+
+ socket_app_with_headers = HeaderMiddleware(socket_app)
+ self.api.mount(str(constants.Endpoint.EVENT), socket_app_with_headers)
# Check the exception handlers
self._validate_exception_handlers()
@@ -648,7 +685,10 @@ class App(MiddlewareMixin, LifespanMixin):
for route in self._pages:
replaced_route = replace_brackets_with_keywords(route)
for rw, r, nr in zip(
- replaced_route.split("/"), route.split("/"), new_route.split("/")
+ replaced_route.split("/"),
+ route.split("/"),
+ new_route.split("/"),
+ strict=False,
):
if rw in segments and r != nr:
# If the slugs in the segments of both routes are not the same, then the route is invalid
@@ -679,8 +719,8 @@ class App(MiddlewareMixin, LifespanMixin):
Args:
component: The component to display at the page.
title: The title of the page.
- description: The description of the page.
image: The image to display on the page.
+ description: The description of the page.
on_load: The event handler(s) that will be called each time the page load.
meta: The metadata of the page.
"""
@@ -747,7 +787,7 @@ class App(MiddlewareMixin, LifespanMixin):
frontend_packages = get_config().frontend_packages
_frontend_packages = []
for package in frontend_packages:
- if package in (get_config().tailwind or {}).get("plugins", []): # type: ignore
+ if package in (get_config().tailwind or {}).get("plugins", []):
console.warn(
f"Tailwind packages are inferred from 'plugins', remove `{package}` from `frontend_packages`"
)
@@ -992,7 +1032,7 @@ class App(MiddlewareMixin, LifespanMixin):
compiler.compile_document_root(
self.head_components,
html_lang=self.html_lang,
- html_custom_attrs=self.html_custom_attrs, # type: ignore
+ html_custom_attrs=self.html_custom_attrs, # pyright: ignore [reportArgumentType]
)
)
@@ -1015,7 +1055,7 @@ class App(MiddlewareMixin, LifespanMixin):
max_workers=environment.REFLEX_COMPILE_THREADS.get() or None
)
- for route, component in zip(self._pages, page_components):
+ for route, component in zip(self._pages, page_components, strict=True):
ExecutorSafeFunctions.COMPONENTS[route] = component
ExecutorSafeFunctions.STATE = self._state
@@ -1023,7 +1063,7 @@ class App(MiddlewareMixin, LifespanMixin):
with executor:
result_futures = []
- def _submit_work(fn, *args, **kwargs):
+ def _submit_work(fn: Callable, *args, **kwargs):
f = executor.submit(fn, *args, **kwargs)
result_futures.append(f)
@@ -1212,6 +1252,7 @@ class App(MiddlewareMixin, LifespanMixin):
frontend_arg_spec,
backend_arg_spec,
],
+ strict=True,
):
if hasattr(handler_fn, "__name__"):
_fn_name = handler_fn.__name__
@@ -1353,15 +1394,14 @@ async def process(
if app._process_background(state, event) is not None:
# `final=True` allows the frontend send more events immediately.
yield StateUpdate(final=True)
- return
+ else:
+ # Process the event synchronously.
+ async for update in state._process(event):
+ # Postprocess the event.
+ update = await app._postprocess(state, event, update)
- # Process the event synchronously.
- async for update in state._process(event):
- # Postprocess the event.
- update = await app._postprocess(state, event, update)
-
- # Yield the update.
- yield update
+ # Yield the update.
+ yield update
except Exception as ex:
telemetry.send_error(ex, context="backend")
@@ -1556,20 +1596,20 @@ class EventNamespace(AsyncNamespace):
self.sid_to_token = {}
self.app = app
- def on_connect(self, sid, environ):
+ def on_connect(self, sid: str, environ: dict):
"""Event for when the websocket is connected.
Args:
sid: The Socket.IO session id.
environ: The request information, including HTTP headers.
"""
- subprotocol = environ.get("HTTP_SEC_WEBSOCKET_PROTOCOL", None)
+ subprotocol = environ.get("HTTP_SEC_WEBSOCKET_PROTOCOL")
if subprotocol and subprotocol != constants.Reflex.VERSION:
console.warn(
f"Frontend version {subprotocol} for session {sid} does not match the backend version {constants.Reflex.VERSION}."
)
- def on_disconnect(self, sid):
+ def on_disconnect(self, sid: str):
"""Event for when the websocket disconnects.
Args:
@@ -1591,7 +1631,7 @@ class EventNamespace(AsyncNamespace):
self.emit(str(constants.SocketEvent.EVENT), update, to=sid)
)
- async def on_event(self, sid, data):
+ async def on_event(self, sid: str, data: Any):
"""Event for receiving front-end websocket events.
Raises:
@@ -1658,7 +1698,7 @@ class EventNamespace(AsyncNamespace):
# Emit the update from processing the event.
await self.emit_update(update=update, sid=sid)
- async def on_ping(self, sid):
+ async def on_ping(self, sid: str):
"""Event for testing the API endpoint.
Args:
diff --git a/reflex/app_mixins/lifespan.py b/reflex/app_mixins/lifespan.py
index 9403e0f35..50b90f25c 100644
--- a/reflex/app_mixins/lifespan.py
+++ b/reflex/app_mixins/lifespan.py
@@ -32,7 +32,7 @@ class LifespanMixin(AppMixin):
try:
async with contextlib.AsyncExitStack() as stack:
for task in self.lifespan_tasks:
- run_msg = f"Started lifespan task: {task.__name__} as {{type}}" # type: ignore
+ run_msg = f"Started lifespan task: {task.__name__} as {{type}}" # pyright: ignore [reportAttributeAccessIssue]
if isinstance(task, asyncio.Task):
running_tasks.append(task)
else:
@@ -61,7 +61,7 @@ class LifespanMixin(AppMixin):
Args:
task: The task to register.
- task_kwargs: The kwargs of the task.
+ **task_kwargs: The kwargs of the task.
Raises:
InvalidLifespanTaskTypeError: If the task is a generator function.
@@ -73,7 +73,7 @@ class LifespanMixin(AppMixin):
if task_kwargs:
original_task = task
- task = functools.partial(task, **task_kwargs) # type: ignore
- functools.update_wrapper(task, original_task) # type: ignore
- self.lifespan_tasks.add(task) # type: ignore
- console.debug(f"Registered lifespan task: {task.__name__}") # type: ignore
+ task = functools.partial(task, **task_kwargs) # pyright: ignore [reportArgumentType]
+ functools.update_wrapper(task, original_task) # pyright: ignore [reportArgumentType]
+ self.lifespan_tasks.add(task)
+ console.debug(f"Registered lifespan task: {task.__name__}") # pyright: ignore [reportAttributeAccessIssue]
diff --git a/reflex/app_mixins/middleware.py b/reflex/app_mixins/middleware.py
index 30593d9ae..c81fd7806 100644
--- a/reflex/app_mixins/middleware.py
+++ b/reflex/app_mixins/middleware.py
@@ -53,11 +53,11 @@ class MiddlewareMixin(AppMixin):
"""
for middleware in self.middleware:
if asyncio.iscoroutinefunction(middleware.preprocess):
- out = await middleware.preprocess(app=self, state=state, event=event) # type: ignore
+ out = await middleware.preprocess(app=self, state=state, event=event) # pyright: ignore [reportArgumentType]
else:
- out = middleware.preprocess(app=self, state=state, event=event) # type: ignore
+ out = middleware.preprocess(app=self, state=state, event=event) # pyright: ignore [reportArgumentType]
if out is not None:
- return out # type: ignore
+ return out # pyright: ignore [reportReturnType]
async def _postprocess(
self, state: BaseState, event: Event, update: StateUpdate
@@ -78,18 +78,18 @@ class MiddlewareMixin(AppMixin):
for middleware in self.middleware:
if asyncio.iscoroutinefunction(middleware.postprocess):
out = await middleware.postprocess(
- app=self, # type: ignore
+ app=self, # pyright: ignore [reportArgumentType]
state=state,
event=event,
update=update,
)
else:
out = middleware.postprocess(
- app=self, # type: ignore
+ app=self, # pyright: ignore [reportArgumentType]
state=state,
event=event,
update=update,
)
if out is not None:
- return out # type: ignore
+ return out # pyright: ignore [reportReturnType]
return update
diff --git a/reflex/base.py b/reflex/base.py
index 1879d76d8..c900f0039 100644
--- a/reflex/base.py
+++ b/reflex/base.py
@@ -38,7 +38,7 @@ def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None
# monkeypatch pydantic validate_field_name method to skip validating
# shadowed state vars when reloading app via utils.prerequisites.get_app(reload=True)
-pydantic_main.validate_field_name = validate_field_name # type: ignore
+pydantic_main.validate_field_name = validate_field_name # pyright: ignore [reportPossiblyUnboundVariable, reportPrivateImportUsage]
if TYPE_CHECKING:
from reflex.vars import Var
@@ -69,12 +69,12 @@ class Base(BaseModel):
"""
from reflex.utils.serializers import serialize
- return self.__config__.json_dumps( # type: ignore
+ return self.__config__.json_dumps(
self.dict(),
default=serialize,
)
- def set(self, **kwargs):
+ def set(self, **kwargs: Any):
"""Set multiple fields and return the object.
Args:
@@ -107,12 +107,12 @@ class Base(BaseModel):
default_value: The default value of the field
"""
var_name = var._var_field_name
- new_field = ModelField.infer(
+ new_field = ModelField.infer( # pyright: ignore [reportPossiblyUnboundVariable]
name=var_name,
value=default_value,
annotation=var._var_type,
class_validators=None,
- config=cls.__config__, # type: ignore
+ config=cls.__config__,
)
cls.__fields__.update({var_name: new_field})
diff --git a/reflex/compiler/utils.py b/reflex/compiler/utils.py
index c0ba28f4b..d145e6c0b 100644
--- a/reflex/compiler/utils.py
+++ b/reflex/compiler/utils.py
@@ -2,6 +2,8 @@
from __future__ import annotations
+import traceback
+from datetime import datetime
from pathlib import Path
from typing import Any, Callable, Dict, Optional, Type, Union
from urllib.parse import urlparse
@@ -12,7 +14,9 @@ from reflex.vars.base import Var
try:
from pydantic.v1.fields import ModelField
except ModuleNotFoundError:
- from pydantic.fields import ModelField # type: ignore
+ from pydantic.fields import (
+ ModelField, # pyright: ignore [reportAttributeAccessIssue]
+ )
from reflex import constants
from reflex.components.base import (
@@ -115,7 +119,7 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]:
default, rest = compile_import_statement(fields)
# prevent lib from being rendered on the page if all imports are non rendered kind
- if not any(f.render for f in fields): # type: ignore
+ if not any(f.render for f in fields):
continue
if not lib:
@@ -163,8 +167,12 @@ def compile_state(state: Type[BaseState]) -> dict:
try:
initial_state = state(_reflex_internal_init=True).dict(initial=True)
except Exception as e:
+ timestamp = datetime.now().strftime("%Y-%m-%d__%H-%M-%S")
+ constants.Reflex.LOGS_DIR.mkdir(parents=True, exist_ok=True)
+ log_path = constants.Reflex.LOGS_DIR / f"state_compile_error_{timestamp}.log"
+ traceback.TracebackException.from_exception(e).print(file=log_path.open("w+"))
console.warn(
- f"Failed to compile initial state with computed vars, excluding them: {e}"
+ f"Failed to compile initial state with computed vars. Error log saved to {log_path}"
)
initial_state = state(_reflex_internal_init=True).dict(
initial=True, include_computed=False
@@ -494,7 +502,7 @@ def empty_dir(path: str | Path, keep_files: list[str] | None = None):
path_ops.rm(element)
-def is_valid_url(url) -> bool:
+def is_valid_url(url: str) -> bool:
"""Check if a url is valid.
Args:
diff --git a/reflex/components/base/bare.py b/reflex/components/base/bare.py
index b07bdfcfa..0c62f9000 100644
--- a/reflex/components/base/bare.py
+++ b/reflex/components/base/bare.py
@@ -31,7 +31,7 @@ class Bare(Component):
return cls(contents=contents)
else:
contents = str(contents) if contents is not None else ""
- return cls(contents=contents) # type: ignore
+ return cls(contents=contents)
def _get_all_hooks_internal(self) -> dict[str, VarData | None]:
"""Include the hooks for the component.
diff --git a/reflex/components/base/error_boundary.py b/reflex/components/base/error_boundary.py
index f328773c2..74867a757 100644
--- a/reflex/components/base/error_boundary.py
+++ b/reflex/components/base/error_boundary.py
@@ -11,10 +11,11 @@ from reflex.event import EventHandler, set_clipboard
from reflex.state import FrontendEventExceptionState
from reflex.vars.base import Var
from reflex.vars.function import ArgsFunctionOperation
+from reflex.vars.object import ObjectVar
def on_error_spec(
- error: Var[Dict[str, str]], info: Var[Dict[str, str]]
+ error: ObjectVar[Dict[str, str]], info: ObjectVar[Dict[str, str]]
) -> Tuple[Var[str], Var[str]]:
"""The spec for the on_error event handler.
diff --git a/reflex/components/base/error_boundary.pyi b/reflex/components/base/error_boundary.pyi
index 2e01c7da0..8d27af0f3 100644
--- a/reflex/components/base/error_boundary.pyi
+++ b/reflex/components/base/error_boundary.pyi
@@ -9,9 +9,10 @@ from reflex.components.component import Component
from reflex.event import BASE_STATE, EventType
from reflex.style import Style
from reflex.vars.base import Var
+from reflex.vars.object import ObjectVar
def on_error_spec(
- error: Var[Dict[str, str]], info: Var[Dict[str, str]]
+ error: ObjectVar[Dict[str, str]], info: ObjectVar[Dict[str, str]]
) -> Tuple[Var[str], Var[str]]: ...
class ErrorBoundary(Component):
diff --git a/reflex/components/base/meta.py b/reflex/components/base/meta.py
index 526233c8b..10264009e 100644
--- a/reflex/components/base/meta.py
+++ b/reflex/components/base/meta.py
@@ -53,11 +53,11 @@ class Description(Meta):
"""A component that displays the title of the current page."""
# The type of the description.
- name: str = "description"
+ name: str | None = "description"
class Image(Meta):
"""A component that displays the title of the current page."""
# The type of the image.
- property: str = "og:image"
+ property: str | None = "og:image"
diff --git a/reflex/components/component.py b/reflex/components/component.py
index 8c3bc5184..d3acf69ab 100644
--- a/reflex/components/component.py
+++ b/reflex/components/component.py
@@ -149,7 +149,7 @@ class BaseComponent(Base, ABC):
class ComponentNamespace(SimpleNamespace):
"""A namespace to manage components with subcomponents."""
- def __hash__(self) -> int:
+ def __hash__(self) -> int: # pyright: ignore [reportIncompatibleVariableOverride]
"""Get the hash of the namespace.
Returns:
@@ -425,7 +425,7 @@ class Component(BaseComponent, ABC):
else:
continue
- def determine_key(value):
+ def determine_key(value: Any):
# Try to create a var from the value
key = value if isinstance(value, Var) else LiteralVar.create(value)
@@ -461,9 +461,7 @@ class Component(BaseComponent, ABC):
if types.is_union(passed_type):
# We need to check all possible types in the union.
passed_types = (
- arg
- for arg in passed_type.__args__ # type: ignore
- if arg is not type(None)
+ arg for arg in passed_type.__args__ if arg is not type(None)
)
if (
# If the passed var is a union, check if all possible types are valid.
@@ -490,7 +488,7 @@ class Component(BaseComponent, ABC):
# Check if the key is an event trigger.
if key in component_specific_triggers:
kwargs["event_triggers"][key] = EventChain.create(
- value=value, # type: ignore
+ value=value,
args_spec=component_specific_triggers[key],
key=key,
)
@@ -577,7 +575,7 @@ class Component(BaseComponent, ABC):
annotation = field.annotation
if (metadata := getattr(annotation, "__metadata__", None)) is not None:
args_spec = metadata[0]
- default_triggers[field.name] = args_spec or (no_args_event_spec) # type: ignore
+ default_triggers[field.name] = args_spec or (no_args_event_spec)
return default_triggers
def __repr__(self) -> str:
@@ -708,7 +706,7 @@ class Component(BaseComponent, ABC):
# Filter out None props
props = {key: value for key, value in props.items() if value is not None}
- def validate_children(children):
+ def validate_children(children: tuple | list):
for child in children:
if isinstance(child, (tuple, list)):
validate_children(child)
@@ -760,7 +758,7 @@ class Component(BaseComponent, ABC):
# Walk the MRO to call all `add_style` methods.
for base in self._iter_parent_classes_with_method("add_style"):
- s = base.add_style(self) # type: ignore
+ s = base.add_style(self)
if s is not None:
styles.append(s)
@@ -852,7 +850,7 @@ class Component(BaseComponent, ABC):
else {}
)
- def render(self) -> Dict:
+ def render(self) -> dict:
"""Render the component.
Returns:
@@ -870,7 +868,7 @@ class Component(BaseComponent, ABC):
self._replace_prop_names(rendered_dict)
return rendered_dict
- def _replace_prop_names(self, rendered_dict) -> None:
+ def _replace_prop_names(self, rendered_dict: dict) -> None:
"""Replace the prop names in the render dictionary.
Args:
@@ -906,7 +904,7 @@ class Component(BaseComponent, ABC):
comp_name = type(self).__name__
allowed_components = [comp.__name__ for comp in (Fragment,)]
- def validate_child(child):
+ def validate_child(child: Any):
child_name = type(child).__name__
# Iterate through the immediate children of fragment
@@ -1683,7 +1681,7 @@ class CustomComponent(Component):
if base_value is not None and isinstance(value, Component):
self.component_props[key] = value
value = base_value._replace(
- merge_var_data=VarData( # type: ignore
+ merge_var_data=VarData(
imports=value._get_all_imports(),
hooks=value._get_all_hooks(),
)
@@ -1716,7 +1714,7 @@ class CustomComponent(Component):
return hash(self.tag)
@classmethod
- def get_props(cls) -> Set[str]:
+ def get_props(cls) -> Set[str]: # pyright: ignore [reportIncompatibleVariableOverride]
"""Get the props for the component.
Returns:
@@ -1811,7 +1809,7 @@ class CustomComponent(Component):
include_children=include_children, ignore_ids=ignore_ids
)
- @lru_cache(maxsize=None) # noqa
+ @lru_cache(maxsize=None) # noqa: B019
def get_component(self) -> Component:
"""Render the component.
@@ -1953,7 +1951,7 @@ class StatefulComponent(BaseComponent):
if not should_memoize:
# Determine if any Vars have associated data.
- for prop_var in component._get_vars():
+ for prop_var in component._get_vars(include_children=True):
if prop_var._get_all_var_data():
should_memoize = True
break
@@ -2323,8 +2321,8 @@ class MemoizationLeaf(Component):
"""
comp = super().create(*children, **props)
if comp._get_all_hooks():
- comp._memoization_mode = cls._memoization_mode.copy(
- update={"disposition": MemoizationDisposition.ALWAYS}
+ comp._memoization_mode = dataclasses.replace(
+ comp._memoization_mode, disposition=MemoizationDisposition.ALWAYS
)
return comp
@@ -2406,6 +2404,7 @@ def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) ->
@dataclasses.dataclass(
eq=False,
frozen=True,
+ slots=True,
)
class LiteralComponentVar(CachedVarOperation, LiteralVar, ComponentVar):
"""A Var that represents a Component."""
diff --git a/reflex/components/core/banner.py b/reflex/components/core/banner.py
index 815510e8b..64b7874b6 100644
--- a/reflex/components/core/banner.py
+++ b/reflex/components/core/banner.py
@@ -5,8 +5,10 @@ from __future__ import annotations
from typing import Optional
from reflex.components.base.fragment import Fragment
+from reflex import constants
from reflex.components.component import Component
from reflex.components.core.cond import cond
+from reflex.components.datadisplay.logo import svg_logo
from reflex.components.el.elements.typography import Div
from reflex.components.lucide.icon import Icon
from reflex.components.radix.themes.components.dialog import (
@@ -26,7 +28,7 @@ from reflex.vars.function import FunctionStringVar
from reflex.vars.number import BooleanVar
from reflex.vars.sequence import LiteralArrayVar
-connect_error_var_data: VarData = VarData( # type: ignore
+connect_error_var_data: VarData = VarData(
imports=Imports.EVENTS,
hooks={Hooks.EVENTS: None},
)
@@ -100,14 +102,14 @@ class ConnectionToaster(Toaster):
"""
toast_id = "websocket-error"
target_url = WebsocketTargetURL.create()
- props = ToastProps( # type: ignore
+ props = ToastProps(
description=LiteralVar.create(
f"Check if server is reachable at {target_url}",
),
close_button=True,
duration=120000,
id=toast_id,
- )
+ ) # pyright: ignore [reportCallIssue]
individual_hooks = [
f"const toast_props = {LiteralVar.create(props)!s};",
@@ -117,7 +119,7 @@ class ConnectionToaster(Toaster):
_var_data=VarData(
imports={
"react": ["useEffect", "useState"],
- **dict(target_url._get_all_var_data().imports), # type: ignore
+ **dict(target_url._get_all_var_data().imports), # pyright: ignore [reportArgumentType, reportOptionalMemberAccess]
}
),
).call(
@@ -296,7 +298,84 @@ class ConnectionPulser(Div):
)
+class BackendDisabled(Div):
+ """A component that displays a message when the backend is disabled."""
+
+ @classmethod
+ def create(cls, **props) -> Component:
+ """Create a backend disabled component.
+
+ Args:
+ **props: The properties of the component.
+
+ Returns:
+ The backend disabled component.
+ """
+ import reflex as rx
+
+ is_backend_disabled = Var(
+ "backendDisabled",
+ _var_type=bool,
+ _var_data=VarData(
+ hooks={
+ "const [backendDisabled, setBackendDisabled] = useState(false);": None,
+ "useEffect(() => { setBackendDisabled(isBackendDisabled()); }, []);": None,
+ },
+ imports={
+ f"$/{constants.Dirs.STATE_PATH}": [
+ ImportVar(tag="isBackendDisabled")
+ ],
+ },
+ ),
+ )
+
+ return super().create(
+ rx.cond(
+ is_backend_disabled,
+ rx.box(
+ rx.box(
+ rx.card(
+ rx.vstack(
+ svg_logo(),
+ rx.text(
+ "You ran out of compute credits.",
+ ),
+ rx.callout(
+ rx.fragment(
+ "Please upgrade your plan or raise your compute credits at ",
+ rx.link(
+ "Reflex Cloud.",
+ href="https://cloud.reflex.dev/",
+ ),
+ ),
+ width="100%",
+ icon="info",
+ variant="surface",
+ ),
+ ),
+ font_size="20px",
+ font_family='"Inter", "Helvetica", "Arial", sans-serif',
+ variant="classic",
+ ),
+ position="fixed",
+ top="50%",
+ left="50%",
+ transform="translate(-50%, -50%)",
+ width="40ch",
+ max_width="90vw",
+ ),
+ position="fixed",
+ z_index=9999,
+ backdrop_filter="grayscale(1) blur(5px)",
+ width="100dvw",
+ height="100dvh",
+ ),
+ )
+ )
+
+
connection_banner = ConnectionBanner.create
connection_modal = ConnectionModal.create
connection_toaster = ConnectionToaster.create
connection_pulser = ConnectionPulser.create
+backend_disabled = BackendDisabled.create
diff --git a/reflex/components/core/banner.pyi b/reflex/components/core/banner.pyi
index 0f10e0df1..ec7de7a6f 100644
--- a/reflex/components/core/banner.pyi
+++ b/reflex/components/core/banner.pyi
@@ -351,7 +351,93 @@ class ConnectionPulser(Div):
"""
...
+class BackendDisabled(Div):
+ @overload
+ @classmethod
+ def create( # type: ignore
+ cls,
+ *children,
+ access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
+ auto_capitalize: Optional[
+ Union[Var[Union[bool, int, str]], bool, int, str]
+ ] = None,
+ content_editable: Optional[
+ Union[Var[Union[bool, int, str]], bool, int, str]
+ ] = None,
+ context_menu: Optional[
+ Union[Var[Union[bool, int, str]], bool, int, str]
+ ] = None,
+ dir: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
+ draggable: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
+ enter_key_hint: Optional[
+ Union[Var[Union[bool, int, str]], bool, int, str]
+ ] = None,
+ hidden: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
+ input_mode: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
+ item_prop: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
+ lang: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
+ role: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
+ slot: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
+ spell_check: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
+ tab_index: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
+ title: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
+ style: Optional[Style] = None,
+ key: Optional[Any] = None,
+ id: Optional[Any] = None,
+ class_name: Optional[Any] = None,
+ autofocus: Optional[bool] = None,
+ custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
+ on_blur: Optional[EventType[[], BASE_STATE]] = None,
+ on_click: Optional[EventType[[], BASE_STATE]] = None,
+ on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
+ on_double_click: Optional[EventType[[], BASE_STATE]] = None,
+ on_focus: Optional[EventType[[], BASE_STATE]] = None,
+ on_mount: Optional[EventType[[], BASE_STATE]] = None,
+ on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
+ on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
+ on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
+ on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
+ on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
+ on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
+ on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
+ on_scroll: Optional[EventType[[], BASE_STATE]] = None,
+ on_unmount: Optional[EventType[[], BASE_STATE]] = None,
+ **props,
+ ) -> "BackendDisabled":
+ """Create a backend disabled component.
+
+ Args:
+ access_key: Provides a hint for generating a keyboard shortcut for the current element.
+ auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
+ content_editable: Indicates whether the element's content is editable.
+ context_menu: Defines the ID of a