diff --git a/enterprise/.gitignore b/enterprise/.gitignore new file mode 100644 index 0000000..e39802e --- /dev/null +++ b/enterprise/.gitignore @@ -0,0 +1,6 @@ +assets/external/ +.web +__pycache__/ +*.py[cod] +.states +*.db diff --git a/enterprise/alembic.ini b/enterprise/alembic.ini new file mode 100644 index 0000000..3700390 --- /dev/null +++ b/enterprise/alembic.ini @@ -0,0 +1,119 @@ +# A generic, single database configuration. + +[alembic] +# path to migration scripts +# Use forward slashes (/) also on windows to provide an os agnostic path +script_location = alembic + +# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s +# Uncomment the line below if you want the files to be prepended with date and time +# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file +# for all available tokens +# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s + +# sys.path path, will be prepended to sys.path if present. +# defaults to the current working directory. +prepend_sys_path = . + +# timezone to use when rendering the date within the migration file +# as well as the filename. +# If specified, requires the python>=3.9 or backports.zoneinfo library and tzdata library. +# Any required deps can installed by adding `alembic[tz]` to the pip requirements +# string value is passed to ZoneInfo() +# leave blank for localtime +# timezone = + +# max length of characters to apply to the "slug" field +# truncate_slug_length = 40 + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + +# set to 'true' to allow .pyc and .pyo files without +# a source .py file to be detected as revisions in the +# versions/ directory +# sourceless = false + +# version location specification; This defaults +# to alembic/versions. When using multiple version +# directories, initial revisions must be specified with --version-path. +# The path separator used here should be the separator specified by "version_path_separator" below. +# version_locations = %(here)s/bar:%(here)s/bat:alembic/versions + +# version path separator; As mentioned above, this is the character used to split +# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep. +# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas. +# Valid values for version_path_separator are: +# +# version_path_separator = : +# version_path_separator = ; +# version_path_separator = space +# version_path_separator = newline +# +# Use os.pathsep. Default configuration used for new projects. +version_path_separator = os + +# set to 'true' to search source files recursively +# in each "version_locations" directory +# new in Alembic version 1.10 +# recursive_version_locations = false + +# the output encoding used when revision files +# are written from script.py.mako +# output_encoding = utf-8 + +sqlalchemy.url = driver://user:pass@localhost/dbname + + +[post_write_hooks] +# post_write_hooks defines scripts or Python functions that are run +# on newly generated revision scripts. See the documentation for further +# detail and examples + +# format using "black" - use the console_scripts runner, against the "black" entrypoint +# hooks = black +# black.type = console_scripts +# black.entrypoint = black +# black.options = -l 79 REVISION_SCRIPT_FILENAME + +# lint with attempts to fix using "ruff" - use the exec runner, execute a binary +# hooks = ruff +# ruff.type = exec +# ruff.executable = %(here)s/.venv/bin/ruff +# ruff.options = --fix REVISION_SCRIPT_FILENAME + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARNING +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARNING +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/enterprise/alembic/README b/enterprise/alembic/README new file mode 100644 index 0000000..98e4f9c --- /dev/null +++ b/enterprise/alembic/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/enterprise/alembic/env.py b/enterprise/alembic/env.py new file mode 100644 index 0000000..9dd6c6c --- /dev/null +++ b/enterprise/alembic/env.py @@ -0,0 +1,74 @@ +from logging.config import fileConfig + +from alembic import context +from sqlalchemy import engine_from_config, pool + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +if config.config_file_name is not None: + fileConfig(config.config_file_name) + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +target_metadata = None + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline() -> None: + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online() -> None: + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + connectable = engine_from_config( + config.get_section(config.config_ini_section, {}), + prefix="sqlalchemy.", + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure(connection=connection, target_metadata=target_metadata) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/enterprise/alembic/script.py.mako b/enterprise/alembic/script.py.mako new file mode 100644 index 0000000..fbc4b07 --- /dev/null +++ b/enterprise/alembic/script.py.mako @@ -0,0 +1,26 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision: str = ${repr(up_revision)} +down_revision: Union[str, None] = ${repr(down_revision)} +branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)} +depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)} + + +def upgrade() -> None: + ${upgrades if upgrades else "pass"} + + +def downgrade() -> None: + ${downgrades if downgrades else "pass"} diff --git a/enterprise/alembic/versions/8a1f2192cab7_.py b/enterprise/alembic/versions/8a1f2192cab7_.py new file mode 100644 index 0000000..02adbaa --- /dev/null +++ b/enterprise/alembic/versions/8a1f2192cab7_.py @@ -0,0 +1,47 @@ +"""empty message + +Revision ID: 8a1f2192cab7 +Revises: +Create Date: 2025-03-04 17:07:14.030943 + +""" + +from typing import Sequence, Union + +import sqlalchemy as sa +import sqlmodel +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = "8a1f2192cab7" +down_revision: Union[str, None] = None +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "friend", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column("age", sa.Integer(), nullable=False), + sa.Column("years_known", sa.Integer(), nullable=False), + sa.Column("owes_me", sa.Boolean(), nullable=False), + sa.Column("has_a_dog", sa.Boolean(), nullable=False), + sa.Column("spouse_is_annoying", sa.Boolean(), nullable=False), + sa.Column( + "met", + sa.DateTime(timezone=True), + server_default=sa.text("(CURRENT_TIMESTAMP)"), + nullable=True, + ), + sa.PrimaryKeyConstraint("id"), + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table("friend") + # ### end Alembic commands ### diff --git a/enterprise/assets/favicon.ico b/enterprise/assets/favicon.ico new file mode 100644 index 0000000..166ae99 Binary files /dev/null and b/enterprise/assets/favicon.ico differ diff --git a/enterprise/assets/style.css b/enterprise/assets/style.css new file mode 100644 index 0000000..47b908c --- /dev/null +++ b/enterprise/assets/style.css @@ -0,0 +1,218 @@ +html, +body { + margin: 0; + font-family: sans-serif; + box-sizing: border-box; +} + +#app { + width: 100vw; + height: 100vh; +} + +/* Circle Node */ + +.react-flow__node-circle { + border-radius: 50%; + height: 100px; + width: 100px; + font-family: monospace; + text-align: center; +} + +/* Text Input Node */ + +.react-flow__node-textinput { + width: 150px; + font-family: monospace; + text-align: left; +} + +.text-input-node__input { + width: 100%; + box-sizing: border-box; + margin: 5px 0; +} + +/* Annotation Node */ + +.react-flow__node-annotation { + font-size: 16px; + width: 200px; + color: #683bfa; + position: absolute; + box-shadow: none; + font-family: monospace; + text-align: left; + background-color: transparent; + border: none; +} + +.react-flow__node-annotation .annotation-content { + padding: 10px; + display: flex; +} + +.react-flow__node-annotation .annotation-level { + margin-right: 4px; +} + +.react-flow__node-annotation .annotation-arrow { + position: absolute; + font-size: 24px; +} + +/* Toolbar Node */ + +.react-flow__node-toolbar { + background-color: #000000; + border-radius: 16px; + overflow: hidden; +} + +.react-flow__node-toolbar button { + cursor: pointer; + background: inherit; + border: none; + padding: 5px 7px; + margin: 3px; + border-radius: 50%; + box-shadow: var(--xy-node-boxshadow-default); +} + +.react-flow__node-toolbar button:hover { + background: #4d4d4d; +} + +/* Resizer Node */ + +.resizer-node__handles { + display: flex; + position: absolute; + bottom: 0; + width: 100%; + justify-content: space-evenly; + left: 0; +} + +.resizer-node__handle { + position: relative; + left: 0; + transform: none; +} + +/* Button Edge */ + +.button-edge__label { + position: absolute; + pointer-events: all; + transform-origin: center; +} + +.button-edge__button { + width: 30px; + height: 30px; + border: 5px solid #f7f9fb; + color: var(--xy-edge-node-color-default); + background-color: #f3f3f4; + cursor: pointer; + border-radius: 50%; + font-size: 12px; + padding-top: 0px; +} + +.button-edge__button:hover { + background-color: var(--xy-theme-hover); + color: #ffffff; +} + +/* Custom Handles */ + +.react-flow__handle.custom-handle { + background-color: var(--xy-handle-border-color-default); + border-radius: 1px; + width: 8px; + height: 4px; + border: none; + min-width: 2px; + min-height: 2px; +} + +.react-flow__handle.custom-handle:hover, +.react-flow__handle.custom-handle.connectionindicator:focus, +.react-flow__handle.custom-handle.connectingfrom, +.react-flow__handle.custom-handle.connectingto { + background-color: var(--xy-theme-edge-hover); +} + +.react-flow__handle-bottom.custom-handle { + bottom: -5px; + transform: none; +} + +.react-flow__handle-top.custom-handle { + top: -5px; + transform: none; +} + +.react-flow__handle-left.custom-handle { + height: 8px; + width: 4px; + left: -3px; +} + +/* Minimap */ + +.react-flow__minimap .group { + fill-opacity: 0.4; +} + +.react-flow__minimap .resizer, +.react-flow__minimap .tools, +.react-flow__minimap .circle, +.react-flow__minimap .textinput { + fill: rgb(208, 192, 247); +} + +.react-flow__minimap .circle { + rx: 100%; + ry: 100%; +} + +.react-flow__minimap .annotation { + display: none; +} + +.react-flow__node-custom .react-flow__handle.connectable { + border-color: var(--xy-theme-selected); + background: var(--xy-theme-selected); + + &:hover { + background: var(--xy-theme-selected); + } +} + +.drag-handle__label { + display: flex; + align-items: center; +} + +.drag-handle__custom { + display: inline-block; + width: 20px; + height: 20px; + background-color: teal; + margin-left: 15px; + border-radius: 50%; +} + +/* Intersections highlight */ + +.react-flow__node.highlight { + background-color: rgb(255, 194, 206); + border-color: rgb(255, 101, 132); +} + +.intersection-flow .react-flow__handle { + display: none; +} diff --git a/enterprise/assets/xy-theme.css b/enterprise/assets/xy-theme.css new file mode 100644 index 0000000..ff6b4ca --- /dev/null +++ b/enterprise/assets/xy-theme.css @@ -0,0 +1,260 @@ +/* xyflow theme files. Delete these to start from our base */ + +.react-flow { + --xy-background-color: #f7f9fb; + /* Custom Variables */ + --xy-theme-selected: #f57dbd; + --xy-theme-hover: #c5c5c5; + --xy-theme-edge-hover: black; + --xy-theme-color-focus: #e8e8e8; + + /* Built-in Variables see https://reactflow.dev/learn/customization/theming */ + --xy-node-border-default: 1px solid #ededed; + + --xy-node-boxshadow-default: 0px 3.54px 4.55px 0px #00000005, + 0px 3.54px 4.55px 0px #0000000d, 0px 0.51px 1.01px 0px #0000001a; + + --xy-node-border-radius-default: 8px; + + --xy-handle-background-color-default: #ffffff; + --xy-handle-border-color-default: #aaaaaa; + + --xy-edge-label-color-default: #505050; +} + +.react-flow.dark { + --xy-node-boxshadow-default: 0px 3.54px 4.55px 0px rgba(255, 255, 255, 0.05), + /* light shadow */ 0px 3.54px 4.55px 0px rgba(255, 255, 255, 0.13), + /* medium shadow */ 0px 0.51px 1.01px 0px rgba(255, 255, 255, 0.2); /* smallest shadow */ + --xy-theme-color-focus: #535353; +} + +/* Customizing Default Theming */ + +.react-flow__node { + box-shadow: var(--xy-node-boxshadow-default); + border-radius: var(--xy-node-border-radius-default); + background-color: var(--xy-node-background-color-default); + display: flex; + justify-content: center; + align-items: center; + text-align: center; + padding: 10px; + font-size: 12px; + flex-direction: column; + border: var(--xy-node-border-default); + color: var(--xy-node-color, var(--xy-node-color-default)); +} + +.react-flow__node.selectable:focus { + box-shadow: 0px 0px 0px 4px var(--xy-theme-color-focus); + border-color: #d9d9d9; +} + +.react-flow__node.selectable:focus:active { + box-shadow: var(--xy-node-boxshadow-default); +} + +.react-flow__node.selectable:hover, +.react-flow__node.draggable:hover { + border-color: var(--xy-theme-hover); +} + +.react-flow__node.selectable.selected { + border-color: var(--xy-theme-selected); + box-shadow: var(--xy-node-boxshadow-default); +} + +.react-flow__node-group { + background-color: rgba(207, 182, 255, 0.4); + border-color: #9e86ed; +} + +.react-flow__edge.selectable:hover .react-flow__edge-path, +.react-flow__edge.selectable.selected .react-flow__edge-path { + stroke: var(--xy-theme-edge-hover); +} + +.react-flow__handle { + background-color: var(--xy-handle-background-color-default); +} + +.react-flow__handle.connectionindicator:hover { + pointer-events: all; + border-color: var(--xy-theme-edge-hover); + background-color: white; +} + +.react-flow__handle.connectionindicator:focus, +.react-flow__handle.connectingfrom, +.react-flow__handle.connectingto { + border-color: var(--xy-theme-edge-hover); +} + +.react-flow__node-resizer { + border-radius: 0; + border: none; +} + +.react-flow__resize-control.handle { + background-color: #ffffff; + border-color: #9e86ed; + border-radius: 0; + width: 5px; + height: 5px; +} + +/* + Custom Example CSS - This CSS is to improve the example experience. + You can remove it if you want to use the default styles. + + New Theme Classes: + .xy-theme__button - Styles for buttons. + .xy-theme__input - Styles for text inputs. + .xy-theme__checkbox - Styles for checkboxes. + .xy-theme__select - Styles for dropdown selects. + .xy-theme__label - Styles for labels. + + Use these classes to apply consistent theming across your components. +*/ + +:root { + --color-primary: #ff0073; + --color-background: #fefefe; + --color-hover-bg: #f6f6f6; + --color-disabled: #76797e; +} + +.xy-theme__button-group { + display: flex; + align-items: center; + + .xy-theme__button:first-child { + border-radius: 100px 0 0 100px; + } + + .xy-theme__button:last-child { + border-radius: 0 100px 100px 0; + margin: 0; + } +} + +/* Custom Button Styling */ +.xy-theme__button { + display: inline-flex; + align-items: center; + justify-content: center; + height: 2.5rem; + padding: 0 1rem; + border-radius: 100px; + border: 1px solid var(--color-primary); + background-color: var(--color-background); + color: var(--color-primary); + transition: background-color 0.2s ease, border-color 0.2s ease; + box-shadow: var(--xy-node-boxshadow-default); + cursor: pointer; +} + +.xy-theme__button.active { + background-color: var(--color-primary); + color: white; + border-color: var(--color-primary); +} + +.xy-theme__button.active:hover, +.xy-theme__button.active:active { + background-color: var(--color-primary); + opacity: 0.9; +} + +.xy-theme__button:hover { + background-color: var(--xy-controls-button-background-color-hover-default); +} + +.xy-theme__button:active { + background-color: var(--color-hover-bg); +} + +.xy-theme__button:disabled { + color: var(--color-disabled); + opacity: 0.8; + cursor: not-allowed; + border: 1px solid var(--color-disabled); +} + +.xy-theme__button > span { + margin-right: 0.2rem; +} + +/* Add gap between adjacent buttons */ +.xy-theme__button + .xy-theme__button { + margin-left: 0.3rem; +} + +/* Example Input Styling */ +.xy-theme__input { + padding: 0.5rem 0.75rem; + border: 1px solid var(--color-primary); + border-radius: 7px; + background-color: var(--color-background); + transition: background-color 0.2s ease, border-color 0.2s ease; + font-size: 1rem; + color: inherit; +} + +.xy-theme__input:focus { + outline: none; + border-color: var(--color-primary); + box-shadow: 0 0 0 2px rgba(255, 0, 115, 0.3); +} + +/* Specific Checkbox Styling */ +.xy-theme__checkbox { + appearance: none; + -webkit-appearance: none; + width: 1.25rem; + height: 1.25rem; + border-radius: 7px; + border: 2px solid var(--color-primary); + background-color: var(--color-background); + transition: background-color 0.2s ease, border-color 0.2s ease; + cursor: pointer; + display: inline-block; + vertical-align: middle; + margin-right: 0.5rem; +} + +.xy-theme__checkbox:checked { + background-color: var(--color-primary); + border-color: var(--color-primary); +} + +.xy-theme__checkbox:focus { + outline: none; + box-shadow: 0 0 0 2px rgba(255, 0, 115, 0.3); +} + +/* Dropdown Styling */ +.xy-theme__select { + padding: 0.5rem 0.75rem; + border: 1px solid var(--color-primary); + border-radius: 50px; + background-color: var(--color-background); + transition: background-color 0.2s ease, border-color 0.2s ease; + font-size: 1rem; + color: inherit; + margin-right: 0.5rem; + box-shadow: var(--xy-node-boxshadow-default); +} + +.xy-theme__select:focus { + outline: none; + border-color: var(--color-primary); + box-shadow: 0 0 0 2px rgba(255, 0, 115, 0.3); +} + +.xy-theme__label { + margin-top: 10px; + margin-bottom: 3px; + display: inline-block; +} diff --git a/enterprise/enterprise/__init__.py b/enterprise/enterprise/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/enterprise/enterprise/ag_grid/ag_grid/__init__.py b/enterprise/enterprise/ag_grid/ag_grid/__init__.py new file mode 100644 index 0000000..b6dd028 --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/__init__.py @@ -0,0 +1 @@ +"""AG Grid Demo.""" diff --git a/enterprise/enterprise/ag_grid/ag_grid/ag_grid.py b/enterprise/enterprise/ag_grid/ag_grid/ag_grid.py new file mode 100644 index 0000000..02fb4f3 --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/ag_grid.py @@ -0,0 +1,63 @@ +"""AG Grid Demo.""" + +import reflex as rx + +from .aligned_grids import aligned_grids_page +from .cell_selection import cell_selection_page +from .common import DemoState, demo +from .editable import editable_page +from .fill_handle import fill_handle_page +from .formatters import formatter_page +from .grid_state_serialization import grid_state_serialization_simple_page +from .grid_state_serialization_advanced import grid_state_serialization_advanced_page +from .integrated_charts import integrated_chart_page +from .master_detail import master_detail_page +from .model_wrapper_customized import model_page_auth +from .model_wrapper_simple import model_page +from .model_wrapper_ssrm import model_page_ssrm +from .pivot import pivot_page +from .selected_items import selected_items_example +from .state_grid import state_grid_page +from .tree import tree_example + +__all__ = [ + "aligned_grids_page", + "cell_selection_page", + "editable_page", + "fill_handle_page", + "formatter_page", + "grid_state_serialization_advanced_page", + "grid_state_serialization_simple_page", + "integrated_chart_page", + "master_detail_page", + "model_page", + "model_page_auth", + "model_page_ssrm", + "pivot_page", + "selected_items_example", + "state_grid_page", + "tree_example", +] + + +@demo( + route="/", + title="AG Grid Demo", + description="A collection of examples using AG Grid in Reflex.", +) +def index(): + """Index page for the AG Grid demos.""" + return rx.flex( + rx.foreach( + DemoState.pages, + lambda page: rx.card( + rx.vstack( + rx.link(page.title, href=page.route), + rx.text(page.description), + ), + width="300px", + ), + ), + wrap="wrap", + spacing="3", + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/aligned_grids.py b/enterprise/enterprise/ag_grid/ag_grid/aligned_grids.py new file mode 100644 index 0000000..237936f --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/aligned_grids.py @@ -0,0 +1,66 @@ +"""Demonstrates the use of aligned grids in Reflex.""" + +import pandas as pd +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +class AlignedState(rx.State): + """State for the aligned grids demo.""" + + data: list[dict] = [] + + @rx.event + def load_data(self): + """Load data into the state.""" + df = pd.read_json("https://www.ag-grid.com/example-assets/olympic-winners.json") + self.data = df.to_dict("records") + + +column_defs = [ + {"field": "athlete"}, + {"field": "age"}, + {"field": "country"}, + {"field": "year"}, + {"field": "sport"}, + { + "header_name": "Medals", + "children": [ + { + "field": "total", + "column_group_show": "closed", + "col_id": "total", + "value_getter": "params.data.gold + params.data.silver + params.data.bronze", + "width": 100, + }, + {"field": "gold", "column_group_show": "open", "width": 100}, + {"field": "silver", "column_group_show": "open", "width": 100}, + {"field": "bronze", "column_group_show": "open", "width": 100}, + ], + }, +] + + +@demo( + route="/aligned-grids", + title="Aligned Grids", + description="Demonstrates the use of aligned grids in Reflex.", + on_load=AlignedState.load_data, +) +def aligned_grids_page(): + """Aligned grids demo.""" + return rxe.ag_grid( + id="grid1", + column_defs=column_defs, + row_data=AlignedState.data, + aligned_grids=["grid2"], + width="100%", + ), rxe.ag_grid( + id="grid2", + column_defs=column_defs, + row_data=AlignedState.data, + aligned_grids=["grid1"], + width="100%", + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/cell_selection.py b/enterprise/enterprise/ag_grid/ag_grid/cell_selection.py new file mode 100644 index 0000000..1f2a368 --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/cell_selection.py @@ -0,0 +1,68 @@ +"""Cell selection demo for AG Grid in Reflex.""" + +import pandas as pd +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +class CellSelectionState(rx.State): + """State for the cell selection demo.""" + + data: list[dict] = [] + + @rx.event + def load_data(self): + """Load data into the state.""" + df = pd.read_json("https://www.ag-grid.com/example-assets/olympic-winners.json") + self.data = df.to_dict("records") + + @rx.event + def echo_selection(self, ranges: list[dict], started: bool, finished: bool): + """Echo the selected cells.""" + if finished: + yield rx.toast(f"Selected cells: {ranges}") + + +column_defs = [ + {"field": "athlete"}, + {"field": "age"}, + {"field": "country"}, + {"field": "year"}, + {"field": "sport"}, + { + "header_name": "Medals", + "children": [ + { + "field": "total", + "column_group_show": "closed", + "col_id": "total", + "value_getter": "params.data.gold + params.data.silver + params.data.bronze", + "width": 100, + }, + {"field": "gold", "column_group_show": "open", "width": 100}, + {"field": "silver", "column_group_show": "open", "width": 100}, + {"field": "bronze", "column_group_show": "open", "width": 100}, + ], + }, +] + + +@demo( + route="/cell-selection", + title="Cell Selection", + description="Demonstrates cell selection in AG Grid.", + on_load=CellSelectionState.load_data, +) +def cell_selection_page(): + """Cell selection demo.""" + return rxe.ag_grid( + id="cell_selection_grid", + column_defs=column_defs, + row_data=CellSelectionState.data, + cell_selection=True, + on_cell_selection_changed=CellSelectionState.echo_selection, + width="100%", + height="600px", + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/common.py b/enterprise/enterprise/ag_grid/ag_grid/common.py new file mode 100644 index 0000000..ac065cb --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/common.py @@ -0,0 +1,8 @@ +"""Common components used by all demo pages.""" + +from ...demo import demo_builder + +demo, DemoState = demo_builder( + demo_prefix="/ag-grid", + demo_title="AG Grid Demo", +) diff --git a/enterprise/enterprise/ag_grid/ag_grid/editable.py b/enterprise/enterprise/ag_grid/ag_grid/editable.py new file mode 100644 index 0000000..d7a2596 --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/editable.py @@ -0,0 +1,64 @@ +"""Editable AG Grid Example.""" + +from typing import TypedDict + +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +class Person(TypedDict): + """Person type for AG Grid.""" + + name: str + age: int + country: str + + +class EditableState(rx.State): + """State for the editable demo.""" + + # This state is used to store the data for the AG Grid. + row_data: list[Person] = [ + {"name": "John", "age": 30, "country": "USA"}, + {"name": "Anna", "age": 25, "country": "Sweden"}, + {"name": "Mike", "age": 35, "country": "Canada"}, + ] + + @rx.event + def on_cell_value_changed(self, params: dict[str, str]): + """Handle cell value changes.""" + # We use node_id which represent the initial position of the changed row in the dataset. + # rowIndex is the index of the row in the grid, which may change if the grid is sorted or filtered. + row_index = int(params["node_id"]) + field = params["field"] + new_value = params["newValue"] + + # Update the row data in the state. + self.row_data[row_index][field] = new_value + + # Show a toast message with the updated value. + return rx.toast(f"Cell value changed: {field} = {new_value}") + + +column_defs = [ + {"header_name": "Name", "field": "name", "editable": True}, + {"header_name": "Age", "field": "age", "editable": True}, + {"header_name": "Country", "field": "country", "editable": True}, +] + + +@demo( + route="/editable", + title="Editable AG Grid", + description="An editable AG Grid example.", +) +def editable_page(): + """Editable AG Grid example page.""" + return rxe.ag_grid( + id="editable-grid", + column_defs=column_defs, + row_data=EditableState.row_data, # pyright: ignore [reportArgumentType], + on_cell_value_changed=EditableState.on_cell_value_changed, # pyright: ignore [reportArgumentType], + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/fill_handle.py b/enterprise/enterprise/ag_grid/ag_grid/fill_handle.py new file mode 100644 index 0000000..a9e26b3 --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/fill_handle.py @@ -0,0 +1,281 @@ +"""Fill Handle demo for AG Grid in Reflex.""" + +from typing import Any, TypedDict + +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +class DataRow(TypedDict): + """Data row type for AG Grid.""" + + athlete: str + age: int | None + country: str + year: int | None + date: str + sport: str + gold: int + silver: int + bronze: int + total: int + + +class FillHandleState(rx.State): + """State for the fill handle demo.""" + + # Sample Olympic data similar to AG Grid's example + row_data: list[DataRow] = [ + { + "athlete": "Michael Phelps", + "age": 23, + "country": "United States", + "year": 2008, + "date": "24/08/2008", + "sport": "Swimming", + "gold": 8, + "silver": 0, + "bronze": 0, + "total": 8, + }, + { + "athlete": "Michael Phelps", + "age": 19, + "country": "United States", + "year": 2004, + "date": "29/08/2004", + "sport": "Swimming", + "gold": 6, + "silver": 0, + "bronze": 2, + "total": 8, + }, + { + "athlete": "Michael Phelps", + "age": 27, + "country": "United States", + "year": 2012, + "date": "12/08/2012", + "sport": "Swimming", + "gold": 4, + "silver": 2, + "bronze": 0, + "total": 6, + }, + { + "athlete": "Natalie Coughlin", + "age": 25, + "country": "United States", + "year": 2008, + "date": "24/08/2008", + "sport": "Swimming", + "gold": 1, + "silver": 2, + "bronze": 3, + "total": 6, + }, + { + "athlete": "Aleksey Nemov", + "age": 24, + "country": "Russia", + "year": 2000, + "date": "01/10/2000", + "sport": "Gymnastics", + "gold": 2, + "silver": 1, + "bronze": 3, + "total": 6, + }, + { + "athlete": "Alicia Coutts", + "age": 24, + "country": "Australia", + "year": 2012, + "date": "12/08/2012", + "sport": "Swimming", + "gold": 1, + "silver": 3, + "bronze": 1, + "total": 5, + }, + { + "athlete": "Missy Franklin", + "age": 17, + "country": "United States", + "year": 2012, + "date": "12/08/2012", + "sport": "Swimming", + "gold": 4, + "silver": 0, + "bronze": 1, + "total": 5, + }, + { + "athlete": "Ryan Lochte", + "age": 27, + "country": "United States", + "year": 2012, + "date": "12/08/2012", + "sport": "Swimming", + "gold": 2, + "silver": 2, + "bronze": 1, + "total": 5, + }, + { + "athlete": "Allison Schmitt", + "age": 22, + "country": "United States", + "year": 2012, + "date": "12/08/2012", + "sport": "Swimming", + "gold": 3, + "silver": 1, + "bronze": 1, + "total": 5, + }, + { + "athlete": "Natalie Coughlin", + "age": 21, + "country": "United States", + "year": 2004, + "date": "29/08/2004", + "sport": "Swimming", + "gold": 2, + "silver": 2, + "bronze": 1, + "total": 5, + }, + ] + + @rx.event + def on_cell_value_changed(self, params: dict[str, Any]): + """Handle cell value changes from fill handle operations.""" + row_index = int(params["node_id"]) + field = params["field"] + new_value = params["newValue"] + + # Convert numeric fields appropriately + if field in ["age", "year", "gold", "silver", "bronze", "total"]: + try: + new_value = int(new_value) if new_value else None + except (ValueError, TypeError): + new_value = None + + # Update the row data in the state + self.row_data[row_index][field] = new_value + + return rx.toast(f"Updated {field}: {new_value}") + + +# Column definitions based on the AG Grid reference +column_defs = [ + { + "field": "athlete", + "width": 150, + "suppress_fill_handle": True, # Text fields typically don't use fill handle + }, + { + "field": "age", + "width": 90, + "editable": True, + }, + { + "field": "country", + "width": 120, + "suppress_fill_handle": True, # Country names shouldn't be filled + }, + { + "field": "year", + "width": 90, + "editable": True, + }, + { + "field": "date", + "width": 110, + "editable": True, # Enable editing and fill handle for dates + }, + { + "field": "sport", + "width": 110, + "suppress_fill_handle": True, # Sport names shouldn't be filled + }, + { + "field": "gold", + "width": 100, + "editable": True, + "type": "numericColumn", + }, + { + "field": "silver", + "width": 100, + "editable": True, + "type": "numericColumn", + }, + { + "field": "bronze", + "width": 100, + "editable": True, + "type": "numericColumn", + }, + { + "field": "total", + "width": 100, + "editable": True, + "type": "numericColumn", + }, +] + + +@demo( + route="/fill-handle", + title="Fill Handle", + description="Demonstrates the Fill Handle feature. Select cells and drag the fill handle (small square in bottom-right corner) to copy values or create series.", +) +def fill_handle_page(): + """Fill handle demo page.""" + return rx.vstack( + rx.heading("Fill Handle Demo", size="6", margin_bottom="1em"), + rx.text( + "How to use the Fill Handle:", + font_weight="bold", + margin_bottom="0.5em", + ), + rx.unordered_list( + rx.list_item("Select a cell or range of cells"), + rx.list_item( + "Look for the small square (fill handle) in the bottom-right corner" + ), + rx.list_item("Drag the fill handle to extend the selection"), + rx.list_item("For numbers: Creates incremental series (1, 2, 3...)"), + rx.list_item("For dates: Copies the date value to adjacent cells"), + rx.list_item("For single values: Copies the value to all selected cells"), + rx.list_item("Try with different data types (age, year, dates, medals)"), + margin_bottom="1em", + ), + rx.text( + "Note: Fill handle is disabled only for text fields like athlete, country, and sport to show selective control.", + color="gray", + font_size="sm", + margin_bottom="1em", + ), + rxe.ag_grid( + id="fill-handle-grid", + column_defs=column_defs, + row_data=FillHandleState.row_data, + on_cell_value_changed=FillHandleState.on_cell_value_changed, + # Configure cell selection with fill handle - single cell only + cell_selection={ + "mode": "singleCell", # Only allow single cell selection + "handle": { + "mode": "fill", # Enable fill handle + "direction": "xy", # Allow both horizontal and vertical filling + }, + }, + width="100%", + height="500px", + ), + width="100%", + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/formatters.py b/enterprise/enterprise/ag_grid/ag_grid/formatters.py new file mode 100644 index 0000000..869d14c --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/formatters.py @@ -0,0 +1,341 @@ +"""AG Grid with custom formatters.""" + +import datetime +from typing import Any, TypedDict + +import reflex as rx +import reflex_enterprise as rxe +from reflex.components import dynamic +from reflex_enterprise.components.ag_grid.resource import RendererParams + +from .common import demo + +# This ensures that `@rx.memo` components are available to cell_renderer functions. +dynamic.bundle_library("$/utils/components") + +# A regex defined as literal JS expression +GROUP_THREE_DIGITS = rx.vars.StringVar(r"/\B(?=(\d{3})+(?!\d))/g") + + +class RowData(TypedDict): + """Type for the row data.""" + + name: str + percent: float + country: str + number: float + symbol: str + + +# The row data used by this example. +row_data: list[RowData] = [ + { + "name": "John", + "percent": 0.56, + "country": "USA", + "number": 12345.6789, + "symbol": "$", + }, + { + "name": "Anna", + "percent": 0.25, + "country": "Sweden", + "number": 3243.6789, + "symbol": "€", + }, + { + "name": "Tom", + "percent": 0.12, + "country": "Germany", + "number": 12345.6789, + "symbol": "Β£", + }, + { + "name": "Mike", + "percent": 0.35, + "country": "Canada", + "number": 8745.1234, + "symbol": "$", + }, + { + "name": "Chaz", + "percent": 0.9999, + "country": "Utopia", + "number": 42.42, + "symbol": "ΰΈΏ", + }, +] + +# A formatter function can be defined in Javascript as a FunctionStringVar +PERCENT_FORMATTER = rx.vars.FunctionStringVar.create("""(params) => { +if (typeof params.value === 'undefined' || Number.isNaN(params.value)) { + return ''; +} +var rounded = (params.value * 100).toFixed(2); +return `${rounded}%`;} +""") + + +# Alternatively, a formatter can be defined as a Python function that accepts +# Var typed arguments. The following type is defined to ensure that Var +# Operations use the correct field types for the row automatically. +class FormatterParams(rx.Base): + """Type for the formatter params.""" + + data: RowData + value: str | float + + +# These python formatter functions accept Var typed arguments and may only use +# Var Operations to construct the return value. +def currency_formatter(params: rx.vars.ObjectVar[FormatterParams]) -> str: + """Format a number as currency.""" + rounded_value = round(params.data.number, 2).to_string() + money_value = rounded_value.replace(GROUP_THREE_DIGITS, ",") + return f"{params.data.symbol}{money_value}" + + +def flag_formatter(params: rx.vars.ObjectVar[FormatterParams]) -> rx.Var[str]: + """Format a country as a flag emoji.""" + return rx.Var.create( + { + "USA": "πŸ‡ΊπŸ‡Έ", + "Sweden": "πŸ‡ΈπŸ‡ͺ", + "Germany": "πŸ‡©πŸ‡ͺ", + "Canada": "πŸ‡¨πŸ‡¦", + } + ).get(params.value.to(str), "πŸ³οΈβ€πŸŒˆ") # Default to rainbow flag if country not found + + +cols_defs: list[dict] = [ + {"field": "name"}, + { + "field": "name reversed", + # synthetic column getter defined as a string (plotly style). + "value_getter": {"function": 'params.data.name.split("").reverse().join("")'}, + }, + # Formatter defined as a plain string, interpreted as a JS expression with `params` in scope. + {"field": "country", "value_formatter": "params.value.toUpperCase()"}, + # Formatter defined as FunctionStringVar. + {"field": "percent", "value_formatter": PERCENT_FORMATTER}, + { + "field": "flag", + # Synthetic column getter defined as a python lambda. + "value_getter": lambda params: params.data.country, + # Formatter defined as a python function of Var typed arguments. + "value_formatter": flag_formatter, + }, + { + "field": "number", + # Cell renderer defined as a python lambda with generic params. + "cell_renderer": lambda params: rx.text( + params.value, + font_family="monospace", + line_height="inherit", + color="rebeccapurple", + ), + }, + { + "field": "currency number", + "value_getter": "params.data.number", + # Formatter defined as a python function of Var typed arguments. + "value_formatter": currency_formatter, + }, + { + "field": "scaled number", + # Synthetic column getter defined as a plain string, interpreted as a JS expression with `params` in scope. + "value_getter": "params.data.number * params.data.percent", + # Formatter defined as a lambda with generic params (why .to(float) is needed). + "value_formatter": lambda params: round(params.value.to(float), 4), + # Renderer defined as a lambda with generic params. + "cell_renderer": lambda params: rx.tooltip( + rx.text(params.valueFormatted, line_height="inherit", width="fit-content"), + content=f"{params.data.number} * {params.data.percent}", + side="left", + ), + }, + { + "field": "row counter", + "header_name": "# Clicks (Last click)", + # Cell renderer is complex, so use `@rx.memo` component to encapsulate it. + "cell_renderer": lambda params: row_counter(rowid=params.node.id), + "sortable": False, + }, + { + "field": "raw data", + "header_name": "Show raw data", + # The component was registered with the grid and can be passed by name. + "cell_renderer": "dataDialog", + "sortable": False, + }, +] + + +# The following state and rx.memo component shows how to include complex interactive +# elements in the grid using a cell_renderer (see "row counter" field). +class RowClickCounterState(rx.State): + """Keep track of button clicks per row.""" + + row_clicks: dict[str, int] = {} + last_click: dict[str, datetime.datetime] = {} + + @rx.event + def handle_click(self, rowid: str): + """Handle a row click.""" + if rowid in self.row_clicks: + self.row_clicks[rowid] += 1 + else: + self.row_clicks[rowid] = 1 + self.last_click[rowid] = datetime.datetime.now() + + @rx.var + def button_colors(self) -> dict[str, str]: + """Get the button colors.""" + return { + rowid: "red" if count % 2 == 0 else "blue" + for rowid, count in self.row_clicks.items() + } + + +# Because react hooks cannot be evaluated at runtime, it is not possible to +# directly return dynamic components (like rx.moment) or use component event +# triggers in a renderer function. Instead, wrapping the component in rx.memo +# enables the hooks/imports/custom code to be evaluated at compile time and the +# resulting component may then referenced from an eval'd renderer function. +@rx.memo +def row_counter(rowid: str) -> rx.Component: + """Create a row counter component.""" + return rx.flex( + rx.button( + RowClickCounterState.row_clicks.get(rowid, 0), + rx.cond( + RowClickCounterState.last_click[rowid], + rx.moment( + RowClickCounterState.last_click[rowid], + format="(mm:ss)", + interval=1000, + duration_from_now=True, + ), + " (∞)", + ), + color_scheme=RowClickCounterState.button_colors.get(rowid, "gray"), + on_click=RowClickCounterState.handle_click(rowid), + ), + height="100%", + align="center", + ) + + +# Alternatively, a component can be registered with the grid at compile time and +# then set by string in the column def. Use rxe.static decorator to allow hooks, +# but preclude direct usage from state. This is fine, because in state we +# reference it by the registered name. +@rxe.static +def data_dialog(params: rx.vars.ObjectVar[RendererParams]) -> rx.Component: + """Create a data dialog component.""" + return rx.flex( + rx.dialog.root( + rx.dialog.trigger(rx.button("Raw Data")), + rx.dialog.content( + rx.dialog.title("Raw Row Data"), + rx.dialog.description("JSON representation of the row data."), + rx.code_block( + params.data.to_string(), + ), + ), + ), + height="100%", + align="center", + ) + + +class FormatterState(rx.State): + """State for the formatter demo.""" + + cols_defs: list[dict] = cols_defs + + +def formatter_grid(id: str, column_defs: Any) -> rx.Component: + """Create a grid with the given id, column defs and default props.""" + return rxe.ag_grid( + id=id, + column_defs=column_defs, + row_data=row_data, + width="100%", + height="50vh", + auto_size_strategy={"type": "fitCellContents"}, + components={ + "dataDialog": data_dialog, + }, + ) + + +@demo( + route="/formatters", + title="AG Grid Formatters", + description="AG Grid with custom formatters.", +) +def formatter_page(): + """AG Grid with custom formatters.""" + return rx.vstack( + rx.box( + row_counter(rowid=""), display="none" + ), # to ensure row_counter is compiled. + rx.text( + "Each of the three methods of setting column defs should work the same" + ), + rx.tabs.root( + rx.tabs.list( + rx.tabs.trigger( + "Inline", + value="inline", + ), + rx.tabs.trigger( + "State", + value="state", + ), + rx.tabs.trigger( + "API", + value="api", + ), + ), + rx.tabs.content( + formatter_grid( + id="formatter-grid-bare", + column_defs=cols_defs, + ), + value="inline", + ), + rx.tabs.content( + formatter_grid( + id="formatter-grid-state", + column_defs=FormatterState.cols_defs, + ), + value="state", + ), + rx.tabs.content( + rx.button( + "Set column defs", + on_click=[ + (api := rxe.ag_grid.api("formatter-grid-api")).set_grid_option( + "column_defs", + cols_defs, + ), + api.size_columns_to_fit(), + ], + ), + rx.button( + "Clear column defs", + on_click=rxe.ag_grid.api("formatter-grid-api").set_grid_option( + "columnDefs", + [], + ), + ), + formatter_grid(id="formatter-grid-api", column_defs=[]), + value="api", + ), + default_value="inline", + width="100%", + ), + width="100%", + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/grid_state_serialization.py b/enterprise/enterprise/ag_grid/ag_grid/grid_state_serialization.py new file mode 100644 index 0000000..3cf005a --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/grid_state_serialization.py @@ -0,0 +1,105 @@ +"""Grid State Serialization Example.""" + +import json + +import pandas as pd +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + +data_url = "https://www.ag-grid.com/example-assets/olympic-winners.json" + + +class GridSerializationState(rx.State): + """State for the grid serialization example.""" + + grid_state: str = rx.LocalStorage() + + grid_state_backend: list = [] + + row_data: list = [] + + @rx.event + def load_data(self): + """Load data from the URL.""" + self.row_data = pd.read_json(data_url).to_dict("records") + + @rx.event + def save_state(self, state_data: list): + """Save the columns state to local storage.""" + self.grid_state = json.dumps(state_data) + + @rx.event + def save_state_backend(self, state_data: list): + """Save the columns state to the backend.""" + self.grid_state_backend = state_data + + @rx.var + def column_state(self) -> list: + """Get the column state from local storage.""" + return json.loads(self.grid_state) if self.grid_state else [] + + +@demo( + route="/simple-serialization", + title="Grid State Serialization (Simple)", + description="AG Grid with column state serialization.", + on_load=GridSerializationState.load_data, +) +def grid_state_serialization_simple_page(): + """Grid State Serialization Example.""" + # We define the grid here to be able to access it's .api outside the grid. + grid = rxe.ag_grid( + id="grid_serialization", + column_defs=[ + {"field": "athlete"}, + {"field": "age", "value_formatter": "params.value + ' years old'"}, + {"field": "country"}, + {"field": "year"}, + ], + row_data=GridSerializationState.row_data, + width="100%", + ) + # Use grid.api.get_column_state() to get the column state and save it to local storage / backend. + return rx.vstack( + rx.hstack( + rx.button( + "Save State", + on_click=[ + grid.api.get_column_state( # pyright: ignore [reportAttributeAccessIssue] + callback=GridSerializationState.save_state + ), + rx.toast("State saved"), + ], + ), + rx.button( + "Restore State", + on_click=[ + grid.api.apply_column_state( # pyright: ignore [reportAttributeAccessIssue] + {"state": GridSerializationState.column_state} + ), + rx.toast("State restored"), + ], + ), + rx.button( + "Save State Backend", + on_click=[ + grid.api.get_column_state( # pyright: ignore [reportAttributeAccessIssue] + callback=GridSerializationState.save_state_backend + ), + rx.toast("State saved to backend"), + ], + ), + rx.button( + "Restore State Backend", + on_click=[ + grid.api.apply_column_state( # pyright: ignore [reportAttributeAccessIssue] + {"state": GridSerializationState.grid_state_backend} + ), + rx.toast("State restored from backend"), + ], + ), + ), + grid, # Finally, don't forget to add the grid to the layout. + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/grid_state_serialization_advanced.py b/enterprise/enterprise/ag_grid/ag_grid/grid_state_serialization_advanced.py new file mode 100644 index 0000000..0ae9d5c --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/grid_state_serialization_advanced.py @@ -0,0 +1,92 @@ +"""Grid State Serialization Example.""" + +import json +from typing import Any + +import pandas as pd +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + +data_url = "https://www.ag-grid.com/example-assets/olympic-winners.json" + +column_defs = [ + {"field": "athlete", "minWidth": 150, "filter": True}, + {"field": "age", "maxWidth": 90}, + {"field": "country", "minWidth": 150}, + {"field": "year", "maxWidth": 90}, + {"field": "date", "minWidth": 150}, + {"field": "sport", "minWidth": 150}, + {"field": "gold"}, + {"field": "silver"}, + {"field": "bronze"}, + {"field": "total"}, +] + +default_column_def = { + "flex": 1, + "minWidth": 100, + "filter": True, + "enableRowGroup": True, + "enablePivot": True, + "enableValue": True, +} + + +class GridSerializationAdvancedState(rx.State): + """State for the advanced grid serialization example.""" + + grid_state: str = rx.LocalStorage() + + row_data: list[dict] = [] + + @rx.event + def load_data(self): + """Load data from the URL.""" + self.row_data = pd.read_json(data_url).to_dict("records") + + @rx.event + def save_state(self, state_data: Any): + """Save the columns state to local storage.""" + self.grid_state = json.dumps(state_data["state"]) + + @rx.var + def grid_state_dict(self) -> dict: + """Get the grid state from local storage.""" + return json.loads(self.grid_state) if self.grid_state else {} + + +@demo( + route="/advanced-serialization", + title="Grid State Serialization (Advanced)", + description="AG Grid with column state serialization.", + on_load=GridSerializationAdvancedState.load_data, +) +def grid_state_serialization_advanced_page(): + """Grid State Serialization Advanced Example.""" + grid = rxe.ag_grid( + id="grid_serialization_advanced", + column_defs=column_defs, + default_column_def=default_column_def, + row_data=GridSerializationAdvancedState.row_data, + side_bar=True, + pagination=True, + row_selection={"mode": "multiRow"}, + suppress_column_move_animation=True, + initial_state=GridSerializationAdvancedState.grid_state_dict, + on_state_updated=GridSerializationAdvancedState.save_state, + community_modules={"NumberFilterModule"}, + enterprise_modules={"FiltersToolPanelModule"}, + width="100%", + height="600px", + ) + return rx.vstack( + rx.hstack( + rx.cond( + rx.State.is_hydrated, grid + ), # Finally, don't forget to add the grid to the layout. + width="100%", + ), + width="100%", + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/integrated_charts.py b/enterprise/enterprise/ag_grid/ag_grid/integrated_charts.py new file mode 100644 index 0000000..4ba9196 --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/integrated_charts.py @@ -0,0 +1,39 @@ +"""Example of handling grid selection events and displaying selected items in a separate panel.""" + +import pandas as pd +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + +df = pd.read_csv( + "https://raw.githubusercontent.com/plotly/datasets/master/wind_dataset.csv" +) + +column_defs = [ + rxe.ag_grid.column_def(field="direction"), # pyright: ignore [reportCallIssue] + rxe.ag_grid.column_def(field="strength"), # pyright: ignore [reportCallIssue] + rxe.ag_grid.column_def(field="frequency"), # pyright: ignore [reportCallIssue] +] + + +@demo( + route="/integrated-charts", + title="Integrated Charts", + description="Select a range of data, then right-click to create a chart.", +) +def integrated_chart_page(): + """Selected items example.""" + return rx.hstack( + rxe.ag_grid( + id="ag_grid_integrated_charts", + column_defs=column_defs, # pyright: ignore [reportArgumentType] + row_data=df.to_dict("records"), # pyright: ignore [reportArgumentType] + width="100%", + height="71vh", + enable_charts=True, + cell_selection=True, + enterprise_modules={"AllEnterpriseModule"}, + ), + width="100%", + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/master_detail.py b/enterprise/enterprise/ag_grid/ag_grid/master_detail.py new file mode 100644 index 0000000..d50ef2a --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/master_detail.py @@ -0,0 +1,153 @@ +"""Master Detail Demo for AG Grid.""" + +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + +# Static column definitions (non-Var) +STATIC_COLUMN_DEFS = [ + { + "field": "id", + "header_name": "ID", + "width": 80, + "cell_renderer": "agGroupCellRenderer", + }, + {"field": "name", "header_name": "Product Name", "width": 150}, + {"field": "category", "header_name": "Category", "width": 120}, + { + "field": "price", + "header_name": "Price", + "width": 100, + "value_formatter": "params.value ? '$' + params.value.toFixed(2) : ''", + }, +] + +# Static detail cell renderer params (non-Var) +STATIC_DETAIL_PARAMS = { + "detail_grid_options": { + "column_defs": [ + {"field": "count", "header_name": "Count"}, + {"field": "value", "header_name": "Description"}, + ] + }, + "get_detail_row_data": lambda params: rx.vars.function.FunctionStringVar( + "params.successCallback" + ).call(params.data.counts), +} + + +class MasterDetailState(rx.State): + """State for the master detail demo.""" + + # Sample data with nested detail information + master_data: list[dict] = [ + { + "id": 1, + "name": "Product A", + "category": "Electronics", + "price": 299.99, + "counts": [ + {"count": 10, "value": "Stock Level"}, + {"count": 5, "value": "Orders Today"}, + {"count": 25, "value": "Total Sales"}, + ], + }, + { + "id": 2, + "name": "Product B", + "category": "Clothing", + "price": 49.99, + "counts": [ + {"count": 50, "value": "Stock Level"}, + {"count": 12, "value": "Orders Today"}, + {"count": 78, "value": "Total Sales"}, + ], + }, + { + "id": 3, + "name": "Product C", + "category": "Books", + "price": 19.99, + "counts": [ + {"count": 30, "value": "Stock Level"}, + {"count": 8, "value": "Orders Today"}, + {"count": 45, "value": "Total Sales"}, + ], + }, + { + "id": 4, + "name": "Product D", + "category": "Home & Kitchen", + "price": 89.99, + "counts": [ + {"count": 20, "value": "Stock Level"}, + {"count": 3, "value": "Orders Today"}, + {"count": 15, "value": "Total Sales"}, + ], + }, + ] + + # Assign static definitions to State vars to test Var handling + column_defs: list[dict] = STATIC_COLUMN_DEFS + detail_cell_renderer_params: dict = STATIC_DETAIL_PARAMS + + +@demo( + route="/master-detail", + title="Master Detail", + description="Demonstrates AG Grid master detail functionality with expandable rows showing detailed information.", +) +def master_detail_page(): + """Master detail demo page.""" + return rx.vstack( + rx.heading("Master Detail Demo", size="6"), + rx.text( + "Click the expand icon (β–Ί) on any row to see detailed information in a nested grid below." + ), + rx.text( + "Both grids should behave identically - one uses State Vars (left) and one uses static objects (right).", + size="2", + color="gray", + ), + # Two grids side by side + rx.hstack( + # State Vars grid (left) + rx.vstack( + rx.heading("State Vars (Dynamic)", size="4", color="green"), + rx.text("Using column_defs and detail params from State", size="2"), + rxe.ag_grid( + id="state-vars-grid", + row_data=MasterDetailState.master_data, + column_defs=MasterDetailState.column_defs, + master_detail=True, + detail_cell_renderer_params=MasterDetailState.detail_cell_renderer_params, + height="400px", + width="100%", + ), + width="50%", + spacing="2", + ), + # Static objects grid (right) + rx.vstack( + rx.heading("Static Objects", size="4", color="blue"), + rx.text("Using static column definitions and detail params", size="2"), + rxe.ag_grid( + id="static-objects-grid", + row_data=MasterDetailState.master_data, + column_defs=STATIC_COLUMN_DEFS, + master_detail=True, + detail_cell_renderer_params=STATIC_DETAIL_PARAMS, + height="400px", + width="100%", + ), + width="50%", + spacing="2", + ), + spacing="4", + width="100%", + ), + spacing="4", + width="100%", + padding="4", + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/model_wrapper_customized.py b/enterprise/enterprise/ag_grid/ag_grid/model_wrapper_customized.py new file mode 100644 index 0000000..1a6cf9a --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/model_wrapper_customized.py @@ -0,0 +1,138 @@ +"""Demo of a customized ModelWrapper with auth state.""" + +from typing import Any + +import reflex as rx +import reflex_enterprise as rxe +from reflex_enterprise.components.ag_grid.datasource import DatasourceParams + +from .common import demo +from .model_wrapper_simple import Friend + + +# This bogus auth state demonstrates how an extended ModelWrapper can check +# against values in another state before returning/modifying the data. +class AuthState(rx.State): + """State for the auth demo.""" + + _logged_in: bool = False + + @rx.var + def logged_in(self) -> bool: + """Whether the user is logged in.""" + return self._logged_in + + @rx.event + def toggle_login(self): + """Toggle the login state.""" + self._logged_in = not self._logged_in + return self._refresh_grid() + + def _refresh_grid(self): + from .model_wrapper_ssrm import FriendModelWrapperSSRM + + return [ + cls.on_mount + for cls in FriendModelWrapper.__subclasses__() + + FriendModelWrapperSSRM.__subclasses__() + ] + + @rx.event + async def generate_friends(self, n: int): + """If only it were that easy...""" + from .model_wrapper_ssrm import FriendModelWrapperSSRM + + if not self._logged_in: + yield rx.toast.error("You must be logged in to generate friends.") + return + with rx.session() as session: + for f in Friend.generate_fakes(n): + session.add(f) + session.commit() + yield rx.toast.info(f"Created {n} friends.") + for cls in ( + FriendModelWrapper.__subclasses__() + + FriendModelWrapperSSRM.__subclasses__() + ): + inst = await self.get_state(cls) + yield cls._grid_component.api.set_row_count(inst._row_count()) + + +# When extending a ModelWrapper, you can override methods to customize the behavior. +class FriendModelWrapper(rxe.ModelWrapper[Friend]): + """Customized ModelWrapper for the Friend model.""" + + def _get_column_defs(self): + """In this example, we remove the ability to filter and sort a particular field.""" + cols = super()._get_column_defs() + for col in cols: + if col.field == "spouse_is_annoying": + col.filter = None + col.sortable = False + return cols + + @rx.event + async def on_value_setter( + self, row_data: dict[str, Any], field_name: str, value: Any + ): + """In this example, we prevent modifications to the data if the user is not logged in.""" + auth_state = await self.get_state(AuthState) + if not auth_state.logged_in: + return # no modification for logged out users + return await super().on_value_setter(row_data, field_name, value) + + async def _get_data( + self, + params: DatasourceParams, + ) -> list[Friend]: + auth_state = await self.get_state(AuthState) + if not auth_state.logged_in: + return [] # no records for logged out users + return await super()._get_data(params) + + @rx.var + def selected_items(self) -> list[Friend]: + """Get the selected items from the grid.""" + # Normally selected items are backend-only, but we can provide + # a computed var to render them in the UI. + return self._selected_items + + +# Advanced example of an extended ModelWrapper with custom behavior +@demo( + route="/model-auth", + title="Customized ModelWrapper", + description="Extended infinite-row ModelWrapper with custom behavior and auth.", +) +def model_page_auth(): + """Page for the customized ModelWrapper demo.""" + grid = FriendModelWrapper.create( + model_class=Friend, + row_selection={"mode": "multiRow"}, + ) + return rx.vstack( + rx.hstack( + rx.cond( + AuthState.logged_in, + rx.button("Logout", on_click=AuthState.toggle_login), + rx.button("Login", on_click=AuthState.toggle_login), + ), + rx.cond( + AuthState.logged_in, + rx.button("Generate Friends", on_click=AuthState.generate_friends(50)), + ), + rx.foreach( + grid.State.selected_items, # pyright: ignore [reportAttributeAccessIssue] + lambda friend: rx.badge(friend.name), + ) + if grid.State + else (), + rx.spacer(), + ), + rx.box( + grid, + width="100%", + height="65vh", + padding_bottom="60px", # for scroll bar and controls + ), + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/model_wrapper_simple.py b/enterprise/enterprise/ag_grid/ag_grid/model_wrapper_simple.py new file mode 100644 index 0000000..d0da614 --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/model_wrapper_simple.py @@ -0,0 +1,65 @@ +"""Simple ModelWrapper example with no customization.""" + +import datetime + +import faker +import reflex as rx +import reflex_enterprise as rxe +from sqlmodel import Column, DateTime, Field, func + +from .common import demo + + +class Friend(rx.Model, table=True): + """Friend model.""" + + name: str + age: int + years_known: int + owes_me: bool = False + has_a_dog: bool = False + spouse_is_annoying: bool = False + met: datetime.datetime = Field( + sa_column=Column(DateTime(timezone=True), server_default=func.now()), + ) + + @classmethod + def generate_fakes(cls, n: int) -> list["Friend"]: + """Generate n fake friends.""" + new_friends = [] + fake = faker.Faker() + for _ in range(n): + name = fake.name() + age = fake.random_int(min=18, max=80) + years_known = fake.random_int(min=0, max=age) + new_friends.append( + Friend( + name=name, + age=age, + years_known=years_known, + owes_me=fake.pybool(20), + has_a_dog=fake.pybool(60), + spouse_is_annoying=fake.pybool(30), + met=fake.date_time_between( + start_date=f"-{years_known + 1}y", end_date=f"-{years_known}y" + ), + ), + ) + return new_friends + + +@demo( + route="/model", + title="Simple ModelWrapper", + description="Basic example of an infinite-row ModelWrapper with no customization.", +) +def model_page(): + """Page for the simple model wrapper.""" + return rx.box( + rxe.model_wrapper( + model_class=Friend, + ), + width="100%", + height="71vh", + padding_bottom="60px", # for scroll bar and controls + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/model_wrapper_ssrm.py b/enterprise/enterprise/ag_grid/ag_grid/model_wrapper_ssrm.py new file mode 100644 index 0000000..cb286a9 --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/model_wrapper_ssrm.py @@ -0,0 +1,128 @@ +"""Demo of a customized ModelWrapper with auth state.""" + +import asyncio +from typing import Any + +import reflex as rx +import reflex_enterprise as rxe +from reflex_enterprise.components.ag_grid.datasource import SSRMDatasourceRequestParams + +from .common import demo +from .model_wrapper_customized import AuthState +from .model_wrapper_simple import Friend + + +class CustomDatasourceParams(SSRMDatasourceRequestParams): + """Custom request parameters for SSRM.""" + + sid: str + + +# When extending a ModelWrapper, you can override methods to customize the behavior. +class FriendModelWrapperSSRM(rxe.ModelWrapperSSRM[Friend]): + """Customized ModelWrapper for the Friend model.""" + + __get_data_kwargs__ = { + **rxe.ModelWrapperSSRM.__get_data_kwargs__, + "sid": lambda self: self.router.session.session_id, + } + __data_source_params_class__ = CustomDatasourceParams + + def _get_column_defs(self): + """In this example, we remove the ability to filter and sort a particular field.""" + cols = super()._get_column_defs() + for col in cols: + if col.field == "spouse_is_annoying": + col.filter = None + col.sortable = False + return cols + + @rx.event + async def on_value_setter( + self, row_data: dict[str, Any], field_name: str, value: Any + ): + """In this example, we prevent modifications to the data if the user is not logged in.""" + auth_state = await self.get_state(AuthState) + if not auth_state.logged_in: + return # no modification for logged out users + return await super().on_value_setter(row_data, field_name, value) + + async def _get_data( + self, + params: CustomDatasourceParams, + ): + print(f"_get_data: CustomDatasourceParams.sid = {params.sid}") # noqa: T201 + auth_state = await self.get_state(AuthState) + if not auth_state.logged_in: + return [] # no records for logged out users + await asyncio.sleep(0.2) + return await super()._get_data(params) + + @rx.var + def selected_items(self) -> list[Friend]: + """Get the selected items from the grid.""" + # Normally selected items are backend-only, but we can provide + # a computed var to render them in the UI. + return self._selected_items + + +# Advanced example of an extended ModelWrapper with custom behavior +@demo( + route="/model-ssrm", + title="SSRM ModelWrapper", + description="Extended SSRM ModelWrapper with custom behavior and auth.", +) +def model_page_ssrm(): + """Page for the customized ModelWrapper demo.""" + grid = FriendModelWrapperSSRM.create( + model_class=Friend, + row_selection={"mode": "multiRow"}, + loading_cell_renderer=rx.vars.function.ArgsFunctionOperation.create( + args_names=["params"], + return_expr=rx.Var.create( + rx.box( + rx.cond( + rx.Var("params.node.failedLoad"), + rx.hstack( + rx.icon("x"), + rx.text( + "Failed to load rows: ", + rx.Var("params.node.parent.failReason"), + align="center", + ), + ), + rx.hstack( + rx.spinner(), rx.text("Loading rows..."), align="center" + ), + ), + padding_x="5px", + ), + ), + ), + ) + return rx.vstack( + rx.hstack( + rx.cond( + AuthState.logged_in, + rx.button("Logout", on_click=AuthState.toggle_login), + rx.button("Login", on_click=AuthState.toggle_login), + ), + rx.cond( + AuthState.logged_in, + rx.button("Generate Friends", on_click=AuthState.generate_friends(50)), + ), + rx.foreach( + grid.State.selected_items, # pyright: ignore [reportAttributeAccessIssue] + lambda friend: rx.badge(friend.name), + ) + if grid.State + else (), + rx.spacer(), + ), + rx.box( + grid, + width="100%", + height="65vh", + padding_bottom="60px", # for scroll bar and controls + ), + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/pivot.py b/enterprise/enterprise/ag_grid/ag_grid/pivot.py new file mode 100644 index 0000000..551d227 --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/pivot.py @@ -0,0 +1,44 @@ +"""Pivot demo for AgGrid.""" + +import pandas as pd +import reflex_enterprise as rxe + +from .common import demo + +df = pd.read_json("https://www.ag-grid.com/example-assets/olympic-winners.json") + + +@demo( + route="/pivot", + title="Pivot", + description="AgGrid with pivoting", +) +def pivot_page(): + """Β¨Pivot demo.""" + return rxe.ag_grid( + id="sandbox_grid", + column_defs=[ + {"field": "country", "row_group": True}, + {"field": "sport", "pivot": True}, + {"field": "year", "pivot": True}, + {"field": "gold", "aggFunc": "sum"}, + ], + loading=False, + row_data=df.to_dict("records"), # pyright: ignore [reportArgumentType] + default_col_def={ + "flex": 1, + "min_width": 130, + "enable_value": True, + "enable_row_group": True, + "enable_pivot": True, + }, + auto_group_column_def={ + "minWidth": 200, + "pinned": "left", + }, + pivot_mode=True, + side_bar="columns", + pivot_panel_show="always", + width="100%", + height="500px", + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/selected_items.py b/enterprise/enterprise/ag_grid/ag_grid/selected_items.py new file mode 100644 index 0000000..872b945 --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/selected_items.py @@ -0,0 +1,111 @@ +"""Example of handling grid selection events and displaying selected items in a separate panel.""" + +import pandas as pd +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + +df = pd.read_csv( + "https://raw.githubusercontent.com/plotly/datasets/master/wind_dataset.csv" +) + +column_defs = [ + rxe.ag_grid.column_def(field="direction"), # pyright: ignore [reportCallIssue] + rxe.ag_grid.column_def(field="strength"), # pyright: ignore [reportCallIssue] + rxe.ag_grid.column_def(field="frequency"), # pyright: ignore [reportCallIssue] +] + + +class BasicGridState(rx.State): + """State for the basic grid example.""" + + selection: list[dict[str, str]] = [] + + keys: list[str] = [] + + @rx.event + def set_keys(self, keys: list[str]): + self.keys = [k.upper() for k in keys] + return type(self).select_by_direction + + @rx.event + def select_by_direction(self): + return grid_api.select_rows_by_key(self.keys, node_path_key="data.direction") + + +grid = rxe.ag_grid( + id="ag_grid_basic_1", + row_data=df.to_dict("records"), # pyright: ignore [reportArgumentType] + column_defs=column_defs, # pyright: ignore [reportArgumentType] + row_selection={"mode": "multiRow"}, + on_selection_changed=lambda rows, _0, _1: BasicGridState.setvar( # pyright: ignore [reportArgumentType] + "selection", rows + ), + width="50%", + height="71vh", +) +grid_api = rxe.ag_grid.api("ag_grid_basic_1") + + +def selected_item(item: dict[str, str]) -> rx.Component: + """Create a selected item component.""" + return rx.card( + rx.data_list.root( + rx.foreach( + item, + lambda kv: rx.data_list.item( + rx.data_list.label(kv[0]), + rx.data_list.value(kv[1]), + ), + ), + ), + ) + + +@demo( + route="/selected-items", + title="Selected Items", + description="Handle grid selection events and display selected items in a separate panel.", +) +def selected_items_example(): + """Selected items example.""" + return rx.hstack( + rx.vstack( + rx.text("Select by Direction"), + rxe.mantine.tags_input( + value=BasicGridState.keys, + allow_duplicates=False, + on_change=BasicGridState.set_keys, + width="10vw", + ), + rx.button( + "Select All", + on_click=[grid_api.select_all], # pyright: ignore [reportAttributeAccessIssue] + ), + rx.button( + "Deselect All", + on_click=[grid_api.deselect_all, BasicGridState.set_keys([])], # pyright: ignore [reportAttributeAccessIssue] + ), + rx.button("Log nodes", on_click=grid_api.log_nodes("data")), + ), + grid, + rx.vstack( + rx.heading( + f"Selected Items ({BasicGridState.selection.length()})", # pyright: ignore [reportAttributeAccessIssue] + size="4", + ), + rx.scroll_area( + rx.hstack( + rx.foreach( + BasicGridState.selection, + selected_item, + ), + wrap="wrap", + ), + ), + max_width="48%", + height="71vh", + ), + width="100%", + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/state_grid.py b/enterprise/enterprise/ag_grid/ag_grid/state_grid.py new file mode 100644 index 0000000..991f237 --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/state_grid.py @@ -0,0 +1,94 @@ +"""Demo of AgGrid defining columns and data in the state.""" + +from typing import Any + +import pandas as pd +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + +df = pd.read_csv( + "https://raw.githubusercontent.com/plotly/datasets/master/wind_dataset.csv" +) + + +class GridState(rx.State): + """State for the AGGrid with data and column definitions.""" + + column_defs: list[dict[str, Any]] + row_data: list[dict[str, Any]] + select_all_on_load: bool = False + + @rx.event + def load_columns(self): + """Load columns into the state.""" + self.column_defs = [ + {"field": "direction", "header_name": "DIR"}, + {"field": "strength", "headerName": "STR"}, + { + "field": "frequency", + "header_name": "HZ", + "value_formatter": "params.value + ' Hz'", + }, + ] + + @rx.event + def load_data(self): + """Load columns and data into the state.""" + self.row_data = df.to_dict("records") + + @rx.event + def clear_columns(self): + """Clear the columns from the state.""" + self.column_defs = [] + + @rx.event + def clear_data(self): + """Clear the data from the state.""" + self.row_data = [] + + +@demo( + route="/state-grid", + title="AGGrid w/ State", + description="AGGrid with data and column definitions in the state.", +) +def state_grid_page(): + """AGGrid with data and column definitions in the state.""" + return rx.container( + rx.hstack( + rx.button("Load Columns", on_click=GridState.load_columns), + rx.button("Load Data", on_click=GridState.load_data), + rx.vstack( + rx.text("Select All on Load", size="1"), + rx.switch( + checked=GridState.select_all_on_load, + on_change=GridState.set_select_all_on_load, + ), + align="center", + justify="center", + ), + rx.button("Clear Columns", on_click=GridState.clear_columns), + rx.button("Clear Data", on_click=GridState.clear_data), + padding_bottom="25px", + ), + rxe.ag_grid( + id="ag_grid_state", + column_defs=GridState.column_defs, + row_data=GridState.row_data, + row_selection={ + "mode": "multiRow", + }, + on_row_data_updated=[ + rx.cond( + GridState.select_all_on_load, + rxe.ag_grid.api(id="ag_grid_state").select_all(), + rx.noop(), + ), + GridState.set_select_all_on_load(False), + ], + width="100%", + height="71vh", + ), + ) diff --git a/enterprise/enterprise/ag_grid/ag_grid/tree.py b/enterprise/enterprise/ag_grid/ag_grid/tree.py new file mode 100644 index 0000000..4253c74 --- /dev/null +++ b/enterprise/enterprise/ag_grid/ag_grid/tree.py @@ -0,0 +1,308 @@ +"""Tree example using ag-grid.""" + +import json +from typing import Any + +import reflex as rx +import reflex_enterprise as rxe +from reflex.vars.base import Var + +from .common import demo + +human_size = rx.vars.function.ArgsFunctionOperation.create( + ["params"], + Var("""{const sizeInKb = params.value / 1024; + + if (sizeInKb > 1024) { + return `${+(sizeInKb / 1024).toFixed(2)} MB`; + } else { + return `${+sizeInKb.toFixed(2)} KB`; + }}"""), +) + + +class TreeDisplayState(rx.State): + """State for the tree display.""" + + data: list[dict[str, Any]] = [ + { + "host": "vali", + "path": ["Desktop", "ProjectAlpha", "Proposal.docx"], + "size": 512000, + "created": "2023-07-10", + "modified": "2023-08-01", + }, + { + "host": "vali", + "path": ["Desktop", "ProjectAlpha", "Timeline.xlsx"], + "size": 1048576, + "created": "2023-07-12", + "modified": "2023-08-03", + }, + { + "host": "vali", + "path": ["Desktop", "ToDoList.txt"], + "size": 51200, + "created": "2023-08-05", + "modified": "2023-08-10", + }, + { + "host": "vali", + "path": ["Desktop", "MeetingNotes_August.pdf"], + "size": 460800, + "created": "2023-08-15", + "modified": "2023-08-15", + }, + { + "host": "vidar", + "path": ["Desktop", "LaunchCodes.txt"], + "size": 32500, + "created": "1973-08-05", + "modified": "2023-08-10", + }, + { + "host": "vidar", + "path": ["Desktop", "funtime.pdf"], + "size": 460800, + "created": "2023-08-15", + "modified": "2023-08-15", + }, + { + "host": "vali", + "path": ["Documents", "Work", "ProjectAlpha", "Proposal.docx"], + "size": 512000, + "created": "2023-07-10", + "modified": "2023-08-01", + }, + { + "host": "vali", + "path": ["Documents", "Work", "ProjectAlpha", "Timeline.xlsx"], + "size": 1048576, + "created": "2023-07-12", + "modified": "2023-08-03", + }, + { + "host": "vali", + "path": ["Documents", "Work", "ProjectBeta", "Report.pdf"], + "size": 1024000, + "created": "2023-06-22", + "modified": "2023-07-15", + }, + { + "host": "vali", + "path": ["Documents", "Work", "ProjectBeta", "Budget.xlsx"], + "size": 1048576, + "created": "2023-06-25", + "modified": "2023-07-18", + }, + { + "host": "vidar", + "path": ["Documents", "Work", "Meetings", "TeamMeeting_August.pdf"], + "size": 512000, + "created": "2023-08-20", + "modified": "2023-08-21", + }, + { + "host": "vidar", + "path": ["Documents", "Work", "Meetings", "ClientMeeting_July.pdf"], + "size": 1048576, + "created": "2023-07-15", + "modified": "2023-07-16", + }, + { + "host": "vali", + "path": ["Documents", "Personal", "Taxes", "2022.pdf"], + "size": 1024000, + "created": "2023-04-10", + "modified": "2023-04-10", + }, + { + "host": "vali", + "path": ["Documents", "Personal", "Taxes", "2021.pdf"], + "size": 1048576, + "created": "2022-04-05", + "modified": "2022-04-06", + }, + { + "host": "vali", + "path": ["Documents", "Personal", "Taxes", "2020.pdf"], + "size": 1024000, + "created": "2021-04-03", + "modified": "2021-04-03", + }, + { + "host": "vali", + "path": ["Pictures", "Vacation2019", "Beach.jpg"], + "size": 1048576, + "created": "2019-07-10", + "modified": "2019-07-12", + }, + { + "host": "vali", + "path": ["Pictures", "Vacation2019", "Mountain.png"], + "size": 2048000, + "created": "2019-07-11", + "modified": "2019-07-13", + }, + { + "host": "vali", + "path": ["Pictures", "Family", "Birthday2022.jpg"], + "size": 3072000, + "created": "2022-12-15", + "modified": "2022-12-20", + }, + { + "host": "vali", + "path": ["Pictures", "Family", "Christmas2021.png"], + "size": 2048000, + "created": "2021-12-25", + "modified": "2021-12-26", + }, + { + "host": "vali", + "path": ["Videos", "Vacation2019", "Beach.mov"], + "size": 4194304, + "created": "2019-07-10", + "modified": "2019-07-12", + }, + { + "host": "vali", + "path": ["Videos", "Vacation2019", "Hiking.mp4"], + "size": 4194304, + "created": "2019-07-15", + "modified": "2019-07-16", + }, + { + "host": "vali", + "path": ["Videos", "Family", "Birthday2022.mp4"], + "size": 6291456, + "created": "2022-12-15", + "modified": "2022-12-20", + }, + { + "host": "vali", + "path": ["Videos", "Family", "Christmas2021.mov"], + "size": 6291456, + "created": "2021-12-25", + "modified": "2021-12-26", + }, + { + "host": "vidar", + "path": ["Downloads", "SoftwareInstaller.exe"], + "size": 2097152, + "created": "2023-08-01", + "modified": "2023-08-01", + }, + { + "host": "vidar", + "path": ["Downloads", "Receipt_OnlineStore.pdf"], + "size": 1048576, + "created": "2023-08-05", + "modified": "2023-08-05", + }, + { + "host": "vali", + "path": ["Downloads", "Ebook.pdf"], + "size": 1048576, + "created": "2023-08-08", + "modified": "2023-08-08", + }, + ] + combine_hosts: rx.Field[bool] = rx.field(True) + + +class GridState(rx.State): + """State for the grid demo.""" + + column_state_json: str = rx.LocalStorage() + + @rx.event + def save_column_state(self, state: list): + """Event handler to save the column state.""" + self.column_state_json = json.dumps(state) + + @rx.var + def column_state(self) -> list: + """Get the column state from the json.""" + try: + return json.loads(self.column_state_json) + except ValueError: + return [] + + +@demo( + route="/tree", + title="Tree (enterprise)", + description="Use tree data with get_data_path to visualize hierarchical information.", +) +def tree_example(): + """Tree example.""" + return rx.box( + rx.hstack( + "Combine Hosts", + rx.switch( + checked=TreeDisplayState.combine_hosts, + on_change=TreeDisplayState.setvar("combine_hosts"), + ), + rx.button( + "Save column state", + on_click=rxe.ag_grid.api("ag_grid_tree_1").get_column_state( # pyright: ignore [reportAttributeAccessIssue] + callback=GridState.save_column_state + ), + ), + rx.button( + "Load column state", + on_click=rxe.ag_grid.api("ag_grid_tree_1").apply_column_state( # pyright: ignore [reportAttributeAccessIssue] + {"state": GridState.column_state, "applyOrder": True} + ), + disabled=GridState.column_state.length() == 0, + ), + align="center", + ), + rxe.ag_grid.root( + id="ag_grid_tree_1", + row_data=TreeDisplayState.data, + auto_group_column_def=rxe.ag_grid.column_def( # pyright: ignore [reportCallIssue] + field="", + header_name="File Explorer", + min_width=280, + cell_renderer_params={"suppressCount": True}, + ), + column_defs=[ # pyright: ignore [reportArgumentType] + rxe.ag_grid.column_def(field="created"), # pyright: ignore [reportCallIssue] + rxe.ag_grid.column_def(field="modified"), # pyright: ignore [reportCallIssue] + rxe.ag_grid.column_def( # pyright: ignore [reportCallIssue] + field="size", + agg_func="sum", + value_formatter=human_size, + ), + rxe.ag_grid.column_def( # pyright: ignore [reportCallIssue] + field="host", + hide=~TreeDisplayState.combine_hosts, + agg_func=rx.vars.FunctionStringVar.create( + "(params) => params.values.join(', ').split(', ').filter((value, index, self) => self.indexOf(value) === index).join(', ')" + ), + ), + ], + default_column_def={"flex": 1}, + group_default_expanded=Var.create(0), + tree_data=True, + # get_data_path is an Initial option, it cannot be set after initialization. + get_data_path=rx.cond( + TreeDisplayState.combine_hosts, + rx.vars.function.ArgsFunctionOperation.create( + ["data"], + Var("data.path"), + ), + rx.vars.function.ArgsFunctionOperation.create( + ["data"], + Var("[data.host, ...data.path]"), + ), + ).to(rx.vars.FunctionVar), + # This key causes the grid to re-initialize when `combine_hosts` var changes + key=f"ag_grid_{TreeDisplayState.combine_hosts}", + ), + width="100%", + height="71vh", + padding_bottom="25px", # for scroll bar + ) diff --git a/enterprise/enterprise/demo.py b/enterprise/enterprise/demo.py new file mode 100644 index 0000000..85c47db --- /dev/null +++ b/enterprise/enterprise/demo.py @@ -0,0 +1,174 @@ +"""Shared components for demos.""" + +import dataclasses +import inspect +from functools import wraps +from pathlib import Path +from typing import Callable + +import reflex as rx + + +def enterprise_sidebar(): + return rx.box( + rx.box( + "Enterprise Demos", + class_name="w-full h-10 absolute top-0 left-0 flex items-center px-3 font-semibold", + ), + rx.box( + rx.vstack( + rx.link("AG Grid", href="/ag-grid"), + rx.link("Drag and Drop", href="/dnd"), + rx.link("Flow", href="/flow"), + rx.link("Mantine", href="/mantine"), + rx.link("Map", href="/map"), + spacing="2", + align_items="start", + width="100%", + ), + class_name="flex flex-col", + width="260px", + ), + bg=rx.color("gray", 2), + class_name="flex flex-col pt-12 px-3", + width="260px", + height="100vh", + overflow_y="auto", + position="fixed", + top="0", + left="0", + ) + + +@dataclasses.dataclass(frozen=True) +class DemoPage: + """A demo page.""" + + route: str + title: str + description: str + + +def demo_builder(demo_prefix: str, demo_title: str): + """Factory for demo components.""" + _DEMO_PAGES: dict[str, DemoPage] = {} + + class DemoState(rx.State): + """State for the demo pages.""" + + @rx.var + def pages(self) -> list[DemoPage]: + """List of demo pages.""" + return sorted( + [p for p in _DEMO_PAGES.values() if p.route != demo_prefix], + key=lambda p: p.title, + ) + + def demo_dropdown(): + """Dropdown to navigate between demo pages.""" + return rx.select.root( + rx.select.trigger(placeholder="Select Demo"), + rx.select.content( + rx.foreach( + DemoState.pages, + lambda page: rx.select.item( + rx.heading(page.title, size="3"), value=page.route + ), + ) + ), + value=rx.cond( + rx.State.router.page.path == demo_prefix, + "", + rx.State.router.page.path, + ), + on_change=rx.redirect, + ) + + def demo_template(page: Callable): + """Template for all demo pages.""" + page_data = _DEMO_PAGES[page.__name__] + page_file = Path(inspect.getfile(page)) + page_source = page_file.read_text() + relative_page_file = page_file.relative_to( + Path(__file__).parent.parent.parent.resolve() + ) + + page_content = rx.container( + rx.hstack( + demo_dropdown(), + rx.spacer(), + rx.link( + rx.heading(demo_title, size="4"), + href=demo_prefix, + ), + rx.color_mode.button(), + width="100%", + align="center", + ), + rx.text(page_data.description, margin_left="10px", margin_top="5px"), + rx.tabs.root( + rx.tabs.list( + rx.tabs.trigger( + rx.hstack(rx.icon("eye"), rx.text("Example")), value="example" + ), + rx.tabs.trigger( + rx.hstack(rx.icon("code"), rx.text("Source")), value="source" + ), + margin_bottom="1em", + ), + rx.tabs.content(page(), value="example", height="fit-content"), + rx.tabs.content( + rx.card( + rx.inset( + rx.badge( + rx.code(str(relative_page_file)), + width="100%", + size="2", + height="3em", + radius="none", + ), + side="top", + pb="current", + ), + rx.code_block( + page_source, language="python", show_line_numbers=True + ), + ), + value="source", + ), + default_value="example", + margin_top="1em", + ), + size="4", + ) + + return rx.box( + enterprise_sidebar(), + rx.box( + page_content, + padding="1em", + margin_left="260px", + width="calc(100% - 260px)", + ), + height="100vh", + ) + + def demo(route: str, title: str, description: str, **kwargs): + """Decorator to add the demo page to the demo registry.""" + + def decorator(page: Callable): + new_route = f"{demo_prefix}{route if route != '/' else ''}" + _DEMO_PAGES[page.__name__] = DemoPage( + route=new_route, title=title, description=description + ) + + @rx.page(route=new_route, title=title, description=description, **kwargs) + @wraps(page) + def inner(): + return demo_template(page) + + return inner + + return decorator + + return demo, DemoState diff --git a/enterprise/enterprise/dnd/dnd/__init__.py b/enterprise/enterprise/dnd/dnd/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/enterprise/enterprise/dnd/dnd/basic.py b/enterprise/enterprise/dnd/dnd/basic.py new file mode 100644 index 0000000..29b9428 --- /dev/null +++ b/enterprise/enterprise/dnd/dnd/basic.py @@ -0,0 +1,61 @@ +"""Drag and Drop Basic Demo.""" + +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +class DndState(rx.State): + """The app state.""" + + drop_points: list[int] = [0, 1, 2, 3] + + card_pos: int = 0 + + +@rx.memo +def card(): + return rxe.dnd.draggable( + rx.card( + rx.text("Draggable Thingy"), + width="199px", + height="199px", + ), + type="BasicDraggable", + border="1px solid black", + ) + + +def target(pos: int = 0): + params = rxe.dnd.DropTarget.collected_params + return rxe.dnd.drop_target( + rx.cond(DndState.card_pos == pos, card()), + width="200px", + height="200px", + border="1px solid red", + accept=["BasicDraggable"], + on_drop=[ + rx.toast(f"Dropped in position {pos}"), + DndState.setvar("card_pos", pos), + ], + background_color=rx.cond(params.is_over, "green", "blue"), + ) + + +@demo( + route="/basic", + title="Drag and Drop Basic Demo", + description="Drag and Drop when using basic components", +) +def basic_page() -> rx.Component: + return rx.container( + rx.heading("Drag and Drop Basic Demo"), + rx.grid( + target(0), + target(1), + target(2), + target(3), + columns="4", + ), + ) diff --git a/enterprise/enterprise/dnd/dnd/common.py b/enterprise/enterprise/dnd/dnd/common.py new file mode 100644 index 0000000..a17da9c --- /dev/null +++ b/enterprise/enterprise/dnd/dnd/common.py @@ -0,0 +1,8 @@ +"""Common components used by all demo pages.""" + +from ...demo import demo_builder + +demo, DemoState = demo_builder( + demo_prefix="/dnd", + demo_title="Drag and Drop demo", +) diff --git a/enterprise/enterprise/dnd/dnd/dnd.py b/enterprise/enterprise/dnd/dnd/dnd.py new file mode 100644 index 0000000..fcb0016 --- /dev/null +++ b/enterprise/enterprise/dnd/dnd/dnd.py @@ -0,0 +1,36 @@ +"""Welcome to Reflex! This file outlines the steps to create a basic app.""" + +import reflex as rx + +from .basic import basic_page +from .common import DemoState, demo +from .foreach import foreach_page +from .kanban import kanban_page + +__all__ = [ + "basic_page", + "foreach_page", + "kanban_page", +] + + +@demo( + route="/", + title="Drag and Drop Demo", + description="A collection of examples using React-Dnd in Reflex.", +) +def index(): + return rx.flex( + rx.foreach( + DemoState.pages, + lambda page: rx.card( + rx.vstack( + rx.link(page.title, href=page.route), + rx.text(page.description), + ), + width="300px", + ), + ), + wrap="wrap", + spacing="3", + ) diff --git a/enterprise/enterprise/dnd/dnd/foreach.py b/enterprise/enterprise/dnd/dnd/foreach.py new file mode 100644 index 0000000..ceb71dc --- /dev/null +++ b/enterprise/enterprise/dnd/dnd/foreach.py @@ -0,0 +1,61 @@ +"""Drag and Drop Foreach Demo.""" + +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +class DndForeachState(rx.State): + """The app state.""" + + drop_points: list[int] = [0, 1, 2, 3] + + card_pos: int = 0 + + +@rx.memo +def card_foreach(): + return rxe.dnd.draggable( + rx.card( + rx.text("Draggable Thingy"), + width="199px", + height="199px", + ), + type="ForeachDraggable", + ) + + +@rx.memo +def target_foreach(pos: int = 0): + params = rxe.dnd.DropTarget.collected_params + return rxe.dnd.drop_target( + rx.cond(DndForeachState.card_pos == pos, card_foreach()), + width="200px", + height="200px", + border="1px solid red", + on_drop=[ + rx.toast(f"Dropped in position {pos}"), + DndForeachState.setvar("card_pos", pos), + ], + accept=["ForeachDraggable"], + background_color=rx.cond(params.is_over, "green", "blue"), + ) + + +@demo( + "/foreach", + "Drag and Drop Foreach Demo", + "Drag and Drop when using Foreach", +) +def foreach_page() -> rx.Component: + return rx.container( + rx.heading("Drag and Drop w/ Foreach"), + rx.grid( + rx.foreach( + DndForeachState.drop_points, + lambda pos: target_foreach(pos=pos), + ), + columns="4", + ), + ) diff --git a/enterprise/enterprise/dnd/dnd/kanban.py b/enterprise/enterprise/dnd/dnd/kanban.py new file mode 100644 index 0000000..a95cf60 --- /dev/null +++ b/enterprise/enterprise/dnd/dnd/kanban.py @@ -0,0 +1,457 @@ +"""Kanban Drag n Drop.""" + +import dataclasses +import json +import uuid +from typing import Any, Callable, Mapping + +import reflex as rx +import reflex_enterprise as rxe +from reflex_enterprise.components.dnd import DropTargetMonitor + +from .common import demo + +COL_MIN_WIDTH = "300px" +COL_HEIGHT = "80vh" + + +@dataclasses.dataclass +class KanbanColumn: + """Kanban column.""" + + __drag_type__ = "KanbanDraggableColumn" + + id: str + title: str + description: str + order: int + + +@dataclasses.dataclass +class ItemInfo: + """Item information.""" + + __drag_type__ = "KanbanDraggableItemInfo" + + id: str + title: str + description: str = "" + order: int = 0 + column_id: str = "" + + +UnknownItem = ItemInfo(id="unknown", title="Error") + + +class KanbanState(rx.State): + _columns: dict[str, KanbanColumn] = {} + _items: dict[str, ItemInfo] = {} + + kanban_data_json: str = rx.LocalStorage() + + @rx.event + def on_load(self): + """Load the kanban data from local storage.""" + if self.kanban_data_json: + try: + data = json.loads(self.kanban_data_json) + except ValueError: + self.kanban_data_json = "" + return rx.toast("Could not load your data from browser storage, sorry.") + + for col_data in data.get("columns", []): + col = KanbanColumn(**col_data) + self._columns[col.id] = col + + for item_data in data.get("items", []): + item = ItemInfo(**item_data) + self._items[item.id] = item + + @rx.event + def on_save(self): + """Save the kanban data to local storage.""" + data = { + "columns": [dataclasses.asdict(col) for col in self._columns.values()], + "items": [dataclasses.asdict(item) for item in self._items.values()], + } + self.kanban_data_json = json.dumps(data) + + @rx.var + def items(self) -> dict[str, ItemInfo]: + """Get items.""" + return self._items + + @rx.var + def ordered_items_by_column_id(self) -> dict[str, list[ItemInfo]]: + """Get items ordered by column.""" + items_by_column = {} + for item in self._items.values(): + items_by_column.setdefault(item.column_id, []).append(item) + return { + col_id: sorted(items, key=lambda x: x.order) + for col_id, items in items_by_column.items() + } + + @rx.var + def columns(self) -> dict[str, KanbanColumn]: + """Get columns.""" + return self._columns + + @rx.var + def ordered_columns(self) -> list[KanbanColumn]: + """Get columns ordered by order.""" + columns = list(self._columns.values()) + columns.sort(key=lambda x: x.order) + return columns + + @rx.event + def on_item_drop( + self, + column_id: str, + replace_position: int, + dropped_item_data: dict[str, Any], + ): + """Handle item drop.""" + dropped_item_id = dropped_item_data.get("id") + if not dropped_item_id: + return + dropped_item = self._items.get(dropped_item_id) + if not dropped_item: + return + new_items = self.ordered_items_by_column_id.get(column_id, []) + try: + ix_prior_to_drop = new_items.index(dropped_item) + # When the item is moving to a higher position in the same column, + # decrement the replace_position to account for the item being removed + if ix_prior_to_drop < replace_position: + replace_position -= 1 + except ValueError: + # The item is not in the new column, so we don't need to adjust the position + pass + dropped_item.column_id = column_id + new_items = [ + item + for item in self.ordered_items_by_column_id.get(column_id, []) + if item.id != dropped_item.id + ] + if replace_position < 0: + new_items.append(dropped_item) + else: + new_items.insert(replace_position, dropped_item) + # Update the order for all items in the column + for ix, item in enumerate(new_items): + item.order = ix + self._items[item.id] = item + self.on_save() + + @rx.event + def on_column_drop( + self, + replace_position: int, + dropped_column_data: dict[str, Any], + ): + """Handle column drop.""" + dropped_column_id = dropped_column_data.get("id") + if not dropped_column_id: + return + dropped_column = self._columns.get(dropped_column_id) + if not dropped_column: + return + new_columns = self.ordered_columns + try: + ix_prior_to_drop = new_columns.index(dropped_column) + # When the column is moving to a higher position, decrement the + # replace_position to account for the column being removed + if ix_prior_to_drop < replace_position: + replace_position -= 1 + except ValueError: + pass + new_columns.remove(dropped_column) + if replace_position < 0: + new_columns.append(dropped_column) + else: + new_columns.insert(replace_position, dropped_column) + # Update the order for all columns + for ix, col in enumerate(new_columns): + col.order = ix + self._columns[col.id] = col + self.on_save() + + @rx.event + def new_column(self, form_data: dict[str, Any]): + """Create a new column.""" + name = form_data.get("name") + if not name: + return + col = KanbanColumn( + id=str(uuid.uuid4()), + title=name, + description="", + order=len(self._columns), + ) + self._columns[col.id] = col + self.on_save() + + @rx.event + def new_item(self, form_data: dict[str, Any]): + """Create a new item.""" + column_id = form_data.get("column_id") + name = form_data.get("name") + if not column_id or not name: + return + item = ItemInfo( + id=str(uuid.uuid4()), + title=name, + description="", + order=len(self.ordered_items_by_column_id.get(column_id, [])), + column_id=column_id, + ) + self._items[item.id] = item + self.on_save() + + @classmethod + def can_drop_item( + cls, + column_id: rx.vars.StringVar[str] | str, + replace_position: rx.vars.NumberVar[int] | int, + ) -> Callable[[rx.Var[Any], DropTargetMonitor], rx.Var[bool]]: + n_items_in_column = KanbanState.ordered_items_by_column_id.get( + column_id, [] + ).length() + + @rxe.static + def _can_drop( + item: rx.vars.ObjectVar[Mapping[str, str]], monitor: DropTargetMonitor + ) -> rx.Var[bool]: + dragged_item = cls.item_by_id(item.id) + return (dragged_item.column_id != column_id) | ~rx.Var.create( + [dragged_item.order, dragged_item.order.to(int) + 1] + ).contains( + rx.cond( + replace_position < 0, + n_items_in_column, + replace_position, + ) + ) + + return _can_drop + + @classmethod + def item_by_id(cls, item_id: rx.Var[str]) -> rx.vars.ObjectVar[ItemInfo]: + """Get an item by its ID.""" + return cls.items.get(item_id.to(str), UnknownItem).to(ItemInfo) + + @classmethod + def can_drop_column( + cls, + replace_position: rx.vars.NumberVar[int] | int, + ) -> Callable[[rx.Var[Any], DropTargetMonitor], rx.Var[bool]]: + n_columns = KanbanState.ordered_columns.length() + + @rxe.static + def _can_drop( + item: rx.vars.ObjectVar[Mapping[str, str]], monitor: DropTargetMonitor + ) -> rx.Var[bool]: + dragged_column = cls.columns[item.id] + return ~rx.Var.create( + [dragged_column.order, dragged_column.order.to(int) + 1] + ).contains( + rx.cond( + replace_position < 0, + n_columns, + replace_position, + ) + ) + + return _can_drop + + +@rx.memo +def item_card(item: ItemInfo, dragging: bool = False): + return rx.card( + rx.text(item.title), + rx.text(item.order, size="1"), + width="100%", + background_color=rx.cond(dragging, "green", "inherit"), + ) + + +@rx.memo +def item_card_drop_target(item: ItemInfo): + return item_drop_target( + column_id=item.column_id, + replace_position=item.order, + child_after=rxe.dnd.draggable( + item_card(item=item), + item={"id": item.id}, + type=ItemInfo.__drag_type__, + width="100%", + cursor=rx.cond( + rxe.dnd.Draggable.collected_params.is_dragging, + "grabbing", + "grab", + ), + on_end=lambda item: rx.toast(f"You dropped {item.id}"), + ), + ) + + +@rx.memo +def item_drop_target( + column_id: str, + replace_position: int, + child_before: rx.Component, + child_after: rx.Component, +): + params = rxe.dnd.DropTarget.collected_params + dragged_item = KanbanState.item_by_id(params.item.id) + return rxe.dnd.drop_target( + rx.vstack( + child_before, + rx.cond( + params.is_over & params.can_drop, + item_card(item=dragged_item, dragging=True), + ), + child_after, + padding="var(--space-2)", + width="100%", + ), + accept=[ItemInfo.__drag_type__], + can_drop=KanbanState.can_drop_item( + column_id=column_id, + replace_position=replace_position, + ), + on_drop=KanbanState.on_item_drop(column_id, replace_position), + width="100%", + ) + + +@rx.memo +def column_drop_target( + replace_position: int, child_before: rx.Component, child_after: rx.Component +): + params = rxe.dnd.DropTarget.collected_params + dragged_column = KanbanState.columns.get(params.item.id.to(str), None) + return rxe.dnd.drop_target( + rx.hstack( + child_before, + rx.cond( + params.is_over & params.can_drop, + kanban_column( + col=dragged_column, + dragging=True, + ), + rx.cond(params.is_over, kanban_column(col=dragged_column)), + ), + child_after, + padding="var(--space-1)", + width="100%", + ), + accept=[KanbanColumn.__drag_type__], + can_drop=KanbanState.can_drop_column( + replace_position=replace_position, + ), + on_drop=KanbanState.on_column_drop(replace_position), + width="100%", + height=COL_HEIGHT, + ) + + +@rx.memo +def kanban_column( + col: KanbanColumn, + dragging: bool = False, +): + """Render a kanban column.""" + return rx.card( + rx.vstack( + item_drop_target( + column_id=col.id, + replace_position=0, + child_before=rx.heading(col.title, width="100%"), + ), + rx.foreach( + KanbanState.ordered_items_by_column_id.get(col.id, []), + lambda item: item_card_drop_target( + item=item, + key=item.id, + ), + ), + item_drop_target( + column_id=col.id, + replace_position=-1, + child_after=rx.form( + rx.hstack( + rx.input(placeholder="New Item", name="name", flex_grow="1"), + rx.el.input(type="hidden", name="column_id", value=col.id), + rx.button("Add"), + width="100%", + ), + on_submit=KanbanState.new_item, + reset_on_submit=True, + width="100%", + cursor="default", + ), + ), + width="100%", + spacing="0", + ), + min_width=COL_MIN_WIDTH, + background_color=rx.cond(dragging, "green", "inherit"), + margin_x="0", + ) + + +@rx.memo +def kanban_column_drop_target(col: KanbanColumn): + return column_drop_target( + replace_position=col.order, + child_after=rxe.dnd.draggable( + rx.el.div( + kanban_column(col=col), + width="100%", + style={ + "&": rx.cond( + rxe.dnd.Draggable.collected_params.is_dragging, + {"display": "none", "cursor": "grabbing"}, + {"cursor": "move"}, + ) + }, + ), + item={"id": col.id}, + type=KanbanColumn.__drag_type__, + ), + ) + + +@demo( + route="/kanban", + title="Kanban Board Demo", + description="A multi-draggable UI for task management.", + on_load=KanbanState.on_load, +) +def kanban_page() -> rx.Component: + return rx.container( + rx.hstack( + rx.foreach( + KanbanState.ordered_columns, + lambda col: kanban_column_drop_target( + col=col, + key=col.id, + ), + ), + column_drop_target( + replace_position=-1, + child_after=rx.form( + rx.hstack( + rx.input(placeholder="New Column", name="name"), + rx.button("Add"), + min_width=COL_MIN_WIDTH, + ), + on_submit=KanbanState.new_column, + reset_on_submit=True, + ), + ), + spacing="0", + ), + ) diff --git a/enterprise/enterprise/enterprise.py b/enterprise/enterprise/enterprise.py new file mode 100644 index 0000000..a3930aa --- /dev/null +++ b/enterprise/enterprise/enterprise.py @@ -0,0 +1,39 @@ +"""Main entry point for the combined enterprise demos.""" + +import reflex as rx +import reflex_enterprise as rxe + +from .ag_grid.ag_grid import ag_grid +from .dnd.dnd import dnd +from .flow.flow import flow +from .mantine.mantine import mantine +from .map.map import map + +from .demo import enterprise_sidebar + + +@rx.page(route="/") +def index() -> rx.Component: + """The index page for the enterprise demos.""" + return rx.box( + enterprise_sidebar(), + rx.box( + rx.vstack( + rx.heading("Welcome to the Enterprise Demos!"), + rx.text("Select a demo from the sidebar to get started."), + align="center", + ), + padding="1em", + margin_left="260px", + width="calc(100% - 260px)", + height="100%", + display="flex", + align_items="center", + justify_content="center", + ), + height="100vh", + ) + + +# Create the app. +app = rxe.App() diff --git a/enterprise/enterprise/flow/flow/__init__.py b/enterprise/enterprise/flow/flow/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/enterprise/enterprise/flow/flow/add_nodes_on_edge_drop.py b/enterprise/enterprise/flow/flow/add_nodes_on_edge_drop.py new file mode 100644 index 0000000..3b136db --- /dev/null +++ b/enterprise/enterprise/flow/flow/add_nodes_on_edge_drop.py @@ -0,0 +1,114 @@ +"""You can create a new node when you drop the connection line on the pane by using the onConnectStart and onConnectEnd handlers.""" + +import reflex as rx +import reflex_enterprise as rxe +from reflex_enterprise.components.flow.types import ( + ConnectionInProgress, + Edge, + NoConnection, + Node, + XYPosition, +) + +from .common import demo + +initial_nodes: list[Node] = [ + { + "id": "0", + "type": "input", + "data": {"label": "Node"}, + "position": {"x": 0, "y": 50}, + }, +] + + +class AddNodesOnEdgeDropState(rx.State): + nodes: rx.Field[list[Node]] = rx.field(default_factory=lambda: initial_nodes) + edges: rx.Field[list[Edge]] = rx.field(default_factory=list) + node_id: int = 1 + + @rx.event + def increment(self): + self.node_id += 1 + + @rx.event + def set_nodes(self, nodes: list[Node]): + self.nodes = nodes + + @rx.event + def set_edges(self, edges: list[Edge]): + self.edges = edges + + @rx.event + def handle_connect_end( + self, + connection_status: NoConnection | ConnectionInProgress, + event: rx.event.PointerEventInfo, + flow_position: XYPosition, + ): + if not connection_status["isValid"]: + node_id = str(self.node_id) + self.increment() + self.nodes.append( + { + "id": node_id, + "position": flow_position, + "data": {"label": f"Node {node_id}"}, + "origin": (0.5, 0.0), + } + ) + self.edges.append( + { + "id": node_id, + "source": connection_status["fromNode"]["id"], + "target": node_id, + } + ) + + +@demo( + route="/nodes/add-node-on-edge-drop", + title="Add Node on Edge Drop Demo", + description="You can create a new node when you drop the connection line on the pane by using the onConnectStart and onConnectEnd handlers.", +) +def add_node_on_edge_drop(): + return rx.box( + rxe.flow.provider( + rxe.flow( + rxe.flow.background(), + on_connect=lambda connection: AddNodesOnEdgeDropState.set_edges( + rxe.flow.util.add_edge(connection, AddNodesOnEdgeDropState.edges) + ), + on_connect_end=( + lambda connection_status, event: ( + AddNodesOnEdgeDropState.handle_connect_end( + connection_status, + event, + rxe.flow.api.screen_to_flow_position( + x=event.client_x, + y=event.client_y, + ), + ) + ) + ), + nodes=AddNodesOnEdgeDropState.nodes, + edges=AddNodesOnEdgeDropState.edges, + on_nodes_change=lambda changes: AddNodesOnEdgeDropState.set_nodes( + rxe.flow.util.apply_node_changes( + AddNodesOnEdgeDropState.nodes, changes + ) + ), + on_edges_change=lambda changes: AddNodesOnEdgeDropState.set_edges( + rxe.flow.util.apply_edge_changes( + AddNodesOnEdgeDropState.edges, changes + ) + ), + color_mode="light", + fit_view=True, + fit_view_options={"padding": 2}, + node_origin=(0.5, 0.0), + ) + ), + height="100vh", + width="100vw", + ) diff --git a/enterprise/enterprise/flow/flow/common.py b/enterprise/enterprise/flow/flow/common.py new file mode 100644 index 0000000..e1b53d8 --- /dev/null +++ b/enterprise/enterprise/flow/flow/common.py @@ -0,0 +1,8 @@ +"""Common components used by all flow demo pages.""" + +from ...demo import demo_builder + +demo, DemoState = demo_builder( + demo_prefix="/flow", + demo_title="Flow Demo", +) diff --git a/enterprise/enterprise/flow/flow/connection_limit.py b/enterprise/enterprise/flow/flow/connection_limit.py new file mode 100644 index 0000000..feabfe6 --- /dev/null +++ b/enterprise/enterprise/flow/flow/connection_limit.py @@ -0,0 +1,95 @@ +"""This is an example of a custom node with a custom handle that can limit the amount of connections a handle can have using the isConnectable prop. + +You can use a boolean, a number (the number of max. connections the handle should have) or a callback function that returns a boolean as an arg for the isConnectable prop of the CustomHandle component.""" + +import reflex as rx +import reflex_enterprise as rxe +from reflex_enterprise.components.flow.types import Edge, HandleType, Node, Position + +from .common import demo + + +class ConnectionLimitState(rx.State): + nodes: rx.Field[list[Node]] = rx.field( + default_factory=lambda: [ + { + "id": "1", + "type": "input", + "data": {"label": "Node 1"}, + "position": {"x": 0, "y": 25}, + "sourcePosition": "right", + }, + { + "id": "2", + "type": "custom", + "data": {}, + "position": {"x": 250, "y": 50}, + }, + { + "id": "3", + "type": "input", + "data": {"label": "Node 2"}, + "position": {"x": 0, "y": 100}, + "sourcePosition": "right", + }, + ] + ) + edges: rx.Field[list[Edge]] = rx.field(default_factory=list) + + @rx.event + def set_nodes(self, nodes: list[Node]): + self.nodes = nodes + + @rx.event + def set_edges(self, edges: list[Edge]): + self.edges = edges + + +@rx.memo +def custom_handle( + type: rx.Var[HandleType], position: rx.Var[Position], connection_count: rx.Var[int] +): + connections = rxe.flow.api.get_node_connections() + return rxe.flow.handle( + type=type, + position=position, + connection_count=connection_count, + is_connectable=connections.length() < connection_count.guess_type(), + ) + + +@rx.memo +def custom_node(): + return rx.el.div( + custom_handle(type="target", position="left", connection_count=1), + rx.el.div("← Only one edge allowed"), + ) + + +@demo( + route="/nodes/connection-limit", + title="Connection Limit Demo", + description="This is an example of a custom node with a custom handle that can limit the amount of connections a handle can have using the isConnectable prop.", +) +def connection_limit(): + return rx.box( + rxe.flow( + rxe.flow.background(), + nodes=ConnectionLimitState.nodes, + edges=ConnectionLimitState.edges, + on_nodes_change=lambda changes: ConnectionLimitState.set_nodes( + rxe.flow.util.apply_node_changes(ConnectionLimitState.nodes, changes) + ), + on_edges_change=lambda changes: ConnectionLimitState.set_edges( + rxe.flow.util.apply_edge_changes(ConnectionLimitState.edges, changes) + ), + on_connect=lambda connection: ConnectionLimitState.set_edges( + rxe.flow.util.add_edge(connection, ConnectionLimitState.edges) + ), + node_types={"custom": custom_node}, + color_mode="light", + fit_view=True, + ), + height="100vh", + width="100vw", + ) diff --git a/enterprise/enterprise/flow/flow/custom_node.py b/enterprise/enterprise/flow/flow/custom_node.py new file mode 100644 index 0000000..0304198 --- /dev/null +++ b/enterprise/enterprise/flow/flow/custom_node.py @@ -0,0 +1,186 @@ +"""Creating custom nodes is as easy as building a regular React component and passing it to nodeTypes. + +Since they are standard React components, you can display any content and implement any functionality you need. Plus, you will have access to a range of props that allow you to extend and customize the default node behavior. +For more details, check out our [Custom Nodes guide](https://reactflow.dev/learn/customization/custom-nodes).""" + +from typing import Any + +import reflex as rx +import reflex_enterprise as rxe +from reflex_enterprise.components.flow.types import Connection, Edge, Node + +from .common import demo + + +class CustomNodeState(rx.State): + bg_color: rx.Field[str] = rx.field(default="#c9f1dd") + nodes: rx.Field[list[Node]] = rx.field( + default_factory=lambda: [ + { + "id": "1", + "type": "input", + "data": {"label": "An input node"}, + "position": {"x": 0, "y": 50}, + "sourcePosition": "right", + }, + { + "id": "2", + "type": "selectorNode", + "data": { + "color": "#c9f1dd", + }, + "position": {"x": 300, "y": 50}, + }, + { + "id": "3", + "type": "output", + "data": {"label": "Output A"}, + "position": {"x": 650, "y": 25}, + "targetPosition": "left", + }, + { + "id": "4", + "type": "output", + "data": {"label": "Output B"}, + "position": {"x": 650, "y": 100}, + "targetPosition": "left", + }, + ] + ) + edges: rx.Field[list[Edge]] = rx.field( + default_factory=lambda: [ + { + "id": "e1-2", + "source": "1", + "target": "2", + "animated": True, + }, + { + "id": "e2a-3", + "source": "2", + "target": "3", + "animated": True, + }, + { + "id": "e2b-4", + "source": "2", + "target": "4", + "animated": True, + }, + ] + ) + + @rx.event + def on_change_color(self, color: str): + self.nodes = [ + node + if node["id"] != "2" or "data" not in node + else {**node, "data": {**node["data"], "color": color}} + for node in self.nodes + ] + self.bg_color = color + + @rx.event + def set_nodes(self, nodes: list[Node]): + self.nodes = nodes + + @rx.event + def set_edges(self, edges: list[Edge]): + self.edges = edges + + +@rx.memo +def color_selector_node(data: rx.Var[dict[str, Any]], isConnectable: rx.Var[bool]): + data = data.to(dict) + return rx.fragment( + rxe.flow.handle( + type="target", + position="left", + on_connect=lambda params: rx.console_log(f"handle onConnect {params}"), + is_connectable=isConnectable, + ), + rx.el.div( + "Custom Color Picker Node: ", + rx.el.strong(data["color"]), + ), + rx.el.input( + class_name="nodrag", + type="color", + on_change=CustomNodeState.on_change_color, + default_value=data["color"], + ), + rxe.flow.handle( + type="source", + position="right", + is_connectable=isConnectable, + ), + ) + + +def node_stroke_color(node: rx.vars.ObjectVar[Node]): + return rx.match( + node["type"], + ("input", "#0041d0"), + ( + "selectorNode", + CustomNodeState.bg_color, + ), + ("output", "#ff0072"), + None, + ) + + +def node_color(node: rx.vars.ObjectVar[Node]): + return rx.match( + node["type"], + ( + "selectorNode", + CustomNodeState.bg_color, + ), + "#fff", + ) + + +@demo( + route="/nodes/custom-node", + title="Custom Node Demo", + description="Creating custom nodes is as easy as building a regular React component and passing it to nodeTypes.", +) +def custom_node(): + return rx.box( + rxe.flow( + rxe.flow.background(bg_color=CustomNodeState.bg_color), + rxe.flow.mini_map( + node_stroke_color=rx.vars.function.ArgsFunctionOperation.create( + ("node",), node_stroke_color(rx.Var("node").to(Node)) + ), + node_color=rx.vars.function.ArgsFunctionOperation.create( + ("node",), node_color(rx.Var("node").to(Node)) + ), + ), + rxe.flow.controls(), + nodes=CustomNodeState.nodes, + edges=CustomNodeState.edges, + on_nodes_change=lambda changes: CustomNodeState.set_nodes( + rxe.flow.util.apply_node_changes(CustomNodeState.nodes, changes) + ), + on_edges_change=lambda changes: CustomNodeState.set_edges( + rxe.flow.util.apply_edge_changes(CustomNodeState.edges, changes) + ), + on_connect=lambda connection: CustomNodeState.set_edges( + rxe.flow.util.add_edge( + connection.to(dict).merge({"animated": True}).to(Connection), + CustomNodeState.edges, + ) + ), + node_types={"selectorNode": color_selector_node}, + color_mode="light", + snap_grid=(20, 20), + default_viewport={"x": 0, "y": 0, "zoom": 1.5}, + snap_to_grid=True, + attribution_position="bottom-left", + fit_view=True, + ), + height="100vh", + width="100vw", + ) diff --git a/enterprise/enterprise/flow/flow/drag_handle.py b/enterprise/enterprise/flow/flow/drag_handle.py new file mode 100644 index 0000000..b81cc94 --- /dev/null +++ b/enterprise/enterprise/flow/flow/drag_handle.py @@ -0,0 +1,55 @@ +import reflex as rx +import reflex_enterprise as rxe +from reflex_enterprise.components.flow.types import Edge, Node + +from .common import demo + +initial_nodes: list[Node] = [ + { + "id": "2", + "type": "dragHandleNode", + "dragHandle": ".drag-handle__custom", + "position": {"x": 200, "y": 200}, + }, +] + +initial_edges: list[Edge] = [] + + +@rx.memo +def drag_handle_node(): + return rx.fragment( + rxe.flow.handle( + type="target", + position="left", + ), + rx.el.div( + "Only draggable here β†’ ", + rx.el.span(class_name="drag-handle__custom"), + class_name="drag-handle__label", + ), + rxe.flow.handle( + type="source", + position="right", + ), + ) + + +@demo( + route="/nodes/drag-handle", + title="Drag Handle Demo", + description="A demo of a node with a drag handle.", +) +def drag_handle(): + return rx.box( + rxe.flow( + rxe.flow.background(), + default_nodes=initial_nodes, + default_edges=initial_edges, + node_types={"dragHandleNode": drag_handle_node}, + color_mode="light", + fit_view=True, + ), + height="100vh", + width="100vw", + ) diff --git a/enterprise/enterprise/flow/flow/flow.py b/enterprise/enterprise/flow/flow/flow.py new file mode 100644 index 0000000..cd4acea --- /dev/null +++ b/enterprise/enterprise/flow/flow/flow.py @@ -0,0 +1,41 @@ +import reflex as rx + +# These imports are needed to register the demo pages. +from .add_nodes_on_edge_drop import add_node_on_edge_drop +from .common import DemoState, demo +from .connection_limit import connection_limit +from .custom_node import custom_node +from .drag_handle import drag_handle +from .intersections import intersections +from .overview import overview + +__all__ = [ + "add_node_on_edge_drop", + "connection_limit", + "custom_node", + "drag_handle", + "intersections", + "overview", +] + + +@demo( + route="/", + title="Flow Demo", + description="A collection of examples using React Flow in Reflex.", +) +def index(): + return rx.flex( + rx.foreach( + DemoState.pages, + lambda page: rx.card( + rx.vstack( + rx.link(page.title, href=page.route), + rx.text(page.description), + ), + width="300px", + ), + ), + wrap="wrap", + spacing="3", + ) diff --git a/enterprise/enterprise/flow/flow/intersections.py b/enterprise/enterprise/flow/flow/intersections.py new file mode 100644 index 0000000..b9e4ba0 --- /dev/null +++ b/enterprise/enterprise/flow/flow/intersections.py @@ -0,0 +1,100 @@ +import reflex as rx +import reflex_enterprise as rxe +from reflex_enterprise.components.flow.types import Edge, Node + +from .common import demo + +initial_nodes: list[Node] = [ + { + "id": "1", + "data": {"label": "Node 1"}, + "position": {"x": 0, "y": 0}, + "style": { + "width": 200, + "height": 100, + }, + }, + { + "id": "2", + "data": {"label": "Node 2"}, + "position": {"x": 0, "y": 150}, + }, + { + "id": "3", + "data": {"label": "Node 3"}, + "position": {"x": 250, "y": 0}, + }, + { + "id": "4", + "data": {"label": "Node"}, + "position": {"x": 350, "y": 150}, + "style": { + "width": 50, + "height": 50, + }, + }, +] + +initial_edges: list[Edge] = [] + + +class IntersectionsState(rx.State): + nodes: rx.Field[list[Node]] = rx.field(default_factory=lambda: initial_nodes) + edges: rx.Field[list[Edge]] = rx.field(default_factory=lambda: initial_edges) + + @rx.event + def set_nodes(self, nodes: list[Node]): + self.nodes = nodes + + @rx.event + def set_edges(self, edges: list[Edge]): + self.edges = edges + + +@demo( + route="/nodes/intersections", + title="Intersections", + description="A demo of intersecting nodes.", +) +def intersections(): + return rx.box( + rxe.flow.provider( + rxe.flow( + rxe.flow.background(), + rxe.flow.controls(), + on_nodes_change=lambda node_changes: IntersectionsState.set_nodes( + rxe.flow.util.apply_node_changes( + IntersectionsState.nodes, node_changes + ) + ), + on_edges_change=lambda edge_changes: IntersectionsState.set_edges( + rxe.flow.util.apply_edge_changes( + IntersectionsState.edges, edge_changes + ) + ), + on_node_drag=lambda node: IntersectionsState.set_nodes( + IntersectionsState.nodes.foreach( + lambda n: n.to(Node).merge( + { + "className": rx.cond( + rxe.flow.api.get_intersecting_nodes(node) + .foreach(lambda n: n["id"]) + .contains(n["id"]), + "highlight", + "", + ) + } + ) + ), + ).throttle(100), + nodes=IntersectionsState.nodes, + edges=IntersectionsState.edges, + color_mode="light", + class_name="intersection-flow", + select_nodes_on_drag=False, + fit_view=True, + ), + ), + height="100vh", + width="100vw", + ) diff --git a/enterprise/enterprise/flow/flow/overview.py b/enterprise/enterprise/flow/flow/overview.py new file mode 100644 index 0000000..6c4c06e --- /dev/null +++ b/enterprise/enterprise/flow/flow/overview.py @@ -0,0 +1,471 @@ +from typing import Any, Mapping, TypedDict + +import reflex as rx +import reflex_enterprise as rxe +from reflex_enterprise.components.flow.types import Edge, Node, Position + +from .common import demo + +initial_edges: list[Edge] = [ + { + "id": "e1-2", + "source": "1-1", + "target": "1-2", + "label": "edge", + "type": "smoothstep", + }, + { + "id": "e1-3", + "source": "1-1", + "target": "1-3", + "animated": True, + "label": "animated edge", + }, + { + "id": "e2-2", + "source": "1-2", + "target": "2-2", + "type": "smoothstep", + "markerEnd": { + "type": "arrowclosed", + }, + }, + { + "id": "e2-3", + "source": "2-2", + "target": "2-3", + "type": "smoothstep", + "markerEnd": { + "type": "arrowclosed", + }, + }, + { + "id": "e3-3", + "source": "2-3", + "sourceHandle": "a", + "target": "3-2", + "type": "button", + "animated": True, + "style": {"stroke": "rgb(158, 118, 255)"}, + }, + { + "id": "e3-4", + "source": "2-3", + "sourceHandle": "b", + "target": "3-1", + "type": "button", + }, +] + +initial_nodes: list[Node] = [ + { + "id": "annotation-1", + "type": "annotation", + "draggable": False, + "selectable": False, + "data": { + "level": 1, + "label": "Built-in node and edge types. Draggable, deletable and connectable!", + "arrowStyle": { + "right": 0, + "bottom": 0, + "transform": "translate(-30px,10px) rotate(-80deg)", + }, + }, + "position": {"x": -200, "y": -30}, + }, + { + "id": "1-1", + "type": "input", + "data": { + "label": "Input Node", + }, + "position": {"x": 150, "y": 0}, + }, + { + "id": "1-2", + "type": "default", + "data": { + "label": "Default Node", + }, + "position": {"x": 0, "y": 100}, + }, + { + "id": "1-3", + "type": "output", + "data": { + "label": "Output Node", + }, + "position": {"x": 300, "y": 100}, + }, + { + "id": "annotation-2", + "type": "annotation", + "draggable": False, + "selectable": False, + "data": { + "level": 2, + "label": "Sub flows, toolbars and resizable nodes!", + "arrowStyle": { + "left": 0, + "bottom": 0, + "transform": "translate(5px, 25px) scale(1, -1) rotate(100deg)", + }, + }, + "position": {"x": 220, "y": 200}, + }, + { + "id": "2-1", + "type": "group", + "position": { + "x": -170, + "y": 250, + }, + "style": { + "width": 380, + "height": 180, + }, + }, + { + "id": "2-2", + "data": {}, + "type": "tools", + "position": {"x": 50, "y": 50}, + "style": { + "width": 80, + "height": 80, + }, + "parentId": "2-1", + "extent": "parent", + }, + { + "id": "2-3", + "type": "resizer", + "data": { + "label": "Resize Me", + }, + "position": {"x": 250, "y": 50}, + "style": { + "width": 80, + "height": 80, + }, + "parentId": "2-1", + "extent": "parent", + }, + { + "id": "annotation-3", + "type": "annotation", + "draggable": False, + "selectable": False, + "data": { + "level": 3, + "label": "Nodes and edges can be anything and are fully customizable!", + "arrowStyle": { + "right": 0, + "bottom": 0, + "transform": "translate(-35px, 20px) rotate(-80deg)", + }, + }, + "position": {"x": -40, "y": 570}, + }, + { + "id": "3-2", + "type": "textinput", + "position": {"x": 150, "y": 650}, + "data": {}, + }, + { + "id": "3-1", + "type": "circle", + "position": {"x": 350, "y": 500}, + "data": {}, + }, +] + + +@rx.memo +def button_edge( + id: rx.Var[str], + sourceX: rx.Var[float], + sourceY: rx.Var[float], + targetX: rx.Var[float], + targetY: rx.Var[float], + sourcePosition: rx.Var[Position], + targetPosition: rx.Var[Position], + markerEnd: rx.Var[str], +): + bezier_path = rxe.components.flow.util.get_bezier_path( + source_x=sourceX, + source_y=sourceY, + target_x=targetX, + target_y=targetY, + source_position=sourcePosition, + target_position=targetPosition, + ) + return rx.fragment( + rxe.flow.base_edge(path=bezier_path.path, markerEnd=markerEnd), + rxe.flow.edge_label_renderer( + rx.el.div( + rx.el.button( + "Γ—", # noqa: RUF001 + class_name="button-edge__button", + on_click=rx.run_script( + rxe.flow.api.set_edges( + rx.vars.FunctionStringVar.create( + "Array.prototype.filter.call" + ).call( + rxe.flow.api.get_edges(), + rx.Var(f"((edge) => edge.id !== {id})"), + ), + ) + ), + ), + class_name="button-edge__label nodrag nopan", + transform=f"translate(-50%, -50%) translate({bezier_path.label_x}px,{bezier_path.label_y}px)", + ) + ), + ) + + +emojis = ["πŸš€", "πŸ”₯", "✨"] + + +@rx.memo +def toolbar_node(data: rx.vars.ObjectVar[Mapping[str, Any]]): + return rx.fragment( + rxe.flow.node_toolbar( + *[ + rx.el.button( + emoji, + key=emoji, + on_click=OverviewState.set_emoji(emoji), + custom_attrs={"aria-label": f"Select emoji {emoji}"}, + ) + for emoji in emojis + ], + is_visible=True, + ), + rx.el.div(rx.el.div(OverviewState.emoji)), + rxe.flow.handle( + type="source", + position="left", + ), + rxe.flow.handle( + type="target", + position="right", + ), + rx.el.div(data["label"]), + ) + + +@rx.memo +def circle_node( + positionAbsoluteX: rx.vars.Var[float], + positionAbsoluteY: rx.vars.Var[float], +): + label = f"Position x:{round(positionAbsoluteX.guess_type())} y:{round(positionAbsoluteY.guess_type())}" + return rx.el.div( + rx.el.div(label), + rxe.flow.handle( + type="target", + position="left", + class_name="custom-handle", + ), + ) + + +@rx.memo +def resizer_node(data: rx.vars.ObjectVar[Mapping[str, Any]]): + return rx.fragment( + rxe.flow.node_resizer( + min_width=1, + min_height=1, + ), + rxe.flow.handle( + type="target", + position="left", + class_name="custom-handle", + ), + rx.el.div(data["label"]), + rx.el.div( + rxe.flow.handle( + id="a", + type="source", + position="bottom", + class_name="resizer-node__handle custom-handle", + ), + rxe.flow.handle( + id="b", + type="source", + position="bottom", + class_name="resizer-node__handle custom-handle", + ), + class_name="resizer-node__handles", + ), + ) + + +@rx.memo +def annotation_node(data: rx.vars.ObjectVar[Mapping[str, Any]]): + return rx.fragment( + rx.el.div( + rx.el.div(data["level"], ".", class_name="annotation-level"), + rx.el.div(data["label"]), + class_name="annotation-content", + ), + rx.cond( + data["arrowStyle"], + rx.el.div( + "β€Ή", + class_name="annotation-arrow", + style=data["arrowStyle"], + ), + ), + ) + + +dimension_attrs = ["width", "height"] + + +def dimension_input(attr: str): + return rx.fragment( + rx.el.label(f"Node {attr}"), + rx.el.input( + type="number", + value=rx.cond(OverviewState.dimensions, OverviewState.dimensions[attr], 0), + on_change=lambda value: OverviewState.set_dimensions(attr, value), + class_name="text-input-node__input xy-theme__input nodrag", + ), + key=attr, + ) + + +@rx.memo +def dimension_node(id: rx.vars.Var[str]): + return rx.fragment( + *[dimension_input(attr) for attr in dimension_attrs], + rxe.flow.handle( + type="target", + position="top", + class_name="custom-handle", + ), + ) + + +class Dimensions(TypedDict): + width: float + height: float + + +class OverviewState(rx.State): + emoji: str = "πŸš€" + + nodes: rx.Field[list[Node]] = rx.field(default_factory=lambda: initial_nodes) + edges: rx.Field[list[Edge]] = rx.field(default_factory=lambda: initial_edges) + + @rx.var + def dimensions(self) -> Dimensions | None: + node = next((node for node in self.nodes if node["id"] == "2-3"), None) + if ( + not node + or not (measured := node.get("measured")) + or not (height := measured.get("height")) + or not (width := measured.get("width")) + ): + return None + return {"width": width, "height": height} + + @rx.event + def set_emoji(self, emoji: str): + self.emoji = emoji + + @rx.event + def set_nodes(self, nodes: list[Node]): + self.nodes = nodes + + @rx.event + def set_edges(self, edges: list[Edge]): + self.edges = edges + + @rx.event + def set_dimensions(self, attr: str, value_str: str): + value = float(value_str) + + def _updated_node(current_node: Node) -> Node: + parent_node = next( + (node for node in self.nodes if node["id"] == "2-1"), None + ) + parent_width = ( + parent_node.get("style", {}).get("width") if parent_node else None + ) or float("inf") + parent_height = ( + parent_node.get("style", {}).get("height") if parent_node else None + ) or float("inf") + + current_pos_x = current_node.get("position", {}).get("x", 0) + current_pos_y = current_node.get("position", {}).get("y", 0) + + max_width = max(parent_width - current_pos_x, 0) + max_height = max(parent_height - current_pos_y, 0) + + new_size = { + "width": ( + min(value, max_width) + if attr == "width" + else current_node.get("style", {}).get("width") + ), + "height": ( + min(value, max_height) + if attr == "height" + else current_node.get("style", {}).get("height") + ), + } + + return { + **current_node, + "style": {**current_node.get("style", {}), **new_size}, + } + + self.nodes = [ + node if node["id"] != "2-3" else _updated_node(node) for node in self.nodes + ] + + +@demo( + route="/overview", + title="Feature Overview", + description="A high-level overview of the features of the Flow component.", +) +def overview(): + return rx.box( + rxe.flow( + rxe.flow.mini_map( + zoomable=True, + pannable=True, + node_class_name=rx.Var("((node) => node.type)"), + ), + rxe.flow.controls(), + rxe.flow.background(), + on_nodes_change=lambda node_changes: OverviewState.set_nodes( + rxe.flow.util.apply_node_changes(OverviewState.nodes, node_changes) + ), + on_edges_change=lambda edge_changes: OverviewState.set_edges( + rxe.flow.util.apply_edge_changes(OverviewState.edges, edge_changes) + ), + nodes=OverviewState.nodes, + edges=OverviewState.edges, + node_types={ + "tools": toolbar_node, + "circle": circle_node, + "resizer": resizer_node, + "annotation": annotation_node, + "textinput": dimension_node, + }, + edge_types={"button": button_edge}, + color_mode="light", + fit_view=True, + attribution_position="top-right", + ), + height="100vh", + width="100vw", + ) diff --git a/enterprise/enterprise/mantine/mantine/__init__.py b/enterprise/enterprise/mantine/mantine/__init__.py new file mode 100644 index 0000000..e85da35 --- /dev/null +++ b/enterprise/enterprise/mantine/mantine/__init__.py @@ -0,0 +1 @@ +"""Mantine Demo app.""" diff --git a/enterprise/enterprise/mantine/mantine/accordion_demo.py b/enterprise/enterprise/mantine/mantine/accordion_demo.py new file mode 100644 index 0000000..58ebf0f --- /dev/null +++ b/enterprise/enterprise/mantine/mantine/accordion_demo.py @@ -0,0 +1,69 @@ +"""Accordion demo page.""" + +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +@demo( + route="/accordion", + title="Accordion", + description="An accordion is a component that displays a list of items in a collapsible format.", +) +def accordion_page(): + """Accordion demo page.""" + return rx.vstack( + rxe.mantine.accordion( + rxe.mantine.accordion.item( + rxe.mantine.accordion.control("Customization"), + rxe.mantine.accordion.panel( + rx.text( + "The Mantine Accordion component supports various customization options including different variants, chevron positions, and multiple selection modes." + ) + ), + value="customization", + width="100%", + ), + rxe.mantine.accordion.item( + rxe.mantine.accordion.control("Accessibility"), + rxe.mantine.accordion.panel( + rx.text( + "Accordions are keyboard accessible and follow WAI-ARIA guidelines. Users can navigate between items using arrow keys and toggle panels with Enter or Space." + ) + ), + value="accessibility", + width="100%", + ), + rxe.mantine.accordion.item( + rxe.mantine.accordion.control( + rx.hstack( + rx.icon("info"), + rx.text("With Icon"), + spacing="2", + ) + ), + rxe.mantine.accordion.panel( + rx.text( + "You can add icons or other components to the accordion control to enhance visual appearance." + ) + ), + value="icon", + width="100%", + ), + rxe.mantine.accordion.item( + rxe.mantine.accordion.control("Disabled Item", disabled=True), + rxe.mantine.accordion.panel( + rx.text("This item is disabled and cannot be opened.") + ), + value="disabled", + width="100%", + ), + variant="contained", + chevron_position="left", + default_value="customization", + multiple=True, + width="30rem", + on_change=rx.toast("Value changed"), + ), + ) diff --git a/enterprise/enterprise/mantine/mantine/action_icon_demo.py b/enterprise/enterprise/mantine/mantine/action_icon_demo.py new file mode 100644 index 0000000..e64e337 --- /dev/null +++ b/enterprise/enterprise/mantine/mantine/action_icon_demo.py @@ -0,0 +1,50 @@ +"""Action icon demo page.""" + +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +class ActionIconState(rx.State): + """State for the action icon demo.""" + + count: int = 0 + + @rx.event + def increment(self): + self.count += 1 + + @rx.event + def decrement(self): + self.count -= 1 + + +@demo( + route="/action-icon", + title="Action Icon", + description="An action icon is a small, button-like component that has an icon inside.", +) +def action_icon_page(): + """Action icon demo page.""" + return rx.hstack( + rxe.action_icon( + rx.icon("minus"), + on_click=ActionIconState.decrement, + size="xl", + variant="gradient", + disabled=ActionIconState.count <= 0, + gradient={"from": "red", "to": "orange", "deg": 90}, + ), + rx.text(f"Count: {ActionIconState.count}"), + rxe.action_icon( + rx.icon("plus"), + on_click=ActionIconState.increment, + size="xl", + variant="gradient", + disabled=ActionIconState.count >= 10, + gradient={"from": "blue", "to": "cyan", "deg": 90}, + ), + align="center", + spacing="4", + ) diff --git a/enterprise/enterprise/mantine/mantine/alert_demo.py b/enterprise/enterprise/mantine/mantine/alert_demo.py new file mode 100644 index 0000000..1780e87 --- /dev/null +++ b/enterprise/enterprise/mantine/mantine/alert_demo.py @@ -0,0 +1,48 @@ +"""Alert demo page.""" + +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +class AlertState(rx.State): + """State for the alert demo.""" + + show_alert: bool = True + + @rx.event + def toggle_alert(self): + self.show_alert = not self.show_alert + + +@demo( + route="/alert", + title="Alert", + description="An alert is used to display important information to the user.", +) +def alert_page(): + """Alert demo page.""" + return rx.hstack( + rxe.alert( + "Lorem ipsum dolor sit, amet consectetur adipisicing elit. At officiis, quae tempore necessitatibus placeat saepe.", + icon=rx.icon("info"), + title="Alert", + variant="light", + color="blue", + with_close_button=True, + radius="lg", + on_close=AlertState.toggle_alert, + display=rx.cond(AlertState.show_alert, "block", "none"), + ), + rx.cond( + ~AlertState.show_alert, + rxe.action_icon( + rx.icon("eye"), + on_click=AlertState.toggle_alert, + size="lg", + ), + ), + align="center", + spacing="4", + ) diff --git a/enterprise/enterprise/mantine/mantine/anchor_demo.py b/enterprise/enterprise/mantine/mantine/anchor_demo.py new file mode 100644 index 0000000..3e17e2f --- /dev/null +++ b/enterprise/enterprise/mantine/mantine/anchor_demo.py @@ -0,0 +1,24 @@ +"""Anchor demo page.""" + +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +@demo( + route="/anchor", + title="Anchor", + description="An anchor is a component that allows you to link to a specific page.", +) +def anchor_page(): + """Anchor demo page.""" + return rx.hstack( + rxe.anchor( + "Anchor", + href="https://build.reflex.dev/", + target="_blank", + ), + align="center", + spacing="4", + ) diff --git a/enterprise/enterprise/mantine/mantine/angle_slider_demo.py b/enterprise/enterprise/mantine/mantine/angle_slider_demo.py new file mode 100644 index 0000000..92835b1 --- /dev/null +++ b/enterprise/enterprise/mantine/mantine/angle_slider_demo.py @@ -0,0 +1,33 @@ +"""AngleSlider demo page.""" + +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +@demo( + route="/angle-slider", + title="Angle Slider", + description="An angle slider is a component that allows you to select an angle.", +) +def angle_slider_page(): + """Angle slider demo page.""" + return rx.hstack( + rxe.angle_slider( + on_change_end=lambda v: rx.toast(f"Selected angle: {v}"), + marks=[ + {"value": 0, "label": "0"}, + {"value": 45, "label": "45"}, + {"value": 90, "label": "90"}, + {"value": 135, "label": "135"}, + {"value": 180, "label": "180"}, + {"value": 225, "label": "225"}, + {"value": 270, "label": "270"}, + {"value": 315, "label": "315"}, + ], + ), + align="center", + spacing="4", + margin_top="25px", + ) diff --git a/enterprise/enterprise/mantine/mantine/aspect_ratio_demo.py b/enterprise/enterprise/mantine/mantine/aspect_ratio_demo.py new file mode 100644 index 0000000..3583a11 --- /dev/null +++ b/enterprise/enterprise/mantine/mantine/aspect_ratio_demo.py @@ -0,0 +1,25 @@ +"""Aspect Ratio demo page.""" + +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +@demo( + route="/aspect-ratio", + title="Aspect Ratio", + description="An aspect ratio is used to maintain the aspect ratio of a component.", +) +def aspect_ratio_page(): + """Aspect ratio demo page.""" + return rx.hstack( + rxe.aspect_ratio( + rx.image( + src="https://reflex.dev/logo.jpg", + ), + ratio=1 / 1, + ), + align="center", + spacing="4", + ) diff --git a/enterprise/enterprise/mantine/mantine/combobox.py b/enterprise/enterprise/mantine/mantine/combobox.py new file mode 100644 index 0000000..06cf182 --- /dev/null +++ b/enterprise/enterprise/mantine/mantine/combobox.py @@ -0,0 +1,34 @@ +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +@rx.memo +def memo_combobox(): + return rxe.mantine.combobox( + rxe.mantine.combobox.target( + rx.input( + type="button", + on_click=lambda: rx.Var("combobox.toggleDropdown()").to(rx.EventChain), + ), + ), + rxe.mantine.combobox.dropdown( + rxe.mantine.combobox.options( + rxe.mantine.combobox.option("Option 1"), + rxe.mantine.combobox.option("Option 2"), + rxe.mantine.combobox.option("Option 3"), + ), + ), + label="Combobox", + placeholder="Select a value", + ) + + +@demo( + route="/combobox", + title="Combobox", + description="A simple combobox example using Mantine.", +) +def combobox_page(): + return memo_combobox() diff --git a/enterprise/enterprise/mantine/mantine/common.py b/enterprise/enterprise/mantine/mantine/common.py new file mode 100644 index 0000000..52c3720 --- /dev/null +++ b/enterprise/enterprise/mantine/mantine/common.py @@ -0,0 +1,8 @@ +"""Common components used by all demo pages.""" + +from ...demo import demo_builder + +demo, DemoState = demo_builder( + demo_prefix="/mantine", + demo_title="Mantine demo", +) diff --git a/enterprise/enterprise/mantine/mantine/dates.py b/enterprise/enterprise/mantine/mantine/dates.py new file mode 100644 index 0000000..3c74038 --- /dev/null +++ b/enterprise/enterprise/mantine/mantine/dates.py @@ -0,0 +1,94 @@ +"""Mantine Dates Demo""" + +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +class DateState(rx.State): + """State for the Dates demo.""" + + date: str = "" + + +# @rx.memo +def picker_grid(): + return rx.grid( + rx.card( + rx.text("Calendar"), + rxe.mantine.dates.calendar(), + ), + rx.card( + rx.text("DateTimePicker"), + rxe.mantine.dates.date_time_picker( + label="Pick a Date", + placeholder="Pick date", + on_change=lambda value: rx.toast(f"Date selected: {value}"), + ), + ), + rx.card( + rx.text("DatePicker"), + rxe.mantine.dates.date_picker( + on_change=lambda value: rx.toast(f"Date selected: {value}"), + ), + ), + rx.card( + rx.text("DatePickerInput"), + rxe.mantine.dates.date_picker_input( + label="Pick a Date", + placeholder="Pick date", + on_change=lambda value: rx.toast(f"Date selected: {value}"), + ), + ), + rx.card( + rx.text("DateInput"), + rxe.mantine.dates.date_input(), + ), + rx.card( + rx.text("MonthPicker"), + rxe.mantine.dates.month_picker( + on_change=lambda value: rx.toast(f"Month selected: {value}"), + ), + ), + rx.card( + rx.text("MonthPickerInput"), + rxe.mantine.dates.month_picker_input( + on_change=lambda value: rx.toast(f"Month selected: {value}"), + ), + ), + rx.card( + rx.text("YearPicker"), + rxe.mantine.dates.year_picker( + on_change=lambda value: rx.toast(f"Year selected: {value}"), + ), + ), + rx.card( + rx.text("YearPickerInput"), + rxe.mantine.dates.year_picker_input( + on_change=lambda value: rx.toast(f"Year selected: {value}"), + ), + ), + rx.card( + rx.text("TimeInput"), + rxe.mantine.dates.time_input( + on_change=lambda value: rx.toast(f"Time selected: {value}"), + ), + ), + rx.card( + rx.text("TimePicker"), + rxe.mantine.dates.time_picker( + on_change=lambda value: rx.toast(f"Time selected: {value}"), + ), + ), + columns="3", + ) + + +@demo( + route="/dates", + title="Dates", + description="A collection of examples using Mantine Dates components in Reflex.", +) +def dates_page(): + return picker_grid() diff --git a/enterprise/enterprise/mantine/mantine/mantine.py b/enterprise/enterprise/mantine/mantine/mantine.py new file mode 100644 index 0000000..bd1fbad --- /dev/null +++ b/enterprise/enterprise/mantine/mantine/mantine.py @@ -0,0 +1,37 @@ +"""AG Grid Demo.""" + +import reflex as rx + +from .common import DemoState, demo +from .dates import dates_page +from .pill_demo import pill_page +from .tags_input import tags_input_page + +__all__ = [ + "dates_page", + "pill_page", + "tags_input_page", +] + + +@demo( + route="/", + title="Mantine Demo", + description="A collection of examples using Mantine in Reflex.", +) +def index(): + """Index page for the AG Grid demos.""" + return rx.flex( + rx.foreach( + DemoState.pages, + lambda page: rx.card( + rx.vstack( + rx.link(page.title, href=page.route), + rx.text(page.description), + ), + width="300px", + ), + ), + wrap="wrap", + spacing="3", + ) diff --git a/enterprise/enterprise/mantine/mantine/pill_demo.py b/enterprise/enterprise/mantine/mantine/pill_demo.py new file mode 100644 index 0000000..3aa0768 --- /dev/null +++ b/enterprise/enterprise/mantine/mantine/pill_demo.py @@ -0,0 +1,32 @@ +"""Pill demo page.""" + +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +@demo( + route="/pill", + title="Pill", + description="A pill is a small, rounded component that can be used to represent a single value or a small set of values.", +) +def pill_page(): + """Pill demo page.""" + return rx.vstack( + rx.hstack( + rxe.mantine.pill("Default"), + rxe.mantine.pill("Default", color="red"), + rxe.mantine.pill( + "Default", with_remove_button=True, on_remove=rx.toast("Removed") + ), + spacing="2", + ), + rxe.mantine.pill.group( + rxe.mantine.pill("Default", size="xs"), + rxe.mantine.pill("Default", size="sm"), + rxe.mantine.pill("Default", size="md"), + rxe.mantine.pill("Default", size="lg"), + ), + spacing="4", + ) diff --git a/enterprise/enterprise/mantine/mantine/tags_input.py b/enterprise/enterprise/mantine/mantine/tags_input.py new file mode 100644 index 0000000..8055c4d --- /dev/null +++ b/enterprise/enterprise/mantine/mantine/tags_input.py @@ -0,0 +1,32 @@ +import reflex as rx +import reflex_enterprise as rxe + +from .common import demo + + +class TagsInputState(rx.State): + """State for the TagsInput component.""" + + tags: list[str] = ["Tag1", "Tag2"] + + @rx.event + def update_tags(self, tags: list[str]): + """Add a tag to the list of tags.""" + self.tags = tags + + +@demo( + route="/tags-input", + title="Tags Input", + description="A simple Tags Input example using Mantine.", +) +def tags_input_page(): + return rxe.mantine.tags_input( + value=TagsInputState.tags, + on_change=TagsInputState.update_tags, + placeholder="Enter tags", + label="TagsInput", + description="This is a TagsInput component", + size="md", + radius="xl", + ) diff --git a/enterprise/enterprise/map/map/__init__.py b/enterprise/enterprise/map/map/__init__.py new file mode 100644 index 0000000..8c1f696 --- /dev/null +++ b/enterprise/enterprise/map/map/__init__.py @@ -0,0 +1 @@ +"""Map demos for Reflex Enterprise.""" diff --git a/enterprise/enterprise/map/map/common.py b/enterprise/enterprise/map/map/common.py new file mode 100644 index 0000000..5939632 --- /dev/null +++ b/enterprise/enterprise/map/map/common.py @@ -0,0 +1,8 @@ +"""Common components used by all map demo pages.""" + +from ...demo import demo_builder + +demo, DemoState = demo_builder( + demo_prefix="/map", + demo_title="Map Demos", +) diff --git a/enterprise/enterprise/map/map/fly_to_location.py b/enterprise/enterprise/map/map/fly_to_location.py new file mode 100644 index 0000000..18ac69e --- /dev/null +++ b/enterprise/enterprise/map/map/fly_to_location.py @@ -0,0 +1,137 @@ +"""Map demo showing how to fly to different locations.""" + +import reflex as rx +import reflex_enterprise as rxe +from reflex_enterprise.components.map.types import ( + LatLng, + ZoomLevelsChangeEvent, + latlng, + locate_options, +) + +from .common import demo + + +class FlyToLocationState(rx.State): + """State class for the fly-to-location map demo.""" + + # Define state variables + zoom: float = 13 + center: LatLng = latlng(lat=51.505, lng=-0.09) + location_found: LatLng | None = None + zoom_levels_changed: bool = False + + @rx.event + def handle_event(self, evt: dict): + yield rx.toast( + f"{evt['type']} {evt['latlng']}", + position="top-center", + ) + + @rx.event + def handle_zoom_levels_change(self, evt: ZoomLevelsChangeEvent): + self.zoom_levels_changed = True + yield rx.toast( + f"Zoom levels changed! Min zoom: {evt['min_zoom']}, Max zoom: {evt['max_zoom']}", + position="top-center", + level="success", + ) + + @rx.event + def handle_zoom(self, evt: dict): + self.zoom = round(evt["target"]["zoom"], 4) + + @rx.event + def handle_location_found(self, latlng_: LatLng): + """Handle location found event.""" + self.location_found = latlng(lat=latlng_["lat"], lng=latlng_["lng"], nround=4) + + +pos = latlng(lat=51.505, lng=-0.09) + + +@demo( + route="/fly-to-location", + title="Fly to Location", + description="Demonstrates flying to different map locations and using geolocation.", +) +def fly_to_location() -> rx.Component: + map_id = "my-map-foo" + my_api = rxe.map.api(map_id) + return rx.vstack( + rx.hstack( + rx.heading("Map Demo with Events"), + rx.text("Zoom: ", FlyToLocationState.zoom), + rx.text("Located: ", FlyToLocationState.location_found), + ), + # Map container with tile layer + rx.hstack( + rx.button( + "Locate", + on_click=my_api.locate( + locate_options( + max_zoom=16, + ) + ), + ), + rx.button( + "Locate and setView", + on_click=my_api.locate( + locate_options( + set_view=True, + ) + ), + ), + rx.button( + "Fly to Found Location", + on_click=rx.cond( + FlyToLocationState.location_found, + my_api.fly_to( + FlyToLocationState.location_found, FlyToLocationState.zoom + ), + None, + ), + ), + rx.button( + "Fly to center", + on_click=my_api.fly_to( + FlyToLocationState.center, FlyToLocationState.zoom + ), + ), + ), + rxe.map( + # Base tile layer + rxe.map.tile_layer( + url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", + ), + rxe.map.marker( + rxe.map.popup( + rx.button("Foo bar", on_click=rx.toast("foo bar from popup")) + ), + rxe.map.tooltip("Baz bum"), + position=pos, + ), + rxe.map.marker( + position=latlng(lat=51.515, lng=-0.1), + draggable=True, + ), + id=map_id, + zoom=FlyToLocationState.zoom, + width="100%", + center=FlyToLocationState.center, + height="50vh", + on_click=lambda e: my_api.set_view( + e.latlng, FlyToLocationState.zoom, {"animate": True} + ), + on_zoom=FlyToLocationState.handle_zoom.debounce(100), + on_locationfound=FlyToLocationState.handle_location_found, + on_locationerror=rx.toast( + "Failed to find location", + description="Check your permissions.", + level="error", + position="top-center", + ), + ), + width="100%", + padding="1em", + ) diff --git a/enterprise/enterprise/map/map/map.py b/enterprise/enterprise/map/map/map.py new file mode 100644 index 0000000..6812a39 --- /dev/null +++ b/enterprise/enterprise/map/map/map.py @@ -0,0 +1,36 @@ +"""Leaflet Map Demos for Reflex Enterprise.""" + +import reflex as rx + +from .common import DemoState, demo +from .fly_to_location import fly_to_location +from .map_controls import map_controls +from .vector_layers import vector_layers + +__all__ = [ + "fly_to_location", + "map_controls", + "vector_layers", +] + + +@demo( + route="/", + title="Map Demos", + description="A collection of examples showcasing Leaflet maps in Reflex Enterprise.", +) +def index(): + return rx.flex( + rx.foreach( + DemoState.pages, + lambda page: rx.card( + rx.vstack( + rx.link(page.title, href=page.route), + rx.text(page.description), + ), + width="300px", + ), + ), + wrap="wrap", + spacing="3", + ) diff --git a/enterprise/enterprise/map/map/map_controls.py b/enterprise/enterprise/map/map/map_controls.py new file mode 100644 index 0000000..bc3621f --- /dev/null +++ b/enterprise/enterprise/map/map/map_controls.py @@ -0,0 +1,70 @@ +"""Map demo showcasing different map controls.""" + +import reflex as rx +import reflex_enterprise as rxe +from reflex_enterprise.components.map.types import latlng + +from .common import demo + + +class ControlsState(rx.State): + """State class for the map controls demo.""" + + pass + + +@demo( + route="/map-controls", + title="Map Controls", + description="Demonstrates different map controls including zoom, scale, attribution, and layers.", +) +def map_controls() -> rx.Component: + # Create coordinates for map center + london = latlng(lat=51.505, lng=-0.09) + map_id = "map-controls-demo" + + return rx.vstack( + rx.heading("Map Controls Demo"), + rx.text("This map demonstrates different controls available in Leaflet."), + rxe.map( + # Basic tile layer + rxe.map.tile_layer( + url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", + ), + # Add ZoomControl + rxe.map.zoom_control( + position="topright", + ), + # # Add ScaleControl + rxe.map.scale_control( + position="bottomleft", + ), + # # Add AttributionControl + rxe.map.attribution_control( + position="topleft", + ), + # Map settings + id=map_id, + zoom=13, + center=london, + zoom_control=False, # Disable default zoom control + attribution_control=False, # Disable default attribution control + width="100%", + height="50vh", + ), + rx.vstack( + rx.text("Available Controls:"), + rx.unordered_list( + rx.list_item("Zoom Control - Located at topright (default is topleft)"), + rx.list_item("Scale Control - Located at bottom-left (default is off)"), + rx.list_item( + "Attribution Control - Located at topleft (default is bottom-right)" + ), + ), + align_items="flex-start", + spacing="2", + width="100%", + ), + width="100%", + padding="1em", + ) diff --git a/enterprise/enterprise/map/map/vector_layers.py b/enterprise/enterprise/map/map/vector_layers.py new file mode 100644 index 0000000..af7e85e --- /dev/null +++ b/enterprise/enterprise/map/map/vector_layers.py @@ -0,0 +1,142 @@ +"""Map demo showcasing vector layers.""" + +import reflex as rx +import reflex_enterprise as rxe +from reflex_enterprise.components.map.types import LatLng, latlng, latlng_bounds + +from .common import demo + + +class VectorLayersState(rx.State): + """State class for the vector layers map demo.""" + + # Define state variables + zoom: float = 13 + center: LatLng = latlng(lat=51.505, lng=-0.09) + + +@demo( + route="/vector-layers", + title="Vector Layers", + description="Demonstrates different vector layers like circles, polygons, polylines, and rectangles.", +) +def vector_layers() -> rx.Component: + # Create coordinates for our vector layers + center = latlng(lat=51.505, lng=-0.09) + map_id = "vector-layers-demo" + + # Create polygon coordinates + polygon_points = [ + latlng(lat=51.51, lng=-0.1), + latlng(lat=51.51, lng=-0.08), + latlng(lat=51.5, lng=-0.07), + latlng(lat=51.49, lng=-0.08), + latlng(lat=51.49, lng=-0.1), + ] + + # Create polyline coordinates + polyline_points = [ + latlng(lat=51.52, lng=-0.12), + latlng(lat=51.53, lng=-0.11), + latlng(lat=51.51, lng=-0.06), + latlng(lat=51.52, lng=-0.05), + ] + + # Create rectangle bounds + rect_bounds = latlng_bounds( + corner1_lat=51.49, # Southwest corner + corner1_lng=-0.13, + corner2_lat=51.51, # Northeast corner + corner2_lng=-0.11, + ) + + # Create path options for styling + circle_options = rxe.map.path_options( + color="#ff0000", + fill_color="#ff3333", + fill_opacity=0.5, + ) + + polygon_options = rxe.map.path_options( + color="#0033ff", + fill_color="#3366ff", + fill_opacity=0.4, + weight=2, + ) + + polyline_options = rxe.map.path_options( + color="#166516FF", + weight=5, + opacity=0.7, + line_cap="round", + dash_array="5,10", + ) + + rectangle_options = rxe.map.path_options( + color="#ff9900", + fill_color="#ffcc00", + fill_opacity=0.3, + weight=3, + ) + + return rx.vstack( + rx.heading("Vector Layers Demo"), + rx.text("This map demonstrates different vector layers available in Leaflet."), + rx.button( + "Get Bounds", + on_click=rxe.map.api(map_id).get_bounds( + callback=rx.console_log, + ), + ), + rxe.map( + # Base tile layer + rxe.map.tile_layer( + url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", + ), + # Add Circle + rxe.map.circle( + center=center, + radius=500, # 500 meters + path_options=circle_options, + ), + # Add CircleMarker (radius in pixels) + rxe.map.circle_marker( + rxe.map.tooltip("Circle Marker A"), + center=latlng(lat=51.515, lng=-0.09), + radius=15, # 15 pixels + path_options=circle_options, + ), + # Add Polygon + rxe.map.polygon( + positions=polygon_points, + path_options=polygon_options, + ), + # Add Polyline + rxe.map.polyline( + positions=polyline_points, + path_options=polyline_options, + ), + # Add Rectangle + rxe.map.rectangle( + bounds=rect_bounds, + path_options=rectangle_options, + ), + # Add markers to help with orientation + rxe.map.marker( + rxe.map.tooltip("Center point"), + position=latlng(lat=51.505, lng=-0.09), + ), + # Map settings + id=map_id, + zoom=VectorLayersState.zoom, + center=VectorLayersState.center, + width="100%", + height="50vh", + ), + rx.text( + "The map shows: a red circle (500m radius), a red circle marker (15px), a blue polygon, " + "a green dashed polyline, and an orange rectangle." + ), + width="100%", + padding="1em", + ) diff --git a/enterprise/requirements.txt b/enterprise/requirements.txt new file mode 100644 index 0000000..c1b03de --- /dev/null +++ b/enterprise/requirements.txt @@ -0,0 +1,6 @@ +reflex>=0.8.11 +reflex-enterprise>=0.3.2 +faker==36.2.2 +pandas==2.2.3 +aiosqlite +greenlet \ No newline at end of file diff --git a/enterprise/rxconfig.py b/enterprise/rxconfig.py new file mode 100644 index 0000000..e6bb383 --- /dev/null +++ b/enterprise/rxconfig.py @@ -0,0 +1,13 @@ +"""Configuration for the enterprise demos.""" + +import reflex as rx +import reflex_enterprise as rxe + +config = rxe.Config( + app_name="enterprise", + async_db_url="sqlite+aiosqlite:///reflex.db", + use_single_port=True, + disable_plugins=["reflex.plugins.sitemap.SitemapPlugin"], + stylesheets=["xy-theme.css", "style.css"], + plugins=[rx.plugins.TailwindV4Plugin()], +) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1a2bb80 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,10 @@ +[project] +name = "templates" +version = "0.0.1" +readme = "README.md" +requires-python = ">=3.11" +dependencies = [ + "reflex @ git+https://github.com/reflex-dev/reflex@main", + "reflex-enterprise>=0.3.4", + "pre-commit>=3.7.0", +] diff --git a/templates.json b/templates.json index 9b04ffa..efe2bd9 100644 --- a/templates.json +++ b/templates.json @@ -186,6 +186,13 @@ "demo_url": "https://retail-dashboard-navy-wood.reflex.run/", "hidden": false, "reflex_build": true + }, + { + "name": "enterprise", + "description": "A collection of enterprise related components", + "demo_url": "https://enterprise-demos.reflex.run/", + "hidden": false, + "reflex_build": false } ] } diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..7441bc1 --- /dev/null +++ b/uv.lock @@ -0,0 +1,1427 @@ +version = 1 +revision = 2 +requires-python = ">=3.11" + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.12.15" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9b/e7/d92a237d8802ca88483906c388f7c201bbe96cd80a165ffd0ac2f6a8d59f/aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2", size = 7823716, upload-time = "2025-07-29T05:52:32.215Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/19/9e86722ec8e835959bd97ce8c1efa78cf361fa4531fca372551abcc9cdd6/aiohttp-3.12.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d3ce17ce0220383a0f9ea07175eeaa6aa13ae5a41f30bc61d84df17f0e9b1117", size = 711246, upload-time = "2025-07-29T05:50:15.937Z" }, + { url = "https://files.pythonhosted.org/packages/71/f9/0a31fcb1a7d4629ac9d8f01f1cb9242e2f9943f47f5d03215af91c3c1a26/aiohttp-3.12.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:010cc9bbd06db80fe234d9003f67e97a10fe003bfbedb40da7d71c1008eda0fe", size = 483515, upload-time = "2025-07-29T05:50:17.442Z" }, + { url = "https://files.pythonhosted.org/packages/62/6c/94846f576f1d11df0c2e41d3001000527c0fdf63fce7e69b3927a731325d/aiohttp-3.12.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f9d7c55b41ed687b9d7165b17672340187f87a773c98236c987f08c858145a9", size = 471776, upload-time = "2025-07-29T05:50:19.568Z" }, + { url = "https://files.pythonhosted.org/packages/f8/6c/f766d0aaafcee0447fad0328da780d344489c042e25cd58fde566bf40aed/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc4fbc61bb3548d3b482f9ac7ddd0f18c67e4225aaa4e8552b9f1ac7e6bda9e5", size = 1741977, upload-time = "2025-07-29T05:50:21.665Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/fb779a05ba6ff44d7bc1e9d24c644e876bfff5abe5454f7b854cace1b9cc/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7fbc8a7c410bb3ad5d595bb7118147dfbb6449d862cc1125cf8867cb337e8728", size = 1690645, upload-time = "2025-07-29T05:50:23.333Z" }, + { url = "https://files.pythonhosted.org/packages/37/4e/a22e799c2035f5d6a4ad2cf8e7c1d1bd0923192871dd6e367dafb158b14c/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74dad41b3458dbb0511e760fb355bb0b6689e0630de8a22b1b62a98777136e16", size = 1789437, upload-time = "2025-07-29T05:50:25.007Z" }, + { url = "https://files.pythonhosted.org/packages/28/e5/55a33b991f6433569babb56018b2fb8fb9146424f8b3a0c8ecca80556762/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b6f0af863cf17e6222b1735a756d664159e58855da99cfe965134a3ff63b0b0", size = 1828482, upload-time = "2025-07-29T05:50:26.693Z" }, + { url = "https://files.pythonhosted.org/packages/c6/82/1ddf0ea4f2f3afe79dffed5e8a246737cff6cbe781887a6a170299e33204/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5b7fe4972d48a4da367043b8e023fb70a04d1490aa7d68800e465d1b97e493b", size = 1730944, upload-time = "2025-07-29T05:50:28.382Z" }, + { url = "https://files.pythonhosted.org/packages/1b/96/784c785674117b4cb3877522a177ba1b5e4db9ce0fd519430b5de76eec90/aiohttp-3.12.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6443cca89553b7a5485331bc9bedb2342b08d073fa10b8c7d1c60579c4a7b9bd", size = 1668020, upload-time = "2025-07-29T05:50:30.032Z" }, + { url = "https://files.pythonhosted.org/packages/12/8a/8b75f203ea7e5c21c0920d84dd24a5c0e971fe1e9b9ebbf29ae7e8e39790/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c5f40ec615e5264f44b4282ee27628cea221fcad52f27405b80abb346d9f3f8", size = 1716292, upload-time = "2025-07-29T05:50:31.983Z" }, + { url = "https://files.pythonhosted.org/packages/47/0b/a1451543475bb6b86a5cfc27861e52b14085ae232896a2654ff1231c0992/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2abbb216a1d3a2fe86dbd2edce20cdc5e9ad0be6378455b05ec7f77361b3ab50", size = 1711451, upload-time = "2025-07-29T05:50:33.989Z" }, + { url = "https://files.pythonhosted.org/packages/55/fd/793a23a197cc2f0d29188805cfc93aa613407f07e5f9da5cd1366afd9d7c/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:db71ce547012a5420a39c1b744d485cfb823564d01d5d20805977f5ea1345676", size = 1691634, upload-time = "2025-07-29T05:50:35.846Z" }, + { url = "https://files.pythonhosted.org/packages/ca/bf/23a335a6670b5f5dfc6d268328e55a22651b440fca341a64fccf1eada0c6/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ced339d7c9b5030abad5854aa5413a77565e5b6e6248ff927d3e174baf3badf7", size = 1785238, upload-time = "2025-07-29T05:50:37.597Z" }, + { url = "https://files.pythonhosted.org/packages/57/4f/ed60a591839a9d85d40694aba5cef86dde9ee51ce6cca0bb30d6eb1581e7/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7c7dd29c7b5bda137464dc9bfc738d7ceea46ff70309859ffde8c022e9b08ba7", size = 1805701, upload-time = "2025-07-29T05:50:39.591Z" }, + { url = "https://files.pythonhosted.org/packages/85/e0/444747a9455c5de188c0f4a0173ee701e2e325d4b2550e9af84abb20cdba/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:421da6fd326460517873274875c6c5a18ff225b40da2616083c5a34a7570b685", size = 1718758, upload-time = "2025-07-29T05:50:41.292Z" }, + { url = "https://files.pythonhosted.org/packages/36/ab/1006278d1ffd13a698e5dd4bfa01e5878f6bddefc296c8b62649753ff249/aiohttp-3.12.15-cp311-cp311-win32.whl", hash = "sha256:4420cf9d179ec8dfe4be10e7d0fe47d6d606485512ea2265b0d8c5113372771b", size = 428868, upload-time = "2025-07-29T05:50:43.063Z" }, + { url = "https://files.pythonhosted.org/packages/10/97/ad2b18700708452400278039272032170246a1bf8ec5d832772372c71f1a/aiohttp-3.12.15-cp311-cp311-win_amd64.whl", hash = "sha256:edd533a07da85baa4b423ee8839e3e91681c7bfa19b04260a469ee94b778bf6d", size = 453273, upload-time = "2025-07-29T05:50:44.613Z" }, + { url = "https://files.pythonhosted.org/packages/63/97/77cb2450d9b35f517d6cf506256bf4f5bda3f93a66b4ad64ba7fc917899c/aiohttp-3.12.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:802d3868f5776e28f7bf69d349c26fc0efadb81676d0afa88ed00d98a26340b7", size = 702333, upload-time = "2025-07-29T05:50:46.507Z" }, + { url = "https://files.pythonhosted.org/packages/83/6d/0544e6b08b748682c30b9f65640d006e51f90763b41d7c546693bc22900d/aiohttp-3.12.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2800614cd560287be05e33a679638e586a2d7401f4ddf99e304d98878c29444", size = 476948, upload-time = "2025-07-29T05:50:48.067Z" }, + { url = "https://files.pythonhosted.org/packages/3a/1d/c8c40e611e5094330284b1aea8a4b02ca0858f8458614fa35754cab42b9c/aiohttp-3.12.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8466151554b593909d30a0a125d638b4e5f3836e5aecde85b66b80ded1cb5b0d", size = 469787, upload-time = "2025-07-29T05:50:49.669Z" }, + { url = "https://files.pythonhosted.org/packages/38/7d/b76438e70319796bfff717f325d97ce2e9310f752a267bfdf5192ac6082b/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e5a495cb1be69dae4b08f35a6c4579c539e9b5706f606632102c0f855bcba7c", size = 1716590, upload-time = "2025-07-29T05:50:51.368Z" }, + { url = "https://files.pythonhosted.org/packages/79/b1/60370d70cdf8b269ee1444b390cbd72ce514f0d1cd1a715821c784d272c9/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6404dfc8cdde35c69aaa489bb3542fb86ef215fc70277c892be8af540e5e21c0", size = 1699241, upload-time = "2025-07-29T05:50:53.628Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2b/4968a7b8792437ebc12186db31523f541943e99bda8f30335c482bea6879/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ead1c00f8521a5c9070fcb88f02967b1d8a0544e6d85c253f6968b785e1a2ab", size = 1754335, upload-time = "2025-07-29T05:50:55.394Z" }, + { url = "https://files.pythonhosted.org/packages/fb/c1/49524ed553f9a0bec1a11fac09e790f49ff669bcd14164f9fab608831c4d/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6990ef617f14450bc6b34941dba4f12d5613cbf4e33805932f853fbd1cf18bfb", size = 1800491, upload-time = "2025-07-29T05:50:57.202Z" }, + { url = "https://files.pythonhosted.org/packages/de/5e/3bf5acea47a96a28c121b167f5ef659cf71208b19e52a88cdfa5c37f1fcc/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd736ed420f4db2b8148b52b46b88ed038d0354255f9a73196b7bbce3ea97545", size = 1719929, upload-time = "2025-07-29T05:50:59.192Z" }, + { url = "https://files.pythonhosted.org/packages/39/94/8ae30b806835bcd1cba799ba35347dee6961a11bd507db634516210e91d8/aiohttp-3.12.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c5092ce14361a73086b90c6efb3948ffa5be2f5b6fbcf52e8d8c8b8848bb97c", size = 1635733, upload-time = "2025-07-29T05:51:01.394Z" }, + { url = "https://files.pythonhosted.org/packages/7a/46/06cdef71dd03acd9da7f51ab3a9107318aee12ad38d273f654e4f981583a/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aaa2234bb60c4dbf82893e934d8ee8dea30446f0647e024074237a56a08c01bd", size = 1696790, upload-time = "2025-07-29T05:51:03.657Z" }, + { url = "https://files.pythonhosted.org/packages/02/90/6b4cfaaf92ed98d0ec4d173e78b99b4b1a7551250be8937d9d67ecb356b4/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6d86a2fbdd14192e2f234a92d3b494dd4457e683ba07e5905a0b3ee25389ac9f", size = 1718245, upload-time = "2025-07-29T05:51:05.911Z" }, + { url = "https://files.pythonhosted.org/packages/2e/e6/2593751670fa06f080a846f37f112cbe6f873ba510d070136a6ed46117c6/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a041e7e2612041a6ddf1c6a33b883be6a421247c7afd47e885969ee4cc58bd8d", size = 1658899, upload-time = "2025-07-29T05:51:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/8f/28/c15bacbdb8b8eb5bf39b10680d129ea7410b859e379b03190f02fa104ffd/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5015082477abeafad7203757ae44299a610e89ee82a1503e3d4184e6bafdd519", size = 1738459, upload-time = "2025-07-29T05:51:09.56Z" }, + { url = "https://files.pythonhosted.org/packages/00/de/c269cbc4faa01fb10f143b1670633a8ddd5b2e1ffd0548f7aa49cb5c70e2/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56822ff5ddfd1b745534e658faba944012346184fbfe732e0d6134b744516eea", size = 1766434, upload-time = "2025-07-29T05:51:11.423Z" }, + { url = "https://files.pythonhosted.org/packages/52/b0/4ff3abd81aa7d929b27d2e1403722a65fc87b763e3a97b3a2a494bfc63bc/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2acbbfff69019d9014508c4ba0401822e8bae5a5fdc3b6814285b71231b60f3", size = 1726045, upload-time = "2025-07-29T05:51:13.689Z" }, + { url = "https://files.pythonhosted.org/packages/71/16/949225a6a2dd6efcbd855fbd90cf476052e648fb011aa538e3b15b89a57a/aiohttp-3.12.15-cp312-cp312-win32.whl", hash = "sha256:d849b0901b50f2185874b9a232f38e26b9b3d4810095a7572eacea939132d4e1", size = 423591, upload-time = "2025-07-29T05:51:15.452Z" }, + { url = "https://files.pythonhosted.org/packages/2b/d8/fa65d2a349fe938b76d309db1a56a75c4fb8cc7b17a398b698488a939903/aiohttp-3.12.15-cp312-cp312-win_amd64.whl", hash = "sha256:b390ef5f62bb508a9d67cb3bba9b8356e23b3996da7062f1a57ce1a79d2b3d34", size = 450266, upload-time = "2025-07-29T05:51:17.239Z" }, + { url = "https://files.pythonhosted.org/packages/f2/33/918091abcf102e39d15aba2476ad9e7bd35ddb190dcdd43a854000d3da0d/aiohttp-3.12.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9f922ffd05034d439dde1c77a20461cf4a1b0831e6caa26151fe7aa8aaebc315", size = 696741, upload-time = "2025-07-29T05:51:19.021Z" }, + { url = "https://files.pythonhosted.org/packages/b5/2a/7495a81e39a998e400f3ecdd44a62107254803d1681d9189be5c2e4530cd/aiohttp-3.12.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2ee8a8ac39ce45f3e55663891d4b1d15598c157b4d494a4613e704c8b43112cd", size = 474407, upload-time = "2025-07-29T05:51:21.165Z" }, + { url = "https://files.pythonhosted.org/packages/49/fc/a9576ab4be2dcbd0f73ee8675d16c707cfc12d5ee80ccf4015ba543480c9/aiohttp-3.12.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3eae49032c29d356b94eee45a3f39fdf4b0814b397638c2f718e96cfadf4c4e4", size = 466703, upload-time = "2025-07-29T05:51:22.948Z" }, + { url = "https://files.pythonhosted.org/packages/09/2f/d4bcc8448cf536b2b54eed48f19682031ad182faa3a3fee54ebe5b156387/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97752ff12cc12f46a9b20327104448042fce5c33a624f88c18f66f9368091c7", size = 1705532, upload-time = "2025-07-29T05:51:25.211Z" }, + { url = "https://files.pythonhosted.org/packages/f1/f3/59406396083f8b489261e3c011aa8aee9df360a96ac8fa5c2e7e1b8f0466/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:894261472691d6fe76ebb7fcf2e5870a2ac284c7406ddc95823c8598a1390f0d", size = 1686794, upload-time = "2025-07-29T05:51:27.145Z" }, + { url = "https://files.pythonhosted.org/packages/dc/71/164d194993a8d114ee5656c3b7ae9c12ceee7040d076bf7b32fb98a8c5c6/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fa5d9eb82ce98959fc1031c28198b431b4d9396894f385cb63f1e2f3f20ca6b", size = 1738865, upload-time = "2025-07-29T05:51:29.366Z" }, + { url = "https://files.pythonhosted.org/packages/1c/00/d198461b699188a93ead39cb458554d9f0f69879b95078dce416d3209b54/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0fa751efb11a541f57db59c1dd821bec09031e01452b2b6217319b3a1f34f3d", size = 1788238, upload-time = "2025-07-29T05:51:31.285Z" }, + { url = "https://files.pythonhosted.org/packages/85/b8/9e7175e1fa0ac8e56baa83bf3c214823ce250d0028955dfb23f43d5e61fd/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5346b93e62ab51ee2a9d68e8f73c7cf96ffb73568a23e683f931e52450e4148d", size = 1710566, upload-time = "2025-07-29T05:51:33.219Z" }, + { url = "https://files.pythonhosted.org/packages/59/e4/16a8eac9df39b48ae102ec030fa9f726d3570732e46ba0c592aeeb507b93/aiohttp-3.12.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:049ec0360f939cd164ecbfd2873eaa432613d5e77d6b04535e3d1fbae5a9e645", size = 1624270, upload-time = "2025-07-29T05:51:35.195Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f8/cd84dee7b6ace0740908fd0af170f9fab50c2a41ccbc3806aabcb1050141/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b52dcf013b57464b6d1e51b627adfd69a8053e84b7103a7cd49c030f9ca44461", size = 1677294, upload-time = "2025-07-29T05:51:37.215Z" }, + { url = "https://files.pythonhosted.org/packages/ce/42/d0f1f85e50d401eccd12bf85c46ba84f947a84839c8a1c2c5f6e8ab1eb50/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b2af240143dd2765e0fb661fd0361a1b469cab235039ea57663cda087250ea9", size = 1708958, upload-time = "2025-07-29T05:51:39.328Z" }, + { url = "https://files.pythonhosted.org/packages/d5/6b/f6fa6c5790fb602538483aa5a1b86fcbad66244997e5230d88f9412ef24c/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac77f709a2cde2cc71257ab2d8c74dd157c67a0558a0d2799d5d571b4c63d44d", size = 1651553, upload-time = "2025-07-29T05:51:41.356Z" }, + { url = "https://files.pythonhosted.org/packages/04/36/a6d36ad545fa12e61d11d1932eef273928b0495e6a576eb2af04297fdd3c/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:47f6b962246f0a774fbd3b6b7be25d59b06fdb2f164cf2513097998fc6a29693", size = 1727688, upload-time = "2025-07-29T05:51:43.452Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c8/f195e5e06608a97a4e52c5d41c7927301bf757a8e8bb5bbf8cef6c314961/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:760fb7db442f284996e39cf9915a94492e1896baac44f06ae551974907922b64", size = 1761157, upload-time = "2025-07-29T05:51:45.643Z" }, + { url = "https://files.pythonhosted.org/packages/05/6a/ea199e61b67f25ba688d3ce93f63b49b0a4e3b3d380f03971b4646412fc6/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad702e57dc385cae679c39d318def49aef754455f237499d5b99bea4ef582e51", size = 1710050, upload-time = "2025-07-29T05:51:48.203Z" }, + { url = "https://files.pythonhosted.org/packages/b4/2e/ffeb7f6256b33635c29dbed29a22a723ff2dd7401fff42ea60cf2060abfb/aiohttp-3.12.15-cp313-cp313-win32.whl", hash = "sha256:f813c3e9032331024de2eb2e32a88d86afb69291fbc37a3a3ae81cc9917fb3d0", size = 422647, upload-time = "2025-07-29T05:51:50.718Z" }, + { url = "https://files.pythonhosted.org/packages/1b/8e/78ee35774201f38d5e1ba079c9958f7629b1fd079459aea9467441dbfbf5/aiohttp-3.12.15-cp313-cp313-win_amd64.whl", hash = "sha256:1a649001580bdb37c6fdb1bebbd7e3bc688e8ec2b5c6f52edbb664662b17dc84", size = 449067, upload-time = "2025-07-29T05:51:52.549Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, +] + +[[package]] +name = "alembic" +version = "1.16.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mako" }, + { name = "sqlalchemy" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9a/ca/4dc52902cf3491892d464f5265a81e9dff094692c8a049a3ed6a05fe7ee8/alembic-1.16.5.tar.gz", hash = "sha256:a88bb7f6e513bd4301ecf4c7f2206fe93f9913f9b48dac3b78babde2d6fe765e", size = 1969868, upload-time = "2025-08-27T18:02:05.668Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/4a/4c61d4c84cfd9befb6fa08a702535b27b21fff08c946bc2f6139decbf7f7/alembic-1.16.5-py3-none-any.whl", hash = "sha256:e845dfe090c5ffa7b92593ae6687c5cb1a101e91fa53868497dbd79847f9dbe3", size = 247355, upload-time = "2025-08-27T18:02:07.37Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/b4/636b3b65173d3ce9a38ef5f0522789614e590dab6a8d505340a4efe4c567/anyio-4.10.0.tar.gz", hash = "sha256:3f3fae35c96039744587aa5b8371e7e8e603c0702999535961dd336026973ba6", size = 213252, upload-time = "2025-08-04T08:54:26.451Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1", size = 107213, upload-time = "2025-08-04T08:54:24.882Z" }, +] + +[[package]] +name = "asgiproxy" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "starlette" }, + { name = "websockets" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/a9/ceb963a6f5be13024f850816db1ab9b53efbcf4be688c64a4c1ecccda810/asgiproxy-0.2.0-py3-none-any.whl", hash = "sha256:b952917b2a3318c558f2cba6a91329b060af5621e5f4e301948d922fe2fdcc5b", size = 8839, upload-time = "2025-02-07T10:18:49.692Z" }, +] + +[[package]] +name = "async-timeout" +version = "5.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, +] + +[[package]] +name = "attrs" +version = "25.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, +] + +[[package]] +name = "bidict" +version = "0.23.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/6e/026678aa5a830e07cd9498a05d3e7e650a4f56a42f267a53d22bcda1bdc9/bidict-0.23.1.tar.gz", hash = "sha256:03069d763bc387bbd20e7d49914e75fc4132a41937fa3405417e1a5a2d006d71", size = 29093, upload-time = "2024-02-18T19:09:05.748Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/37/e8730c3587a65eb5645d4aba2d27aae48e8003614d6aaf15dda67f702f1f/bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5", size = 32764, upload-time = "2024-02-18T19:09:04.156Z" }, +] + +[[package]] +name = "certifi" +version = "2025.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, +] + +[[package]] +name = "cfgv" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, +] + +[[package]] +name = "click" +version = "8.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, +] + +[[package]] +name = "filelock" +version = "3.19.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/40/bb/0ab3e58d22305b6f5440629d20683af28959bf793d98d11950e305c1c326/filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", size = 17687, upload-time = "2025-08-14T16:56:03.016Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" }, +] + +[[package]] +name = "frozenlist" +version = "1.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/7e/803dde33760128acd393a27eb002f2020ddb8d99d30a44bfbaab31c5f08a/frozenlist-1.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a", size = 82251, upload-time = "2025-06-09T23:00:16.279Z" }, + { url = "https://files.pythonhosted.org/packages/75/a9/9c2c5760b6ba45eae11334db454c189d43d34a4c0b489feb2175e5e64277/frozenlist-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750", size = 48183, upload-time = "2025-06-09T23:00:17.698Z" }, + { url = "https://files.pythonhosted.org/packages/47/be/4038e2d869f8a2da165f35a6befb9158c259819be22eeaf9c9a8f6a87771/frozenlist-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd", size = 47107, upload-time = "2025-06-09T23:00:18.952Z" }, + { url = "https://files.pythonhosted.org/packages/79/26/85314b8a83187c76a37183ceed886381a5f992975786f883472fcb6dc5f2/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2", size = 237333, upload-time = "2025-06-09T23:00:20.275Z" }, + { url = "https://files.pythonhosted.org/packages/1f/fd/e5b64f7d2c92a41639ffb2ad44a6a82f347787abc0c7df5f49057cf11770/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f", size = 231724, upload-time = "2025-06-09T23:00:21.705Z" }, + { url = "https://files.pythonhosted.org/packages/20/fb/03395c0a43a5976af4bf7534759d214405fbbb4c114683f434dfdd3128ef/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30", size = 245842, upload-time = "2025-06-09T23:00:23.148Z" }, + { url = "https://files.pythonhosted.org/packages/d0/15/c01c8e1dffdac5d9803507d824f27aed2ba76b6ed0026fab4d9866e82f1f/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98", size = 239767, upload-time = "2025-06-09T23:00:25.103Z" }, + { url = "https://files.pythonhosted.org/packages/14/99/3f4c6fe882c1f5514b6848aa0a69b20cb5e5d8e8f51a339d48c0e9305ed0/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86", size = 224130, upload-time = "2025-06-09T23:00:27.061Z" }, + { url = "https://files.pythonhosted.org/packages/4d/83/220a374bd7b2aeba9d0725130665afe11de347d95c3620b9b82cc2fcab97/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae", size = 235301, upload-time = "2025-06-09T23:00:29.02Z" }, + { url = "https://files.pythonhosted.org/packages/03/3c/3e3390d75334a063181625343e8daab61b77e1b8214802cc4e8a1bb678fc/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8", size = 234606, upload-time = "2025-06-09T23:00:30.514Z" }, + { url = "https://files.pythonhosted.org/packages/23/1e/58232c19608b7a549d72d9903005e2d82488f12554a32de2d5fb59b9b1ba/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31", size = 248372, upload-time = "2025-06-09T23:00:31.966Z" }, + { url = "https://files.pythonhosted.org/packages/c0/a4/e4a567e01702a88a74ce8a324691e62a629bf47d4f8607f24bf1c7216e7f/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7", size = 229860, upload-time = "2025-06-09T23:00:33.375Z" }, + { url = "https://files.pythonhosted.org/packages/73/a6/63b3374f7d22268b41a9db73d68a8233afa30ed164c46107b33c4d18ecdd/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5", size = 245893, upload-time = "2025-06-09T23:00:35.002Z" }, + { url = "https://files.pythonhosted.org/packages/6d/eb/d18b3f6e64799a79673c4ba0b45e4cfbe49c240edfd03a68be20002eaeaa/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898", size = 246323, upload-time = "2025-06-09T23:00:36.468Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f5/720f3812e3d06cd89a1d5db9ff6450088b8f5c449dae8ffb2971a44da506/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56", size = 233149, upload-time = "2025-06-09T23:00:37.963Z" }, + { url = "https://files.pythonhosted.org/packages/69/68/03efbf545e217d5db8446acfd4c447c15b7c8cf4dbd4a58403111df9322d/frozenlist-1.7.0-cp311-cp311-win32.whl", hash = "sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7", size = 39565, upload-time = "2025-06-09T23:00:39.753Z" }, + { url = "https://files.pythonhosted.org/packages/58/17/fe61124c5c333ae87f09bb67186d65038834a47d974fc10a5fadb4cc5ae1/frozenlist-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d", size = 44019, upload-time = "2025-06-09T23:00:40.988Z" }, + { url = "https://files.pythonhosted.org/packages/ef/a2/c8131383f1e66adad5f6ecfcce383d584ca94055a34d683bbb24ac5f2f1c/frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2", size = 81424, upload-time = "2025-06-09T23:00:42.24Z" }, + { url = "https://files.pythonhosted.org/packages/4c/9d/02754159955088cb52567337d1113f945b9e444c4960771ea90eb73de8db/frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb", size = 47952, upload-time = "2025-06-09T23:00:43.481Z" }, + { url = "https://files.pythonhosted.org/packages/01/7a/0046ef1bd6699b40acd2067ed6d6670b4db2f425c56980fa21c982c2a9db/frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478", size = 46688, upload-time = "2025-06-09T23:00:44.793Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a2/a910bafe29c86997363fb4c02069df4ff0b5bc39d33c5198b4e9dd42d8f8/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8", size = 243084, upload-time = "2025-06-09T23:00:46.125Z" }, + { url = "https://files.pythonhosted.org/packages/64/3e/5036af9d5031374c64c387469bfcc3af537fc0f5b1187d83a1cf6fab1639/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08", size = 233524, upload-time = "2025-06-09T23:00:47.73Z" }, + { url = "https://files.pythonhosted.org/packages/06/39/6a17b7c107a2887e781a48ecf20ad20f1c39d94b2a548c83615b5b879f28/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4", size = 248493, upload-time = "2025-06-09T23:00:49.742Z" }, + { url = "https://files.pythonhosted.org/packages/be/00/711d1337c7327d88c44d91dd0f556a1c47fb99afc060ae0ef66b4d24793d/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b", size = 244116, upload-time = "2025-06-09T23:00:51.352Z" }, + { url = "https://files.pythonhosted.org/packages/24/fe/74e6ec0639c115df13d5850e75722750adabdc7de24e37e05a40527ca539/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e", size = 224557, upload-time = "2025-06-09T23:00:52.855Z" }, + { url = "https://files.pythonhosted.org/packages/8d/db/48421f62a6f77c553575201e89048e97198046b793f4a089c79a6e3268bd/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca", size = 241820, upload-time = "2025-06-09T23:00:54.43Z" }, + { url = "https://files.pythonhosted.org/packages/1d/fa/cb4a76bea23047c8462976ea7b7a2bf53997a0ca171302deae9d6dd12096/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df", size = 236542, upload-time = "2025-06-09T23:00:56.409Z" }, + { url = "https://files.pythonhosted.org/packages/5d/32/476a4b5cfaa0ec94d3f808f193301debff2ea42288a099afe60757ef6282/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5", size = 249350, upload-time = "2025-06-09T23:00:58.468Z" }, + { url = "https://files.pythonhosted.org/packages/8d/ba/9a28042f84a6bf8ea5dbc81cfff8eaef18d78b2a1ad9d51c7bc5b029ad16/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025", size = 225093, upload-time = "2025-06-09T23:01:00.015Z" }, + { url = "https://files.pythonhosted.org/packages/bc/29/3a32959e68f9cf000b04e79ba574527c17e8842e38c91d68214a37455786/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01", size = 245482, upload-time = "2025-06-09T23:01:01.474Z" }, + { url = "https://files.pythonhosted.org/packages/80/e8/edf2f9e00da553f07f5fa165325cfc302dead715cab6ac8336a5f3d0adc2/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08", size = 249590, upload-time = "2025-06-09T23:01:02.961Z" }, + { url = "https://files.pythonhosted.org/packages/1c/80/9a0eb48b944050f94cc51ee1c413eb14a39543cc4f760ed12657a5a3c45a/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43", size = 237785, upload-time = "2025-06-09T23:01:05.095Z" }, + { url = "https://files.pythonhosted.org/packages/f3/74/87601e0fb0369b7a2baf404ea921769c53b7ae00dee7dcfe5162c8c6dbf0/frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3", size = 39487, upload-time = "2025-06-09T23:01:06.54Z" }, + { url = "https://files.pythonhosted.org/packages/0b/15/c026e9a9fc17585a9d461f65d8593d281fedf55fbf7eb53f16c6df2392f9/frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a", size = 43874, upload-time = "2025-06-09T23:01:07.752Z" }, + { url = "https://files.pythonhosted.org/packages/24/90/6b2cebdabdbd50367273c20ff6b57a3dfa89bd0762de02c3a1eb42cb6462/frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee", size = 79791, upload-time = "2025-06-09T23:01:09.368Z" }, + { url = "https://files.pythonhosted.org/packages/83/2e/5b70b6a3325363293fe5fc3ae74cdcbc3e996c2a11dde2fd9f1fb0776d19/frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d", size = 47165, upload-time = "2025-06-09T23:01:10.653Z" }, + { url = "https://files.pythonhosted.org/packages/f4/25/a0895c99270ca6966110f4ad98e87e5662eab416a17e7fd53c364bf8b954/frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43", size = 45881, upload-time = "2025-06-09T23:01:12.296Z" }, + { url = "https://files.pythonhosted.org/packages/19/7c/71bb0bbe0832793c601fff68cd0cf6143753d0c667f9aec93d3c323f4b55/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d", size = 232409, upload-time = "2025-06-09T23:01:13.641Z" }, + { url = "https://files.pythonhosted.org/packages/c0/45/ed2798718910fe6eb3ba574082aaceff4528e6323f9a8570be0f7028d8e9/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee", size = 225132, upload-time = "2025-06-09T23:01:15.264Z" }, + { url = "https://files.pythonhosted.org/packages/ba/e2/8417ae0f8eacb1d071d4950f32f229aa6bf68ab69aab797b72a07ea68d4f/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb", size = 237638, upload-time = "2025-06-09T23:01:16.752Z" }, + { url = "https://files.pythonhosted.org/packages/f8/b7/2ace5450ce85f2af05a871b8c8719b341294775a0a6c5585d5e6170f2ce7/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f", size = 233539, upload-time = "2025-06-09T23:01:18.202Z" }, + { url = "https://files.pythonhosted.org/packages/46/b9/6989292c5539553dba63f3c83dc4598186ab2888f67c0dc1d917e6887db6/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60", size = 215646, upload-time = "2025-06-09T23:01:19.649Z" }, + { url = "https://files.pythonhosted.org/packages/72/31/bc8c5c99c7818293458fe745dab4fd5730ff49697ccc82b554eb69f16a24/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00", size = 232233, upload-time = "2025-06-09T23:01:21.175Z" }, + { url = "https://files.pythonhosted.org/packages/59/52/460db4d7ba0811b9ccb85af996019f5d70831f2f5f255f7cc61f86199795/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b", size = 227996, upload-time = "2025-06-09T23:01:23.098Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c9/f4b39e904c03927b7ecf891804fd3b4df3db29b9e487c6418e37988d6e9d/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c", size = 242280, upload-time = "2025-06-09T23:01:24.808Z" }, + { url = "https://files.pythonhosted.org/packages/b8/33/3f8d6ced42f162d743e3517781566b8481322be321b486d9d262adf70bfb/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949", size = 217717, upload-time = "2025-06-09T23:01:26.28Z" }, + { url = "https://files.pythonhosted.org/packages/3e/e8/ad683e75da6ccef50d0ab0c2b2324b32f84fc88ceee778ed79b8e2d2fe2e/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca", size = 236644, upload-time = "2025-06-09T23:01:27.887Z" }, + { url = "https://files.pythonhosted.org/packages/b2/14/8d19ccdd3799310722195a72ac94ddc677541fb4bef4091d8e7775752360/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b", size = 238879, upload-time = "2025-06-09T23:01:29.524Z" }, + { url = "https://files.pythonhosted.org/packages/ce/13/c12bf657494c2fd1079a48b2db49fa4196325909249a52d8f09bc9123fd7/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e", size = 232502, upload-time = "2025-06-09T23:01:31.287Z" }, + { url = "https://files.pythonhosted.org/packages/d7/8b/e7f9dfde869825489382bc0d512c15e96d3964180c9499efcec72e85db7e/frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1", size = 39169, upload-time = "2025-06-09T23:01:35.503Z" }, + { url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba", size = 43219, upload-time = "2025-06-09T23:01:36.784Z" }, + { url = "https://files.pythonhosted.org/packages/56/d5/5c4cf2319a49eddd9dd7145e66c4866bdc6f3dbc67ca3d59685149c11e0d/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d", size = 84345, upload-time = "2025-06-09T23:01:38.295Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/ec2c1e1dc16b85bc9d526009961953df9cec8481b6886debb36ec9107799/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d", size = 48880, upload-time = "2025-06-09T23:01:39.887Z" }, + { url = "https://files.pythonhosted.org/packages/69/86/f9596807b03de126e11e7d42ac91e3d0b19a6599c714a1989a4e85eeefc4/frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b", size = 48498, upload-time = "2025-06-09T23:01:41.318Z" }, + { url = "https://files.pythonhosted.org/packages/5e/cb/df6de220f5036001005f2d726b789b2c0b65f2363b104bbc16f5be8084f8/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146", size = 292296, upload-time = "2025-06-09T23:01:42.685Z" }, + { url = "https://files.pythonhosted.org/packages/83/1f/de84c642f17c8f851a2905cee2dae401e5e0daca9b5ef121e120e19aa825/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74", size = 273103, upload-time = "2025-06-09T23:01:44.166Z" }, + { url = "https://files.pythonhosted.org/packages/88/3c/c840bfa474ba3fa13c772b93070893c6e9d5c0350885760376cbe3b6c1b3/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1", size = 292869, upload-time = "2025-06-09T23:01:45.681Z" }, + { url = "https://files.pythonhosted.org/packages/a6/1c/3efa6e7d5a39a1d5ef0abeb51c48fb657765794a46cf124e5aca2c7a592c/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1", size = 291467, upload-time = "2025-06-09T23:01:47.234Z" }, + { url = "https://files.pythonhosted.org/packages/4f/00/d5c5e09d4922c395e2f2f6b79b9a20dab4b67daaf78ab92e7729341f61f6/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384", size = 266028, upload-time = "2025-06-09T23:01:48.819Z" }, + { url = "https://files.pythonhosted.org/packages/4e/27/72765be905619dfde25a7f33813ac0341eb6b076abede17a2e3fbfade0cb/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb", size = 284294, upload-time = "2025-06-09T23:01:50.394Z" }, + { url = "https://files.pythonhosted.org/packages/88/67/c94103a23001b17808eb7dd1200c156bb69fb68e63fcf0693dde4cd6228c/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c", size = 281898, upload-time = "2025-06-09T23:01:52.234Z" }, + { url = "https://files.pythonhosted.org/packages/42/34/a3e2c00c00f9e2a9db5653bca3fec306349e71aff14ae45ecc6d0951dd24/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65", size = 290465, upload-time = "2025-06-09T23:01:53.788Z" }, + { url = "https://files.pythonhosted.org/packages/bb/73/f89b7fbce8b0b0c095d82b008afd0590f71ccb3dee6eee41791cf8cd25fd/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3", size = 266385, upload-time = "2025-06-09T23:01:55.769Z" }, + { url = "https://files.pythonhosted.org/packages/cd/45/e365fdb554159462ca12df54bc59bfa7a9a273ecc21e99e72e597564d1ae/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657", size = 288771, upload-time = "2025-06-09T23:01:57.4Z" }, + { url = "https://files.pythonhosted.org/packages/00/11/47b6117002a0e904f004d70ec5194fe9144f117c33c851e3d51c765962d0/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104", size = 288206, upload-time = "2025-06-09T23:01:58.936Z" }, + { url = "https://files.pythonhosted.org/packages/40/37/5f9f3c3fd7f7746082ec67bcdc204db72dad081f4f83a503d33220a92973/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf", size = 282620, upload-time = "2025-06-09T23:02:00.493Z" }, + { url = "https://files.pythonhosted.org/packages/0b/31/8fbc5af2d183bff20f21aa743b4088eac4445d2bb1cdece449ae80e4e2d1/frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81", size = 43059, upload-time = "2025-06-09T23:02:02.072Z" }, + { url = "https://files.pythonhosted.org/packages/bb/ed/41956f52105b8dbc26e457c5705340c67c8cc2b79f394b79bffc09d0e938/frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e", size = 47516, upload-time = "2025-06-09T23:02:03.779Z" }, + { url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" }, +] + +[[package]] +name = "granian" +version = "2.5.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/80/4ed5065cc6b5c60a76d1e1484f172d3c190b695b671677064019b1de1c27/granian-2.5.3.tar.gz", hash = "sha256:c9ff9994624e2e10d92dac0757da11cb205007dfdc5a6b422ca4bb100408c75a", size = 111929, upload-time = "2025-09-11T13:20:33.266Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/d3/acea82536e00be2b3abbdfd854928b1ac6cff5209e2e696fed1e95fea756/granian-2.5.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6a098bb162c45716fa88a22c71919330b83954d7775ea854e5ca42fcc0ee0aea", size = 2840933, upload-time = "2025-09-11T13:18:05.015Z" }, + { url = "https://files.pythonhosted.org/packages/df/20/1fd6f95ccef0dcfa0ba3a3001927a34c9d9e7130d38003e2cb3841470802/granian-2.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d6a8b826948c91118ef1b7188e15ae07392a1cc869a1bca7fae4e3f4426c2279", size = 2539585, upload-time = "2025-09-11T13:18:06.596Z" }, + { url = "https://files.pythonhosted.org/packages/1f/8f/c2c080785e44eeb3663ccd667701d13314608189a9a65767ed172769d6d2/granian-2.5.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:76ceebbf9bb7fc6c0dfc2e3fa0b18e49315e576997b6c11c77c0842bd656f727", size = 3049684, upload-time = "2025-09-11T13:18:08.638Z" }, + { url = "https://files.pythonhosted.org/packages/77/a2/59a4ac8ed0452d511f4c0981c70b5e97e33eff4c494a8ba4d492b5809aad/granian-2.5.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48c890dbabe49e534a074cee34a50b133acc88ed63b74b629e85f7f3d906f13a", size = 2851726, upload-time = "2025-09-11T13:18:10.148Z" }, + { url = "https://files.pythonhosted.org/packages/02/39/fc672a88dfe9f69fcdf4f4700d6bcbb7aec376729394ace1f8f7f21ff9a3/granian-2.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52dacb995c9ac287bedd035eea30313984366ac119027b02d69927e211910cd9", size = 3149977, upload-time = "2025-09-11T13:18:11.694Z" }, + { url = "https://files.pythonhosted.org/packages/f4/13/72c7c5fe9307c16bd5a6e3e9dd197cf8454821ad9560c37124c770a5c456/granian-2.5.3-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:ac57522c729944fc0a8d16339fef8caa43a02070ca6d048b361d6e6b4dc99571", size = 2919696, upload-time = "2025-09-11T13:18:12.987Z" }, + { url = "https://files.pythonhosted.org/packages/0f/51/812b29351bd4d32bbad562739706a53609f32be1466e3c71daa5b837646c/granian-2.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:de0f17039c62b545817c75beda32eb49e3786ffd88323f362d5767e5b9c6f57d", size = 2916402, upload-time = "2025-09-11T13:18:14.427Z" }, + { url = "https://files.pythonhosted.org/packages/52/27/357411dc27f8da816c69b40677d0b37fc65ebe32572d0334411f168f3250/granian-2.5.3-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:42f4dfaf92400bcf9ec45fb7e5e0ae6e7c34a7bac1d3f11ff632503d533c3fb1", size = 3167476, upload-time = "2025-09-11T13:18:18.464Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a0/8781cc4525267f40de5f7e3e76a5f1b0fcd130d2bff065f0e2816ae611eb/granian-2.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b757481aea213c18cef5b09b6f8008e680ca3c19cc88fb9ae354af16d8287dfb", size = 3205454, upload-time = "2025-09-11T13:18:20.36Z" }, + { url = "https://files.pythonhosted.org/packages/b5/a7/93901a65c4bc1986ca6ea759cf6e089eed9003cb8e9ec0caaa09740f21cc/granian-2.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:4f5445f530cafce160ac91e11fcf1ee54b09fe31cad05415e0910b448f1002d5", size = 2186687, upload-time = "2025-09-11T13:18:21.719Z" }, + { url = "https://files.pythonhosted.org/packages/45/ef/6af6a6f6c66bfc9776227d2d4222bfbfa6a80740a32d2e67a61b142770e4/granian-2.5.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:73c314129ce4f54f16f6639d10f6aa0b12ab0a89949fc5b1c5212f024029483b", size = 2826835, upload-time = "2025-09-11T13:18:23.477Z" }, + { url = "https://files.pythonhosted.org/packages/94/9d/089b534be2f1f074332dd34ff0ed4e11020c57f67c90f3cd4575767b189c/granian-2.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:560b764c9af2379f0aee23cb9a502a48f03ac86ffcee3987b9ec510ef58b1540", size = 2526366, upload-time = "2025-09-11T13:18:24.572Z" }, + { url = "https://files.pythonhosted.org/packages/08/ba/2fc589c859289e6ae288d13f4b3f7063190a740b42b64747d42bca8e9603/granian-2.5.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:af23f4c1e00fe44c2155cb4caa2764e04f401052940f4c01ee31b98128d86375", size = 3037390, upload-time = "2025-09-11T13:18:26.441Z" }, + { url = "https://files.pythonhosted.org/packages/1d/16/6b130a06301050a450bc89da3a26215c955f0048d6d9b4ed991c2789a12c/granian-2.5.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80e1c886f0ddc6093a7a9749be80db99e76ab4d498151df89632060359b6b084", size = 2849901, upload-time = "2025-09-11T13:18:27.676Z" }, + { url = "https://files.pythonhosted.org/packages/bc/23/8f036fd4183bf64f2c83fa274311272e50b9dfeb2553d0648969ab700b8b/granian-2.5.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6da4c06557664819ff5711dcdd6e5ad0ca3a179235d314c70ef336c23e1a3a78", size = 3143055, upload-time = "2025-09-11T13:18:29.451Z" }, + { url = "https://files.pythonhosted.org/packages/fd/5b/ea4cba27e6d2f7f1452df5e5d18b4aa7ce8cb2a3ff350ad9215d300fdc7c/granian-2.5.3-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:14376f821be8b43a66cccda82203baa6844f0b23d397265daa50c14dea0a1cf0", size = 2921033, upload-time = "2025-09-11T13:18:30.996Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b1/c311d75069945e7ea71816dad426bcf00951e9ece0cf32bc63b9ae7fd4dd/granian-2.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5b107c7cc1447bf1711b98ad3cd222bfda6148a704648932e1180fe3cb9efc57", size = 2912455, upload-time = "2025-09-11T13:18:32.377Z" }, + { url = "https://files.pythonhosted.org/packages/12/51/45f7536251395ce3a65b56dd220f74f0aca65d31f6c866115bbc99f8cbf8/granian-2.5.3-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:540d87ffd463d010aac9437b813be66f5017b4cea1e5ef39c05ac4202f857f8a", size = 3154591, upload-time = "2025-09-11T13:18:33.603Z" }, + { url = "https://files.pythonhosted.org/packages/7c/dc/2ecc634f4806540ba66e12156ebb543cc19aac68401d080b4b327b617274/granian-2.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f8bfe3a29ae2bd436aa6e8d224a3c70544a1d08cbe970ce55c116545939f78ea", size = 3219988, upload-time = "2025-09-11T13:18:34.725Z" }, + { url = "https://files.pythonhosted.org/packages/04/81/dbeb06e60bee0020ad1bf8a6a3b3fcd15a2fee7460f4b0464c6a435969e9/granian-2.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:34c0faaea7bed4f805f26e20f423079baffffe73f58d59984db742ab50521bc9", size = 2189720, upload-time = "2025-09-11T13:18:35.908Z" }, + { url = "https://files.pythonhosted.org/packages/e6/84/0646287cf8b477415f47931cb7eda3f34c0b90b5d5475648addc1249499f/granian-2.5.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:b9a06467446600e69b36f1cffec06d4ddb1fe3186409092fdfb95043385662cf", size = 2826501, upload-time = "2025-09-11T13:18:37.123Z" }, + { url = "https://files.pythonhosted.org/packages/14/cc/7cb0f257f61eba28e6e1035e9ca0f41d23dde187968e900d14e995cec217/granian-2.5.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:29cc2ade23d57c31c51efff8e51192b8be33227aeee7fc331d84cb4b9b67fe5e", size = 2526120, upload-time = "2025-09-11T13:18:38.473Z" }, + { url = "https://files.pythonhosted.org/packages/d7/8d/632e97407e6214d7049c4e333cf834e9d7099fe9259a6da71182f6a2d3a8/granian-2.5.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:49d5a09fd640240214c1d48aa1c58f1964808d062e290021157c050f463d8973", size = 3037021, upload-time = "2025-09-11T13:18:39.577Z" }, + { url = "https://files.pythonhosted.org/packages/2a/1b/9083356a0dbf4392324043e849f9936027ba22a5b7d201ac274d297774f3/granian-2.5.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93f5748d175f099c5b736b14f2eb1d78eab7a30e0c7c68c9dc4bd07d9a77ce7a", size = 2849577, upload-time = "2025-09-11T13:18:40.891Z" }, + { url = "https://files.pythonhosted.org/packages/61/22/0bf7cbbaea49896193be42dc0e59fce55f617db5510219a9312d6a9717e5/granian-2.5.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e85af483b3c09ab1a5b1a73743ba3027af529e32ede893c376b6ea743d3e7ea", size = 3142615, upload-time = "2025-09-11T13:18:42.046Z" }, + { url = "https://files.pythonhosted.org/packages/59/70/01656c5497969109d0341c97977cebfe05534999098347cfedf2f68c0204/granian-2.5.3-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:357fc2007a6c2eb320dbc1774e859f9a78141d42b63f6ec933849b8061f6c6f4", size = 2920633, upload-time = "2025-09-11T13:18:43.306Z" }, + { url = "https://files.pythonhosted.org/packages/1f/1d/f7410fa20eafa3abb07fd3aea081167686f70d9e68333fcf690cc8161e27/granian-2.5.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c987cc99911ea7d9c7d4e4a07bc1238b46707eb3dc16ba2566955343691fe749", size = 2912190, upload-time = "2025-09-11T13:18:44.842Z" }, + { url = "https://files.pythonhosted.org/packages/6c/35/72f4673ddcfa3be0e8f37482fc179f1669f6e90e98ea3c4cc455f658f400/granian-2.5.3-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5eaa8714a4ca1171a75985b19f49f0268e611792c949967bb59f87e9cfd0a490", size = 3154900, upload-time = "2025-09-11T13:18:46.555Z" }, + { url = "https://files.pythonhosted.org/packages/d0/c2/cbab7166afe4b9e29da38c559b4afa1db53d335b26969ed6573e3dd561c4/granian-2.5.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:a5537ad9fc27e13919d54d4a3882c3a4dcbfd1c01bba04bdd14a88bb36fbf1c1", size = 3219617, upload-time = "2025-09-11T13:18:47.981Z" }, + { url = "https://files.pythonhosted.org/packages/94/00/f0bc60f54463b1e31a277d90cce7cbceaf781907e1e88da5e222849c167d/granian-2.5.3-cp313-cp313-win_amd64.whl", hash = "sha256:5de37f78d4b085320a7e9727da8bd6b159d38b6306cd1330bee9f6bcc0cbdca6", size = 2189600, upload-time = "2025-09-11T13:18:49.158Z" }, + { url = "https://files.pythonhosted.org/packages/45/27/7c497414d9fdca8d93e3e3d6bcc64f99149f2e8df324e75e07f5b3a6902a/granian-2.5.3-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:b6d3c9653e90a0ad04acf895cd4cd1a33d8fcb93bb7db7e6c95d2d95205458ad", size = 2774008, upload-time = "2025-09-11T13:18:50.331Z" }, + { url = "https://files.pythonhosted.org/packages/5e/e6/58134dada9031a9bb8f47fec094ee820eb7d614286069b2976f8d59bc41e/granian-2.5.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:93ff6a857e5f553f0674386b03c53a58709189f4d446837e7ffa27c8fb36bcdd", size = 2491304, upload-time = "2025-09-11T13:18:51.955Z" }, + { url = "https://files.pythonhosted.org/packages/b2/00/65941b0229b2b1ed794281a37fa61ff3c1f99d9cfdfb0d0f96184fc9396c/granian-2.5.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0f9cfb0fc772ee89a781a10ce5e8b5cb9da7fe8d00ca1318bdf36b667539186", size = 3031750, upload-time = "2025-09-11T13:18:53.168Z" }, + { url = "https://files.pythonhosted.org/packages/ff/75/0b12183edf05cddb5056ae2d2392f468eacb68b148ae8141202cbbb066b2/granian-2.5.3-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:7015d857fc4608b7707342e94e4bea228f9212675d2b94b0c949168637b65d85", size = 2779977, upload-time = "2025-09-11T13:18:54.483Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a2/7d7d7417db1c9d9fe7bc95b783614d9b3b0e3c480b73ea0d1a546a99f85a/granian-2.5.3-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:06d64c196581c2a3a77333a086f91d2a0d7049880dbba2b1acc2ebfa4d3da6ba", size = 2906517, upload-time = "2025-09-11T13:18:56.63Z" }, + { url = "https://files.pythonhosted.org/packages/7c/d0/999483db56924193efd7b348417326c982fd946b1eaffedf0b818061b957/granian-2.5.3-cp313-cp313t-musllinux_1_1_armv7l.whl", hash = "sha256:2ad5d9f6117f75080968a13203b2774c5596073a7bea9a155441da04dac49276", size = 3135964, upload-time = "2025-09-11T13:18:57.931Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ab/989874b51fa9bc1cb3b0e8253def86e8e538cd844e353420c297d61c3f4c/granian-2.5.3-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:9b91e95d06d7b34938df26a586a6d21548cef6966390eee7f8e7ac84c086fbf5", size = 3206823, upload-time = "2025-09-11T13:18:59.205Z" }, + { url = "https://files.pythonhosted.org/packages/51/b6/29deb5c5dd5ab3e01042c99ca7b26d46c4cd5ce5d1b4fea1eecd393f7c23/granian-2.5.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1a11817d09c131b649dc1d57eae7dfe945bbea0bd45c65c8a4fb2045dc604ee2", size = 2180130, upload-time = "2025-09-11T13:19:00.382Z" }, + { url = "https://files.pythonhosted.org/packages/ea/9b/940095cf58681f0702cb1f3b1cfa578c541238c6d4e68d05c9186e356d94/granian-2.5.3-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:b54fbf22faf9f0a9eb6c0236b1c536501ecbad8ab0aa57b25a4af9be3cce9736", size = 2807704, upload-time = "2025-09-11T13:19:02.162Z" }, + { url = "https://files.pythonhosted.org/packages/e3/f3/f7aeb3153ea909d6e517338a7486f10c74e42b1ca2f6b1028fb3955b874d/granian-2.5.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d3cd19ccd469092431d6f48be0480b24e823a58ddc2a7bb744f010b34d055951", size = 2512472, upload-time = "2025-09-11T13:19:03.581Z" }, + { url = "https://files.pythonhosted.org/packages/ff/79/bfcfd23bfe20649afbc97aceb7049e6d49757a471c72673b58c7f09a39d6/granian-2.5.3-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95e86f0fc6744e1fa5612dd22329730093936b28c5f9518acc347ec43808f7df", size = 3030309, upload-time = "2025-09-11T13:19:04.823Z" }, + { url = "https://files.pythonhosted.org/packages/6c/23/b964bfdbcaeb3796ece66c787baa8b175018424ed1faad0f6077176c55f8/granian-2.5.3-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1eda9e2bd6b4995118ced449fbe8f81fe5601bed7acb46bca5a2884f6daee838", size = 2842146, upload-time = "2025-09-11T13:19:06.235Z" }, + { url = "https://files.pythonhosted.org/packages/e1/f0/7ba8d9d212c03c4970ca0573de250fe9d99301c9d719f862515dc9cf8091/granian-2.5.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a99231cfcfbc5bada23de3ff52f5c5515141c8d41ab7550a8cc33c62bbfaf74", size = 3137183, upload-time = "2025-09-11T13:19:07.712Z" }, + { url = "https://files.pythonhosted.org/packages/60/ca/3603be5e1c56a445c5cf3e0be7a737664f022c2b2e03606eee1844eb6c0a/granian-2.5.3-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:4df3b2a2ee8e7a0a77555cab5038395006c194f137ce64d461739e237fc0f6e8", size = 2920599, upload-time = "2025-09-11T13:19:09.125Z" }, + { url = "https://files.pythonhosted.org/packages/15/39/0eb0829989f14ae44fbc88dc857b339ca464cff706a2faf9476c22757dd0/granian-2.5.3-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:d3149a149c15c9bf1ffbcb0a06e056ee917e281ae96611b14ff42f3506508da2", size = 2911553, upload-time = "2025-09-11T13:19:10.357Z" }, + { url = "https://files.pythonhosted.org/packages/26/b3/79bb2b0c622fa4cca8181cf9850647bbd7a7d47944020a546879587ccbce/granian-2.5.3-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:9c7830eca54c7249553703669e25e6e864c767d080af4f447a89cf39c328f779", size = 3149464, upload-time = "2025-09-11T13:19:12.303Z" }, + { url = "https://files.pythonhosted.org/packages/38/bc/2b226a5a31c0226a4e8b3f2805b5797dfb8958abb93b70eae4daec284591/granian-2.5.3-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:538e11845e19f6c1924cb7126f5a606f056eccd0732525362ef7c3dc3d49b1e7", size = 3210849, upload-time = "2025-09-11T13:19:13.619Z" }, + { url = "https://files.pythonhosted.org/packages/aa/8a/6c8fc42589fc7b2d552a5ba4e29f827836feb29cae9ff4ebf05e6b2f4aa5/granian-2.5.3-cp314-cp314-win_amd64.whl", hash = "sha256:08eea6b9372ad50f7d11651661cd696329b306f211259fb62197efa32b112a8f", size = 2175728, upload-time = "2025-09-11T13:19:14.955Z" }, + { url = "https://files.pythonhosted.org/packages/d0/52/6924685b141badc2021846e21392b64e34b6b9e12254a7fec83ff68b6a5b/granian-2.5.3-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:da2096a0e50f302486608b4ba11f1451e78230745268af443adc25a51e17609a", size = 2758903, upload-time = "2025-09-11T13:19:17.624Z" }, + { url = "https://files.pythonhosted.org/packages/74/55/82b853bf8e00cbb8f4765588bd475d3cff8786e3bfaea22fe21e57e243f0/granian-2.5.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3b84f2f172fcda46728c905b94d5758337edddfa5fe6b4f9e814c30c3f3e7a6f", size = 2474901, upload-time = "2025-09-11T13:19:19.193Z" }, + { url = "https://files.pythonhosted.org/packages/46/91/a1a7c34d86462c5f2f01e4aa7658799509903fcd94db6ce4e77c65b66ba9/granian-2.5.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1216ebec4387134264795ce2f1670a50e38ea9c6aea5ca97024265deaf9e801", size = 3024547, upload-time = "2025-09-11T13:19:21.01Z" }, + { url = "https://files.pythonhosted.org/packages/4f/1a/bea17c82e94f23b790ca74cfda2d3591ce75a0a9a650b7aacbf05a89979d/granian-2.5.3-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:0075015e27cb7e328ce7f9f9ebb43cbbe4dec4a4851a9e0c68cd8e7d53017c21", size = 2779913, upload-time = "2025-09-11T13:19:23.183Z" }, + { url = "https://files.pythonhosted.org/packages/e2/76/5344efa7d629989a9b19296ef2ad82ddf1c7114ab3596395f8cd97d54c3f/granian-2.5.3-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:33483cfe92a81d43243016b10911814f7cdeef90a25d523658965503f47643fd", size = 2905657, upload-time = "2025-09-11T13:19:24.622Z" }, + { url = "https://files.pythonhosted.org/packages/c7/9c/28fda138718534b7d460184432c1dfe94a9c53a498d05a4cdfa9a9dc8bdc/granian-2.5.3-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:a9fd71e5338824433da0ec260e3f3637c1f858d9f18e923226894187b0b327e6", size = 3130516, upload-time = "2025-09-11T13:19:26.065Z" }, + { url = "https://files.pythonhosted.org/packages/a7/fb/3fa02fb394a1edbb292eb298e66ad6b041b84a539e690c81fc673d187b6a/granian-2.5.3-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:46176f5213a26affb46955312929fbf55905603af10b9133cf48424ef0eb7452", size = 3199950, upload-time = "2025-09-11T13:19:27.589Z" }, + { url = "https://files.pythonhosted.org/packages/9e/1a/d319652dfd506bc18ad030dd692b668ce243113b542ede65107720283c23/granian-2.5.3-cp314-cp314t-win_amd64.whl", hash = "sha256:d56bb0f648f6d72ad236156d24ade73be9587bf9a8f01bced4f87b25e900b9b3", size = 2167481, upload-time = "2025-09-11T13:19:28.941Z" }, + { url = "https://files.pythonhosted.org/packages/6f/f4/0a4a065a54c587f29ef519f41c7ac26e355967b3be3019d6f1761e54f228/granian-2.5.3-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7ed320a782d9b96d214016a47c1537d928aeabc2a9f1695861dc5feed3298685", size = 2837610, upload-time = "2025-09-11T13:20:02.843Z" }, + { url = "https://files.pythonhosted.org/packages/1e/29/0aa0e6ecff4119447748fef10fe41c9d31bb5a5d177b7344a286b54b9ee5/granian-2.5.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:8fc7c8cd2209bc1840d311543e481629ebb8ff7a3c5c8795c5e0e1ade0df5dcb", size = 2549403, upload-time = "2025-09-11T13:20:05.065Z" }, + { url = "https://files.pythonhosted.org/packages/a9/53/98330cbb2cbe00fd9d1eff8b7f3bf8e7a6eefa264b57ec803409ccdf7b4f/granian-2.5.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f66232b48a207f45501c4daefa0361223417e9f903b6824a515a676df4f05a8f", size = 3146010, upload-time = "2025-09-11T13:20:06.524Z" }, + { url = "https://files.pythonhosted.org/packages/bf/00/35edb52da777401e32916f912d8a5d11069cdd6eb6603568612dce244ab2/granian-2.5.3-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0414181fd958031eacfae885995eed7f21aa7131b2c5e6f0fbf7cbf702ac4944", size = 2924725, upload-time = "2025-09-11T13:20:08.26Z" }, + { url = "https://files.pythonhosted.org/packages/ea/e8/c4a80e7e1ec553399ad2222d8979de63510da93cb44f5b53c9907148973e/granian-2.5.3-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:361729e128eb8646949a0139524d5b1ae0dc51c8f6d3607b0709c12bb05fa98d", size = 2915114, upload-time = "2025-09-11T13:20:10.208Z" }, + { url = "https://files.pythonhosted.org/packages/cf/de/27a29cf9a8414dfa0939f0472ccafce0d2bc429d5051883adec439827c38/granian-2.5.3-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:79920221fabd1ad62d9985cb3d1b07262fd54b7595e31a03b3a122aa17bc567f", size = 3159160, upload-time = "2025-09-11T13:20:11.922Z" }, + { url = "https://files.pythonhosted.org/packages/f0/88/744063cc9b8b49b195b08f90fc886db71a0af89c609386c4e0587caa4b57/granian-2.5.3-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:894c8775c8a3b346def845d7dde4833bd80c57dc50722323328c5e0356b1aa1f", size = 3199865, upload-time = "2025-09-11T13:20:13.833Z" }, + { url = "https://files.pythonhosted.org/packages/5e/d3/dbff7a98c65cd8c5424c6b62cd0b4c82139c59dbb2c0599157bf5171a6e6/granian-2.5.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:caab1f3988ed5dd715168d87f5939464e9729cf0f24ff8ca2bede5c5448cc1f5", size = 2179382, upload-time = "2025-09-11T13:20:15.215Z" }, +] + +[package.optional-dependencies] +reload = [ + { name = "watchfiles" }, +] + +[[package]] +name = "greenlet" +version = "3.2.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/03/b8/704d753a5a45507a7aab61f18db9509302ed3d0a27ac7e0359ec2905b1a6/greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", size = 188260, upload-time = "2025-08-07T13:24:33.51Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/de/f28ced0a67749cac23fecb02b694f6473f47686dff6afaa211d186e2ef9c/greenlet-3.2.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2", size = 272305, upload-time = "2025-08-07T13:15:41.288Z" }, + { url = "https://files.pythonhosted.org/packages/09/16/2c3792cba130000bf2a31c5272999113f4764fd9d874fb257ff588ac779a/greenlet-3.2.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246", size = 632472, upload-time = "2025-08-07T13:42:55.044Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/95d48d7e3d433e6dae5b1682e4292242a53f22df82e6d3dda81b1701a960/greenlet-3.2.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3", size = 644646, upload-time = "2025-08-07T13:45:26.523Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5e/405965351aef8c76b8ef7ad370e5da58d57ef6068df197548b015464001a/greenlet-3.2.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633", size = 640519, upload-time = "2025-08-07T13:53:13.928Z" }, + { url = "https://files.pythonhosted.org/packages/25/5d/382753b52006ce0218297ec1b628e048c4e64b155379331f25a7316eb749/greenlet-3.2.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079", size = 639707, upload-time = "2025-08-07T13:18:27.146Z" }, + { url = "https://files.pythonhosted.org/packages/1f/8e/abdd3f14d735b2929290a018ecf133c901be4874b858dd1c604b9319f064/greenlet-3.2.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8", size = 587684, upload-time = "2025-08-07T13:18:25.164Z" }, + { url = "https://files.pythonhosted.org/packages/5d/65/deb2a69c3e5996439b0176f6651e0052542bb6c8f8ec2e3fba97c9768805/greenlet-3.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52", size = 1116647, upload-time = "2025-08-07T13:42:38.655Z" }, + { url = "https://files.pythonhosted.org/packages/3f/cc/b07000438a29ac5cfb2194bfc128151d52f333cee74dd7dfe3fb733fc16c/greenlet-3.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa", size = 1142073, upload-time = "2025-08-07T13:18:21.737Z" }, + { url = "https://files.pythonhosted.org/packages/d8/0f/30aef242fcab550b0b3520b8e3561156857c94288f0332a79928c31a52cf/greenlet-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9", size = 299100, upload-time = "2025-08-07T13:44:12.287Z" }, + { url = "https://files.pythonhosted.org/packages/44/69/9b804adb5fd0671f367781560eb5eb586c4d495277c93bde4307b9e28068/greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd", size = 274079, upload-time = "2025-08-07T13:15:45.033Z" }, + { url = "https://files.pythonhosted.org/packages/46/e9/d2a80c99f19a153eff70bc451ab78615583b8dac0754cfb942223d2c1a0d/greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb", size = 640997, upload-time = "2025-08-07T13:42:56.234Z" }, + { url = "https://files.pythonhosted.org/packages/3b/16/035dcfcc48715ccd345f3a93183267167cdd162ad123cd93067d86f27ce4/greenlet-3.2.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968", size = 655185, upload-time = "2025-08-07T13:45:27.624Z" }, + { url = "https://files.pythonhosted.org/packages/31/da/0386695eef69ffae1ad726881571dfe28b41970173947e7c558d9998de0f/greenlet-3.2.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9", size = 649926, upload-time = "2025-08-07T13:53:15.251Z" }, + { url = "https://files.pythonhosted.org/packages/68/88/69bf19fd4dc19981928ceacbc5fd4bb6bc2215d53199e367832e98d1d8fe/greenlet-3.2.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6", size = 651839, upload-time = "2025-08-07T13:18:30.281Z" }, + { url = "https://files.pythonhosted.org/packages/19/0d/6660d55f7373b2ff8152401a83e02084956da23ae58cddbfb0b330978fe9/greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0", size = 607586, upload-time = "2025-08-07T13:18:28.544Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1a/c953fdedd22d81ee4629afbb38d2f9d71e37d23caace44775a3a969147d4/greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0", size = 1123281, upload-time = "2025-08-07T13:42:39.858Z" }, + { url = "https://files.pythonhosted.org/packages/3f/c7/12381b18e21aef2c6bd3a636da1088b888b97b7a0362fac2e4de92405f97/greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f", size = 1151142, upload-time = "2025-08-07T13:18:22.981Z" }, + { url = "https://files.pythonhosted.org/packages/e9/08/b0814846b79399e585f974bbeebf5580fbe59e258ea7be64d9dfb253c84f/greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02", size = 299899, upload-time = "2025-08-07T13:38:53.448Z" }, + { url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814, upload-time = "2025-08-07T13:15:50.011Z" }, + { url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073, upload-time = "2025-08-07T13:42:57.23Z" }, + { url = "https://files.pythonhosted.org/packages/f7/0b/bc13f787394920b23073ca3b6c4a7a21396301ed75a655bcb47196b50e6e/greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc", size = 655191, upload-time = "2025-08-07T13:45:29.752Z" }, + { url = "https://files.pythonhosted.org/packages/f2/d6/6adde57d1345a8d0f14d31e4ab9c23cfe8e2cd39c3baf7674b4b0338d266/greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a", size = 649516, upload-time = "2025-08-07T13:53:16.314Z" }, + { url = "https://files.pythonhosted.org/packages/7f/3b/3a3328a788d4a473889a2d403199932be55b1b0060f4ddd96ee7cdfcad10/greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504", size = 652169, upload-time = "2025-08-07T13:18:32.861Z" }, + { url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497, upload-time = "2025-08-07T13:18:31.636Z" }, + { url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662, upload-time = "2025-08-07T13:42:41.117Z" }, + { url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210, upload-time = "2025-08-07T13:18:24.072Z" }, + { url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685, upload-time = "2025-08-07T13:24:38.824Z" }, + { url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586, upload-time = "2025-08-07T13:16:08.004Z" }, + { url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346, upload-time = "2025-08-07T13:42:59.944Z" }, + { url = "https://files.pythonhosted.org/packages/c0/aa/687d6b12ffb505a4447567d1f3abea23bd20e73a5bed63871178e0831b7a/greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5", size = 699218, upload-time = "2025-08-07T13:45:30.969Z" }, + { url = "https://files.pythonhosted.org/packages/dc/8b/29aae55436521f1d6f8ff4e12fb676f3400de7fcf27fccd1d4d17fd8fecd/greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", size = 694659, upload-time = "2025-08-07T13:53:17.759Z" }, + { url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355, upload-time = "2025-08-07T13:18:34.517Z" }, + { url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512, upload-time = "2025-08-07T13:18:33.969Z" }, + { url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425, upload-time = "2025-08-07T13:32:27.59Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "identify" +version = "2.6.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/c4/62963f25a678f6a050fb0505a65e9e726996171e6dbe1547f79619eefb15/identify-2.6.14.tar.gz", hash = "sha256:663494103b4f717cb26921c52f8751363dc89db64364cd836a9bf1535f53cd6a", size = 99283, upload-time = "2025-09-06T19:30:52.938Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/ae/2ad30f4652712c82f1c23423d79136fbce338932ad166d70c1efb86a5998/identify-2.6.14-py2.py3-none-any.whl", hash = "sha256:11a073da82212c6646b1f39bb20d4483bfb9543bd5566fec60053c4bb309bf2e", size = 99172, upload-time = "2025-09-06T19:30:51.759Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "mako" +version = "1.3.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474, upload-time = "2025-04-10T12:44:31.16Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509, upload-time = "2025-04-10T12:50:53.297Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, + { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, + { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, + { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, + { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, + { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, + { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, + { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, + { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "multidict" +version = "6.6.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/69/7f/0652e6ed47ab288e3756ea9c0df8b14950781184d4bd7883f4d87dd41245/multidict-6.6.4.tar.gz", hash = "sha256:d2d4e4787672911b48350df02ed3fa3fffdc2f2e8ca06dd6afdf34189b76a9dd", size = 101843, upload-time = "2025-08-11T12:08:48.217Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/7f/90a7f01e2d005d6653c689039977f6856718c75c5579445effb7e60923d1/multidict-6.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c7a0e9b561e6460484318a7612e725df1145d46b0ef57c6b9866441bf6e27e0c", size = 76472, upload-time = "2025-08-11T12:06:29.006Z" }, + { url = "https://files.pythonhosted.org/packages/54/a3/bed07bc9e2bb302ce752f1dabc69e884cd6a676da44fb0e501b246031fdd/multidict-6.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6bf2f10f70acc7a2446965ffbc726e5fc0b272c97a90b485857e5c70022213eb", size = 44634, upload-time = "2025-08-11T12:06:30.374Z" }, + { url = "https://files.pythonhosted.org/packages/a7/4b/ceeb4f8f33cf81277da464307afeaf164fb0297947642585884f5cad4f28/multidict-6.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66247d72ed62d5dd29752ffc1d3b88f135c6a8de8b5f63b7c14e973ef5bda19e", size = 44282, upload-time = "2025-08-11T12:06:31.958Z" }, + { url = "https://files.pythonhosted.org/packages/03/35/436a5da8702b06866189b69f655ffdb8f70796252a8772a77815f1812679/multidict-6.6.4-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:105245cc6b76f51e408451a844a54e6823bbd5a490ebfe5bdfc79798511ceded", size = 229696, upload-time = "2025-08-11T12:06:33.087Z" }, + { url = "https://files.pythonhosted.org/packages/b6/0e/915160be8fecf1fca35f790c08fb74ca684d752fcba62c11daaf3d92c216/multidict-6.6.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cbbc54e58b34c3bae389ef00046be0961f30fef7cb0dd9c7756aee376a4f7683", size = 246665, upload-time = "2025-08-11T12:06:34.448Z" }, + { url = "https://files.pythonhosted.org/packages/08/ee/2f464330acd83f77dcc346f0b1a0eaae10230291450887f96b204b8ac4d3/multidict-6.6.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:56c6b3652f945c9bc3ac6c8178cd93132b8d82dd581fcbc3a00676c51302bc1a", size = 225485, upload-time = "2025-08-11T12:06:35.672Z" }, + { url = "https://files.pythonhosted.org/packages/71/cc/9a117f828b4d7fbaec6adeed2204f211e9caf0a012692a1ee32169f846ae/multidict-6.6.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b95494daf857602eccf4c18ca33337dd2be705bccdb6dddbfc9d513e6addb9d9", size = 257318, upload-time = "2025-08-11T12:06:36.98Z" }, + { url = "https://files.pythonhosted.org/packages/25/77/62752d3dbd70e27fdd68e86626c1ae6bccfebe2bb1f84ae226363e112f5a/multidict-6.6.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e5b1413361cef15340ab9dc61523e653d25723e82d488ef7d60a12878227ed50", size = 254689, upload-time = "2025-08-11T12:06:38.233Z" }, + { url = "https://files.pythonhosted.org/packages/00/6e/fac58b1072a6fc59af5e7acb245e8754d3e1f97f4f808a6559951f72a0d4/multidict-6.6.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e167bf899c3d724f9662ef00b4f7fef87a19c22b2fead198a6f68b263618df52", size = 246709, upload-time = "2025-08-11T12:06:39.517Z" }, + { url = "https://files.pythonhosted.org/packages/01/ef/4698d6842ef5e797c6db7744b0081e36fb5de3d00002cc4c58071097fac3/multidict-6.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:aaea28ba20a9026dfa77f4b80369e51cb767c61e33a2d4043399c67bd95fb7c6", size = 243185, upload-time = "2025-08-11T12:06:40.796Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c9/d82e95ae1d6e4ef396934e9b0e942dfc428775f9554acf04393cce66b157/multidict-6.6.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8c91cdb30809a96d9ecf442ec9bc45e8cfaa0f7f8bdf534e082c2443a196727e", size = 237838, upload-time = "2025-08-11T12:06:42.595Z" }, + { url = "https://files.pythonhosted.org/packages/57/cf/f94af5c36baaa75d44fab9f02e2a6bcfa0cd90acb44d4976a80960759dbc/multidict-6.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1a0ccbfe93ca114c5d65a2471d52d8829e56d467c97b0e341cf5ee45410033b3", size = 246368, upload-time = "2025-08-11T12:06:44.304Z" }, + { url = "https://files.pythonhosted.org/packages/4a/fe/29f23460c3d995f6a4b678cb2e9730e7277231b981f0b234702f0177818a/multidict-6.6.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:55624b3f321d84c403cb7d8e6e982f41ae233d85f85db54ba6286f7295dc8a9c", size = 253339, upload-time = "2025-08-11T12:06:45.597Z" }, + { url = "https://files.pythonhosted.org/packages/29/b6/fd59449204426187b82bf8a75f629310f68c6adc9559dc922d5abe34797b/multidict-6.6.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:4a1fb393a2c9d202cb766c76208bd7945bc194eba8ac920ce98c6e458f0b524b", size = 246933, upload-time = "2025-08-11T12:06:46.841Z" }, + { url = "https://files.pythonhosted.org/packages/19/52/d5d6b344f176a5ac3606f7a61fb44dc746e04550e1a13834dff722b8d7d6/multidict-6.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:43868297a5759a845fa3a483fb4392973a95fb1de891605a3728130c52b8f40f", size = 242225, upload-time = "2025-08-11T12:06:48.588Z" }, + { url = "https://files.pythonhosted.org/packages/ec/d3/5b2281ed89ff4d5318d82478a2a2450fcdfc3300da48ff15c1778280ad26/multidict-6.6.4-cp311-cp311-win32.whl", hash = "sha256:ed3b94c5e362a8a84d69642dbeac615452e8af9b8eb825b7bc9f31a53a1051e2", size = 41306, upload-time = "2025-08-11T12:06:49.95Z" }, + { url = "https://files.pythonhosted.org/packages/74/7d/36b045c23a1ab98507aefd44fd8b264ee1dd5e5010543c6fccf82141ccef/multidict-6.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:d8c112f7a90d8ca5d20213aa41eac690bb50a76da153e3afb3886418e61cb22e", size = 46029, upload-time = "2025-08-11T12:06:51.082Z" }, + { url = "https://files.pythonhosted.org/packages/0f/5e/553d67d24432c5cd52b49047f2d248821843743ee6d29a704594f656d182/multidict-6.6.4-cp311-cp311-win_arm64.whl", hash = "sha256:3bb0eae408fa1996d87247ca0d6a57b7fc1dcf83e8a5c47ab82c558c250d4adf", size = 43017, upload-time = "2025-08-11T12:06:52.243Z" }, + { url = "https://files.pythonhosted.org/packages/05/f6/512ffd8fd8b37fb2680e5ac35d788f1d71bbaf37789d21a820bdc441e565/multidict-6.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0ffb87be160942d56d7b87b0fdf098e81ed565add09eaa1294268c7f3caac4c8", size = 76516, upload-time = "2025-08-11T12:06:53.393Z" }, + { url = "https://files.pythonhosted.org/packages/99/58/45c3e75deb8855c36bd66cc1658007589662ba584dbf423d01df478dd1c5/multidict-6.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d191de6cbab2aff5de6c5723101705fd044b3e4c7cfd587a1929b5028b9714b3", size = 45394, upload-time = "2025-08-11T12:06:54.555Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ca/e8c4472a93a26e4507c0b8e1f0762c0d8a32de1328ef72fd704ef9cc5447/multidict-6.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38a0956dd92d918ad5feff3db8fcb4a5eb7dba114da917e1a88475619781b57b", size = 43591, upload-time = "2025-08-11T12:06:55.672Z" }, + { url = "https://files.pythonhosted.org/packages/05/51/edf414f4df058574a7265034d04c935aa84a89e79ce90fcf4df211f47b16/multidict-6.6.4-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:6865f6d3b7900ae020b495d599fcf3765653bc927951c1abb959017f81ae8287", size = 237215, upload-time = "2025-08-11T12:06:57.213Z" }, + { url = "https://files.pythonhosted.org/packages/c8/45/8b3d6dbad8cf3252553cc41abea09ad527b33ce47a5e199072620b296902/multidict-6.6.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a2088c126b6f72db6c9212ad827d0ba088c01d951cee25e758c450da732c138", size = 258299, upload-time = "2025-08-11T12:06:58.946Z" }, + { url = "https://files.pythonhosted.org/packages/3c/e8/8ca2e9a9f5a435fc6db40438a55730a4bf4956b554e487fa1b9ae920f825/multidict-6.6.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0f37bed7319b848097085d7d48116f545985db988e2256b2e6f00563a3416ee6", size = 242357, upload-time = "2025-08-11T12:07:00.301Z" }, + { url = "https://files.pythonhosted.org/packages/0f/84/80c77c99df05a75c28490b2af8f7cba2a12621186e0a8b0865d8e745c104/multidict-6.6.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:01368e3c94032ba6ca0b78e7ccb099643466cf24f8dc8eefcfdc0571d56e58f9", size = 268369, upload-time = "2025-08-11T12:07:01.638Z" }, + { url = "https://files.pythonhosted.org/packages/0d/e9/920bfa46c27b05fb3e1ad85121fd49f441492dca2449c5bcfe42e4565d8a/multidict-6.6.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fe323540c255db0bffee79ad7f048c909f2ab0edb87a597e1c17da6a54e493c", size = 269341, upload-time = "2025-08-11T12:07:02.943Z" }, + { url = "https://files.pythonhosted.org/packages/af/65/753a2d8b05daf496f4a9c367fe844e90a1b2cac78e2be2c844200d10cc4c/multidict-6.6.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8eb3025f17b0a4c3cd08cda49acf312a19ad6e8a4edd9dbd591e6506d999402", size = 256100, upload-time = "2025-08-11T12:07:04.564Z" }, + { url = "https://files.pythonhosted.org/packages/09/54/655be13ae324212bf0bc15d665a4e34844f34c206f78801be42f7a0a8aaa/multidict-6.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bbc14f0365534d35a06970d6a83478b249752e922d662dc24d489af1aa0d1be7", size = 253584, upload-time = "2025-08-11T12:07:05.914Z" }, + { url = "https://files.pythonhosted.org/packages/5c/74/ab2039ecc05264b5cec73eb018ce417af3ebb384ae9c0e9ed42cb33f8151/multidict-6.6.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:75aa52fba2d96bf972e85451b99d8e19cc37ce26fd016f6d4aa60da9ab2b005f", size = 251018, upload-time = "2025-08-11T12:07:08.301Z" }, + { url = "https://files.pythonhosted.org/packages/af/0a/ccbb244ac848e56c6427f2392741c06302bbfba49c0042f1eb3c5b606497/multidict-6.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4fefd4a815e362d4f011919d97d7b4a1e566f1dde83dc4ad8cfb5b41de1df68d", size = 251477, upload-time = "2025-08-11T12:07:10.248Z" }, + { url = "https://files.pythonhosted.org/packages/0e/b0/0ed49bba775b135937f52fe13922bc64a7eaf0a3ead84a36e8e4e446e096/multidict-6.6.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:db9801fe021f59a5b375ab778973127ca0ac52429a26e2fd86aa9508f4d26eb7", size = 263575, upload-time = "2025-08-11T12:07:11.928Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d9/7fb85a85e14de2e44dfb6a24f03c41e2af8697a6df83daddb0e9b7569f73/multidict-6.6.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a650629970fa21ac1fb06ba25dabfc5b8a2054fcbf6ae97c758aa956b8dba802", size = 259649, upload-time = "2025-08-11T12:07:13.244Z" }, + { url = "https://files.pythonhosted.org/packages/03/9e/b3a459bcf9b6e74fa461a5222a10ff9b544cb1cd52fd482fb1b75ecda2a2/multidict-6.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:452ff5da78d4720d7516a3a2abd804957532dd69296cb77319c193e3ffb87e24", size = 251505, upload-time = "2025-08-11T12:07:14.57Z" }, + { url = "https://files.pythonhosted.org/packages/86/a2/8022f78f041dfe6d71e364001a5cf987c30edfc83c8a5fb7a3f0974cff39/multidict-6.6.4-cp312-cp312-win32.whl", hash = "sha256:8c2fcb12136530ed19572bbba61b407f655e3953ba669b96a35036a11a485793", size = 41888, upload-time = "2025-08-11T12:07:15.904Z" }, + { url = "https://files.pythonhosted.org/packages/c7/eb/d88b1780d43a56db2cba24289fa744a9d216c1a8546a0dc3956563fd53ea/multidict-6.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:047d9425860a8c9544fed1b9584f0c8bcd31bcde9568b047c5e567a1025ecd6e", size = 46072, upload-time = "2025-08-11T12:07:17.045Z" }, + { url = "https://files.pythonhosted.org/packages/9f/16/b929320bf5750e2d9d4931835a4c638a19d2494a5b519caaaa7492ebe105/multidict-6.6.4-cp312-cp312-win_arm64.whl", hash = "sha256:14754eb72feaa1e8ae528468f24250dd997b8e2188c3d2f593f9eba259e4b364", size = 43222, upload-time = "2025-08-11T12:07:18.328Z" }, + { url = "https://files.pythonhosted.org/packages/3a/5d/e1db626f64f60008320aab00fbe4f23fc3300d75892a3381275b3d284580/multidict-6.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f46a6e8597f9bd71b31cc708195d42b634c8527fecbcf93febf1052cacc1f16e", size = 75848, upload-time = "2025-08-11T12:07:19.912Z" }, + { url = "https://files.pythonhosted.org/packages/4c/aa/8b6f548d839b6c13887253af4e29c939af22a18591bfb5d0ee6f1931dae8/multidict-6.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:22e38b2bc176c5eb9c0a0e379f9d188ae4cd8b28c0f53b52bce7ab0a9e534657", size = 45060, upload-time = "2025-08-11T12:07:21.163Z" }, + { url = "https://files.pythonhosted.org/packages/eb/c6/f5e97e5d99a729bc2aa58eb3ebfa9f1e56a9b517cc38c60537c81834a73f/multidict-6.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5df8afd26f162da59e218ac0eefaa01b01b2e6cd606cffa46608f699539246da", size = 43269, upload-time = "2025-08-11T12:07:22.392Z" }, + { url = "https://files.pythonhosted.org/packages/dc/31/d54eb0c62516776f36fe67f84a732f97e0b0e12f98d5685bebcc6d396910/multidict-6.6.4-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:49517449b58d043023720aa58e62b2f74ce9b28f740a0b5d33971149553d72aa", size = 237158, upload-time = "2025-08-11T12:07:23.636Z" }, + { url = "https://files.pythonhosted.org/packages/c4/1c/8a10c1c25b23156e63b12165a929d8eb49a6ed769fdbefb06e6f07c1e50d/multidict-6.6.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9408439537c5afdca05edd128a63f56a62680f4b3c234301055d7a2000220f", size = 257076, upload-time = "2025-08-11T12:07:25.049Z" }, + { url = "https://files.pythonhosted.org/packages/ad/86/90e20b5771d6805a119e483fd3d1e8393e745a11511aebca41f0da38c3e2/multidict-6.6.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:87a32d20759dc52a9e850fe1061b6e41ab28e2998d44168a8a341b99ded1dba0", size = 240694, upload-time = "2025-08-11T12:07:26.458Z" }, + { url = "https://files.pythonhosted.org/packages/e7/49/484d3e6b535bc0555b52a0a26ba86e4d8d03fd5587d4936dc59ba7583221/multidict-6.6.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:52e3c8d43cdfff587ceedce9deb25e6ae77daba560b626e97a56ddcad3756879", size = 266350, upload-time = "2025-08-11T12:07:27.94Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b4/aa4c5c379b11895083d50021e229e90c408d7d875471cb3abf721e4670d6/multidict-6.6.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ad8850921d3a8d8ff6fbef790e773cecfc260bbfa0566998980d3fa8f520bc4a", size = 267250, upload-time = "2025-08-11T12:07:29.303Z" }, + { url = "https://files.pythonhosted.org/packages/80/e5/5e22c5bf96a64bdd43518b1834c6d95a4922cc2066b7d8e467dae9b6cee6/multidict-6.6.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:497a2954adc25c08daff36f795077f63ad33e13f19bfff7736e72c785391534f", size = 254900, upload-time = "2025-08-11T12:07:30.764Z" }, + { url = "https://files.pythonhosted.org/packages/17/38/58b27fed927c07035abc02befacab42491e7388ca105e087e6e0215ead64/multidict-6.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:024ce601f92d780ca1617ad4be5ac15b501cc2414970ffa2bb2bbc2bd5a68fa5", size = 252355, upload-time = "2025-08-11T12:07:32.205Z" }, + { url = "https://files.pythonhosted.org/packages/d0/a1/dad75d23a90c29c02b5d6f3d7c10ab36c3197613be5d07ec49c7791e186c/multidict-6.6.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a693fc5ed9bdd1c9e898013e0da4dcc640de7963a371c0bd458e50e046bf6438", size = 250061, upload-time = "2025-08-11T12:07:33.623Z" }, + { url = "https://files.pythonhosted.org/packages/b8/1a/ac2216b61c7f116edab6dc3378cca6c70dc019c9a457ff0d754067c58b20/multidict-6.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:190766dac95aab54cae5b152a56520fd99298f32a1266d66d27fdd1b5ac00f4e", size = 249675, upload-time = "2025-08-11T12:07:34.958Z" }, + { url = "https://files.pythonhosted.org/packages/d4/79/1916af833b800d13883e452e8e0977c065c4ee3ab7a26941fbfdebc11895/multidict-6.6.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:34d8f2a5ffdceab9dcd97c7a016deb2308531d5f0fced2bb0c9e1df45b3363d7", size = 261247, upload-time = "2025-08-11T12:07:36.588Z" }, + { url = "https://files.pythonhosted.org/packages/c5/65/d1f84fe08ac44a5fc7391cbc20a7cedc433ea616b266284413fd86062f8c/multidict-6.6.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:59e8d40ab1f5a8597abcef00d04845155a5693b5da00d2c93dbe88f2050f2812", size = 257960, upload-time = "2025-08-11T12:07:39.735Z" }, + { url = "https://files.pythonhosted.org/packages/13/b5/29ec78057d377b195ac2c5248c773703a6b602e132a763e20ec0457e7440/multidict-6.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:467fe64138cfac771f0e949b938c2e1ada2b5af22f39692aa9258715e9ea613a", size = 250078, upload-time = "2025-08-11T12:07:41.525Z" }, + { url = "https://files.pythonhosted.org/packages/c4/0e/7e79d38f70a872cae32e29b0d77024bef7834b0afb406ddae6558d9e2414/multidict-6.6.4-cp313-cp313-win32.whl", hash = "sha256:14616a30fe6d0a48d0a48d1a633ab3b8bec4cf293aac65f32ed116f620adfd69", size = 41708, upload-time = "2025-08-11T12:07:43.405Z" }, + { url = "https://files.pythonhosted.org/packages/9d/34/746696dffff742e97cd6a23da953e55d0ea51fa601fa2ff387b3edcfaa2c/multidict-6.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:40cd05eaeb39e2bc8939451f033e57feaa2ac99e07dbca8afe2be450a4a3b6cf", size = 45912, upload-time = "2025-08-11T12:07:45.082Z" }, + { url = "https://files.pythonhosted.org/packages/c7/87/3bac136181e271e29170d8d71929cdeddeb77f3e8b6a0c08da3a8e9da114/multidict-6.6.4-cp313-cp313-win_arm64.whl", hash = "sha256:f6eb37d511bfae9e13e82cb4d1af36b91150466f24d9b2b8a9785816deb16605", size = 43076, upload-time = "2025-08-11T12:07:46.746Z" }, + { url = "https://files.pythonhosted.org/packages/64/94/0a8e63e36c049b571c9ae41ee301ada29c3fee9643d9c2548d7d558a1d99/multidict-6.6.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6c84378acd4f37d1b507dfa0d459b449e2321b3ba5f2338f9b085cf7a7ba95eb", size = 82812, upload-time = "2025-08-11T12:07:48.402Z" }, + { url = "https://files.pythonhosted.org/packages/25/1a/be8e369dfcd260d2070a67e65dd3990dd635cbd735b98da31e00ea84cd4e/multidict-6.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0e0558693063c75f3d952abf645c78f3c5dfdd825a41d8c4d8156fc0b0da6e7e", size = 48313, upload-time = "2025-08-11T12:07:49.679Z" }, + { url = "https://files.pythonhosted.org/packages/26/5a/dd4ade298674b2f9a7b06a32c94ffbc0497354df8285f27317c66433ce3b/multidict-6.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3f8e2384cb83ebd23fd07e9eada8ba64afc4c759cd94817433ab8c81ee4b403f", size = 46777, upload-time = "2025-08-11T12:07:51.318Z" }, + { url = "https://files.pythonhosted.org/packages/89/db/98aa28bc7e071bfba611ac2ae803c24e96dd3a452b4118c587d3d872c64c/multidict-6.6.4-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:f996b87b420995a9174b2a7c1a8daf7db4750be6848b03eb5e639674f7963773", size = 229321, upload-time = "2025-08-11T12:07:52.965Z" }, + { url = "https://files.pythonhosted.org/packages/c7/bc/01ddda2a73dd9d167bd85d0e8ef4293836a8f82b786c63fb1a429bc3e678/multidict-6.6.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc356250cffd6e78416cf5b40dc6a74f1edf3be8e834cf8862d9ed5265cf9b0e", size = 249954, upload-time = "2025-08-11T12:07:54.423Z" }, + { url = "https://files.pythonhosted.org/packages/06/78/6b7c0f020f9aa0acf66d0ab4eb9f08375bac9a50ff5e3edb1c4ccd59eafc/multidict-6.6.4-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:dadf95aa862714ea468a49ad1e09fe00fcc9ec67d122f6596a8d40caf6cec7d0", size = 228612, upload-time = "2025-08-11T12:07:55.914Z" }, + { url = "https://files.pythonhosted.org/packages/00/44/3faa416f89b2d5d76e9d447296a81521e1c832ad6e40b92f990697b43192/multidict-6.6.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7dd57515bebffd8ebd714d101d4c434063322e4fe24042e90ced41f18b6d3395", size = 257528, upload-time = "2025-08-11T12:07:57.371Z" }, + { url = "https://files.pythonhosted.org/packages/05/5f/77c03b89af0fcb16f018f668207768191fb9dcfb5e3361a5e706a11db2c9/multidict-6.6.4-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:967af5f238ebc2eb1da4e77af5492219fbd9b4b812347da39a7b5f5c72c0fa45", size = 256329, upload-time = "2025-08-11T12:07:58.844Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e9/ed750a2a9afb4f8dc6f13dc5b67b514832101b95714f1211cd42e0aafc26/multidict-6.6.4-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a4c6875c37aae9794308ec43e3530e4aa0d36579ce38d89979bbf89582002bb", size = 247928, upload-time = "2025-08-11T12:08:01.037Z" }, + { url = "https://files.pythonhosted.org/packages/1f/b5/e0571bc13cda277db7e6e8a532791d4403dacc9850006cb66d2556e649c0/multidict-6.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7f683a551e92bdb7fac545b9c6f9fa2aebdeefa61d607510b3533286fcab67f5", size = 245228, upload-time = "2025-08-11T12:08:02.96Z" }, + { url = "https://files.pythonhosted.org/packages/f3/a3/69a84b0eccb9824491f06368f5b86e72e4af54c3067c37c39099b6687109/multidict-6.6.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:3ba5aaf600edaf2a868a391779f7a85d93bed147854925f34edd24cc70a3e141", size = 235869, upload-time = "2025-08-11T12:08:04.746Z" }, + { url = "https://files.pythonhosted.org/packages/a9/9d/28802e8f9121a6a0804fa009debf4e753d0a59969ea9f70be5f5fdfcb18f/multidict-6.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:580b643b7fd2c295d83cad90d78419081f53fd532d1f1eb67ceb7060f61cff0d", size = 243446, upload-time = "2025-08-11T12:08:06.332Z" }, + { url = "https://files.pythonhosted.org/packages/38/ea/6c98add069b4878c1d66428a5f5149ddb6d32b1f9836a826ac764b9940be/multidict-6.6.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:37b7187197da6af3ee0b044dbc9625afd0c885f2800815b228a0e70f9a7f473d", size = 252299, upload-time = "2025-08-11T12:08:07.931Z" }, + { url = "https://files.pythonhosted.org/packages/3a/09/8fe02d204473e14c0af3affd50af9078839dfca1742f025cca765435d6b4/multidict-6.6.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e1b93790ed0bc26feb72e2f08299691ceb6da5e9e14a0d13cc74f1869af327a0", size = 246926, upload-time = "2025-08-11T12:08:09.467Z" }, + { url = "https://files.pythonhosted.org/packages/37/3d/7b1e10d774a6df5175ecd3c92bff069e77bed9ec2a927fdd4ff5fe182f67/multidict-6.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a506a77ddee1efcca81ecbeae27ade3e09cdf21a8ae854d766c2bb4f14053f92", size = 243383, upload-time = "2025-08-11T12:08:10.981Z" }, + { url = "https://files.pythonhosted.org/packages/50/b0/a6fae46071b645ae98786ab738447de1ef53742eaad949f27e960864bb49/multidict-6.6.4-cp313-cp313t-win32.whl", hash = "sha256:f93b2b2279883d1d0a9e1bd01f312d6fc315c5e4c1f09e112e4736e2f650bc4e", size = 47775, upload-time = "2025-08-11T12:08:12.439Z" }, + { url = "https://files.pythonhosted.org/packages/b2/0a/2436550b1520091af0600dff547913cb2d66fbac27a8c33bc1b1bccd8d98/multidict-6.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:6d46a180acdf6e87cc41dc15d8f5c2986e1e8739dc25dbb7dac826731ef381a4", size = 53100, upload-time = "2025-08-11T12:08:13.823Z" }, + { url = "https://files.pythonhosted.org/packages/97/ea/43ac51faff934086db9c072a94d327d71b7d8b40cd5dcb47311330929ef0/multidict-6.6.4-cp313-cp313t-win_arm64.whl", hash = "sha256:756989334015e3335d087a27331659820d53ba432befdef6a718398b0a8493ad", size = 45501, upload-time = "2025-08-11T12:08:15.173Z" }, + { url = "https://files.pythonhosted.org/packages/fd/69/b547032297c7e63ba2af494edba695d781af8a0c6e89e4d06cf848b21d80/multidict-6.6.4-py3-none-any.whl", hash = "sha256:27d8f8e125c07cb954e54d75d04905a9bba8a439c1d84aca94949d4d03d8601c", size = 12313, upload-time = "2025-08-11T12:08:46.891Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.9.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" }, +] + +[[package]] +name = "pre-commit" +version = "4.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ff/29/7cf5bbc236333876e4b41f56e06857a87937ce4bf91e117a6991a2dbb02a/pre_commit-4.3.0.tar.gz", hash = "sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16", size = 193792, upload-time = "2025-08-09T18:56:14.651Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/a5/987a405322d78a73b66e39e4a90e4ef156fd7141bf71df987e50717c321b/pre_commit-4.3.0-py2.py3-none-any.whl", hash = "sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8", size = 220965, upload-time = "2025-08-09T18:56:13.192Z" }, +] + +[[package]] +name = "propcache" +version = "0.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/80/8d/e8b436717ab9c2cfc23b116d2c297305aa4cd8339172a456d61ebf5669b8/propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be", size = 74207, upload-time = "2025-06-09T22:54:05.399Z" }, + { url = "https://files.pythonhosted.org/packages/d6/29/1e34000e9766d112171764b9fa3226fa0153ab565d0c242c70e9945318a7/propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f", size = 43648, upload-time = "2025-06-09T22:54:08.023Z" }, + { url = "https://files.pythonhosted.org/packages/46/92/1ad5af0df781e76988897da39b5f086c2bf0f028b7f9bd1f409bb05b6874/propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9", size = 43496, upload-time = "2025-06-09T22:54:09.228Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ce/e96392460f9fb68461fabab3e095cb00c8ddf901205be4eae5ce246e5b7e/propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf", size = 217288, upload-time = "2025-06-09T22:54:10.466Z" }, + { url = "https://files.pythonhosted.org/packages/c5/2a/866726ea345299f7ceefc861a5e782b045545ae6940851930a6adaf1fca6/propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9", size = 227456, upload-time = "2025-06-09T22:54:11.828Z" }, + { url = "https://files.pythonhosted.org/packages/de/03/07d992ccb6d930398689187e1b3c718339a1c06b8b145a8d9650e4726166/propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66", size = 225429, upload-time = "2025-06-09T22:54:13.823Z" }, + { url = "https://files.pythonhosted.org/packages/5d/e6/116ba39448753b1330f48ab8ba927dcd6cf0baea8a0ccbc512dfb49ba670/propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df", size = 213472, upload-time = "2025-06-09T22:54:15.232Z" }, + { url = "https://files.pythonhosted.org/packages/a6/85/f01f5d97e54e428885a5497ccf7f54404cbb4f906688a1690cd51bf597dc/propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2", size = 204480, upload-time = "2025-06-09T22:54:17.104Z" }, + { url = "https://files.pythonhosted.org/packages/e3/79/7bf5ab9033b8b8194cc3f7cf1aaa0e9c3256320726f64a3e1f113a812dce/propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7", size = 214530, upload-time = "2025-06-09T22:54:18.512Z" }, + { url = "https://files.pythonhosted.org/packages/31/0b/bd3e0c00509b609317df4a18e6b05a450ef2d9a963e1d8bc9c9415d86f30/propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95", size = 205230, upload-time = "2025-06-09T22:54:19.947Z" }, + { url = "https://files.pythonhosted.org/packages/7a/23/fae0ff9b54b0de4e819bbe559508da132d5683c32d84d0dc2ccce3563ed4/propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e", size = 206754, upload-time = "2025-06-09T22:54:21.716Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7f/ad6a3c22630aaa5f618b4dc3c3598974a72abb4c18e45a50b3cdd091eb2f/propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e", size = 218430, upload-time = "2025-06-09T22:54:23.17Z" }, + { url = "https://files.pythonhosted.org/packages/5b/2c/ba4f1c0e8a4b4c75910742f0d333759d441f65a1c7f34683b4a74c0ee015/propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf", size = 223884, upload-time = "2025-06-09T22:54:25.539Z" }, + { url = "https://files.pythonhosted.org/packages/88/e4/ebe30fc399e98572019eee82ad0caf512401661985cbd3da5e3140ffa1b0/propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e", size = 211480, upload-time = "2025-06-09T22:54:26.892Z" }, + { url = "https://files.pythonhosted.org/packages/96/0a/7d5260b914e01d1d0906f7f38af101f8d8ed0dc47426219eeaf05e8ea7c2/propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897", size = 37757, upload-time = "2025-06-09T22:54:28.241Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2d/89fe4489a884bc0da0c3278c552bd4ffe06a1ace559db5ef02ef24ab446b/propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39", size = 41500, upload-time = "2025-06-09T22:54:29.4Z" }, + { url = "https://files.pythonhosted.org/packages/a8/42/9ca01b0a6f48e81615dca4765a8f1dd2c057e0540f6116a27dc5ee01dfb6/propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10", size = 73674, upload-time = "2025-06-09T22:54:30.551Z" }, + { url = "https://files.pythonhosted.org/packages/af/6e/21293133beb550f9c901bbece755d582bfaf2176bee4774000bd4dd41884/propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154", size = 43570, upload-time = "2025-06-09T22:54:32.296Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c8/0393a0a3a2b8760eb3bde3c147f62b20044f0ddac81e9d6ed7318ec0d852/propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615", size = 43094, upload-time = "2025-06-09T22:54:33.929Z" }, + { url = "https://files.pythonhosted.org/packages/37/2c/489afe311a690399d04a3e03b069225670c1d489eb7b044a566511c1c498/propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db", size = 226958, upload-time = "2025-06-09T22:54:35.186Z" }, + { url = "https://files.pythonhosted.org/packages/9d/ca/63b520d2f3d418c968bf596839ae26cf7f87bead026b6192d4da6a08c467/propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1", size = 234894, upload-time = "2025-06-09T22:54:36.708Z" }, + { url = "https://files.pythonhosted.org/packages/11/60/1d0ed6fff455a028d678df30cc28dcee7af77fa2b0e6962ce1df95c9a2a9/propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c", size = 233672, upload-time = "2025-06-09T22:54:38.062Z" }, + { url = "https://files.pythonhosted.org/packages/37/7c/54fd5301ef38505ab235d98827207176a5c9b2aa61939b10a460ca53e123/propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67", size = 224395, upload-time = "2025-06-09T22:54:39.634Z" }, + { url = "https://files.pythonhosted.org/packages/ee/1a/89a40e0846f5de05fdc6779883bf46ba980e6df4d2ff8fb02643de126592/propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b", size = 212510, upload-time = "2025-06-09T22:54:41.565Z" }, + { url = "https://files.pythonhosted.org/packages/5e/33/ca98368586c9566a6b8d5ef66e30484f8da84c0aac3f2d9aec6d31a11bd5/propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8", size = 222949, upload-time = "2025-06-09T22:54:43.038Z" }, + { url = "https://files.pythonhosted.org/packages/ba/11/ace870d0aafe443b33b2f0b7efdb872b7c3abd505bfb4890716ad7865e9d/propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251", size = 217258, upload-time = "2025-06-09T22:54:44.376Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d2/86fd6f7adffcfc74b42c10a6b7db721d1d9ca1055c45d39a1a8f2a740a21/propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474", size = 213036, upload-time = "2025-06-09T22:54:46.243Z" }, + { url = "https://files.pythonhosted.org/packages/07/94/2d7d1e328f45ff34a0a284cf5a2847013701e24c2a53117e7c280a4316b3/propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535", size = 227684, upload-time = "2025-06-09T22:54:47.63Z" }, + { url = "https://files.pythonhosted.org/packages/b7/05/37ae63a0087677e90b1d14710e532ff104d44bc1efa3b3970fff99b891dc/propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06", size = 234562, upload-time = "2025-06-09T22:54:48.982Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7c/3f539fcae630408d0bd8bf3208b9a647ccad10976eda62402a80adf8fc34/propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1", size = 222142, upload-time = "2025-06-09T22:54:50.424Z" }, + { url = "https://files.pythonhosted.org/packages/7c/d2/34b9eac8c35f79f8a962546b3e97e9d4b990c420ee66ac8255d5d9611648/propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1", size = 37711, upload-time = "2025-06-09T22:54:52.072Z" }, + { url = "https://files.pythonhosted.org/packages/19/61/d582be5d226cf79071681d1b46b848d6cb03d7b70af7063e33a2787eaa03/propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c", size = 41479, upload-time = "2025-06-09T22:54:53.234Z" }, + { url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" }, + { url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" }, + { url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" }, + { url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" }, + { url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" }, + { url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" }, + { url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" }, + { url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" }, + { url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" }, + { url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" }, + { url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" }, + { url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" }, + { url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" }, + { url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" }, + { url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" }, + { url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" }, + { url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" }, + { url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" }, + { url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" }, + { url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" }, + { url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" }, + { url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" }, + { url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" }, + { url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" }, + { url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" }, + { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" }, +] + +[[package]] +name = "psutil" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/31/4723d756b59344b643542936e37a31d1d3204bcdc42a7daa8ee9eb06fb50/psutil-7.1.0.tar.gz", hash = "sha256:655708b3c069387c8b77b072fc429a57d0e214221d01c0a772df7dfedcb3bcd2", size = 497660, upload-time = "2025-09-17T20:14:52.902Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/62/ce4051019ee20ce0ed74432dd73a5bb087a6704284a470bb8adff69a0932/psutil-7.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76168cef4397494250e9f4e73eb3752b146de1dd950040b29186d0cce1d5ca13", size = 245242, upload-time = "2025-09-17T20:14:56.126Z" }, + { url = "https://files.pythonhosted.org/packages/38/61/f76959fba841bf5b61123fbf4b650886dc4094c6858008b5bf73d9057216/psutil-7.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:5d007560c8c372efdff9e4579c2846d71de737e4605f611437255e81efcca2c5", size = 246682, upload-time = "2025-09-17T20:14:58.25Z" }, + { url = "https://files.pythonhosted.org/packages/88/7a/37c99d2e77ec30d63398ffa6a660450b8a62517cabe44b3e9bae97696e8d/psutil-7.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22e4454970b32472ce7deaa45d045b34d3648ce478e26a04c7e858a0a6e75ff3", size = 287994, upload-time = "2025-09-17T20:14:59.901Z" }, + { url = "https://files.pythonhosted.org/packages/9d/de/04c8c61232f7244aa0a4b9a9fbd63a89d5aeaf94b2fc9d1d16e2faa5cbb0/psutil-7.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c70e113920d51e89f212dd7be06219a9b88014e63a4cec69b684c327bc474e3", size = 291163, upload-time = "2025-09-17T20:15:01.481Z" }, + { url = "https://files.pythonhosted.org/packages/f4/58/c4f976234bf6d4737bc8c02a81192f045c307b72cf39c9e5c5a2d78927f6/psutil-7.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d4a113425c037300de3ac8b331637293da9be9713855c4fc9d2d97436d7259d", size = 293625, upload-time = "2025-09-17T20:15:04.492Z" }, + { url = "https://files.pythonhosted.org/packages/79/87/157c8e7959ec39ced1b11cc93c730c4fb7f9d408569a6c59dbd92ceb35db/psutil-7.1.0-cp37-abi3-win32.whl", hash = "sha256:09ad740870c8d219ed8daae0ad3b726d3bf9a028a198e7f3080f6a1888b99bca", size = 244812, upload-time = "2025-09-17T20:15:07.462Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e9/b44c4f697276a7a95b8e94d0e320a7bf7f3318521b23de69035540b39838/psutil-7.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:57f5e987c36d3146c0dd2528cd42151cf96cd359b9d67cfff836995cc5df9a3d", size = 247965, upload-time = "2025-09-17T20:15:09.673Z" }, + { url = "https://files.pythonhosted.org/packages/26/65/1070a6e3c036f39142c2820c4b52e9243246fcfc3f96239ac84472ba361e/psutil-7.1.0-cp37-abi3-win_arm64.whl", hash = "sha256:6937cb68133e7c97b6cc9649a570c9a18ba0efebed46d8c5dae4c07fa1b67a07", size = 244971, upload-time = "2025-09-17T20:15:12.262Z" }, +] + +[[package]] +name = "pydantic" +version = "2.11.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ff/5d/09a551ba512d7ca404d785072700d3f6727a02f6f3c24ecfd081c7cf0aa8/pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2", size = 788495, upload-time = "2025-09-13T11:26:39.325Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/d3/108f2006987c58e76691d5ae5d200dd3e0f532cb4e5fa3560751c3a1feba/pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2", size = 444855, upload-time = "2025-09-13T11:26:36.909Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584, upload-time = "2025-04-23T18:31:03.106Z" }, + { url = "https://files.pythonhosted.org/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071, upload-time = "2025-04-23T18:31:04.621Z" }, + { url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823, upload-time = "2025-04-23T18:31:06.377Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792, upload-time = "2025-04-23T18:31:07.93Z" }, + { url = "https://files.pythonhosted.org/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338, upload-time = "2025-04-23T18:31:09.283Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998, upload-time = "2025-04-23T18:31:11.7Z" }, + { url = "https://files.pythonhosted.org/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200, upload-time = "2025-04-23T18:31:13.536Z" }, + { url = "https://files.pythonhosted.org/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890, upload-time = "2025-04-23T18:31:15.011Z" }, + { url = "https://files.pythonhosted.org/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359, upload-time = "2025-04-23T18:31:16.393Z" }, + { url = "https://files.pythonhosted.org/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883, upload-time = "2025-04-23T18:31:17.892Z" }, + { url = "https://files.pythonhosted.org/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074, upload-time = "2025-04-23T18:31:19.205Z" }, + { url = "https://files.pythonhosted.org/packages/e0/ed/55532bb88f674d5d8f67ab121a2a13c385df382de2a1677f30ad385f7438/pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51", size = 1910538, upload-time = "2025-04-23T18:31:20.541Z" }, + { url = "https://files.pythonhosted.org/packages/fe/1b/25b7cccd4519c0b23c2dd636ad39d381abf113085ce4f7bec2b0dc755eb1/pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab", size = 1952909, upload-time = "2025-04-23T18:31:22.371Z" }, + { url = "https://files.pythonhosted.org/packages/49/a9/d809358e49126438055884c4366a1f6227f0f84f635a9014e2deb9b9de54/pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65", size = 1897786, upload-time = "2025-04-23T18:31:24.161Z" }, + { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, + { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, + { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, + { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, + { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, + { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, + { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, + { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, + { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, + { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, + { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, + { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, + { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, + { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, + { url = "https://files.pythonhosted.org/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200, upload-time = "2025-04-23T18:33:14.199Z" }, + { url = "https://files.pythonhosted.org/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123, upload-time = "2025-04-23T18:33:16.555Z" }, + { url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852, upload-time = "2025-04-23T18:33:18.513Z" }, + { url = "https://files.pythonhosted.org/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484, upload-time = "2025-04-23T18:33:20.475Z" }, + { url = "https://files.pythonhosted.org/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896, upload-time = "2025-04-23T18:33:22.501Z" }, + { url = "https://files.pythonhosted.org/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475, upload-time = "2025-04-23T18:33:24.528Z" }, + { url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013, upload-time = "2025-04-23T18:33:26.621Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715, upload-time = "2025-04-23T18:33:28.656Z" }, + { url = "https://files.pythonhosted.org/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757, upload-time = "2025-04-23T18:33:30.645Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "python-engineio" +version = "4.12.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "simple-websocket" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ba/0b/67295279b66835f9fa7a491650efcd78b20321c127036eef62c11a31e028/python_engineio-4.12.2.tar.gz", hash = "sha256:e7e712ffe1be1f6a05ee5f951e72d434854a32fcfc7f6e4d9d3cae24ec70defa", size = 91677, upload-time = "2025-06-04T19:22:18.789Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/fa/df59acedf7bbb937f69174d00f921a7b93aa5a5f5c17d05296c814fff6fc/python_engineio-4.12.2-py3-none-any.whl", hash = "sha256:8218ab66950e179dfec4b4bbb30aecf3f5d86f5e58e6fc1aa7fde2c698b2804f", size = 59536, upload-time = "2025-06-04T19:22:16.916Z" }, +] + +[[package]] +name = "python-multipart" +version = "0.0.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, +] + +[[package]] +name = "python-socketio" +version = "5.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bidict" }, + { name = "python-engineio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/1a/396d50ccf06ee539fa758ce5623b59a9cb27637fc4b2dc07ed08bf495e77/python_socketio-5.13.0.tar.gz", hash = "sha256:ac4e19a0302ae812e23b712ec8b6427ca0521f7c582d6abb096e36e24a263029", size = 121125, upload-time = "2025-04-12T15:46:59.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/32/b4fb8585d1be0f68bde7e110dffbcf354915f77ad8c778563f0ad9655c02/python_socketio-5.13.0-py3-none-any.whl", hash = "sha256:51f68d6499f2df8524668c24bcec13ba1414117cfb3a90115c559b601ab10caf", size = 77800, upload-time = "2025-04-12T15:46:58.412Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" }, + { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" }, + { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" }, + { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" }, + { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" }, + { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" }, + { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" }, + { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" }, + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, +] + +[[package]] +name = "redis" +version = "6.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "async-timeout", marker = "python_full_version < '3.11.3'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0d/d6/e8b92798a5bd67d659d51a18170e91c16ac3b59738d91894651ee255ed49/redis-6.4.0.tar.gz", hash = "sha256:b01bc7282b8444e28ec36b261df5375183bb47a07eb9c603f284e89cbc5ef010", size = 4647399, upload-time = "2025-08-07T08:10:11.441Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/02/89e2ed7e85db6c93dfa9e8f691c5087df4e3551ab39081a4d7c6d1f90e05/redis-6.4.0-py3-none-any.whl", hash = "sha256:f0544fa9604264e9464cdf4814e7d4830f74b165d52f2a330a760a88dd248b7f", size = 279847, upload-time = "2025-08-07T08:10:09.84Z" }, +] + +[[package]] +name = "reflex" +version = "0.8.12.dev1" +source = { git = "https://github.com/reflex-dev/reflex?rev=main#6d8b083201debe2c932f9a4146996c32ad5883e7" } +dependencies = [ + { name = "alembic" }, + { name = "click" }, + { name = "granian", extra = ["reload"] }, + { name = "httpx" }, + { name = "packaging" }, + { name = "platformdirs" }, + { name = "psutil", marker = "sys_platform == 'win32'" }, + { name = "pydantic" }, + { name = "python-multipart" }, + { name = "python-socketio" }, + { name = "redis" }, + { name = "reflex-hosting-cli" }, + { name = "rich" }, + { name = "sqlmodel" }, + { name = "starlette" }, + { name = "typing-extensions" }, + { name = "wrapt" }, +] + +[[package]] +name = "reflex-enterprise" +version = "0.3.4.post2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asgiproxy" }, + { name = "psutil" }, + { name = "reflex" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/73/26/d5a05b8da95732fe26d189a68750d002bba5c3d04e67fac02ad23f614e6d/reflex_enterprise-0.3.4.post2.tar.gz", hash = "sha256:507d433a83d115bd1759c02eccd2970ca8a32028f338f77c8b15a9a8fae65be9", size = 312682, upload-time = "2025-09-11T17:25:08.005Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/98/11883185d0702ccea43e42bfdbb48b24fc8fa2463fc503458e154329bfb6/reflex_enterprise-0.3.4.post2-py3-none-any.whl", hash = "sha256:fc339ebbd60e888d07081b3a715d28f48cc7978256293cf71674721f7ae318ee", size = 185887, upload-time = "2025-09-11T17:25:06.724Z" }, +] + +[[package]] +name = "reflex-hosting-cli" +version = "0.1.55" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "httpx" }, + { name = "packaging" }, + { name = "platformdirs" }, + { name = "rich" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/80/04/5920b46c3363edf5b4165909c3f87a197ee42d42a33cbd8497479f2cfefd/reflex_hosting_cli-0.1.55.tar.gz", hash = "sha256:f5d5b0c26cefdc7ba3356954b7be6bfa8ec50267c13a2247f6cf18a140e95918", size = 35818, upload-time = "2025-08-14T21:04:55.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/b3/e3e96eec558368cce20d7064862f50849886565187b2dd1df600874799c9/reflex_hosting_cli-0.1.55-py3-none-any.whl", hash = "sha256:84e78715a1f112996a0a1f8c5503958931a7fc6f0f61b7332645b8fde96c3b17", size = 45323, upload-time = "2025-08-14T21:04:53.9Z" }, +] + +[[package]] +name = "rich" +version = "14.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8", size = 224441, upload-time = "2025-07-25T07:32:58.125Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", size = 243368, upload-time = "2025-07-25T07:32:56.73Z" }, +] + +[[package]] +name = "simple-websocket" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wsproto" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b0/d4/bfa032f961103eba93de583b161f0e6a5b63cebb8f2c7d0c6e6efe1e3d2e/simple_websocket-1.1.0.tar.gz", hash = "sha256:7939234e7aa067c534abdab3a9ed933ec9ce4691b0713c78acb195560aa52ae4", size = 17300, upload-time = "2024-10-10T22:39:31.412Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl", hash = "sha256:4af6069630a38ed6c561010f0e11a5bc0d4ca569b36306eb257cd9a192497c8c", size = 13842, upload-time = "2024-10-10T22:39:29.645Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.43" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d7/bc/d59b5d97d27229b0e009bd9098cd81af71c2fa5549c580a0a67b9bed0496/sqlalchemy-2.0.43.tar.gz", hash = "sha256:788bfcef6787a7764169cfe9859fe425bf44559619e1d9f56f5bddf2ebf6f417", size = 9762949, upload-time = "2025-08-11T14:24:58.438Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/77/fa7189fe44114658002566c6fe443d3ed0ec1fa782feb72af6ef7fbe98e7/sqlalchemy-2.0.43-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:52d9b73b8fb3e9da34c2b31e6d99d60f5f99fd8c1225c9dad24aeb74a91e1d29", size = 2136472, upload-time = "2025-08-11T15:52:21.789Z" }, + { url = "https://files.pythonhosted.org/packages/99/ea/92ac27f2fbc2e6c1766bb807084ca455265707e041ba027c09c17d697867/sqlalchemy-2.0.43-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f42f23e152e4545157fa367b2435a1ace7571cab016ca26038867eb7df2c3631", size = 2126535, upload-time = "2025-08-11T15:52:23.109Z" }, + { url = "https://files.pythonhosted.org/packages/94/12/536ede80163e295dc57fff69724caf68f91bb40578b6ac6583a293534849/sqlalchemy-2.0.43-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fb1a8c5438e0c5ea51afe9c6564f951525795cf432bed0c028c1cb081276685", size = 3297521, upload-time = "2025-08-11T15:50:33.536Z" }, + { url = "https://files.pythonhosted.org/packages/03/b5/cacf432e6f1fc9d156eca0560ac61d4355d2181e751ba8c0cd9cb232c8c1/sqlalchemy-2.0.43-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db691fa174e8f7036afefe3061bc40ac2b770718be2862bfb03aabae09051aca", size = 3297343, upload-time = "2025-08-11T15:57:51.186Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ba/d4c9b526f18457667de4c024ffbc3a0920c34237b9e9dd298e44c7c00ee5/sqlalchemy-2.0.43-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe2b3b4927d0bc03d02ad883f402d5de201dbc8894ac87d2e981e7d87430e60d", size = 3232113, upload-time = "2025-08-11T15:50:34.949Z" }, + { url = "https://files.pythonhosted.org/packages/aa/79/c0121b12b1b114e2c8a10ea297a8a6d5367bc59081b2be896815154b1163/sqlalchemy-2.0.43-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4d3d9b904ad4a6b175a2de0738248822f5ac410f52c2fd389ada0b5262d6a1e3", size = 3258240, upload-time = "2025-08-11T15:57:52.983Z" }, + { url = "https://files.pythonhosted.org/packages/79/99/a2f9be96fb382f3ba027ad42f00dbe30fdb6ba28cda5f11412eee346bec5/sqlalchemy-2.0.43-cp311-cp311-win32.whl", hash = "sha256:5cda6b51faff2639296e276591808c1726c4a77929cfaa0f514f30a5f6156921", size = 2101248, upload-time = "2025-08-11T15:55:01.855Z" }, + { url = "https://files.pythonhosted.org/packages/ee/13/744a32ebe3b4a7a9c7ea4e57babae7aa22070d47acf330d8e5a1359607f1/sqlalchemy-2.0.43-cp311-cp311-win_amd64.whl", hash = "sha256:c5d1730b25d9a07727d20ad74bc1039bbbb0a6ca24e6769861c1aa5bf2c4c4a8", size = 2126109, upload-time = "2025-08-11T15:55:04.092Z" }, + { url = "https://files.pythonhosted.org/packages/61/db/20c78f1081446095450bdc6ee6cc10045fce67a8e003a5876b6eaafc5cc4/sqlalchemy-2.0.43-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:20d81fc2736509d7a2bd33292e489b056cbae543661bb7de7ce9f1c0cd6e7f24", size = 2134891, upload-time = "2025-08-11T15:51:13.019Z" }, + { url = "https://files.pythonhosted.org/packages/45/0a/3d89034ae62b200b4396f0f95319f7d86e9945ee64d2343dcad857150fa2/sqlalchemy-2.0.43-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b9fc27650ff5a2c9d490c13c14906b918b0de1f8fcbb4c992712d8caf40e83", size = 2123061, upload-time = "2025-08-11T15:51:14.319Z" }, + { url = "https://files.pythonhosted.org/packages/cb/10/2711f7ff1805919221ad5bee205971254845c069ee2e7036847103ca1e4c/sqlalchemy-2.0.43-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6772e3ca8a43a65a37c88e2f3e2adfd511b0b1da37ef11ed78dea16aeae85bd9", size = 3320384, upload-time = "2025-08-11T15:52:35.088Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0e/3d155e264d2ed2778484006ef04647bc63f55b3e2d12e6a4f787747b5900/sqlalchemy-2.0.43-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a113da919c25f7f641ffbd07fbc9077abd4b3b75097c888ab818f962707eb48", size = 3329648, upload-time = "2025-08-11T15:56:34.153Z" }, + { url = "https://files.pythonhosted.org/packages/5b/81/635100fb19725c931622c673900da5efb1595c96ff5b441e07e3dd61f2be/sqlalchemy-2.0.43-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4286a1139f14b7d70141c67a8ae1582fc2b69105f1b09d9573494eb4bb4b2687", size = 3258030, upload-time = "2025-08-11T15:52:36.933Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ed/a99302716d62b4965fded12520c1cbb189f99b17a6d8cf77611d21442e47/sqlalchemy-2.0.43-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:529064085be2f4d8a6e5fab12d36ad44f1909a18848fcfbdb59cc6d4bbe48efe", size = 3294469, upload-time = "2025-08-11T15:56:35.553Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a2/3a11b06715149bf3310b55a98b5c1e84a42cfb949a7b800bc75cb4e33abc/sqlalchemy-2.0.43-cp312-cp312-win32.whl", hash = "sha256:b535d35dea8bbb8195e7e2b40059e2253acb2b7579b73c1b432a35363694641d", size = 2098906, upload-time = "2025-08-11T15:55:00.645Z" }, + { url = "https://files.pythonhosted.org/packages/bc/09/405c915a974814b90aa591280623adc6ad6b322f61fd5cff80aeaef216c9/sqlalchemy-2.0.43-cp312-cp312-win_amd64.whl", hash = "sha256:1c6d85327ca688dbae7e2b06d7d84cfe4f3fffa5b5f9e21bb6ce9d0e1a0e0e0a", size = 2126260, upload-time = "2025-08-11T15:55:02.965Z" }, + { url = "https://files.pythonhosted.org/packages/41/1c/a7260bd47a6fae7e03768bf66451437b36451143f36b285522b865987ced/sqlalchemy-2.0.43-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e7c08f57f75a2bb62d7ee80a89686a5e5669f199235c6d1dac75cd59374091c3", size = 2130598, upload-time = "2025-08-11T15:51:15.903Z" }, + { url = "https://files.pythonhosted.org/packages/8e/84/8a337454e82388283830b3586ad7847aa9c76fdd4f1df09cdd1f94591873/sqlalchemy-2.0.43-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:14111d22c29efad445cd5021a70a8b42f7d9152d8ba7f73304c4d82460946aaa", size = 2118415, upload-time = "2025-08-11T15:51:17.256Z" }, + { url = "https://files.pythonhosted.org/packages/cf/ff/22ab2328148492c4d71899d62a0e65370ea66c877aea017a244a35733685/sqlalchemy-2.0.43-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21b27b56eb2f82653168cefe6cb8e970cdaf4f3a6cb2c5e3c3c1cf3158968ff9", size = 3248707, upload-time = "2025-08-11T15:52:38.444Z" }, + { url = "https://files.pythonhosted.org/packages/dc/29/11ae2c2b981de60187f7cbc84277d9d21f101093d1b2e945c63774477aba/sqlalchemy-2.0.43-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c5a9da957c56e43d72126a3f5845603da00e0293720b03bde0aacffcf2dc04f", size = 3253602, upload-time = "2025-08-11T15:56:37.348Z" }, + { url = "https://files.pythonhosted.org/packages/b8/61/987b6c23b12c56d2be451bc70900f67dd7d989d52b1ee64f239cf19aec69/sqlalchemy-2.0.43-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d79f9fdc9584ec83d1b3c75e9f4595c49017f5594fee1a2217117647225d738", size = 3183248, upload-time = "2025-08-11T15:52:39.865Z" }, + { url = "https://files.pythonhosted.org/packages/86/85/29d216002d4593c2ce1c0ec2cec46dda77bfbcd221e24caa6e85eff53d89/sqlalchemy-2.0.43-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9df7126fd9db49e3a5a3999442cc67e9ee8971f3cb9644250107d7296cb2a164", size = 3219363, upload-time = "2025-08-11T15:56:39.11Z" }, + { url = "https://files.pythonhosted.org/packages/b6/e4/bd78b01919c524f190b4905d47e7630bf4130b9f48fd971ae1c6225b6f6a/sqlalchemy-2.0.43-cp313-cp313-win32.whl", hash = "sha256:7f1ac7828857fcedb0361b48b9ac4821469f7694089d15550bbcf9ab22564a1d", size = 2096718, upload-time = "2025-08-11T15:55:05.349Z" }, + { url = "https://files.pythonhosted.org/packages/ac/a5/ca2f07a2a201f9497de1928f787926613db6307992fe5cda97624eb07c2f/sqlalchemy-2.0.43-cp313-cp313-win_amd64.whl", hash = "sha256:971ba928fcde01869361f504fcff3b7143b47d30de188b11c6357c0505824197", size = 2123200, upload-time = "2025-08-11T15:55:07.932Z" }, + { url = "https://files.pythonhosted.org/packages/b8/d9/13bdde6521f322861fab67473cec4b1cc8999f3871953531cf61945fad92/sqlalchemy-2.0.43-py3-none-any.whl", hash = "sha256:1681c21dd2ccee222c2fe0bef671d1aef7c504087c9c4e800371cfcc8ac966fc", size = 1924759, upload-time = "2025-08-11T15:39:53.024Z" }, +] + +[[package]] +name = "sqlmodel" +version = "0.0.25" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "sqlalchemy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ea/80/d9c098a88724ee4554907939cf39590cf67e10c6683723216e228d3315f7/sqlmodel-0.0.25.tar.gz", hash = "sha256:56548c2e645975b1ed94d6c53f0d13c85593f57926a575e2bf566650b2243fa4", size = 117075, upload-time = "2025-09-17T21:44:41.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/cf/5d175ce8de07fe694ec4e3d4d65c2dd06cc30f6c79599b31f9d2f6dd2830/sqlmodel-0.0.25-py3-none-any.whl", hash = "sha256:c98234cda701fb77e9dcbd81688c23bb251c13bb98ce1dd8d4adc467374d45b7", size = 28893, upload-time = "2025-09-17T21:44:39.764Z" }, +] + +[[package]] +name = "starlette" +version = "0.48.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/a5/d6f429d43394057b67a6b5bbe6eae2f77a6bf7459d961fdb224bf206eee6/starlette-0.48.0.tar.gz", hash = "sha256:7e8cee469a8ab2352911528110ce9088fdc6a37d9876926e73da7ce4aa4c7a46", size = 2652949, upload-time = "2025-09-13T08:41:05.699Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/72/2db2f49247d0a18b4f1bb9a5a39a0162869acf235f3a96418363947b3d46/starlette-0.48.0-py3-none-any.whl", hash = "sha256:0764ca97b097582558ecb498132ed0c7d942f233f365b86ba37770e026510659", size = 73736, upload-time = "2025-09-13T08:41:03.869Z" }, +] + +[[package]] +name = "templates" +version = "0.0.1" +source = { virtual = "." } +dependencies = [ + { name = "pre-commit" }, + { name = "reflex" }, + { name = "reflex-enterprise" }, +] + +[package.metadata] +requires-dist = [ + { name = "pre-commit", specifier = ">=3.7.0" }, + { name = "reflex", git = "https://github.com/reflex-dev/reflex?rev=main" }, + { name = "reflex-enterprise", specifier = ">=0.3.4" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, +] + +[[package]] +name = "virtualenv" +version = "20.34.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1c/14/37fcdba2808a6c615681cd216fecae00413c9dab44fb2e57805ecf3eaee3/virtualenv-20.34.0.tar.gz", hash = "sha256:44815b2c9dee7ed86e387b842a84f20b93f7f417f95886ca1996a72a4138eb1a", size = 6003808, upload-time = "2025-08-13T14:24:07.464Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/06/04c8e804f813cf972e3262f3f8584c232de64f0cde9f703b46cf53a45090/virtualenv-20.34.0-py3-none-any.whl", hash = "sha256:341f5afa7eee943e4984a9207c025feedd768baff6753cd660c857ceb3e36026", size = 5983279, upload-time = "2025-08-13T14:24:05.111Z" }, +] + +[[package]] +name = "watchfiles" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2a/9a/d451fcc97d029f5812e898fd30a53fd8c15c7bbd058fd75cfc6beb9bd761/watchfiles-1.1.0.tar.gz", hash = "sha256:693ed7ec72cbfcee399e92c895362b6e66d63dac6b91e2c11ae03d10d503e575", size = 94406, upload-time = "2025-06-15T19:06:59.42Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/78/7401154b78ab484ccaaeef970dc2af0cb88b5ba8a1b415383da444cdd8d3/watchfiles-1.1.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c9649dfc57cc1f9835551deb17689e8d44666315f2e82d337b9f07bd76ae3aa2", size = 405751, upload-time = "2025-06-15T19:05:07.679Z" }, + { url = "https://files.pythonhosted.org/packages/76/63/e6c3dbc1f78d001589b75e56a288c47723de28c580ad715eb116639152b5/watchfiles-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:406520216186b99374cdb58bc48e34bb74535adec160c8459894884c983a149c", size = 397313, upload-time = "2025-06-15T19:05:08.764Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a2/8afa359ff52e99af1632f90cbf359da46184207e893a5f179301b0c8d6df/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb45350fd1dc75cd68d3d72c47f5b513cb0578da716df5fba02fff31c69d5f2d", size = 450792, upload-time = "2025-06-15T19:05:09.869Z" }, + { url = "https://files.pythonhosted.org/packages/1d/bf/7446b401667f5c64972a57a0233be1104157fc3abf72c4ef2666c1bd09b2/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:11ee4444250fcbeb47459a877e5e80ed994ce8e8d20283857fc128be1715dac7", size = 458196, upload-time = "2025-06-15T19:05:11.91Z" }, + { url = "https://files.pythonhosted.org/packages/58/2f/501ddbdfa3fa874ea5597c77eeea3d413579c29af26c1091b08d0c792280/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bda8136e6a80bdea23e5e74e09df0362744d24ffb8cd59c4a95a6ce3d142f79c", size = 484788, upload-time = "2025-06-15T19:05:13.373Z" }, + { url = "https://files.pythonhosted.org/packages/61/1e/9c18eb2eb5c953c96bc0e5f626f0e53cfef4bd19bd50d71d1a049c63a575/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b915daeb2d8c1f5cee4b970f2e2c988ce6514aace3c9296e58dd64dc9aa5d575", size = 597879, upload-time = "2025-06-15T19:05:14.725Z" }, + { url = "https://files.pythonhosted.org/packages/8b/6c/1467402e5185d89388b4486745af1e0325007af0017c3384cc786fff0542/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed8fc66786de8d0376f9f913c09e963c66e90ced9aa11997f93bdb30f7c872a8", size = 477447, upload-time = "2025-06-15T19:05:15.775Z" }, + { url = "https://files.pythonhosted.org/packages/2b/a1/ec0a606bde4853d6c4a578f9391eeb3684a9aea736a8eb217e3e00aa89a1/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe4371595edf78c41ef8ac8df20df3943e13defd0efcb732b2e393b5a8a7a71f", size = 453145, upload-time = "2025-06-15T19:05:17.17Z" }, + { url = "https://files.pythonhosted.org/packages/90/b9/ef6f0c247a6a35d689fc970dc7f6734f9257451aefb30def5d100d6246a5/watchfiles-1.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b7c5f6fe273291f4d414d55b2c80d33c457b8a42677ad14b4b47ff025d0893e4", size = 626539, upload-time = "2025-06-15T19:05:18.557Z" }, + { url = "https://files.pythonhosted.org/packages/34/44/6ffda5537085106ff5aaa762b0d130ac6c75a08015dd1621376f708c94de/watchfiles-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7738027989881e70e3723c75921f1efa45225084228788fc59ea8c6d732eb30d", size = 624472, upload-time = "2025-06-15T19:05:19.588Z" }, + { url = "https://files.pythonhosted.org/packages/c3/e3/71170985c48028fa3f0a50946916a14055e741db11c2e7bc2f3b61f4d0e3/watchfiles-1.1.0-cp311-cp311-win32.whl", hash = "sha256:622d6b2c06be19f6e89b1d951485a232e3b59618def88dbeda575ed8f0d8dbf2", size = 279348, upload-time = "2025-06-15T19:05:20.856Z" }, + { url = "https://files.pythonhosted.org/packages/89/1b/3e39c68b68a7a171070f81fc2561d23ce8d6859659406842a0e4bebf3bba/watchfiles-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:48aa25e5992b61debc908a61ab4d3f216b64f44fdaa71eb082d8b2de846b7d12", size = 292607, upload-time = "2025-06-15T19:05:21.937Z" }, + { url = "https://files.pythonhosted.org/packages/61/9f/2973b7539f2bdb6ea86d2c87f70f615a71a1fc2dba2911795cea25968aea/watchfiles-1.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:00645eb79a3faa70d9cb15c8d4187bb72970b2470e938670240c7998dad9f13a", size = 285056, upload-time = "2025-06-15T19:05:23.12Z" }, + { url = "https://files.pythonhosted.org/packages/f6/b8/858957045a38a4079203a33aaa7d23ea9269ca7761c8a074af3524fbb240/watchfiles-1.1.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9dc001c3e10de4725c749d4c2f2bdc6ae24de5a88a339c4bce32300a31ede179", size = 402339, upload-time = "2025-06-15T19:05:24.516Z" }, + { url = "https://files.pythonhosted.org/packages/80/28/98b222cca751ba68e88521fabd79a4fab64005fc5976ea49b53fa205d1fa/watchfiles-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d9ba68ec283153dead62cbe81872d28e053745f12335d037de9cbd14bd1877f5", size = 394409, upload-time = "2025-06-15T19:05:25.469Z" }, + { url = "https://files.pythonhosted.org/packages/86/50/dee79968566c03190677c26f7f47960aff738d32087087bdf63a5473e7df/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:130fc497b8ee68dce163e4254d9b0356411d1490e868bd8790028bc46c5cc297", size = 450939, upload-time = "2025-06-15T19:05:26.494Z" }, + { url = "https://files.pythonhosted.org/packages/40/45/a7b56fb129700f3cfe2594a01aa38d033b92a33dddce86c8dfdfc1247b72/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:50a51a90610d0845a5931a780d8e51d7bd7f309ebc25132ba975aca016b576a0", size = 457270, upload-time = "2025-06-15T19:05:27.466Z" }, + { url = "https://files.pythonhosted.org/packages/b5/c8/fa5ef9476b1d02dc6b5e258f515fcaaecf559037edf8b6feffcbc097c4b8/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc44678a72ac0910bac46fa6a0de6af9ba1355669b3dfaf1ce5f05ca7a74364e", size = 483370, upload-time = "2025-06-15T19:05:28.548Z" }, + { url = "https://files.pythonhosted.org/packages/98/68/42cfcdd6533ec94f0a7aab83f759ec11280f70b11bfba0b0f885e298f9bd/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a543492513a93b001975ae283a51f4b67973662a375a403ae82f420d2c7205ee", size = 598654, upload-time = "2025-06-15T19:05:29.997Z" }, + { url = "https://files.pythonhosted.org/packages/d3/74/b2a1544224118cc28df7e59008a929e711f9c68ce7d554e171b2dc531352/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ac164e20d17cc285f2b94dc31c384bc3aa3dd5e7490473b3db043dd70fbccfd", size = 478667, upload-time = "2025-06-15T19:05:31.172Z" }, + { url = "https://files.pythonhosted.org/packages/8c/77/e3362fe308358dc9f8588102481e599c83e1b91c2ae843780a7ded939a35/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7590d5a455321e53857892ab8879dce62d1f4b04748769f5adf2e707afb9d4f", size = 452213, upload-time = "2025-06-15T19:05:32.299Z" }, + { url = "https://files.pythonhosted.org/packages/6e/17/c8f1a36540c9a1558d4faf08e909399e8133599fa359bf52ec8fcee5be6f/watchfiles-1.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:37d3d3f7defb13f62ece99e9be912afe9dd8a0077b7c45ee5a57c74811d581a4", size = 626718, upload-time = "2025-06-15T19:05:33.415Z" }, + { url = "https://files.pythonhosted.org/packages/26/45/fb599be38b4bd38032643783d7496a26a6f9ae05dea1a42e58229a20ac13/watchfiles-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7080c4bb3efd70a07b1cc2df99a7aa51d98685be56be6038c3169199d0a1c69f", size = 623098, upload-time = "2025-06-15T19:05:34.534Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e7/fdf40e038475498e160cd167333c946e45d8563ae4dd65caf757e9ffe6b4/watchfiles-1.1.0-cp312-cp312-win32.whl", hash = "sha256:cbcf8630ef4afb05dc30107bfa17f16c0896bb30ee48fc24bf64c1f970f3b1fd", size = 279209, upload-time = "2025-06-15T19:05:35.577Z" }, + { url = "https://files.pythonhosted.org/packages/3f/d3/3ae9d5124ec75143bdf088d436cba39812122edc47709cd2caafeac3266f/watchfiles-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:cbd949bdd87567b0ad183d7676feb98136cde5bb9025403794a4c0db28ed3a47", size = 292786, upload-time = "2025-06-15T19:05:36.559Z" }, + { url = "https://files.pythonhosted.org/packages/26/2f/7dd4fc8b5f2b34b545e19629b4a018bfb1de23b3a496766a2c1165ca890d/watchfiles-1.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:0a7d40b77f07be87c6faa93d0951a0fcd8cbca1ddff60a1b65d741bac6f3a9f6", size = 284343, upload-time = "2025-06-15T19:05:37.5Z" }, + { url = "https://files.pythonhosted.org/packages/d3/42/fae874df96595556a9089ade83be34a2e04f0f11eb53a8dbf8a8a5e562b4/watchfiles-1.1.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5007f860c7f1f8df471e4e04aaa8c43673429047d63205d1630880f7637bca30", size = 402004, upload-time = "2025-06-15T19:05:38.499Z" }, + { url = "https://files.pythonhosted.org/packages/fa/55/a77e533e59c3003d9803c09c44c3651224067cbe7fb5d574ddbaa31e11ca/watchfiles-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:20ecc8abbd957046f1fe9562757903f5eaf57c3bce70929fda6c7711bb58074a", size = 393671, upload-time = "2025-06-15T19:05:39.52Z" }, + { url = "https://files.pythonhosted.org/packages/05/68/b0afb3f79c8e832e6571022611adbdc36e35a44e14f129ba09709aa4bb7a/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2f0498b7d2a3c072766dba3274fe22a183dbea1f99d188f1c6c72209a1063dc", size = 449772, upload-time = "2025-06-15T19:05:40.897Z" }, + { url = "https://files.pythonhosted.org/packages/ff/05/46dd1f6879bc40e1e74c6c39a1b9ab9e790bf1f5a2fe6c08b463d9a807f4/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:239736577e848678e13b201bba14e89718f5c2133dfd6b1f7846fa1b58a8532b", size = 456789, upload-time = "2025-06-15T19:05:42.045Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ca/0eeb2c06227ca7f12e50a47a3679df0cd1ba487ea19cf844a905920f8e95/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eff4b8d89f444f7e49136dc695599a591ff769300734446c0a86cba2eb2f9895", size = 482551, upload-time = "2025-06-15T19:05:43.781Z" }, + { url = "https://files.pythonhosted.org/packages/31/47/2cecbd8694095647406645f822781008cc524320466ea393f55fe70eed3b/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12b0a02a91762c08f7264e2e79542f76870c3040bbc847fb67410ab81474932a", size = 597420, upload-time = "2025-06-15T19:05:45.244Z" }, + { url = "https://files.pythonhosted.org/packages/d9/7e/82abc4240e0806846548559d70f0b1a6dfdca75c1b4f9fa62b504ae9b083/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29e7bc2eee15cbb339c68445959108803dc14ee0c7b4eea556400131a8de462b", size = 477950, upload-time = "2025-06-15T19:05:46.332Z" }, + { url = "https://files.pythonhosted.org/packages/25/0d/4d564798a49bf5482a4fa9416dea6b6c0733a3b5700cb8a5a503c4b15853/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9481174d3ed982e269c090f780122fb59cee6c3796f74efe74e70f7780ed94c", size = 451706, upload-time = "2025-06-15T19:05:47.459Z" }, + { url = "https://files.pythonhosted.org/packages/81/b5/5516cf46b033192d544102ea07c65b6f770f10ed1d0a6d388f5d3874f6e4/watchfiles-1.1.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:80f811146831c8c86ab17b640801c25dc0a88c630e855e2bef3568f30434d52b", size = 625814, upload-time = "2025-06-15T19:05:48.654Z" }, + { url = "https://files.pythonhosted.org/packages/0c/dd/7c1331f902f30669ac3e754680b6edb9a0dd06dea5438e61128111fadd2c/watchfiles-1.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:60022527e71d1d1fda67a33150ee42869042bce3d0fcc9cc49be009a9cded3fb", size = 622820, upload-time = "2025-06-15T19:05:50.088Z" }, + { url = "https://files.pythonhosted.org/packages/1b/14/36d7a8e27cd128d7b1009e7715a7c02f6c131be9d4ce1e5c3b73d0e342d8/watchfiles-1.1.0-cp313-cp313-win32.whl", hash = "sha256:32d6d4e583593cb8576e129879ea0991660b935177c0f93c6681359b3654bfa9", size = 279194, upload-time = "2025-06-15T19:05:51.186Z" }, + { url = "https://files.pythonhosted.org/packages/25/41/2dd88054b849aa546dbeef5696019c58f8e0774f4d1c42123273304cdb2e/watchfiles-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:f21af781a4a6fbad54f03c598ab620e3a77032c5878f3d780448421a6e1818c7", size = 292349, upload-time = "2025-06-15T19:05:52.201Z" }, + { url = "https://files.pythonhosted.org/packages/c8/cf/421d659de88285eb13941cf11a81f875c176f76a6d99342599be88e08d03/watchfiles-1.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:5366164391873ed76bfdf618818c82084c9db7fac82b64a20c44d335eec9ced5", size = 283836, upload-time = "2025-06-15T19:05:53.265Z" }, + { url = "https://files.pythonhosted.org/packages/45/10/6faf6858d527e3599cc50ec9fcae73590fbddc1420bd4fdccfebffeedbc6/watchfiles-1.1.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:17ab167cca6339c2b830b744eaf10803d2a5b6683be4d79d8475d88b4a8a4be1", size = 400343, upload-time = "2025-06-15T19:05:54.252Z" }, + { url = "https://files.pythonhosted.org/packages/03/20/5cb7d3966f5e8c718006d0e97dfe379a82f16fecd3caa7810f634412047a/watchfiles-1.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:328dbc9bff7205c215a7807da7c18dce37da7da718e798356212d22696404339", size = 392916, upload-time = "2025-06-15T19:05:55.264Z" }, + { url = "https://files.pythonhosted.org/packages/8c/07/d8f1176328fa9e9581b6f120b017e286d2a2d22ae3f554efd9515c8e1b49/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7208ab6e009c627b7557ce55c465c98967e8caa8b11833531fdf95799372633", size = 449582, upload-time = "2025-06-15T19:05:56.317Z" }, + { url = "https://files.pythonhosted.org/packages/66/e8/80a14a453cf6038e81d072a86c05276692a1826471fef91df7537dba8b46/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a8f6f72974a19efead54195bc9bed4d850fc047bb7aa971268fd9a8387c89011", size = 456752, upload-time = "2025-06-15T19:05:57.359Z" }, + { url = "https://files.pythonhosted.org/packages/5a/25/0853b3fe0e3c2f5af9ea60eb2e781eade939760239a72c2d38fc4cc335f6/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d181ef50923c29cf0450c3cd47e2f0557b62218c50b2ab8ce2ecaa02bd97e670", size = 481436, upload-time = "2025-06-15T19:05:58.447Z" }, + { url = "https://files.pythonhosted.org/packages/fe/9e/4af0056c258b861fbb29dcb36258de1e2b857be4a9509e6298abcf31e5c9/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:adb4167043d3a78280d5d05ce0ba22055c266cf8655ce942f2fb881262ff3cdf", size = 596016, upload-time = "2025-06-15T19:05:59.59Z" }, + { url = "https://files.pythonhosted.org/packages/c5/fa/95d604b58aa375e781daf350897aaaa089cff59d84147e9ccff2447c8294/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5701dc474b041e2934a26d31d39f90fac8a3dee2322b39f7729867f932b1d4", size = 476727, upload-time = "2025-06-15T19:06:01.086Z" }, + { url = "https://files.pythonhosted.org/packages/65/95/fe479b2664f19be4cf5ceeb21be05afd491d95f142e72d26a42f41b7c4f8/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b067915e3c3936966a8607f6fe5487df0c9c4afb85226613b520890049deea20", size = 451864, upload-time = "2025-06-15T19:06:02.144Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8a/3c4af14b93a15ce55901cd7a92e1a4701910f1768c78fb30f61d2b79785b/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:9c733cda03b6d636b4219625a4acb5c6ffb10803338e437fb614fef9516825ef", size = 625626, upload-time = "2025-06-15T19:06:03.578Z" }, + { url = "https://files.pythonhosted.org/packages/da/f5/cf6aa047d4d9e128f4b7cde615236a915673775ef171ff85971d698f3c2c/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:cc08ef8b90d78bfac66f0def80240b0197008e4852c9f285907377b2947ffdcb", size = 622744, upload-time = "2025-06-15T19:06:05.066Z" }, + { url = "https://files.pythonhosted.org/packages/2c/00/70f75c47f05dea6fd30df90f047765f6fc2d6eb8b5a3921379b0b04defa2/watchfiles-1.1.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:9974d2f7dc561cce3bb88dfa8eb309dab64c729de85fba32e98d75cf24b66297", size = 402114, upload-time = "2025-06-15T19:06:06.186Z" }, + { url = "https://files.pythonhosted.org/packages/53/03/acd69c48db4a1ed1de26b349d94077cca2238ff98fd64393f3e97484cae6/watchfiles-1.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c68e9f1fcb4d43798ad8814c4c1b61547b014b667216cb754e606bfade587018", size = 393879, upload-time = "2025-06-15T19:06:07.369Z" }, + { url = "https://files.pythonhosted.org/packages/2f/c8/a9a2a6f9c8baa4eceae5887fecd421e1b7ce86802bcfc8b6a942e2add834/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95ab1594377effac17110e1352989bdd7bdfca9ff0e5eeccd8c69c5389b826d0", size = 450026, upload-time = "2025-06-15T19:06:08.476Z" }, + { url = "https://files.pythonhosted.org/packages/fe/51/d572260d98388e6e2b967425c985e07d47ee6f62e6455cefb46a6e06eda5/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fba9b62da882c1be1280a7584ec4515d0a6006a94d6e5819730ec2eab60ffe12", size = 457917, upload-time = "2025-06-15T19:06:09.988Z" }, + { url = "https://files.pythonhosted.org/packages/c6/2d/4258e52917bf9f12909b6ec314ff9636276f3542f9d3807d143f27309104/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3434e401f3ce0ed6b42569128b3d1e3af773d7ec18751b918b89cd49c14eaafb", size = 483602, upload-time = "2025-06-15T19:06:11.088Z" }, + { url = "https://files.pythonhosted.org/packages/84/99/bee17a5f341a4345fe7b7972a475809af9e528deba056f8963d61ea49f75/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa257a4d0d21fcbca5b5fcba9dca5a78011cb93c0323fb8855c6d2dfbc76eb77", size = 596758, upload-time = "2025-06-15T19:06:12.197Z" }, + { url = "https://files.pythonhosted.org/packages/40/76/e4bec1d59b25b89d2b0716b41b461ed655a9a53c60dc78ad5771fda5b3e6/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fd1b3879a578a8ec2076c7961076df540b9af317123f84569f5a9ddee64ce92", size = 477601, upload-time = "2025-06-15T19:06:13.391Z" }, + { url = "https://files.pythonhosted.org/packages/1f/fa/a514292956f4a9ce3c567ec0c13cce427c158e9f272062685a8a727d08fc/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62cc7a30eeb0e20ecc5f4bd113cd69dcdb745a07c68c0370cea919f373f65d9e", size = 451936, upload-time = "2025-06-15T19:06:14.656Z" }, + { url = "https://files.pythonhosted.org/packages/32/5d/c3bf927ec3bbeb4566984eba8dd7a8eb69569400f5509904545576741f88/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:891c69e027748b4a73847335d208e374ce54ca3c335907d381fde4e41661b13b", size = 626243, upload-time = "2025-06-15T19:06:16.232Z" }, + { url = "https://files.pythonhosted.org/packages/e6/65/6e12c042f1a68c556802a84d54bb06d35577c81e29fba14019562479159c/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:12fe8eaffaf0faa7906895b4f8bb88264035b3f0243275e0bf24af0436b27259", size = 623073, upload-time = "2025-06-15T19:06:17.457Z" }, + { url = "https://files.pythonhosted.org/packages/89/ab/7f79d9bf57329e7cbb0a6fd4c7bd7d0cee1e4a8ef0041459f5409da3506c/watchfiles-1.1.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:bfe3c517c283e484843cb2e357dd57ba009cff351edf45fb455b5fbd1f45b15f", size = 400872, upload-time = "2025-06-15T19:06:18.57Z" }, + { url = "https://files.pythonhosted.org/packages/df/d5/3f7bf9912798e9e6c516094db6b8932df53b223660c781ee37607030b6d3/watchfiles-1.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a9ccbf1f129480ed3044f540c0fdbc4ee556f7175e5ab40fe077ff6baf286d4e", size = 392877, upload-time = "2025-06-15T19:06:19.55Z" }, + { url = "https://files.pythonhosted.org/packages/0d/c5/54ec7601a2798604e01c75294770dbee8150e81c6e471445d7601610b495/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba0e3255b0396cac3cc7bbace76404dd72b5438bf0d8e7cefa2f79a7f3649caa", size = 449645, upload-time = "2025-06-15T19:06:20.66Z" }, + { url = "https://files.pythonhosted.org/packages/0a/04/c2f44afc3b2fce21ca0b7802cbd37ed90a29874f96069ed30a36dfe57c2b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4281cd9fce9fc0a9dbf0fc1217f39bf9cf2b4d315d9626ef1d4e87b84699e7e8", size = 457424, upload-time = "2025-06-15T19:06:21.712Z" }, + { url = "https://files.pythonhosted.org/packages/9f/b0/eec32cb6c14d248095261a04f290636da3df3119d4040ef91a4a50b29fa5/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d2404af8db1329f9a3c9b79ff63e0ae7131986446901582067d9304ae8aaf7f", size = 481584, upload-time = "2025-06-15T19:06:22.777Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e2/ca4bb71c68a937d7145aa25709e4f5d68eb7698a25ce266e84b55d591bbd/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e78b6ed8165996013165eeabd875c5dfc19d41b54f94b40e9fff0eb3193e5e8e", size = 596675, upload-time = "2025-06-15T19:06:24.226Z" }, + { url = "https://files.pythonhosted.org/packages/a1/dd/b0e4b7fb5acf783816bc950180a6cd7c6c1d2cf7e9372c0ea634e722712b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:249590eb75ccc117f488e2fabd1bfa33c580e24b96f00658ad88e38844a040bb", size = 477363, upload-time = "2025-06-15T19:06:25.42Z" }, + { url = "https://files.pythonhosted.org/packages/69/c4/088825b75489cb5b6a761a4542645718893d395d8c530b38734f19da44d2/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05686b5487cfa2e2c28ff1aa370ea3e6c5accfe6435944ddea1e10d93872147", size = 452240, upload-time = "2025-06-15T19:06:26.552Z" }, + { url = "https://files.pythonhosted.org/packages/10/8c/22b074814970eeef43b7c44df98c3e9667c1f7bf5b83e0ff0201b0bd43f9/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d0e10e6f8f6dc5762adee7dece33b722282e1f59aa6a55da5d493a97282fedd8", size = 625607, upload-time = "2025-06-15T19:06:27.606Z" }, + { url = "https://files.pythonhosted.org/packages/32/fa/a4f5c2046385492b2273213ef815bf71a0d4c1943b784fb904e184e30201/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:af06c863f152005c7592df1d6a7009c836a247c9d8adb78fef8575a5a98699db", size = 623315, upload-time = "2025-06-15T19:06:29.076Z" }, + { url = "https://files.pythonhosted.org/packages/8c/6b/686dcf5d3525ad17b384fd94708e95193529b460a1b7bf40851f1328ec6e/watchfiles-1.1.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0ece16b563b17ab26eaa2d52230c9a7ae46cf01759621f4fbbca280e438267b3", size = 406910, upload-time = "2025-06-15T19:06:49.335Z" }, + { url = "https://files.pythonhosted.org/packages/f3/d3/71c2dcf81dc1edcf8af9f4d8d63b1316fb0a2dd90cbfd427e8d9dd584a90/watchfiles-1.1.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:51b81e55d40c4b4aa8658427a3ee7ea847c591ae9e8b81ef94a90b668999353c", size = 398816, upload-time = "2025-06-15T19:06:50.433Z" }, + { url = "https://files.pythonhosted.org/packages/b8/fa/12269467b2fc006f8fce4cd6c3acfa77491dd0777d2a747415f28ccc8c60/watchfiles-1.1.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2bcdc54ea267fe72bfc7d83c041e4eb58d7d8dc6f578dfddb52f037ce62f432", size = 451584, upload-time = "2025-06-15T19:06:51.834Z" }, + { url = "https://files.pythonhosted.org/packages/bd/d3/254cea30f918f489db09d6a8435a7de7047f8cb68584477a515f160541d6/watchfiles-1.1.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:923fec6e5461c42bd7e3fd5ec37492c6f3468be0499bc0707b4bbbc16ac21792", size = 454009, upload-time = "2025-06-15T19:06:52.896Z" }, +] + +[[package]] +name = "websockets" +version = "15.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, + { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, + { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, + { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, + { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, + { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, + { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, + { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, + { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, + { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, + { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, + { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, + { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, + { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, + { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, + { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, + { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, + { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, + { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, + { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, + { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, + { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, + { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, + { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, + { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, + { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, +] + +[[package]] +name = "wrapt" +version = "1.17.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/8f/aeb76c5b46e273670962298c23e7ddde79916cb74db802131d49a85e4b7d/wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0", size = 55547, upload-time = "2025-08-12T05:53:21.714Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/db/00e2a219213856074a213503fdac0511203dceefff26e1daa15250cc01a0/wrapt-1.17.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7", size = 53482, upload-time = "2025-08-12T05:51:45.79Z" }, + { url = "https://files.pythonhosted.org/packages/5e/30/ca3c4a5eba478408572096fe9ce36e6e915994dd26a4e9e98b4f729c06d9/wrapt-1.17.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85", size = 38674, upload-time = "2025-08-12T05:51:34.629Z" }, + { url = "https://files.pythonhosted.org/packages/31/25/3e8cc2c46b5329c5957cec959cb76a10718e1a513309c31399a4dad07eb3/wrapt-1.17.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f", size = 38959, upload-time = "2025-08-12T05:51:56.074Z" }, + { url = "https://files.pythonhosted.org/packages/5d/8f/a32a99fc03e4b37e31b57cb9cefc65050ea08147a8ce12f288616b05ef54/wrapt-1.17.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311", size = 82376, upload-time = "2025-08-12T05:52:32.134Z" }, + { url = "https://files.pythonhosted.org/packages/31/57/4930cb8d9d70d59c27ee1332a318c20291749b4fba31f113c2f8ac49a72e/wrapt-1.17.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1", size = 83604, upload-time = "2025-08-12T05:52:11.663Z" }, + { url = "https://files.pythonhosted.org/packages/a8/f3/1afd48de81d63dd66e01b263a6fbb86e1b5053b419b9b33d13e1f6d0f7d0/wrapt-1.17.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5", size = 82782, upload-time = "2025-08-12T05:52:12.626Z" }, + { url = "https://files.pythonhosted.org/packages/1e/d7/4ad5327612173b144998232f98a85bb24b60c352afb73bc48e3e0d2bdc4e/wrapt-1.17.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2", size = 82076, upload-time = "2025-08-12T05:52:33.168Z" }, + { url = "https://files.pythonhosted.org/packages/bb/59/e0adfc831674a65694f18ea6dc821f9fcb9ec82c2ce7e3d73a88ba2e8718/wrapt-1.17.3-cp311-cp311-win32.whl", hash = "sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89", size = 36457, upload-time = "2025-08-12T05:53:03.936Z" }, + { url = "https://files.pythonhosted.org/packages/83/88/16b7231ba49861b6f75fc309b11012ede4d6b0a9c90969d9e0db8d991aeb/wrapt-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77", size = 38745, upload-time = "2025-08-12T05:53:02.885Z" }, + { url = "https://files.pythonhosted.org/packages/9a/1e/c4d4f3398ec073012c51d1c8d87f715f56765444e1a4b11e5180577b7e6e/wrapt-1.17.3-cp311-cp311-win_arm64.whl", hash = "sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a", size = 36806, upload-time = "2025-08-12T05:52:53.368Z" }, + { url = "https://files.pythonhosted.org/packages/9f/41/cad1aba93e752f1f9268c77270da3c469883d56e2798e7df6240dcb2287b/wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0", size = 53998, upload-time = "2025-08-12T05:51:47.138Z" }, + { url = "https://files.pythonhosted.org/packages/60/f8/096a7cc13097a1869fe44efe68dace40d2a16ecb853141394047f0780b96/wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba", size = 39020, upload-time = "2025-08-12T05:51:35.906Z" }, + { url = "https://files.pythonhosted.org/packages/33/df/bdf864b8997aab4febb96a9ae5c124f700a5abd9b5e13d2a3214ec4be705/wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd", size = 39098, upload-time = "2025-08-12T05:51:57.474Z" }, + { url = "https://files.pythonhosted.org/packages/9f/81/5d931d78d0eb732b95dc3ddaeeb71c8bb572fb01356e9133916cd729ecdd/wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828", size = 88036, upload-time = "2025-08-12T05:52:34.784Z" }, + { url = "https://files.pythonhosted.org/packages/ca/38/2e1785df03b3d72d34fc6252d91d9d12dc27a5c89caef3335a1bbb8908ca/wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9", size = 88156, upload-time = "2025-08-12T05:52:13.599Z" }, + { url = "https://files.pythonhosted.org/packages/b3/8b/48cdb60fe0603e34e05cffda0b2a4adab81fd43718e11111a4b0100fd7c1/wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396", size = 87102, upload-time = "2025-08-12T05:52:14.56Z" }, + { url = "https://files.pythonhosted.org/packages/3c/51/d81abca783b58f40a154f1b2c56db1d2d9e0d04fa2d4224e357529f57a57/wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc", size = 87732, upload-time = "2025-08-12T05:52:36.165Z" }, + { url = "https://files.pythonhosted.org/packages/9e/b1/43b286ca1392a006d5336412d41663eeef1ad57485f3e52c767376ba7e5a/wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe", size = 36705, upload-time = "2025-08-12T05:53:07.123Z" }, + { url = "https://files.pythonhosted.org/packages/28/de/49493f962bd3c586ab4b88066e967aa2e0703d6ef2c43aa28cb83bf7b507/wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c", size = 38877, upload-time = "2025-08-12T05:53:05.436Z" }, + { url = "https://files.pythonhosted.org/packages/f1/48/0f7102fe9cb1e8a5a77f80d4f0956d62d97034bbe88d33e94699f99d181d/wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6", size = 36885, upload-time = "2025-08-12T05:52:54.367Z" }, + { url = "https://files.pythonhosted.org/packages/fc/f6/759ece88472157acb55fc195e5b116e06730f1b651b5b314c66291729193/wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0", size = 54003, upload-time = "2025-08-12T05:51:48.627Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a9/49940b9dc6d47027dc850c116d79b4155f15c08547d04db0f07121499347/wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77", size = 39025, upload-time = "2025-08-12T05:51:37.156Z" }, + { url = "https://files.pythonhosted.org/packages/45/35/6a08de0f2c96dcdd7fe464d7420ddb9a7655a6561150e5fc4da9356aeaab/wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7", size = 39108, upload-time = "2025-08-12T05:51:58.425Z" }, + { url = "https://files.pythonhosted.org/packages/0c/37/6faf15cfa41bf1f3dba80cd3f5ccc6622dfccb660ab26ed79f0178c7497f/wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277", size = 88072, upload-time = "2025-08-12T05:52:37.53Z" }, + { url = "https://files.pythonhosted.org/packages/78/f2/efe19ada4a38e4e15b6dff39c3e3f3f73f5decf901f66e6f72fe79623a06/wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d", size = 88214, upload-time = "2025-08-12T05:52:15.886Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/ca86701e9de1622b16e09689fc24b76f69b06bb0150990f6f4e8b0eeb576/wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa", size = 87105, upload-time = "2025-08-12T05:52:17.914Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e0/d10bd257c9a3e15cbf5523025252cc14d77468e8ed644aafb2d6f54cb95d/wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050", size = 87766, upload-time = "2025-08-12T05:52:39.243Z" }, + { url = "https://files.pythonhosted.org/packages/e8/cf/7d848740203c7b4b27eb55dbfede11aca974a51c3d894f6cc4b865f42f58/wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8", size = 36711, upload-time = "2025-08-12T05:53:10.074Z" }, + { url = "https://files.pythonhosted.org/packages/57/54/35a84d0a4d23ea675994104e667ceff49227ce473ba6a59ba2c84f250b74/wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb", size = 38885, upload-time = "2025-08-12T05:53:08.695Z" }, + { url = "https://files.pythonhosted.org/packages/01/77/66e54407c59d7b02a3c4e0af3783168fff8e5d61def52cda8728439d86bc/wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16", size = 36896, upload-time = "2025-08-12T05:52:55.34Z" }, + { url = "https://files.pythonhosted.org/packages/02/a2/cd864b2a14f20d14f4c496fab97802001560f9f41554eef6df201cd7f76c/wrapt-1.17.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39", size = 54132, upload-time = "2025-08-12T05:51:49.864Z" }, + { url = "https://files.pythonhosted.org/packages/d5/46/d011725b0c89e853dc44cceb738a307cde5d240d023d6d40a82d1b4e1182/wrapt-1.17.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235", size = 39091, upload-time = "2025-08-12T05:51:38.935Z" }, + { url = "https://files.pythonhosted.org/packages/2e/9e/3ad852d77c35aae7ddebdbc3b6d35ec8013af7d7dddad0ad911f3d891dae/wrapt-1.17.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c", size = 39172, upload-time = "2025-08-12T05:51:59.365Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f7/c983d2762bcce2326c317c26a6a1e7016f7eb039c27cdf5c4e30f4160f31/wrapt-1.17.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b", size = 87163, upload-time = "2025-08-12T05:52:40.965Z" }, + { url = "https://files.pythonhosted.org/packages/e4/0f/f673f75d489c7f22d17fe0193e84b41540d962f75fce579cf6873167c29b/wrapt-1.17.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa", size = 87963, upload-time = "2025-08-12T05:52:20.326Z" }, + { url = "https://files.pythonhosted.org/packages/df/61/515ad6caca68995da2fac7a6af97faab8f78ebe3bf4f761e1b77efbc47b5/wrapt-1.17.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7", size = 86945, upload-time = "2025-08-12T05:52:21.581Z" }, + { url = "https://files.pythonhosted.org/packages/d3/bd/4e70162ce398462a467bc09e768bee112f1412e563620adc353de9055d33/wrapt-1.17.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4", size = 86857, upload-time = "2025-08-12T05:52:43.043Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b8/da8560695e9284810b8d3df8a19396a6e40e7518059584a1a394a2b35e0a/wrapt-1.17.3-cp314-cp314-win32.whl", hash = "sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10", size = 37178, upload-time = "2025-08-12T05:53:12.605Z" }, + { url = "https://files.pythonhosted.org/packages/db/c8/b71eeb192c440d67a5a0449aaee2310a1a1e8eca41676046f99ed2487e9f/wrapt-1.17.3-cp314-cp314-win_amd64.whl", hash = "sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6", size = 39310, upload-time = "2025-08-12T05:53:11.106Z" }, + { url = "https://files.pythonhosted.org/packages/45/20/2cda20fd4865fa40f86f6c46ed37a2a8356a7a2fde0773269311f2af56c7/wrapt-1.17.3-cp314-cp314-win_arm64.whl", hash = "sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58", size = 37266, upload-time = "2025-08-12T05:52:56.531Z" }, + { url = "https://files.pythonhosted.org/packages/77/ed/dd5cf21aec36c80443c6f900449260b80e2a65cf963668eaef3b9accce36/wrapt-1.17.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a", size = 56544, upload-time = "2025-08-12T05:51:51.109Z" }, + { url = "https://files.pythonhosted.org/packages/8d/96/450c651cc753877ad100c7949ab4d2e2ecc4d97157e00fa8f45df682456a/wrapt-1.17.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067", size = 40283, upload-time = "2025-08-12T05:51:39.912Z" }, + { url = "https://files.pythonhosted.org/packages/d1/86/2fcad95994d9b572db57632acb6f900695a648c3e063f2cd344b3f5c5a37/wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454", size = 40366, upload-time = "2025-08-12T05:52:00.693Z" }, + { url = "https://files.pythonhosted.org/packages/64/0e/f4472f2fdde2d4617975144311f8800ef73677a159be7fe61fa50997d6c0/wrapt-1.17.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e", size = 108571, upload-time = "2025-08-12T05:52:44.521Z" }, + { url = "https://files.pythonhosted.org/packages/cc/01/9b85a99996b0a97c8a17484684f206cbb6ba73c1ce6890ac668bcf3838fb/wrapt-1.17.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f", size = 113094, upload-time = "2025-08-12T05:52:22.618Z" }, + { url = "https://files.pythonhosted.org/packages/25/02/78926c1efddcc7b3aa0bc3d6b33a822f7d898059f7cd9ace8c8318e559ef/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056", size = 110659, upload-time = "2025-08-12T05:52:24.057Z" }, + { url = "https://files.pythonhosted.org/packages/dc/ee/c414501ad518ac3e6fe184753632fe5e5ecacdcf0effc23f31c1e4f7bfcf/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804", size = 106946, upload-time = "2025-08-12T05:52:45.976Z" }, + { url = "https://files.pythonhosted.org/packages/be/44/a1bd64b723d13bb151d6cc91b986146a1952385e0392a78567e12149c7b4/wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977", size = 38717, upload-time = "2025-08-12T05:53:15.214Z" }, + { url = "https://files.pythonhosted.org/packages/79/d9/7cfd5a312760ac4dd8bf0184a6ee9e43c33e47f3dadc303032ce012b8fa3/wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116", size = 41334, upload-time = "2025-08-12T05:53:14.178Z" }, + { url = "https://files.pythonhosted.org/packages/46/78/10ad9781128ed2f99dbc474f43283b13fea8ba58723e98844367531c18e9/wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6", size = 38471, upload-time = "2025-08-12T05:52:57.784Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" }, +] + +[[package]] +name = "wsproto" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/4a/44d3c295350d776427904d73c189e10aeae66d7f555bb2feee16d1e4ba5a/wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065", size = 53425, upload-time = "2022-08-23T19:58:21.447Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/58/e860788190eba3bcce367f74d29c4675466ce8dddfba85f7827588416f01/wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736", size = 24226, upload-time = "2022-08-23T19:58:19.96Z" }, +] + +[[package]] +name = "yarl" +version = "1.20.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/18/893b50efc2350e47a874c5c2d67e55a0ea5df91186b2a6f5ac52eff887cd/yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e", size = 133833, upload-time = "2025-06-10T00:43:07.393Z" }, + { url = "https://files.pythonhosted.org/packages/89/ed/b8773448030e6fc47fa797f099ab9eab151a43a25717f9ac043844ad5ea3/yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b", size = 91070, upload-time = "2025-06-10T00:43:09.538Z" }, + { url = "https://files.pythonhosted.org/packages/e3/e3/409bd17b1e42619bf69f60e4f031ce1ccb29bd7380117a55529e76933464/yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b", size = 89818, upload-time = "2025-06-10T00:43:11.575Z" }, + { url = "https://files.pythonhosted.org/packages/f8/77/64d8431a4d77c856eb2d82aa3de2ad6741365245a29b3a9543cd598ed8c5/yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4", size = 347003, upload-time = "2025-06-10T00:43:14.088Z" }, + { url = "https://files.pythonhosted.org/packages/8d/d2/0c7e4def093dcef0bd9fa22d4d24b023788b0a33b8d0088b51aa51e21e99/yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1", size = 336537, upload-time = "2025-06-10T00:43:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/f0/f3/fc514f4b2cf02cb59d10cbfe228691d25929ce8f72a38db07d3febc3f706/yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833", size = 362358, upload-time = "2025-06-10T00:43:18.704Z" }, + { url = "https://files.pythonhosted.org/packages/ea/6d/a313ac8d8391381ff9006ac05f1d4331cee3b1efaa833a53d12253733255/yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d", size = 357362, upload-time = "2025-06-10T00:43:20.888Z" }, + { url = "https://files.pythonhosted.org/packages/00/70/8f78a95d6935a70263d46caa3dd18e1f223cf2f2ff2037baa01a22bc5b22/yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8", size = 348979, upload-time = "2025-06-10T00:43:23.169Z" }, + { url = "https://files.pythonhosted.org/packages/cb/05/42773027968968f4f15143553970ee36ead27038d627f457cc44bbbeecf3/yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf", size = 337274, upload-time = "2025-06-10T00:43:27.111Z" }, + { url = "https://files.pythonhosted.org/packages/05/be/665634aa196954156741ea591d2f946f1b78ceee8bb8f28488bf28c0dd62/yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e", size = 363294, upload-time = "2025-06-10T00:43:28.96Z" }, + { url = "https://files.pythonhosted.org/packages/eb/90/73448401d36fa4e210ece5579895731f190d5119c4b66b43b52182e88cd5/yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389", size = 358169, upload-time = "2025-06-10T00:43:30.701Z" }, + { url = "https://files.pythonhosted.org/packages/c3/b0/fce922d46dc1eb43c811f1889f7daa6001b27a4005587e94878570300881/yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f", size = 362776, upload-time = "2025-06-10T00:43:32.51Z" }, + { url = "https://files.pythonhosted.org/packages/f1/0d/b172628fce039dae8977fd22caeff3eeebffd52e86060413f5673767c427/yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845", size = 381341, upload-time = "2025-06-10T00:43:34.543Z" }, + { url = "https://files.pythonhosted.org/packages/6b/9b/5b886d7671f4580209e855974fe1cecec409aa4a89ea58b8f0560dc529b1/yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1", size = 379988, upload-time = "2025-06-10T00:43:36.489Z" }, + { url = "https://files.pythonhosted.org/packages/73/be/75ef5fd0fcd8f083a5d13f78fd3f009528132a1f2a1d7c925c39fa20aa79/yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e", size = 371113, upload-time = "2025-06-10T00:43:38.592Z" }, + { url = "https://files.pythonhosted.org/packages/50/4f/62faab3b479dfdcb741fe9e3f0323e2a7d5cd1ab2edc73221d57ad4834b2/yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773", size = 81485, upload-time = "2025-06-10T00:43:41.038Z" }, + { url = "https://files.pythonhosted.org/packages/f0/09/d9c7942f8f05c32ec72cd5c8e041c8b29b5807328b68b4801ff2511d4d5e/yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e", size = 86686, upload-time = "2025-06-10T00:43:42.692Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9a/cb7fad7d73c69f296eda6815e4a2c7ed53fc70c2f136479a91c8e5fbdb6d/yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9", size = 133667, upload-time = "2025-06-10T00:43:44.369Z" }, + { url = "https://files.pythonhosted.org/packages/67/38/688577a1cb1e656e3971fb66a3492501c5a5df56d99722e57c98249e5b8a/yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a", size = 91025, upload-time = "2025-06-10T00:43:46.295Z" }, + { url = "https://files.pythonhosted.org/packages/50/ec/72991ae51febeb11a42813fc259f0d4c8e0507f2b74b5514618d8b640365/yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2", size = 89709, upload-time = "2025-06-10T00:43:48.22Z" }, + { url = "https://files.pythonhosted.org/packages/99/da/4d798025490e89426e9f976702e5f9482005c548c579bdae792a4c37769e/yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee", size = 352287, upload-time = "2025-06-10T00:43:49.924Z" }, + { url = "https://files.pythonhosted.org/packages/1a/26/54a15c6a567aac1c61b18aa0f4b8aa2e285a52d547d1be8bf48abe2b3991/yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819", size = 345429, upload-time = "2025-06-10T00:43:51.7Z" }, + { url = "https://files.pythonhosted.org/packages/d6/95/9dcf2386cb875b234353b93ec43e40219e14900e046bf6ac118f94b1e353/yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16", size = 365429, upload-time = "2025-06-10T00:43:53.494Z" }, + { url = "https://files.pythonhosted.org/packages/91/b2/33a8750f6a4bc224242a635f5f2cff6d6ad5ba651f6edcccf721992c21a0/yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6", size = 363862, upload-time = "2025-06-10T00:43:55.766Z" }, + { url = "https://files.pythonhosted.org/packages/98/28/3ab7acc5b51f4434b181b0cee8f1f4b77a65919700a355fb3617f9488874/yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd", size = 355616, upload-time = "2025-06-10T00:43:58.056Z" }, + { url = "https://files.pythonhosted.org/packages/36/a3/f666894aa947a371724ec7cd2e5daa78ee8a777b21509b4252dd7bd15e29/yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a", size = 339954, upload-time = "2025-06-10T00:43:59.773Z" }, + { url = "https://files.pythonhosted.org/packages/f1/81/5f466427e09773c04219d3450d7a1256138a010b6c9f0af2d48565e9ad13/yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38", size = 365575, upload-time = "2025-06-10T00:44:02.051Z" }, + { url = "https://files.pythonhosted.org/packages/2e/e3/e4b0ad8403e97e6c9972dd587388940a032f030ebec196ab81a3b8e94d31/yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef", size = 365061, upload-time = "2025-06-10T00:44:04.196Z" }, + { url = "https://files.pythonhosted.org/packages/ac/99/b8a142e79eb86c926f9f06452eb13ecb1bb5713bd01dc0038faf5452e544/yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f", size = 364142, upload-time = "2025-06-10T00:44:06.527Z" }, + { url = "https://files.pythonhosted.org/packages/34/f2/08ed34a4a506d82a1a3e5bab99ccd930a040f9b6449e9fd050320e45845c/yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8", size = 381894, upload-time = "2025-06-10T00:44:08.379Z" }, + { url = "https://files.pythonhosted.org/packages/92/f8/9a3fbf0968eac704f681726eff595dce9b49c8a25cd92bf83df209668285/yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a", size = 383378, upload-time = "2025-06-10T00:44:10.51Z" }, + { url = "https://files.pythonhosted.org/packages/af/85/9363f77bdfa1e4d690957cd39d192c4cacd1c58965df0470a4905253b54f/yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004", size = 374069, upload-time = "2025-06-10T00:44:12.834Z" }, + { url = "https://files.pythonhosted.org/packages/35/99/9918c8739ba271dcd935400cff8b32e3cd319eaf02fcd023d5dcd487a7c8/yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5", size = 81249, upload-time = "2025-06-10T00:44:14.731Z" }, + { url = "https://files.pythonhosted.org/packages/eb/83/5d9092950565481b413b31a23e75dd3418ff0a277d6e0abf3729d4d1ce25/yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698", size = 86710, upload-time = "2025-06-10T00:44:16.716Z" }, + { url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" }, + { url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" }, + { url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" }, + { url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" }, + { url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" }, + { url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" }, + { url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" }, + { url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" }, + { url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" }, + { url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" }, + { url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" }, + { url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" }, + { url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" }, + { url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" }, + { url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" }, + { url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" }, + { url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" }, + { url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" }, + { url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" }, + { url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" }, + { url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" }, + { url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" }, + { url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" }, + { url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" }, + { url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" }, + { url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" }, + { url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" }, + { url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" }, + { url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" }, + { url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" }, + { url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" }, + { url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" }, + { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" }, +]