merging
This commit is contained in:
commit
8b74a7a1e9
8
.github/workflows/benchmarks.yml
vendored
8
.github/workflows/benchmarks.yml
vendored
@ -81,11 +81,15 @@ jobs:
|
||||
matrix:
|
||||
# Show OS combos first in GUI
|
||||
os: [ubuntu-latest, windows-latest, macos-12]
|
||||
python-version: ['3.10.13', '3.11.5', '3.12.0']
|
||||
python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0']
|
||||
exclude:
|
||||
- os: windows-latest
|
||||
python-version: '3.10.13'
|
||||
- os: windows-latest
|
||||
python-version: '3.9.18'
|
||||
# keep only one python version for MacOS
|
||||
- os: macos-latest
|
||||
python-version: '3.9.18'
|
||||
- os: macos-latest
|
||||
python-version: '3.10.13'
|
||||
- os: macos-12
|
||||
@ -93,6 +97,8 @@ jobs:
|
||||
include:
|
||||
- os: windows-latest
|
||||
python-version: '3.10.11'
|
||||
- os: windows-latest
|
||||
python-version: '3.9.13'
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
40
.github/workflows/check_node_latest.yml
vendored
Normal file
40
.github/workflows/check_node_latest.yml
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
name: integration-node-latest
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
env:
|
||||
TELEMETRY_ENABLED: false
|
||||
REFLEX_USE_SYSTEM_NODE: true
|
||||
|
||||
jobs:
|
||||
check_latest_node:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.12']
|
||||
node-version: ['node']
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup_build_env
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
run-poetry-install: true
|
||||
create-venv-at-path: .venv
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: |
|
||||
poetry run uv pip install pyvirtualdisplay pillow
|
||||
poetry run playwright install --with-deps
|
||||
- run: |
|
||||
poetry run pytest tests/test_node_version.py
|
||||
poetry run pytest tests/integration
|
||||
|
||||
|
||||
|
@ -51,7 +51,7 @@ jobs:
|
||||
SCREENSHOT_DIR: /tmp/screenshots
|
||||
REDIS_URL: ${{ matrix.state_manager == 'redis' && 'redis://localhost:6379' || '' }}
|
||||
run: |
|
||||
poetry run pytest integration
|
||||
poetry run pytest tests/integration
|
||||
- uses: actions/upload-artifact@v4
|
||||
name: Upload failed test screenshots
|
||||
if: always()
|
||||
|
7
.github/workflows/integration_tests.yml
vendored
7
.github/workflows/integration_tests.yml
vendored
@ -43,14 +43,17 @@ jobs:
|
||||
matrix:
|
||||
# Show OS combos first in GUI
|
||||
os: [ubuntu-latest, windows-latest, macos-12]
|
||||
python-version: ['3.10.13', '3.11.5', '3.12.0']
|
||||
python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0']
|
||||
exclude:
|
||||
- os: windows-latest
|
||||
python-version: '3.10.13'
|
||||
- os: windows-latest
|
||||
python-version: '3.9.18'
|
||||
include:
|
||||
- os: windows-latest
|
||||
python-version: '3.10.11'
|
||||
|
||||
- os: windows-latest
|
||||
python-version: '3.9.13'
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
@ -28,5 +28,5 @@ jobs:
|
||||
# Run reflex init in a docker container
|
||||
|
||||
# cwd is repo root
|
||||
docker build -f integration/init-test/Dockerfile -t reflex-init-test integration/init-test
|
||||
docker run --rm -v $(pwd):/reflex-repo/ reflex-init-test /reflex-repo/integration/init-test/in_docker_test_script.sh
|
||||
docker build -f tests/integration/init-test/Dockerfile -t reflex-init-test tests/integration/init-test
|
||||
docker run --rm -v $(pwd):/reflex-repo/ reflex-init-test /reflex-repo/tests/integration/init-test/in_docker_test_script.sh
|
||||
|
12
.github/workflows/unit_tests.yml
vendored
12
.github/workflows/unit_tests.yml
vendored
@ -28,14 +28,18 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-12]
|
||||
python-version: ['3.10.13', '3.11.5', '3.12.0']
|
||||
python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0']
|
||||
# Windows is a bit behind on Python version availability in Github
|
||||
exclude:
|
||||
- os: windows-latest
|
||||
python-version: '3.10.13'
|
||||
- os: windows-latest
|
||||
python-version: '3.9.18'
|
||||
include:
|
||||
- os: windows-latest
|
||||
python-version: '3.10.11'
|
||||
- os: windows-latest
|
||||
python-version: '3.9.13'
|
||||
runs-on: ${{ matrix.os }}
|
||||
# Service containers to run with `runner-job`
|
||||
services:
|
||||
@ -61,17 +65,17 @@ jobs:
|
||||
- name: Run unit tests
|
||||
run: |
|
||||
export PYTHONUNBUFFERED=1
|
||||
poetry run pytest tests --cov --no-cov-on-fail --cov-report=
|
||||
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
|
||||
- name: Run unit tests w/ redis
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
export PYTHONUNBUFFERED=1
|
||||
export REDIS_URL=redis://localhost:6379
|
||||
poetry run pytest tests --cov --no-cov-on-fail --cov-report=
|
||||
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
|
||||
# Change to explicitly install v1 when reflex-hosting-cli is compatible with v2
|
||||
- name: Run unit tests w/ pydantic v1
|
||||
run: |
|
||||
export PYTHONUNBUFFERED=1
|
||||
poetry run uv pip install "pydantic~=1.10"
|
||||
poetry run pytest tests --cov --no-cov-on-fail --cov-report=
|
||||
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
|
||||
- run: poetry run coverage html
|
||||
|
@ -6,7 +6,7 @@ repos:
|
||||
rev: v0.4.10
|
||||
hooks:
|
||||
- id: ruff-format
|
||||
args: [integration, reflex, tests]
|
||||
args: [reflex, tests]
|
||||
- id: ruff
|
||||
args: ["--fix", "--exit-non-zero-on-fix"]
|
||||
exclude: '^integration/benchmarks/'
|
||||
|
@ -8,7 +8,7 @@ Here is a quick guide on how to run Reflex repo locally so you can start contrib
|
||||
|
||||
**Prerequisites:**
|
||||
|
||||
- Python >= 3.10
|
||||
- Python >= 3.9
|
||||
- Poetry version >= 1.4.0 and add it to your path (see [Poetry Docs](https://python-poetry.org/docs/#installation) for more info).
|
||||
|
||||
**1. Fork this repository:**
|
||||
@ -69,7 +69,7 @@ In your `reflex` directory run make sure all the unit tests are still passing us
|
||||
This will fail if code coverage is below 70%.
|
||||
|
||||
``` bash
|
||||
poetry run pytest tests --cov --no-cov-on-fail --cov-report=
|
||||
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
|
||||
```
|
||||
|
||||
Next make sure all the following tests pass. This ensures that every new change has proper documentation and type checking.
|
||||
@ -87,7 +87,7 @@ poetry run ruff format .
|
||||
```
|
||||
|
||||
Consider installing git pre-commit hooks so Ruff, Pyright, Darglint and `make_pyi` will run automatically before each commit.
|
||||
Note that pre-commit will only be installed when you use a Python version >= 3.8.
|
||||
Note that pre-commit will only be installed when you use a Python version >= 3.9.
|
||||
|
||||
``` bash
|
||||
pre-commit install
|
||||
|
@ -34,7 +34,7 @@ See our [architecture page](https://reflex.dev/blog/2024-03-21-reflex-architectu
|
||||
|
||||
## ⚙️ Installation
|
||||
|
||||
Open a terminal and run (Requires Python 3.10+):
|
||||
Open a terminal and run (Requires Python 3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -34,7 +34,7 @@ Auf unserer [Architektur-Seite](https://reflex.dev/blog/2024-03-21-reflex-archit
|
||||
|
||||
## ⚙️ Installation
|
||||
|
||||
Öffne ein Terminal und führe den folgenden Befehl aus (benötigt Python 3.10+):
|
||||
Öffne ein Terminal und führe den folgenden Befehl aus (benötigt Python 3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -35,7 +35,7 @@ Consulta nuestra [página de arquitectura](https://reflex.dev/blog/2024-03-21-re
|
||||
|
||||
## ⚙️ Instalación
|
||||
|
||||
Abra un terminal y ejecute (Requiere Python 3.10+):
|
||||
Abra un terminal y ejecute (Requiere Python 3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -35,7 +35,7 @@ Reflex के अंदर के कामकाज को जानने क
|
||||
|
||||
## ⚙️ इंस्टॉलेशन (Installation)
|
||||
|
||||
एक टर्मिनल खोलें और चलाएं (Python 3.10+ की आवश्यकता है):
|
||||
एक टर्मिनल खोलें और चलाएं (Python 3.9+ की आवश्यकता है):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
## ⚙️ Installazione
|
||||
|
||||
Apri un terminale ed esegui (Richiede Python 3.10+):
|
||||
Apri un terminale ed esegui (Richiede Python 3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -37,7 +37,7 @@ Reflex がどのように動作しているかを知るには、[アーキテク
|
||||
|
||||
## ⚙️ インストール
|
||||
|
||||
ターミナルを開いて以下のコマンドを実行してください。(Python 3.8 以上が必要です。):
|
||||
ターミナルを開いて以下のコマンドを実行してください。(Python 3.9 以上が必要です。):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -20,7 +20,7 @@
|
||||
---
|
||||
## ⚙️ 설치
|
||||
|
||||
터미널을 열고 실행하세요. (Python 3.10+ 필요):
|
||||
터미널을 열고 실행하세요. (Python 3.9+ 필요):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
## ⚙️ Installation - نصب و راه اندازی
|
||||
|
||||
یک ترمینال را باز کنید و اجرا کنید (نیازمند Python 3.10+):
|
||||
یک ترمینال را باز کنید و اجرا کنید (نیازمند Python 3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -21,7 +21,7 @@
|
||||
---
|
||||
## ⚙️ Instalação
|
||||
|
||||
Abra um terminal e execute (Requer Python 3.10+):
|
||||
Abra um terminal e execute (Requer Python 3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
## ⚙️ Kurulum
|
||||
|
||||
Bir terminal açın ve çalıştırın (Python 3.10+ gerekir):
|
||||
Bir terminal açın ve çalıştırın (Python 3.9+ gerekir):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -34,7 +34,7 @@ Reflex 是一个使用纯Python构建全栈web应用的库。
|
||||
|
||||
## ⚙️ 安装
|
||||
|
||||
打开一个终端并且运行(要求Python3.8+):
|
||||
打开一个终端并且运行(要求Python3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -36,7 +36,7 @@ Reflex 是一個可以用純 Python 構建全端網頁應用程式的函式庫
|
||||
|
||||
## ⚙️ 安裝
|
||||
|
||||
開啟一個終端機並且執行 (需要 Python 3.10+):
|
||||
開啟一個終端機並且執行 (需要 Python 3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
581
poetry.lock
generated
581
poetry.lock
generated
@ -2,13 +2,13 @@
|
||||
|
||||
[[package]]
|
||||
name = "alembic"
|
||||
version = "1.13.2"
|
||||
version = "1.13.3"
|
||||
description = "A database migration tool for SQLAlchemy."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "alembic-1.13.2-py3-none-any.whl", hash = "sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953"},
|
||||
{file = "alembic-1.13.2.tar.gz", hash = "sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef"},
|
||||
{file = "alembic-1.13.3-py3-none-any.whl", hash = "sha256:908e905976d15235fae59c9ac42c4c5b75cfcefe3d27c0fbf7ae15a37715d80e"},
|
||||
{file = "alembic-1.13.3.tar.gz", hash = "sha256:203503117415561e203aa14541740643a611f641517f0209fcae63e9fa09f1a2"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -32,13 +32,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.5.0"
|
||||
version = "4.6.0"
|
||||
description = "High level compatibility layer for multiple asynchronous event loop implementations"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "anyio-4.5.0-py3-none-any.whl", hash = "sha256:fdeb095b7cc5a5563175eedd926ec4ae55413bb4be5770c424af0ba46ccb4a78"},
|
||||
{file = "anyio-4.5.0.tar.gz", hash = "sha256:c5a275fe5ca0afd788001f58fca1e69e29ce706d746e317d660e21f70c530ef9"},
|
||||
{file = "anyio-4.6.0-py3-none-any.whl", hash = "sha256:c7d2e9d63e31599eeb636c8c5c03a7e108d73b345f064f1c19fdc87b79036a9a"},
|
||||
{file = "anyio-4.6.0.tar.gz", hash = "sha256:137b4559cbb034c477165047febb6ff83f390fc3b20bf181c1fc0a728cb8beeb"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -616,77 +616,69 @@ typing = ["typing-extensions (>=4.12.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "greenlet"
|
||||
version = "3.1.0"
|
||||
version = "3.0.3"
|
||||
description = "Lightweight in-process concurrent programming"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "greenlet-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a814dc3100e8a046ff48faeaa909e80cdb358411a3d6dd5293158425c684eda8"},
|
||||
{file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a771dc64fa44ebe58d65768d869fcfb9060169d203446c1d446e844b62bdfdca"},
|
||||
{file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0e49a65d25d7350cca2da15aac31b6f67a43d867448babf997fe83c7505f57bc"},
|
||||
{file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2cd8518eade968bc52262d8c46727cfc0826ff4d552cf0430b8d65aaf50bb91d"},
|
||||
{file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76dc19e660baea5c38e949455c1181bc018893f25372d10ffe24b3ed7341fb25"},
|
||||
{file = "greenlet-3.1.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c0a5b1c22c82831f56f2f7ad9bbe4948879762fe0d59833a4a71f16e5fa0f682"},
|
||||
{file = "greenlet-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2651dfb006f391bcb240635079a68a261b227a10a08af6349cba834a2141efa1"},
|
||||
{file = "greenlet-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3e7e6ef1737a819819b1163116ad4b48d06cfdd40352d813bb14436024fcda99"},
|
||||
{file = "greenlet-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:ffb08f2a1e59d38c7b8b9ac8083c9c8b9875f0955b1e9b9b9a965607a51f8e54"},
|
||||
{file = "greenlet-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9730929375021ec90f6447bff4f7f5508faef1c02f399a1953870cdb78e0c345"},
|
||||
{file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:713d450cf8e61854de9420fb7eea8ad228df4e27e7d4ed465de98c955d2b3fa6"},
|
||||
{file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c3446937be153718250fe421da548f973124189f18fe4575a0510b5c928f0cc"},
|
||||
{file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ddc7bcedeb47187be74208bc652d63d6b20cb24f4e596bd356092d8000da6d6"},
|
||||
{file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44151d7b81b9391ed759a2f2865bbe623ef00d648fed59363be2bbbd5154656f"},
|
||||
{file = "greenlet-3.1.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cea1cca3be76c9483282dc7760ea1cc08a6ecec1f0b6ca0a94ea0d17432da19"},
|
||||
{file = "greenlet-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:619935a44f414274a2c08c9e74611965650b730eb4efe4b2270f91df5e4adf9a"},
|
||||
{file = "greenlet-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:221169d31cada333a0c7fd087b957c8f431c1dba202c3a58cf5a3583ed973e9b"},
|
||||
{file = "greenlet-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:01059afb9b178606b4b6e92c3e710ea1635597c3537e44da69f4531e111dd5e9"},
|
||||
{file = "greenlet-3.1.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:24fc216ec7c8be9becba8b64a98a78f9cd057fd2dc75ae952ca94ed8a893bf27"},
|
||||
{file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d07c28b85b350564bdff9f51c1c5007dfb2f389385d1bc23288de51134ca303"},
|
||||
{file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:243a223c96a4246f8a30ea470c440fe9db1f5e444941ee3c3cd79df119b8eebf"},
|
||||
{file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26811df4dc81271033a7836bc20d12cd30938e6bd2e9437f56fa03da81b0f8fc"},
|
||||
{file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9d86401550b09a55410f32ceb5fe7efcd998bd2dad9e82521713cb148a4a15f"},
|
||||
{file = "greenlet-3.1.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:26d9c1c4f1748ccac0bae1dbb465fb1a795a75aba8af8ca871503019f4285e2a"},
|
||||
{file = "greenlet-3.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:cd468ec62257bb4544989402b19d795d2305eccb06cde5da0eb739b63dc04665"},
|
||||
{file = "greenlet-3.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a53dfe8f82b715319e9953330fa5c8708b610d48b5c59f1316337302af5c0811"},
|
||||
{file = "greenlet-3.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:28fe80a3eb673b2d5cc3b12eea468a5e5f4603c26aa34d88bf61bba82ceb2f9b"},
|
||||
{file = "greenlet-3.1.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:76b3e3976d2a452cba7aa9e453498ac72240d43030fdc6d538a72b87eaff52fd"},
|
||||
{file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655b21ffd37a96b1e78cc48bf254f5ea4b5b85efaf9e9e2a526b3c9309d660ca"},
|
||||
{file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6f4c2027689093775fd58ca2388d58789009116844432d920e9147f91acbe64"},
|
||||
{file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76e5064fd8e94c3f74d9fd69b02d99e3cdb8fc286ed49a1f10b256e59d0d3a0b"},
|
||||
{file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a4bf607f690f7987ab3291406e012cd8591a4f77aa54f29b890f9c331e84989"},
|
||||
{file = "greenlet-3.1.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:037d9ac99540ace9424cb9ea89f0accfaff4316f149520b4ae293eebc5bded17"},
|
||||
{file = "greenlet-3.1.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:90b5bbf05fe3d3ef697103850c2ce3374558f6fe40fd57c9fac1bf14903f50a5"},
|
||||
{file = "greenlet-3.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:726377bd60081172685c0ff46afbc600d064f01053190e4450857483c4d44484"},
|
||||
{file = "greenlet-3.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:d46d5069e2eeda111d6f71970e341f4bd9aeeee92074e649ae263b834286ecc0"},
|
||||
{file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81eeec4403a7d7684b5812a8aaa626fa23b7d0848edb3a28d2eb3220daddcbd0"},
|
||||
{file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a3dae7492d16e85ea6045fd11cb8e782b63eac8c8d520c3a92c02ac4573b0a6"},
|
||||
{file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b5ea3664eed571779403858d7cd0a9b0ebf50d57d2cdeafc7748e09ef8cd81a"},
|
||||
{file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a22f4e26400f7f48faef2d69c20dc055a1f3043d330923f9abe08ea0aecc44df"},
|
||||
{file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13ff8c8e54a10472ce3b2a2da007f915175192f18e6495bad50486e87c7f6637"},
|
||||
{file = "greenlet-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9671e7282d8c6fcabc32c0fb8d7c0ea8894ae85cee89c9aadc2d7129e1a9954"},
|
||||
{file = "greenlet-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:184258372ae9e1e9bddce6f187967f2e08ecd16906557c4320e3ba88a93438c3"},
|
||||
{file = "greenlet-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:a0409bc18a9f85321399c29baf93545152d74a49d92f2f55302f122007cfda00"},
|
||||
{file = "greenlet-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9eb4a1d7399b9f3c7ac68ae6baa6be5f9195d1d08c9ddc45ad559aa6b556bce6"},
|
||||
{file = "greenlet-3.1.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:a8870983af660798dc1b529e1fd6f1cefd94e45135a32e58bd70edd694540f33"},
|
||||
{file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfcfb73aed40f550a57ea904629bdaf2e562c68fa1164fa4588e752af6efdc3f"},
|
||||
{file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9482c2ed414781c0af0b35d9d575226da6b728bd1a720668fa05837184965b7"},
|
||||
{file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d58ec349e0c2c0bc6669bf2cd4982d2f93bf067860d23a0ea1fe677b0f0b1e09"},
|
||||
{file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd65695a8df1233309b701dec2539cc4b11e97d4fcc0f4185b4a12ce54db0491"},
|
||||
{file = "greenlet-3.1.0-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:665b21e95bc0fce5cab03b2e1d90ba9c66c510f1bb5fdc864f3a377d0f553f6b"},
|
||||
{file = "greenlet-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d3c59a06c2c28a81a026ff11fbf012081ea34fb9b7052f2ed0366e14896f0a1d"},
|
||||
{file = "greenlet-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5415b9494ff6240b09af06b91a375731febe0090218e2898d2b85f9b92abcda0"},
|
||||
{file = "greenlet-3.1.0-cp38-cp38-win32.whl", hash = "sha256:1544b8dd090b494c55e60c4ff46e238be44fdc472d2589e943c241e0169bcea2"},
|
||||
{file = "greenlet-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:7f346d24d74c00b6730440f5eb8ec3fe5774ca8d1c9574e8e57c8671bb51b910"},
|
||||
{file = "greenlet-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:db1b3ccb93488328c74e97ff888604a8b95ae4f35f4f56677ca57a4fc3a4220b"},
|
||||
{file = "greenlet-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44cd313629ded43bb3b98737bba2f3e2c2c8679b55ea29ed73daea6b755fe8e7"},
|
||||
{file = "greenlet-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fad7a051e07f64e297e6e8399b4d6a3bdcad3d7297409e9a06ef8cbccff4f501"},
|
||||
{file = "greenlet-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3967dcc1cd2ea61b08b0b276659242cbce5caca39e7cbc02408222fb9e6ff39"},
|
||||
{file = "greenlet-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d45b75b0f3fd8d99f62eb7908cfa6d727b7ed190737dec7fe46d993da550b81a"},
|
||||
{file = "greenlet-3.1.0-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2d004db911ed7b6218ec5c5bfe4cf70ae8aa2223dffbb5b3c69e342bb253cb28"},
|
||||
{file = "greenlet-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9505a0c8579899057cbefd4ec34d865ab99852baf1ff33a9481eb3924e2da0b"},
|
||||
{file = "greenlet-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fd6e94593f6f9714dbad1aaba734b5ec04593374fa6638df61592055868f8b8"},
|
||||
{file = "greenlet-3.1.0-cp39-cp39-win32.whl", hash = "sha256:d0dd943282231480aad5f50f89bdf26690c995e8ff555f26d8a5b9887b559bcc"},
|
||||
{file = "greenlet-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:ac0adfdb3a21dc2a24ed728b61e72440d297d0fd3a577389df566651fcd08f97"},
|
||||
{file = "greenlet-3.1.0.tar.gz", hash = "sha256:b395121e9bbe8d02a750886f108d540abe66075e61e22f7353d9acb0b81be0f0"},
|
||||
{file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"},
|
||||
{file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"},
|
||||
{file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"},
|
||||
{file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"},
|
||||
{file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"},
|
||||
{file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"},
|
||||
{file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"},
|
||||
{file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"},
|
||||
{file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"},
|
||||
{file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"},
|
||||
{file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"},
|
||||
{file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"},
|
||||
{file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"},
|
||||
{file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"},
|
||||
{file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"},
|
||||
{file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"},
|
||||
{file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"},
|
||||
{file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"},
|
||||
{file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"},
|
||||
{file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"},
|
||||
{file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"},
|
||||
{file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"},
|
||||
{file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"},
|
||||
{file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"},
|
||||
{file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"},
|
||||
{file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"},
|
||||
{file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"},
|
||||
{file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"},
|
||||
{file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"},
|
||||
{file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"},
|
||||
{file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"},
|
||||
{file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"},
|
||||
{file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"},
|
||||
{file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"},
|
||||
{file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"},
|
||||
{file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"},
|
||||
{file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"},
|
||||
{file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"},
|
||||
{file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"},
|
||||
{file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"},
|
||||
{file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"},
|
||||
{file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"},
|
||||
{file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"},
|
||||
{file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"},
|
||||
{file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"},
|
||||
{file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"},
|
||||
{file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"},
|
||||
{file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"},
|
||||
{file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"},
|
||||
{file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"},
|
||||
{file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"},
|
||||
{file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"},
|
||||
{file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"},
|
||||
{file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"},
|
||||
{file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"},
|
||||
{file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"},
|
||||
{file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"},
|
||||
{file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@ -921,13 +913,13 @@ i18n = ["Babel (>=2.7)"]
|
||||
|
||||
[[package]]
|
||||
name = "keyring"
|
||||
version = "25.4.0"
|
||||
version = "25.4.1"
|
||||
description = "Store and access your passwords safely."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "keyring-25.4.0-py3-none-any.whl", hash = "sha256:a2a630d5c9bef5d3f0968d15ef4e42b894a83e17494edcb67b154c36491c9920"},
|
||||
{file = "keyring-25.4.0.tar.gz", hash = "sha256:ae8263fd9264c94f91ad82d098f8a5bb1b7fa71ce0a72388dc4fc0be3f6a034e"},
|
||||
{file = "keyring-25.4.1-py3-none-any.whl", hash = "sha256:5426f817cf7f6f007ba5ec722b1bcad95a75b27d780343772ad76b17cb47b0bf"},
|
||||
{file = "keyring-25.4.1.tar.gz", hash = "sha256:b07ebc55f3e8ed86ac81dd31ef14e81ace9dd9c3d4b5d77a6e9a2016d0d71a1b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1137,6 +1129,60 @@ files = [
|
||||
{file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "2.0.2"
|
||||
description = "Fundamental package for array computing in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece"},
|
||||
{file = "numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04"},
|
||||
{file = "numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66"},
|
||||
{file = "numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b"},
|
||||
{file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd"},
|
||||
{file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318"},
|
||||
{file = "numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8"},
|
||||
{file = "numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326"},
|
||||
{file = "numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97"},
|
||||
{file = "numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131"},
|
||||
{file = "numpy-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:49ca4decb342d66018b01932139c0961a8f9ddc7589611158cb3c27cbcf76448"},
|
||||
{file = "numpy-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:11a76c372d1d37437857280aa142086476136a8c0f373b2e648ab2c8f18fb195"},
|
||||
{file = "numpy-2.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:807ec44583fd708a21d4a11d94aedf2f4f3c3719035c76a2bbe1fe8e217bdc57"},
|
||||
{file = "numpy-2.0.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8cafab480740e22f8d833acefed5cc87ce276f4ece12fdaa2e8903db2f82897a"},
|
||||
{file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a15f476a45e6e5a3a79d8a14e62161d27ad897381fecfa4a09ed5322f2085669"},
|
||||
{file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e689d772146140a252c3a28501da66dfecd77490b498b168b501835041f951"},
|
||||
{file = "numpy-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9ea91dfb7c3d1c56a0e55657c0afb38cf1eeae4544c208dc465c3c9f3a7c09f9"},
|
||||
{file = "numpy-2.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c1c9307701fec8f3f7a1e6711f9089c06e6284b3afbbcd259f7791282d660a15"},
|
||||
{file = "numpy-2.0.2-cp311-cp311-win32.whl", hash = "sha256:a392a68bd329eafac5817e5aefeb39038c48b671afd242710b451e76090e81f4"},
|
||||
{file = "numpy-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:286cd40ce2b7d652a6f22efdfc6d1edf879440e53e76a75955bc0c826c7e64dc"},
|
||||
{file = "numpy-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b"},
|
||||
{file = "numpy-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e"},
|
||||
{file = "numpy-2.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c"},
|
||||
{file = "numpy-2.0.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c"},
|
||||
{file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692"},
|
||||
{file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a"},
|
||||
{file = "numpy-2.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c"},
|
||||
{file = "numpy-2.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded"},
|
||||
{file = "numpy-2.0.2-cp312-cp312-win32.whl", hash = "sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5"},
|
||||
{file = "numpy-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a"},
|
||||
{file = "numpy-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9059e10581ce4093f735ed23f3b9d283b9d517ff46009ddd485f1747eb22653c"},
|
||||
{file = "numpy-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:423e89b23490805d2a5a96fe40ec507407b8ee786d66f7328be214f9679df6dd"},
|
||||
{file = "numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:2b2955fa6f11907cf7a70dab0d0755159bca87755e831e47932367fc8f2f2d0b"},
|
||||
{file = "numpy-2.0.2-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:97032a27bd9d8988b9a97a8c4d2c9f2c15a81f61e2f21404d7e8ef00cb5be729"},
|
||||
{file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e795a8be3ddbac43274f18588329c72939870a16cae810c2b73461c40718ab1"},
|
||||
{file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b258c385842546006213344c50655ff1555a9338e2e5e02a0756dc3e803dd"},
|
||||
{file = "numpy-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fec9451a7789926bcf7c2b8d187292c9f93ea30284802a0ab3f5be8ab36865d"},
|
||||
{file = "numpy-2.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9189427407d88ff25ecf8f12469d4d39d35bee1db5d39fc5c168c6f088a6956d"},
|
||||
{file = "numpy-2.0.2-cp39-cp39-win32.whl", hash = "sha256:905d16e0c60200656500c95b6b8dca5d109e23cb24abc701d41c02d74c6b3afa"},
|
||||
{file = "numpy-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:a3f4ab0caa7f053f6797fcd4e1e25caee367db3112ef2b6ef82d749530768c73"},
|
||||
{file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f0a0c6f12e07fa94133c8a67404322845220c06a9e80e85999afe727f7438b8"},
|
||||
{file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:312950fdd060354350ed123c0e25a71327d3711584beaef30cdaa93320c392d4"},
|
||||
{file = "numpy-2.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26df23238872200f63518dd2aa984cfca675d82469535dc7162dc2ee52d9dd5c"},
|
||||
{file = "numpy-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a46288ec55ebbd58947d31d72be2c63cbf839f0a63b49cb755022310792a3385"},
|
||||
{file = "numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "2.1.1"
|
||||
@ -1226,40 +1272,53 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pandas"
|
||||
version = "2.2.2"
|
||||
version = "2.2.3"
|
||||
description = "Powerful data structures for data analysis, time series, and statistics"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "pandas-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99"},
|
||||
{file = "pandas-2.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772"},
|
||||
{file = "pandas-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288"},
|
||||
{file = "pandas-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151"},
|
||||
{file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b"},
|
||||
{file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee"},
|
||||
{file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db"},
|
||||
{file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1"},
|
||||
{file = "pandas-2.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24"},
|
||||
{file = "pandas-2.2.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef"},
|
||||
{file = "pandas-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce"},
|
||||
{file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad"},
|
||||
{file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad"},
|
||||
{file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76"},
|
||||
{file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32"},
|
||||
{file = "pandas-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57"},
|
||||
{file = "pandas-2.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4"},
|
||||
{file = "pandas-2.2.2.tar.gz", hash = "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54"},
|
||||
{file = "pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5"},
|
||||
{file = "pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348"},
|
||||
{file = "pandas-2.2.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed"},
|
||||
{file = "pandas-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57"},
|
||||
{file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42"},
|
||||
{file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f"},
|
||||
{file = "pandas-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645"},
|
||||
{file = "pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039"},
|
||||
{file = "pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd"},
|
||||
{file = "pandas-2.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698"},
|
||||
{file = "pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc"},
|
||||
{file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3"},
|
||||
{file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32"},
|
||||
{file = "pandas-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5"},
|
||||
{file = "pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9"},
|
||||
{file = "pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4"},
|
||||
{file = "pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3"},
|
||||
{file = "pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319"},
|
||||
{file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8"},
|
||||
{file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a"},
|
||||
{file = "pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13"},
|
||||
{file = "pandas-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015"},
|
||||
{file = "pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28"},
|
||||
{file = "pandas-2.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0"},
|
||||
{file = "pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24"},
|
||||
{file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659"},
|
||||
{file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb"},
|
||||
{file = "pandas-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d"},
|
||||
{file = "pandas-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468"},
|
||||
{file = "pandas-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18"},
|
||||
{file = "pandas-2.2.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2"},
|
||||
{file = "pandas-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4"},
|
||||
{file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d"},
|
||||
{file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a"},
|
||||
{file = "pandas-2.2.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39"},
|
||||
{file = "pandas-2.2.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30"},
|
||||
{file = "pandas-2.2.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c"},
|
||||
{file = "pandas-2.2.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c"},
|
||||
{file = "pandas-2.2.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea"},
|
||||
{file = "pandas-2.2.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761"},
|
||||
{file = "pandas-2.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e"},
|
||||
{file = "pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1453,6 +1512,26 @@ docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-a
|
||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"]
|
||||
type = ["mypy (>=1.11.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "playwright"
|
||||
version = "1.47.0"
|
||||
description = "A high-level API to automate web browsers"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "playwright-1.47.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:f205df24edb925db1a4ab62f1ab0da06f14bb69e382efecfb0deedc4c7f4b8cd"},
|
||||
{file = "playwright-1.47.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7fc820faf6885f69a52ba4ec94124e575d3c4a4003bf29200029b4a4f2b2d0ab"},
|
||||
{file = "playwright-1.47.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:8e212dc472ff19c7d46ed7e900191c7a786ce697556ac3f1615986ec3aa00341"},
|
||||
{file = "playwright-1.47.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:a1935672531963e4b2a321de5aa59b982fb92463ee6e1032dd7326378e462955"},
|
||||
{file = "playwright-1.47.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0a1b61473d6f7f39c5d77d4800b3cbefecb03344c90b98f3fbcae63294ad249"},
|
||||
{file = "playwright-1.47.0-py3-none-win32.whl", hash = "sha256:1b977ed81f6bba5582617684a21adab9bad5676d90a357ebf892db7bdf4a9974"},
|
||||
{file = "playwright-1.47.0-py3-none-win_amd64.whl", hash = "sha256:0ec1056042d2e86088795a503347407570bffa32cbe20748e5d4c93dba085280"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
greenlet = "3.0.3"
|
||||
pyee = "12.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "plotly"
|
||||
version = "5.24.1"
|
||||
@ -1676,6 +1755,23 @@ files = [
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
||||
|
||||
[[package]]
|
||||
name = "pyee"
|
||||
version = "12.0.0"
|
||||
description = "A rough port of Node.js's EventEmitter to Python with a few tricks of its own"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pyee-12.0.0-py3-none-any.whl", hash = "sha256:7b14b74320600049ccc7d0e0b1becd3b4bd0a03c745758225e31a59f4095c990"},
|
||||
{file = "pyee-12.0.0.tar.gz", hash = "sha256:c480603f4aa2927d4766eb41fa82793fe60a82cbfdb8d688e0d08c55a534e145"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = "*"
|
||||
|
||||
[package.extras]
|
||||
dev = ["black", "build", "flake8", "flake8-black", "isort", "jupyter-console", "mkdocs", "mkdocs-include-markdown-plugin", "mkdocstrings[python]", "pytest", "pytest-asyncio", "pytest-trio", "sphinx", "toml", "tox", "trio", "trio", "trio-typing", "twine", "twisted", "validate-pyproject[all]"]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.18.0"
|
||||
@ -1771,6 +1867,24 @@ pytest = ">=7.0.0"
|
||||
docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"]
|
||||
testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-base-url"
|
||||
version = "2.1.0"
|
||||
description = "pytest plugin for URL based testing"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pytest_base_url-2.1.0-py3-none-any.whl", hash = "sha256:3ad15611778764d451927b2a53240c1a7a591b521ea44cebfe45849d2d2812e6"},
|
||||
{file = "pytest_base_url-2.1.0.tar.gz", hash = "sha256:02748589a54f9e63fcbe62301d6b0496da0d10231b753e950c63e03aee745d45"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pytest = ">=7.0.0"
|
||||
requests = ">=2.9"
|
||||
|
||||
[package.extras]
|
||||
test = ["black (>=22.1.0)", "flake8 (>=4.0.1)", "pre-commit (>=2.17.0)", "pytest-localserver (>=0.7.1)", "tox (>=3.24.5)"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-benchmark"
|
||||
version = "4.0.0"
|
||||
@ -1826,6 +1940,23 @@ pytest = ">=6.2.5"
|
||||
[package.extras]
|
||||
dev = ["pre-commit", "pytest-asyncio", "tox"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-playwright"
|
||||
version = "0.5.2"
|
||||
description = "A pytest wrapper with fixtures for Playwright to automate web browsers"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pytest_playwright-0.5.2-py3-none-any.whl", hash = "sha256:2c5720591364a1cdf66610b972ff8492512bc380953e043c85f705b78b2ed582"},
|
||||
{file = "pytest_playwright-0.5.2.tar.gz", hash = "sha256:c6d603df9e6c50b35f057b0528e11d41c0963283e98c257267117f5ed6ba1924"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
playwright = ">=1.18"
|
||||
pytest = ">=6.2.4,<9.0.0"
|
||||
pytest-base-url = ">=1.0.0,<3.0.0"
|
||||
python-slugify = ">=6.0.0,<9.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.9.0.post0"
|
||||
@ -1861,17 +1992,31 @@ docs = ["sphinx"]
|
||||
|
||||
[[package]]
|
||||
name = "python-multipart"
|
||||
version = "0.0.9"
|
||||
version = "0.0.10"
|
||||
description = "A streaming multipart parser for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "python_multipart-0.0.9-py3-none-any.whl", hash = "sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215"},
|
||||
{file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"},
|
||||
{file = "python_multipart-0.0.10-py3-none-any.whl", hash = "sha256:2b06ad9e8d50c7a8db80e3b56dab590137b323410605af2be20d62a5f1ba1dc8"},
|
||||
{file = "python_multipart-0.0.10.tar.gz", hash = "sha256:46eb3c6ce6fdda5fb1a03c7e11d490e407c6930a2703fe7aef4da71c374688fa"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-slugify"
|
||||
version = "8.0.4"
|
||||
description = "A Python slugify application that also handles Unicode"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856"},
|
||||
{file = "python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
text-unidecode = ">=1.3"
|
||||
|
||||
[package.extras]
|
||||
dev = ["atomicwrites (==1.4.1)", "attrs (==23.2.0)", "coverage (==7.4.1)", "hatch", "invoke (==2.2.0)", "more-itertools (==10.2.0)", "pbr (==6.0.0)", "pluggy (==1.4.0)", "py (==1.11.0)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.2.0)", "pyyaml (==6.0.1)", "ruff (==0.2.1)"]
|
||||
unidecode = ["Unidecode (>=1.1.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "python-socketio"
|
||||
@ -2016,13 +2161,13 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"
|
||||
|
||||
[[package]]
|
||||
name = "reflex-chakra"
|
||||
version = "0.6.0a7"
|
||||
version = "0.6.0"
|
||||
description = "reflex using chakra components"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.8"
|
||||
files = [
|
||||
{file = "reflex_chakra-0.6.0a7-py3-none-any.whl", hash = "sha256:d693aee7323af13ce491165ffb4fe392344939e45516991671d5601727f749f4"},
|
||||
{file = "reflex_chakra-0.6.0a7.tar.gz", hash = "sha256:fe17282e439fdfdfd507e24857a615258ef9789f15049aa0e70239fbcb4d5fbf"},
|
||||
{file = "reflex_chakra-0.6.0-py3-none-any.whl", hash = "sha256:eca1593fca67289e05591dd21fbcc8632c119d64a08bdc41fd995055a114cc91"},
|
||||
{file = "reflex_chakra-0.6.0.tar.gz", hash = "sha256:db1c7b48f1ba547bf91e5af103fce6fc7191d7225b414ebfbada7d983e33dd87"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -2161,13 +2306,13 @@ jeepney = ">=0.6"
|
||||
|
||||
[[package]]
|
||||
name = "selenium"
|
||||
version = "4.24.0"
|
||||
version = "4.25.0"
|
||||
description = "Official Python bindings for Selenium WebDriver"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "selenium-4.24.0-py3-none-any.whl", hash = "sha256:42c23f60753d5415b261b236cecbd69bd4eb5271e1563915f546b443cb6b71c6"},
|
||||
{file = "selenium-4.24.0.tar.gz", hash = "sha256:88281e5b5b90fe231868905d5ea745b9ee5e30db280b33498cc73fb0fa06d571"},
|
||||
{file = "selenium-4.25.0-py3-none-any.whl", hash = "sha256:3798d2d12b4a570bc5790163ba57fef10b2afee958bf1d80f2a3cf07c4141f33"},
|
||||
{file = "selenium-4.25.0.tar.gz", hash = "sha256:95d08d3b82fb353f3c474895154516604c7f0e6a9a565ae6498ef36c9bac6921"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -2358,17 +2503,18 @@ SQLAlchemy = ">=2.0.14,<2.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "starlette"
|
||||
version = "0.38.5"
|
||||
version = "0.38.6"
|
||||
description = "The little ASGI library that shines."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "starlette-0.38.5-py3-none-any.whl", hash = "sha256:632f420a9d13e3ee2a6f18f437b0a9f1faecb0bc42e1942aa2ea0e379a4c4206"},
|
||||
{file = "starlette-0.38.5.tar.gz", hash = "sha256:04a92830a9b6eb1442c766199d62260c3d4dc9c4f9188360626b1e0273cb7077"},
|
||||
{file = "starlette-0.38.6-py3-none-any.whl", hash = "sha256:4517a1409e2e73ee4951214ba012052b9e16f60e90d73cfb06192c19203bbb05"},
|
||||
{file = "starlette-0.38.6.tar.gz", hash = "sha256:863a1588f5574e70a821dadefb41e4881ea451a47a3cd1b4df359d4ffefe5ead"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
anyio = ">=3.4.0,<5"
|
||||
typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""}
|
||||
|
||||
[package.extras]
|
||||
full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"]
|
||||
@ -2425,6 +2571,17 @@ files = [
|
||||
doc = ["reno", "sphinx"]
|
||||
test = ["pytest", "tornado (>=4.5)", "typeguard"]
|
||||
|
||||
[[package]]
|
||||
name = "text-unidecode"
|
||||
version = "1.3"
|
||||
description = "The most basic Text::Unidecode port"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"},
|
||||
{file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.10.2"
|
||||
@ -2546,13 +2703,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "tzdata"
|
||||
version = "2024.1"
|
||||
version = "2024.2"
|
||||
description = "Provider of IANA time zone data"
|
||||
optional = false
|
||||
python-versions = ">=2"
|
||||
files = [
|
||||
{file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"},
|
||||
{file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"},
|
||||
{file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"},
|
||||
{file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2632,97 +2789,97 @@ test = ["websockets"]
|
||||
|
||||
[[package]]
|
||||
name = "websockets"
|
||||
version = "13.0.1"
|
||||
version = "13.1"
|
||||
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "websockets-13.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1841c9082a3ba4a05ea824cf6d99570a6a2d8849ef0db16e9c826acb28089e8f"},
|
||||
{file = "websockets-13.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c5870b4a11b77e4caa3937142b650fbbc0914a3e07a0cf3131f35c0587489c1c"},
|
||||
{file = "websockets-13.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f1d3d1f2eb79fe7b0fb02e599b2bf76a7619c79300fc55f0b5e2d382881d4f7f"},
|
||||
{file = "websockets-13.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15c7d62ee071fa94a2fc52c2b472fed4af258d43f9030479d9c4a2de885fd543"},
|
||||
{file = "websockets-13.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6724b554b70d6195ba19650fef5759ef11346f946c07dbbe390e039bcaa7cc3d"},
|
||||
{file = "websockets-13.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56a952fa2ae57a42ba7951e6b2605e08a24801a4931b5644dfc68939e041bc7f"},
|
||||
{file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:17118647c0ea14796364299e942c330d72acc4b248e07e639d34b75067b3cdd8"},
|
||||
{file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64a11aae1de4c178fa653b07d90f2fb1a2ed31919a5ea2361a38760192e1858b"},
|
||||
{file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0617fd0b1d14309c7eab6ba5deae8a7179959861846cbc5cb528a7531c249448"},
|
||||
{file = "websockets-13.0.1-cp310-cp310-win32.whl", hash = "sha256:11f9976ecbc530248cf162e359a92f37b7b282de88d1d194f2167b5e7ad80ce3"},
|
||||
{file = "websockets-13.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c3c493d0e5141ec055a7d6809a28ac2b88d5b878bb22df8c621ebe79a61123d0"},
|
||||
{file = "websockets-13.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:699ba9dd6a926f82a277063603fc8d586b89f4cb128efc353b749b641fcddda7"},
|
||||
{file = "websockets-13.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf2fae6d85e5dc384bf846f8243ddaa9197f3a1a70044f59399af001fd1f51d4"},
|
||||
{file = "websockets-13.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:52aed6ef21a0f1a2a5e310fb5c42d7555e9c5855476bbd7173c3aa3d8a0302f2"},
|
||||
{file = "websockets-13.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8eb2b9a318542153674c6e377eb8cb9ca0fc011c04475110d3477862f15d29f0"},
|
||||
{file = "websockets-13.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5df891c86fe68b2c38da55b7aea7095beca105933c697d719f3f45f4220a5e0e"},
|
||||
{file = "websockets-13.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac2d146ff30d9dd2fcf917e5d147db037a5c573f0446c564f16f1f94cf87462"},
|
||||
{file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b8ac5b46fd798bbbf2ac6620e0437c36a202b08e1f827832c4bf050da081b501"},
|
||||
{file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:46af561eba6f9b0848b2c9d2427086cabadf14e0abdd9fde9d72d447df268418"},
|
||||
{file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b5a06d7f60bc2fc378a333978470dfc4e1415ee52f5f0fce4f7853eb10c1e9df"},
|
||||
{file = "websockets-13.0.1-cp311-cp311-win32.whl", hash = "sha256:556e70e4f69be1082e6ef26dcb70efcd08d1850f5d6c5f4f2bcb4e397e68f01f"},
|
||||
{file = "websockets-13.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:67494e95d6565bf395476e9d040037ff69c8b3fa356a886b21d8422ad86ae075"},
|
||||
{file = "websockets-13.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f9c9e258e3d5efe199ec23903f5da0eeaad58cf6fccb3547b74fd4750e5ac47a"},
|
||||
{file = "websockets-13.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6b41a1b3b561f1cba8321fb32987552a024a8f67f0d05f06fcf29f0090a1b956"},
|
||||
{file = "websockets-13.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f73e676a46b0fe9426612ce8caeca54c9073191a77c3e9d5c94697aef99296af"},
|
||||
{file = "websockets-13.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f613289f4a94142f914aafad6c6c87903de78eae1e140fa769a7385fb232fdf"},
|
||||
{file = "websockets-13.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f52504023b1480d458adf496dc1c9e9811df4ba4752f0bc1f89ae92f4f07d0c"},
|
||||
{file = "websockets-13.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:139add0f98206cb74109faf3611b7783ceafc928529c62b389917a037d4cfdf4"},
|
||||
{file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:47236c13be337ef36546004ce8c5580f4b1150d9538b27bf8a5ad8edf23ccfab"},
|
||||
{file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c44ca9ade59b2e376612df34e837013e2b273e6c92d7ed6636d0556b6f4db93d"},
|
||||
{file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9bbc525f4be3e51b89b2a700f5746c2a6907d2e2ef4513a8daafc98198b92237"},
|
||||
{file = "websockets-13.0.1-cp312-cp312-win32.whl", hash = "sha256:3624fd8664f2577cf8de996db3250662e259bfbc870dd8ebdcf5d7c6ac0b5185"},
|
||||
{file = "websockets-13.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0513c727fb8adffa6d9bf4a4463b2bade0186cbd8c3604ae5540fae18a90cb99"},
|
||||
{file = "websockets-13.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1ee4cc030a4bdab482a37462dbf3ffb7e09334d01dd37d1063be1136a0d825fa"},
|
||||
{file = "websockets-13.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dbb0b697cc0655719522406c059eae233abaa3243821cfdfab1215d02ac10231"},
|
||||
{file = "websockets-13.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:acbebec8cb3d4df6e2488fbf34702cbc37fc39ac7abf9449392cefb3305562e9"},
|
||||
{file = "websockets-13.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63848cdb6fcc0bf09d4a155464c46c64ffdb5807ede4fb251da2c2692559ce75"},
|
||||
{file = "websockets-13.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:872afa52a9f4c414d6955c365b6588bc4401272c629ff8321a55f44e3f62b553"},
|
||||
{file = "websockets-13.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05e70fec7c54aad4d71eae8e8cab50525e899791fc389ec6f77b95312e4e9920"},
|
||||
{file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e82db3756ccb66266504f5a3de05ac6b32f287faacff72462612120074103329"},
|
||||
{file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e85f46ce287f5c52438bb3703d86162263afccf034a5ef13dbe4318e98d86e7"},
|
||||
{file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f3fea72e4e6edb983908f0db373ae0732b275628901d909c382aae3b592589f2"},
|
||||
{file = "websockets-13.0.1-cp313-cp313-win32.whl", hash = "sha256:254ecf35572fca01a9f789a1d0f543898e222f7b69ecd7d5381d8d8047627bdb"},
|
||||
{file = "websockets-13.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca48914cdd9f2ccd94deab5bcb5ac98025a5ddce98881e5cce762854a5de330b"},
|
||||
{file = "websockets-13.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b74593e9acf18ea5469c3edaa6b27fa7ecf97b30e9dabd5a94c4c940637ab96e"},
|
||||
{file = "websockets-13.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:132511bfd42e77d152c919147078460c88a795af16b50e42a0bd14f0ad71ddd2"},
|
||||
{file = "websockets-13.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:165bedf13556f985a2aa064309baa01462aa79bf6112fbd068ae38993a0e1f1b"},
|
||||
{file = "websockets-13.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e801ca2f448850685417d723ec70298feff3ce4ff687c6f20922c7474b4746ae"},
|
||||
{file = "websockets-13.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30d3a1f041360f029765d8704eae606781e673e8918e6b2c792e0775de51352f"},
|
||||
{file = "websockets-13.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67648f5e50231b5a7f6d83b32f9c525e319f0ddc841be0de64f24928cd75a603"},
|
||||
{file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:4f0426d51c8f0926a4879390f53c7f5a855e42d68df95fff6032c82c888b5f36"},
|
||||
{file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ef48e4137e8799998a343706531e656fdec6797b80efd029117edacb74b0a10a"},
|
||||
{file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:249aab278810bee585cd0d4de2f08cfd67eed4fc75bde623be163798ed4db2eb"},
|
||||
{file = "websockets-13.0.1-cp38-cp38-win32.whl", hash = "sha256:06c0a667e466fcb56a0886d924b5f29a7f0886199102f0a0e1c60a02a3751cb4"},
|
||||
{file = "websockets-13.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1f3cf6d6ec1142412d4535adabc6bd72a63f5f148c43fe559f06298bc21953c9"},
|
||||
{file = "websockets-13.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1fa082ea38d5de51dd409434edc27c0dcbd5fed2b09b9be982deb6f0508d25bc"},
|
||||
{file = "websockets-13.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4a365bcb7be554e6e1f9f3ed64016e67e2fa03d7b027a33e436aecf194febb63"},
|
||||
{file = "websockets-13.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:10a0dc7242215d794fb1918f69c6bb235f1f627aaf19e77f05336d147fce7c37"},
|
||||
{file = "websockets-13.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59197afd478545b1f73367620407b0083303569c5f2d043afe5363676f2697c9"},
|
||||
{file = "websockets-13.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d20516990d8ad557b5abeb48127b8b779b0b7e6771a265fa3e91767596d7d97"},
|
||||
{file = "websockets-13.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1a2e272d067030048e1fe41aa1ec8cfbbaabce733b3d634304fa2b19e5c897f"},
|
||||
{file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ad327ac80ba7ee61da85383ca8822ff808ab5ada0e4a030d66703cc025b021c4"},
|
||||
{file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:518f90e6dd089d34eaade01101fd8a990921c3ba18ebbe9b0165b46ebff947f0"},
|
||||
{file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:68264802399aed6fe9652e89761031acc734fc4c653137a5911c2bfa995d6d6d"},
|
||||
{file = "websockets-13.0.1-cp39-cp39-win32.whl", hash = "sha256:a5dc0c42ded1557cc7c3f0240b24129aefbad88af4f09346164349391dea8e58"},
|
||||
{file = "websockets-13.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b448a0690ef43db5ef31b3a0d9aea79043882b4632cfc3eaab20105edecf6097"},
|
||||
{file = "websockets-13.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:faef9ec6354fe4f9a2c0bbb52fb1ff852effc897e2a4501e25eb3a47cb0a4f89"},
|
||||
{file = "websockets-13.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:03d3f9ba172e0a53e37fa4e636b86cc60c3ab2cfee4935e66ed1d7acaa4625ad"},
|
||||
{file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d450f5a7a35662a9b91a64aefa852f0c0308ee256122f5218a42f1d13577d71e"},
|
||||
{file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f55b36d17ac50aa8a171b771e15fbe1561217510c8768af3d546f56c7576cdc"},
|
||||
{file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14b9c006cac63772b31abbcd3e3abb6228233eec966bf062e89e7fa7ae0b7333"},
|
||||
{file = "websockets-13.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b79915a1179a91f6c5f04ece1e592e2e8a6bd245a0e45d12fd56b2b59e559a32"},
|
||||
{file = "websockets-13.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f40de079779acbcdbb6ed4c65af9f018f8b77c5ec4e17a4b737c05c2db554491"},
|
||||
{file = "websockets-13.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80e4ba642fc87fa532bac07e5ed7e19d56940b6af6a8c61d4429be48718a380f"},
|
||||
{file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a02b0161c43cc9e0232711eff846569fad6ec836a7acab16b3cf97b2344c060"},
|
||||
{file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6aa74a45d4cdc028561a7d6ab3272c8b3018e23723100b12e58be9dfa5a24491"},
|
||||
{file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00fd961943b6c10ee6f0b1130753e50ac5dcd906130dcd77b0003c3ab797d026"},
|
||||
{file = "websockets-13.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d93572720d781331fb10d3da9ca1067817d84ad1e7c31466e9f5e59965618096"},
|
||||
{file = "websockets-13.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:71e6e5a3a3728886caee9ab8752e8113670936a193284be9d6ad2176a137f376"},
|
||||
{file = "websockets-13.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c4a6343e3b0714e80da0b0893543bf9a5b5fa71b846ae640e56e9abc6fbc4c83"},
|
||||
{file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a678532018e435396e37422a95e3ab87f75028ac79570ad11f5bf23cd2a7d8c"},
|
||||
{file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6716c087e4aa0b9260c4e579bb82e068f84faddb9bfba9906cb87726fa2e870"},
|
||||
{file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e33505534f3f673270dd67f81e73550b11de5b538c56fe04435d63c02c3f26b5"},
|
||||
{file = "websockets-13.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acab3539a027a85d568c2573291e864333ec9d912675107d6efceb7e2be5d980"},
|
||||
{file = "websockets-13.0.1-py3-none-any.whl", hash = "sha256:b80f0c51681c517604152eb6a572f5a9378f877763231fddb883ba2f968e8817"},
|
||||
{file = "websockets-13.0.1.tar.gz", hash = "sha256:4d6ece65099411cfd9a48d13701d7438d9c34f479046b34c50ff60bb8834e43e"},
|
||||
{file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"},
|
||||
{file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"},
|
||||
{file = "websockets-13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6"},
|
||||
{file = "websockets-13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b"},
|
||||
{file = "websockets-13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa"},
|
||||
{file = "websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700"},
|
||||
{file = "websockets-13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c"},
|
||||
{file = "websockets-13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0"},
|
||||
{file = "websockets-13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f"},
|
||||
{file = "websockets-13.1-cp310-cp310-win32.whl", hash = "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe"},
|
||||
{file = "websockets-13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a"},
|
||||
{file = "websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19"},
|
||||
{file = "websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5"},
|
||||
{file = "websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd"},
|
||||
{file = "websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02"},
|
||||
{file = "websockets-13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7"},
|
||||
{file = "websockets-13.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096"},
|
||||
{file = "websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084"},
|
||||
{file = "websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3"},
|
||||
{file = "websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9"},
|
||||
{file = "websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f"},
|
||||
{file = "websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557"},
|
||||
{file = "websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc"},
|
||||
{file = "websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49"},
|
||||
{file = "websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd"},
|
||||
{file = "websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0"},
|
||||
{file = "websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6"},
|
||||
{file = "websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9"},
|
||||
{file = "websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68"},
|
||||
{file = "websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14"},
|
||||
{file = "websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf"},
|
||||
{file = "websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c"},
|
||||
{file = "websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3"},
|
||||
{file = "websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6"},
|
||||
{file = "websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708"},
|
||||
{file = "websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418"},
|
||||
{file = "websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a"},
|
||||
{file = "websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f"},
|
||||
{file = "websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5"},
|
||||
{file = "websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135"},
|
||||
{file = "websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2"},
|
||||
{file = "websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6"},
|
||||
{file = "websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d"},
|
||||
{file = "websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2"},
|
||||
{file = "websockets-13.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c7934fd0e920e70468e676fe7f1b7261c1efa0d6c037c6722278ca0228ad9d0d"},
|
||||
{file = "websockets-13.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:149e622dc48c10ccc3d2760e5f36753db9cacf3ad7bc7bbbfd7d9c819e286f23"},
|
||||
{file = "websockets-13.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a569eb1b05d72f9bce2ebd28a1ce2054311b66677fcd46cf36204ad23acead8c"},
|
||||
{file = "websockets-13.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95df24ca1e1bd93bbca51d94dd049a984609687cb2fb08a7f2c56ac84e9816ea"},
|
||||
{file = "websockets-13.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8dbb1bf0c0a4ae8b40bdc9be7f644e2f3fb4e8a9aca7145bfa510d4a374eeb7"},
|
||||
{file = "websockets-13.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:035233b7531fb92a76beefcbf479504db8c72eb3bff41da55aecce3a0f729e54"},
|
||||
{file = "websockets-13.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e4450fc83a3df53dec45922b576e91e94f5578d06436871dce3a6be38e40f5db"},
|
||||
{file = "websockets-13.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:463e1c6ec853202dd3657f156123d6b4dad0c546ea2e2e38be2b3f7c5b8e7295"},
|
||||
{file = "websockets-13.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6d6855bbe70119872c05107e38fbc7f96b1d8cb047d95c2c50869a46c65a8e96"},
|
||||
{file = "websockets-13.1-cp38-cp38-win32.whl", hash = "sha256:204e5107f43095012b00f1451374693267adbb832d29966a01ecc4ce1db26faf"},
|
||||
{file = "websockets-13.1-cp38-cp38-win_amd64.whl", hash = "sha256:485307243237328c022bc908b90e4457d0daa8b5cf4b3723fd3c4a8012fce4c6"},
|
||||
{file = "websockets-13.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9b37c184f8b976f0c0a231a5f3d6efe10807d41ccbe4488df8c74174805eea7d"},
|
||||
{file = "websockets-13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:163e7277e1a0bd9fb3c8842a71661ad19c6aa7bb3d6678dc7f89b17fbcc4aeb7"},
|
||||
{file = "websockets-13.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b889dbd1342820cc210ba44307cf75ae5f2f96226c0038094455a96e64fb07a"},
|
||||
{file = "websockets-13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:586a356928692c1fed0eca68b4d1c2cbbd1ca2acf2ac7e7ebd3b9052582deefa"},
|
||||
{file = "websockets-13.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7bd6abf1e070a6b72bfeb71049d6ad286852e285f146682bf30d0296f5fbadfa"},
|
||||
{file = "websockets-13.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2aad13a200e5934f5a6767492fb07151e1de1d6079c003ab31e1823733ae79"},
|
||||
{file = "websockets-13.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:df01aea34b6e9e33572c35cd16bae5a47785e7d5c8cb2b54b2acdb9678315a17"},
|
||||
{file = "websockets-13.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e54affdeb21026329fb0744ad187cf812f7d3c2aa702a5edb562b325191fcab6"},
|
||||
{file = "websockets-13.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9ef8aa8bdbac47f4968a5d66462a2a0935d044bf35c0e5a8af152d58516dbeb5"},
|
||||
{file = "websockets-13.1-cp39-cp39-win32.whl", hash = "sha256:deeb929efe52bed518f6eb2ddc00cc496366a14c726005726ad62c2dd9017a3c"},
|
||||
{file = "websockets-13.1-cp39-cp39-win_amd64.whl", hash = "sha256:7c65ffa900e7cc958cd088b9a9157a8141c991f8c53d11087e6fb7277a03f81d"},
|
||||
{file = "websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238"},
|
||||
{file = "websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5"},
|
||||
{file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9"},
|
||||
{file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6"},
|
||||
{file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a"},
|
||||
{file = "websockets-13.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23"},
|
||||
{file = "websockets-13.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9156c45750b37337f7b0b00e6248991a047be4aa44554c9886fe6bdd605aab3b"},
|
||||
{file = "websockets-13.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80c421e07973a89fbdd93e6f2003c17d20b69010458d3a8e37fb47874bd67d51"},
|
||||
{file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82d0ba76371769d6a4e56f7e83bb8e81846d17a6190971e38b5de108bde9b0d7"},
|
||||
{file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9875a0143f07d74dc5e1ded1c4581f0d9f7ab86c78994e2ed9e95050073c94d"},
|
||||
{file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11e38ad8922c7961447f35c7b17bffa15de4d17c70abd07bfbe12d6faa3e027"},
|
||||
{file = "websockets-13.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4059f790b6ae8768471cddb65d3c4fe4792b0ab48e154c9f0a04cefaabcd5978"},
|
||||
{file = "websockets-13.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25c35bf84bf7c7369d247f0b8cfa157f989862c49104c5cf85cb5436a641d93e"},
|
||||
{file = "websockets-13.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:83f91d8a9bb404b8c2c41a707ac7f7f75b9442a0a876df295de27251a856ad09"},
|
||||
{file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a43cfdcddd07f4ca2b1afb459824dd3c6d53a51410636a2c7fc97b9a8cf4842"},
|
||||
{file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a2ef1381632a2f0cb4efeff34efa97901c9fbc118e01951ad7cfc10601a9bb"},
|
||||
{file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459bf774c754c35dbb487360b12c5727adab887f1622b8aed5755880a21c4a20"},
|
||||
{file = "websockets-13.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:95858ca14a9f6fa8413d29e0a585b31b278388aa775b8a81fa24830123874678"},
|
||||
{file = "websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f"},
|
||||
{file = "websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2853,5 +3010,5 @@ type = ["pytest-mypy"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "1c8904971be7061c2b33400d2b5f461e526703586e5b7f9eb08c2fbfda1a23ab"
|
||||
python-versions = "^3.9"
|
||||
content-hash = "adccd071775567aeefe219261aeb9e222906c865745f03edb1e770edc79c44ac"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "reflex"
|
||||
version = "0.6.0a1"
|
||||
version = "0.6.2dev1"
|
||||
description = "Web apps in pure Python."
|
||||
license = "Apache-2.0"
|
||||
authors = [
|
||||
@ -26,7 +26,7 @@ packages = [
|
||||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
python = "^3.9"
|
||||
dill = ">=0.3.8,<0.4"
|
||||
fastapi = ">=0.96.0,!=0.111.0,!=0.111.1"
|
||||
gunicorn = ">=20.1.0,<24.0"
|
||||
@ -59,7 +59,7 @@ httpx = ">=0.25.1,<1.0"
|
||||
twine = ">=4.0.0,<6.0"
|
||||
tomlkit = ">=0.12.4,<1.0"
|
||||
lazy_loader = ">=0.4"
|
||||
reflex-chakra = ">=0.6.0a6"
|
||||
reflex-chakra = ">=0.6.0"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
pytest = ">=7.1.2,<8.0"
|
||||
@ -77,6 +77,8 @@ asynctest = ">=0.13.0,<1.0"
|
||||
pre-commit = ">=3.2.1"
|
||||
selenium = ">=4.11.0,<5.0"
|
||||
pytest-benchmark = ">=4.0.0,<5.0"
|
||||
playwright = ">=1.46.0"
|
||||
pytest-playwright = ">=0.5.1"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
reflex = "reflex.reflex:cli"
|
||||
@ -88,7 +90,7 @@ build-backend = "poetry.core.masonry.api"
|
||||
[tool.pyright]
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py310"
|
||||
target-version = "py39"
|
||||
lint.select = ["B", "D", "E", "F", "I", "SIM", "W"]
|
||||
lint.ignore = ["B008", "D203", "D205", "D213", "D401", "D406", "D407", "E501", "F403", "F405", "F541"]
|
||||
lint.pydocstyle.convention = "google"
|
||||
|
@ -8,7 +8,7 @@ version = "0.0.1"
|
||||
description = "Reflex custom component {{ module_name }}"
|
||||
readme = "README.md"
|
||||
license = { text = "Apache-2.0" }
|
||||
requires-python = ">=3.10"
|
||||
requires-python = ">=3.9"
|
||||
authors = [{ name = "", email = "YOUREMAIL@domain.com" }]
|
||||
keywords = ["reflex","reflex-custom-components"]
|
||||
|
||||
|
@ -832,7 +832,9 @@ export const useEventLoop = (
|
||||
* @returns True if the value is truthy, false otherwise.
|
||||
*/
|
||||
export const isTrue = (val) => {
|
||||
return Array.isArray(val) ? val.length > 0 : !!val;
|
||||
if (Array.isArray(val)) return val.length > 0;
|
||||
if (val === Object(val)) return Object.keys(val).length > 0;
|
||||
return Boolean(val);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -509,9 +509,8 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
"""
|
||||
# If the route is not set, get it from the callable.
|
||||
if route is None:
|
||||
assert isinstance(
|
||||
component, Callable
|
||||
), "Route must be set if component is not a callable."
|
||||
if not isinstance(component, Callable):
|
||||
raise ValueError("Route must be set if component is not a callable.")
|
||||
# Format the route.
|
||||
route = format.format_route(component.__name__)
|
||||
else:
|
||||
@ -615,10 +614,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
for route in self.pages:
|
||||
replaced_route = replace_brackets_with_keywords(route)
|
||||
for rw, r, nr in zip(
|
||||
replaced_route.split("/"),
|
||||
route.split("/"),
|
||||
new_route.split("/"),
|
||||
strict=False,
|
||||
replaced_route.split("/"), route.split("/"), new_route.split("/")
|
||||
):
|
||||
if rw in segments and r != nr:
|
||||
# If the slugs in the segments of both routes are not the same, then the route is invalid
|
||||
@ -1203,7 +1199,6 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
FRONTEND_ARG_SPEC,
|
||||
BACKEND_ARG_SPEC,
|
||||
],
|
||||
strict=False,
|
||||
):
|
||||
if hasattr(handler_fn, "__name__"):
|
||||
_fn_name = handler_fn.__name__
|
||||
@ -1563,6 +1558,9 @@ class EventNamespace(AsyncNamespace):
|
||||
async def on_event(self, sid, data):
|
||||
"""Event for receiving front-end websocket events.
|
||||
|
||||
Raises:
|
||||
RuntimeError: If the Socket.IO is badly initialized.
|
||||
|
||||
Args:
|
||||
sid: The Socket.IO session id.
|
||||
data: The event data.
|
||||
@ -1575,9 +1573,11 @@ class EventNamespace(AsyncNamespace):
|
||||
self.sid_to_token[sid] = event.token
|
||||
|
||||
# Get the event environment.
|
||||
assert self.app.sio is not None
|
||||
if self.app.sio is None:
|
||||
raise RuntimeError("Socket.IO is not initialized.")
|
||||
environ = self.app.sio.get_environ(sid, self.namespace)
|
||||
assert environ is not None
|
||||
if environ is None:
|
||||
raise RuntimeError("Socket.IO environ is not initialized.")
|
||||
|
||||
# Get the client headers.
|
||||
headers = {
|
||||
|
@ -6,11 +6,13 @@ import asyncio
|
||||
import contextlib
|
||||
import functools
|
||||
import inspect
|
||||
import sys
|
||||
from typing import Callable, Coroutine, Set, Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
from reflex.utils import console
|
||||
from reflex.utils.exceptions import InvalidLifespanTaskType
|
||||
|
||||
from .mixin import AppMixin
|
||||
|
||||
|
||||
@ -26,6 +28,7 @@ class LifespanMixin(AppMixin):
|
||||
try:
|
||||
async with contextlib.AsyncExitStack() as stack:
|
||||
for task in self.lifespan_tasks:
|
||||
run_msg = f"Started lifespan task: {task.__name__} as {{type}}" # type: ignore
|
||||
if isinstance(task, asyncio.Task):
|
||||
running_tasks.append(task)
|
||||
else:
|
||||
@ -35,15 +38,19 @@ class LifespanMixin(AppMixin):
|
||||
_t = task()
|
||||
if isinstance(_t, contextlib._AsyncGeneratorContextManager):
|
||||
await stack.enter_async_context(_t)
|
||||
console.debug(run_msg.format(type="asynccontextmanager"))
|
||||
elif isinstance(_t, Coroutine):
|
||||
running_tasks.append(asyncio.create_task(_t))
|
||||
task_ = asyncio.create_task(_t)
|
||||
task_.add_done_callback(lambda t: t.result())
|
||||
running_tasks.append(task_)
|
||||
console.debug(run_msg.format(type="coroutine"))
|
||||
else:
|
||||
console.debug(run_msg.format(type="function"))
|
||||
yield
|
||||
finally:
|
||||
cancel_kwargs = (
|
||||
{"msg": "lifespan_cleanup"} if sys.version_info >= (3, 9) else {}
|
||||
)
|
||||
for task in running_tasks:
|
||||
task.cancel(**cancel_kwargs)
|
||||
console.debug(f"Canceling lifespan task: {task}")
|
||||
task.cancel(msg="lifespan_cleanup")
|
||||
|
||||
def register_lifespan_task(self, task: Callable | asyncio.Task, **task_kwargs):
|
||||
"""Register a task to run during the lifespan of the app.
|
||||
@ -51,7 +58,18 @@ class LifespanMixin(AppMixin):
|
||||
Args:
|
||||
task: The task to register.
|
||||
task_kwargs: The kwargs of the task.
|
||||
|
||||
Raises:
|
||||
InvalidLifespanTaskType: If the task is a generator function.
|
||||
"""
|
||||
if inspect.isgeneratorfunction(task) or inspect.isasyncgenfunction(task):
|
||||
raise InvalidLifespanTaskType(
|
||||
f"Task {task.__name__} of type generator must be decorated with contextlib.asynccontextmanager."
|
||||
)
|
||||
|
||||
if task_kwargs:
|
||||
original_task = task
|
||||
task = functools.partial(task, **task_kwargs) # type: ignore
|
||||
functools.update_wrapper(task, original_task) # type: ignore
|
||||
self.lifespan_tasks.add(task) # type: ignore
|
||||
console.debug(f"Registered lifespan task: {task.__name__}") # type: ignore
|
||||
|
@ -15,7 +15,7 @@ if constants.CompileVars.APP != "app":
|
||||
telemetry.send("compile")
|
||||
app_module = get_app(reload=False)
|
||||
app = getattr(app_module, constants.CompileVars.APP)
|
||||
# For py3.8 and py3.9 compatibility when redis is used, we MUST add any decorator pages
|
||||
# For py3.9 compatibility when redis is used, we MUST add any decorator pages
|
||||
# before compiling the app in a thread to avoid event loop error (REF-2172).
|
||||
app._apply_decorated_pages()
|
||||
compile_future = ThreadPoolExecutor(max_workers=1).submit(app._compile)
|
||||
|
@ -44,6 +44,9 @@ def compile_import_statement(fields: list[ImportVar]) -> tuple[str, list[str]]:
|
||||
Args:
|
||||
fields: The set of fields to import from the library.
|
||||
|
||||
Raises:
|
||||
ValueError: If there is more than one default import.
|
||||
|
||||
Returns:
|
||||
The libraries for default and rest.
|
||||
default: default library. When install "import def from library".
|
||||
@ -54,7 +57,8 @@ def compile_import_statement(fields: list[ImportVar]) -> tuple[str, list[str]]:
|
||||
|
||||
# Check for default imports.
|
||||
defaults = {field for field in fields_set if field.is_default}
|
||||
assert len(defaults) < 2
|
||||
if len(defaults) >= 2:
|
||||
raise ValueError("Only one default import is allowed.")
|
||||
|
||||
# Get the default import, and the specific imports.
|
||||
default = next(iter({field.name for field in defaults}), "")
|
||||
@ -92,6 +96,9 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]:
|
||||
Args:
|
||||
import_dict: The import dict to compile.
|
||||
|
||||
Raises:
|
||||
ValueError: If an import in the dict is invalid.
|
||||
|
||||
Returns:
|
||||
The list of import dict.
|
||||
"""
|
||||
@ -106,8 +113,10 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]:
|
||||
continue
|
||||
|
||||
if not lib:
|
||||
assert not default, "No default field allowed for empty library."
|
||||
assert rest is not None and len(rest) > 0, "No fields to import."
|
||||
if default:
|
||||
raise ValueError("No default field allowed for empty library.")
|
||||
if rest is None or len(rest) == 0:
|
||||
raise ValueError("No fields to import.")
|
||||
for module in sorted(rest):
|
||||
import_dicts.append(get_import_dict(module))
|
||||
continue
|
||||
@ -155,7 +164,7 @@ def compile_state(state: Type[BaseState]) -> dict:
|
||||
initial_state = state(_reflex_internal_init=True).dict(
|
||||
initial=True, include_computed=False
|
||||
)
|
||||
return format.format_state(initial_state)
|
||||
return initial_state
|
||||
|
||||
|
||||
def _compile_client_storage_field(
|
||||
@ -429,11 +438,11 @@ def add_meta(
|
||||
Returns:
|
||||
The component with the metadata added.
|
||||
"""
|
||||
meta_tags = [Meta.create(**item) for item in meta]
|
||||
|
||||
children: list[Any] = [
|
||||
Title.create(title),
|
||||
meta_tags = [
|
||||
item if isinstance(item, Component) else Meta.create(**item) for item in meta
|
||||
]
|
||||
|
||||
children: list[Any] = [Title.create(title)]
|
||||
if description:
|
||||
children.append(Description.create(content=description))
|
||||
children.append(Image.create(content=image))
|
||||
|
@ -7,7 +7,7 @@ from typing import Any, Iterator
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.tags import Tag
|
||||
from reflex.components.tags.tagless import Tagless
|
||||
from reflex.vars.base import Var
|
||||
from reflex.vars import ArrayVar, BooleanVar, ObjectVar, Var
|
||||
|
||||
|
||||
class Bare(Component):
|
||||
@ -33,6 +33,8 @@ class Bare(Component):
|
||||
|
||||
def _render(self) -> Tag:
|
||||
if isinstance(self.contents, Var):
|
||||
if isinstance(self.contents, (BooleanVar, ObjectVar, ArrayVar)):
|
||||
return Tagless(contents=f"{{{str(self.contents.to_string())}}}")
|
||||
return Tagless(contents=f"{{{str(self.contents)}}}")
|
||||
return Tagless(contents=str(self.contents))
|
||||
|
||||
|
@ -16,13 +16,15 @@ class Title(Component):
|
||||
def render(self) -> dict:
|
||||
"""Render the title component.
|
||||
|
||||
Raises:
|
||||
ValueError: If the title is not a single string.
|
||||
|
||||
Returns:
|
||||
The rendered title component.
|
||||
"""
|
||||
# Make sure the title is a single string.
|
||||
assert len(self.children) == 1 and isinstance(
|
||||
self.children[0], Bare
|
||||
), "Title must be a single string."
|
||||
if len(self.children) != 1 or not isinstance(self.children[0], Bare):
|
||||
raise ValueError("Title must be a single string.")
|
||||
return super().render()
|
||||
|
||||
|
||||
|
@ -55,6 +55,7 @@ from reflex.utils.imports import (
|
||||
)
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import LiteralVar, Var
|
||||
from reflex.vars.sequence import LiteralArrayVar
|
||||
|
||||
|
||||
class BaseComponent(Base, ABC):
|
||||
@ -448,8 +449,16 @@ class Component(BaseComponent, ABC):
|
||||
and not types._issubclass(passed_type, expected_type, value)
|
||||
):
|
||||
value_name = value._js_expr if isinstance(value, Var) else value
|
||||
|
||||
additional_info = (
|
||||
" You can call `.bool()` on the value to convert it to a boolean."
|
||||
if expected_type is bool and isinstance(value, Var)
|
||||
else ""
|
||||
)
|
||||
|
||||
raise TypeError(
|
||||
f"Invalid var passed for prop {type(self).__name__}.{key}, expected type {expected_type}, got value {value_name} of type {passed_type}."
|
||||
+ additional_info
|
||||
)
|
||||
# Check if the key is an event trigger.
|
||||
if key in component_specific_triggers:
|
||||
@ -469,7 +478,7 @@ class Component(BaseComponent, ABC):
|
||||
# Merge styles, the later ones overriding keys in the earlier ones.
|
||||
style = {k: v for style_dict in style for k, v in style_dict.items()}
|
||||
|
||||
if isinstance(style, Breakpoints):
|
||||
if isinstance(style, (Breakpoints, Var)):
|
||||
style = {
|
||||
# Assign the Breakpoints to the self-referential selector to avoid squashing down to a regular dict.
|
||||
"&": style,
|
||||
@ -488,6 +497,11 @@ class Component(BaseComponent, ABC):
|
||||
# Convert class_name to str if it's list
|
||||
class_name = kwargs.get("class_name", "")
|
||||
if isinstance(class_name, (List, tuple)):
|
||||
if any(isinstance(c, Var) for c in class_name):
|
||||
kwargs["class_name"] = LiteralArrayVar.create(
|
||||
class_name, _var_type=List[str]
|
||||
).join(" ")
|
||||
else:
|
||||
kwargs["class_name"] = " ".join(class_name)
|
||||
|
||||
# Construct the component.
|
||||
@ -1730,10 +1744,14 @@ class CustomComponent(Component):
|
||||
Args:
|
||||
seen: The tags of the components that have already been seen.
|
||||
|
||||
Raises:
|
||||
ValueError: If the tag is not set.
|
||||
|
||||
Returns:
|
||||
The set of custom components.
|
||||
"""
|
||||
assert self.tag is not None, "The tag must be set."
|
||||
if self.tag is None:
|
||||
raise ValueError("The tag must be set.")
|
||||
|
||||
# Store the seen components in a set to avoid infinite recursion.
|
||||
if seen is None:
|
||||
|
@ -82,9 +82,7 @@ class Breakpoints(Dict[K, V]):
|
||||
return Breakpoints(
|
||||
{
|
||||
k: v
|
||||
for k, v in zip(
|
||||
["initial", *breakpoint_names], thresholds, strict=False
|
||||
)
|
||||
for k, v in zip(["initial", *breakpoint_names], thresholds)
|
||||
if v is not None
|
||||
}
|
||||
)
|
||||
|
@ -138,13 +138,13 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var:
|
||||
"""
|
||||
# Convert the condition to a Var.
|
||||
cond_var = LiteralVar.create(condition)
|
||||
assert cond_var is not None, "The condition must be set."
|
||||
if cond_var is None:
|
||||
raise ValueError("The condition must be set.")
|
||||
|
||||
# If the first component is a component, create a Cond component.
|
||||
if isinstance(c1, BaseComponent):
|
||||
assert c2 is None or isinstance(
|
||||
c2, BaseComponent
|
||||
), "Both arguments must be components."
|
||||
if c2 is not None and not isinstance(c2, BaseComponent):
|
||||
raise ValueError("Both arguments must be components.")
|
||||
return Cond.create(cond_var, c1, c2)
|
||||
|
||||
# Otherwise, create a conditional Var.
|
||||
|
@ -8,7 +8,6 @@ _SUBMOD_ATTRS: dict[str, list[str]] = {
|
||||
"code": [
|
||||
"CodeBlock",
|
||||
"code_block",
|
||||
"LiteralCodeBlockTheme",
|
||||
"LiteralCodeLanguage",
|
||||
],
|
||||
"dataeditor": ["data_editor", "data_editor_theme", "DataEditorTheme"],
|
||||
|
@ -4,7 +4,6 @@
|
||||
# ------------------------------------------------------
|
||||
|
||||
from .code import CodeBlock as CodeBlock
|
||||
from .code import LiteralCodeBlockTheme as LiteralCodeBlockTheme
|
||||
from .code import LiteralCodeLanguage as LiteralCodeLanguage
|
||||
from .code import code_block as code_block
|
||||
from .dataeditor import DataEditorTheme as DataEditorTheme
|
||||
|
@ -2,10 +2,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import enum
|
||||
from typing import Any, Dict, Literal, Optional, Union
|
||||
|
||||
from typing_extensions import get_args
|
||||
import dataclasses
|
||||
from typing import ClassVar, Dict, Literal, Optional, Union
|
||||
|
||||
from reflex.components.component import Component, ComponentNamespace
|
||||
from reflex.components.core.cond import color_mode_cond
|
||||
@ -19,55 +17,6 @@ from reflex.utils import console, format
|
||||
from reflex.utils.imports import ImportDict, ImportVar
|
||||
from reflex.vars.base import LiteralVar, Var, VarData
|
||||
|
||||
LiteralCodeBlockTheme = Literal[
|
||||
"a11y-dark",
|
||||
"atom-dark",
|
||||
"cb",
|
||||
"coldark-cold",
|
||||
"coldark-dark",
|
||||
"coy",
|
||||
"coy-without-shadows",
|
||||
"darcula",
|
||||
"dark",
|
||||
"dracula",
|
||||
"duotone-dark",
|
||||
"duotone-earth",
|
||||
"duotone-forest",
|
||||
"duotone-light",
|
||||
"duotone-sea",
|
||||
"duotone-space",
|
||||
"funky",
|
||||
"ghcolors",
|
||||
"gruvbox-dark",
|
||||
"gruvbox-light",
|
||||
"holi-theme",
|
||||
"hopscotch",
|
||||
"light", # not present in react-syntax-highlighter styles
|
||||
"lucario",
|
||||
"material-dark",
|
||||
"material-light",
|
||||
"material-oceanic",
|
||||
"night-owl",
|
||||
"nord",
|
||||
"okaidia",
|
||||
"one-dark",
|
||||
"one-light",
|
||||
"pojoaque",
|
||||
"prism",
|
||||
"shades-of-purple",
|
||||
"solarized-dark-atom",
|
||||
"solarizedlight",
|
||||
"synthwave84",
|
||||
"tomorrow",
|
||||
"twilight",
|
||||
"vs",
|
||||
"vs-dark",
|
||||
"vsc-dark-plus",
|
||||
"xonokai",
|
||||
"z-touch",
|
||||
]
|
||||
|
||||
|
||||
LiteralCodeLanguage = Literal[
|
||||
"abap",
|
||||
"abnf",
|
||||
@ -351,18 +300,82 @@ LiteralCodeLanguage = Literal[
|
||||
]
|
||||
|
||||
|
||||
def replace_quotes_with_camel_case(value: str) -> str:
|
||||
"""Replaces quotes in the given string with camel case format.
|
||||
def construct_theme_var(theme: str) -> Var[Theme]:
|
||||
"""Construct a theme var.
|
||||
|
||||
Args:
|
||||
value (str): The string to be processed.
|
||||
theme: The theme to construct.
|
||||
|
||||
Returns:
|
||||
str: The processed string with quotes replaced by camel case.
|
||||
The constructed theme var.
|
||||
"""
|
||||
for theme in get_args(LiteralCodeBlockTheme):
|
||||
value = value.replace(f'"{theme}"', format.to_camel_case(theme))
|
||||
return value
|
||||
return Var(
|
||||
theme,
|
||||
_var_data=VarData(
|
||||
imports={
|
||||
f"react-syntax-highlighter/dist/cjs/styles/prism/{format.to_kebab_case(theme)}": [
|
||||
ImportVar(tag=theme, is_default=True, install=False)
|
||||
]
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@dataclasses.dataclass(init=False)
|
||||
class Theme:
|
||||
"""Themes for the CodeBlock component."""
|
||||
|
||||
a11y_dark: ClassVar[Var[Theme]] = construct_theme_var("a11yDark")
|
||||
atom_dark: ClassVar[Var[Theme]] = construct_theme_var("atomDark")
|
||||
cb: ClassVar[Var[Theme]] = construct_theme_var("cb")
|
||||
coldark_cold: ClassVar[Var[Theme]] = construct_theme_var("coldarkCold")
|
||||
coldark_dark: ClassVar[Var[Theme]] = construct_theme_var("coldarkDark")
|
||||
coy: ClassVar[Var[Theme]] = construct_theme_var("coy")
|
||||
coy_without_shadows: ClassVar[Var[Theme]] = construct_theme_var("coyWithoutShadows")
|
||||
darcula: ClassVar[Var[Theme]] = construct_theme_var("darcula")
|
||||
dark: ClassVar[Var[Theme]] = construct_theme_var("oneDark")
|
||||
dracula: ClassVar[Var[Theme]] = construct_theme_var("dracula")
|
||||
duotone_dark: ClassVar[Var[Theme]] = construct_theme_var("duotoneDark")
|
||||
duotone_earth: ClassVar[Var[Theme]] = construct_theme_var("duotoneEarth")
|
||||
duotone_forest: ClassVar[Var[Theme]] = construct_theme_var("duotoneForest")
|
||||
duotone_light: ClassVar[Var[Theme]] = construct_theme_var("duotoneLight")
|
||||
duotone_sea: ClassVar[Var[Theme]] = construct_theme_var("duotoneSea")
|
||||
duotone_space: ClassVar[Var[Theme]] = construct_theme_var("duotoneSpace")
|
||||
funky: ClassVar[Var[Theme]] = construct_theme_var("funky")
|
||||
ghcolors: ClassVar[Var[Theme]] = construct_theme_var("ghcolors")
|
||||
gruvbox_dark: ClassVar[Var[Theme]] = construct_theme_var("gruvboxDark")
|
||||
gruvbox_light: ClassVar[Var[Theme]] = construct_theme_var("gruvboxLight")
|
||||
holi_theme: ClassVar[Var[Theme]] = construct_theme_var("holiTheme")
|
||||
hopscotch: ClassVar[Var[Theme]] = construct_theme_var("hopscotch")
|
||||
light: ClassVar[Var[Theme]] = construct_theme_var("oneLight")
|
||||
lucario: ClassVar[Var[Theme]] = construct_theme_var("lucario")
|
||||
material_dark: ClassVar[Var[Theme]] = construct_theme_var("materialDark")
|
||||
material_light: ClassVar[Var[Theme]] = construct_theme_var("materialLight")
|
||||
material_oceanic: ClassVar[Var[Theme]] = construct_theme_var("materialOceanic")
|
||||
night_owl: ClassVar[Var[Theme]] = construct_theme_var("nightOwl")
|
||||
nord: ClassVar[Var[Theme]] = construct_theme_var("nord")
|
||||
okaidia: ClassVar[Var[Theme]] = construct_theme_var("okaidia")
|
||||
one_dark: ClassVar[Var[Theme]] = construct_theme_var("oneDark")
|
||||
one_light: ClassVar[Var[Theme]] = construct_theme_var("oneLight")
|
||||
pojoaque: ClassVar[Var[Theme]] = construct_theme_var("pojoaque")
|
||||
prism: ClassVar[Var[Theme]] = construct_theme_var("prism")
|
||||
shades_of_purple: ClassVar[Var[Theme]] = construct_theme_var("shadesOfPurple")
|
||||
solarized_dark_atom: ClassVar[Var[Theme]] = construct_theme_var("solarizedDarkAtom")
|
||||
solarizedlight: ClassVar[Var[Theme]] = construct_theme_var("solarizedlight")
|
||||
synthwave84: ClassVar[Var[Theme]] = construct_theme_var("synthwave84")
|
||||
tomorrow: ClassVar[Var[Theme]] = construct_theme_var("tomorrow")
|
||||
twilight: ClassVar[Var[Theme]] = construct_theme_var("twilight")
|
||||
vs: ClassVar[Var[Theme]] = construct_theme_var("vs")
|
||||
vs_dark: ClassVar[Var[Theme]] = construct_theme_var("vsDark")
|
||||
vsc_dark_plus: ClassVar[Var[Theme]] = construct_theme_var("vscDarkPlus")
|
||||
xonokai: ClassVar[Var[Theme]] = construct_theme_var("xonokai")
|
||||
z_touch: ClassVar[Var[Theme]] = construct_theme_var("zTouch")
|
||||
|
||||
|
||||
for theme_name in dir(Theme):
|
||||
if theme_name.startswith("_"):
|
||||
continue
|
||||
setattr(Theme, theme_name, getattr(Theme, theme_name)._replace(_var_type=Theme))
|
||||
|
||||
|
||||
class CodeBlock(Component):
|
||||
@ -375,7 +388,7 @@ class CodeBlock(Component):
|
||||
alias = "SyntaxHighlighter"
|
||||
|
||||
# The theme to use ("light" or "dark").
|
||||
theme: Var[Any] = "one-light" # type: ignore
|
||||
theme: Var[Union[Theme, str]] = Theme.one_light
|
||||
|
||||
# The language to use.
|
||||
language: Var[LiteralCodeLanguage] = "python" # type: ignore
|
||||
@ -523,91 +536,6 @@ class CodeBlock(Component):
|
||||
|
||||
return out
|
||||
|
||||
@staticmethod
|
||||
def convert_theme_name(theme) -> str:
|
||||
"""Convert theme names to appropriate names.
|
||||
|
||||
Args:
|
||||
theme: The theme name.
|
||||
|
||||
Returns:
|
||||
The right theme name.
|
||||
"""
|
||||
if theme in ["light", "dark"]:
|
||||
return f"one-{theme}"
|
||||
return theme
|
||||
|
||||
|
||||
def construct_theme_var(theme: str) -> Var:
|
||||
"""Construct a theme var.
|
||||
|
||||
Args:
|
||||
theme: The theme to construct.
|
||||
|
||||
Returns:
|
||||
The constructed theme var.
|
||||
"""
|
||||
return Var(
|
||||
theme,
|
||||
_var_data=VarData(
|
||||
imports={
|
||||
f"react-syntax-highlighter/dist/cjs/styles/prism/{format.to_kebab_case(theme)}": [
|
||||
ImportVar(tag=theme, is_default=True, install=False)
|
||||
]
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class Theme(enum.Enum):
|
||||
"""Themes for the CodeBlock component."""
|
||||
|
||||
a11y_dark = construct_theme_var("a11yDark")
|
||||
atom_dark = construct_theme_var("atomDark")
|
||||
cb = construct_theme_var("cb")
|
||||
coldark_cold = construct_theme_var("coldarkCold")
|
||||
coldark_dark = construct_theme_var("coldarkDark")
|
||||
coy = construct_theme_var("coy")
|
||||
coy_without_shadows = construct_theme_var("coyWithoutShadows")
|
||||
darcula = construct_theme_var("darcula")
|
||||
dark = construct_theme_var("oneDark")
|
||||
dracula = construct_theme_var("dracula")
|
||||
duotone_dark = construct_theme_var("duotoneDark")
|
||||
duotone_earth = construct_theme_var("duotoneEarth")
|
||||
duotone_forest = construct_theme_var("duotoneForest")
|
||||
duotone_light = construct_theme_var("duotoneLight")
|
||||
duotone_sea = construct_theme_var("duotoneSea")
|
||||
duotone_space = construct_theme_var("duotoneSpace")
|
||||
funky = construct_theme_var("funky")
|
||||
ghcolors = construct_theme_var("ghcolors")
|
||||
gruvbox_dark = construct_theme_var("gruvboxDark")
|
||||
gruvbox_light = construct_theme_var("gruvboxLight")
|
||||
holi_theme = construct_theme_var("holiTheme")
|
||||
hopscotch = construct_theme_var("hopscotch")
|
||||
light = construct_theme_var("oneLight")
|
||||
lucario = construct_theme_var("lucario")
|
||||
material_dark = construct_theme_var("materialDark")
|
||||
material_light = construct_theme_var("materialLight")
|
||||
material_oceanic = construct_theme_var("materialOceanic")
|
||||
night_owl = construct_theme_var("nightOwl")
|
||||
nord = construct_theme_var("nord")
|
||||
okaidia = construct_theme_var("okaidia")
|
||||
one_dark = construct_theme_var("oneDark")
|
||||
one_light = construct_theme_var("oneLight")
|
||||
pojoaque = construct_theme_var("pojoaque")
|
||||
prism = construct_theme_var("prism")
|
||||
shades_of_purple = construct_theme_var("shadesOfPurple")
|
||||
solarized_dark_atom = construct_theme_var("solarizedDarkAtom")
|
||||
solarizedlight = construct_theme_var("solarizedlight")
|
||||
synthwave84 = construct_theme_var("synthwave84")
|
||||
tomorrow = construct_theme_var("tomorrow")
|
||||
twilight = construct_theme_var("twilight")
|
||||
vs = construct_theme_var("vs")
|
||||
vs_dark = construct_theme_var("vsDark")
|
||||
vsc_dark_plus = construct_theme_var("vscDarkPlus")
|
||||
xonokai = construct_theme_var("xonokai")
|
||||
z_touch = construct_theme_var("zTouch")
|
||||
|
||||
|
||||
class CodeblockNamespace(ComponentNamespace):
|
||||
"""Namespace for the CodeBlock component."""
|
||||
|
@ -3,8 +3,8 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
import enum
|
||||
from typing import Any, Callable, Dict, Literal, Optional, Union, overload
|
||||
import dataclasses
|
||||
from typing import Any, Callable, ClassVar, Dict, Literal, Optional, Union, overload
|
||||
|
||||
from reflex.components.component import Component, ComponentNamespace
|
||||
from reflex.constants.colors import Color
|
||||
@ -13,53 +13,6 @@ from reflex.style import Style
|
||||
from reflex.utils.imports import ImportDict
|
||||
from reflex.vars.base import Var
|
||||
|
||||
LiteralCodeBlockTheme = Literal[
|
||||
"a11y-dark",
|
||||
"atom-dark",
|
||||
"cb",
|
||||
"coldark-cold",
|
||||
"coldark-dark",
|
||||
"coy",
|
||||
"coy-without-shadows",
|
||||
"darcula",
|
||||
"dark",
|
||||
"dracula",
|
||||
"duotone-dark",
|
||||
"duotone-earth",
|
||||
"duotone-forest",
|
||||
"duotone-light",
|
||||
"duotone-sea",
|
||||
"duotone-space",
|
||||
"funky",
|
||||
"ghcolors",
|
||||
"gruvbox-dark",
|
||||
"gruvbox-light",
|
||||
"holi-theme",
|
||||
"hopscotch",
|
||||
"light",
|
||||
"lucario",
|
||||
"material-dark",
|
||||
"material-light",
|
||||
"material-oceanic",
|
||||
"night-owl",
|
||||
"nord",
|
||||
"okaidia",
|
||||
"one-dark",
|
||||
"one-light",
|
||||
"pojoaque",
|
||||
"prism",
|
||||
"shades-of-purple",
|
||||
"solarized-dark-atom",
|
||||
"solarizedlight",
|
||||
"synthwave84",
|
||||
"tomorrow",
|
||||
"twilight",
|
||||
"vs",
|
||||
"vs-dark",
|
||||
"vsc-dark-plus",
|
||||
"xonokai",
|
||||
"z-touch",
|
||||
]
|
||||
LiteralCodeLanguage = Literal[
|
||||
"abap",
|
||||
"abnf",
|
||||
@ -342,7 +295,59 @@ LiteralCodeLanguage = Literal[
|
||||
"zig",
|
||||
]
|
||||
|
||||
def replace_quotes_with_camel_case(value: str) -> str: ...
|
||||
def construct_theme_var(theme: str) -> Var[Theme]: ...
|
||||
@dataclasses.dataclass(init=False)
|
||||
class Theme:
|
||||
a11y_dark: ClassVar[Var[Theme]] = construct_theme_var("a11yDark")
|
||||
atom_dark: ClassVar[Var[Theme]] = construct_theme_var("atomDark")
|
||||
cb: ClassVar[Var[Theme]] = construct_theme_var("cb")
|
||||
coldark_cold: ClassVar[Var[Theme]] = construct_theme_var("coldarkCold")
|
||||
coldark_dark: ClassVar[Var[Theme]] = construct_theme_var("coldarkDark")
|
||||
coy: ClassVar[Var[Theme]] = construct_theme_var("coy")
|
||||
coy_without_shadows: ClassVar[Var[Theme]] = construct_theme_var("coyWithoutShadows")
|
||||
darcula: ClassVar[Var[Theme]] = construct_theme_var("darcula")
|
||||
dark: ClassVar[Var[Theme]] = construct_theme_var("oneDark")
|
||||
dracula: ClassVar[Var[Theme]] = construct_theme_var("dracula")
|
||||
duotone_dark: ClassVar[Var[Theme]] = construct_theme_var("duotoneDark")
|
||||
duotone_earth: ClassVar[Var[Theme]] = construct_theme_var("duotoneEarth")
|
||||
duotone_forest: ClassVar[Var[Theme]] = construct_theme_var("duotoneForest")
|
||||
duotone_light: ClassVar[Var[Theme]] = construct_theme_var("duotoneLight")
|
||||
duotone_sea: ClassVar[Var[Theme]] = construct_theme_var("duotoneSea")
|
||||
duotone_space: ClassVar[Var[Theme]] = construct_theme_var("duotoneSpace")
|
||||
funky: ClassVar[Var[Theme]] = construct_theme_var("funky")
|
||||
ghcolors: ClassVar[Var[Theme]] = construct_theme_var("ghcolors")
|
||||
gruvbox_dark: ClassVar[Var[Theme]] = construct_theme_var("gruvboxDark")
|
||||
gruvbox_light: ClassVar[Var[Theme]] = construct_theme_var("gruvboxLight")
|
||||
holi_theme: ClassVar[Var[Theme]] = construct_theme_var("holiTheme")
|
||||
hopscotch: ClassVar[Var[Theme]] = construct_theme_var("hopscotch")
|
||||
light: ClassVar[Var[Theme]] = construct_theme_var("oneLight")
|
||||
lucario: ClassVar[Var[Theme]] = construct_theme_var("lucario")
|
||||
material_dark: ClassVar[Var[Theme]] = construct_theme_var("materialDark")
|
||||
material_light: ClassVar[Var[Theme]] = construct_theme_var("materialLight")
|
||||
material_oceanic: ClassVar[Var[Theme]] = construct_theme_var("materialOceanic")
|
||||
night_owl: ClassVar[Var[Theme]] = construct_theme_var("nightOwl")
|
||||
nord: ClassVar[Var[Theme]] = construct_theme_var("nord")
|
||||
okaidia: ClassVar[Var[Theme]] = construct_theme_var("okaidia")
|
||||
one_dark: ClassVar[Var[Theme]] = construct_theme_var("oneDark")
|
||||
one_light: ClassVar[Var[Theme]] = construct_theme_var("oneLight")
|
||||
pojoaque: ClassVar[Var[Theme]] = construct_theme_var("pojoaque")
|
||||
prism: ClassVar[Var[Theme]] = construct_theme_var("prism")
|
||||
shades_of_purple: ClassVar[Var[Theme]] = construct_theme_var("shadesOfPurple")
|
||||
solarized_dark_atom: ClassVar[Var[Theme]] = construct_theme_var("solarizedDarkAtom")
|
||||
solarizedlight: ClassVar[Var[Theme]] = construct_theme_var("solarizedlight")
|
||||
synthwave84: ClassVar[Var[Theme]] = construct_theme_var("synthwave84")
|
||||
tomorrow: ClassVar[Var[Theme]] = construct_theme_var("tomorrow")
|
||||
twilight: ClassVar[Var[Theme]] = construct_theme_var("twilight")
|
||||
vs: ClassVar[Var[Theme]] = construct_theme_var("vs")
|
||||
vs_dark: ClassVar[Var[Theme]] = construct_theme_var("vsDark")
|
||||
vsc_dark_plus: ClassVar[Var[Theme]] = construct_theme_var("vscDarkPlus")
|
||||
xonokai: ClassVar[Var[Theme]] = construct_theme_var("xonokai")
|
||||
z_touch: ClassVar[Var[Theme]] = construct_theme_var("zTouch")
|
||||
|
||||
for theme_name in dir(Theme):
|
||||
if theme_name.startswith("_"):
|
||||
continue
|
||||
setattr(Theme, theme_name, getattr(Theme, theme_name)._replace(_var_type=Theme))
|
||||
|
||||
class CodeBlock(Component):
|
||||
def add_imports(self) -> ImportDict: ...
|
||||
@ -353,7 +358,7 @@ class CodeBlock(Component):
|
||||
*children,
|
||||
can_copy: Optional[bool] = False,
|
||||
copy_button: Optional[Union[Component, bool]] = None,
|
||||
theme: Optional[Union[Any, Var[Any]]] = None,
|
||||
theme: Optional[Union[Theme, Var[Union[Theme, str]], str]] = None,
|
||||
language: Optional[
|
||||
Union[
|
||||
Literal[
|
||||
@ -999,57 +1004,6 @@ class CodeBlock(Component):
|
||||
...
|
||||
|
||||
def add_style(self): ...
|
||||
@staticmethod
|
||||
def convert_theme_name(theme) -> str: ...
|
||||
|
||||
def construct_theme_var(theme: str) -> Var: ...
|
||||
|
||||
class Theme(enum.Enum):
|
||||
a11y_dark = construct_theme_var("a11yDark")
|
||||
atom_dark = construct_theme_var("atomDark")
|
||||
cb = construct_theme_var("cb")
|
||||
coldark_cold = construct_theme_var("coldarkCold")
|
||||
coldark_dark = construct_theme_var("coldarkDark")
|
||||
coy = construct_theme_var("coy")
|
||||
coy_without_shadows = construct_theme_var("coyWithoutShadows")
|
||||
darcula = construct_theme_var("darcula")
|
||||
dark = construct_theme_var("oneDark")
|
||||
dracula = construct_theme_var("dracula")
|
||||
duotone_dark = construct_theme_var("duotoneDark")
|
||||
duotone_earth = construct_theme_var("duotoneEarth")
|
||||
duotone_forest = construct_theme_var("duotoneForest")
|
||||
duotone_light = construct_theme_var("duotoneLight")
|
||||
duotone_sea = construct_theme_var("duotoneSea")
|
||||
duotone_space = construct_theme_var("duotoneSpace")
|
||||
funky = construct_theme_var("funky")
|
||||
ghcolors = construct_theme_var("ghcolors")
|
||||
gruvbox_dark = construct_theme_var("gruvboxDark")
|
||||
gruvbox_light = construct_theme_var("gruvboxLight")
|
||||
holi_theme = construct_theme_var("holiTheme")
|
||||
hopscotch = construct_theme_var("hopscotch")
|
||||
light = construct_theme_var("oneLight")
|
||||
lucario = construct_theme_var("lucario")
|
||||
material_dark = construct_theme_var("materialDark")
|
||||
material_light = construct_theme_var("materialLight")
|
||||
material_oceanic = construct_theme_var("materialOceanic")
|
||||
night_owl = construct_theme_var("nightOwl")
|
||||
nord = construct_theme_var("nord")
|
||||
okaidia = construct_theme_var("okaidia")
|
||||
one_dark = construct_theme_var("oneDark")
|
||||
one_light = construct_theme_var("oneLight")
|
||||
pojoaque = construct_theme_var("pojoaque")
|
||||
prism = construct_theme_var("prism")
|
||||
shades_of_purple = construct_theme_var("shadesOfPurple")
|
||||
solarized_dark_atom = construct_theme_var("solarizedDarkAtom")
|
||||
solarizedlight = construct_theme_var("solarizedlight")
|
||||
synthwave84 = construct_theme_var("synthwave84")
|
||||
tomorrow = construct_theme_var("tomorrow")
|
||||
twilight = construct_theme_var("twilight")
|
||||
vs = construct_theme_var("vs")
|
||||
vs_dark = construct_theme_var("vsDark")
|
||||
vsc_dark_plus = construct_theme_var("vscDarkPlus")
|
||||
xonokai = construct_theme_var("xonokai")
|
||||
z_touch = construct_theme_var("zTouch")
|
||||
|
||||
class CodeblockNamespace(ComponentNamespace):
|
||||
themes = Theme
|
||||
@ -1059,7 +1013,7 @@ class CodeblockNamespace(ComponentNamespace):
|
||||
*children,
|
||||
can_copy: Optional[bool] = False,
|
||||
copy_button: Optional[Union[Component, bool]] = None,
|
||||
theme: Optional[Union[Any, Var[Any]]] = None,
|
||||
theme: Optional[Union[Theme, Var[Union[Theme, str]], str]] = None,
|
||||
language: Optional[
|
||||
Union[
|
||||
Literal[
|
||||
|
@ -12,31 +12,33 @@ def logo(**props):
|
||||
Returns:
|
||||
The logo component.
|
||||
"""
|
||||
light_mode_logo = """<svg width="56" height="12" viewBox="0 0 56 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 11.6V0.400024H8.96V4.88002H6.72V2.64002H2.24V4.88002H6.72V7.12002H2.24V11.6H0ZM6.72 11.6V7.12002H8.96V11.6H6.72Z" fill="#110F1F"/>
|
||||
<path d="M11.2 11.6V0.400024H17.92V2.64002H13.44V4.88002H17.92V7.12002H13.44V9.36002H17.92V11.6H11.2Z" fill="#110F1F"/>
|
||||
<path d="M20.16 11.6V0.400024H26.88V2.64002H22.4V4.88002H26.88V7.12002H22.4V11.6H20.16Z" fill="#110F1F"/>
|
||||
<path d="M29.12 11.6V0.400024H31.36V9.36002H35.84V11.6H29.12Z" fill="#110F1F"/>
|
||||
<path d="M38.08 11.6V0.400024H44.8V2.64002H40.32V4.88002H44.8V7.12002H40.32V9.36002H44.8V11.6H38.08Z" fill="#110F1F"/>
|
||||
<path d="M47.04 4.88002V0.400024H49.28V4.88002H47.04ZM53.76 4.88002V0.400024H56V4.88002H53.76ZM49.28 7.12002V4.88002H53.76V7.12002H49.28ZM47.04 11.6V7.12002H49.28V11.6H47.04ZM53.76 11.6V7.12002H56V11.6H53.76Z" fill="#110F1F"/>
|
||||
</svg>"""
|
||||
|
||||
dark_mode_logo = """<svg width="56" height="12" viewBox="0 0 56 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 11.5999V0.399902H8.96V4.8799H6.72V2.6399H2.24V4.8799H6.72V7.1199H2.24V11.5999H0ZM6.72 11.5999V7.1199H8.96V11.5999H6.72Z" fill="white"/>
|
||||
<path d="M11.2 11.5999V0.399902H17.92V2.6399H13.44V4.8799H17.92V7.1199H13.44V9.3599H17.92V11.5999H11.2Z" fill="white"/>
|
||||
<path d="M20.16 11.5999V0.399902H26.88V2.6399H22.4V4.8799H26.88V7.1199H22.4V11.5999H20.16Z" fill="white"/>
|
||||
<path d="M29.12 11.5999V0.399902H31.36V9.3599H35.84V11.5999H29.12Z" fill="white"/>
|
||||
<path d="M38.08 11.5999V0.399902H44.8V2.6399H40.32V4.8799H44.8V7.1199H40.32V9.3599H44.8V11.5999H38.08Z" fill="white"/>
|
||||
<path d="M47.04 4.8799V0.399902H49.28V4.8799H47.04ZM53.76 4.8799V0.399902H56V4.8799H53.76ZM49.28 7.1199V4.8799H53.76V7.1199H49.28ZM47.04 11.5999V7.1199H49.28V11.5999H47.04ZM53.76 11.5999V7.1199H56V11.5999H53.76Z" fill="white"/>
|
||||
</svg>"""
|
||||
def logo_path(d):
|
||||
return rx.el.svg.path(
|
||||
d=d,
|
||||
fill=rx.color_mode_cond("#110F1F", "white"),
|
||||
)
|
||||
|
||||
paths = [
|
||||
"M0 11.5999V0.399902H8.96V4.8799H6.72V2.6399H2.24V4.8799H6.72V7.1199H2.24V11.5999H0ZM6.72 11.5999V7.1199H8.96V11.5999H6.72Z",
|
||||
"M11.2 11.5999V0.399902H17.92V2.6399H13.44V4.8799H17.92V7.1199H13.44V9.3599H17.92V11.5999H11.2Z",
|
||||
"M20.16 11.5999V0.399902H26.88V2.6399H22.4V4.8799H26.88V7.1199H22.4V11.5999H20.16Z",
|
||||
"M29.12 11.5999V0.399902H31.36V9.3599H35.84V11.5999H29.12Z",
|
||||
"M38.08 11.5999V0.399902H44.8V2.6399H40.32V4.8799H44.8V7.1199H40.32V9.3599H44.8V11.5999H38.08Z",
|
||||
"M47.04 4.8799V0.399902H49.28V4.8799H47.04ZM53.76 4.8799V0.399902H56V4.8799H53.76ZM49.28 7.1199V4.8799H53.76V7.1199H49.28ZM47.04 11.5999V7.1199H49.28V11.5999H47.04ZM53.76 11.5999V7.1199H56V11.5999H53.76Z",
|
||||
]
|
||||
|
||||
return rx.center(
|
||||
rx.link(
|
||||
rx.hstack(
|
||||
"Built with ",
|
||||
rx.color_mode_cond(
|
||||
rx.html(light_mode_logo),
|
||||
rx.html(dark_mode_logo),
|
||||
rx.el.svg(
|
||||
*[logo_path(d) for d in paths],
|
||||
width="56",
|
||||
height="12",
|
||||
viewBox="0 0 56 12",
|
||||
fill="none",
|
||||
xmlns="http://www.w3.org/2000/svg",
|
||||
),
|
||||
text_align="center",
|
||||
align="center",
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
from reflex import constants
|
||||
from reflex.utils import imports
|
||||
from reflex.utils.format import format_library_name
|
||||
from reflex.utils.serializers import serializer
|
||||
from reflex.vars import Var, get_unique_variable_name
|
||||
from reflex.vars.base import VarData, transform
|
||||
@ -57,12 +58,21 @@ def load_dynamic_serializer():
|
||||
)
|
||||
] = None
|
||||
|
||||
libs_in_window = [
|
||||
"react",
|
||||
"@radix-ui/themes",
|
||||
]
|
||||
|
||||
imports = {}
|
||||
for lib, names in component._get_all_imports().items():
|
||||
formatted_lib_name = format_library_name(lib)
|
||||
if (
|
||||
not lib.startswith((".", "/"))
|
||||
and not lib.startswith("http")
|
||||
and lib != "react"
|
||||
and all(
|
||||
formatted_lib_name != lib_in_window
|
||||
for lib_in_window in libs_in_window
|
||||
)
|
||||
):
|
||||
imports[get_cdn_url(lib)] = names
|
||||
else:
|
||||
@ -83,10 +93,16 @@ def load_dynamic_serializer():
|
||||
)
|
||||
+ "]"
|
||||
)
|
||||
elif 'from "react"' in line:
|
||||
module_code_lines[ix] = line.replace(
|
||||
"import ", "const ", 1
|
||||
).replace(' from "react"', " = window.__reflex.react", 1)
|
||||
else:
|
||||
for lib in libs_in_window:
|
||||
if f'from "{lib}"' in line:
|
||||
module_code_lines[ix] = (
|
||||
line.replace("import ", "const ", 1)
|
||||
.replace(
|
||||
f' from "{lib}"', f" = window.__reflex['{lib}']", 1
|
||||
)
|
||||
.replace(" as ", ": ")
|
||||
)
|
||||
if line.startswith("export function"):
|
||||
module_code_lines[ix] = line.replace(
|
||||
"export function", "export default function", 1
|
||||
|
@ -10,7 +10,7 @@ from jinja2 import Environment
|
||||
from reflex.components.el.element import Element
|
||||
from reflex.components.tags.tag import Tag
|
||||
from reflex.constants import Dirs, EventTriggers
|
||||
from reflex.event import EventChain, EventHandler
|
||||
from reflex.event import EventChain, EventHandler, prevent_default
|
||||
from reflex.utils.imports import ImportDict
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import LiteralVar, Var
|
||||
@ -148,6 +148,9 @@ class Form(BaseHTML):
|
||||
Returns:
|
||||
The form component.
|
||||
"""
|
||||
if "on_submit" not in props:
|
||||
props["on_submit"] = prevent_default
|
||||
|
||||
if "handle_submit_unique_name" in props:
|
||||
return super().create(*children, **props)
|
||||
|
||||
|
@ -317,6 +317,42 @@ class Svg(BaseHTML):
|
||||
xmlns: Var[str]
|
||||
|
||||
|
||||
class Text(BaseHTML):
|
||||
"""The SVG text component."""
|
||||
|
||||
tag = "text"
|
||||
# The x coordinate of the starting point of the text baseline.
|
||||
x: Var[Union[str, int]]
|
||||
# The y coordinate of the starting point of the text baseline.
|
||||
y: Var[Union[str, int]]
|
||||
# Shifts the text position horizontally from a previous text element.
|
||||
dx: Var[Union[str, int]]
|
||||
# Shifts the text position vertically from a previous text element.
|
||||
dy: Var[Union[str, int]]
|
||||
# Rotates orientation of each individual glyph.
|
||||
rotate: Var[Union[str, int]]
|
||||
# How the text is stretched or compressed to fit the width defined by the text_length attribute.
|
||||
length_adjust: Var[str]
|
||||
# A width that the text should be scaled to fit.
|
||||
text_length: Var[Union[str, int]]
|
||||
|
||||
|
||||
class Line(BaseHTML):
|
||||
"""The SVG line component."""
|
||||
|
||||
tag = "line"
|
||||
# The x-axis coordinate of the line starting point.
|
||||
x1: Var[Union[str, int]]
|
||||
# The x-axis coordinate of the the line ending point.
|
||||
x2: Var[Union[str, int]]
|
||||
# The y-axis coordinate of the line starting point.
|
||||
y1: Var[Union[str, int]]
|
||||
# The y-axis coordinate of the the line ending point.
|
||||
y2: Var[Union[str, int]]
|
||||
# The total path length, in user units.
|
||||
path_length: Var[int]
|
||||
|
||||
|
||||
class Circle(BaseHTML):
|
||||
"""The SVG circle component."""
|
||||
|
||||
@ -331,6 +367,22 @@ class Circle(BaseHTML):
|
||||
path_length: Var[int]
|
||||
|
||||
|
||||
class Ellipse(BaseHTML):
|
||||
"""The SVG ellipse component."""
|
||||
|
||||
tag = "ellipse"
|
||||
# The x position of the center of the ellipse.
|
||||
cx: Var[Union[str, int]]
|
||||
# The y position of the center of the ellipse.
|
||||
cy: Var[Union[str, int]]
|
||||
# The radius of the ellipse on the x axis.
|
||||
rx: Var[Union[str, int]]
|
||||
# The radius of the ellipse on the y axis.
|
||||
ry: Var[Union[str, int]]
|
||||
# The total length for the ellipse's circumference, in user units.
|
||||
path_length: Var[int]
|
||||
|
||||
|
||||
class Rect(BaseHTML):
|
||||
"""The SVG rect component."""
|
||||
|
||||
@ -394,6 +446,39 @@ class LinearGradient(BaseHTML):
|
||||
y2: Var[Union[str, int, bool]]
|
||||
|
||||
|
||||
class RadialGradient(BaseHTML):
|
||||
"""Display the radialGradient element."""
|
||||
|
||||
tag = "radialGradient"
|
||||
|
||||
# The x coordinate of the end circle of the radial gradient.
|
||||
cx: Var[Union[str, int, bool]]
|
||||
|
||||
# The y coordinate of the end circle of the radial gradient.
|
||||
cy: Var[Union[str, int, bool]]
|
||||
|
||||
# The radius of the start circle of the radial gradient.
|
||||
fr: Var[Union[str, int, bool]]
|
||||
|
||||
# The x coordinate of the start circle of the radial gradient.
|
||||
fx: Var[Union[str, int, bool]]
|
||||
|
||||
# The y coordinate of the start circle of the radial gradient.
|
||||
fy: Var[Union[str, int, bool]]
|
||||
|
||||
# Units for the gradient.
|
||||
gradient_units: Var[Union[str, bool]]
|
||||
|
||||
# Transform applied to the gradient.
|
||||
gradient_transform: Var[Union[str, bool]]
|
||||
|
||||
# The radius of the end circle of the radial gradient.
|
||||
r: Var[Union[str, int, bool]]
|
||||
|
||||
# Method used to spread the gradient.
|
||||
spread_method: Var[Union[str, bool]]
|
||||
|
||||
|
||||
class Stop(BaseHTML):
|
||||
"""Display the stop element."""
|
||||
|
||||
@ -421,12 +506,16 @@ class Path(BaseHTML):
|
||||
class SVG(ComponentNamespace):
|
||||
"""SVG component namespace."""
|
||||
|
||||
text = staticmethod(Text.create)
|
||||
line = staticmethod(Line.create)
|
||||
circle = staticmethod(Circle.create)
|
||||
ellipse = staticmethod(Ellipse.create)
|
||||
rect = staticmethod(Rect.create)
|
||||
polygon = staticmethod(Polygon.create)
|
||||
path = staticmethod(Path.create)
|
||||
stop = staticmethod(Stop.create)
|
||||
linear_gradient = staticmethod(LinearGradient.create)
|
||||
radial_gradient = staticmethod(RadialGradient.create)
|
||||
defs = staticmethod(Defs.create)
|
||||
__call__ = staticmethod(Svg.create)
|
||||
|
||||
|
@ -1550,6 +1550,242 @@ class Svg(BaseHTML):
|
||||
"""
|
||||
...
|
||||
|
||||
class Text(BaseHTML):
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
x: Optional[Union[Var[Union[int, str]], int, str]] = None,
|
||||
y: Optional[Union[Var[Union[int, str]], int, str]] = None,
|
||||
dx: Optional[Union[Var[Union[int, str]], int, str]] = None,
|
||||
dy: Optional[Union[Var[Union[int, str]], int, str]] = None,
|
||||
rotate: Optional[Union[Var[Union[int, str]], int, str]] = None,
|
||||
length_adjust: Optional[Union[Var[str], str]] = None,
|
||||
text_length: Optional[Union[Var[Union[int, str]], int, str]] = None,
|
||||
access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
auto_capitalize: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
content_editable: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
context_menu: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
dir: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
draggable: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
enter_key_hint: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
hidden: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
input_mode: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
item_prop: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
lang: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
role: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
slot: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
spell_check: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
tab_index: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
title: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
style: Optional[Style] = None,
|
||||
key: Optional[Any] = None,
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
||||
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
**props,
|
||||
) -> "Text":
|
||||
"""Create the component.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
x: The x coordinate of the starting point of the text baseline.
|
||||
y: The y coordinate of the starting point of the text baseline.
|
||||
dx: Shifts the text position horizontally from a previous text element.
|
||||
dy: Shifts the text position vertically from a previous text element.
|
||||
rotate: Rotates orientation of each individual glyph.
|
||||
length_adjust: How the text is stretched or compressed to fit the width defined by the text_length attribute.
|
||||
text_length: A width that the text should be scaled to fit.
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
||||
dir: Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left)
|
||||
draggable: Defines whether the element can be dragged.
|
||||
enter_key_hint: Hints what media types the media element is able to play.
|
||||
hidden: Defines whether the element is hidden.
|
||||
input_mode: Defines the type of the element.
|
||||
item_prop: Defines the name of the element for metadata purposes.
|
||||
lang: Defines the language used in the element.
|
||||
role: Defines the role of the element.
|
||||
slot: Assigns a slot in a shadow DOM shadow tree to an element.
|
||||
spell_check: Defines whether the element may be checked for spelling errors.
|
||||
tab_index: Defines the position of the current element in the tabbing order.
|
||||
title: Defines a tooltip for the element.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
class_name: The class name for the component.
|
||||
autofocus: Whether the component should take the focus once the page is loaded
|
||||
custom_attrs: custom attribute
|
||||
**props: The props of the component.
|
||||
|
||||
Returns:
|
||||
The component.
|
||||
"""
|
||||
...
|
||||
|
||||
class Line(BaseHTML):
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
x1: Optional[Union[Var[Union[int, str]], int, str]] = None,
|
||||
x2: Optional[Union[Var[Union[int, str]], int, str]] = None,
|
||||
y1: Optional[Union[Var[Union[int, str]], int, str]] = None,
|
||||
y2: Optional[Union[Var[Union[int, str]], int, str]] = None,
|
||||
path_length: Optional[Union[Var[int], int]] = None,
|
||||
access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
auto_capitalize: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
content_editable: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
context_menu: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
dir: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
draggable: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
enter_key_hint: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
hidden: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
input_mode: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
item_prop: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
lang: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
role: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
slot: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
spell_check: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
tab_index: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
title: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
style: Optional[Style] = None,
|
||||
key: Optional[Any] = None,
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
||||
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
**props,
|
||||
) -> "Line":
|
||||
"""Create the component.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
x1: The x-axis coordinate of the line starting point.
|
||||
x2: The x-axis coordinate of the the line ending point.
|
||||
y1: The y-axis coordinate of the line starting point.
|
||||
y2: The y-axis coordinate of the the line ending point.
|
||||
path_length: The total path length, in user units.
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
||||
dir: Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left)
|
||||
draggable: Defines whether the element can be dragged.
|
||||
enter_key_hint: Hints what media types the media element is able to play.
|
||||
hidden: Defines whether the element is hidden.
|
||||
input_mode: Defines the type of the element.
|
||||
item_prop: Defines the name of the element for metadata purposes.
|
||||
lang: Defines the language used in the element.
|
||||
role: Defines the role of the element.
|
||||
slot: Assigns a slot in a shadow DOM shadow tree to an element.
|
||||
spell_check: Defines whether the element may be checked for spelling errors.
|
||||
tab_index: Defines the position of the current element in the tabbing order.
|
||||
title: Defines a tooltip for the element.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
class_name: The class name for the component.
|
||||
autofocus: Whether the component should take the focus once the page is loaded
|
||||
custom_attrs: custom attribute
|
||||
**props: The props of the component.
|
||||
|
||||
Returns:
|
||||
The component.
|
||||
"""
|
||||
...
|
||||
|
||||
class Circle(BaseHTML):
|
||||
@overload
|
||||
@classmethod
|
||||
@ -1664,6 +1900,122 @@ class Circle(BaseHTML):
|
||||
"""
|
||||
...
|
||||
|
||||
class Ellipse(BaseHTML):
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
cx: Optional[Union[Var[Union[int, str]], int, str]] = None,
|
||||
cy: Optional[Union[Var[Union[int, str]], int, str]] = None,
|
||||
rx: Optional[Union[Var[Union[int, str]], int, str]] = None,
|
||||
ry: Optional[Union[Var[Union[int, str]], int, str]] = None,
|
||||
path_length: Optional[Union[Var[int], int]] = None,
|
||||
access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
auto_capitalize: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
content_editable: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
context_menu: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
dir: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
draggable: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
enter_key_hint: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
hidden: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
input_mode: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
item_prop: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
lang: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
role: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
slot: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
spell_check: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
tab_index: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
title: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
style: Optional[Style] = None,
|
||||
key: Optional[Any] = None,
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
||||
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
**props,
|
||||
) -> "Ellipse":
|
||||
"""Create the component.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
cx: The x position of the center of the ellipse.
|
||||
cy: The y position of the center of the ellipse.
|
||||
rx: The radius of the ellipse on the x axis.
|
||||
ry: The radius of the ellipse on the y axis.
|
||||
path_length: The total length for the ellipse's circumference, in user units.
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
||||
dir: Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left)
|
||||
draggable: Defines whether the element can be dragged.
|
||||
enter_key_hint: Hints what media types the media element is able to play.
|
||||
hidden: Defines whether the element is hidden.
|
||||
input_mode: Defines the type of the element.
|
||||
item_prop: Defines the name of the element for metadata purposes.
|
||||
lang: Defines the language used in the element.
|
||||
role: Defines the role of the element.
|
||||
slot: Assigns a slot in a shadow DOM shadow tree to an element.
|
||||
spell_check: Defines whether the element may be checked for spelling errors.
|
||||
tab_index: Defines the position of the current element in the tabbing order.
|
||||
title: Defines a tooltip for the element.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
class_name: The class name for the component.
|
||||
autofocus: Whether the component should take the focus once the page is loaded
|
||||
custom_attrs: custom attribute
|
||||
**props: The props of the component.
|
||||
|
||||
Returns:
|
||||
The component.
|
||||
"""
|
||||
...
|
||||
|
||||
class Rect(BaseHTML):
|
||||
@overload
|
||||
@classmethod
|
||||
@ -2120,6 +2472,130 @@ class LinearGradient(BaseHTML):
|
||||
"""
|
||||
...
|
||||
|
||||
class RadialGradient(BaseHTML):
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
cx: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
cy: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
fr: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
fx: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
fy: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
gradient_units: Optional[Union[Var[Union[bool, str]], bool, str]] = None,
|
||||
gradient_transform: Optional[Union[Var[Union[bool, str]], bool, str]] = None,
|
||||
r: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
spread_method: Optional[Union[Var[Union[bool, str]], bool, str]] = None,
|
||||
access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
auto_capitalize: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
content_editable: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
context_menu: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
dir: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
draggable: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
enter_key_hint: Optional[
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
hidden: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
input_mode: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
item_prop: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
lang: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
role: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
slot: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
spell_check: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
tab_index: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
title: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
style: Optional[Style] = None,
|
||||
key: Optional[Any] = None,
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
||||
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, Var]
|
||||
] = None,
|
||||
**props,
|
||||
) -> "RadialGradient":
|
||||
"""Create the component.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
cx: The x coordinate of the end circle of the radial gradient.
|
||||
cy: The y coordinate of the end circle of the radial gradient.
|
||||
fr: The radius of the start circle of the radial gradient.
|
||||
fx: The x coordinate of the start circle of the radial gradient.
|
||||
fy: The y coordinate of the start circle of the radial gradient.
|
||||
gradient_units: Units for the gradient.
|
||||
gradient_transform: Transform applied to the gradient.
|
||||
r: The radius of the end circle of the radial gradient.
|
||||
spread_method: Method used to spread the gradient.
|
||||
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
||||
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
||||
content_editable: Indicates whether the element's content is editable.
|
||||
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
||||
dir: Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left)
|
||||
draggable: Defines whether the element can be dragged.
|
||||
enter_key_hint: Hints what media types the media element is able to play.
|
||||
hidden: Defines whether the element is hidden.
|
||||
input_mode: Defines the type of the element.
|
||||
item_prop: Defines the name of the element for metadata purposes.
|
||||
lang: Defines the language used in the element.
|
||||
role: Defines the role of the element.
|
||||
slot: Assigns a slot in a shadow DOM shadow tree to an element.
|
||||
spell_check: Defines whether the element may be checked for spelling errors.
|
||||
tab_index: Defines the position of the current element in the tabbing order.
|
||||
title: Defines a tooltip for the element.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
class_name: The class name for the component.
|
||||
autofocus: Whether the component should take the focus once the page is loaded
|
||||
custom_attrs: custom attribute
|
||||
**props: The props of the component.
|
||||
|
||||
Returns:
|
||||
The component.
|
||||
"""
|
||||
...
|
||||
|
||||
class Stop(BaseHTML):
|
||||
@overload
|
||||
@classmethod
|
||||
@ -2345,12 +2821,16 @@ class Path(BaseHTML):
|
||||
...
|
||||
|
||||
class SVG(ComponentNamespace):
|
||||
text = staticmethod(Text.create)
|
||||
line = staticmethod(Line.create)
|
||||
circle = staticmethod(Circle.create)
|
||||
ellipse = staticmethod(Ellipse.create)
|
||||
rect = staticmethod(Rect.create)
|
||||
polygon = staticmethod(Polygon.create)
|
||||
path = staticmethod(Path.create)
|
||||
stop = staticmethod(Stop.create)
|
||||
linear_gradient = staticmethod(LinearGradient.create)
|
||||
radial_gradient = staticmethod(RadialGradient.create)
|
||||
defs = staticmethod(Defs.create)
|
||||
|
||||
@staticmethod
|
||||
|
@ -124,7 +124,8 @@ class DataTable(Gridjs):
|
||||
if types.is_dataframe(type(self.data)):
|
||||
# If given a pandas df break up the data and columns
|
||||
data = serialize(self.data)
|
||||
assert isinstance(data, dict), "Serialized dataframe should be a dict."
|
||||
if not isinstance(data, dict):
|
||||
raise ValueError("Serialized dataframe should be a dict.")
|
||||
self.columns = LiteralVar.create(data["columns"])
|
||||
self.data = LiteralVar.create(data["data"])
|
||||
|
||||
|
@ -95,12 +95,16 @@ class Markdown(Component):
|
||||
*children: The children of the component.
|
||||
**props: The properties of the component.
|
||||
|
||||
Raises:
|
||||
ValueError: If the children are not valid.
|
||||
|
||||
Returns:
|
||||
The markdown component.
|
||||
"""
|
||||
assert (
|
||||
len(children) == 1 and types._isinstance(children[0], Union[str, Var])
|
||||
), "Markdown component must have exactly one child containing the markdown source."
|
||||
if len(children) != 1 or not types._isinstance(children[0], Union[str, Var]):
|
||||
raise ValueError(
|
||||
"Markdown component must have exactly one child containing the markdown source."
|
||||
)
|
||||
|
||||
# Update the base component map with the custom component map.
|
||||
component_map = {**get_base_component_map(), **props.pop("component_map", {})}
|
||||
@ -147,7 +151,7 @@ class Markdown(Component):
|
||||
Returns:
|
||||
The imports for the markdown component.
|
||||
"""
|
||||
from reflex.components.datadisplay.code import CodeBlock
|
||||
from reflex.components.datadisplay.code import CodeBlock, Theme
|
||||
from reflex.components.radix.themes.typography.code import Code
|
||||
|
||||
return [
|
||||
@ -173,8 +177,8 @@ class Markdown(Component):
|
||||
component(_MOCK_ARG)._get_all_imports() # type: ignore
|
||||
for component in self.component_map.values()
|
||||
],
|
||||
CodeBlock.create(theme="light")._get_imports(), # type: ignore,
|
||||
Code.create()._get_imports(), # type: ignore,
|
||||
CodeBlock.create(theme=Theme.light)._get_imports(),
|
||||
Code.create()._get_imports(),
|
||||
]
|
||||
|
||||
def get_component(self, tag: str, **props) -> Component:
|
||||
|
@ -93,6 +93,9 @@ class Markdown(Component):
|
||||
custom_attrs: custom attribute
|
||||
**props: The properties of the component.
|
||||
|
||||
Raises:
|
||||
ValueError: If the children are not valid.
|
||||
|
||||
Returns:
|
||||
The markdown component.
|
||||
"""
|
||||
|
@ -33,7 +33,7 @@ class Stack(Flex):
|
||||
"""
|
||||
# Apply the default classname
|
||||
given_class_name = props.pop("class_name", [])
|
||||
if isinstance(given_class_name, str):
|
||||
if not isinstance(given_class_name, list):
|
||||
given_class_name = [given_class_name]
|
||||
props["class_name"] = ["rx-Stack", *given_class_name]
|
||||
|
||||
|
@ -17,7 +17,7 @@ from reflex.event import (
|
||||
from reflex.style import Style, resolved_color_mode
|
||||
from reflex.utils import format
|
||||
from reflex.utils.imports import ImportVar
|
||||
from reflex.utils.serializers import serialize, serializer
|
||||
from reflex.utils.serializers import serializer
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import LiteralVar, Var
|
||||
|
||||
@ -281,8 +281,8 @@ class Toaster(Component):
|
||||
if message == "" and ("title" not in props or "description" not in props):
|
||||
raise ValueError("Toast message or title or description must be provided.")
|
||||
if props:
|
||||
args = serialize(ToastProps(**props)) # type: ignore
|
||||
toast = f"{toast_command}(`{message}`, {args})"
|
||||
args = LiteralVar.create(ToastProps(**props))
|
||||
toast = f"{toast_command}(`{message}`, {str(args)})"
|
||||
else:
|
||||
toast = f"{toast_command}(`{message}`)"
|
||||
|
||||
|
@ -114,6 +114,9 @@ class IterTag(Tag):
|
||||
def render_component(self) -> Component:
|
||||
"""Render the component.
|
||||
|
||||
Raises:
|
||||
ValueError: If the render function takes more than 2 arguments.
|
||||
|
||||
Returns:
|
||||
The rendered component.
|
||||
"""
|
||||
@ -132,7 +135,8 @@ class IterTag(Tag):
|
||||
component = self.render_fn(arg)
|
||||
else:
|
||||
# If the render function takes the index as an argument.
|
||||
assert len(args) == 2
|
||||
if len(args) != 2:
|
||||
raise ValueError("The render function must take 2 arguments.")
|
||||
component = self.render_fn(arg, index)
|
||||
|
||||
# Nested foreach components or cond must be wrapped in fragments.
|
||||
|
@ -158,7 +158,7 @@ class Config(Base):
|
||||
app_name: str
|
||||
|
||||
# The log level to use.
|
||||
loglevel: constants.LogLevel = constants.LogLevel.INFO
|
||||
loglevel: constants.LogLevel = constants.LogLevel.DEFAULT
|
||||
|
||||
# The port to run the frontend on. NOTE: When running in dev mode, the next available port will be used if this is taken.
|
||||
frontend_port: int = constants.DefaultPorts.FRONTEND_PORT
|
||||
@ -194,7 +194,7 @@ class Config(Base):
|
||||
cors_allowed_origins: List[str] = ["*"]
|
||||
|
||||
# Tailwind config.
|
||||
tailwind: Optional[Dict[str, Any]] = {}
|
||||
tailwind: Optional[Dict[str, Any]] = {"plugins": ["@tailwindcss/typography"]}
|
||||
|
||||
# Timeout when launching the gunicorn server. TODO(rename this to backend_timeout?)
|
||||
timeout: int = 120
|
||||
|
@ -173,6 +173,7 @@ class LogLevel(str, Enum):
|
||||
"""The log levels."""
|
||||
|
||||
DEBUG = "debug"
|
||||
DEFAULT = "default"
|
||||
INFO = "info"
|
||||
WARNING = "warning"
|
||||
ERROR = "error"
|
||||
|
@ -54,6 +54,9 @@ class Bun(SimpleNamespace):
|
||||
# Path of the bunfig file
|
||||
CONFIG_PATH = "bunfig.toml"
|
||||
|
||||
# The environment variable to use the system installed bun.
|
||||
USE_SYSTEM_VAR = "REFLEX_USE_SYSTEM_BUN"
|
||||
|
||||
|
||||
# FNM config.
|
||||
class Fnm(SimpleNamespace):
|
||||
@ -96,6 +99,9 @@ class Node(SimpleNamespace):
|
||||
# The default path where npm is installed.
|
||||
NPM_PATH = os.path.join(BIN_PATH, "npm")
|
||||
|
||||
# The environment variable to use the system installed node.
|
||||
USE_SYSTEM_VAR = "REFLEX_USE_SYSTEM_NODE"
|
||||
|
||||
|
||||
class PackageJson(SimpleNamespace):
|
||||
"""Constants used to build the package.json file."""
|
||||
@ -115,7 +121,7 @@ class PackageJson(SimpleNamespace):
|
||||
"@emotion/react": "11.11.1",
|
||||
"axios": "1.6.0",
|
||||
"json5": "2.2.3",
|
||||
"next": "14.0.1",
|
||||
"next": "14.2.13",
|
||||
"next-sitemap": "4.1.8",
|
||||
"next-themes": "0.2.1",
|
||||
"react": "18.2.0",
|
||||
|
@ -18,10 +18,12 @@ from typing import (
|
||||
get_type_hints,
|
||||
)
|
||||
|
||||
from typing_extensions import get_args, get_origin
|
||||
|
||||
from reflex import constants
|
||||
from reflex.utils import format
|
||||
from reflex.utils.exceptions import EventFnArgMismatch, EventHandlerArgMismatch
|
||||
from reflex.utils.types import ArgsSpec
|
||||
from reflex.utils.types import ArgsSpec, GenericType
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import LiteralVar, Var
|
||||
from reflex.vars.function import FunctionStringVar, FunctionVar
|
||||
@ -217,7 +219,7 @@ class EventHandler(EventActionsMixin):
|
||||
raise EventHandlerTypeError(
|
||||
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
|
||||
) from e
|
||||
payload = tuple(zip(fn_args, values, strict=False))
|
||||
payload = tuple(zip(fn_args, values))
|
||||
|
||||
# Return the event spec.
|
||||
return EventSpec(
|
||||
@ -310,7 +312,7 @@ class EventSpec(EventActionsMixin):
|
||||
raise EventHandlerTypeError(
|
||||
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
|
||||
) from e
|
||||
new_payload = tuple(zip(fn_args, values, strict=False))
|
||||
new_payload = tuple(zip(fn_args, values))
|
||||
return self.with_args(self.args + new_payload)
|
||||
|
||||
|
||||
@ -417,7 +419,7 @@ class FileUpload:
|
||||
on_upload_progress: Optional[Union[EventHandler, Callable]] = None
|
||||
|
||||
@staticmethod
|
||||
def on_upload_progress_args_spec(_prog: Dict[str, Union[int, float, bool]]):
|
||||
def on_upload_progress_args_spec(_prog: Var[Dict[str, Union[int, float, bool]]]):
|
||||
"""Args spec for on_upload_progress event handler.
|
||||
|
||||
Returns:
|
||||
@ -910,6 +912,20 @@ def call_event_handler(
|
||||
)
|
||||
|
||||
|
||||
def unwrap_var_annotation(annotation: GenericType):
|
||||
"""Unwrap a Var annotation or return it as is if it's not Var[X].
|
||||
|
||||
Args:
|
||||
annotation: The annotation to unwrap.
|
||||
|
||||
Returns:
|
||||
The unwrapped annotation.
|
||||
"""
|
||||
if get_origin(annotation) is Var and (args := get_args(annotation)):
|
||||
return args[0]
|
||||
return annotation
|
||||
|
||||
|
||||
def parse_args_spec(arg_spec: ArgsSpec):
|
||||
"""Parse the args provided in the ArgsSpec of an event trigger.
|
||||
|
||||
@ -921,20 +937,54 @@ def parse_args_spec(arg_spec: ArgsSpec):
|
||||
"""
|
||||
spec = inspect.getfullargspec(arg_spec)
|
||||
annotations = get_type_hints(arg_spec)
|
||||
|
||||
return arg_spec(
|
||||
*[
|
||||
Var(f"_{l_arg}").to(annotations.get(l_arg, FrontendEvent))
|
||||
Var(f"_{l_arg}").to(
|
||||
unwrap_var_annotation(annotations.get(l_arg, FrontendEvent))
|
||||
)
|
||||
for l_arg in spec.args
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def check_fn_match_arg_spec(fn: Callable, arg_spec: ArgsSpec) -> List[Var]:
|
||||
"""Ensures that the function signature matches the passed argument specification
|
||||
or raises an EventFnArgMismatch if they do not.
|
||||
|
||||
Args:
|
||||
fn: The function to be validated.
|
||||
arg_spec: The argument specification for the event trigger.
|
||||
|
||||
Returns:
|
||||
The parsed arguments from the argument specification.
|
||||
|
||||
Raises:
|
||||
EventFnArgMismatch: Raised if the number of mandatory arguments do not match
|
||||
"""
|
||||
fn_args = inspect.getfullargspec(fn).args
|
||||
fn_defaults_args = inspect.getfullargspec(fn).defaults
|
||||
n_fn_args = len(fn_args)
|
||||
n_fn_defaults_args = len(fn_defaults_args) if fn_defaults_args else 0
|
||||
if isinstance(fn, types.MethodType):
|
||||
n_fn_args -= 1 # subtract 1 for bound self arg
|
||||
parsed_args = parse_args_spec(arg_spec)
|
||||
if not (n_fn_args - n_fn_defaults_args <= len(parsed_args) <= n_fn_args):
|
||||
raise EventFnArgMismatch(
|
||||
"The number of mandatory arguments accepted by "
|
||||
f"{fn} ({n_fn_args - n_fn_defaults_args}) "
|
||||
"does not match the arguments passed by the event trigger: "
|
||||
f"{[str(v) for v in parsed_args]}\n"
|
||||
"See https://reflex.dev/docs/events/event-arguments/"
|
||||
)
|
||||
return parsed_args
|
||||
|
||||
|
||||
def call_event_fn(fn: Callable, arg_spec: ArgsSpec) -> list[EventSpec] | Var:
|
||||
"""Call a function to a list of event specs.
|
||||
|
||||
The function should return a single EventSpec, a list of EventSpecs, or a
|
||||
single Var. The function signature must match the passed arg_spec or
|
||||
EventFnArgsMismatch will be raised.
|
||||
single Var.
|
||||
|
||||
Args:
|
||||
fn: The function to call.
|
||||
@ -944,7 +994,6 @@ def call_event_fn(fn: Callable, arg_spec: ArgsSpec) -> list[EventSpec] | Var:
|
||||
The event specs from calling the function or a Var.
|
||||
|
||||
Raises:
|
||||
EventFnArgMismatch: If the function signature doesn't match the arg spec.
|
||||
EventHandlerValueError: If the lambda returns an unusable value.
|
||||
"""
|
||||
# Import here to avoid circular imports.
|
||||
@ -952,19 +1001,7 @@ def call_event_fn(fn: Callable, arg_spec: ArgsSpec) -> list[EventSpec] | Var:
|
||||
from reflex.utils.exceptions import EventHandlerValueError
|
||||
|
||||
# Check that fn signature matches arg_spec
|
||||
fn_args = inspect.getfullargspec(fn).args
|
||||
n_fn_args = len(fn_args)
|
||||
if isinstance(fn, types.MethodType):
|
||||
n_fn_args -= 1 # subtract 1 for bound self arg
|
||||
parsed_args = parse_args_spec(arg_spec)
|
||||
if len(parsed_args) != n_fn_args:
|
||||
raise EventFnArgMismatch(
|
||||
"The number of arguments accepted by "
|
||||
f"{fn} ({n_fn_args}) "
|
||||
"does not match the arguments passed by the event trigger: "
|
||||
f"{[str(v) for v in parsed_args]}\n"
|
||||
"See https://reflex.dev/docs/events/event-arguments/"
|
||||
)
|
||||
parsed_args = check_fn_match_arg_spec(fn, arg_spec)
|
||||
|
||||
# Call the function with the parsed args.
|
||||
out = fn(*parsed_args)
|
||||
@ -1025,6 +1062,9 @@ def fix_events(
|
||||
token: The user token.
|
||||
router_data: The optional router data to set in the event.
|
||||
|
||||
Raises:
|
||||
ValueError: If the event type is not what was expected.
|
||||
|
||||
Returns:
|
||||
The fixed events.
|
||||
"""
|
||||
@ -1048,7 +1088,8 @@ def fix_events(
|
||||
# Otherwise, create an event from the event spec.
|
||||
if isinstance(e, EventHandler):
|
||||
e = e()
|
||||
assert isinstance(e, EventSpec), f"Unexpected event type, {type(e)}."
|
||||
if not isinstance(e, EventSpec):
|
||||
raise ValueError(f"Unexpected event type, {type(e)}.")
|
||||
name = format.format_event_handler(e.handler)
|
||||
payload = {k._js_expr: v._decode() for k, v in e.args} # type: ignore
|
||||
|
||||
|
@ -24,6 +24,7 @@ def asset(relative_filename: str, subfolder: Optional[str] = None) -> str:
|
||||
|
||||
Raises:
|
||||
FileNotFoundError: If the file does not exist.
|
||||
ValueError: If the module is None.
|
||||
|
||||
Returns:
|
||||
The relative URL to the copied asset.
|
||||
@ -31,7 +32,8 @@ def asset(relative_filename: str, subfolder: Optional[str] = None) -> str:
|
||||
# Determine the file by which the asset is exposed.
|
||||
calling_file = inspect.stack()[1].filename
|
||||
module = inspect.getmodule(inspect.stack()[1][0])
|
||||
assert module is not None
|
||||
if module is None:
|
||||
raise ValueError("Module is None")
|
||||
caller_module_path = module.__name__.replace(".", "/")
|
||||
|
||||
subfolder = f"{caller_module_path}/{subfolder}" if subfolder else caller_module_path
|
||||
|
@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import dataclasses
|
||||
import re
|
||||
import sys
|
||||
from typing import Any, Callable, Union
|
||||
|
||||
@ -90,12 +91,16 @@ class ClientStateVar(Var):
|
||||
default: The default value of the variable.
|
||||
global_ref: Whether the state should be accessible in any Component and on the backend.
|
||||
|
||||
Raises:
|
||||
ValueError: If the var_name is not a string.
|
||||
|
||||
Returns:
|
||||
ClientStateVar
|
||||
"""
|
||||
if var_name is None:
|
||||
var_name = get_unique_variable_name()
|
||||
assert isinstance(var_name, str), "var_name must be a string."
|
||||
if not isinstance(var_name, str):
|
||||
raise ValueError("var_name must be a string.")
|
||||
if default is NoValue:
|
||||
default_var = Var(_js_expr="")
|
||||
elif not isinstance(default, Var):
|
||||
@ -174,15 +179,15 @@ class ClientStateVar(Var):
|
||||
else self._setter_name
|
||||
)
|
||||
if value is not NoValue:
|
||||
import re
|
||||
|
||||
# This is a hack to make it work like an EventSpec taking an arg
|
||||
value_str = str(LiteralVar.create(value))
|
||||
|
||||
if value_str.startswith("_"):
|
||||
# remove patterns of ["*"] from the value_str using regex
|
||||
arg = re.sub(r"\[\".*\"\]", "", value_str)
|
||||
|
||||
setter = f"({arg}) => {setter}({str(value)})"
|
||||
setter = f"(({arg}) => {setter}({value_str}))"
|
||||
else:
|
||||
setter = f"(() => {setter}({value_str}))"
|
||||
return Var(
|
||||
_js_expr=setter,
|
||||
_var_data=VarData(imports=_refs_import if self._global_ref else {}),
|
||||
|
@ -12,10 +12,12 @@ async def run_in_thread(func) -> Any:
|
||||
Args:
|
||||
func (callable): The non-async function to run.
|
||||
|
||||
Raises:
|
||||
ValueError: If the function is an async function.
|
||||
|
||||
Returns:
|
||||
Any: The return value of the function.
|
||||
"""
|
||||
assert not asyncio.coroutines.iscoroutinefunction(
|
||||
func
|
||||
), "func must be a non-async function"
|
||||
if asyncio.coroutines.iscoroutinefunction(func):
|
||||
raise ValueError("func must be a non-async function")
|
||||
return await asyncio.get_event_loop().run_in_executor(None, func)
|
||||
|
@ -9,7 +9,6 @@ from reflex import constants
|
||||
from reflex.event import Event, get_hydrate_event
|
||||
from reflex.middleware.middleware import Middleware
|
||||
from reflex.state import BaseState, StateUpdate
|
||||
from reflex.utils import format
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from reflex.app import App
|
||||
@ -43,7 +42,7 @@ class HydrateMiddleware(Middleware):
|
||||
setattr(state, constants.CompileVars.IS_HYDRATED, False)
|
||||
|
||||
# Get the initial state.
|
||||
delta = format.format_state(state.dict())
|
||||
delta = state.dict()
|
||||
# since a full dict was captured, clean any dirtiness
|
||||
state._clean()
|
||||
|
||||
|
@ -22,7 +22,7 @@ from reflex import constants
|
||||
from reflex.base import Base
|
||||
from reflex.config import get_config
|
||||
from reflex.utils import console
|
||||
from reflex.utils.compat import sqlmodel
|
||||
from reflex.utils.compat import sqlmodel, sqlmodel_field_has_primary_key
|
||||
|
||||
|
||||
def get_engine(url: str | None = None) -> sqlalchemy.engine.Engine:
|
||||
@ -166,8 +166,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
|
||||
non_default_primary_key_fields = [
|
||||
field_name
|
||||
for field_name, field in cls.__fields__.items()
|
||||
if field_name != "id"
|
||||
and getattr(field.field_info, "primary_key", None) is True
|
||||
if field_name != "id" and sqlmodel_field_has_primary_key(field)
|
||||
]
|
||||
if non_default_primary_key_fields:
|
||||
cls.__fields__.pop("id", None)
|
||||
|
@ -63,3 +63,22 @@ def page(
|
||||
return render_fn
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def get_decorated_pages(omit_implicit_routes=True) -> list[dict[str, Any]]:
|
||||
"""Get the decorated pages.
|
||||
|
||||
Args:
|
||||
omit_implicit_routes: Whether to omit pages where the route will be implicitely guessed later.
|
||||
|
||||
Returns:
|
||||
The decorated pages.
|
||||
"""
|
||||
return sorted(
|
||||
[
|
||||
page_data
|
||||
for _, page_data in DECORATED_PAGES[get_config().app_name]
|
||||
if not omit_implicit_routes or "route" in page_data
|
||||
],
|
||||
key=lambda x: x.get("route", ""),
|
||||
)
|
||||
|
@ -15,6 +15,7 @@ from reflex_cli.utils import dependency
|
||||
|
||||
from reflex import constants
|
||||
from reflex.config import get_config
|
||||
from reflex.constants.base import LogLevel
|
||||
from reflex.custom_components.custom_components import custom_components_cli
|
||||
from reflex.state import reset_disk_state_manager
|
||||
from reflex.utils import console, redir, telemetry
|
||||
@ -229,7 +230,8 @@ def _run(
|
||||
exec.run_frontend_prod,
|
||||
exec.run_backend_prod,
|
||||
)
|
||||
assert setup_frontend and frontend_cmd and backend_cmd, "Invalid env"
|
||||
if not setup_frontend or not frontend_cmd or not backend_cmd:
|
||||
raise ValueError("Invalid env")
|
||||
|
||||
# Post a telemetry event.
|
||||
telemetry.send(f"run-{env.value}")
|
||||
@ -245,15 +247,30 @@ def _run(
|
||||
setup_frontend(Path.cwd())
|
||||
commands.append((frontend_cmd, Path.cwd(), frontend_port, backend))
|
||||
|
||||
# If no loglevel is specified, set the subprocesses loglevel to WARNING.
|
||||
subprocesses_loglevel = (
|
||||
loglevel if loglevel != LogLevel.DEFAULT else LogLevel.WARNING
|
||||
)
|
||||
|
||||
# In prod mode, run the backend on a separate thread.
|
||||
if backend and env == constants.Env.PROD:
|
||||
commands.append((backend_cmd, backend_host, backend_port))
|
||||
commands.append(
|
||||
(
|
||||
backend_cmd,
|
||||
backend_host,
|
||||
backend_port,
|
||||
subprocesses_loglevel,
|
||||
frontend,
|
||||
)
|
||||
)
|
||||
|
||||
# Start the frontend and backend.
|
||||
with processes.run_concurrently_context(*commands):
|
||||
# In dev mode, run the backend on the main thread.
|
||||
if backend and env == constants.Env.DEV:
|
||||
backend_cmd(backend_host, int(backend_port))
|
||||
backend_cmd(
|
||||
backend_host, int(backend_port), subprocesses_loglevel, frontend
|
||||
)
|
||||
# The windows uvicorn bug workaround
|
||||
# https://github.com/reflex-dev/reflex/issues/2335
|
||||
if constants.IS_WINDOWS and exec.frontend_process:
|
||||
|
102
reflex/state.py
102
reflex/state.py
@ -12,6 +12,7 @@ import os
|
||||
import uuid
|
||||
from abc import ABC, abstractmethod
|
||||
from collections import defaultdict
|
||||
from hashlib import md5
|
||||
from pathlib import Path
|
||||
from types import FunctionType, MethodType
|
||||
from typing import (
|
||||
@ -29,10 +30,12 @@ from typing import (
|
||||
Type,
|
||||
Union,
|
||||
cast,
|
||||
get_type_hints,
|
||||
)
|
||||
|
||||
import dill
|
||||
from sqlalchemy.orm import DeclarativeBase
|
||||
from typing_extensions import Self
|
||||
|
||||
from reflex.config import get_config
|
||||
from reflex.vars.base import (
|
||||
@ -41,6 +44,7 @@ from reflex.vars.base import (
|
||||
Var,
|
||||
computed_var,
|
||||
dispatch,
|
||||
get_unique_variable_name,
|
||||
is_computed_var,
|
||||
)
|
||||
|
||||
@ -72,7 +76,7 @@ from reflex.utils.exceptions import (
|
||||
LockExpiredError,
|
||||
)
|
||||
from reflex.utils.exec import is_testing_env
|
||||
from reflex.utils.serializers import SerializedType, serialize, serializer
|
||||
from reflex.utils.serializers import serializer
|
||||
from reflex.utils.types import override
|
||||
from reflex.vars import VarData
|
||||
|
||||
@ -572,6 +576,15 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
||||
for name, value in cls.__dict__.items()
|
||||
if types.is_backend_base_variable(name, cls)
|
||||
}
|
||||
# Add annotated backend vars that do not have a default value.
|
||||
new_backend_vars.update(
|
||||
{
|
||||
name: Var("", _var_type=annotation_value).get_default_value()
|
||||
for name, annotation_value in get_type_hints(cls).items()
|
||||
if name not in new_backend_vars
|
||||
and types.is_backend_base_variable(name, cls)
|
||||
}
|
||||
)
|
||||
|
||||
cls.backend_vars = {
|
||||
**cls.inherited_backend_vars,
|
||||
@ -684,6 +697,36 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
||||
and hasattr(value, "__code__")
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _evaluate(cls, f: Callable[[Self], Any]) -> Var:
|
||||
"""Evaluate a function to a ComputedVar. Experimental.
|
||||
|
||||
Args:
|
||||
f: The function to evaluate.
|
||||
|
||||
Returns:
|
||||
The ComputedVar.
|
||||
"""
|
||||
console.warn(
|
||||
"The _evaluate method is experimental and may be removed in future versions."
|
||||
)
|
||||
from reflex.components.base.fragment import fragment
|
||||
from reflex.components.component import Component
|
||||
|
||||
unique_var_name = get_unique_variable_name()
|
||||
|
||||
@computed_var(_js_expr=unique_var_name, return_type=Component)
|
||||
def computed_var_func(state: Self):
|
||||
return fragment(f(state))
|
||||
|
||||
setattr(cls, unique_var_name, computed_var_func)
|
||||
cls.computed_vars[unique_var_name] = computed_var_func
|
||||
cls.vars[unique_var_name] = computed_var_func
|
||||
cls._update_substate_inherited_vars({unique_var_name: computed_var_func})
|
||||
cls._always_dirty_computed_vars.add(unique_var_name)
|
||||
|
||||
return getattr(cls, unique_var_name)
|
||||
|
||||
@classmethod
|
||||
def _mixins(cls) -> List[Type]:
|
||||
"""Get the mixin classes of the state.
|
||||
@ -827,6 +870,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
||||
def get_parent_state(cls) -> Type[BaseState] | None:
|
||||
"""Get the parent state.
|
||||
|
||||
Raises:
|
||||
ValueError: If more than one parent state is found.
|
||||
|
||||
Returns:
|
||||
The parent state.
|
||||
"""
|
||||
@ -835,9 +881,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
||||
for base in cls.__bases__
|
||||
if issubclass(base, BaseState) and base is not BaseState and not base._mixin
|
||||
]
|
||||
assert (
|
||||
len(parent_states) < 2
|
||||
), f"Only one parent state is allowed {parent_states}."
|
||||
if len(parent_states) >= 2:
|
||||
raise ValueError(f"Only one parent state is allowed {parent_states}.")
|
||||
return parent_states[0] if len(parent_states) == 1 else None # type: ignore
|
||||
|
||||
@classmethod
|
||||
@ -1316,7 +1361,6 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
||||
for part1, part2 in zip(
|
||||
cls.get_full_name().split("."),
|
||||
other.get_full_name().split("."),
|
||||
strict=False,
|
||||
):
|
||||
if part1 != part2:
|
||||
break
|
||||
@ -1790,9 +1834,6 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
||||
for substate in self.dirty_substates.union(self._always_dirty_substates):
|
||||
delta.update(substates[substate].get_delta())
|
||||
|
||||
# Format the delta.
|
||||
delta = format.format_state(delta)
|
||||
|
||||
# Return the delta.
|
||||
return delta
|
||||
|
||||
@ -2433,7 +2474,7 @@ class StateUpdate:
|
||||
Returns:
|
||||
The state update as a JSON string.
|
||||
"""
|
||||
return format.json_dumps(dataclasses.asdict(self))
|
||||
return format.json_dumps(self)
|
||||
|
||||
|
||||
class StateManager(Base, ABC):
|
||||
@ -2592,16 +2633,24 @@ def _serialize_type(type_: Any) -> str:
|
||||
return f"{type_.__module__}.{type_.__qualname__}"
|
||||
|
||||
|
||||
def is_serializable(value: Any) -> bool:
|
||||
"""Check if a value is serializable.
|
||||
|
||||
Args:
|
||||
value: The value to check.
|
||||
|
||||
Returns:
|
||||
Whether the value is serializable.
|
||||
"""
|
||||
try:
|
||||
return bool(dill.dumps(value))
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def state_to_schema(
|
||||
state: BaseState,
|
||||
) -> List[
|
||||
Tuple[
|
||||
str,
|
||||
str,
|
||||
Any,
|
||||
Union[bool, None],
|
||||
]
|
||||
]:
|
||||
) -> List[Tuple[str, str, Any, Union[bool, None], Any]]:
|
||||
"""Convert a state to a schema.
|
||||
|
||||
Args:
|
||||
@ -2621,6 +2670,7 @@ def state_to_schema(
|
||||
if isinstance(model_field.required, bool)
|
||||
else None
|
||||
),
|
||||
(model_field.default if is_serializable(model_field.default) else None),
|
||||
)
|
||||
for field_name, model_field in state.__fields__.items()
|
||||
)
|
||||
@ -2705,7 +2755,9 @@ class StateManagerDisk(StateManager):
|
||||
Returns:
|
||||
The path for the token.
|
||||
"""
|
||||
return (self.states_directory / f"{token}.pkl").absolute()
|
||||
return (
|
||||
self.states_directory / f"{md5(token.encode()).hexdigest()}.pkl"
|
||||
).absolute()
|
||||
|
||||
async def load_state(self, token: str, root_state: BaseState) -> BaseState:
|
||||
"""Load a state object based on the provided token.
|
||||
@ -3649,22 +3701,16 @@ class MutableProxy(wrapt.ObjectProxy):
|
||||
|
||||
|
||||
@serializer
|
||||
def serialize_mutable_proxy(mp: MutableProxy) -> SerializedType:
|
||||
"""Serialize the wrapped value of a MutableProxy.
|
||||
def serialize_mutable_proxy(mp: MutableProxy):
|
||||
"""Return the wrapped value of a MutableProxy.
|
||||
|
||||
Args:
|
||||
mp: The MutableProxy to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized wrapped object.
|
||||
|
||||
Raises:
|
||||
ValueError: when the wrapped object is not serializable.
|
||||
The wrapped object.
|
||||
"""
|
||||
value = serialize(mp.__wrapped__)
|
||||
if value is None:
|
||||
raise ValueError(f"Cannot serialize {type(mp.__wrapped__)}")
|
||||
return value
|
||||
return mp.__wrapped__
|
||||
|
||||
|
||||
class ImmutableMutableProxy(MutableProxy):
|
||||
|
@ -13,6 +13,7 @@ from reflex.utils.imports import ImportVar
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import CallableVar, LiteralVar, Var
|
||||
from reflex.vars.function import FunctionVar
|
||||
from reflex.vars.object import ObjectVar
|
||||
|
||||
SYSTEM_COLOR_MODE: str = "system"
|
||||
LIGHT_COLOR_MODE: str = "light"
|
||||
@ -188,7 +189,16 @@ def convert(
|
||||
out[k] = return_value
|
||||
|
||||
for key, value in style_dict.items():
|
||||
keys = format_style_key(key)
|
||||
keys = (
|
||||
format_style_key(key)
|
||||
if not isinstance(value, (dict, ObjectVar))
|
||||
or (
|
||||
isinstance(value, Breakpoints)
|
||||
and all(not isinstance(v, dict) for v in value.values())
|
||||
)
|
||||
else (key,)
|
||||
)
|
||||
|
||||
if isinstance(value, Var):
|
||||
return_val = value
|
||||
new_var_data = value._get_all_var_data()
|
||||
@ -286,7 +296,7 @@ def _format_emotion_style_pseudo_selector(key: str) -> str:
|
||||
"""Format a pseudo selector for emotion CSS-in-JS.
|
||||
|
||||
Args:
|
||||
key: Underscore-prefixed or colon-prefixed pseudo selector key (_hover).
|
||||
key: Underscore-prefixed or colon-prefixed pseudo selector key (_hover/:hover).
|
||||
|
||||
Returns:
|
||||
A self-referential pseudo selector key (&:hover).
|
||||
|
@ -340,6 +340,9 @@ class AppHarness:
|
||||
|
||||
This is necessary when the backend is restarted and the state manager is a
|
||||
StateManagerRedis instance.
|
||||
|
||||
Raises:
|
||||
RuntimeError: when the state manager cannot be reset
|
||||
"""
|
||||
if (
|
||||
self.app_instance is not None
|
||||
@ -354,7 +357,8 @@ class AppHarness:
|
||||
self.app_instance._state_manager = StateManagerRedis.create(
|
||||
state=self.app_instance.state,
|
||||
)
|
||||
assert isinstance(self.app_instance.state_manager, StateManagerRedis)
|
||||
if not isinstance(self.app_instance.state_manager, StateManagerRedis):
|
||||
raise RuntimeError("Failed to reset state manager.")
|
||||
|
||||
def _start_frontend(self):
|
||||
# Set up the frontend.
|
||||
@ -787,13 +791,13 @@ class AppHarness:
|
||||
Raises:
|
||||
RuntimeError: when the app hasn't started running
|
||||
TimeoutError: when the timeout expires before any states are seen
|
||||
ValueError: when the state_manager is not a memory state manager
|
||||
"""
|
||||
if self.app_instance is None:
|
||||
raise RuntimeError("App is not running.")
|
||||
state_manager = self.app_instance.state_manager
|
||||
assert isinstance(
|
||||
state_manager, (StateManagerMemory, StateManagerDisk)
|
||||
), "Only works with memory state manager"
|
||||
if not isinstance(state_manager, (StateManagerMemory, StateManagerDisk)):
|
||||
raise ValueError("Only works with memory or disk state manager")
|
||||
if not self._poll_for(
|
||||
target=lambda: state_manager.states,
|
||||
timeout=timeout,
|
||||
|
@ -69,3 +69,21 @@ def pydantic_v1_patch():
|
||||
|
||||
with pydantic_v1_patch():
|
||||
import sqlmodel as sqlmodel
|
||||
|
||||
|
||||
def sqlmodel_field_has_primary_key(field) -> bool:
|
||||
"""Determines if a field is a priamary.
|
||||
|
||||
Args:
|
||||
field: a rx.model field
|
||||
|
||||
Returns:
|
||||
If field is a primary key (Bool)
|
||||
"""
|
||||
if getattr(field.field_info, "primary_key", None) is True:
|
||||
return True
|
||||
if getattr(field.field_info, "sa_column", None) is None:
|
||||
return False
|
||||
if getattr(field.field_info.sa_column, "primary_key", None) is True:
|
||||
return True
|
||||
return False
|
||||
|
@ -58,7 +58,7 @@ def debug(msg: str, **kwargs):
|
||||
kwargs: Keyword arguments to pass to the print function.
|
||||
"""
|
||||
if is_debug():
|
||||
msg_ = f"[blue]Debug: {msg}[/blue]"
|
||||
msg_ = f"[purple]Debug: {msg}[/purple]"
|
||||
if progress := kwargs.pop("progress", None):
|
||||
progress.console.print(msg_, **kwargs)
|
||||
else:
|
||||
|
@ -111,3 +111,7 @@ class GeneratedCodeHasNoFunctionDefs(ReflexError):
|
||||
|
||||
class PrimitiveUnserializableToJSON(ReflexError, ValueError):
|
||||
"""Raised when a primitive type is unserializable to JSON. Usually with NaN and Infinity."""
|
||||
|
||||
|
||||
class InvalidLifespanTaskType(ReflexError, TypeError):
|
||||
"""Raised when an invalid task type is registered as a lifespan task."""
|
||||
|
@ -16,6 +16,7 @@ import psutil
|
||||
|
||||
from reflex import constants
|
||||
from reflex.config import get_config
|
||||
from reflex.constants.base import LogLevel
|
||||
from reflex.utils import console, path_ops
|
||||
from reflex.utils.prerequisites import get_web_dir
|
||||
|
||||
@ -60,6 +61,13 @@ def kill(proc_pid: int):
|
||||
process.kill()
|
||||
|
||||
|
||||
def notify_backend():
|
||||
"""Output a string notifying where the backend is running."""
|
||||
console.print(
|
||||
f"Backend running at: [bold green]http://0.0.0.0:{get_config().backend_port}[/bold green]"
|
||||
)
|
||||
|
||||
|
||||
# run_process_and_launch_url is assumed to be used
|
||||
# only to launch the frontend
|
||||
# If this is not the case, might have to change the logic
|
||||
@ -103,9 +111,7 @@ def run_process_and_launch_url(run_command: list[str], backend_present=True):
|
||||
f"App running at: [bold green]{url}[/bold green]{' (Frontend-only mode)' if not backend_present else ''}"
|
||||
)
|
||||
if backend_present:
|
||||
console.print(
|
||||
f"Backend running at: [bold green]http://0.0.0.0:{get_config().backend_port}[/bold green]"
|
||||
)
|
||||
notify_backend()
|
||||
first_run = False
|
||||
else:
|
||||
console.print("New packages detected: Updating app...")
|
||||
@ -172,13 +178,69 @@ def run_frontend_prod(root: Path, port: str, backend_present=True):
|
||||
)
|
||||
|
||||
|
||||
def should_use_granian():
|
||||
"""Whether to use Granian for backend.
|
||||
|
||||
Returns:
|
||||
True if Granian should be used.
|
||||
"""
|
||||
return os.getenv("REFLEX_USE_GRANIAN", "0") == "1"
|
||||
|
||||
|
||||
def get_app_module():
|
||||
"""Get the app module for the backend.
|
||||
|
||||
Returns:
|
||||
The app module for the backend.
|
||||
"""
|
||||
return f"reflex.app_module_for_backend:{constants.CompileVars.APP}"
|
||||
|
||||
|
||||
def get_granian_target():
|
||||
"""Get the Granian target for the backend.
|
||||
|
||||
Returns:
|
||||
The Granian target for the backend.
|
||||
"""
|
||||
import reflex
|
||||
|
||||
app_module_path = Path(reflex.__file__).parent / "app_module_for_backend.py"
|
||||
|
||||
return f"{str(app_module_path)}:{constants.CompileVars.APP}.{constants.CompileVars.API}"
|
||||
|
||||
|
||||
def run_backend(
|
||||
host: str,
|
||||
port: int,
|
||||
loglevel: constants.LogLevel = constants.LogLevel.ERROR,
|
||||
frontend_present: bool = False,
|
||||
):
|
||||
"""Run the backend.
|
||||
|
||||
Args:
|
||||
host: The app host
|
||||
port: The app port
|
||||
loglevel: The log level.
|
||||
frontend_present: Whether the frontend is present.
|
||||
"""
|
||||
web_dir = get_web_dir()
|
||||
# Create a .nocompile file to skip compile for backend.
|
||||
if web_dir.exists():
|
||||
(web_dir / constants.NOCOMPILE_FILE).touch()
|
||||
|
||||
if not frontend_present:
|
||||
notify_backend()
|
||||
|
||||
# Run the backend in development mode.
|
||||
if should_use_granian():
|
||||
run_granian_backend(host, port, loglevel)
|
||||
else:
|
||||
run_uvicorn_backend(host, port, loglevel)
|
||||
|
||||
|
||||
def run_uvicorn_backend(host, port, loglevel: LogLevel):
|
||||
"""Run the backend in development mode using Uvicorn.
|
||||
|
||||
Args:
|
||||
host: The app host
|
||||
port: The app port
|
||||
@ -186,22 +248,55 @@ def run_backend(
|
||||
"""
|
||||
import uvicorn
|
||||
|
||||
config = get_config()
|
||||
app_module = f"reflex.app_module_for_backend:{constants.CompileVars.APP}"
|
||||
|
||||
web_dir = get_web_dir()
|
||||
# Create a .nocompile file to skip compile for backend.
|
||||
if web_dir.exists():
|
||||
(web_dir / constants.NOCOMPILE_FILE).touch()
|
||||
|
||||
# Run the backend in development mode.
|
||||
uvicorn.run(
|
||||
app=f"{app_module}.{constants.CompileVars.API}",
|
||||
app=f"{get_app_module()}.{constants.CompileVars.API}",
|
||||
host=host,
|
||||
port=port,
|
||||
log_level=loglevel.value,
|
||||
reload=True,
|
||||
reload_dirs=[config.app_name],
|
||||
reload_dirs=[get_config().app_name],
|
||||
)
|
||||
|
||||
|
||||
def run_granian_backend(host, port, loglevel: LogLevel):
|
||||
"""Run the backend in development mode using Granian.
|
||||
|
||||
Args:
|
||||
host: The app host
|
||||
port: The app port
|
||||
loglevel: The log level.
|
||||
"""
|
||||
console.debug("Using Granian for backend")
|
||||
try:
|
||||
from granian import Granian # type: ignore
|
||||
from granian.constants import Interfaces # type: ignore
|
||||
from granian.log import LogLevels # type: ignore
|
||||
|
||||
Granian(
|
||||
target=get_granian_target(),
|
||||
address=host,
|
||||
port=port,
|
||||
interface=Interfaces.ASGI,
|
||||
log_level=LogLevels(loglevel.value),
|
||||
reload=True,
|
||||
reload_paths=[Path(get_config().app_name)],
|
||||
reload_ignore_dirs=[".web"],
|
||||
).serve()
|
||||
except ImportError:
|
||||
console.error(
|
||||
'InstallError: REFLEX_USE_GRANIAN is set but `granian` is not installed. (run `pip install "granian>=1.6.0"`)'
|
||||
)
|
||||
os._exit(1)
|
||||
|
||||
|
||||
def _get_backend_workers():
|
||||
from reflex.utils import processes
|
||||
|
||||
config = get_config()
|
||||
return (
|
||||
processes.get_num_workers()
|
||||
if not config.gunicorn_workers
|
||||
else config.gunicorn_workers
|
||||
)
|
||||
|
||||
|
||||
@ -209,9 +304,28 @@ def run_backend_prod(
|
||||
host: str,
|
||||
port: int,
|
||||
loglevel: constants.LogLevel = constants.LogLevel.ERROR,
|
||||
frontend_present: bool = False,
|
||||
):
|
||||
"""Run the backend.
|
||||
|
||||
Args:
|
||||
host: The app host
|
||||
port: The app port
|
||||
loglevel: The log level.
|
||||
frontend_present: Whether the frontend is present.
|
||||
"""
|
||||
if not frontend_present:
|
||||
notify_backend()
|
||||
|
||||
if should_use_granian():
|
||||
run_granian_backend_prod(host, port, loglevel)
|
||||
else:
|
||||
run_uvicorn_backend_prod(host, port, loglevel)
|
||||
|
||||
|
||||
def run_uvicorn_backend_prod(host, port, loglevel):
|
||||
"""Run the backend in production mode using Uvicorn.
|
||||
|
||||
Args:
|
||||
host: The app host
|
||||
port: The app port
|
||||
@ -220,14 +334,11 @@ def run_backend_prod(
|
||||
from reflex.utils import processes
|
||||
|
||||
config = get_config()
|
||||
num_workers = (
|
||||
processes.get_num_workers()
|
||||
if not config.gunicorn_workers
|
||||
else config.gunicorn_workers
|
||||
)
|
||||
|
||||
app_module = get_app_module()
|
||||
|
||||
RUN_BACKEND_PROD = f"gunicorn --worker-class {config.gunicorn_worker_class} --preload --timeout {config.timeout} --log-level critical".split()
|
||||
RUN_BACKEND_PROD_WINDOWS = f"uvicorn --timeout-keep-alive {config.timeout}".split()
|
||||
app_module = f"reflex.app_module_for_backend:{constants.CompileVars.APP}"
|
||||
command = (
|
||||
[
|
||||
*RUN_BACKEND_PROD_WINDOWS,
|
||||
@ -243,7 +354,7 @@ def run_backend_prod(
|
||||
"--bind",
|
||||
f"{host}:{port}",
|
||||
"--threads",
|
||||
str(num_workers),
|
||||
str(_get_backend_workers()),
|
||||
f"{app_module}()",
|
||||
]
|
||||
)
|
||||
@ -252,7 +363,7 @@ def run_backend_prod(
|
||||
"--log-level",
|
||||
loglevel.value,
|
||||
"--workers",
|
||||
str(num_workers),
|
||||
str(_get_backend_workers()),
|
||||
]
|
||||
processes.new_process(
|
||||
command,
|
||||
@ -262,6 +373,47 @@ def run_backend_prod(
|
||||
)
|
||||
|
||||
|
||||
def run_granian_backend_prod(host, port, loglevel):
|
||||
"""Run the backend in production mode using Granian.
|
||||
|
||||
Args:
|
||||
host: The app host
|
||||
port: The app port
|
||||
loglevel: The log level.
|
||||
"""
|
||||
from reflex.utils import processes
|
||||
|
||||
try:
|
||||
from granian.constants import Interfaces # type: ignore
|
||||
|
||||
command = [
|
||||
"granian",
|
||||
"--workers",
|
||||
str(_get_backend_workers()),
|
||||
"--log-level",
|
||||
"critical",
|
||||
"--host",
|
||||
host,
|
||||
"--port",
|
||||
str(port),
|
||||
"--interface",
|
||||
str(Interfaces.ASGI),
|
||||
get_granian_target(),
|
||||
]
|
||||
processes.new_process(
|
||||
command,
|
||||
run=True,
|
||||
show_logs=True,
|
||||
env={
|
||||
constants.SKIP_COMPILE_ENV_VAR: "yes"
|
||||
}, # skip compile for prod backend
|
||||
)
|
||||
except ImportError:
|
||||
console.error(
|
||||
'InstallError: REFLEX_USE_GRANIAN is set but `granian` is not installed. (run `pip install "granian>=1.6.0"`)'
|
||||
)
|
||||
|
||||
|
||||
def output_system_info():
|
||||
"""Show system information if the loglevel is in DEBUG."""
|
||||
if console._LOG_LEVEL > constants.LogLevel.DEBUG:
|
||||
|
@ -9,7 +9,7 @@ import re
|
||||
from typing import TYPE_CHECKING, Any, Callable, List, Optional, Union
|
||||
|
||||
from reflex import constants
|
||||
from reflex.utils import exceptions, types
|
||||
from reflex.utils import exceptions
|
||||
from reflex.utils.console import deprecate
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -345,6 +345,7 @@ def format_prop(
|
||||
Raises:
|
||||
exceptions.InvalidStylePropError: If the style prop value is not a valid type.
|
||||
TypeError: If the prop is not valid.
|
||||
ValueError: If the prop is not a string.
|
||||
"""
|
||||
# import here to avoid circular import.
|
||||
from reflex.event import EventChain
|
||||
@ -391,7 +392,8 @@ def format_prop(
|
||||
raise TypeError(f"Could not format prop: {prop} of type {type(prop)}") from e
|
||||
|
||||
# Wrap the variable in braces.
|
||||
assert isinstance(prop, str), "The prop must be a string."
|
||||
if not isinstance(prop, str):
|
||||
raise ValueError(f"Invalid prop: {prop}. Expected a string.")
|
||||
return wrap(prop, "{", check_first=False)
|
||||
|
||||
|
||||
@ -624,48 +626,6 @@ def format_query_params(router_data: dict[str, Any]) -> dict[str, str]:
|
||||
return {k.replace("-", "_"): v for k, v in params.items()}
|
||||
|
||||
|
||||
def format_state(value: Any, key: Optional[str] = None) -> Any:
|
||||
"""Recursively format values in the given state.
|
||||
|
||||
Args:
|
||||
value: The state to format.
|
||||
key: The key associated with the value (optional).
|
||||
|
||||
Returns:
|
||||
The formatted state.
|
||||
|
||||
Raises:
|
||||
TypeError: If the given value is not a valid state.
|
||||
"""
|
||||
from reflex.utils import serializers
|
||||
|
||||
# Handle dicts.
|
||||
if isinstance(value, dict):
|
||||
return {k: format_state(v, k) for k, v in value.items()}
|
||||
|
||||
# Handle lists, sets, typles.
|
||||
if isinstance(value, types.StateIterBases):
|
||||
return [format_state(v) for v in value]
|
||||
|
||||
# Return state vars as is.
|
||||
if isinstance(value, types.StateBases):
|
||||
return value
|
||||
|
||||
# Serialize the value.
|
||||
serialized = serializers.serialize(value)
|
||||
if serialized is not None:
|
||||
return serialized
|
||||
|
||||
if key is None:
|
||||
raise TypeError(
|
||||
f"No JSON serializer found for var {value} of type {type(value)}."
|
||||
)
|
||||
else:
|
||||
raise TypeError(
|
||||
f"No JSON serializer found for State Var '{key}' of value {value} of type {type(value)}."
|
||||
)
|
||||
|
||||
|
||||
def format_state_name(state_name: str) -> str:
|
||||
"""Format a state name, replacing dots with double underscore.
|
||||
|
||||
|
@ -129,6 +129,41 @@ def which(program: str | Path) -> str | Path | None:
|
||||
return shutil.which(str(program))
|
||||
|
||||
|
||||
def use_system_install(var_name: str) -> bool:
|
||||
"""Check if the system install should be used.
|
||||
|
||||
Args:
|
||||
var_name: The name of the environment variable.
|
||||
|
||||
Raises:
|
||||
ValueError: If the variable name is invalid.
|
||||
|
||||
Returns:
|
||||
Whether the associated env var should use the system install.
|
||||
"""
|
||||
if not var_name.startswith("REFLEX_USE_SYSTEM_"):
|
||||
raise ValueError("Invalid system install variable name.")
|
||||
return os.getenv(var_name, "").lower() in ["true", "1", "yes"]
|
||||
|
||||
|
||||
def use_system_node() -> bool:
|
||||
"""Check if the system node should be used.
|
||||
|
||||
Returns:
|
||||
Whether the system node should be used.
|
||||
"""
|
||||
return use_system_install(constants.Node.USE_SYSTEM_VAR)
|
||||
|
||||
|
||||
def use_system_bun() -> bool:
|
||||
"""Check if the system bun should be used.
|
||||
|
||||
Returns:
|
||||
Whether the system bun should be used.
|
||||
"""
|
||||
return use_system_install(constants.Bun.USE_SYSTEM_VAR)
|
||||
|
||||
|
||||
def get_node_bin_path() -> str | None:
|
||||
"""Get the node binary dir path.
|
||||
|
||||
@ -149,7 +184,7 @@ def get_node_path() -> str | None:
|
||||
The path to the node binary file.
|
||||
"""
|
||||
node_path = Path(constants.Node.PATH)
|
||||
if not node_path.exists():
|
||||
if use_system_node() or not node_path.exists():
|
||||
return str(which("node"))
|
||||
return str(node_path)
|
||||
|
||||
|
@ -74,6 +74,18 @@ def get_web_dir() -> Path:
|
||||
return workdir
|
||||
|
||||
|
||||
def _python_version_check():
|
||||
"""Emit deprecation warning for deprecated python versions."""
|
||||
# Check for end-of-life python versions.
|
||||
if sys.version_info < (3, 10):
|
||||
console.deprecate(
|
||||
feature_name="Support for Python 3.9 and older",
|
||||
reason="please upgrade to Python 3.10 or newer",
|
||||
deprecation_version="0.6.0",
|
||||
removal_version="0.7.0",
|
||||
)
|
||||
|
||||
|
||||
def check_latest_package_version(package_name: str):
|
||||
"""Check if the latest version of the package is installed.
|
||||
|
||||
@ -86,15 +98,16 @@ def check_latest_package_version(package_name: str):
|
||||
url = f"https://pypi.org/pypi/{package_name}/json"
|
||||
response = net.get(url)
|
||||
latest_version = response.json()["info"]["version"]
|
||||
if (
|
||||
version.parse(current_version) < version.parse(latest_version)
|
||||
and not get_or_set_last_reflex_version_check_datetime()
|
||||
):
|
||||
# only show a warning when the host version is outdated and
|
||||
# the last_version_check_datetime is not set in reflex.json
|
||||
if get_or_set_last_reflex_version_check_datetime():
|
||||
# Versions were already checked and saved in reflex.json, no need to warn again
|
||||
return
|
||||
if version.parse(current_version) < version.parse(latest_version):
|
||||
# Show a warning when the host version is older than PyPI version
|
||||
console.warn(
|
||||
f"Your version ({current_version}) of {package_name} is out of date. Upgrade to {latest_version} with 'pip install {package_name} --upgrade'"
|
||||
)
|
||||
# Check for depreacted python versions
|
||||
_python_version_check()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@ -130,7 +143,7 @@ def check_node_version() -> bool:
|
||||
# Compare the version numbers
|
||||
return (
|
||||
current_version >= version.parse(constants.Node.MIN_VERSION)
|
||||
if constants.IS_WINDOWS
|
||||
if constants.IS_WINDOWS or path_ops.use_system_node()
|
||||
else current_version == version.parse(constants.Node.VERSION)
|
||||
)
|
||||
return False
|
||||
@ -291,7 +304,7 @@ def get_compiled_app(reload: bool = False, export: bool = False) -> ModuleType:
|
||||
"""
|
||||
app_module = get_app(reload=reload)
|
||||
app = getattr(app_module, constants.CompileVars.APP)
|
||||
# For py3.8 and py3.9 compatibility when redis is used, we MUST add any decorator pages
|
||||
# For py3.9 compatibility when redis is used, we MUST add any decorator pages
|
||||
# before compiling the app in a thread to avoid event loop error (REF-2172).
|
||||
app._apply_decorated_pages()
|
||||
app._compile(export=export)
|
||||
@ -1021,6 +1034,8 @@ def validate_bun():
|
||||
# if a custom bun path is provided, make sure its valid
|
||||
# This is specific to non-FHS OS
|
||||
bun_path = get_config().bun_path
|
||||
if path_ops.use_system_bun():
|
||||
bun_path = path_ops.which("bun")
|
||||
if bun_path != constants.Bun.DEFAULT_PATH:
|
||||
console.info(f"Using custom Bun path: {bun_path}")
|
||||
bun_version = get_bun_version()
|
||||
@ -1481,13 +1496,20 @@ def initialize_main_module_index_from_generation(app_name: str, generation_hash:
|
||||
|
||||
main_module_path = Path(app_name, app_name + constants.Ext.PY)
|
||||
main_module_code = main_module_path.read_text()
|
||||
main_module_path.write_text(
|
||||
re.sub(
|
||||
|
||||
main_module_code = re.sub(
|
||||
r"def index\(\).*:\n([^\n]\s+.*\n+)+",
|
||||
replace_content,
|
||||
main_module_code,
|
||||
)
|
||||
# Make the app use light mode until flexgen enforces the conversion of
|
||||
# tailwind colors to radix colors.
|
||||
main_module_code = re.sub(
|
||||
r"app\s*=\s*rx\.App\(\s*\)",
|
||||
'app = rx.App(theme=rx.theme(color_mode="light"))',
|
||||
main_module_code,
|
||||
)
|
||||
main_module_path.write_text(main_module_code)
|
||||
|
||||
|
||||
def format_address_width(address_width) -> int | None:
|
||||
|
@ -12,7 +12,6 @@ from pathlib import Path
|
||||
from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
Dict,
|
||||
List,
|
||||
Literal,
|
||||
Optional,
|
||||
@ -126,7 +125,8 @@ def serialize(
|
||||
# If there is no serializer, return None.
|
||||
if serializer is None:
|
||||
if dataclasses.is_dataclass(value) and not isinstance(value, type):
|
||||
return serialize(dataclasses.asdict(value))
|
||||
return {k.name: getattr(value, k.name) for k in dataclasses.fields(value)}
|
||||
|
||||
if get_type:
|
||||
return None, None
|
||||
return None
|
||||
@ -214,32 +214,6 @@ def serialize_type(value: type) -> str:
|
||||
return value.__name__
|
||||
|
||||
|
||||
@serializer
|
||||
def serialize_str(value: str) -> str:
|
||||
"""Serialize a string.
|
||||
|
||||
Args:
|
||||
value: The string to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized string.
|
||||
"""
|
||||
return value
|
||||
|
||||
|
||||
@serializer
|
||||
def serialize_primitive(value: Union[bool, int, float, None]):
|
||||
"""Serialize a primitive type.
|
||||
|
||||
Args:
|
||||
value: The number/bool/None to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized number/bool/None.
|
||||
"""
|
||||
return value
|
||||
|
||||
|
||||
@serializer
|
||||
def serialize_base(value: Base) -> dict:
|
||||
"""Serialize a Base instance.
|
||||
@ -250,33 +224,20 @@ def serialize_base(value: Base) -> dict:
|
||||
Returns:
|
||||
The serialized Base.
|
||||
"""
|
||||
return {k: serialize(v) for k, v in value.dict().items() if not callable(v)}
|
||||
return {k: v for k, v in value.dict().items() if not callable(v)}
|
||||
|
||||
|
||||
@serializer
|
||||
def serialize_list(value: Union[List, Tuple, Set]) -> list:
|
||||
"""Serialize a list to a JSON string.
|
||||
def serialize_set(value: Set) -> list:
|
||||
"""Serialize a set to a JSON serializable list.
|
||||
|
||||
Args:
|
||||
value: The list to serialize.
|
||||
value: The set to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized list.
|
||||
"""
|
||||
return [serialize(item) for item in value]
|
||||
|
||||
|
||||
@serializer
|
||||
def serialize_dict(prop: Dict[str, Any]) -> dict:
|
||||
"""Serialize a dictionary to a JSON string.
|
||||
|
||||
Args:
|
||||
prop: The dictionary to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized dictionary.
|
||||
"""
|
||||
return {k: serialize(v) for k, v in prop.items()}
|
||||
return list(value)
|
||||
|
||||
|
||||
@serializer(to=str)
|
||||
|
@ -121,7 +121,7 @@ def _prepare_event(event: str, **kwargs) -> dict:
|
||||
return {}
|
||||
|
||||
if UTC is None:
|
||||
# for python 3.10
|
||||
# for python 3.9 & 3.10
|
||||
stamp = datetime.utcnow().isoformat()
|
||||
else:
|
||||
# for python 3.11 & 3.12
|
||||
|
@ -9,6 +9,7 @@ import sys
|
||||
import types
|
||||
from functools import cached_property, lru_cache, wraps
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Callable,
|
||||
ClassVar,
|
||||
@ -96,8 +97,22 @@ PrimitiveType = Union[int, float, bool, str, list, dict, set, tuple]
|
||||
StateVar = Union[PrimitiveType, Base, None]
|
||||
StateIterVar = Union[list, set, tuple]
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from reflex.vars.base import Var
|
||||
|
||||
# ArgsSpec = Callable[[Var], list[Var]]
|
||||
ArgsSpec = Callable
|
||||
ArgsSpec = (
|
||||
Callable[[], List[Var]]
|
||||
| Callable[[Var], List[Var]]
|
||||
| Callable[[Var, Var], List[Var]]
|
||||
| Callable[[Var, Var, Var], List[Var]]
|
||||
| Callable[[Var, Var, Var, Var], List[Var]]
|
||||
| Callable[[Var, Var, Var, Var, Var], List[Var]]
|
||||
| Callable[[Var, Var, Var, Var, Var, Var], List[Var]]
|
||||
| Callable[[Var, Var, Var, Var, Var, Var, Var], List[Var]]
|
||||
)
|
||||
else:
|
||||
ArgsSpec = Callable[..., List[Any]]
|
||||
|
||||
|
||||
PrimitiveToAnnotation = {
|
||||
@ -632,7 +647,7 @@ def validate_parameter_literals(func):
|
||||
annotations = {param[0]: param[1].annotation for param in func_params}
|
||||
|
||||
# validate args
|
||||
for param, arg in zip(annotations, args, strict=False):
|
||||
for param, arg in zip(annotations, args):
|
||||
if annotations[param] is inspect.Parameter.empty:
|
||||
continue
|
||||
validate_literal(param, arg, annotations[param], func.__name__)
|
||||
|
@ -1141,7 +1141,7 @@ def serialize_literal(value: LiteralVar):
|
||||
Returns:
|
||||
The serialized Literal.
|
||||
"""
|
||||
return serializers.serialize(value._var_value)
|
||||
return value._var_value
|
||||
|
||||
|
||||
P = ParamSpec("P")
|
||||
@ -1559,8 +1559,9 @@ class ComputedVar(Var[RETURN_TYPE]):
|
||||
Raises:
|
||||
TypeError: If the computed var dependencies are not Var instances or var names.
|
||||
"""
|
||||
hints = get_type_hints(fget)
|
||||
hint = hints.get("return", Any)
|
||||
hint = kwargs.pop("return_type", None) or get_type_hints(fget).get(
|
||||
"return", Any
|
||||
)
|
||||
|
||||
kwargs["_js_expr"] = kwargs.pop("_js_expr", fget.__name__)
|
||||
kwargs["_var_type"] = kwargs.pop("_var_type", hint)
|
||||
@ -2667,7 +2668,7 @@ def generic_type_to_actual_type_map(
|
||||
# call recursively for nested generic types and merge the results
|
||||
return {
|
||||
k: v
|
||||
for generic_arg, actual_arg in zip(generic_args, actual_args, strict=False)
|
||||
for generic_arg, actual_arg in zip(generic_args, actual_args)
|
||||
for k, v in generic_type_to_actual_type_map(generic_arg, actual_arg).items()
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ from typing import (
|
||||
from reflex.constants.base import Dirs
|
||||
from reflex.utils.exceptions import PrimitiveUnserializableToJSON, VarTypeError
|
||||
from reflex.utils.imports import ImportDict, ImportVar
|
||||
from reflex.utils.types import is_optional
|
||||
|
||||
from .base import (
|
||||
CustomVarOperationReturn,
|
||||
@ -524,6 +525,8 @@ class NumberVar(Var[NUMBER_T]):
|
||||
Returns:
|
||||
The boolean value of the number.
|
||||
"""
|
||||
if is_optional(self._var_type):
|
||||
return boolify((self != None) & (self != 0)) # noqa: E711
|
||||
return self != 0
|
||||
|
||||
def _is_strict_float(self) -> bool:
|
||||
|
@ -194,14 +194,6 @@ class StringVar(Var[str]):
|
||||
"""
|
||||
return string_strip_operation(self)
|
||||
|
||||
def bool(self):
|
||||
"""Boolean conversion.
|
||||
|
||||
Returns:
|
||||
The boolean value of the string.
|
||||
"""
|
||||
return self.length() != 0
|
||||
|
||||
def reversed(self) -> StringVar:
|
||||
"""Reverse the string.
|
||||
|
||||
@ -600,6 +592,29 @@ class LiteralStringVar(LiteralVar, StringVar):
|
||||
else:
|
||||
return only_string.to(StringVar, only_string._var_type)
|
||||
|
||||
if len(
|
||||
literal_strings := [
|
||||
s
|
||||
for s in filtered_strings_and_vals
|
||||
if isinstance(s, (str, LiteralStringVar))
|
||||
]
|
||||
) == len(filtered_strings_and_vals):
|
||||
return LiteralStringVar.create(
|
||||
"".join(
|
||||
s._var_value if isinstance(s, LiteralStringVar) else s
|
||||
for s in literal_strings
|
||||
),
|
||||
_var_type=_var_type,
|
||||
_var_data=VarData.merge(
|
||||
_var_data,
|
||||
*(
|
||||
s._get_all_var_data()
|
||||
for s in filtered_strings_and_vals
|
||||
if isinstance(s, Var)
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
concat_result = ConcatVarOperation.create(
|
||||
*filtered_strings_and_vals,
|
||||
_var_data=_var_data,
|
||||
@ -744,6 +759,26 @@ class ArrayVar(Var[ARRAY_VAR_TYPE]):
|
||||
"""
|
||||
if not isinstance(sep, (StringVar, str)):
|
||||
raise_unsupported_operand_types("join", (type(self), type(sep)))
|
||||
if (
|
||||
isinstance(self, LiteralArrayVar)
|
||||
and (
|
||||
len(
|
||||
args := [
|
||||
x
|
||||
for x in self._var_value
|
||||
if isinstance(x, (LiteralStringVar, str))
|
||||
]
|
||||
)
|
||||
== len(self._var_value)
|
||||
)
|
||||
and isinstance(sep, (LiteralStringVar, str))
|
||||
):
|
||||
sep_str = sep._var_value if isinstance(sep, LiteralStringVar) else sep
|
||||
return LiteralStringVar.create(
|
||||
sep_str.join(
|
||||
i._var_value if isinstance(i, LiteralStringVar) else i for i in args
|
||||
)
|
||||
)
|
||||
return array_join_operation(self, sep)
|
||||
|
||||
def reverse(self) -> ArrayVar[ARRAY_VAR_TYPE]:
|
||||
|
74
tests/components/el/test_svg.py
Normal file
74
tests/components/el/test_svg.py
Normal file
@ -0,0 +1,74 @@
|
||||
from reflex.components.el.elements.media import (
|
||||
Circle,
|
||||
Defs,
|
||||
Ellipse,
|
||||
Line,
|
||||
LinearGradient,
|
||||
Path,
|
||||
Polygon,
|
||||
RadialGradient,
|
||||
Rect,
|
||||
Stop,
|
||||
Svg,
|
||||
Text,
|
||||
)
|
||||
|
||||
|
||||
def test_circle():
|
||||
circle = Circle.create().render()
|
||||
assert circle["name"] == "circle"
|
||||
|
||||
|
||||
def test_defs():
|
||||
defs = Defs.create().render()
|
||||
assert defs["name"] == "defs"
|
||||
|
||||
|
||||
def test_ellipse():
|
||||
ellipse = Ellipse.create().render()
|
||||
assert ellipse["name"] == "ellipse"
|
||||
|
||||
|
||||
def test_line():
|
||||
line = Line.create().render()
|
||||
assert line["name"] == "line"
|
||||
|
||||
|
||||
def test_linear_gradient():
|
||||
linear_gradient = LinearGradient.create().render()
|
||||
assert linear_gradient["name"] == "linearGradient"
|
||||
|
||||
|
||||
def test_path():
|
||||
path = Path.create().render()
|
||||
assert path["name"] == "path"
|
||||
|
||||
|
||||
def test_polygon():
|
||||
polygon = Polygon.create().render()
|
||||
assert polygon["name"] == "polygon"
|
||||
|
||||
|
||||
def test_radial_gradient():
|
||||
radial_gradient = RadialGradient.create().render()
|
||||
assert radial_gradient["name"] == "radialGradient"
|
||||
|
||||
|
||||
def test_rect():
|
||||
rect = Rect.create().render()
|
||||
assert rect["name"] == "rect"
|
||||
|
||||
|
||||
def test_svg():
|
||||
svg = Svg.create().render()
|
||||
assert svg["name"] == "svg"
|
||||
|
||||
|
||||
def test_text():
|
||||
text = Text.create().render()
|
||||
assert text["name"] == "text"
|
||||
|
||||
|
||||
def test_stop():
|
||||
stop = Stop.create().render()
|
||||
assert stop["name"] == "stop"
|
@ -1,4 +1,4 @@
|
||||
FROM python:3.10
|
||||
FROM python:3.9
|
||||
|
||||
ARG USERNAME=kerrigan
|
||||
RUN useradd -m $USERNAME
|
@ -13,7 +13,7 @@ function do_export () {
|
||||
reflex init --template "$template"
|
||||
reflex export
|
||||
(
|
||||
cd "$SCRIPTPATH/../.."
|
||||
cd "$SCRIPTPATH/../../.."
|
||||
scripts/integration.sh ~/"$template" dev
|
||||
pkill -9 -f 'next-server|python3' || true
|
||||
sleep 10
|
167
tests/integration/test_dynamic_components.py
Normal file
167
tests/integration/test_dynamic_components.py
Normal file
@ -0,0 +1,167 @@
|
||||
"""Integration tests for var operations."""
|
||||
|
||||
import time
|
||||
from typing import Callable, Generator, TypeVar
|
||||
|
||||
import pytest
|
||||
from selenium.webdriver.common.by import By
|
||||
|
||||
from reflex.testing import AppHarness
|
||||
|
||||
# pyright: reportOptionalMemberAccess=false, reportGeneralTypeIssues=false, reportUnknownMemberType=false
|
||||
|
||||
|
||||
def DynamicComponents():
|
||||
"""App with var operations."""
|
||||
import reflex as rx
|
||||
|
||||
class DynamicComponentsState(rx.State):
|
||||
value: int = 10
|
||||
|
||||
button: rx.Component = rx.button(
|
||||
"Click me",
|
||||
custom_attrs={
|
||||
"id": "button",
|
||||
},
|
||||
)
|
||||
|
||||
def got_clicked(self):
|
||||
self.button = rx.button(
|
||||
"Clicked",
|
||||
custom_attrs={
|
||||
"id": "button",
|
||||
},
|
||||
)
|
||||
|
||||
@rx.var
|
||||
def client_token_component(self) -> rx.Component:
|
||||
return rx.vstack(
|
||||
rx.el.input(
|
||||
custom_attrs={
|
||||
"id": "token",
|
||||
},
|
||||
value=self.router.session.client_token,
|
||||
is_read_only=True,
|
||||
),
|
||||
rx.button(
|
||||
"Update",
|
||||
custom_attrs={
|
||||
"id": "update",
|
||||
},
|
||||
on_click=DynamicComponentsState.got_clicked,
|
||||
),
|
||||
)
|
||||
|
||||
app = rx.App()
|
||||
|
||||
def factorial(n: int) -> int:
|
||||
if n == 0:
|
||||
return 1
|
||||
return n * factorial(n - 1)
|
||||
|
||||
@app.add_page
|
||||
def index():
|
||||
return rx.vstack(
|
||||
DynamicComponentsState.client_token_component,
|
||||
DynamicComponentsState.button,
|
||||
rx.text(
|
||||
DynamicComponentsState._evaluate(lambda state: factorial(state.value)),
|
||||
id="factorial",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def dynamic_components(tmp_path_factory) -> Generator[AppHarness, None, None]:
|
||||
"""Start VarOperations app at tmp_path via AppHarness.
|
||||
|
||||
Args:
|
||||
tmp_path_factory: pytest tmp_path_factory fixture
|
||||
|
||||
Yields:
|
||||
running AppHarness instance
|
||||
"""
|
||||
with AppHarness.create(
|
||||
root=tmp_path_factory.mktemp("dynamic_components"),
|
||||
app_source=DynamicComponents, # type: ignore
|
||||
) as harness:
|
||||
assert harness.app_instance is not None, "app is not running"
|
||||
yield harness
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def poll_for_result(
|
||||
f: Callable[[], T], exception=Exception, max_attempts=5, seconds_between_attempts=1
|
||||
) -> T:
|
||||
"""Poll for a result from a function.
|
||||
|
||||
Args:
|
||||
f: function to call
|
||||
exception: exception to catch
|
||||
max_attempts: maximum number of attempts
|
||||
seconds_between_attempts: seconds to wait between
|
||||
|
||||
Returns:
|
||||
Result of the function
|
||||
|
||||
Raises:
|
||||
AssertionError: if the function does not return a value
|
||||
"""
|
||||
attempts = 0
|
||||
while attempts < max_attempts:
|
||||
try:
|
||||
return f()
|
||||
except exception:
|
||||
attempts += 1
|
||||
time.sleep(seconds_between_attempts)
|
||||
raise AssertionError("Function did not return a value")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def driver(dynamic_components: AppHarness):
|
||||
"""Get an instance of the browser open to the dynamic components app.
|
||||
|
||||
Args:
|
||||
dynamic_components: AppHarness for the dynamic components
|
||||
|
||||
Yields:
|
||||
WebDriver instance.
|
||||
"""
|
||||
driver = dynamic_components.frontend()
|
||||
try:
|
||||
token_input = poll_for_result(lambda: driver.find_element(By.ID, "token"))
|
||||
assert token_input
|
||||
# wait for the backend connection to send the token
|
||||
token = dynamic_components.poll_for_value(token_input)
|
||||
assert token is not None
|
||||
|
||||
yield driver
|
||||
finally:
|
||||
driver.quit()
|
||||
|
||||
|
||||
def test_dynamic_components(driver, dynamic_components: AppHarness):
|
||||
"""Test that the var operations produce the right results.
|
||||
|
||||
Args:
|
||||
driver: selenium WebDriver open to the app
|
||||
dynamic_components: AppHarness for the dynamic components
|
||||
"""
|
||||
button = poll_for_result(lambda: driver.find_element(By.ID, "button"))
|
||||
assert button
|
||||
assert button.text == "Click me"
|
||||
|
||||
update_button = driver.find_element(By.ID, "update")
|
||||
assert update_button
|
||||
update_button.click()
|
||||
|
||||
assert (
|
||||
dynamic_components.poll_for_content(button, exp_not_equal="Click me")
|
||||
== "Clicked"
|
||||
)
|
||||
|
||||
factorial = poll_for_result(lambda: driver.find_element(By.ID, "factorial"))
|
||||
assert factorial
|
||||
assert factorial.text == "3628800"
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user