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:
|
matrix:
|
||||||
# Show OS combos first in GUI
|
# Show OS combos first in GUI
|
||||||
os: [ubuntu-latest, windows-latest, macos-12]
|
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:
|
exclude:
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
python-version: '3.10.13'
|
python-version: '3.10.13'
|
||||||
|
- os: windows-latest
|
||||||
|
python-version: '3.9.18'
|
||||||
# keep only one python version for MacOS
|
# keep only one python version for MacOS
|
||||||
|
- os: macos-latest
|
||||||
|
python-version: '3.9.18'
|
||||||
- os: macos-latest
|
- os: macos-latest
|
||||||
python-version: '3.10.13'
|
python-version: '3.10.13'
|
||||||
- os: macos-12
|
- os: macos-12
|
||||||
@ -93,6 +97,8 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
python-version: '3.10.11'
|
python-version: '3.10.11'
|
||||||
|
- os: windows-latest
|
||||||
|
python-version: '3.9.13'
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
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
|
SCREENSHOT_DIR: /tmp/screenshots
|
||||||
REDIS_URL: ${{ matrix.state_manager == 'redis' && 'redis://localhost:6379' || '' }}
|
REDIS_URL: ${{ matrix.state_manager == 'redis' && 'redis://localhost:6379' || '' }}
|
||||||
run: |
|
run: |
|
||||||
poetry run pytest integration
|
poetry run pytest tests/integration
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
name: Upload failed test screenshots
|
name: Upload failed test screenshots
|
||||||
if: always()
|
if: always()
|
||||||
|
7
.github/workflows/integration_tests.yml
vendored
7
.github/workflows/integration_tests.yml
vendored
@ -43,14 +43,17 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
# Show OS combos first in GUI
|
# Show OS combos first in GUI
|
||||||
os: [ubuntu-latest, windows-latest, macos-12]
|
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:
|
exclude:
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
python-version: '3.10.13'
|
python-version: '3.10.13'
|
||||||
|
- os: windows-latest
|
||||||
|
python-version: '3.9.18'
|
||||||
include:
|
include:
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
python-version: '3.10.11'
|
python-version: '3.10.11'
|
||||||
|
- os: windows-latest
|
||||||
|
python-version: '3.9.13'
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
|
@ -28,5 +28,5 @@ jobs:
|
|||||||
# Run reflex init in a docker container
|
# Run reflex init in a docker container
|
||||||
|
|
||||||
# cwd is repo root
|
# cwd is repo root
|
||||||
docker build -f integration/init-test/Dockerfile -t reflex-init-test integration/init-test
|
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/integration/init-test/in_docker_test_script.sh
|
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
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest, macos-12]
|
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
|
# Windows is a bit behind on Python version availability in Github
|
||||||
exclude:
|
exclude:
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
python-version: '3.10.13'
|
python-version: '3.10.13'
|
||||||
|
- os: windows-latest
|
||||||
|
python-version: '3.9.18'
|
||||||
include:
|
include:
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
python-version: '3.10.11'
|
python-version: '3.10.11'
|
||||||
|
- os: windows-latest
|
||||||
|
python-version: '3.9.13'
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
# Service containers to run with `runner-job`
|
# Service containers to run with `runner-job`
|
||||||
services:
|
services:
|
||||||
@ -61,17 +65,17 @@ jobs:
|
|||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
run: |
|
run: |
|
||||||
export PYTHONUNBUFFERED=1
|
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
|
- name: Run unit tests w/ redis
|
||||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||||
run: |
|
run: |
|
||||||
export PYTHONUNBUFFERED=1
|
export PYTHONUNBUFFERED=1
|
||||||
export REDIS_URL=redis://localhost:6379
|
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
|
# Change to explicitly install v1 when reflex-hosting-cli is compatible with v2
|
||||||
- name: Run unit tests w/ pydantic v1
|
- name: Run unit tests w/ pydantic v1
|
||||||
run: |
|
run: |
|
||||||
export PYTHONUNBUFFERED=1
|
export PYTHONUNBUFFERED=1
|
||||||
poetry run uv pip install "pydantic~=1.10"
|
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
|
- run: poetry run coverage html
|
||||||
|
@ -6,7 +6,7 @@ repos:
|
|||||||
rev: v0.4.10
|
rev: v0.4.10
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff-format
|
- id: ruff-format
|
||||||
args: [integration, reflex, tests]
|
args: [reflex, tests]
|
||||||
- id: ruff
|
- id: ruff
|
||||||
args: ["--fix", "--exit-non-zero-on-fix"]
|
args: ["--fix", "--exit-non-zero-on-fix"]
|
||||||
exclude: '^integration/benchmarks/'
|
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:**
|
**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).
|
- 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:**
|
**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%.
|
This will fail if code coverage is below 70%.
|
||||||
|
|
||||||
``` bash
|
``` 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.
|
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.
|
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
|
``` bash
|
||||||
pre-commit install
|
pre-commit install
|
||||||
|
@ -34,7 +34,7 @@ See our [architecture page](https://reflex.dev/blog/2024-03-21-reflex-architectu
|
|||||||
|
|
||||||
## ⚙️ Installation
|
## ⚙️ Installation
|
||||||
|
|
||||||
Open a terminal and run (Requires Python 3.10+):
|
Open a terminal and run (Requires Python 3.9+):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install reflex
|
pip install reflex
|
||||||
|
@ -34,7 +34,7 @@ Auf unserer [Architektur-Seite](https://reflex.dev/blog/2024-03-21-reflex-archit
|
|||||||
|
|
||||||
## ⚙️ Installation
|
## ⚙️ 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
|
```bash
|
||||||
pip install reflex
|
pip install reflex
|
||||||
|
@ -35,7 +35,7 @@ Consulta nuestra [página de arquitectura](https://reflex.dev/blog/2024-03-21-re
|
|||||||
|
|
||||||
## ⚙️ Instalación
|
## ⚙️ Instalación
|
||||||
|
|
||||||
Abra un terminal y ejecute (Requiere Python 3.10+):
|
Abra un terminal y ejecute (Requiere Python 3.9+):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install reflex
|
pip install reflex
|
||||||
|
@ -35,7 +35,7 @@ Reflex के अंदर के कामकाज को जानने क
|
|||||||
|
|
||||||
## ⚙️ इंस्टॉलेशन (Installation)
|
## ⚙️ इंस्टॉलेशन (Installation)
|
||||||
|
|
||||||
एक टर्मिनल खोलें और चलाएं (Python 3.10+ की आवश्यकता है):
|
एक टर्मिनल खोलें और चलाएं (Python 3.9+ की आवश्यकता है):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install reflex
|
pip install reflex
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
## ⚙️ Installazione
|
## ⚙️ Installazione
|
||||||
|
|
||||||
Apri un terminale ed esegui (Richiede Python 3.10+):
|
Apri un terminale ed esegui (Richiede Python 3.9+):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install reflex
|
pip install reflex
|
||||||
|
@ -37,7 +37,7 @@ Reflex がどのように動作しているかを知るには、[アーキテク
|
|||||||
|
|
||||||
## ⚙️ インストール
|
## ⚙️ インストール
|
||||||
|
|
||||||
ターミナルを開いて以下のコマンドを実行してください。(Python 3.8 以上が必要です。):
|
ターミナルを開いて以下のコマンドを実行してください。(Python 3.9 以上が必要です。):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install reflex
|
pip install reflex
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
---
|
---
|
||||||
## ⚙️ 설치
|
## ⚙️ 설치
|
||||||
|
|
||||||
터미널을 열고 실행하세요. (Python 3.10+ 필요):
|
터미널을 열고 실행하세요. (Python 3.9+ 필요):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install reflex
|
pip install reflex
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
## ⚙️ Installation - نصب و راه اندازی
|
## ⚙️ Installation - نصب و راه اندازی
|
||||||
|
|
||||||
یک ترمینال را باز کنید و اجرا کنید (نیازمند Python 3.10+):
|
یک ترمینال را باز کنید و اجرا کنید (نیازمند Python 3.9+):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install reflex
|
pip install reflex
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
---
|
---
|
||||||
## ⚙️ Instalação
|
## ⚙️ Instalação
|
||||||
|
|
||||||
Abra um terminal e execute (Requer Python 3.10+):
|
Abra um terminal e execute (Requer Python 3.9+):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install reflex
|
pip install reflex
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
## ⚙️ Kurulum
|
## ⚙️ 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
|
```bash
|
||||||
pip install reflex
|
pip install reflex
|
||||||
|
@ -34,7 +34,7 @@ Reflex 是一个使用纯Python构建全栈web应用的库。
|
|||||||
|
|
||||||
## ⚙️ 安装
|
## ⚙️ 安装
|
||||||
|
|
||||||
打开一个终端并且运行(要求Python3.8+):
|
打开一个终端并且运行(要求Python3.9+):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install reflex
|
pip install reflex
|
||||||
|
@ -36,7 +36,7 @@ Reflex 是一個可以用純 Python 構建全端網頁應用程式的函式庫
|
|||||||
|
|
||||||
## ⚙️ 安裝
|
## ⚙️ 安裝
|
||||||
|
|
||||||
開啟一個終端機並且執行 (需要 Python 3.10+):
|
開啟一個終端機並且執行 (需要 Python 3.9+):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install reflex
|
pip install reflex
|
||||||
|
581
poetry.lock
generated
581
poetry.lock
generated
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alembic"
|
name = "alembic"
|
||||||
version = "1.13.2"
|
version = "1.13.3"
|
||||||
description = "A database migration tool for SQLAlchemy."
|
description = "A database migration tool for SQLAlchemy."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "alembic-1.13.2-py3-none-any.whl", hash = "sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953"},
|
{file = "alembic-1.13.3-py3-none-any.whl", hash = "sha256:908e905976d15235fae59c9ac42c4c5b75cfcefe3d27c0fbf7ae15a37715d80e"},
|
||||||
{file = "alembic-1.13.2.tar.gz", hash = "sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef"},
|
{file = "alembic-1.13.3.tar.gz", hash = "sha256:203503117415561e203aa14541740643a611f641517f0209fcae63e9fa09f1a2"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -32,13 +32,13 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyio"
|
name = "anyio"
|
||||||
version = "4.5.0"
|
version = "4.6.0"
|
||||||
description = "High level compatibility layer for multiple asynchronous event loop implementations"
|
description = "High level compatibility layer for multiple asynchronous event loop implementations"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "anyio-4.5.0-py3-none-any.whl", hash = "sha256:fdeb095b7cc5a5563175eedd926ec4ae55413bb4be5770c424af0ba46ccb4a78"},
|
{file = "anyio-4.6.0-py3-none-any.whl", hash = "sha256:c7d2e9d63e31599eeb636c8c5c03a7e108d73b345f064f1c19fdc87b79036a9a"},
|
||||||
{file = "anyio-4.5.0.tar.gz", hash = "sha256:c5a275fe5ca0afd788001f58fca1e69e29ce706d746e317d660e21f70c530ef9"},
|
{file = "anyio-4.6.0.tar.gz", hash = "sha256:137b4559cbb034c477165047febb6ff83f390fc3b20bf181c1fc0a728cb8beeb"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -616,77 +616,69 @@ typing = ["typing-extensions (>=4.12.2)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "greenlet"
|
name = "greenlet"
|
||||||
version = "3.1.0"
|
version = "3.0.3"
|
||||||
description = "Lightweight in-process concurrent programming"
|
description = "Lightweight in-process concurrent programming"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "greenlet-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a814dc3100e8a046ff48faeaa909e80cdb358411a3d6dd5293158425c684eda8"},
|
{file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"},
|
||||||
{file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a771dc64fa44ebe58d65768d869fcfb9060169d203446c1d446e844b62bdfdca"},
|
{file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"},
|
||||||
{file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0e49a65d25d7350cca2da15aac31b6f67a43d867448babf997fe83c7505f57bc"},
|
{file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"},
|
||||||
{file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2cd8518eade968bc52262d8c46727cfc0826ff4d552cf0430b8d65aaf50bb91d"},
|
{file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"},
|
||||||
{file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76dc19e660baea5c38e949455c1181bc018893f25372d10ffe24b3ed7341fb25"},
|
{file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"},
|
||||||
{file = "greenlet-3.1.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c0a5b1c22c82831f56f2f7ad9bbe4948879762fe0d59833a4a71f16e5fa0f682"},
|
{file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"},
|
||||||
{file = "greenlet-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2651dfb006f391bcb240635079a68a261b227a10a08af6349cba834a2141efa1"},
|
{file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"},
|
||||||
{file = "greenlet-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3e7e6ef1737a819819b1163116ad4b48d06cfdd40352d813bb14436024fcda99"},
|
{file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"},
|
||||||
{file = "greenlet-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:ffb08f2a1e59d38c7b8b9ac8083c9c8b9875f0955b1e9b9b9a965607a51f8e54"},
|
{file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"},
|
||||||
{file = "greenlet-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9730929375021ec90f6447bff4f7f5508faef1c02f399a1953870cdb78e0c345"},
|
{file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"},
|
||||||
{file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:713d450cf8e61854de9420fb7eea8ad228df4e27e7d4ed465de98c955d2b3fa6"},
|
{file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"},
|
||||||
{file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c3446937be153718250fe421da548f973124189f18fe4575a0510b5c928f0cc"},
|
{file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"},
|
||||||
{file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ddc7bcedeb47187be74208bc652d63d6b20cb24f4e596bd356092d8000da6d6"},
|
{file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"},
|
||||||
{file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44151d7b81b9391ed759a2f2865bbe623ef00d648fed59363be2bbbd5154656f"},
|
{file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"},
|
||||||
{file = "greenlet-3.1.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cea1cca3be76c9483282dc7760ea1cc08a6ecec1f0b6ca0a94ea0d17432da19"},
|
{file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"},
|
||||||
{file = "greenlet-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:619935a44f414274a2c08c9e74611965650b730eb4efe4b2270f91df5e4adf9a"},
|
{file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"},
|
||||||
{file = "greenlet-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:221169d31cada333a0c7fd087b957c8f431c1dba202c3a58cf5a3583ed973e9b"},
|
{file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"},
|
||||||
{file = "greenlet-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:01059afb9b178606b4b6e92c3e710ea1635597c3537e44da69f4531e111dd5e9"},
|
{file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"},
|
||||||
{file = "greenlet-3.1.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:24fc216ec7c8be9becba8b64a98a78f9cd057fd2dc75ae952ca94ed8a893bf27"},
|
{file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"},
|
||||||
{file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d07c28b85b350564bdff9f51c1c5007dfb2f389385d1bc23288de51134ca303"},
|
{file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"},
|
||||||
{file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:243a223c96a4246f8a30ea470c440fe9db1f5e444941ee3c3cd79df119b8eebf"},
|
{file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"},
|
||||||
{file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26811df4dc81271033a7836bc20d12cd30938e6bd2e9437f56fa03da81b0f8fc"},
|
{file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"},
|
||||||
{file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9d86401550b09a55410f32ceb5fe7efcd998bd2dad9e82521713cb148a4a15f"},
|
{file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"},
|
||||||
{file = "greenlet-3.1.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:26d9c1c4f1748ccac0bae1dbb465fb1a795a75aba8af8ca871503019f4285e2a"},
|
{file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"},
|
||||||
{file = "greenlet-3.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:cd468ec62257bb4544989402b19d795d2305eccb06cde5da0eb739b63dc04665"},
|
{file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"},
|
||||||
{file = "greenlet-3.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a53dfe8f82b715319e9953330fa5c8708b610d48b5c59f1316337302af5c0811"},
|
{file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"},
|
||||||
{file = "greenlet-3.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:28fe80a3eb673b2d5cc3b12eea468a5e5f4603c26aa34d88bf61bba82ceb2f9b"},
|
{file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"},
|
||||||
{file = "greenlet-3.1.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:76b3e3976d2a452cba7aa9e453498ac72240d43030fdc6d538a72b87eaff52fd"},
|
{file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"},
|
||||||
{file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655b21ffd37a96b1e78cc48bf254f5ea4b5b85efaf9e9e2a526b3c9309d660ca"},
|
{file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"},
|
||||||
{file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6f4c2027689093775fd58ca2388d58789009116844432d920e9147f91acbe64"},
|
{file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"},
|
||||||
{file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76e5064fd8e94c3f74d9fd69b02d99e3cdb8fc286ed49a1f10b256e59d0d3a0b"},
|
{file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"},
|
||||||
{file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a4bf607f690f7987ab3291406e012cd8591a4f77aa54f29b890f9c331e84989"},
|
{file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"},
|
||||||
{file = "greenlet-3.1.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:037d9ac99540ace9424cb9ea89f0accfaff4316f149520b4ae293eebc5bded17"},
|
{file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"},
|
||||||
{file = "greenlet-3.1.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:90b5bbf05fe3d3ef697103850c2ce3374558f6fe40fd57c9fac1bf14903f50a5"},
|
{file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"},
|
||||||
{file = "greenlet-3.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:726377bd60081172685c0ff46afbc600d064f01053190e4450857483c4d44484"},
|
{file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"},
|
||||||
{file = "greenlet-3.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:d46d5069e2eeda111d6f71970e341f4bd9aeeee92074e649ae263b834286ecc0"},
|
{file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"},
|
||||||
{file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81eeec4403a7d7684b5812a8aaa626fa23b7d0848edb3a28d2eb3220daddcbd0"},
|
{file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"},
|
||||||
{file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a3dae7492d16e85ea6045fd11cb8e782b63eac8c8d520c3a92c02ac4573b0a6"},
|
{file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"},
|
||||||
{file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b5ea3664eed571779403858d7cd0a9b0ebf50d57d2cdeafc7748e09ef8cd81a"},
|
{file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"},
|
||||||
{file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a22f4e26400f7f48faef2d69c20dc055a1f3043d330923f9abe08ea0aecc44df"},
|
{file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"},
|
||||||
{file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13ff8c8e54a10472ce3b2a2da007f915175192f18e6495bad50486e87c7f6637"},
|
{file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"},
|
||||||
{file = "greenlet-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9671e7282d8c6fcabc32c0fb8d7c0ea8894ae85cee89c9aadc2d7129e1a9954"},
|
{file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"},
|
||||||
{file = "greenlet-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:184258372ae9e1e9bddce6f187967f2e08ecd16906557c4320e3ba88a93438c3"},
|
{file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"},
|
||||||
{file = "greenlet-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:a0409bc18a9f85321399c29baf93545152d74a49d92f2f55302f122007cfda00"},
|
{file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"},
|
||||||
{file = "greenlet-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9eb4a1d7399b9f3c7ac68ae6baa6be5f9195d1d08c9ddc45ad559aa6b556bce6"},
|
{file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"},
|
||||||
{file = "greenlet-3.1.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:a8870983af660798dc1b529e1fd6f1cefd94e45135a32e58bd70edd694540f33"},
|
{file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"},
|
||||||
{file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfcfb73aed40f550a57ea904629bdaf2e562c68fa1164fa4588e752af6efdc3f"},
|
{file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"},
|
||||||
{file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9482c2ed414781c0af0b35d9d575226da6b728bd1a720668fa05837184965b7"},
|
{file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"},
|
||||||
{file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d58ec349e0c2c0bc6669bf2cd4982d2f93bf067860d23a0ea1fe677b0f0b1e09"},
|
{file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"},
|
||||||
{file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd65695a8df1233309b701dec2539cc4b11e97d4fcc0f4185b4a12ce54db0491"},
|
{file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"},
|
||||||
{file = "greenlet-3.1.0-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:665b21e95bc0fce5cab03b2e1d90ba9c66c510f1bb5fdc864f3a377d0f553f6b"},
|
{file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"},
|
||||||
{file = "greenlet-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d3c59a06c2c28a81a026ff11fbf012081ea34fb9b7052f2ed0366e14896f0a1d"},
|
{file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"},
|
||||||
{file = "greenlet-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5415b9494ff6240b09af06b91a375731febe0090218e2898d2b85f9b92abcda0"},
|
{file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"},
|
||||||
{file = "greenlet-3.1.0-cp38-cp38-win32.whl", hash = "sha256:1544b8dd090b494c55e60c4ff46e238be44fdc472d2589e943c241e0169bcea2"},
|
{file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"},
|
||||||
{file = "greenlet-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:7f346d24d74c00b6730440f5eb8ec3fe5774ca8d1c9574e8e57c8671bb51b910"},
|
{file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"},
|
||||||
{file = "greenlet-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:db1b3ccb93488328c74e97ff888604a8b95ae4f35f4f56677ca57a4fc3a4220b"},
|
{file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"},
|
||||||
{file = "greenlet-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44cd313629ded43bb3b98737bba2f3e2c2c8679b55ea29ed73daea6b755fe8e7"},
|
{file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"},
|
||||||
{file = "greenlet-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fad7a051e07f64e297e6e8399b4d6a3bdcad3d7297409e9a06ef8cbccff4f501"},
|
{file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"},
|
||||||
{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"},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
@ -921,13 +913,13 @@ i18n = ["Babel (>=2.7)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "keyring"
|
name = "keyring"
|
||||||
version = "25.4.0"
|
version = "25.4.1"
|
||||||
description = "Store and access your passwords safely."
|
description = "Store and access your passwords safely."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "keyring-25.4.0-py3-none-any.whl", hash = "sha256:a2a630d5c9bef5d3f0968d15ef4e42b894a83e17494edcb67b154c36491c9920"},
|
{file = "keyring-25.4.1-py3-none-any.whl", hash = "sha256:5426f817cf7f6f007ba5ec722b1bcad95a75b27d780343772ad76b17cb47b0bf"},
|
||||||
{file = "keyring-25.4.0.tar.gz", hash = "sha256:ae8263fd9264c94f91ad82d098f8a5bb1b7fa71ce0a72388dc4fc0be3f6a034e"},
|
{file = "keyring-25.4.1.tar.gz", hash = "sha256:b07ebc55f3e8ed86ac81dd31ef14e81ace9dd9c3d4b5d77a6e9a2016d0d71a1b"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -1137,6 +1129,60 @@ files = [
|
|||||||
{file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"},
|
{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]]
|
[[package]]
|
||||||
name = "numpy"
|
name = "numpy"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
@ -1226,40 +1272,53 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pandas"
|
name = "pandas"
|
||||||
version = "2.2.2"
|
version = "2.2.3"
|
||||||
description = "Powerful data structures for data analysis, time series, and statistics"
|
description = "Powerful data structures for data analysis, time series, and statistics"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.9"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "pandas-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce"},
|
{file = "pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5"},
|
||||||
{file = "pandas-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238"},
|
{file = "pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348"},
|
||||||
{file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08"},
|
{file = "pandas-2.2.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed"},
|
||||||
{file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0"},
|
{file = "pandas-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57"},
|
||||||
{file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51"},
|
{file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42"},
|
||||||
{file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99"},
|
{file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f"},
|
||||||
{file = "pandas-2.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772"},
|
{file = "pandas-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645"},
|
||||||
{file = "pandas-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288"},
|
{file = "pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039"},
|
||||||
{file = "pandas-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151"},
|
{file = "pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd"},
|
||||||
{file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b"},
|
{file = "pandas-2.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698"},
|
||||||
{file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee"},
|
{file = "pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc"},
|
||||||
{file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db"},
|
{file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3"},
|
||||||
{file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1"},
|
{file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32"},
|
||||||
{file = "pandas-2.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24"},
|
{file = "pandas-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5"},
|
||||||
{file = "pandas-2.2.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef"},
|
{file = "pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9"},
|
||||||
{file = "pandas-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce"},
|
{file = "pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4"},
|
||||||
{file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad"},
|
{file = "pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3"},
|
||||||
{file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad"},
|
{file = "pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319"},
|
||||||
{file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76"},
|
{file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8"},
|
||||||
{file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32"},
|
{file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a"},
|
||||||
{file = "pandas-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23"},
|
{file = "pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13"},
|
||||||
{file = "pandas-2.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2"},
|
{file = "pandas-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015"},
|
||||||
{file = "pandas-2.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd"},
|
{file = "pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28"},
|
||||||
{file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863"},
|
{file = "pandas-2.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0"},
|
||||||
{file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921"},
|
{file = "pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24"},
|
||||||
{file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a"},
|
{file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659"},
|
||||||
{file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57"},
|
{file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb"},
|
||||||
{file = "pandas-2.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4"},
|
{file = "pandas-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d"},
|
||||||
{file = "pandas-2.2.2.tar.gz", hash = "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54"},
|
{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]
|
[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)"]
|
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"]
|
||||||
type = ["mypy (>=1.11.2)"]
|
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]]
|
[[package]]
|
||||||
name = "plotly"
|
name = "plotly"
|
||||||
version = "5.24.1"
|
version = "5.24.1"
|
||||||
@ -1676,6 +1755,23 @@ files = [
|
|||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
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]]
|
[[package]]
|
||||||
name = "pygments"
|
name = "pygments"
|
||||||
version = "2.18.0"
|
version = "2.18.0"
|
||||||
@ -1771,6 +1867,24 @@ pytest = ">=7.0.0"
|
|||||||
docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.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)"]
|
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]]
|
[[package]]
|
||||||
name = "pytest-benchmark"
|
name = "pytest-benchmark"
|
||||||
version = "4.0.0"
|
version = "4.0.0"
|
||||||
@ -1826,6 +1940,23 @@ pytest = ">=6.2.5"
|
|||||||
[package.extras]
|
[package.extras]
|
||||||
dev = ["pre-commit", "pytest-asyncio", "tox"]
|
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]]
|
[[package]]
|
||||||
name = "python-dateutil"
|
name = "python-dateutil"
|
||||||
version = "2.9.0.post0"
|
version = "2.9.0.post0"
|
||||||
@ -1861,17 +1992,31 @@ docs = ["sphinx"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-multipart"
|
name = "python-multipart"
|
||||||
version = "0.0.9"
|
version = "0.0.10"
|
||||||
description = "A streaming multipart parser for Python"
|
description = "A streaming multipart parser for Python"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "python_multipart-0.0.9-py3-none-any.whl", hash = "sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215"},
|
{file = "python_multipart-0.0.10-py3-none-any.whl", hash = "sha256:2b06ad9e8d50c7a8db80e3b56dab590137b323410605af2be20d62a5f1ba1dc8"},
|
||||||
{file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"},
|
{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]
|
[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]]
|
[[package]]
|
||||||
name = "python-socketio"
|
name = "python-socketio"
|
||||||
@ -2016,13 +2161,13 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reflex-chakra"
|
name = "reflex-chakra"
|
||||||
version = "0.6.0a7"
|
version = "0.6.0"
|
||||||
description = "reflex using chakra components"
|
description = "reflex using chakra components"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "<4.0,>=3.8"
|
python-versions = "<4.0,>=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "reflex_chakra-0.6.0a7-py3-none-any.whl", hash = "sha256:d693aee7323af13ce491165ffb4fe392344939e45516991671d5601727f749f4"},
|
{file = "reflex_chakra-0.6.0-py3-none-any.whl", hash = "sha256:eca1593fca67289e05591dd21fbcc8632c119d64a08bdc41fd995055a114cc91"},
|
||||||
{file = "reflex_chakra-0.6.0a7.tar.gz", hash = "sha256:fe17282e439fdfdfd507e24857a615258ef9789f15049aa0e70239fbcb4d5fbf"},
|
{file = "reflex_chakra-0.6.0.tar.gz", hash = "sha256:db1c7b48f1ba547bf91e5af103fce6fc7191d7225b414ebfbada7d983e33dd87"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -2161,13 +2306,13 @@ jeepney = ">=0.6"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "selenium"
|
name = "selenium"
|
||||||
version = "4.24.0"
|
version = "4.25.0"
|
||||||
description = "Official Python bindings for Selenium WebDriver"
|
description = "Official Python bindings for Selenium WebDriver"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "selenium-4.24.0-py3-none-any.whl", hash = "sha256:42c23f60753d5415b261b236cecbd69bd4eb5271e1563915f546b443cb6b71c6"},
|
{file = "selenium-4.25.0-py3-none-any.whl", hash = "sha256:3798d2d12b4a570bc5790163ba57fef10b2afee958bf1d80f2a3cf07c4141f33"},
|
||||||
{file = "selenium-4.24.0.tar.gz", hash = "sha256:88281e5b5b90fe231868905d5ea745b9ee5e30db280b33498cc73fb0fa06d571"},
|
{file = "selenium-4.25.0.tar.gz", hash = "sha256:95d08d3b82fb353f3c474895154516604c7f0e6a9a565ae6498ef36c9bac6921"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -2358,17 +2503,18 @@ SQLAlchemy = ">=2.0.14,<2.1.0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "starlette"
|
name = "starlette"
|
||||||
version = "0.38.5"
|
version = "0.38.6"
|
||||||
description = "The little ASGI library that shines."
|
description = "The little ASGI library that shines."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "starlette-0.38.5-py3-none-any.whl", hash = "sha256:632f420a9d13e3ee2a6f18f437b0a9f1faecb0bc42e1942aa2ea0e379a4c4206"},
|
{file = "starlette-0.38.6-py3-none-any.whl", hash = "sha256:4517a1409e2e73ee4951214ba012052b9e16f60e90d73cfb06192c19203bbb05"},
|
||||||
{file = "starlette-0.38.5.tar.gz", hash = "sha256:04a92830a9b6eb1442c766199d62260c3d4dc9c4f9188360626b1e0273cb7077"},
|
{file = "starlette-0.38.6.tar.gz", hash = "sha256:863a1588f5574e70a821dadefb41e4881ea451a47a3cd1b4df359d4ffefe5ead"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
anyio = ">=3.4.0,<5"
|
anyio = ">=3.4.0,<5"
|
||||||
|
typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""}
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"]
|
full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"]
|
||||||
@ -2425,6 +2571,17 @@ files = [
|
|||||||
doc = ["reno", "sphinx"]
|
doc = ["reno", "sphinx"]
|
||||||
test = ["pytest", "tornado (>=4.5)", "typeguard"]
|
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]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
@ -2546,13 +2703,13 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tzdata"
|
name = "tzdata"
|
||||||
version = "2024.1"
|
version = "2024.2"
|
||||||
description = "Provider of IANA time zone data"
|
description = "Provider of IANA time zone data"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2"
|
python-versions = ">=2"
|
||||||
files = [
|
files = [
|
||||||
{file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"},
|
{file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"},
|
||||||
{file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"},
|
{file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2632,97 +2789,97 @@ test = ["websockets"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "websockets"
|
name = "websockets"
|
||||||
version = "13.0.1"
|
version = "13.1"
|
||||||
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
|
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "websockets-13.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1841c9082a3ba4a05ea824cf6d99570a6a2d8849ef0db16e9c826acb28089e8f"},
|
{file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"},
|
||||||
{file = "websockets-13.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c5870b4a11b77e4caa3937142b650fbbc0914a3e07a0cf3131f35c0587489c1c"},
|
{file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"},
|
||||||
{file = "websockets-13.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f1d3d1f2eb79fe7b0fb02e599b2bf76a7619c79300fc55f0b5e2d382881d4f7f"},
|
{file = "websockets-13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6"},
|
||||||
{file = "websockets-13.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15c7d62ee071fa94a2fc52c2b472fed4af258d43f9030479d9c4a2de885fd543"},
|
{file = "websockets-13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b"},
|
||||||
{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.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa"},
|
||||||
{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.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.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:17118647c0ea14796364299e942c330d72acc4b248e07e639d34b75067b3cdd8"},
|
{file = "websockets-13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c"},
|
||||||
{file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64a11aae1de4c178fa653b07d90f2fb1a2ed31919a5ea2361a38760192e1858b"},
|
{file = "websockets-13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0"},
|
||||||
{file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0617fd0b1d14309c7eab6ba5deae8a7179959861846cbc5cb528a7531c249448"},
|
{file = "websockets-13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f"},
|
||||||
{file = "websockets-13.0.1-cp310-cp310-win32.whl", hash = "sha256:11f9976ecbc530248cf162e359a92f37b7b282de88d1d194f2167b5e7ad80ce3"},
|
{file = "websockets-13.1-cp310-cp310-win32.whl", hash = "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe"},
|
||||||
{file = "websockets-13.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c3c493d0e5141ec055a7d6809a28ac2b88d5b878bb22df8c621ebe79a61123d0"},
|
{file = "websockets-13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a"},
|
||||||
{file = "websockets-13.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:699ba9dd6a926f82a277063603fc8d586b89f4cb128efc353b749b641fcddda7"},
|
{file = "websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19"},
|
||||||
{file = "websockets-13.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf2fae6d85e5dc384bf846f8243ddaa9197f3a1a70044f59399af001fd1f51d4"},
|
{file = "websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5"},
|
||||||
{file = "websockets-13.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:52aed6ef21a0f1a2a5e310fb5c42d7555e9c5855476bbd7173c3aa3d8a0302f2"},
|
{file = "websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd"},
|
||||||
{file = "websockets-13.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8eb2b9a318542153674c6e377eb8cb9ca0fc011c04475110d3477862f15d29f0"},
|
{file = "websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02"},
|
||||||
{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.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7"},
|
||||||
{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.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.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b8ac5b46fd798bbbf2ac6620e0437c36a202b08e1f827832c4bf050da081b501"},
|
{file = "websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084"},
|
||||||
{file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:46af561eba6f9b0848b2c9d2427086cabadf14e0abdd9fde9d72d447df268418"},
|
{file = "websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3"},
|
||||||
{file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b5a06d7f60bc2fc378a333978470dfc4e1415ee52f5f0fce4f7853eb10c1e9df"},
|
{file = "websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9"},
|
||||||
{file = "websockets-13.0.1-cp311-cp311-win32.whl", hash = "sha256:556e70e4f69be1082e6ef26dcb70efcd08d1850f5d6c5f4f2bcb4e397e68f01f"},
|
{file = "websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f"},
|
||||||
{file = "websockets-13.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:67494e95d6565bf395476e9d040037ff69c8b3fa356a886b21d8422ad86ae075"},
|
{file = "websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557"},
|
||||||
{file = "websockets-13.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f9c9e258e3d5efe199ec23903f5da0eeaad58cf6fccb3547b74fd4750e5ac47a"},
|
{file = "websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc"},
|
||||||
{file = "websockets-13.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6b41a1b3b561f1cba8321fb32987552a024a8f67f0d05f06fcf29f0090a1b956"},
|
{file = "websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49"},
|
||||||
{file = "websockets-13.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f73e676a46b0fe9426612ce8caeca54c9073191a77c3e9d5c94697aef99296af"},
|
{file = "websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd"},
|
||||||
{file = "websockets-13.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f613289f4a94142f914aafad6c6c87903de78eae1e140fa769a7385fb232fdf"},
|
{file = "websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0"},
|
||||||
{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.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6"},
|
||||||
{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.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.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:47236c13be337ef36546004ce8c5580f4b1150d9538b27bf8a5ad8edf23ccfab"},
|
{file = "websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68"},
|
||||||
{file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c44ca9ade59b2e376612df34e837013e2b273e6c92d7ed6636d0556b6f4db93d"},
|
{file = "websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14"},
|
||||||
{file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9bbc525f4be3e51b89b2a700f5746c2a6907d2e2ef4513a8daafc98198b92237"},
|
{file = "websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf"},
|
||||||
{file = "websockets-13.0.1-cp312-cp312-win32.whl", hash = "sha256:3624fd8664f2577cf8de996db3250662e259bfbc870dd8ebdcf5d7c6ac0b5185"},
|
{file = "websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c"},
|
||||||
{file = "websockets-13.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0513c727fb8adffa6d9bf4a4463b2bade0186cbd8c3604ae5540fae18a90cb99"},
|
{file = "websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3"},
|
||||||
{file = "websockets-13.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1ee4cc030a4bdab482a37462dbf3ffb7e09334d01dd37d1063be1136a0d825fa"},
|
{file = "websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6"},
|
||||||
{file = "websockets-13.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dbb0b697cc0655719522406c059eae233abaa3243821cfdfab1215d02ac10231"},
|
{file = "websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708"},
|
||||||
{file = "websockets-13.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:acbebec8cb3d4df6e2488fbf34702cbc37fc39ac7abf9449392cefb3305562e9"},
|
{file = "websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418"},
|
||||||
{file = "websockets-13.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63848cdb6fcc0bf09d4a155464c46c64ffdb5807ede4fb251da2c2692559ce75"},
|
{file = "websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a"},
|
||||||
{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.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f"},
|
||||||
{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.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.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e82db3756ccb66266504f5a3de05ac6b32f287faacff72462612120074103329"},
|
{file = "websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135"},
|
||||||
{file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e85f46ce287f5c52438bb3703d86162263afccf034a5ef13dbe4318e98d86e7"},
|
{file = "websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2"},
|
||||||
{file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f3fea72e4e6edb983908f0db373ae0732b275628901d909c382aae3b592589f2"},
|
{file = "websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6"},
|
||||||
{file = "websockets-13.0.1-cp313-cp313-win32.whl", hash = "sha256:254ecf35572fca01a9f789a1d0f543898e222f7b69ecd7d5381d8d8047627bdb"},
|
{file = "websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d"},
|
||||||
{file = "websockets-13.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca48914cdd9f2ccd94deab5bcb5ac98025a5ddce98881e5cce762854a5de330b"},
|
{file = "websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2"},
|
||||||
{file = "websockets-13.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b74593e9acf18ea5469c3edaa6b27fa7ecf97b30e9dabd5a94c4c940637ab96e"},
|
{file = "websockets-13.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c7934fd0e920e70468e676fe7f1b7261c1efa0d6c037c6722278ca0228ad9d0d"},
|
||||||
{file = "websockets-13.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:132511bfd42e77d152c919147078460c88a795af16b50e42a0bd14f0ad71ddd2"},
|
{file = "websockets-13.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:149e622dc48c10ccc3d2760e5f36753db9cacf3ad7bc7bbbfd7d9c819e286f23"},
|
||||||
{file = "websockets-13.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:165bedf13556f985a2aa064309baa01462aa79bf6112fbd068ae38993a0e1f1b"},
|
{file = "websockets-13.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a569eb1b05d72f9bce2ebd28a1ce2054311b66677fcd46cf36204ad23acead8c"},
|
||||||
{file = "websockets-13.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e801ca2f448850685417d723ec70298feff3ce4ff687c6f20922c7474b4746ae"},
|
{file = "websockets-13.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95df24ca1e1bd93bbca51d94dd049a984609687cb2fb08a7f2c56ac84e9816ea"},
|
||||||
{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.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8dbb1bf0c0a4ae8b40bdc9be7f644e2f3fb4e8a9aca7145bfa510d4a374eeb7"},
|
||||||
{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.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.0.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:4f0426d51c8f0926a4879390f53c7f5a855e42d68df95fff6032c82c888b5f36"},
|
{file = "websockets-13.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e4450fc83a3df53dec45922b576e91e94f5578d06436871dce3a6be38e40f5db"},
|
||||||
{file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ef48e4137e8799998a343706531e656fdec6797b80efd029117edacb74b0a10a"},
|
{file = "websockets-13.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:463e1c6ec853202dd3657f156123d6b4dad0c546ea2e2e38be2b3f7c5b8e7295"},
|
||||||
{file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:249aab278810bee585cd0d4de2f08cfd67eed4fc75bde623be163798ed4db2eb"},
|
{file = "websockets-13.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6d6855bbe70119872c05107e38fbc7f96b1d8cb047d95c2c50869a46c65a8e96"},
|
||||||
{file = "websockets-13.0.1-cp38-cp38-win32.whl", hash = "sha256:06c0a667e466fcb56a0886d924b5f29a7f0886199102f0a0e1c60a02a3751cb4"},
|
{file = "websockets-13.1-cp38-cp38-win32.whl", hash = "sha256:204e5107f43095012b00f1451374693267adbb832d29966a01ecc4ce1db26faf"},
|
||||||
{file = "websockets-13.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1f3cf6d6ec1142412d4535adabc6bd72a63f5f148c43fe559f06298bc21953c9"},
|
{file = "websockets-13.1-cp38-cp38-win_amd64.whl", hash = "sha256:485307243237328c022bc908b90e4457d0daa8b5cf4b3723fd3c4a8012fce4c6"},
|
||||||
{file = "websockets-13.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1fa082ea38d5de51dd409434edc27c0dcbd5fed2b09b9be982deb6f0508d25bc"},
|
{file = "websockets-13.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9b37c184f8b976f0c0a231a5f3d6efe10807d41ccbe4488df8c74174805eea7d"},
|
||||||
{file = "websockets-13.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4a365bcb7be554e6e1f9f3ed64016e67e2fa03d7b027a33e436aecf194febb63"},
|
{file = "websockets-13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:163e7277e1a0bd9fb3c8842a71661ad19c6aa7bb3d6678dc7f89b17fbcc4aeb7"},
|
||||||
{file = "websockets-13.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:10a0dc7242215d794fb1918f69c6bb235f1f627aaf19e77f05336d147fce7c37"},
|
{file = "websockets-13.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b889dbd1342820cc210ba44307cf75ae5f2f96226c0038094455a96e64fb07a"},
|
||||||
{file = "websockets-13.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59197afd478545b1f73367620407b0083303569c5f2d043afe5363676f2697c9"},
|
{file = "websockets-13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:586a356928692c1fed0eca68b4d1c2cbbd1ca2acf2ac7e7ebd3b9052582deefa"},
|
||||||
{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.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7bd6abf1e070a6b72bfeb71049d6ad286852e285f146682bf30d0296f5fbadfa"},
|
||||||
{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.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.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ad327ac80ba7ee61da85383ca8822ff808ab5ada0e4a030d66703cc025b021c4"},
|
{file = "websockets-13.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:df01aea34b6e9e33572c35cd16bae5a47785e7d5c8cb2b54b2acdb9678315a17"},
|
||||||
{file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:518f90e6dd089d34eaade01101fd8a990921c3ba18ebbe9b0165b46ebff947f0"},
|
{file = "websockets-13.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e54affdeb21026329fb0744ad187cf812f7d3c2aa702a5edb562b325191fcab6"},
|
||||||
{file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:68264802399aed6fe9652e89761031acc734fc4c653137a5911c2bfa995d6d6d"},
|
{file = "websockets-13.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9ef8aa8bdbac47f4968a5d66462a2a0935d044bf35c0e5a8af152d58516dbeb5"},
|
||||||
{file = "websockets-13.0.1-cp39-cp39-win32.whl", hash = "sha256:a5dc0c42ded1557cc7c3f0240b24129aefbad88af4f09346164349391dea8e58"},
|
{file = "websockets-13.1-cp39-cp39-win32.whl", hash = "sha256:deeb929efe52bed518f6eb2ddc00cc496366a14c726005726ad62c2dd9017a3c"},
|
||||||
{file = "websockets-13.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b448a0690ef43db5ef31b3a0d9aea79043882b4632cfc3eaab20105edecf6097"},
|
{file = "websockets-13.1-cp39-cp39-win_amd64.whl", hash = "sha256:7c65ffa900e7cc958cd088b9a9157a8141c991f8c53d11087e6fb7277a03f81d"},
|
||||||
{file = "websockets-13.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:faef9ec6354fe4f9a2c0bbb52fb1ff852effc897e2a4501e25eb3a47cb0a4f89"},
|
{file = "websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238"},
|
||||||
{file = "websockets-13.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:03d3f9ba172e0a53e37fa4e636b86cc60c3ab2cfee4935e66ed1d7acaa4625ad"},
|
{file = "websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5"},
|
||||||
{file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d450f5a7a35662a9b91a64aefa852f0c0308ee256122f5218a42f1d13577d71e"},
|
{file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9"},
|
||||||
{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.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6"},
|
||||||
{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.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.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b79915a1179a91f6c5f04ece1e592e2e8a6bd245a0e45d12fd56b2b59e559a32"},
|
{file = "websockets-13.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23"},
|
||||||
{file = "websockets-13.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f40de079779acbcdbb6ed4c65af9f018f8b77c5ec4e17a4b737c05c2db554491"},
|
{file = "websockets-13.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9156c45750b37337f7b0b00e6248991a047be4aa44554c9886fe6bdd605aab3b"},
|
||||||
{file = "websockets-13.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80e4ba642fc87fa532bac07e5ed7e19d56940b6af6a8c61d4429be48718a380f"},
|
{file = "websockets-13.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80c421e07973a89fbdd93e6f2003c17d20b69010458d3a8e37fb47874bd67d51"},
|
||||||
{file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a02b0161c43cc9e0232711eff846569fad6ec836a7acab16b3cf97b2344c060"},
|
{file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82d0ba76371769d6a4e56f7e83bb8e81846d17a6190971e38b5de108bde9b0d7"},
|
||||||
{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.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9875a0143f07d74dc5e1ded1c4581f0d9f7ab86c78994e2ed9e95050073c94d"},
|
||||||
{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.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.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d93572720d781331fb10d3da9ca1067817d84ad1e7c31466e9f5e59965618096"},
|
{file = "websockets-13.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4059f790b6ae8768471cddb65d3c4fe4792b0ab48e154c9f0a04cefaabcd5978"},
|
||||||
{file = "websockets-13.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:71e6e5a3a3728886caee9ab8752e8113670936a193284be9d6ad2176a137f376"},
|
{file = "websockets-13.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25c35bf84bf7c7369d247f0b8cfa157f989862c49104c5cf85cb5436a641d93e"},
|
||||||
{file = "websockets-13.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c4a6343e3b0714e80da0b0893543bf9a5b5fa71b846ae640e56e9abc6fbc4c83"},
|
{file = "websockets-13.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:83f91d8a9bb404b8c2c41a707ac7f7f75b9442a0a876df295de27251a856ad09"},
|
||||||
{file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a678532018e435396e37422a95e3ab87f75028ac79570ad11f5bf23cd2a7d8c"},
|
{file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a43cfdcddd07f4ca2b1afb459824dd3c6d53a51410636a2c7fc97b9a8cf4842"},
|
||||||
{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.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a2ef1381632a2f0cb4efeff34efa97901c9fbc118e01951ad7cfc10601a9bb"},
|
||||||
{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.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.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acab3539a027a85d568c2573291e864333ec9d912675107d6efceb7e2be5d980"},
|
{file = "websockets-13.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:95858ca14a9f6fa8413d29e0a585b31b278388aa775b8a81fa24830123874678"},
|
||||||
{file = "websockets-13.0.1-py3-none-any.whl", hash = "sha256:b80f0c51681c517604152eb6a572f5a9378f877763231fddb883ba2f968e8817"},
|
{file = "websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f"},
|
||||||
{file = "websockets-13.0.1.tar.gz", hash = "sha256:4d6ece65099411cfd9a48d13701d7438d9c34f479046b34c50ff60bb8834e43e"},
|
{file = "websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2853,5 +3010,5 @@ type = ["pytest-mypy"]
|
|||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.10"
|
python-versions = "^3.9"
|
||||||
content-hash = "1c8904971be7061c2b33400d2b5f461e526703586e5b7f9eb08c2fbfda1a23ab"
|
content-hash = "adccd071775567aeefe219261aeb9e222906c865745f03edb1e770edc79c44ac"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "reflex"
|
name = "reflex"
|
||||||
version = "0.6.0a1"
|
version = "0.6.2dev1"
|
||||||
description = "Web apps in pure Python."
|
description = "Web apps in pure Python."
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
authors = [
|
authors = [
|
||||||
@ -26,7 +26,7 @@ packages = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.10"
|
python = "^3.9"
|
||||||
dill = ">=0.3.8,<0.4"
|
dill = ">=0.3.8,<0.4"
|
||||||
fastapi = ">=0.96.0,!=0.111.0,!=0.111.1"
|
fastapi = ">=0.96.0,!=0.111.0,!=0.111.1"
|
||||||
gunicorn = ">=20.1.0,<24.0"
|
gunicorn = ">=20.1.0,<24.0"
|
||||||
@ -59,7 +59,7 @@ httpx = ">=0.25.1,<1.0"
|
|||||||
twine = ">=4.0.0,<6.0"
|
twine = ">=4.0.0,<6.0"
|
||||||
tomlkit = ">=0.12.4,<1.0"
|
tomlkit = ">=0.12.4,<1.0"
|
||||||
lazy_loader = ">=0.4"
|
lazy_loader = ">=0.4"
|
||||||
reflex-chakra = ">=0.6.0a6"
|
reflex-chakra = ">=0.6.0"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
pytest = ">=7.1.2,<8.0"
|
pytest = ">=7.1.2,<8.0"
|
||||||
@ -77,6 +77,8 @@ asynctest = ">=0.13.0,<1.0"
|
|||||||
pre-commit = ">=3.2.1"
|
pre-commit = ">=3.2.1"
|
||||||
selenium = ">=4.11.0,<5.0"
|
selenium = ">=4.11.0,<5.0"
|
||||||
pytest-benchmark = ">=4.0.0,<5.0"
|
pytest-benchmark = ">=4.0.0,<5.0"
|
||||||
|
playwright = ">=1.46.0"
|
||||||
|
pytest-playwright = ">=0.5.1"
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
[tool.poetry.scripts]
|
||||||
reflex = "reflex.reflex:cli"
|
reflex = "reflex.reflex:cli"
|
||||||
@ -88,7 +90,7 @@ build-backend = "poetry.core.masonry.api"
|
|||||||
[tool.pyright]
|
[tool.pyright]
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py310"
|
target-version = "py39"
|
||||||
lint.select = ["B", "D", "E", "F", "I", "SIM", "W"]
|
lint.select = ["B", "D", "E", "F", "I", "SIM", "W"]
|
||||||
lint.ignore = ["B008", "D203", "D205", "D213", "D401", "D406", "D407", "E501", "F403", "F405", "F541"]
|
lint.ignore = ["B008", "D203", "D205", "D213", "D401", "D406", "D407", "E501", "F403", "F405", "F541"]
|
||||||
lint.pydocstyle.convention = "google"
|
lint.pydocstyle.convention = "google"
|
||||||
|
@ -8,7 +8,7 @@ version = "0.0.1"
|
|||||||
description = "Reflex custom component {{ module_name }}"
|
description = "Reflex custom component {{ module_name }}"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = { text = "Apache-2.0" }
|
license = { text = "Apache-2.0" }
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.9"
|
||||||
authors = [{ name = "", email = "YOUREMAIL@domain.com" }]
|
authors = [{ name = "", email = "YOUREMAIL@domain.com" }]
|
||||||
keywords = ["reflex","reflex-custom-components"]
|
keywords = ["reflex","reflex-custom-components"]
|
||||||
|
|
||||||
|
@ -832,7 +832,9 @@ export const useEventLoop = (
|
|||||||
* @returns True if the value is truthy, false otherwise.
|
* @returns True if the value is truthy, false otherwise.
|
||||||
*/
|
*/
|
||||||
export const isTrue = (val) => {
|
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 the route is not set, get it from the callable.
|
||||||
if route is None:
|
if route is None:
|
||||||
assert isinstance(
|
if not isinstance(component, Callable):
|
||||||
component, Callable
|
raise ValueError("Route must be set if component is not a callable.")
|
||||||
), "Route must be set if component is not a callable."
|
|
||||||
# Format the route.
|
# Format the route.
|
||||||
route = format.format_route(component.__name__)
|
route = format.format_route(component.__name__)
|
||||||
else:
|
else:
|
||||||
@ -615,10 +614,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
|||||||
for route in self.pages:
|
for route in self.pages:
|
||||||
replaced_route = replace_brackets_with_keywords(route)
|
replaced_route = replace_brackets_with_keywords(route)
|
||||||
for rw, r, nr in zip(
|
for rw, r, nr in zip(
|
||||||
replaced_route.split("/"),
|
replaced_route.split("/"), route.split("/"), new_route.split("/")
|
||||||
route.split("/"),
|
|
||||||
new_route.split("/"),
|
|
||||||
strict=False,
|
|
||||||
):
|
):
|
||||||
if rw in segments and r != nr:
|
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
|
# 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,
|
FRONTEND_ARG_SPEC,
|
||||||
BACKEND_ARG_SPEC,
|
BACKEND_ARG_SPEC,
|
||||||
],
|
],
|
||||||
strict=False,
|
|
||||||
):
|
):
|
||||||
if hasattr(handler_fn, "__name__"):
|
if hasattr(handler_fn, "__name__"):
|
||||||
_fn_name = handler_fn.__name__
|
_fn_name = handler_fn.__name__
|
||||||
@ -1563,6 +1558,9 @@ class EventNamespace(AsyncNamespace):
|
|||||||
async def on_event(self, sid, data):
|
async def on_event(self, sid, data):
|
||||||
"""Event for receiving front-end websocket events.
|
"""Event for receiving front-end websocket events.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
RuntimeError: If the Socket.IO is badly initialized.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sid: The Socket.IO session id.
|
sid: The Socket.IO session id.
|
||||||
data: The event data.
|
data: The event data.
|
||||||
@ -1575,9 +1573,11 @@ class EventNamespace(AsyncNamespace):
|
|||||||
self.sid_to_token[sid] = event.token
|
self.sid_to_token[sid] = event.token
|
||||||
|
|
||||||
# Get the event environment.
|
# 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)
|
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.
|
# Get the client headers.
|
||||||
headers = {
|
headers = {
|
||||||
|
@ -6,11 +6,13 @@ import asyncio
|
|||||||
import contextlib
|
import contextlib
|
||||||
import functools
|
import functools
|
||||||
import inspect
|
import inspect
|
||||||
import sys
|
|
||||||
from typing import Callable, Coroutine, Set, Union
|
from typing import Callable, Coroutine, Set, Union
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
from reflex.utils import console
|
||||||
|
from reflex.utils.exceptions import InvalidLifespanTaskType
|
||||||
|
|
||||||
from .mixin import AppMixin
|
from .mixin import AppMixin
|
||||||
|
|
||||||
|
|
||||||
@ -26,6 +28,7 @@ class LifespanMixin(AppMixin):
|
|||||||
try:
|
try:
|
||||||
async with contextlib.AsyncExitStack() as stack:
|
async with contextlib.AsyncExitStack() as stack:
|
||||||
for task in self.lifespan_tasks:
|
for task in self.lifespan_tasks:
|
||||||
|
run_msg = f"Started lifespan task: {task.__name__} as {{type}}" # type: ignore
|
||||||
if isinstance(task, asyncio.Task):
|
if isinstance(task, asyncio.Task):
|
||||||
running_tasks.append(task)
|
running_tasks.append(task)
|
||||||
else:
|
else:
|
||||||
@ -35,15 +38,19 @@ class LifespanMixin(AppMixin):
|
|||||||
_t = task()
|
_t = task()
|
||||||
if isinstance(_t, contextlib._AsyncGeneratorContextManager):
|
if isinstance(_t, contextlib._AsyncGeneratorContextManager):
|
||||||
await stack.enter_async_context(_t)
|
await stack.enter_async_context(_t)
|
||||||
|
console.debug(run_msg.format(type="asynccontextmanager"))
|
||||||
elif isinstance(_t, Coroutine):
|
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
|
yield
|
||||||
finally:
|
finally:
|
||||||
cancel_kwargs = (
|
|
||||||
{"msg": "lifespan_cleanup"} if sys.version_info >= (3, 9) else {}
|
|
||||||
)
|
|
||||||
for task in running_tasks:
|
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):
|
def register_lifespan_task(self, task: Callable | asyncio.Task, **task_kwargs):
|
||||||
"""Register a task to run during the lifespan of the app.
|
"""Register a task to run during the lifespan of the app.
|
||||||
@ -51,7 +58,18 @@ class LifespanMixin(AppMixin):
|
|||||||
Args:
|
Args:
|
||||||
task: The task to register.
|
task: The task to register.
|
||||||
task_kwargs: The kwargs of the task.
|
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:
|
if task_kwargs:
|
||||||
|
original_task = task
|
||||||
task = functools.partial(task, **task_kwargs) # type: ignore
|
task = functools.partial(task, **task_kwargs) # type: ignore
|
||||||
|
functools.update_wrapper(task, original_task) # type: ignore
|
||||||
self.lifespan_tasks.add(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")
|
telemetry.send("compile")
|
||||||
app_module = get_app(reload=False)
|
app_module = get_app(reload=False)
|
||||||
app = getattr(app_module, constants.CompileVars.APP)
|
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).
|
# before compiling the app in a thread to avoid event loop error (REF-2172).
|
||||||
app._apply_decorated_pages()
|
app._apply_decorated_pages()
|
||||||
compile_future = ThreadPoolExecutor(max_workers=1).submit(app._compile)
|
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:
|
Args:
|
||||||
fields: The set of fields to import from the library.
|
fields: The set of fields to import from the library.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If there is more than one default import.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The libraries for default and rest.
|
The libraries for default and rest.
|
||||||
default: default library. When install "import def from library".
|
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.
|
# Check for default imports.
|
||||||
defaults = {field for field in fields_set if field.is_default}
|
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.
|
# Get the default import, and the specific imports.
|
||||||
default = next(iter({field.name for field in defaults}), "")
|
default = next(iter({field.name for field in defaults}), "")
|
||||||
@ -92,6 +96,9 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]:
|
|||||||
Args:
|
Args:
|
||||||
import_dict: The import dict to compile.
|
import_dict: The import dict to compile.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If an import in the dict is invalid.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The list of import dict.
|
The list of import dict.
|
||||||
"""
|
"""
|
||||||
@ -106,8 +113,10 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
if not lib:
|
if not lib:
|
||||||
assert not default, "No default field allowed for empty library."
|
if default:
|
||||||
assert rest is not None and len(rest) > 0, "No fields to import."
|
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):
|
for module in sorted(rest):
|
||||||
import_dicts.append(get_import_dict(module))
|
import_dicts.append(get_import_dict(module))
|
||||||
continue
|
continue
|
||||||
@ -155,7 +164,7 @@ def compile_state(state: Type[BaseState]) -> dict:
|
|||||||
initial_state = state(_reflex_internal_init=True).dict(
|
initial_state = state(_reflex_internal_init=True).dict(
|
||||||
initial=True, include_computed=False
|
initial=True, include_computed=False
|
||||||
)
|
)
|
||||||
return format.format_state(initial_state)
|
return initial_state
|
||||||
|
|
||||||
|
|
||||||
def _compile_client_storage_field(
|
def _compile_client_storage_field(
|
||||||
@ -429,11 +438,11 @@ def add_meta(
|
|||||||
Returns:
|
Returns:
|
||||||
The component with the metadata added.
|
The component with the metadata added.
|
||||||
"""
|
"""
|
||||||
meta_tags = [Meta.create(**item) for item in meta]
|
meta_tags = [
|
||||||
|
item if isinstance(item, Component) else Meta.create(**item) for item in meta
|
||||||
children: list[Any] = [
|
|
||||||
Title.create(title),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
children: list[Any] = [Title.create(title)]
|
||||||
if description:
|
if description:
|
||||||
children.append(Description.create(content=description))
|
children.append(Description.create(content=description))
|
||||||
children.append(Image.create(content=image))
|
children.append(Image.create(content=image))
|
||||||
|
@ -7,7 +7,7 @@ from typing import Any, Iterator
|
|||||||
from reflex.components.component import Component
|
from reflex.components.component import Component
|
||||||
from reflex.components.tags import Tag
|
from reflex.components.tags import Tag
|
||||||
from reflex.components.tags.tagless import Tagless
|
from reflex.components.tags.tagless import Tagless
|
||||||
from reflex.vars.base import Var
|
from reflex.vars import ArrayVar, BooleanVar, ObjectVar, Var
|
||||||
|
|
||||||
|
|
||||||
class Bare(Component):
|
class Bare(Component):
|
||||||
@ -33,6 +33,8 @@ class Bare(Component):
|
|||||||
|
|
||||||
def _render(self) -> Tag:
|
def _render(self) -> Tag:
|
||||||
if isinstance(self.contents, Var):
|
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=f"{{{str(self.contents)}}}")
|
||||||
return Tagless(contents=str(self.contents))
|
return Tagless(contents=str(self.contents))
|
||||||
|
|
||||||
|
@ -16,13 +16,15 @@ class Title(Component):
|
|||||||
def render(self) -> dict:
|
def render(self) -> dict:
|
||||||
"""Render the title component.
|
"""Render the title component.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If the title is not a single string.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The rendered title component.
|
The rendered title component.
|
||||||
"""
|
"""
|
||||||
# Make sure the title is a single string.
|
# Make sure the title is a single string.
|
||||||
assert len(self.children) == 1 and isinstance(
|
if len(self.children) != 1 or not isinstance(self.children[0], Bare):
|
||||||
self.children[0], Bare
|
raise ValueError("Title must be a single string.")
|
||||||
), "Title must be a single string."
|
|
||||||
return super().render()
|
return super().render()
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,6 +55,7 @@ from reflex.utils.imports import (
|
|||||||
)
|
)
|
||||||
from reflex.vars import VarData
|
from reflex.vars import VarData
|
||||||
from reflex.vars.base import LiteralVar, Var
|
from reflex.vars.base import LiteralVar, Var
|
||||||
|
from reflex.vars.sequence import LiteralArrayVar
|
||||||
|
|
||||||
|
|
||||||
class BaseComponent(Base, ABC):
|
class BaseComponent(Base, ABC):
|
||||||
@ -448,8 +449,16 @@ class Component(BaseComponent, ABC):
|
|||||||
and not types._issubclass(passed_type, expected_type, value)
|
and not types._issubclass(passed_type, expected_type, value)
|
||||||
):
|
):
|
||||||
value_name = value._js_expr if isinstance(value, Var) else 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(
|
raise TypeError(
|
||||||
f"Invalid var passed for prop {type(self).__name__}.{key}, expected type {expected_type}, got value {value_name} of type {passed_type}."
|
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.
|
# Check if the key is an event trigger.
|
||||||
if key in component_specific_triggers:
|
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.
|
# 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()}
|
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 = {
|
style = {
|
||||||
# Assign the Breakpoints to the self-referential selector to avoid squashing down to a regular dict.
|
# Assign the Breakpoints to the self-referential selector to avoid squashing down to a regular dict.
|
||||||
"&": style,
|
"&": style,
|
||||||
@ -488,6 +497,11 @@ class Component(BaseComponent, ABC):
|
|||||||
# Convert class_name to str if it's list
|
# Convert class_name to str if it's list
|
||||||
class_name = kwargs.get("class_name", "")
|
class_name = kwargs.get("class_name", "")
|
||||||
if isinstance(class_name, (List, tuple)):
|
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)
|
kwargs["class_name"] = " ".join(class_name)
|
||||||
|
|
||||||
# Construct the component.
|
# Construct the component.
|
||||||
@ -1730,10 +1744,14 @@ class CustomComponent(Component):
|
|||||||
Args:
|
Args:
|
||||||
seen: The tags of the components that have already been seen.
|
seen: The tags of the components that have already been seen.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If the tag is not set.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The set of custom components.
|
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.
|
# Store the seen components in a set to avoid infinite recursion.
|
||||||
if seen is None:
|
if seen is None:
|
||||||
|
@ -82,9 +82,7 @@ class Breakpoints(Dict[K, V]):
|
|||||||
return Breakpoints(
|
return Breakpoints(
|
||||||
{
|
{
|
||||||
k: v
|
k: v
|
||||||
for k, v in zip(
|
for k, v in zip(["initial", *breakpoint_names], thresholds)
|
||||||
["initial", *breakpoint_names], thresholds, strict=False
|
|
||||||
)
|
|
||||||
if v is not None
|
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.
|
# Convert the condition to a Var.
|
||||||
cond_var = LiteralVar.create(condition)
|
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 the first component is a component, create a Cond component.
|
||||||
if isinstance(c1, BaseComponent):
|
if isinstance(c1, BaseComponent):
|
||||||
assert c2 is None or isinstance(
|
if c2 is not None and not isinstance(c2, BaseComponent):
|
||||||
c2, BaseComponent
|
raise ValueError("Both arguments must be components.")
|
||||||
), "Both arguments must be components."
|
|
||||||
return Cond.create(cond_var, c1, c2)
|
return Cond.create(cond_var, c1, c2)
|
||||||
|
|
||||||
# Otherwise, create a conditional Var.
|
# Otherwise, create a conditional Var.
|
||||||
|
@ -8,7 +8,6 @@ _SUBMOD_ATTRS: dict[str, list[str]] = {
|
|||||||
"code": [
|
"code": [
|
||||||
"CodeBlock",
|
"CodeBlock",
|
||||||
"code_block",
|
"code_block",
|
||||||
"LiteralCodeBlockTheme",
|
|
||||||
"LiteralCodeLanguage",
|
"LiteralCodeLanguage",
|
||||||
],
|
],
|
||||||
"dataeditor": ["data_editor", "data_editor_theme", "DataEditorTheme"],
|
"dataeditor": ["data_editor", "data_editor_theme", "DataEditorTheme"],
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
# ------------------------------------------------------
|
# ------------------------------------------------------
|
||||||
|
|
||||||
from .code import CodeBlock as CodeBlock
|
from .code import CodeBlock as CodeBlock
|
||||||
from .code import LiteralCodeBlockTheme as LiteralCodeBlockTheme
|
|
||||||
from .code import LiteralCodeLanguage as LiteralCodeLanguage
|
from .code import LiteralCodeLanguage as LiteralCodeLanguage
|
||||||
from .code import code_block as code_block
|
from .code import code_block as code_block
|
||||||
from .dataeditor import DataEditorTheme as DataEditorTheme
|
from .dataeditor import DataEditorTheme as DataEditorTheme
|
||||||
|
@ -2,10 +2,8 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import enum
|
import dataclasses
|
||||||
from typing import Any, Dict, Literal, Optional, Union
|
from typing import ClassVar, Dict, Literal, Optional, Union
|
||||||
|
|
||||||
from typing_extensions import get_args
|
|
||||||
|
|
||||||
from reflex.components.component import Component, ComponentNamespace
|
from reflex.components.component import Component, ComponentNamespace
|
||||||
from reflex.components.core.cond import color_mode_cond
|
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.utils.imports import ImportDict, ImportVar
|
||||||
from reflex.vars.base import LiteralVar, Var, VarData
|
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[
|
LiteralCodeLanguage = Literal[
|
||||||
"abap",
|
"abap",
|
||||||
"abnf",
|
"abnf",
|
||||||
@ -351,18 +300,82 @@ LiteralCodeLanguage = Literal[
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def replace_quotes_with_camel_case(value: str) -> str:
|
def construct_theme_var(theme: str) -> Var[Theme]:
|
||||||
"""Replaces quotes in the given string with camel case format.
|
"""Construct a theme var.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
value (str): The string to be processed.
|
theme: The theme to construct.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: The processed string with quotes replaced by camel case.
|
The constructed theme var.
|
||||||
"""
|
"""
|
||||||
for theme in get_args(LiteralCodeBlockTheme):
|
return Var(
|
||||||
value = value.replace(f'"{theme}"', format.to_camel_case(theme))
|
theme,
|
||||||
return value
|
_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):
|
class CodeBlock(Component):
|
||||||
@ -375,7 +388,7 @@ class CodeBlock(Component):
|
|||||||
alias = "SyntaxHighlighter"
|
alias = "SyntaxHighlighter"
|
||||||
|
|
||||||
# The theme to use ("light" or "dark").
|
# 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.
|
# The language to use.
|
||||||
language: Var[LiteralCodeLanguage] = "python" # type: ignore
|
language: Var[LiteralCodeLanguage] = "python" # type: ignore
|
||||||
@ -523,91 +536,6 @@ class CodeBlock(Component):
|
|||||||
|
|
||||||
return out
|
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):
|
class CodeblockNamespace(ComponentNamespace):
|
||||||
"""Namespace for the CodeBlock component."""
|
"""Namespace for the CodeBlock component."""
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
# ------------------- DO NOT EDIT ----------------------
|
# ------------------- DO NOT EDIT ----------------------
|
||||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||||
# ------------------------------------------------------
|
# ------------------------------------------------------
|
||||||
import enum
|
import dataclasses
|
||||||
from typing import Any, Callable, Dict, Literal, Optional, Union, overload
|
from typing import Any, Callable, ClassVar, Dict, Literal, Optional, Union, overload
|
||||||
|
|
||||||
from reflex.components.component import Component, ComponentNamespace
|
from reflex.components.component import Component, ComponentNamespace
|
||||||
from reflex.constants.colors import Color
|
from reflex.constants.colors import Color
|
||||||
@ -13,53 +13,6 @@ from reflex.style import Style
|
|||||||
from reflex.utils.imports import ImportDict
|
from reflex.utils.imports import ImportDict
|
||||||
from reflex.vars.base import Var
|
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[
|
LiteralCodeLanguage = Literal[
|
||||||
"abap",
|
"abap",
|
||||||
"abnf",
|
"abnf",
|
||||||
@ -342,7 +295,59 @@ LiteralCodeLanguage = Literal[
|
|||||||
"zig",
|
"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):
|
class CodeBlock(Component):
|
||||||
def add_imports(self) -> ImportDict: ...
|
def add_imports(self) -> ImportDict: ...
|
||||||
@ -353,7 +358,7 @@ class CodeBlock(Component):
|
|||||||
*children,
|
*children,
|
||||||
can_copy: Optional[bool] = False,
|
can_copy: Optional[bool] = False,
|
||||||
copy_button: Optional[Union[Component, bool]] = None,
|
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[
|
language: Optional[
|
||||||
Union[
|
Union[
|
||||||
Literal[
|
Literal[
|
||||||
@ -999,57 +1004,6 @@ class CodeBlock(Component):
|
|||||||
...
|
...
|
||||||
|
|
||||||
def add_style(self): ...
|
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):
|
class CodeblockNamespace(ComponentNamespace):
|
||||||
themes = Theme
|
themes = Theme
|
||||||
@ -1059,7 +1013,7 @@ class CodeblockNamespace(ComponentNamespace):
|
|||||||
*children,
|
*children,
|
||||||
can_copy: Optional[bool] = False,
|
can_copy: Optional[bool] = False,
|
||||||
copy_button: Optional[Union[Component, bool]] = None,
|
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[
|
language: Optional[
|
||||||
Union[
|
Union[
|
||||||
Literal[
|
Literal[
|
||||||
|
@ -12,31 +12,33 @@ def logo(**props):
|
|||||||
Returns:
|
Returns:
|
||||||
The logo component.
|
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">
|
def logo_path(d):
|
||||||
<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"/>
|
return rx.el.svg.path(
|
||||||
<path d="M11.2 11.5999V0.399902H17.92V2.6399H13.44V4.8799H17.92V7.1199H13.44V9.3599H17.92V11.5999H11.2Z" fill="white"/>
|
d=d,
|
||||||
<path d="M20.16 11.5999V0.399902H26.88V2.6399H22.4V4.8799H26.88V7.1199H22.4V11.5999H20.16Z" fill="white"/>
|
fill=rx.color_mode_cond("#110F1F", "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"/>
|
paths = [
|
||||||
</svg>"""
|
"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(
|
return rx.center(
|
||||||
rx.link(
|
rx.link(
|
||||||
rx.hstack(
|
rx.hstack(
|
||||||
"Built with ",
|
"Built with ",
|
||||||
rx.color_mode_cond(
|
rx.el.svg(
|
||||||
rx.html(light_mode_logo),
|
*[logo_path(d) for d in paths],
|
||||||
rx.html(dark_mode_logo),
|
width="56",
|
||||||
|
height="12",
|
||||||
|
viewBox="0 0 56 12",
|
||||||
|
fill="none",
|
||||||
|
xmlns="http://www.w3.org/2000/svg",
|
||||||
),
|
),
|
||||||
text_align="center",
|
text_align="center",
|
||||||
align="center",
|
align="center",
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.utils import imports
|
from reflex.utils import imports
|
||||||
|
from reflex.utils.format import format_library_name
|
||||||
from reflex.utils.serializers import serializer
|
from reflex.utils.serializers import serializer
|
||||||
from reflex.vars import Var, get_unique_variable_name
|
from reflex.vars import Var, get_unique_variable_name
|
||||||
from reflex.vars.base import VarData, transform
|
from reflex.vars.base import VarData, transform
|
||||||
@ -57,12 +58,21 @@ def load_dynamic_serializer():
|
|||||||
)
|
)
|
||||||
] = None
|
] = None
|
||||||
|
|
||||||
|
libs_in_window = [
|
||||||
|
"react",
|
||||||
|
"@radix-ui/themes",
|
||||||
|
]
|
||||||
|
|
||||||
imports = {}
|
imports = {}
|
||||||
for lib, names in component._get_all_imports().items():
|
for lib, names in component._get_all_imports().items():
|
||||||
|
formatted_lib_name = format_library_name(lib)
|
||||||
if (
|
if (
|
||||||
not lib.startswith((".", "/"))
|
not lib.startswith((".", "/"))
|
||||||
and not lib.startswith("http")
|
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
|
imports[get_cdn_url(lib)] = names
|
||||||
else:
|
else:
|
||||||
@ -83,10 +93,16 @@ def load_dynamic_serializer():
|
|||||||
)
|
)
|
||||||
+ "]"
|
+ "]"
|
||||||
)
|
)
|
||||||
elif 'from "react"' in line:
|
else:
|
||||||
module_code_lines[ix] = line.replace(
|
for lib in libs_in_window:
|
||||||
"import ", "const ", 1
|
if f'from "{lib}"' in line:
|
||||||
).replace(' from "react"', " = window.__reflex.react", 1)
|
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"):
|
if line.startswith("export function"):
|
||||||
module_code_lines[ix] = line.replace(
|
module_code_lines[ix] = line.replace(
|
||||||
"export function", "export default function", 1
|
"export function", "export default function", 1
|
||||||
|
@ -10,7 +10,7 @@ from jinja2 import Environment
|
|||||||
from reflex.components.el.element import Element
|
from reflex.components.el.element import Element
|
||||||
from reflex.components.tags.tag import Tag
|
from reflex.components.tags.tag import Tag
|
||||||
from reflex.constants import Dirs, EventTriggers
|
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.utils.imports import ImportDict
|
||||||
from reflex.vars import VarData
|
from reflex.vars import VarData
|
||||||
from reflex.vars.base import LiteralVar, Var
|
from reflex.vars.base import LiteralVar, Var
|
||||||
@ -148,6 +148,9 @@ class Form(BaseHTML):
|
|||||||
Returns:
|
Returns:
|
||||||
The form component.
|
The form component.
|
||||||
"""
|
"""
|
||||||
|
if "on_submit" not in props:
|
||||||
|
props["on_submit"] = prevent_default
|
||||||
|
|
||||||
if "handle_submit_unique_name" in props:
|
if "handle_submit_unique_name" in props:
|
||||||
return super().create(*children, **props)
|
return super().create(*children, **props)
|
||||||
|
|
||||||
|
@ -317,6 +317,42 @@ class Svg(BaseHTML):
|
|||||||
xmlns: Var[str]
|
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):
|
class Circle(BaseHTML):
|
||||||
"""The SVG circle component."""
|
"""The SVG circle component."""
|
||||||
|
|
||||||
@ -331,6 +367,22 @@ class Circle(BaseHTML):
|
|||||||
path_length: Var[int]
|
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):
|
class Rect(BaseHTML):
|
||||||
"""The SVG rect component."""
|
"""The SVG rect component."""
|
||||||
|
|
||||||
@ -394,6 +446,39 @@ class LinearGradient(BaseHTML):
|
|||||||
y2: Var[Union[str, int, bool]]
|
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):
|
class Stop(BaseHTML):
|
||||||
"""Display the stop element."""
|
"""Display the stop element."""
|
||||||
|
|
||||||
@ -421,12 +506,16 @@ class Path(BaseHTML):
|
|||||||
class SVG(ComponentNamespace):
|
class SVG(ComponentNamespace):
|
||||||
"""SVG component namespace."""
|
"""SVG component namespace."""
|
||||||
|
|
||||||
|
text = staticmethod(Text.create)
|
||||||
|
line = staticmethod(Line.create)
|
||||||
circle = staticmethod(Circle.create)
|
circle = staticmethod(Circle.create)
|
||||||
|
ellipse = staticmethod(Ellipse.create)
|
||||||
rect = staticmethod(Rect.create)
|
rect = staticmethod(Rect.create)
|
||||||
polygon = staticmethod(Polygon.create)
|
polygon = staticmethod(Polygon.create)
|
||||||
path = staticmethod(Path.create)
|
path = staticmethod(Path.create)
|
||||||
stop = staticmethod(Stop.create)
|
stop = staticmethod(Stop.create)
|
||||||
linear_gradient = staticmethod(LinearGradient.create)
|
linear_gradient = staticmethod(LinearGradient.create)
|
||||||
|
radial_gradient = staticmethod(RadialGradient.create)
|
||||||
defs = staticmethod(Defs.create)
|
defs = staticmethod(Defs.create)
|
||||||
__call__ = staticmethod(Svg.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):
|
class Circle(BaseHTML):
|
||||||
@overload
|
@overload
|
||||||
@classmethod
|
@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):
|
class Rect(BaseHTML):
|
||||||
@overload
|
@overload
|
||||||
@classmethod
|
@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):
|
class Stop(BaseHTML):
|
||||||
@overload
|
@overload
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -2345,12 +2821,16 @@ class Path(BaseHTML):
|
|||||||
...
|
...
|
||||||
|
|
||||||
class SVG(ComponentNamespace):
|
class SVG(ComponentNamespace):
|
||||||
|
text = staticmethod(Text.create)
|
||||||
|
line = staticmethod(Line.create)
|
||||||
circle = staticmethod(Circle.create)
|
circle = staticmethod(Circle.create)
|
||||||
|
ellipse = staticmethod(Ellipse.create)
|
||||||
rect = staticmethod(Rect.create)
|
rect = staticmethod(Rect.create)
|
||||||
polygon = staticmethod(Polygon.create)
|
polygon = staticmethod(Polygon.create)
|
||||||
path = staticmethod(Path.create)
|
path = staticmethod(Path.create)
|
||||||
stop = staticmethod(Stop.create)
|
stop = staticmethod(Stop.create)
|
||||||
linear_gradient = staticmethod(LinearGradient.create)
|
linear_gradient = staticmethod(LinearGradient.create)
|
||||||
|
radial_gradient = staticmethod(RadialGradient.create)
|
||||||
defs = staticmethod(Defs.create)
|
defs = staticmethod(Defs.create)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -124,7 +124,8 @@ class DataTable(Gridjs):
|
|||||||
if types.is_dataframe(type(self.data)):
|
if types.is_dataframe(type(self.data)):
|
||||||
# If given a pandas df break up the data and columns
|
# If given a pandas df break up the data and columns
|
||||||
data = serialize(self.data)
|
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.columns = LiteralVar.create(data["columns"])
|
||||||
self.data = LiteralVar.create(data["data"])
|
self.data = LiteralVar.create(data["data"])
|
||||||
|
|
||||||
|
@ -95,12 +95,16 @@ class Markdown(Component):
|
|||||||
*children: The children of the component.
|
*children: The children of the component.
|
||||||
**props: The properties of the component.
|
**props: The properties of the component.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If the children are not valid.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The markdown component.
|
The markdown component.
|
||||||
"""
|
"""
|
||||||
assert (
|
if len(children) != 1 or not types._isinstance(children[0], Union[str, Var]):
|
||||||
len(children) == 1 and types._isinstance(children[0], Union[str, Var])
|
raise ValueError(
|
||||||
), "Markdown component must have exactly one child containing the markdown source."
|
"Markdown component must have exactly one child containing the markdown source."
|
||||||
|
)
|
||||||
|
|
||||||
# Update the base component map with the custom component map.
|
# Update the base component map with the custom component map.
|
||||||
component_map = {**get_base_component_map(), **props.pop("component_map", {})}
|
component_map = {**get_base_component_map(), **props.pop("component_map", {})}
|
||||||
@ -147,7 +151,7 @@ class Markdown(Component):
|
|||||||
Returns:
|
Returns:
|
||||||
The imports for the markdown component.
|
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
|
from reflex.components.radix.themes.typography.code import Code
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -173,8 +177,8 @@ class Markdown(Component):
|
|||||||
component(_MOCK_ARG)._get_all_imports() # type: ignore
|
component(_MOCK_ARG)._get_all_imports() # type: ignore
|
||||||
for component in self.component_map.values()
|
for component in self.component_map.values()
|
||||||
],
|
],
|
||||||
CodeBlock.create(theme="light")._get_imports(), # type: ignore,
|
CodeBlock.create(theme=Theme.light)._get_imports(),
|
||||||
Code.create()._get_imports(), # type: ignore,
|
Code.create()._get_imports(),
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_component(self, tag: str, **props) -> Component:
|
def get_component(self, tag: str, **props) -> Component:
|
||||||
|
@ -93,6 +93,9 @@ class Markdown(Component):
|
|||||||
custom_attrs: custom attribute
|
custom_attrs: custom attribute
|
||||||
**props: The properties of the component.
|
**props: The properties of the component.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If the children are not valid.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The markdown component.
|
The markdown component.
|
||||||
"""
|
"""
|
||||||
|
@ -33,7 +33,7 @@ class Stack(Flex):
|
|||||||
"""
|
"""
|
||||||
# Apply the default classname
|
# Apply the default classname
|
||||||
given_class_name = props.pop("class_name", [])
|
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]
|
given_class_name = [given_class_name]
|
||||||
props["class_name"] = ["rx-Stack", *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.style import Style, resolved_color_mode
|
||||||
from reflex.utils import format
|
from reflex.utils import format
|
||||||
from reflex.utils.imports import ImportVar
|
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 import VarData
|
||||||
from reflex.vars.base import LiteralVar, Var
|
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):
|
if message == "" and ("title" not in props or "description" not in props):
|
||||||
raise ValueError("Toast message or title or description must be provided.")
|
raise ValueError("Toast message or title or description must be provided.")
|
||||||
if props:
|
if props:
|
||||||
args = serialize(ToastProps(**props)) # type: ignore
|
args = LiteralVar.create(ToastProps(**props))
|
||||||
toast = f"{toast_command}(`{message}`, {args})"
|
toast = f"{toast_command}(`{message}`, {str(args)})"
|
||||||
else:
|
else:
|
||||||
toast = f"{toast_command}(`{message}`)"
|
toast = f"{toast_command}(`{message}`)"
|
||||||
|
|
||||||
|
@ -114,6 +114,9 @@ class IterTag(Tag):
|
|||||||
def render_component(self) -> Component:
|
def render_component(self) -> Component:
|
||||||
"""Render the component.
|
"""Render the component.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If the render function takes more than 2 arguments.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The rendered component.
|
The rendered component.
|
||||||
"""
|
"""
|
||||||
@ -132,7 +135,8 @@ class IterTag(Tag):
|
|||||||
component = self.render_fn(arg)
|
component = self.render_fn(arg)
|
||||||
else:
|
else:
|
||||||
# If the render function takes the index as an argument.
|
# 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)
|
component = self.render_fn(arg, index)
|
||||||
|
|
||||||
# Nested foreach components or cond must be wrapped in fragments.
|
# Nested foreach components or cond must be wrapped in fragments.
|
||||||
|
@ -158,7 +158,7 @@ class Config(Base):
|
|||||||
app_name: str
|
app_name: str
|
||||||
|
|
||||||
# The log level to use.
|
# 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.
|
# 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
|
frontend_port: int = constants.DefaultPorts.FRONTEND_PORT
|
||||||
@ -194,7 +194,7 @@ class Config(Base):
|
|||||||
cors_allowed_origins: List[str] = ["*"]
|
cors_allowed_origins: List[str] = ["*"]
|
||||||
|
|
||||||
# Tailwind config.
|
# 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 when launching the gunicorn server. TODO(rename this to backend_timeout?)
|
||||||
timeout: int = 120
|
timeout: int = 120
|
||||||
|
@ -173,6 +173,7 @@ class LogLevel(str, Enum):
|
|||||||
"""The log levels."""
|
"""The log levels."""
|
||||||
|
|
||||||
DEBUG = "debug"
|
DEBUG = "debug"
|
||||||
|
DEFAULT = "default"
|
||||||
INFO = "info"
|
INFO = "info"
|
||||||
WARNING = "warning"
|
WARNING = "warning"
|
||||||
ERROR = "error"
|
ERROR = "error"
|
||||||
|
@ -54,6 +54,9 @@ class Bun(SimpleNamespace):
|
|||||||
# Path of the bunfig file
|
# Path of the bunfig file
|
||||||
CONFIG_PATH = "bunfig.toml"
|
CONFIG_PATH = "bunfig.toml"
|
||||||
|
|
||||||
|
# The environment variable to use the system installed bun.
|
||||||
|
USE_SYSTEM_VAR = "REFLEX_USE_SYSTEM_BUN"
|
||||||
|
|
||||||
|
|
||||||
# FNM config.
|
# FNM config.
|
||||||
class Fnm(SimpleNamespace):
|
class Fnm(SimpleNamespace):
|
||||||
@ -96,6 +99,9 @@ class Node(SimpleNamespace):
|
|||||||
# The default path where npm is installed.
|
# The default path where npm is installed.
|
||||||
NPM_PATH = os.path.join(BIN_PATH, "npm")
|
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):
|
class PackageJson(SimpleNamespace):
|
||||||
"""Constants used to build the package.json file."""
|
"""Constants used to build the package.json file."""
|
||||||
@ -115,7 +121,7 @@ class PackageJson(SimpleNamespace):
|
|||||||
"@emotion/react": "11.11.1",
|
"@emotion/react": "11.11.1",
|
||||||
"axios": "1.6.0",
|
"axios": "1.6.0",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"next": "14.0.1",
|
"next": "14.2.13",
|
||||||
"next-sitemap": "4.1.8",
|
"next-sitemap": "4.1.8",
|
||||||
"next-themes": "0.2.1",
|
"next-themes": "0.2.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
|
@ -18,10 +18,12 @@ from typing import (
|
|||||||
get_type_hints,
|
get_type_hints,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from typing_extensions import get_args, get_origin
|
||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.utils import format
|
from reflex.utils import format
|
||||||
from reflex.utils.exceptions import EventFnArgMismatch, EventHandlerArgMismatch
|
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 import VarData
|
||||||
from reflex.vars.base import LiteralVar, Var
|
from reflex.vars.base import LiteralVar, Var
|
||||||
from reflex.vars.function import FunctionStringVar, FunctionVar
|
from reflex.vars.function import FunctionStringVar, FunctionVar
|
||||||
@ -217,7 +219,7 @@ class EventHandler(EventActionsMixin):
|
|||||||
raise EventHandlerTypeError(
|
raise EventHandlerTypeError(
|
||||||
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
|
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
|
||||||
) from e
|
) from e
|
||||||
payload = tuple(zip(fn_args, values, strict=False))
|
payload = tuple(zip(fn_args, values))
|
||||||
|
|
||||||
# Return the event spec.
|
# Return the event spec.
|
||||||
return EventSpec(
|
return EventSpec(
|
||||||
@ -310,7 +312,7 @@ class EventSpec(EventActionsMixin):
|
|||||||
raise EventHandlerTypeError(
|
raise EventHandlerTypeError(
|
||||||
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
|
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
|
||||||
) from e
|
) 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)
|
return self.with_args(self.args + new_payload)
|
||||||
|
|
||||||
|
|
||||||
@ -417,7 +419,7 @@ class FileUpload:
|
|||||||
on_upload_progress: Optional[Union[EventHandler, Callable]] = None
|
on_upload_progress: Optional[Union[EventHandler, Callable]] = None
|
||||||
|
|
||||||
@staticmethod
|
@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.
|
"""Args spec for on_upload_progress event handler.
|
||||||
|
|
||||||
Returns:
|
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):
|
def parse_args_spec(arg_spec: ArgsSpec):
|
||||||
"""Parse the args provided in the ArgsSpec of an event trigger.
|
"""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)
|
spec = inspect.getfullargspec(arg_spec)
|
||||||
annotations = get_type_hints(arg_spec)
|
annotations = get_type_hints(arg_spec)
|
||||||
|
|
||||||
return 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
|
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:
|
def call_event_fn(fn: Callable, arg_spec: ArgsSpec) -> list[EventSpec] | Var:
|
||||||
"""Call a function to a list of event specs.
|
"""Call a function to a list of event specs.
|
||||||
|
|
||||||
The function should return a single EventSpec, a list of EventSpecs, or a
|
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
|
single Var.
|
||||||
EventFnArgsMismatch will be raised.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
fn: The function to call.
|
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.
|
The event specs from calling the function or a Var.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
EventFnArgMismatch: If the function signature doesn't match the arg spec.
|
|
||||||
EventHandlerValueError: If the lambda returns an unusable value.
|
EventHandlerValueError: If the lambda returns an unusable value.
|
||||||
"""
|
"""
|
||||||
# Import here to avoid circular imports.
|
# 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
|
from reflex.utils.exceptions import EventHandlerValueError
|
||||||
|
|
||||||
# Check that fn signature matches arg_spec
|
# Check that fn signature matches arg_spec
|
||||||
fn_args = inspect.getfullargspec(fn).args
|
parsed_args = check_fn_match_arg_spec(fn, arg_spec)
|
||||||
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/"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Call the function with the parsed args.
|
# Call the function with the parsed args.
|
||||||
out = fn(*parsed_args)
|
out = fn(*parsed_args)
|
||||||
@ -1025,6 +1062,9 @@ def fix_events(
|
|||||||
token: The user token.
|
token: The user token.
|
||||||
router_data: The optional router data to set in the event.
|
router_data: The optional router data to set in the event.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If the event type is not what was expected.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The fixed events.
|
The fixed events.
|
||||||
"""
|
"""
|
||||||
@ -1048,7 +1088,8 @@ def fix_events(
|
|||||||
# Otherwise, create an event from the event spec.
|
# Otherwise, create an event from the event spec.
|
||||||
if isinstance(e, EventHandler):
|
if isinstance(e, EventHandler):
|
||||||
e = e()
|
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)
|
name = format.format_event_handler(e.handler)
|
||||||
payload = {k._js_expr: v._decode() for k, v in e.args} # type: ignore
|
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:
|
Raises:
|
||||||
FileNotFoundError: If the file does not exist.
|
FileNotFoundError: If the file does not exist.
|
||||||
|
ValueError: If the module is None.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The relative URL to the copied asset.
|
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.
|
# Determine the file by which the asset is exposed.
|
||||||
calling_file = inspect.stack()[1].filename
|
calling_file = inspect.stack()[1].filename
|
||||||
module = inspect.getmodule(inspect.stack()[1][0])
|
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(".", "/")
|
caller_module_path = module.__name__.replace(".", "/")
|
||||||
|
|
||||||
subfolder = f"{caller_module_path}/{subfolder}" if subfolder else caller_module_path
|
subfolder = f"{caller_module_path}/{subfolder}" if subfolder else caller_module_path
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import dataclasses
|
import dataclasses
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
from typing import Any, Callable, Union
|
from typing import Any, Callable, Union
|
||||||
|
|
||||||
@ -90,12 +91,16 @@ class ClientStateVar(Var):
|
|||||||
default: The default value of the variable.
|
default: The default value of the variable.
|
||||||
global_ref: Whether the state should be accessible in any Component and on the backend.
|
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:
|
Returns:
|
||||||
ClientStateVar
|
ClientStateVar
|
||||||
"""
|
"""
|
||||||
if var_name is None:
|
if var_name is None:
|
||||||
var_name = get_unique_variable_name()
|
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:
|
if default is NoValue:
|
||||||
default_var = Var(_js_expr="")
|
default_var = Var(_js_expr="")
|
||||||
elif not isinstance(default, Var):
|
elif not isinstance(default, Var):
|
||||||
@ -174,15 +179,15 @@ class ClientStateVar(Var):
|
|||||||
else self._setter_name
|
else self._setter_name
|
||||||
)
|
)
|
||||||
if value is not NoValue:
|
if value is not NoValue:
|
||||||
import re
|
|
||||||
|
|
||||||
# This is a hack to make it work like an EventSpec taking an arg
|
# This is a hack to make it work like an EventSpec taking an arg
|
||||||
value_str = str(LiteralVar.create(value))
|
value_str = str(LiteralVar.create(value))
|
||||||
|
|
||||||
|
if value_str.startswith("_"):
|
||||||
# remove patterns of ["*"] from the value_str using regex
|
# remove patterns of ["*"] from the value_str using regex
|
||||||
arg = re.sub(r"\[\".*\"\]", "", value_str)
|
arg = re.sub(r"\[\".*\"\]", "", value_str)
|
||||||
|
setter = f"(({arg}) => {setter}({value_str}))"
|
||||||
setter = f"({arg}) => {setter}({str(value)})"
|
else:
|
||||||
|
setter = f"(() => {setter}({value_str}))"
|
||||||
return Var(
|
return Var(
|
||||||
_js_expr=setter,
|
_js_expr=setter,
|
||||||
_var_data=VarData(imports=_refs_import if self._global_ref else {}),
|
_var_data=VarData(imports=_refs_import if self._global_ref else {}),
|
||||||
|
@ -12,10 +12,12 @@ async def run_in_thread(func) -> Any:
|
|||||||
Args:
|
Args:
|
||||||
func (callable): The non-async function to run.
|
func (callable): The non-async function to run.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If the function is an async function.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Any: The return value of the function.
|
Any: The return value of the function.
|
||||||
"""
|
"""
|
||||||
assert not asyncio.coroutines.iscoroutinefunction(
|
if asyncio.coroutines.iscoroutinefunction(func):
|
||||||
func
|
raise ValueError("func must be a non-async function")
|
||||||
), "func must be a non-async function"
|
|
||||||
return await asyncio.get_event_loop().run_in_executor(None, func)
|
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.event import Event, get_hydrate_event
|
||||||
from reflex.middleware.middleware import Middleware
|
from reflex.middleware.middleware import Middleware
|
||||||
from reflex.state import BaseState, StateUpdate
|
from reflex.state import BaseState, StateUpdate
|
||||||
from reflex.utils import format
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from reflex.app import App
|
from reflex.app import App
|
||||||
@ -43,7 +42,7 @@ class HydrateMiddleware(Middleware):
|
|||||||
setattr(state, constants.CompileVars.IS_HYDRATED, False)
|
setattr(state, constants.CompileVars.IS_HYDRATED, False)
|
||||||
|
|
||||||
# Get the initial state.
|
# Get the initial state.
|
||||||
delta = format.format_state(state.dict())
|
delta = state.dict()
|
||||||
# since a full dict was captured, clean any dirtiness
|
# since a full dict was captured, clean any dirtiness
|
||||||
state._clean()
|
state._clean()
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ from reflex import constants
|
|||||||
from reflex.base import Base
|
from reflex.base import Base
|
||||||
from reflex.config import get_config
|
from reflex.config import get_config
|
||||||
from reflex.utils import console
|
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:
|
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 = [
|
non_default_primary_key_fields = [
|
||||||
field_name
|
field_name
|
||||||
for field_name, field in cls.__fields__.items()
|
for field_name, field in cls.__fields__.items()
|
||||||
if field_name != "id"
|
if field_name != "id" and sqlmodel_field_has_primary_key(field)
|
||||||
and getattr(field.field_info, "primary_key", None) is True
|
|
||||||
]
|
]
|
||||||
if non_default_primary_key_fields:
|
if non_default_primary_key_fields:
|
||||||
cls.__fields__.pop("id", None)
|
cls.__fields__.pop("id", None)
|
||||||
|
@ -63,3 +63,22 @@ def page(
|
|||||||
return render_fn
|
return render_fn
|
||||||
|
|
||||||
return decorator
|
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 import constants
|
||||||
from reflex.config import get_config
|
from reflex.config import get_config
|
||||||
|
from reflex.constants.base import LogLevel
|
||||||
from reflex.custom_components.custom_components import custom_components_cli
|
from reflex.custom_components.custom_components import custom_components_cli
|
||||||
from reflex.state import reset_disk_state_manager
|
from reflex.state import reset_disk_state_manager
|
||||||
from reflex.utils import console, redir, telemetry
|
from reflex.utils import console, redir, telemetry
|
||||||
@ -229,7 +230,8 @@ def _run(
|
|||||||
exec.run_frontend_prod,
|
exec.run_frontend_prod,
|
||||||
exec.run_backend_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.
|
# Post a telemetry event.
|
||||||
telemetry.send(f"run-{env.value}")
|
telemetry.send(f"run-{env.value}")
|
||||||
@ -245,15 +247,30 @@ def _run(
|
|||||||
setup_frontend(Path.cwd())
|
setup_frontend(Path.cwd())
|
||||||
commands.append((frontend_cmd, Path.cwd(), frontend_port, backend))
|
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.
|
# In prod mode, run the backend on a separate thread.
|
||||||
if backend and env == constants.Env.PROD:
|
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.
|
# Start the frontend and backend.
|
||||||
with processes.run_concurrently_context(*commands):
|
with processes.run_concurrently_context(*commands):
|
||||||
# In dev mode, run the backend on the main thread.
|
# In dev mode, run the backend on the main thread.
|
||||||
if backend and env == constants.Env.DEV:
|
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
|
# The windows uvicorn bug workaround
|
||||||
# https://github.com/reflex-dev/reflex/issues/2335
|
# https://github.com/reflex-dev/reflex/issues/2335
|
||||||
if constants.IS_WINDOWS and exec.frontend_process:
|
if constants.IS_WINDOWS and exec.frontend_process:
|
||||||
|
102
reflex/state.py
102
reflex/state.py
@ -12,6 +12,7 @@ import os
|
|||||||
import uuid
|
import uuid
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from hashlib import md5
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from types import FunctionType, MethodType
|
from types import FunctionType, MethodType
|
||||||
from typing import (
|
from typing import (
|
||||||
@ -29,10 +30,12 @@ from typing import (
|
|||||||
Type,
|
Type,
|
||||||
Union,
|
Union,
|
||||||
cast,
|
cast,
|
||||||
|
get_type_hints,
|
||||||
)
|
)
|
||||||
|
|
||||||
import dill
|
import dill
|
||||||
from sqlalchemy.orm import DeclarativeBase
|
from sqlalchemy.orm import DeclarativeBase
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
from reflex.config import get_config
|
from reflex.config import get_config
|
||||||
from reflex.vars.base import (
|
from reflex.vars.base import (
|
||||||
@ -41,6 +44,7 @@ from reflex.vars.base import (
|
|||||||
Var,
|
Var,
|
||||||
computed_var,
|
computed_var,
|
||||||
dispatch,
|
dispatch,
|
||||||
|
get_unique_variable_name,
|
||||||
is_computed_var,
|
is_computed_var,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -72,7 +76,7 @@ from reflex.utils.exceptions import (
|
|||||||
LockExpiredError,
|
LockExpiredError,
|
||||||
)
|
)
|
||||||
from reflex.utils.exec import is_testing_env
|
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.utils.types import override
|
||||||
from reflex.vars import VarData
|
from reflex.vars import VarData
|
||||||
|
|
||||||
@ -572,6 +576,15 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
for name, value in cls.__dict__.items()
|
for name, value in cls.__dict__.items()
|
||||||
if types.is_backend_base_variable(name, cls)
|
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.backend_vars = {
|
||||||
**cls.inherited_backend_vars,
|
**cls.inherited_backend_vars,
|
||||||
@ -684,6 +697,36 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
and hasattr(value, "__code__")
|
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
|
@classmethod
|
||||||
def _mixins(cls) -> List[Type]:
|
def _mixins(cls) -> List[Type]:
|
||||||
"""Get the mixin classes of the state.
|
"""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:
|
def get_parent_state(cls) -> Type[BaseState] | None:
|
||||||
"""Get the parent state.
|
"""Get the parent state.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If more than one parent state is found.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The parent state.
|
The parent state.
|
||||||
"""
|
"""
|
||||||
@ -835,9 +881,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
for base in cls.__bases__
|
for base in cls.__bases__
|
||||||
if issubclass(base, BaseState) and base is not BaseState and not base._mixin
|
if issubclass(base, BaseState) and base is not BaseState and not base._mixin
|
||||||
]
|
]
|
||||||
assert (
|
if len(parent_states) >= 2:
|
||||||
len(parent_states) < 2
|
raise ValueError(f"Only one parent state is allowed {parent_states}.")
|
||||||
), f"Only one parent state is allowed {parent_states}."
|
|
||||||
return parent_states[0] if len(parent_states) == 1 else None # type: ignore
|
return parent_states[0] if len(parent_states) == 1 else None # type: ignore
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -1316,7 +1361,6 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
for part1, part2 in zip(
|
for part1, part2 in zip(
|
||||||
cls.get_full_name().split("."),
|
cls.get_full_name().split("."),
|
||||||
other.get_full_name().split("."),
|
other.get_full_name().split("."),
|
||||||
strict=False,
|
|
||||||
):
|
):
|
||||||
if part1 != part2:
|
if part1 != part2:
|
||||||
break
|
break
|
||||||
@ -1790,9 +1834,6 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
for substate in self.dirty_substates.union(self._always_dirty_substates):
|
for substate in self.dirty_substates.union(self._always_dirty_substates):
|
||||||
delta.update(substates[substate].get_delta())
|
delta.update(substates[substate].get_delta())
|
||||||
|
|
||||||
# Format the delta.
|
|
||||||
delta = format.format_state(delta)
|
|
||||||
|
|
||||||
# Return the delta.
|
# Return the delta.
|
||||||
return delta
|
return delta
|
||||||
|
|
||||||
@ -2433,7 +2474,7 @@ class StateUpdate:
|
|||||||
Returns:
|
Returns:
|
||||||
The state update as a JSON string.
|
The state update as a JSON string.
|
||||||
"""
|
"""
|
||||||
return format.json_dumps(dataclasses.asdict(self))
|
return format.json_dumps(self)
|
||||||
|
|
||||||
|
|
||||||
class StateManager(Base, ABC):
|
class StateManager(Base, ABC):
|
||||||
@ -2592,16 +2633,24 @@ def _serialize_type(type_: Any) -> str:
|
|||||||
return f"{type_.__module__}.{type_.__qualname__}"
|
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(
|
def state_to_schema(
|
||||||
state: BaseState,
|
state: BaseState,
|
||||||
) -> List[
|
) -> List[Tuple[str, str, Any, Union[bool, None], Any]]:
|
||||||
Tuple[
|
|
||||||
str,
|
|
||||||
str,
|
|
||||||
Any,
|
|
||||||
Union[bool, None],
|
|
||||||
]
|
|
||||||
]:
|
|
||||||
"""Convert a state to a schema.
|
"""Convert a state to a schema.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -2621,6 +2670,7 @@ def state_to_schema(
|
|||||||
if isinstance(model_field.required, bool)
|
if isinstance(model_field.required, bool)
|
||||||
else None
|
else None
|
||||||
),
|
),
|
||||||
|
(model_field.default if is_serializable(model_field.default) else None),
|
||||||
)
|
)
|
||||||
for field_name, model_field in state.__fields__.items()
|
for field_name, model_field in state.__fields__.items()
|
||||||
)
|
)
|
||||||
@ -2705,7 +2755,9 @@ class StateManagerDisk(StateManager):
|
|||||||
Returns:
|
Returns:
|
||||||
The path for the token.
|
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:
|
async def load_state(self, token: str, root_state: BaseState) -> BaseState:
|
||||||
"""Load a state object based on the provided token.
|
"""Load a state object based on the provided token.
|
||||||
@ -3649,22 +3701,16 @@ class MutableProxy(wrapt.ObjectProxy):
|
|||||||
|
|
||||||
|
|
||||||
@serializer
|
@serializer
|
||||||
def serialize_mutable_proxy(mp: MutableProxy) -> SerializedType:
|
def serialize_mutable_proxy(mp: MutableProxy):
|
||||||
"""Serialize the wrapped value of a MutableProxy.
|
"""Return the wrapped value of a MutableProxy.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
mp: The MutableProxy to serialize.
|
mp: The MutableProxy to serialize.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The serialized wrapped object.
|
The wrapped object.
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: when the wrapped object is not serializable.
|
|
||||||
"""
|
"""
|
||||||
value = serialize(mp.__wrapped__)
|
return mp.__wrapped__
|
||||||
if value is None:
|
|
||||||
raise ValueError(f"Cannot serialize {type(mp.__wrapped__)}")
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
class ImmutableMutableProxy(MutableProxy):
|
class ImmutableMutableProxy(MutableProxy):
|
||||||
|
@ -13,6 +13,7 @@ from reflex.utils.imports import ImportVar
|
|||||||
from reflex.vars import VarData
|
from reflex.vars import VarData
|
||||||
from reflex.vars.base import CallableVar, LiteralVar, Var
|
from reflex.vars.base import CallableVar, LiteralVar, Var
|
||||||
from reflex.vars.function import FunctionVar
|
from reflex.vars.function import FunctionVar
|
||||||
|
from reflex.vars.object import ObjectVar
|
||||||
|
|
||||||
SYSTEM_COLOR_MODE: str = "system"
|
SYSTEM_COLOR_MODE: str = "system"
|
||||||
LIGHT_COLOR_MODE: str = "light"
|
LIGHT_COLOR_MODE: str = "light"
|
||||||
@ -188,7 +189,16 @@ def convert(
|
|||||||
out[k] = return_value
|
out[k] = return_value
|
||||||
|
|
||||||
for key, value in style_dict.items():
|
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):
|
if isinstance(value, Var):
|
||||||
return_val = value
|
return_val = value
|
||||||
new_var_data = value._get_all_var_data()
|
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.
|
"""Format a pseudo selector for emotion CSS-in-JS.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key: Underscore-prefixed or colon-prefixed pseudo selector key (_hover).
|
key: Underscore-prefixed or colon-prefixed pseudo selector key (_hover/:hover).
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A self-referential pseudo selector key (&:hover).
|
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
|
This is necessary when the backend is restarted and the state manager is a
|
||||||
StateManagerRedis instance.
|
StateManagerRedis instance.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
RuntimeError: when the state manager cannot be reset
|
||||||
"""
|
"""
|
||||||
if (
|
if (
|
||||||
self.app_instance is not None
|
self.app_instance is not None
|
||||||
@ -354,7 +357,8 @@ class AppHarness:
|
|||||||
self.app_instance._state_manager = StateManagerRedis.create(
|
self.app_instance._state_manager = StateManagerRedis.create(
|
||||||
state=self.app_instance.state,
|
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):
|
def _start_frontend(self):
|
||||||
# Set up the frontend.
|
# Set up the frontend.
|
||||||
@ -787,13 +791,13 @@ class AppHarness:
|
|||||||
Raises:
|
Raises:
|
||||||
RuntimeError: when the app hasn't started running
|
RuntimeError: when the app hasn't started running
|
||||||
TimeoutError: when the timeout expires before any states are seen
|
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:
|
if self.app_instance is None:
|
||||||
raise RuntimeError("App is not running.")
|
raise RuntimeError("App is not running.")
|
||||||
state_manager = self.app_instance.state_manager
|
state_manager = self.app_instance.state_manager
|
||||||
assert isinstance(
|
if not isinstance(state_manager, (StateManagerMemory, StateManagerDisk)):
|
||||||
state_manager, (StateManagerMemory, StateManagerDisk)
|
raise ValueError("Only works with memory or disk state manager")
|
||||||
), "Only works with memory state manager"
|
|
||||||
if not self._poll_for(
|
if not self._poll_for(
|
||||||
target=lambda: state_manager.states,
|
target=lambda: state_manager.states,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
|
@ -69,3 +69,21 @@ def pydantic_v1_patch():
|
|||||||
|
|
||||||
with pydantic_v1_patch():
|
with pydantic_v1_patch():
|
||||||
import sqlmodel as sqlmodel
|
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.
|
kwargs: Keyword arguments to pass to the print function.
|
||||||
"""
|
"""
|
||||||
if is_debug():
|
if is_debug():
|
||||||
msg_ = f"[blue]Debug: {msg}[/blue]"
|
msg_ = f"[purple]Debug: {msg}[/purple]"
|
||||||
if progress := kwargs.pop("progress", None):
|
if progress := kwargs.pop("progress", None):
|
||||||
progress.console.print(msg_, **kwargs)
|
progress.console.print(msg_, **kwargs)
|
||||||
else:
|
else:
|
||||||
|
@ -111,3 +111,7 @@ class GeneratedCodeHasNoFunctionDefs(ReflexError):
|
|||||||
|
|
||||||
class PrimitiveUnserializableToJSON(ReflexError, ValueError):
|
class PrimitiveUnserializableToJSON(ReflexError, ValueError):
|
||||||
"""Raised when a primitive type is unserializable to JSON. Usually with NaN and Infinity."""
|
"""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 import constants
|
||||||
from reflex.config import get_config
|
from reflex.config import get_config
|
||||||
|
from reflex.constants.base import LogLevel
|
||||||
from reflex.utils import console, path_ops
|
from reflex.utils import console, path_ops
|
||||||
from reflex.utils.prerequisites import get_web_dir
|
from reflex.utils.prerequisites import get_web_dir
|
||||||
|
|
||||||
@ -60,6 +61,13 @@ def kill(proc_pid: int):
|
|||||||
process.kill()
|
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
|
# run_process_and_launch_url is assumed to be used
|
||||||
# only to launch the frontend
|
# only to launch the frontend
|
||||||
# If this is not the case, might have to change the logic
|
# 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 ''}"
|
f"App running at: [bold green]{url}[/bold green]{' (Frontend-only mode)' if not backend_present else ''}"
|
||||||
)
|
)
|
||||||
if backend_present:
|
if backend_present:
|
||||||
console.print(
|
notify_backend()
|
||||||
f"Backend running at: [bold green]http://0.0.0.0:{get_config().backend_port}[/bold green]"
|
|
||||||
)
|
|
||||||
first_run = False
|
first_run = False
|
||||||
else:
|
else:
|
||||||
console.print("New packages detected: Updating app...")
|
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(
|
def run_backend(
|
||||||
host: str,
|
host: str,
|
||||||
port: int,
|
port: int,
|
||||||
loglevel: constants.LogLevel = constants.LogLevel.ERROR,
|
loglevel: constants.LogLevel = constants.LogLevel.ERROR,
|
||||||
|
frontend_present: bool = False,
|
||||||
):
|
):
|
||||||
"""Run the backend.
|
"""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:
|
Args:
|
||||||
host: The app host
|
host: The app host
|
||||||
port: The app port
|
port: The app port
|
||||||
@ -186,22 +248,55 @@ def run_backend(
|
|||||||
"""
|
"""
|
||||||
import uvicorn
|
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(
|
uvicorn.run(
|
||||||
app=f"{app_module}.{constants.CompileVars.API}",
|
app=f"{get_app_module()}.{constants.CompileVars.API}",
|
||||||
host=host,
|
host=host,
|
||||||
port=port,
|
port=port,
|
||||||
log_level=loglevel.value,
|
log_level=loglevel.value,
|
||||||
reload=True,
|
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,
|
host: str,
|
||||||
port: int,
|
port: int,
|
||||||
loglevel: constants.LogLevel = constants.LogLevel.ERROR,
|
loglevel: constants.LogLevel = constants.LogLevel.ERROR,
|
||||||
|
frontend_present: bool = False,
|
||||||
):
|
):
|
||||||
"""Run the backend.
|
"""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:
|
Args:
|
||||||
host: The app host
|
host: The app host
|
||||||
port: The app port
|
port: The app port
|
||||||
@ -220,14 +334,11 @@ def run_backend_prod(
|
|||||||
from reflex.utils import processes
|
from reflex.utils import processes
|
||||||
|
|
||||||
config = get_config()
|
config = get_config()
|
||||||
num_workers = (
|
|
||||||
processes.get_num_workers()
|
app_module = get_app_module()
|
||||||
if not config.gunicorn_workers
|
|
||||||
else config.gunicorn_workers
|
|
||||||
)
|
|
||||||
RUN_BACKEND_PROD = f"gunicorn --worker-class {config.gunicorn_worker_class} --preload --timeout {config.timeout} --log-level critical".split()
|
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()
|
RUN_BACKEND_PROD_WINDOWS = f"uvicorn --timeout-keep-alive {config.timeout}".split()
|
||||||
app_module = f"reflex.app_module_for_backend:{constants.CompileVars.APP}"
|
|
||||||
command = (
|
command = (
|
||||||
[
|
[
|
||||||
*RUN_BACKEND_PROD_WINDOWS,
|
*RUN_BACKEND_PROD_WINDOWS,
|
||||||
@ -243,7 +354,7 @@ def run_backend_prod(
|
|||||||
"--bind",
|
"--bind",
|
||||||
f"{host}:{port}",
|
f"{host}:{port}",
|
||||||
"--threads",
|
"--threads",
|
||||||
str(num_workers),
|
str(_get_backend_workers()),
|
||||||
f"{app_module}()",
|
f"{app_module}()",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -252,7 +363,7 @@ def run_backend_prod(
|
|||||||
"--log-level",
|
"--log-level",
|
||||||
loglevel.value,
|
loglevel.value,
|
||||||
"--workers",
|
"--workers",
|
||||||
str(num_workers),
|
str(_get_backend_workers()),
|
||||||
]
|
]
|
||||||
processes.new_process(
|
processes.new_process(
|
||||||
command,
|
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():
|
def output_system_info():
|
||||||
"""Show system information if the loglevel is in DEBUG."""
|
"""Show system information if the loglevel is in DEBUG."""
|
||||||
if console._LOG_LEVEL > constants.LogLevel.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 typing import TYPE_CHECKING, Any, Callable, List, Optional, Union
|
||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.utils import exceptions, types
|
from reflex.utils import exceptions
|
||||||
from reflex.utils.console import deprecate
|
from reflex.utils.console import deprecate
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -345,6 +345,7 @@ def format_prop(
|
|||||||
Raises:
|
Raises:
|
||||||
exceptions.InvalidStylePropError: If the style prop value is not a valid type.
|
exceptions.InvalidStylePropError: If the style prop value is not a valid type.
|
||||||
TypeError: If the prop is not valid.
|
TypeError: If the prop is not valid.
|
||||||
|
ValueError: If the prop is not a string.
|
||||||
"""
|
"""
|
||||||
# import here to avoid circular import.
|
# import here to avoid circular import.
|
||||||
from reflex.event import EventChain
|
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
|
raise TypeError(f"Could not format prop: {prop} of type {type(prop)}") from e
|
||||||
|
|
||||||
# Wrap the variable in braces.
|
# 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)
|
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()}
|
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:
|
def format_state_name(state_name: str) -> str:
|
||||||
"""Format a state name, replacing dots with double underscore.
|
"""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))
|
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:
|
def get_node_bin_path() -> str | None:
|
||||||
"""Get the node binary dir path.
|
"""Get the node binary dir path.
|
||||||
|
|
||||||
@ -149,7 +184,7 @@ def get_node_path() -> str | None:
|
|||||||
The path to the node binary file.
|
The path to the node binary file.
|
||||||
"""
|
"""
|
||||||
node_path = Path(constants.Node.PATH)
|
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(which("node"))
|
||||||
return str(node_path)
|
return str(node_path)
|
||||||
|
|
||||||
|
@ -74,6 +74,18 @@ def get_web_dir() -> Path:
|
|||||||
return workdir
|
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):
|
def check_latest_package_version(package_name: str):
|
||||||
"""Check if the latest version of the package is installed.
|
"""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"
|
url = f"https://pypi.org/pypi/{package_name}/json"
|
||||||
response = net.get(url)
|
response = net.get(url)
|
||||||
latest_version = response.json()["info"]["version"]
|
latest_version = response.json()["info"]["version"]
|
||||||
if (
|
if get_or_set_last_reflex_version_check_datetime():
|
||||||
version.parse(current_version) < version.parse(latest_version)
|
# Versions were already checked and saved in reflex.json, no need to warn again
|
||||||
and not get_or_set_last_reflex_version_check_datetime()
|
return
|
||||||
):
|
if version.parse(current_version) < version.parse(latest_version):
|
||||||
# only show a warning when the host version is outdated and
|
# Show a warning when the host version is older than PyPI version
|
||||||
# the last_version_check_datetime is not set in reflex.json
|
|
||||||
console.warn(
|
console.warn(
|
||||||
f"Your version ({current_version}) of {package_name} is out of date. Upgrade to {latest_version} with 'pip install {package_name} --upgrade'"
|
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:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -130,7 +143,7 @@ def check_node_version() -> bool:
|
|||||||
# Compare the version numbers
|
# Compare the version numbers
|
||||||
return (
|
return (
|
||||||
current_version >= version.parse(constants.Node.MIN_VERSION)
|
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)
|
else current_version == version.parse(constants.Node.VERSION)
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
@ -291,7 +304,7 @@ def get_compiled_app(reload: bool = False, export: bool = False) -> ModuleType:
|
|||||||
"""
|
"""
|
||||||
app_module = get_app(reload=reload)
|
app_module = get_app(reload=reload)
|
||||||
app = getattr(app_module, constants.CompileVars.APP)
|
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).
|
# before compiling the app in a thread to avoid event loop error (REF-2172).
|
||||||
app._apply_decorated_pages()
|
app._apply_decorated_pages()
|
||||||
app._compile(export=export)
|
app._compile(export=export)
|
||||||
@ -1021,6 +1034,8 @@ def validate_bun():
|
|||||||
# if a custom bun path is provided, make sure its valid
|
# if a custom bun path is provided, make sure its valid
|
||||||
# This is specific to non-FHS OS
|
# This is specific to non-FHS OS
|
||||||
bun_path = get_config().bun_path
|
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:
|
if bun_path != constants.Bun.DEFAULT_PATH:
|
||||||
console.info(f"Using custom Bun path: {bun_path}")
|
console.info(f"Using custom Bun path: {bun_path}")
|
||||||
bun_version = get_bun_version()
|
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_path = Path(app_name, app_name + constants.Ext.PY)
|
||||||
main_module_code = main_module_path.read_text()
|
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+)+",
|
r"def index\(\).*:\n([^\n]\s+.*\n+)+",
|
||||||
replace_content,
|
replace_content,
|
||||||
main_module_code,
|
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:
|
def format_address_width(address_width) -> int | None:
|
||||||
|
@ -12,7 +12,6 @@ from pathlib import Path
|
|||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
Any,
|
||||||
Callable,
|
Callable,
|
||||||
Dict,
|
|
||||||
List,
|
List,
|
||||||
Literal,
|
Literal,
|
||||||
Optional,
|
Optional,
|
||||||
@ -126,7 +125,8 @@ def serialize(
|
|||||||
# If there is no serializer, return None.
|
# If there is no serializer, return None.
|
||||||
if serializer is None:
|
if serializer is None:
|
||||||
if dataclasses.is_dataclass(value) and not isinstance(value, type):
|
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:
|
if get_type:
|
||||||
return None, None
|
return None, None
|
||||||
return None
|
return None
|
||||||
@ -214,32 +214,6 @@ def serialize_type(value: type) -> str:
|
|||||||
return value.__name__
|
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
|
@serializer
|
||||||
def serialize_base(value: Base) -> dict:
|
def serialize_base(value: Base) -> dict:
|
||||||
"""Serialize a Base instance.
|
"""Serialize a Base instance.
|
||||||
@ -250,33 +224,20 @@ def serialize_base(value: Base) -> dict:
|
|||||||
Returns:
|
Returns:
|
||||||
The serialized Base.
|
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
|
@serializer
|
||||||
def serialize_list(value: Union[List, Tuple, Set]) -> list:
|
def serialize_set(value: Set) -> list:
|
||||||
"""Serialize a list to a JSON string.
|
"""Serialize a set to a JSON serializable list.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
value: The list to serialize.
|
value: The set to serialize.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The serialized list.
|
The serialized list.
|
||||||
"""
|
"""
|
||||||
return [serialize(item) for item in value]
|
return list(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()}
|
|
||||||
|
|
||||||
|
|
||||||
@serializer(to=str)
|
@serializer(to=str)
|
||||||
|
@ -121,7 +121,7 @@ def _prepare_event(event: str, **kwargs) -> dict:
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
if UTC is None:
|
if UTC is None:
|
||||||
# for python 3.10
|
# for python 3.9 & 3.10
|
||||||
stamp = datetime.utcnow().isoformat()
|
stamp = datetime.utcnow().isoformat()
|
||||||
else:
|
else:
|
||||||
# for python 3.11 & 3.12
|
# for python 3.11 & 3.12
|
||||||
|
@ -9,6 +9,7 @@ import sys
|
|||||||
import types
|
import types
|
||||||
from functools import cached_property, lru_cache, wraps
|
from functools import cached_property, lru_cache, wraps
|
||||||
from typing import (
|
from typing import (
|
||||||
|
TYPE_CHECKING,
|
||||||
Any,
|
Any,
|
||||||
Callable,
|
Callable,
|
||||||
ClassVar,
|
ClassVar,
|
||||||
@ -96,8 +97,22 @@ PrimitiveType = Union[int, float, bool, str, list, dict, set, tuple]
|
|||||||
StateVar = Union[PrimitiveType, Base, None]
|
StateVar = Union[PrimitiveType, Base, None]
|
||||||
StateIterVar = Union[list, set, tuple]
|
StateIterVar = Union[list, set, tuple]
|
||||||
|
|
||||||
# ArgsSpec = Callable[[Var], list[Var]]
|
if TYPE_CHECKING:
|
||||||
ArgsSpec = Callable
|
from reflex.vars.base import Var
|
||||||
|
|
||||||
|
# ArgsSpec = Callable[[Var], list[Var]]
|
||||||
|
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 = {
|
PrimitiveToAnnotation = {
|
||||||
@ -632,7 +647,7 @@ def validate_parameter_literals(func):
|
|||||||
annotations = {param[0]: param[1].annotation for param in func_params}
|
annotations = {param[0]: param[1].annotation for param in func_params}
|
||||||
|
|
||||||
# validate args
|
# 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:
|
if annotations[param] is inspect.Parameter.empty:
|
||||||
continue
|
continue
|
||||||
validate_literal(param, arg, annotations[param], func.__name__)
|
validate_literal(param, arg, annotations[param], func.__name__)
|
||||||
|
@ -1141,7 +1141,7 @@ def serialize_literal(value: LiteralVar):
|
|||||||
Returns:
|
Returns:
|
||||||
The serialized Literal.
|
The serialized Literal.
|
||||||
"""
|
"""
|
||||||
return serializers.serialize(value._var_value)
|
return value._var_value
|
||||||
|
|
||||||
|
|
||||||
P = ParamSpec("P")
|
P = ParamSpec("P")
|
||||||
@ -1559,8 +1559,9 @@ class ComputedVar(Var[RETURN_TYPE]):
|
|||||||
Raises:
|
Raises:
|
||||||
TypeError: If the computed var dependencies are not Var instances or var names.
|
TypeError: If the computed var dependencies are not Var instances or var names.
|
||||||
"""
|
"""
|
||||||
hints = get_type_hints(fget)
|
hint = kwargs.pop("return_type", None) or get_type_hints(fget).get(
|
||||||
hint = hints.get("return", Any)
|
"return", Any
|
||||||
|
)
|
||||||
|
|
||||||
kwargs["_js_expr"] = kwargs.pop("_js_expr", fget.__name__)
|
kwargs["_js_expr"] = kwargs.pop("_js_expr", fget.__name__)
|
||||||
kwargs["_var_type"] = kwargs.pop("_var_type", hint)
|
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
|
# call recursively for nested generic types and merge the results
|
||||||
return {
|
return {
|
||||||
k: v
|
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()
|
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.constants.base import Dirs
|
||||||
from reflex.utils.exceptions import PrimitiveUnserializableToJSON, VarTypeError
|
from reflex.utils.exceptions import PrimitiveUnserializableToJSON, VarTypeError
|
||||||
from reflex.utils.imports import ImportDict, ImportVar
|
from reflex.utils.imports import ImportDict, ImportVar
|
||||||
|
from reflex.utils.types import is_optional
|
||||||
|
|
||||||
from .base import (
|
from .base import (
|
||||||
CustomVarOperationReturn,
|
CustomVarOperationReturn,
|
||||||
@ -524,6 +525,8 @@ class NumberVar(Var[NUMBER_T]):
|
|||||||
Returns:
|
Returns:
|
||||||
The boolean value of the number.
|
The boolean value of the number.
|
||||||
"""
|
"""
|
||||||
|
if is_optional(self._var_type):
|
||||||
|
return boolify((self != None) & (self != 0)) # noqa: E711
|
||||||
return self != 0
|
return self != 0
|
||||||
|
|
||||||
def _is_strict_float(self) -> bool:
|
def _is_strict_float(self) -> bool:
|
||||||
|
@ -194,14 +194,6 @@ class StringVar(Var[str]):
|
|||||||
"""
|
"""
|
||||||
return string_strip_operation(self)
|
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:
|
def reversed(self) -> StringVar:
|
||||||
"""Reverse the string.
|
"""Reverse the string.
|
||||||
|
|
||||||
@ -600,6 +592,29 @@ class LiteralStringVar(LiteralVar, StringVar):
|
|||||||
else:
|
else:
|
||||||
return only_string.to(StringVar, only_string._var_type)
|
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(
|
concat_result = ConcatVarOperation.create(
|
||||||
*filtered_strings_and_vals,
|
*filtered_strings_and_vals,
|
||||||
_var_data=_var_data,
|
_var_data=_var_data,
|
||||||
@ -744,6 +759,26 @@ class ArrayVar(Var[ARRAY_VAR_TYPE]):
|
|||||||
"""
|
"""
|
||||||
if not isinstance(sep, (StringVar, str)):
|
if not isinstance(sep, (StringVar, str)):
|
||||||
raise_unsupported_operand_types("join", (type(self), type(sep)))
|
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)
|
return array_join_operation(self, sep)
|
||||||
|
|
||||||
def reverse(self) -> ArrayVar[ARRAY_VAR_TYPE]:
|
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
|
ARG USERNAME=kerrigan
|
||||||
RUN useradd -m $USERNAME
|
RUN useradd -m $USERNAME
|
@ -13,7 +13,7 @@ function do_export () {
|
|||||||
reflex init --template "$template"
|
reflex init --template "$template"
|
||||||
reflex export
|
reflex export
|
||||||
(
|
(
|
||||||
cd "$SCRIPTPATH/../.."
|
cd "$SCRIPTPATH/../../.."
|
||||||
scripts/integration.sh ~/"$template" dev
|
scripts/integration.sh ~/"$template" dev
|
||||||
pkill -9 -f 'next-server|python3' || true
|
pkill -9 -f 'next-server|python3' || true
|
||||||
sleep 10
|
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