diff --git a/.github/workflows/check_outdated_dependencies.yml b/.github/workflows/check_outdated_dependencies.yml
index fb28bb318..fe8c42608 100644
--- a/.github/workflows/check_outdated_dependencies.yml
+++ b/.github/workflows/check_outdated_dependencies.yml
@@ -74,7 +74,7 @@ jobs:
echo "$outdated"
# Ignore 3rd party dependencies that are not updated.
- filtered_outdated=$(echo "$outdated" | grep -vE 'Package|@chakra-ui|lucide-react|@splinetool/runtime|ag-grid-react|framer-motion|react-markdown|remark-math|remark-gfm|rehype-katex|rehype-raw' || true)
+ filtered_outdated=$(echo "$outdated" | grep -vE 'Package|@chakra-ui|lucide-react|@splinetool/runtime|ag-grid-react|framer-motion|react-markdown|remark-math|remark-gfm|rehype-katex|rehype-raw|remark-unwrap-images' || true)
no_extra=$(echo "$filtered_outdated" | grep -vE '\|\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-' || true)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 4d2e76b31..e2983d1d1 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -3,7 +3,7 @@ fail_fast: true
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
- rev: v0.6.9
+ rev: v0.7.0
hooks:
- id: ruff-format
args: [reflex, tests]
diff --git a/poetry.lock b/poetry.lock
index 144547342..7161e6af7 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -32,13 +32,13 @@ files = [
[[package]]
name = "anyio"
-version = "4.6.0"
+version = "4.6.2.post1"
description = "High level compatibility layer for multiple asynchronous event loop implementations"
optional = false
python-versions = ">=3.9"
files = [
- {file = "anyio-4.6.0-py3-none-any.whl", hash = "sha256:c7d2e9d63e31599eeb636c8c5c03a7e108d73b345f064f1c19fdc87b79036a9a"},
- {file = "anyio-4.6.0.tar.gz", hash = "sha256:137b4559cbb034c477165047febb6ff83f390fc3b20bf181c1fc0a728cb8beeb"},
+ {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"},
+ {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"},
]
[package.dependencies]
@@ -49,7 +49,7 @@ typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""}
[package.extras]
doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
-test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.21.0b1)"]
+test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"]
trio = ["trio (>=0.26.1)"]
[[package]]
@@ -247,101 +247,116 @@ files = [
[[package]]
name = "charset-normalizer"
-version = "3.3.2"
+version = "3.4.0"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
python-versions = ">=3.7.0"
files = [
- {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"},
- {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"},
+ {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"},
+ {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"},
+ {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"},
+ {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"},
+ {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"},
+ {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"},
+ {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"},
+ {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"},
+ {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"},
+ {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"},
+ {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"},
+ {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"},
+ {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"},
+ {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"},
+ {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"},
+ {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"},
+ {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"},
+ {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"},
+ {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"},
+ {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"},
+ {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"},
+ {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"},
+ {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"},
+ {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"},
+ {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"},
+ {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"},
+ {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"},
+ {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"},
+ {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"},
+ {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"},
+ {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"},
+ {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"},
+ {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"},
+ {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"},
+ {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"},
+ {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"},
+ {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"},
+ {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"},
+ {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"},
+ {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"},
+ {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"},
+ {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"},
+ {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"},
+ {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"},
+ {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"},
+ {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"},
+ {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"},
+ {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"},
+ {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"},
+ {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"},
+ {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"},
+ {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"},
+ {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"},
+ {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"},
+ {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"},
+ {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"},
+ {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"},
+ {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"},
+ {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"},
+ {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"},
+ {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"},
+ {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"},
+ {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"},
+ {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"},
+ {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"},
+ {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"},
+ {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"},
+ {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"},
+ {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"},
+ {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"},
+ {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"},
+ {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"},
+ {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"},
+ {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"},
+ {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"},
+ {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"},
+ {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"},
+ {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"},
+ {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"},
+ {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"},
+ {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"},
+ {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"},
+ {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"},
+ {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"},
+ {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"},
+ {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"},
+ {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"},
+ {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"},
+ {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"},
+ {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"},
+ {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"},
+ {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"},
+ {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"},
+ {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"},
+ {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"},
+ {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"},
+ {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"},
+ {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"},
+ {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"},
+ {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"},
+ {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"},
+ {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"},
+ {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"},
+ {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"},
+ {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"},
]
[[package]]
@@ -371,83 +386,73 @@ files = [
[[package]]
name = "coverage"
-version = "7.6.1"
+version = "7.6.4"
description = "Code coverage measurement for Python"
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
files = [
- {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"},
- {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"},
- {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"},
- {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"},
- {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"},
- {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"},
- {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"},
- {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"},
- {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"},
- {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"},
- {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"},
- {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"},
- {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"},
- {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"},
- {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"},
- {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"},
- {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"},
- {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"},
- {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"},
- {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"},
- {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"},
- {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"},
- {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"},
- {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"},
- {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"},
- {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"},
- {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"},
- {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"},
- {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"},
- {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"},
- {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"},
- {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"},
- {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"},
- {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"},
- {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"},
- {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"},
- {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"},
- {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"},
- {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"},
- {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"},
- {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"},
- {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"},
- {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"},
- {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"},
- {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"},
- {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"},
- {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"},
- {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"},
- {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"},
- {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"},
- {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"},
- {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"},
- {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"},
- {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"},
- {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"},
- {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"},
- {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"},
- {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"},
- {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"},
- {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"},
- {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"},
- {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"},
- {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"},
- {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"},
- {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"},
- {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"},
- {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"},
- {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"},
- {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"},
- {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"},
- {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"},
- {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"},
+ {file = "coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07"},
+ {file = "coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0"},
+ {file = "coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72"},
+ {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51"},
+ {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491"},
+ {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b"},
+ {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea"},
+ {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a"},
+ {file = "coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa"},
+ {file = "coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172"},
+ {file = "coverage-7.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b"},
+ {file = "coverage-7.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25"},
+ {file = "coverage-7.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546"},
+ {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b"},
+ {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e"},
+ {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718"},
+ {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db"},
+ {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522"},
+ {file = "coverage-7.6.4-cp311-cp311-win32.whl", hash = "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf"},
+ {file = "coverage-7.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19"},
+ {file = "coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2"},
+ {file = "coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117"},
+ {file = "coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613"},
+ {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27"},
+ {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52"},
+ {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2"},
+ {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1"},
+ {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5"},
+ {file = "coverage-7.6.4-cp312-cp312-win32.whl", hash = "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17"},
+ {file = "coverage-7.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08"},
+ {file = "coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9"},
+ {file = "coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba"},
+ {file = "coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c"},
+ {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06"},
+ {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f"},
+ {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b"},
+ {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21"},
+ {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a"},
+ {file = "coverage-7.6.4-cp313-cp313-win32.whl", hash = "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e"},
+ {file = "coverage-7.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963"},
+ {file = "coverage-7.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f"},
+ {file = "coverage-7.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806"},
+ {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11"},
+ {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3"},
+ {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a"},
+ {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc"},
+ {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70"},
+ {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef"},
+ {file = "coverage-7.6.4-cp313-cp313t-win32.whl", hash = "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e"},
+ {file = "coverage-7.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1"},
+ {file = "coverage-7.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3"},
+ {file = "coverage-7.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c"},
+ {file = "coverage-7.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076"},
+ {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376"},
+ {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0"},
+ {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858"},
+ {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111"},
+ {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901"},
+ {file = "coverage-7.6.4-cp39-cp39-win32.whl", hash = "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09"},
+ {file = "coverage-7.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f"},
+ {file = "coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e"},
+ {file = "coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73"},
]
[package.dependencies]
@@ -458,38 +463,38 @@ toml = ["tomli"]
[[package]]
name = "cryptography"
-version = "43.0.1"
+version = "43.0.3"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
optional = false
python-versions = ">=3.7"
files = [
- {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"},
- {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"},
- {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"},
- {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"},
- {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"},
- {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"},
- {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"},
- {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"},
- {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"},
- {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"},
- {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"},
- {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"},
- {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"},
- {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"},
- {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"},
- {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"},
- {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"},
- {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"},
- {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"},
- {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"},
- {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"},
- {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"},
- {file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"},
- {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"},
- {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"},
- {file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"},
- {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"},
+ {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"},
+ {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"},
+ {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"},
+ {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"},
+ {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"},
+ {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"},
+ {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"},
+ {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"},
+ {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"},
+ {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"},
+ {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"},
+ {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"},
+ {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"},
+ {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"},
+ {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"},
+ {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"},
+ {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"},
+ {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"},
+ {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"},
+ {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"},
+ {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"},
+ {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"},
+ {file = "cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664"},
+ {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08"},
+ {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa"},
+ {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"},
+ {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"},
]
[package.dependencies]
@@ -502,7 +507,7 @@ nox = ["nox"]
pep8test = ["check-sdist", "click", "mypy", "ruff"]
sdist = ["build"]
ssh = ["bcrypt (>=3.1.5)"]
-test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
+test = ["certifi", "cryptography-vectors (==43.0.3)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
test-randomorder = ["pytest-randomly"]
[[package]]
@@ -518,13 +523,13 @@ files = [
[[package]]
name = "distlib"
-version = "0.3.8"
+version = "0.3.9"
description = "Distribution utilities"
optional = false
python-versions = "*"
files = [
- {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
- {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
+ {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"},
+ {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"},
]
[[package]]
@@ -565,18 +570,18 @@ test = ["pytest (>=6)"]
[[package]]
name = "fastapi"
-version = "0.115.0"
+version = "0.115.3"
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
optional = false
python-versions = ">=3.8"
files = [
- {file = "fastapi-0.115.0-py3-none-any.whl", hash = "sha256:17ea427674467486e997206a5ab25760f6b09e069f099b96f5b55a32fb6f1631"},
- {file = "fastapi-0.115.0.tar.gz", hash = "sha256:f93b4ca3529a8ebc6fc3fcf710e5efa8de3df9b41570958abf1d97d843138004"},
+ {file = "fastapi-0.115.3-py3-none-any.whl", hash = "sha256:8035e8f9a2b0aa89cea03b6c77721178ed5358e1aea4cd8570d9466895c0638c"},
+ {file = "fastapi-0.115.3.tar.gz", hash = "sha256:c091c6a35599c036d676fa24bd4a6e19fa30058d93d950216cdc672881f6f7db"},
]
[package.dependencies]
pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0"
-starlette = ">=0.37.2,<0.39.0"
+starlette = ">=0.40.0,<0.42.0"
typing-extensions = ">=4.8.0"
[package.extras]
@@ -601,69 +606,84 @@ typing = ["typing-extensions (>=4.12.2)"]
[[package]]
name = "greenlet"
-version = "3.0.3"
+version = "3.1.1"
description = "Lightweight in-process concurrent programming"
optional = false
python-versions = ">=3.7"
files = [
- {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"},
- {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"},
- {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"},
- {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"},
- {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"},
- {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"},
- {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"},
- {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"},
- {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"},
- {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"},
- {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"},
- {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"},
- {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"},
- {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"},
- {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"},
- {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"},
- {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"},
- {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"},
- {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"},
- {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"},
- {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"},
- {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"},
- {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"},
- {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"},
- {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"},
- {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"},
- {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"},
- {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"},
- {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"},
- {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"},
- {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"},
- {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"},
- {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"},
- {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"},
- {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"},
- {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"},
- {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"},
- {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"},
- {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"},
- {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"},
- {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"},
- {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"},
- {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"},
- {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"},
- {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"},
- {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"},
- {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"},
- {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"},
- {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"},
- {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"},
- {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"},
- {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"},
- {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"},
- {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"},
- {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"},
- {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"},
- {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"},
- {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"},
+ {file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"},
+ {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"},
+ {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0"},
+ {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120"},
+ {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc"},
+ {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617"},
+ {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7"},
+ {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6"},
+ {file = "greenlet-3.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80"},
+ {file = "greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70"},
+ {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159"},
+ {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e"},
+ {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1"},
+ {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383"},
+ {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a"},
+ {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511"},
+ {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395"},
+ {file = "greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39"},
+ {file = "greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d"},
+ {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79"},
+ {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa"},
+ {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441"},
+ {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36"},
+ {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9"},
+ {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0"},
+ {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942"},
+ {file = "greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01"},
+ {file = "greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1"},
+ {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff"},
+ {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a"},
+ {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e"},
+ {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4"},
+ {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e"},
+ {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1"},
+ {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c"},
+ {file = "greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761"},
+ {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011"},
+ {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13"},
+ {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475"},
+ {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b"},
+ {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822"},
+ {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01"},
+ {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6"},
+ {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291"},
+ {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981"},
+ {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803"},
+ {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc"},
+ {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de"},
+ {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa"},
+ {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af"},
+ {file = "greenlet-3.1.1-cp37-cp37m-win32.whl", hash = "sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798"},
+ {file = "greenlet-3.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef"},
+ {file = "greenlet-3.1.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9"},
+ {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111"},
+ {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81"},
+ {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba"},
+ {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8"},
+ {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1"},
+ {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd"},
+ {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7"},
+ {file = "greenlet-3.1.1-cp38-cp38-win32.whl", hash = "sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef"},
+ {file = "greenlet-3.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d"},
+ {file = "greenlet-3.1.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3"},
+ {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42"},
+ {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f"},
+ {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437"},
+ {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145"},
+ {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c"},
+ {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e"},
+ {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e"},
+ {file = "greenlet-3.1.1-cp39-cp39-win32.whl", hash = "sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c"},
+ {file = "greenlet-3.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22"},
+ {file = "greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467"},
]
[package.extras]
@@ -950,13 +970,13 @@ test = ["pytest (>=7.4)", "pytest-cov (>=4.1)"]
[[package]]
name = "mako"
-version = "1.3.5"
+version = "1.3.6"
description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
optional = false
python-versions = ">=3.8"
files = [
- {file = "Mako-1.3.5-py3-none-any.whl", hash = "sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a"},
- {file = "Mako-1.3.5.tar.gz", hash = "sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc"},
+ {file = "Mako-1.3.6-py3-none-any.whl", hash = "sha256:a91198468092a2f1a0de86ca92690fb0cfc43ca90ee17e15d93662b4c04b241a"},
+ {file = "mako-1.3.6.tar.gz", hash = "sha256:9ec3a1583713479fae654f83ed9fa8c9a4c16b7bb0daba0e6bbebff50c0d983d"},
]
[package.dependencies]
@@ -993,71 +1013,72 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
[[package]]
name = "markupsafe"
-version = "2.1.5"
+version = "3.0.2"
description = "Safely add untrusted strings to HTML/XML markup."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.9"
files = [
- {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"},
- {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"},
+ {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"},
]
[[package]]
@@ -1347,95 +1368,90 @@ xml = ["lxml (>=4.9.2)"]
[[package]]
name = "pillow"
-version = "10.4.0"
+version = "11.0.0"
description = "Python Imaging Library (Fork)"
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
files = [
- {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"},
- {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"},
- {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"},
- {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"},
- {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"},
- {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"},
- {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"},
- {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"},
- {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"},
- {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"},
- {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"},
- {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"},
- {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"},
- {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"},
- {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"},
- {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"},
- {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"},
- {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"},
- {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"},
- {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"},
- {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"},
- {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"},
- {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"},
- {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"},
- {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"},
- {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"},
- {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"},
- {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"},
- {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"},
- {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"},
- {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"},
- {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"},
- {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"},
- {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"},
- {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"},
- {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"},
- {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"},
- {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"},
- {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"},
- {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"},
- {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"},
- {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"},
- {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"},
- {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"},
- {file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"},
- {file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"},
- {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"},
- {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"},
- {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"},
- {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"},
- {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"},
- {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"},
- {file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"},
- {file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"},
- {file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"},
- {file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"},
- {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"},
- {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"},
- {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"},
- {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"},
- {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"},
- {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"},
- {file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"},
- {file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"},
- {file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"},
- {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"},
- {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"},
- {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"},
- {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"},
- {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"},
- {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"},
- {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"},
- {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"},
- {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"},
- {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"},
- {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"},
- {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"},
- {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"},
- {file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"},
- {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"},
+ {file = "pillow-11.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6619654954dc4936fcff82db8eb6401d3159ec6be81e33c6000dfd76ae189947"},
+ {file = "pillow-11.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b3c5ac4bed7519088103d9450a1107f76308ecf91d6dabc8a33a2fcfb18d0fba"},
+ {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a65149d8ada1055029fcb665452b2814fe7d7082fcb0c5bed6db851cb69b2086"},
+ {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88a58d8ac0cc0e7f3a014509f0455248a76629ca9b604eca7dc5927cc593c5e9"},
+ {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:c26845094b1af3c91852745ae78e3ea47abf3dbcd1cf962f16b9a5fbe3ee8488"},
+ {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:1a61b54f87ab5786b8479f81c4b11f4d61702830354520837f8cc791ebba0f5f"},
+ {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:674629ff60030d144b7bca2b8330225a9b11c482ed408813924619c6f302fdbb"},
+ {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:598b4e238f13276e0008299bd2482003f48158e2b11826862b1eb2ad7c768b97"},
+ {file = "pillow-11.0.0-cp310-cp310-win32.whl", hash = "sha256:9a0f748eaa434a41fccf8e1ee7a3eed68af1b690e75328fd7a60af123c193b50"},
+ {file = "pillow-11.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:a5629742881bcbc1f42e840af185fd4d83a5edeb96475a575f4da50d6ede337c"},
+ {file = "pillow-11.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:ee217c198f2e41f184f3869f3e485557296d505b5195c513b2bfe0062dc537f1"},
+ {file = "pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc"},
+ {file = "pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a"},
+ {file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3"},
+ {file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5"},
+ {file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b"},
+ {file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa"},
+ {file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306"},
+ {file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9"},
+ {file = "pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5"},
+ {file = "pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291"},
+ {file = "pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9"},
+ {file = "pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923"},
+ {file = "pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903"},
+ {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4"},
+ {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f"},
+ {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9"},
+ {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7"},
+ {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6"},
+ {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc"},
+ {file = "pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6"},
+ {file = "pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47"},
+ {file = "pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25"},
+ {file = "pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699"},
+ {file = "pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38"},
+ {file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2"},
+ {file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2"},
+ {file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527"},
+ {file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa"},
+ {file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f"},
+ {file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb"},
+ {file = "pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798"},
+ {file = "pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de"},
+ {file = "pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84"},
+ {file = "pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b"},
+ {file = "pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003"},
+ {file = "pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2"},
+ {file = "pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a"},
+ {file = "pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8"},
+ {file = "pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8"},
+ {file = "pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904"},
+ {file = "pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3"},
+ {file = "pillow-11.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2e46773dc9f35a1dd28bd6981332fd7f27bec001a918a72a79b4133cf5291dba"},
+ {file = "pillow-11.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2679d2258b7f1192b378e2893a8a0a0ca472234d4c2c0e6bdd3380e8dfa21b6a"},
+ {file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eda2616eb2313cbb3eebbe51f19362eb434b18e3bb599466a1ffa76a033fb916"},
+ {file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ec184af98a121fb2da42642dea8a29ec80fc3efbaefb86d8fdd2606619045d"},
+ {file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:8594f42df584e5b4bb9281799698403f7af489fba84c34d53d1c4bfb71b7c4e7"},
+ {file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:c12b5ae868897c7338519c03049a806af85b9b8c237b7d675b8c5e089e4a618e"},
+ {file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:70fbbdacd1d271b77b7721fe3cdd2d537bbbd75d29e6300c672ec6bb38d9672f"},
+ {file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5178952973e588b3f1360868847334e9e3bf49d19e169bbbdfaf8398002419ae"},
+ {file = "pillow-11.0.0-cp39-cp39-win32.whl", hash = "sha256:8c676b587da5673d3c75bd67dd2a8cdfeb282ca38a30f37950511766b26858c4"},
+ {file = "pillow-11.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:94f3e1780abb45062287b4614a5bc0874519c86a777d4a7ad34978e86428b8dd"},
+ {file = "pillow-11.0.0-cp39-cp39-win_arm64.whl", hash = "sha256:290f2cc809f9da7d6d622550bbf4c1e57518212da51b6a30fe8e0a270a5b78bd"},
+ {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2"},
+ {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2"},
+ {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b"},
+ {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21a0d3b115009ebb8ac3d2ebec5c2982cc693da935f4ab7bb5c8ebe2f47d36f2"},
+ {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:73853108f56df97baf2bb8b522f3578221e56f646ba345a372c78326710d3830"},
+ {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e58876c91f97b0952eb766123bfef372792ab3f4e3e1f1a2267834c2ab131734"},
+ {file = "pillow-11.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316"},
+ {file = "pillow-11.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5bd2d3bdb846d757055910f0a59792d33b555800813c3b39ada1829c372ccb06"},
+ {file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:375b8dd15a1f5d2feafff536d47e22f69625c1aa92f12b339ec0b2ca40263273"},
+ {file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:daffdf51ee5db69a82dd127eabecce20729e21f7a3680cf7cbb23f0829189790"},
+ {file = "pillow-11.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7326a1787e3c7b0429659e0a944725e1b03eeaa10edd945a86dead1913383944"},
+ {file = "pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739"},
]
[package.extras]
-docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"]
+docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"]
fpx = ["olefile"]
mic = ["olefile"]
tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
@@ -1503,22 +1519,22 @@ type = ["mypy (>=1.11.2)"]
[[package]]
name = "playwright"
-version = "1.47.0"
+version = "1.48.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"},
+ {file = "playwright-1.48.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:082bce2739f1078acc7d0734da8cc0e23eb91b7fae553f3316d733276f09a6b1"},
+ {file = "playwright-1.48.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7da2eb51a19c7f3b523e9faa9d98e7af92e52eb983a099979ea79c9668e3cbf7"},
+ {file = "playwright-1.48.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:115b988d1da322358b77bc3bf2d3cc90f8c881e691461538e7df91614c4833c9"},
+ {file = "playwright-1.48.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:8dabb80e62f667fe2640a8b694e26a7b884c0b4803f7514a3954fc849126227b"},
+ {file = "playwright-1.48.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ff8303409ebed76bed4c3d655340320b768817d900ba208b394fdd7d7939a5c"},
+ {file = "playwright-1.48.0-py3-none-win32.whl", hash = "sha256:85598c360c590076d4f435525be991246d74a905b654ac19d26eab7ed9b98b2d"},
+ {file = "playwright-1.48.0-py3-none-win_amd64.whl", hash = "sha256:e0e87b0c4dc8fce83c725dd851aec37bc4e882bb225ec8a96bd83cf32d4f1623"},
]
[package.dependencies]
-greenlet = "3.0.3"
+greenlet = "3.1.1"
pyee = "12.0.0"
[[package]]
@@ -1553,13 +1569,13 @@ testing = ["pytest", "pytest-benchmark"]
[[package]]
name = "pre-commit"
-version = "4.0.0"
+version = "4.0.1"
description = "A framework for managing and maintaining multi-language pre-commit hooks."
optional = false
python-versions = ">=3.9"
files = [
- {file = "pre_commit-4.0.0-py2.py3-none-any.whl", hash = "sha256:0ca2341cf94ac1865350970951e54b1a50521e57b7b500403307aed4315a1234"},
- {file = "pre_commit-4.0.0.tar.gz", hash = "sha256:5d9807162cc5537940f94f266cbe2d716a75cfad0d78a317a92cac16287cfed6"},
+ {file = "pre_commit-4.0.1-py2.py3-none-any.whl", hash = "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878"},
+ {file = "pre_commit-4.0.1.tar.gz", hash = "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2"},
]
[package.dependencies]
@@ -1571,32 +1587,33 @@ virtualenv = ">=20.10.0"
[[package]]
name = "psutil"
-version = "6.0.0"
+version = "6.1.0"
description = "Cross-platform lib for process and system monitoring in Python."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
files = [
- {file = "psutil-6.0.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6"},
- {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0"},
- {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a9a3dbfb4de4f18174528d87cc352d1f788b7496991cca33c6996f40c9e3c92c"},
- {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6ec7588fb3ddaec7344a825afe298db83fe01bfaaab39155fa84cf1c0d6b13c3"},
- {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e7c870afcb7d91fdea2b37c24aeb08f98b6d67257a5cb0a8bc3ac68d0f1a68c"},
- {file = "psutil-6.0.0-cp27-none-win32.whl", hash = "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35"},
- {file = "psutil-6.0.0-cp27-none-win_amd64.whl", hash = "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1"},
- {file = "psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0"},
- {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0"},
- {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd"},
- {file = "psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132"},
- {file = "psutil-6.0.0-cp36-cp36m-win32.whl", hash = "sha256:fc8c9510cde0146432bbdb433322861ee8c3efbf8589865c8bf8d21cb30c4d14"},
- {file = "psutil-6.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:34859b8d8f423b86e4385ff3665d3f4d94be3cdf48221fbe476e883514fdb71c"},
- {file = "psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d"},
- {file = "psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3"},
- {file = "psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0"},
- {file = "psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2"},
+ {file = "psutil-6.1.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ff34df86226c0227c52f38b919213157588a678d049688eded74c76c8ba4a5d0"},
+ {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:c0e0c00aa18ca2d3b2b991643b799a15fc8f0563d2ebb6040f64ce8dc027b942"},
+ {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:000d1d1ebd634b4efb383f4034437384e44a6d455260aaee2eca1e9c1b55f047"},
+ {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5cd2bcdc75b452ba2e10f0e8ecc0b57b827dd5d7aaffbc6821b2a9a242823a76"},
+ {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:045f00a43c737f960d273a83973b2511430d61f283a44c96bf13a6e829ba8fdc"},
+ {file = "psutil-6.1.0-cp27-none-win32.whl", hash = "sha256:9118f27452b70bb1d9ab3198c1f626c2499384935aaf55388211ad982611407e"},
+ {file = "psutil-6.1.0-cp27-none-win_amd64.whl", hash = "sha256:a8506f6119cff7015678e2bce904a4da21025cc70ad283a53b099e7620061d85"},
+ {file = "psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688"},
+ {file = "psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e"},
+ {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38"},
+ {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b"},
+ {file = "psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a"},
+ {file = "psutil-6.1.0-cp36-cp36m-win32.whl", hash = "sha256:6d3fbbc8d23fcdcb500d2c9f94e07b1342df8ed71b948a2649b5cb060a7c94ca"},
+ {file = "psutil-6.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1209036fbd0421afde505a4879dee3b2fd7b1e14fee81c0069807adcbbcca747"},
+ {file = "psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e"},
+ {file = "psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be"},
+ {file = "psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a"},
]
[package.extras]
-test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
+dev = ["black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest-cov", "requests", "rstcheck", "ruff", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "wheel"]
+test = ["pytest", "pytest-xdist", "setuptools"]
[[package]]
name = "py-cpuinfo"
@@ -1960,15 +1977,29 @@ files = [
[package.dependencies]
six = ">=1.5"
+[[package]]
+name = "python-dotenv"
+version = "1.0.1"
+description = "Read key-value pairs from a .env file and set them as environment variables"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"},
+ {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"},
+]
+
+[package.extras]
+cli = ["click (>=5.0)"]
+
[[package]]
name = "python-engineio"
-version = "4.9.1"
+version = "4.10.1"
description = "Engine.IO server and client for Python"
optional = false
python-versions = ">=3.6"
files = [
- {file = "python_engineio-4.9.1-py3-none-any.whl", hash = "sha256:f995e702b21f6b9ebde4e2000cd2ad0112ba0e5116ec8d22fe3515e76ba9dddd"},
- {file = "python_engineio-4.9.1.tar.gz", hash = "sha256:7631cf5563086076611e494c643b3fa93dd3a854634b5488be0bba0ef9b99709"},
+ {file = "python_engineio-4.10.1-py3-none-any.whl", hash = "sha256:445a94004ec8034960ab99e7ce4209ec619c6e6b6a12aedcb05abeab924025c0"},
+ {file = "python_engineio-4.10.1.tar.gz", hash = "sha256:166cea8dd7429638c5c4e3a4895beae95196e860bc6f29ed0b9fe753d1ef2072"},
]
[package.dependencies]
@@ -2150,13 +2181,13 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==23.2.1)", "requests (>=2.31.0)"
[[package]]
name = "reflex-chakra"
-version = "0.6.1"
+version = "0.6.2"
description = "reflex using chakra components"
optional = false
-python-versions = "<4.0,>=3.8"
+python-versions = "<4.0,>=3.9"
files = [
- {file = "reflex_chakra-0.6.1-py3-none-any.whl", hash = "sha256:824d461264b6d2c836ba4a2a430e677a890b82e83da149672accfc58786442fa"},
- {file = "reflex_chakra-0.6.1.tar.gz", hash = "sha256:4b9b3c8bada19cbb4d1b8d8bc4ab0460ec008a91f380010c34d416d5b613dc07"},
+ {file = "reflex_chakra-0.6.2-py3-none-any.whl", hash = "sha256:b8aa19f39a02601c560b97f4b17f171c0b5980e13a58069e3a5dd0999e362e4f"},
+ {file = "reflex_chakra-0.6.2.tar.gz", hash = "sha256:81ddb7f182cc454922cc817312755b799d4e1a49a46ef2e81305052dc76ef86d"},
]
[package.dependencies]
@@ -2236,13 +2267,13 @@ idna2008 = ["idna"]
[[package]]
name = "rich"
-version = "13.9.2"
+version = "13.9.3"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
optional = false
python-versions = ">=3.8.0"
files = [
- {file = "rich-13.9.2-py3-none-any.whl", hash = "sha256:8c82a3d3f8dcfe9e734771313e606b39d8247bb6b826e196f4914b333b743cf1"},
- {file = "rich-13.9.2.tar.gz", hash = "sha256:51a2c62057461aaf7152b4d611168f93a9fc73068f8ded2790f29fe2b5366d0c"},
+ {file = "rich-13.9.3-py3-none-any.whl", hash = "sha256:9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283"},
+ {file = "rich-13.9.3.tar.gz", hash = "sha256:bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e"},
]
[package.dependencies]
@@ -2255,29 +2286,29 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"]
[[package]]
name = "ruff"
-version = "0.6.9"
+version = "0.7.0"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
- {file = "ruff-0.6.9-py3-none-linux_armv6l.whl", hash = "sha256:064df58d84ccc0ac0fcd63bc3090b251d90e2a372558c0f057c3f75ed73e1ccd"},
- {file = "ruff-0.6.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec"},
- {file = "ruff-0.6.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53fd8ca5e82bdee8da7f506d7b03a261f24cd43d090ea9db9a1dc59d9313914c"},
- {file = "ruff-0.6.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645d7d8761f915e48a00d4ecc3686969761df69fb561dd914a773c1a8266e14e"},
- {file = "ruff-0.6.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eae02b700763e3847595b9d2891488989cac00214da7f845f4bcf2989007d577"},
- {file = "ruff-0.6.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d5ccc9e58112441de8ad4b29dcb7a86dc25c5f770e3c06a9d57e0e5eba48829"},
- {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:417b81aa1c9b60b2f8edc463c58363075412866ae4e2b9ab0f690dc1e87ac1b5"},
- {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c866b631f5fbce896a74a6e4383407ba7507b815ccc52bcedabb6810fdb3ef7"},
- {file = "ruff-0.6.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b118afbb3202f5911486ad52da86d1d52305b59e7ef2031cea3425142b97d6f"},
- {file = "ruff-0.6.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67267654edc23c97335586774790cde402fb6bbdb3c2314f1fc087dee320bfa"},
- {file = "ruff-0.6.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3ef0cc774b00fec123f635ce5c547dac263f6ee9fb9cc83437c5904183b55ceb"},
- {file = "ruff-0.6.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:12edd2af0c60fa61ff31cefb90aef4288ac4d372b4962c2864aeea3a1a2460c0"},
- {file = "ruff-0.6.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:55bb01caeaf3a60b2b2bba07308a02fca6ab56233302406ed5245180a05c5625"},
- {file = "ruff-0.6.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:925d26471fa24b0ce5a6cdfab1bb526fb4159952385f386bdcc643813d472039"},
- {file = "ruff-0.6.9-py3-none-win32.whl", hash = "sha256:eb61ec9bdb2506cffd492e05ac40e5bc6284873aceb605503d8494180d6fc84d"},
- {file = "ruff-0.6.9-py3-none-win_amd64.whl", hash = "sha256:785d31851c1ae91f45b3d8fe23b8ae4b5170089021fbb42402d811135f0b7117"},
- {file = "ruff-0.6.9-py3-none-win_arm64.whl", hash = "sha256:a9641e31476d601f83cd602608739a0840e348bda93fec9f1ee816f8b6798b93"},
- {file = "ruff-0.6.9.tar.gz", hash = "sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2"},
+ {file = "ruff-0.7.0-py3-none-linux_armv6l.whl", hash = "sha256:0cdf20c2b6ff98e37df47b2b0bd3a34aaa155f59a11182c1303cce79be715628"},
+ {file = "ruff-0.7.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:496494d350c7fdeb36ca4ef1c9f21d80d182423718782222c29b3e72b3512737"},
+ {file = "ruff-0.7.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:214b88498684e20b6b2b8852c01d50f0651f3cc6118dfa113b4def9f14faaf06"},
+ {file = "ruff-0.7.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:630fce3fefe9844e91ea5bbf7ceadab4f9981f42b704fae011bb8efcaf5d84be"},
+ {file = "ruff-0.7.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:211d877674e9373d4bb0f1c80f97a0201c61bcd1e9d045b6e9726adc42c156aa"},
+ {file = "ruff-0.7.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:194d6c46c98c73949a106425ed40a576f52291c12bc21399eb8f13a0f7073495"},
+ {file = "ruff-0.7.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:82c2579b82b9973a110fab281860403b397c08c403de92de19568f32f7178598"},
+ {file = "ruff-0.7.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9af971fe85dcd5eaed8f585ddbc6bdbe8c217fb8fcf510ea6bca5bdfff56040e"},
+ {file = "ruff-0.7.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b641c7f16939b7d24b7bfc0be4102c56562a18281f84f635604e8a6989948914"},
+ {file = "ruff-0.7.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d71672336e46b34e0c90a790afeac8a31954fd42872c1f6adaea1dff76fd44f9"},
+ {file = "ruff-0.7.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ab7d98c7eed355166f367597e513a6c82408df4181a937628dbec79abb2a1fe4"},
+ {file = "ruff-0.7.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1eb54986f770f49edb14f71d33312d79e00e629a57387382200b1ef12d6a4ef9"},
+ {file = "ruff-0.7.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:dc452ba6f2bb9cf8726a84aa877061a2462afe9ae0ea1d411c53d226661c601d"},
+ {file = "ruff-0.7.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:4b406c2dce5be9bad59f2de26139a86017a517e6bcd2688da515481c05a2cb11"},
+ {file = "ruff-0.7.0-py3-none-win32.whl", hash = "sha256:f6c968509f767776f524a8430426539587d5ec5c662f6addb6aa25bc2e8195ec"},
+ {file = "ruff-0.7.0-py3-none-win_amd64.whl", hash = "sha256:ff4aabfbaaba880e85d394603b9e75d32b0693152e16fa659a3064a85df7fce2"},
+ {file = "ruff-0.7.0-py3-none-win_arm64.whl", hash = "sha256:10842f69c245e78d6adec7e1db0a7d9ddc2fff0621d730e61657b64fa36f207e"},
+ {file = "ruff-0.7.0.tar.gz", hash = "sha256:47a86360cf62d9cd53ebfb0b5eb0e882193fc191c6d717e8bef4462bc3b9ea2b"},
]
[[package]]
@@ -2316,13 +2347,13 @@ websocket-client = ">=1.8,<2.0"
[[package]]
name = "setuptools"
-version = "75.1.0"
+version = "75.2.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.8"
files = [
- {file = "setuptools-75.1.0-py3-none-any.whl", hash = "sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2"},
- {file = "setuptools-75.1.0.tar.gz", hash = "sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538"},
+ {file = "setuptools-75.2.0-py3-none-any.whl", hash = "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8"},
+ {file = "setuptools-75.2.0.tar.gz", hash = "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec"},
]
[package.extras]
@@ -2347,19 +2378,20 @@ files = [
[[package]]
name = "simple-websocket"
-version = "1.0.0"
+version = "1.1.0"
description = "Simple WebSocket server and client for Python"
optional = false
python-versions = ">=3.6"
files = [
- {file = "simple-websocket-1.0.0.tar.gz", hash = "sha256:17d2c72f4a2bd85174a97e3e4c88b01c40c3f81b7b648b0cc3ce1305968928c8"},
- {file = "simple_websocket-1.0.0-py3-none-any.whl", hash = "sha256:1d5bf585e415eaa2083e2bcf02a3ecf91f9712e7b3e6b9fa0b461ad04e0837bc"},
+ {file = "simple_websocket-1.1.0-py3-none-any.whl", hash = "sha256:4af6069630a38ed6c561010f0e11a5bc0d4ca569b36306eb257cd9a192497c8c"},
+ {file = "simple_websocket-1.1.0.tar.gz", hash = "sha256:7939234e7aa067c534abdab3a9ed933ec9ce4691b0713c78acb195560aa52ae4"},
]
[package.dependencies]
wsproto = "*"
[package.extras]
+dev = ["flake8", "pytest", "pytest-cov", "tox"]
docs = ["sphinx"]
[[package]]
@@ -2397,60 +2429,68 @@ files = [
[[package]]
name = "sqlalchemy"
-version = "2.0.35"
+version = "2.0.36"
description = "Database Abstraction Library"
optional = false
python-versions = ">=3.7"
files = [
- {file = "SQLAlchemy-2.0.35-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:67219632be22f14750f0d1c70e62f204ba69d28f62fd6432ba05ab295853de9b"},
- {file = "SQLAlchemy-2.0.35-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4668bd8faf7e5b71c0319407b608f278f279668f358857dbfd10ef1954ac9f90"},
- {file = "SQLAlchemy-2.0.35-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb8bea573863762bbf45d1e13f87c2d2fd32cee2dbd50d050f83f87429c9e1ea"},
- {file = "SQLAlchemy-2.0.35-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f552023710d4b93d8fb29a91fadf97de89c5926c6bd758897875435f2a939f33"},
- {file = "SQLAlchemy-2.0.35-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:016b2e665f778f13d3c438651dd4de244214b527a275e0acf1d44c05bc6026a9"},
- {file = "SQLAlchemy-2.0.35-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7befc148de64b6060937231cbff8d01ccf0bfd75aa26383ffdf8d82b12ec04ff"},
- {file = "SQLAlchemy-2.0.35-cp310-cp310-win32.whl", hash = "sha256:22b83aed390e3099584b839b93f80a0f4a95ee7f48270c97c90acd40ee646f0b"},
- {file = "SQLAlchemy-2.0.35-cp310-cp310-win_amd64.whl", hash = "sha256:a29762cd3d116585278ffb2e5b8cc311fb095ea278b96feef28d0b423154858e"},
- {file = "SQLAlchemy-2.0.35-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e21f66748ab725ade40fa7af8ec8b5019c68ab00b929f6643e1b1af461eddb60"},
- {file = "SQLAlchemy-2.0.35-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8a6219108a15fc6d24de499d0d515c7235c617b2540d97116b663dade1a54d62"},
- {file = "SQLAlchemy-2.0.35-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:042622a5306c23b972192283f4e22372da3b8ddf5f7aac1cc5d9c9b222ab3ff6"},
- {file = "SQLAlchemy-2.0.35-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:627dee0c280eea91aed87b20a1f849e9ae2fe719d52cbf847c0e0ea34464b3f7"},
- {file = "SQLAlchemy-2.0.35-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4fdcd72a789c1c31ed242fd8c1bcd9ea186a98ee8e5408a50e610edfef980d71"},
- {file = "SQLAlchemy-2.0.35-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:89b64cd8898a3a6f642db4eb7b26d1b28a497d4022eccd7717ca066823e9fb01"},
- {file = "SQLAlchemy-2.0.35-cp311-cp311-win32.whl", hash = "sha256:6a93c5a0dfe8d34951e8a6f499a9479ffb9258123551fa007fc708ae2ac2bc5e"},
- {file = "SQLAlchemy-2.0.35-cp311-cp311-win_amd64.whl", hash = "sha256:c68fe3fcde03920c46697585620135b4ecfdfc1ed23e75cc2c2ae9f8502c10b8"},
- {file = "SQLAlchemy-2.0.35-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:eb60b026d8ad0c97917cb81d3662d0b39b8ff1335e3fabb24984c6acd0c900a2"},
- {file = "SQLAlchemy-2.0.35-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6921ee01caf375363be5e9ae70d08ce7ca9d7e0e8983183080211a062d299468"},
- {file = "SQLAlchemy-2.0.35-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8cdf1a0dbe5ced887a9b127da4ffd7354e9c1a3b9bb330dce84df6b70ccb3a8d"},
- {file = "SQLAlchemy-2.0.35-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93a71c8601e823236ac0e5d087e4f397874a421017b3318fd92c0b14acf2b6db"},
- {file = "SQLAlchemy-2.0.35-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e04b622bb8a88f10e439084486f2f6349bf4d50605ac3e445869c7ea5cf0fa8c"},
- {file = "SQLAlchemy-2.0.35-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1b56961e2d31389aaadf4906d453859f35302b4eb818d34a26fab72596076bb8"},
- {file = "SQLAlchemy-2.0.35-cp312-cp312-win32.whl", hash = "sha256:0f9f3f9a3763b9c4deb8c5d09c4cc52ffe49f9876af41cc1b2ad0138878453cf"},
- {file = "SQLAlchemy-2.0.35-cp312-cp312-win_amd64.whl", hash = "sha256:25b0f63e7fcc2a6290cb5f7f5b4fc4047843504983a28856ce9b35d8f7de03cc"},
- {file = "SQLAlchemy-2.0.35-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f021d334f2ca692523aaf7bbf7592ceff70c8594fad853416a81d66b35e3abf9"},
- {file = "SQLAlchemy-2.0.35-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05c3f58cf91683102f2f0265c0db3bd3892e9eedabe059720492dbaa4f922da1"},
- {file = "SQLAlchemy-2.0.35-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:032d979ce77a6c2432653322ba4cbeabf5a6837f704d16fa38b5a05d8e21fa00"},
- {file = "SQLAlchemy-2.0.35-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:2e795c2f7d7249b75bb5f479b432a51b59041580d20599d4e112b5f2046437a3"},
- {file = "SQLAlchemy-2.0.35-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:cc32b2990fc34380ec2f6195f33a76b6cdaa9eecf09f0c9404b74fc120aef36f"},
- {file = "SQLAlchemy-2.0.35-cp37-cp37m-win32.whl", hash = "sha256:9509c4123491d0e63fb5e16199e09f8e262066e58903e84615c301dde8fa2e87"},
- {file = "SQLAlchemy-2.0.35-cp37-cp37m-win_amd64.whl", hash = "sha256:3655af10ebcc0f1e4e06c5900bb33e080d6a1fa4228f502121f28a3b1753cde5"},
- {file = "SQLAlchemy-2.0.35-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4c31943b61ed8fdd63dfd12ccc919f2bf95eefca133767db6fbbd15da62078ec"},
- {file = "SQLAlchemy-2.0.35-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a62dd5d7cc8626a3634208df458c5fe4f21200d96a74d122c83bc2015b333bc1"},
- {file = "SQLAlchemy-2.0.35-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0630774b0977804fba4b6bbea6852ab56c14965a2b0c7fc7282c5f7d90a1ae72"},
- {file = "SQLAlchemy-2.0.35-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d625eddf7efeba2abfd9c014a22c0f6b3796e0ffb48f5d5ab106568ef01ff5a"},
- {file = "SQLAlchemy-2.0.35-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ada603db10bb865bbe591939de854faf2c60f43c9b763e90f653224138f910d9"},
- {file = "SQLAlchemy-2.0.35-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c41411e192f8d3ea39ea70e0fae48762cd11a2244e03751a98bd3c0ca9a4e936"},
- {file = "SQLAlchemy-2.0.35-cp38-cp38-win32.whl", hash = "sha256:d299797d75cd747e7797b1b41817111406b8b10a4f88b6e8fe5b5e59598b43b0"},
- {file = "SQLAlchemy-2.0.35-cp38-cp38-win_amd64.whl", hash = "sha256:0375a141e1c0878103eb3d719eb6d5aa444b490c96f3fedab8471c7f6ffe70ee"},
- {file = "SQLAlchemy-2.0.35-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ccae5de2a0140d8be6838c331604f91d6fafd0735dbdcee1ac78fc8fbaba76b4"},
- {file = "SQLAlchemy-2.0.35-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2a275a806f73e849e1c309ac11108ea1a14cd7058577aba962cd7190e27c9e3c"},
- {file = "SQLAlchemy-2.0.35-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:732e026240cdd1c1b2e3ac515c7a23820430ed94292ce33806a95869c46bd139"},
- {file = "SQLAlchemy-2.0.35-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:890da8cd1941fa3dab28c5bac3b9da8502e7e366f895b3b8e500896f12f94d11"},
- {file = "SQLAlchemy-2.0.35-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0d8326269dbf944b9201911b0d9f3dc524d64779a07518199a58384c3d37a44"},
- {file = "SQLAlchemy-2.0.35-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b76d63495b0508ab9fc23f8152bac63205d2a704cd009a2b0722f4c8e0cba8e0"},
- {file = "SQLAlchemy-2.0.35-cp39-cp39-win32.whl", hash = "sha256:69683e02e8a9de37f17985905a5eca18ad651bf592314b4d3d799029797d0eb3"},
- {file = "SQLAlchemy-2.0.35-cp39-cp39-win_amd64.whl", hash = "sha256:aee110e4ef3c528f3abbc3c2018c121e708938adeeff9006428dd7c8555e9b3f"},
- {file = "SQLAlchemy-2.0.35-py3-none-any.whl", hash = "sha256:2ab3f0336c0387662ce6221ad30ab3a5e6499aab01b9790879b6578fd9b8faa1"},
- {file = "sqlalchemy-2.0.35.tar.gz", hash = "sha256:e11d7ea4d24f0a262bccf9a7cd6284c976c5369dac21db237cff59586045ab9f"},
+ {file = "SQLAlchemy-2.0.36-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:59b8f3adb3971929a3e660337f5dacc5942c2cdb760afcabb2614ffbda9f9f72"},
+ {file = "SQLAlchemy-2.0.36-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37350015056a553e442ff672c2d20e6f4b6d0b2495691fa239d8aa18bb3bc908"},
+ {file = "SQLAlchemy-2.0.36-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8318f4776c85abc3f40ab185e388bee7a6ea99e7fa3a30686580b209eaa35c08"},
+ {file = "SQLAlchemy-2.0.36-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c245b1fbade9c35e5bd3b64270ab49ce990369018289ecfde3f9c318411aaa07"},
+ {file = "SQLAlchemy-2.0.36-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:69f93723edbca7342624d09f6704e7126b152eaed3cdbb634cb657a54332a3c5"},
+ {file = "SQLAlchemy-2.0.36-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f9511d8dd4a6e9271d07d150fb2f81874a3c8c95e11ff9af3a2dfc35fe42ee44"},
+ {file = "SQLAlchemy-2.0.36-cp310-cp310-win32.whl", hash = "sha256:c3f3631693003d8e585d4200730616b78fafd5a01ef8b698f6967da5c605b3fa"},
+ {file = "SQLAlchemy-2.0.36-cp310-cp310-win_amd64.whl", hash = "sha256:a86bfab2ef46d63300c0f06936bd6e6c0105faa11d509083ba8f2f9d237fb5b5"},
+ {file = "SQLAlchemy-2.0.36-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fd3a55deef00f689ce931d4d1b23fa9f04c880a48ee97af488fd215cf24e2a6c"},
+ {file = "SQLAlchemy-2.0.36-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f5e9cd989b45b73bd359f693b935364f7e1f79486e29015813c338450aa5a71"},
+ {file = "SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0ddd9db6e59c44875211bc4c7953a9f6638b937b0a88ae6d09eb46cced54eff"},
+ {file = "SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2519f3a5d0517fc159afab1015e54bb81b4406c278749779be57a569d8d1bb0d"},
+ {file = "SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59b1ee96617135f6e1d6f275bbe988f419c5178016f3d41d3c0abb0c819f75bb"},
+ {file = "SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:39769a115f730d683b0eb7b694db9789267bcd027326cccc3125e862eb03bfd8"},
+ {file = "SQLAlchemy-2.0.36-cp311-cp311-win32.whl", hash = "sha256:66bffbad8d6271bb1cc2f9a4ea4f86f80fe5e2e3e501a5ae2a3dc6a76e604e6f"},
+ {file = "SQLAlchemy-2.0.36-cp311-cp311-win_amd64.whl", hash = "sha256:23623166bfefe1487d81b698c423f8678e80df8b54614c2bf4b4cfcd7c711959"},
+ {file = "SQLAlchemy-2.0.36-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7b64e6ec3f02c35647be6b4851008b26cff592a95ecb13b6788a54ef80bbdd4"},
+ {file = "SQLAlchemy-2.0.36-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:46331b00096a6db1fdc052d55b101dbbfc99155a548e20a0e4a8e5e4d1362855"},
+ {file = "SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdf3386a801ea5aba17c6410dd1dc8d39cf454ca2565541b5ac42a84e1e28f53"},
+ {file = "SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9dfa18ff2a67b09b372d5db8743c27966abf0e5344c555d86cc7199f7ad83a"},
+ {file = "SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:90812a8933df713fdf748b355527e3af257a11e415b613dd794512461eb8a686"},
+ {file = "SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1bc330d9d29c7f06f003ab10e1eaced295e87940405afe1b110f2eb93a233588"},
+ {file = "SQLAlchemy-2.0.36-cp312-cp312-win32.whl", hash = "sha256:79d2e78abc26d871875b419e1fd3c0bca31a1cb0043277d0d850014599626c2e"},
+ {file = "SQLAlchemy-2.0.36-cp312-cp312-win_amd64.whl", hash = "sha256:b544ad1935a8541d177cb402948b94e871067656b3a0b9e91dbec136b06a2ff5"},
+ {file = "SQLAlchemy-2.0.36-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b5cc79df7f4bc3d11e4b542596c03826063092611e481fcf1c9dfee3c94355ef"},
+ {file = "SQLAlchemy-2.0.36-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3c01117dd36800f2ecaa238c65365b7b16497adc1522bf84906e5710ee9ba0e8"},
+ {file = "SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bc633f4ee4b4c46e7adcb3a9b5ec083bf1d9a97c1d3854b92749d935de40b9b"},
+ {file = "SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e46ed38affdfc95d2c958de328d037d87801cfcbea6d421000859e9789e61c2"},
+ {file = "SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b2985c0b06e989c043f1dc09d4fe89e1616aadd35392aea2844f0458a989eacf"},
+ {file = "SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a121d62ebe7d26fec9155f83f8be5189ef1405f5973ea4874a26fab9f1e262c"},
+ {file = "SQLAlchemy-2.0.36-cp313-cp313-win32.whl", hash = "sha256:0572f4bd6f94752167adfd7c1bed84f4b240ee6203a95e05d1e208d488d0d436"},
+ {file = "SQLAlchemy-2.0.36-cp313-cp313-win_amd64.whl", hash = "sha256:8c78ac40bde930c60e0f78b3cd184c580f89456dd87fc08f9e3ee3ce8765ce88"},
+ {file = "SQLAlchemy-2.0.36-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:be9812b766cad94a25bc63bec11f88c4ad3629a0cec1cd5d4ba48dc23860486b"},
+ {file = "SQLAlchemy-2.0.36-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aae840ebbd6cdd41af1c14590e5741665e5272d2fee999306673a1bb1fdb4d"},
+ {file = "SQLAlchemy-2.0.36-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4557e1f11c5f653ebfdd924f3f9d5ebfc718283b0b9beebaa5dd6b77ec290971"},
+ {file = "SQLAlchemy-2.0.36-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:07b441f7d03b9a66299ce7ccf3ef2900abc81c0db434f42a5694a37bd73870f2"},
+ {file = "SQLAlchemy-2.0.36-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:28120ef39c92c2dd60f2721af9328479516844c6b550b077ca450c7d7dc68575"},
+ {file = "SQLAlchemy-2.0.36-cp37-cp37m-win32.whl", hash = "sha256:b81ee3d84803fd42d0b154cb6892ae57ea6b7c55d8359a02379965706c7efe6c"},
+ {file = "SQLAlchemy-2.0.36-cp37-cp37m-win_amd64.whl", hash = "sha256:f942a799516184c855e1a32fbc7b29d7e571b52612647866d4ec1c3242578fcb"},
+ {file = "SQLAlchemy-2.0.36-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3d6718667da04294d7df1670d70eeddd414f313738d20a6f1d1f379e3139a545"},
+ {file = "SQLAlchemy-2.0.36-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:72c28b84b174ce8af8504ca28ae9347d317f9dba3999e5981a3cd441f3712e24"},
+ {file = "SQLAlchemy-2.0.36-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b11d0cfdd2b095e7b0686cf5fabeb9c67fae5b06d265d8180715b8cfa86522e3"},
+ {file = "SQLAlchemy-2.0.36-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e32092c47011d113dc01ab3e1d3ce9f006a47223b18422c5c0d150af13a00687"},
+ {file = "SQLAlchemy-2.0.36-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6a440293d802d3011028e14e4226da1434b373cbaf4a4bbb63f845761a708346"},
+ {file = "SQLAlchemy-2.0.36-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c54a1e53a0c308a8e8a7dffb59097bff7facda27c70c286f005327f21b2bd6b1"},
+ {file = "SQLAlchemy-2.0.36-cp38-cp38-win32.whl", hash = "sha256:1e0d612a17581b6616ff03c8e3d5eff7452f34655c901f75d62bd86449d9750e"},
+ {file = "SQLAlchemy-2.0.36-cp38-cp38-win_amd64.whl", hash = "sha256:8958b10490125124463095bbdadda5aa22ec799f91958e410438ad6c97a7b793"},
+ {file = "SQLAlchemy-2.0.36-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dc022184d3e5cacc9579e41805a681187650e170eb2fd70e28b86192a479dcaa"},
+ {file = "SQLAlchemy-2.0.36-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b817d41d692bf286abc181f8af476c4fbef3fd05e798777492618378448ee689"},
+ {file = "SQLAlchemy-2.0.36-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4e46a888b54be23d03a89be510f24a7652fe6ff660787b96cd0e57a4ebcb46d"},
+ {file = "SQLAlchemy-2.0.36-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4ae3005ed83f5967f961fd091f2f8c5329161f69ce8480aa8168b2d7fe37f06"},
+ {file = "SQLAlchemy-2.0.36-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:03e08af7a5f9386a43919eda9de33ffda16b44eb11f3b313e6822243770e9763"},
+ {file = "SQLAlchemy-2.0.36-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3dbb986bad3ed5ceaf090200eba750b5245150bd97d3e67343a3cfed06feecf7"},
+ {file = "SQLAlchemy-2.0.36-cp39-cp39-win32.whl", hash = "sha256:9fe53b404f24789b5ea9003fc25b9a3988feddebd7e7b369c8fac27ad6f52f28"},
+ {file = "SQLAlchemy-2.0.36-cp39-cp39-win_amd64.whl", hash = "sha256:af148a33ff0349f53512a049c6406923e4e02bf2f26c5fb285f143faf4f0e46a"},
+ {file = "SQLAlchemy-2.0.36-py3-none-any.whl", hash = "sha256:fddbe92b4760c6f5d48162aef14824add991aeda8ddadb3c31d56eb15ca69f8e"},
+ {file = "sqlalchemy-2.0.36.tar.gz", hash = "sha256:7f2767680b6d2398aea7082e45a774b2b0767b5c8d8ffb9c8b683088ea9b29c5"},
]
[package.dependencies]
@@ -2463,7 +2503,7 @@ aioodbc = ["aioodbc", "greenlet (!=0.4.17)"]
aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"]
asyncio = ["greenlet (!=0.4.17)"]
asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"]
-mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"]
+mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10)"]
mssql = ["pyodbc"]
mssql-pymssql = ["pymssql"]
mssql-pyodbc = ["pyodbc"]
@@ -2499,13 +2539,13 @@ SQLAlchemy = ">=2.0.14,<2.1.0"
[[package]]
name = "starlette"
-version = "0.38.6"
+version = "0.41.0"
description = "The little ASGI library that shines."
optional = false
python-versions = ">=3.8"
files = [
- {file = "starlette-0.38.6-py3-none-any.whl", hash = "sha256:4517a1409e2e73ee4951214ba012052b9e16f60e90d73cfb06192c19203bbb05"},
- {file = "starlette-0.38.6.tar.gz", hash = "sha256:863a1588f5574e70a821dadefb41e4881ea451a47a3cd1b4df359d4ffefe5ead"},
+ {file = "starlette-0.41.0-py3-none-any.whl", hash = "sha256:a0193a3c413ebc9c78bff1c3546a45bb8c8bcb4a84cae8747d650a65bd37210a"},
+ {file = "starlette-0.41.0.tar.gz", hash = "sha256:39cbd8768b107d68bfe1ff1672b38a2c38b49777de46d2a592841d58e3bf7c2a"},
]
[package.dependencies]
@@ -2613,13 +2653,13 @@ files = [
[[package]]
name = "trio"
-version = "0.26.2"
+version = "0.27.0"
description = "A friendly Python library for async concurrency and I/O"
optional = false
python-versions = ">=3.8"
files = [
- {file = "trio-0.26.2-py3-none-any.whl", hash = "sha256:c5237e8133eb0a1d72f09a971a55c28ebe69e351c783fc64bc37db8db8bbe1d0"},
- {file = "trio-0.26.2.tar.gz", hash = "sha256:0346c3852c15e5c7d40ea15972c4805689ef2cb8b5206f794c9c19450119f3a4"},
+ {file = "trio-0.27.0-py3-none-any.whl", hash = "sha256:68eabbcf8f457d925df62da780eff15ff5dc68fd6b367e2dde59f7aaf2a0b884"},
+ {file = "trio-0.27.0.tar.gz", hash = "sha256:1dcc95ab1726b2da054afea8fd761af74bad79bd52381b84eae408e983c76831"},
]
[package.dependencies]
@@ -2730,13 +2770,13 @@ zstd = ["zstandard (>=0.18.0)"]
[[package]]
name = "uvicorn"
-version = "0.31.0"
+version = "0.32.0"
description = "The lightning-fast ASGI server."
optional = false
python-versions = ">=3.8"
files = [
- {file = "uvicorn-0.31.0-py3-none-any.whl", hash = "sha256:cac7be4dd4d891c363cd942160a7b02e69150dcbc7a36be04d5f4af4b17c8ced"},
- {file = "uvicorn-0.31.0.tar.gz", hash = "sha256:13bc21373d103859f68fe739608e2eb054a816dea79189bc3ca08ea89a275906"},
+ {file = "uvicorn-0.32.0-py3-none-any.whl", hash = "sha256:60b8f3a5ac027dcd31448f411ced12b5ef452c646f76f02f8cc3f25d8d26fd82"},
+ {file = "uvicorn-0.32.0.tar.gz", hash = "sha256:f78b36b143c16f54ccdb8190d0a26b5f1901fe5a3c777e1ab29f26391af8551e"},
]
[package.dependencies]
@@ -2749,13 +2789,13 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)",
[[package]]
name = "virtualenv"
-version = "20.26.6"
+version = "20.27.0"
description = "Virtual Python Environment builder"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "virtualenv-20.26.6-py3-none-any.whl", hash = "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2"},
- {file = "virtualenv-20.26.6.tar.gz", hash = "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48"},
+ {file = "virtualenv-20.27.0-py3-none-any.whl", hash = "sha256:44a72c29cceb0ee08f300b314848c86e57bf8d1f13107a5e671fb9274138d655"},
+ {file = "virtualenv-20.27.0.tar.gz", hash = "sha256:2ca56a68ed615b8fe4326d11a0dca5dfbe8fd68510fb6c6349163bed3c15f2b2"},
]
[package.dependencies]
@@ -3007,4 +3047,4 @@ type = ["pytest-mypy"]
[metadata]
lock-version = "2.0"
python-versions = "^3.9"
-content-hash = "796ddba36f031ad2b47cae43ce6c49102e2cb98f92823b265d9779e6684333f6"
+content-hash = "c5da15520cef58124f6699007c81158036840469d4f9972592d72bd456c45e7e"
diff --git a/pyproject.toml b/pyproject.toml
index 17ee4d132..3fe6041f0 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "reflex"
-version = "0.6.3dev1"
+version = "0.6.4dev1"
description = "Web apps in pure Python."
license = "Apache-2.0"
authors = [
@@ -33,6 +33,7 @@ jinja2 = ">=3.1.2,<4.0"
psutil = ">=5.9.4,<7.0"
pydantic = ">=1.10.2,<3.0"
python-multipart = ">=0.0.5,<0.1"
+python-dotenv = ">=1.0.1"
python-socketio = ">=5.7.0,<6.0"
redis = ">=4.3.5,<6.0"
rich = ">=13.0.0,<14.0"
@@ -68,9 +69,9 @@ darglint = ">=1.8.1,<2.0"
toml = ">=0.10.2,<1.0"
pytest-asyncio = ">=0.24.0"
pytest-cov = ">=4.0.0,<6.0"
-ruff = "^0.6.9"
+ruff = "^0.7.0"
pandas = ">=2.1.1,<3.0"
-pillow = ">=10.0.0,<11.0"
+pillow = ">=10.0.0,<12.0"
plotly = ">=5.13.0,<6.0"
asynctest = ">=0.13.0,<1.0"
pre-commit = ">=3.2.1"
@@ -91,7 +92,7 @@ build-backend = "poetry.core.masonry.api"
[tool.ruff]
target-version = "py39"
lint.select = ["B", "D", "E", "F", "I", "SIM", "W"]
-lint.ignore = ["B008", "D203", "D205", "D213", "D401", "D406", "D407", "E501", "F403", "F405", "F541"]
+lint.ignore = ["B008", "D203", "D205", "D213", "D401", "D406", "D407", "E501", "F403", "F405", "F541", "SIM115"]
lint.pydocstyle.convention = "google"
[tool.ruff.lint.per-file-ignores]
diff --git a/reflex/.templates/web/components/shiki/code.js b/reflex/.templates/web/components/shiki/code.js
new file mode 100644
index 000000000..c655c3a60
--- /dev/null
+++ b/reflex/.templates/web/components/shiki/code.js
@@ -0,0 +1,29 @@
+import { useEffect, useState } from "react"
+import { codeToHtml} from "shiki"
+
+export function Code ({code, theme, language, transformers, ...divProps}) {
+ const [codeResult, setCodeResult] = useState("")
+ useEffect(() => {
+ async function fetchCode() {
+ let final_code;
+
+ if (Array.isArray(code)) {
+ final_code = code[0];
+ } else {
+ final_code = code;
+ }
+ const result = await codeToHtml(final_code, {
+ lang: language,
+ theme,
+ transformers
+ });
+ setCodeResult(result);
+ }
+ fetchCode();
+ }, [code, language, theme, transformers]
+
+ )
+ return (
+
+ )
+}
diff --git a/reflex/.templates/web/utils/state.js b/reflex/.templates/web/utils/state.js
index 0fe0db8c1..24092f235 100644
--- a/reflex/.templates/web/utils/state.js
+++ b/reflex/.templates/web/utils/state.js
@@ -743,6 +743,7 @@ export const useEventLoop = (
addEvents([
Event(`${exception_state_name}.handle_frontend_exception`, {
stack: error.stack,
+ component_stack: "",
}),
]);
return false;
@@ -754,6 +755,7 @@ export const useEventLoop = (
addEvents([
Event(`${exception_state_name}.handle_frontend_exception`, {
stack: event.reason.stack,
+ component_stack: "",
}),
]);
return false;
diff --git a/reflex/__init__.py b/reflex/__init__.py
index ad51d2cf4..979e5499a 100644
--- a/reflex/__init__.py
+++ b/reflex/__init__.py
@@ -320,13 +320,15 @@ _MAPPING: dict = {
"upload_files",
"window_alert",
],
+ "istate.storage": [
+ "Cookie",
+ "LocalStorage",
+ "SessionStorage",
+ ],
"middleware": ["middleware", "Middleware"],
"model": ["session", "Model"],
"state": [
"var",
- "Cookie",
- "LocalStorage",
- "SessionStorage",
"ComponentState",
"State",
],
diff --git a/reflex/__init__.pyi b/reflex/__init__.pyi
index d928778d8..aeebaadf8 100644
--- a/reflex/__init__.pyi
+++ b/reflex/__init__.pyi
@@ -174,15 +174,15 @@ from .event import stop_propagation as stop_propagation
from .event import upload_files as upload_files
from .event import window_alert as window_alert
from .experimental import _x as _x
+from .istate.storage import Cookie as Cookie
+from .istate.storage import LocalStorage as LocalStorage
+from .istate.storage import SessionStorage as SessionStorage
from .middleware import Middleware as Middleware
from .middleware import middleware as middleware
from .model import Model as Model
from .model import session as session
from .page import page as page
from .state import ComponentState as ComponentState
-from .state import Cookie as Cookie
-from .state import LocalStorage as LocalStorage
-from .state import SessionStorage as SessionStorage
from .state import State as State
from .state import var as var
from .style import Style as Style
diff --git a/reflex/app.py b/reflex/app.py
index 584b8a321..abf0b5d41 100644
--- a/reflex/app.py
+++ b/reflex/app.py
@@ -64,7 +64,7 @@ from reflex.components.core.client_side_routing import (
)
from reflex.components.core.upload import Upload, get_upload_dir
from reflex.components.radix import themes
-from reflex.config import get_config
+from reflex.config import environment, get_config
from reflex.event import Event, EventHandler, EventSpec, window_alert
from reflex.model import Model, get_db_status
from reflex.page import (
@@ -957,15 +957,16 @@ class App(MiddlewareMixin, LifespanMixin, Base):
executor = None
if (
platform.system() in ("Linux", "Darwin")
- and os.environ.get("REFLEX_COMPILE_PROCESSES") is not None
+ and (number_of_processes := environment.REFLEX_COMPILE_PROCESSES)
+ is not None
):
executor = concurrent.futures.ProcessPoolExecutor(
- max_workers=int(os.environ.get("REFLEX_COMPILE_PROCESSES", 0)) or None,
+ max_workers=number_of_processes,
mp_context=multiprocessing.get_context("fork"),
)
else:
executor = concurrent.futures.ThreadPoolExecutor(
- max_workers=int(os.environ.get("REFLEX_COMPILE_THREADS", 0)) or None,
+ max_workers=environment.REFLEX_COMPILE_THREADS
)
with executor:
diff --git a/reflex/compiler/compiler.py b/reflex/compiler/compiler.py
index 0c29f941d..909299635 100644
--- a/reflex/compiler/compiler.py
+++ b/reflex/compiler/compiler.py
@@ -2,7 +2,6 @@
from __future__ import annotations
-import os
from datetime import datetime
from pathlib import Path
from typing import Dict, Iterable, Optional, Type, Union
@@ -16,7 +15,7 @@ from reflex.components.component import (
CustomComponent,
StatefulComponent,
)
-from reflex.config import get_config
+from reflex.config import environment, get_config
from reflex.state import BaseState
from reflex.style import SYSTEM_COLOR_MODE
from reflex.utils.exec import is_prod_mode
@@ -527,7 +526,7 @@ def remove_tailwind_from_postcss() -> tuple[str, str]:
def purge_web_pages_dir():
"""Empty out .web/pages directory."""
- if not is_prod_mode() and os.environ.get("REFLEX_PERSIST_WEB_DIR"):
+ if not is_prod_mode() and environment.REFLEX_PERSIST_WEB_DIR:
# Skip purging the web directory in dev mode if REFLEX_PERSIST_WEB_DIR is set.
return
diff --git a/reflex/compiler/utils.py b/reflex/compiler/utils.py
index 6f4fa2d1b..40640faa6 100644
--- a/reflex/compiler/utils.py
+++ b/reflex/compiler/utils.py
@@ -28,7 +28,8 @@ from reflex.components.base import (
Title,
)
from reflex.components.component import Component, ComponentStyle, CustomComponent
-from reflex.state import BaseState, Cookie, LocalStorage, SessionStorage
+from reflex.istate.storage import Cookie, LocalStorage, SessionStorage
+from reflex.state import BaseState
from reflex.style import Style
from reflex.utils import console, format, imports, path_ops
from reflex.utils.imports import ImportVar, ParsedImportDict
diff --git a/reflex/components/base/error_boundary.py b/reflex/components/base/error_boundary.py
index 66a9c43c8..83becc034 100644
--- a/reflex/components/base/error_boundary.py
+++ b/reflex/components/base/error_boundary.py
@@ -2,16 +2,32 @@
from __future__ import annotations
-from typing import List
+from typing import Dict, List, Tuple
from reflex.compiler.compiler import _compile_component
from reflex.components.component import Component
from reflex.components.el import div, p
-from reflex.constants import Hooks, Imports
-from reflex.event import EventChain, EventHandler
-from reflex.utils.imports import ImportVar
+from reflex.event import EventHandler
+from reflex.state import FrontendEventExceptionState
from reflex.vars.base import Var
-from reflex.vars.function import FunctionVar
+
+
+def on_error_spec(
+ error: Var[Dict[str, str]], info: Var[Dict[str, str]]
+) -> Tuple[Var[str], Var[str]]:
+ """The spec for the on_error event handler.
+
+ Args:
+ error: The error message.
+ info: Additional information about the error.
+
+ Returns:
+ The arguments for the event handler.
+ """
+ return (
+ error.stack,
+ info.componentStack,
+ )
class ErrorBoundary(Component):
@@ -21,31 +37,13 @@ class ErrorBoundary(Component):
tag = "ErrorBoundary"
# Fired when the boundary catches an error.
- on_error: EventHandler[lambda error, info: [error, info]] = Var( # type: ignore
- "logFrontendError"
- ).to(FunctionVar, EventChain)
+ on_error: EventHandler[on_error_spec]
# Rendered instead of the children when an error is caught.
Fallback_component: Var[Component] = Var(_js_expr="Fallback")._replace(
_var_type=Component
)
- def add_imports(self) -> dict[str, list[ImportVar]]:
- """Add imports for the component.
-
- Returns:
- The imports to add.
- """
- return Imports.EVENTS
-
- def add_hooks(self) -> List[str | Var]:
- """Add hooks for the component.
-
- Returns:
- The hooks to add.
- """
- return [Hooks.EVENTS, Hooks.FRONTEND_ERRORS]
-
def add_custom_code(self) -> List[str]:
"""Add custom Javascript code into the page that contains this component.
@@ -75,5 +73,20 @@ class ErrorBoundary(Component):
"""
]
+ @classmethod
+ def create(cls, *children, **props):
+ """Create an ErrorBoundary component.
+
+ Args:
+ *children: The children of the component.
+ **props: The props of the component.
+
+ Returns:
+ The ErrorBoundary component.
+ """
+ if "on_error" not in props:
+ props["on_error"] = FrontendEventExceptionState.handle_frontend_exception
+ return super().create(*children, **props)
+
error_boundary = ErrorBoundary.create
diff --git a/reflex/components/base/error_boundary.pyi b/reflex/components/base/error_boundary.pyi
index 65109b0fe..c84742851 100644
--- a/reflex/components/base/error_boundary.pyi
+++ b/reflex/components/base/error_boundary.pyi
@@ -3,17 +3,18 @@
# ------------------- DO NOT EDIT ----------------------
# This file was generated by `reflex/utils/pyi_generator.py`!
# ------------------------------------------------------
-from typing import Any, Dict, List, Optional, Union, overload
+from typing import Any, Dict, List, Optional, Tuple, Union, overload
from reflex.components.component import Component
from reflex.event import EventType
from reflex.style import Style
-from reflex.utils.imports import ImportVar
from reflex.vars.base import Var
+def on_error_spec(
+ error: Var[Dict[str, str]], info: Var[Dict[str, str]]
+) -> Tuple[Var[str], Var[str]]: ...
+
class ErrorBoundary(Component):
- def add_imports(self) -> dict[str, list[ImportVar]]: ...
- def add_hooks(self) -> List[str | Var]: ...
def add_custom_code(self) -> List[str]: ...
@overload
@classmethod
@@ -31,7 +32,7 @@ class ErrorBoundary(Component):
on_click: Optional[EventType[[]]] = None,
on_context_menu: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
- on_error: Optional[EventType[[]]] = None,
+ on_error: Optional[EventType[str, str]] = None,
on_focus: Optional[EventType[[]]] = None,
on_mount: Optional[EventType[[]]] = None,
on_mouse_down: Optional[EventType[[]]] = None,
@@ -45,7 +46,7 @@ class ErrorBoundary(Component):
on_unmount: Optional[EventType[[]]] = None,
**props,
) -> "ErrorBoundary":
- """Create the component.
+ """Create an ErrorBoundary component.
Args:
*children: The children of the component.
@@ -59,7 +60,7 @@ class ErrorBoundary(Component):
**props: The props of the component.
Returns:
- The component.
+ The ErrorBoundary component.
"""
...
diff --git a/reflex/components/component.py b/reflex/components/component.py
index d456ae762..7a07dc66b 100644
--- a/reflex/components/component.py
+++ b/reflex/components/component.py
@@ -45,6 +45,7 @@ from reflex.event import (
EventVar,
call_event_fn,
call_event_handler,
+ empty_event,
get_handler_args,
)
from reflex.style import Style, format_as_emotion
@@ -626,21 +627,21 @@ class Component(BaseComponent, ABC):
"""
default_triggers = {
- EventTriggers.ON_FOCUS: lambda: [],
- EventTriggers.ON_BLUR: lambda: [],
- EventTriggers.ON_CLICK: lambda: [],
- EventTriggers.ON_CONTEXT_MENU: lambda: [],
- EventTriggers.ON_DOUBLE_CLICK: lambda: [],
- EventTriggers.ON_MOUSE_DOWN: lambda: [],
- EventTriggers.ON_MOUSE_ENTER: lambda: [],
- EventTriggers.ON_MOUSE_LEAVE: lambda: [],
- EventTriggers.ON_MOUSE_MOVE: lambda: [],
- EventTriggers.ON_MOUSE_OUT: lambda: [],
- EventTriggers.ON_MOUSE_OVER: lambda: [],
- EventTriggers.ON_MOUSE_UP: lambda: [],
- EventTriggers.ON_SCROLL: lambda: [],
- EventTriggers.ON_MOUNT: lambda: [],
- EventTriggers.ON_UNMOUNT: lambda: [],
+ EventTriggers.ON_FOCUS: empty_event,
+ EventTriggers.ON_BLUR: empty_event,
+ EventTriggers.ON_CLICK: empty_event,
+ EventTriggers.ON_CONTEXT_MENU: empty_event,
+ EventTriggers.ON_DOUBLE_CLICK: empty_event,
+ EventTriggers.ON_MOUSE_DOWN: empty_event,
+ EventTriggers.ON_MOUSE_ENTER: empty_event,
+ EventTriggers.ON_MOUSE_LEAVE: empty_event,
+ EventTriggers.ON_MOUSE_MOVE: empty_event,
+ EventTriggers.ON_MOUSE_OUT: empty_event,
+ EventTriggers.ON_MOUSE_OVER: empty_event,
+ EventTriggers.ON_MOUSE_UP: empty_event,
+ EventTriggers.ON_SCROLL: empty_event,
+ EventTriggers.ON_MOUNT: empty_event,
+ EventTriggers.ON_UNMOUNT: empty_event,
}
# Look for component specific triggers,
@@ -651,7 +652,7 @@ class Component(BaseComponent, ABC):
annotation = field.annotation
if (metadata := getattr(annotation, "__metadata__", None)) is not None:
args_spec = metadata[0]
- default_triggers[field.name] = args_spec or (lambda: [])
+ default_triggers[field.name] = args_spec or (empty_event) # type: ignore
return default_triggers
def __repr__(self) -> str:
@@ -1708,7 +1709,7 @@ class CustomComponent(Component):
value = self._create_event_chain(
value=value,
args_spec=event_triggers_in_component_declaration.get(
- key, lambda: []
+ key, empty_event
),
key=key,
)
diff --git a/reflex/components/core/clipboard.pyi b/reflex/components/core/clipboard.pyi
index e2f6afc8d..489a9bcc5 100644
--- a/reflex/components/core/clipboard.pyi
+++ b/reflex/components/core/clipboard.pyi
@@ -40,7 +40,7 @@ class Clipboard(Fragment):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_paste: Optional[EventType] = None,
+ on_paste: Optional[EventType[list[tuple[str, str]]]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
diff --git a/reflex/components/core/upload.py b/reflex/components/core/upload.py
index be97b170d..89665bb31 100644
--- a/reflex/components/core/upload.py
+++ b/reflex/components/core/upload.py
@@ -2,13 +2,13 @@
from __future__ import annotations
-import os
from pathlib import Path
from typing import Any, Callable, ClassVar, Dict, List, Optional, Tuple
from reflex.components.component import Component, ComponentNamespace, MemoizationLeaf
from reflex.components.el.elements.forms import Input
from reflex.components.radix.themes.layout.box import Box
+from reflex.config import environment
from reflex.constants import Dirs
from reflex.event import (
CallableEventSpec,
@@ -125,9 +125,7 @@ def get_upload_dir() -> Path:
"""
Upload.is_used = True
- uploaded_files_dir = Path(
- os.environ.get("REFLEX_UPLOADED_FILES_DIR", "./uploaded_files")
- )
+ uploaded_files_dir = environment.REFLEX_UPLOADED_FILES_DIR
uploaded_files_dir.mkdir(parents=True, exist_ok=True)
return uploaded_files_dir
@@ -179,7 +177,7 @@ class UploadFilesProvider(Component):
class Upload(MemoizationLeaf):
"""A file upload component."""
- library = "react-dropzone@14.2.9"
+ library = "react-dropzone@14.2.10"
tag = "ReactDropzone"
diff --git a/reflex/components/datadisplay/code.py b/reflex/components/datadisplay/code.py
index c18e44885..3b4fa39d1 100644
--- a/reflex/components/datadisplay/code.py
+++ b/reflex/components/datadisplay/code.py
@@ -381,7 +381,7 @@ for theme_name in dir(Theme):
class CodeBlock(Component):
"""A code block."""
- library = "react-syntax-highlighter@15.5.0"
+ library = "react-syntax-highlighter@15.6.1"
tag = "PrismAsyncLight"
diff --git a/reflex/components/datadisplay/dataeditor.py b/reflex/components/datadisplay/dataeditor.py
index 01255dd14..b9bd4cebf 100644
--- a/reflex/components/datadisplay/dataeditor.py
+++ b/reflex/components/datadisplay/dataeditor.py
@@ -5,6 +5,8 @@ from __future__ import annotations
from enum import Enum
from typing import Any, Dict, List, Literal, Optional, Tuple, Union
+from typing_extensions import TypedDict
+
from reflex.base import Base
from reflex.components.component import Component, NoSSRComponent
from reflex.components.literals import LiteralRowMarker
@@ -107,17 +109,76 @@ class DataEditorTheme(Base):
text_medium: Optional[str] = None
-def on_edit_spec(pos, data: dict[str, Any]):
- """The on edit spec function.
+class Bounds(TypedDict):
+ """The bounds of the group header."""
- Args:
- pos: The position of the edit event.
- data: The data of the edit event.
+ x: int
+ y: int
+ width: int
+ height: int
- Returns:
- The position and data.
- """
- return [pos, data]
+
+class CompatSelection(TypedDict):
+ """The selection."""
+
+ items: list
+
+
+class Rectangle(TypedDict):
+ """The bounds of the group header."""
+
+ x: int
+ y: int
+ width: int
+ height: int
+
+
+class GridSelectionCurrent(TypedDict):
+ """The current selection."""
+
+ cell: tuple[int, int]
+ range: Rectangle
+ rangeStack: list[Rectangle]
+
+
+class GridSelection(TypedDict):
+ """The grid selection."""
+
+ current: Optional[GridSelectionCurrent]
+ columns: CompatSelection
+ rows: CompatSelection
+
+
+class GroupHeaderClickedEventArgs(TypedDict):
+ """The arguments for the group header clicked event."""
+
+ kind: str
+ group: str
+ location: tuple[int, int]
+ bounds: Bounds
+ isEdge: bool
+ shiftKey: bool
+ ctrlKey: bool
+ metaKey: bool
+ isTouch: bool
+ localEventX: int
+ localEventY: int
+ button: int
+ buttons: int
+ scrollEdge: tuple[int, int]
+
+
+class GridCell(TypedDict):
+ """The grid cell."""
+
+ span: Optional[List[int]]
+
+
+class GridColumn(TypedDict):
+ """The grid column."""
+
+ title: str
+ group: Optional[str]
class DataEditor(NoSSRComponent):
@@ -232,16 +293,18 @@ class DataEditor(NoSSRComponent):
on_cell_context_menu: EventHandler[identity_event(Tuple[int, int])]
# Fired when a cell is edited.
- on_cell_edited: EventHandler[on_edit_spec]
+ on_cell_edited: EventHandler[identity_event(Tuple[int, int], GridCell)]
# Fired when a group header is clicked.
- on_group_header_clicked: EventHandler[on_edit_spec]
+ on_group_header_clicked: EventHandler[identity_event(Tuple[int, int], GridCell)]
# Fired when a group header is right-clicked.
- on_group_header_context_menu: EventHandler[lambda grp_idx, data: [grp_idx, data]]
+ on_group_header_context_menu: EventHandler[
+ identity_event(int, GroupHeaderClickedEventArgs)
+ ]
# Fired when a group header is renamed.
- on_group_header_renamed: EventHandler[lambda idx, val: [idx, val]]
+ on_group_header_renamed: EventHandler[identity_event(str, str)]
# Fired when a header is clicked.
on_header_clicked: EventHandler[identity_event(Tuple[int, int])]
@@ -250,16 +313,18 @@ class DataEditor(NoSSRComponent):
on_header_context_menu: EventHandler[identity_event(Tuple[int, int])]
# Fired when a header menu item is clicked.
- on_header_menu_click: EventHandler[lambda col, pos: [col, pos]]
+ on_header_menu_click: EventHandler[identity_event(int, Rectangle)]
# Fired when an item is hovered.
on_item_hovered: EventHandler[identity_event(Tuple[int, int])]
# Fired when a selection is deleted.
- on_delete: EventHandler[lambda selection: [selection]]
+ on_delete: EventHandler[identity_event(GridSelection)]
# Fired when editing is finished.
- on_finished_editing: EventHandler[lambda new_value, movement: [new_value, movement]]
+ on_finished_editing: EventHandler[
+ identity_event(Union[GridCell, None], tuple[int, int])
+ ]
# Fired when a row is appended.
on_row_appended: EventHandler[empty_event]
@@ -268,7 +333,7 @@ class DataEditor(NoSSRComponent):
on_selection_cleared: EventHandler[empty_event]
# Fired when a column is resized.
- on_column_resize: EventHandler[lambda col, width: [col, width]]
+ on_column_resize: EventHandler[identity_event(GridColumn, int)]
def add_imports(self) -> ImportDict:
"""Add imports for the component.
diff --git a/reflex/components/datadisplay/dataeditor.pyi b/reflex/components/datadisplay/dataeditor.pyi
index b3a9ce2b3..6402aaf42 100644
--- a/reflex/components/datadisplay/dataeditor.pyi
+++ b/reflex/components/datadisplay/dataeditor.pyi
@@ -6,6 +6,8 @@
from enum import Enum
from typing import Any, Dict, List, Literal, Optional, Union, overload
+from typing_extensions import TypedDict
+
from reflex.base import Base
from reflex.components.component import NoSSRComponent
from reflex.event import EventType
@@ -76,7 +78,53 @@ class DataEditorTheme(Base):
text_light: Optional[str]
text_medium: Optional[str]
-def on_edit_spec(pos, data: dict[str, Any]): ...
+class Bounds(TypedDict):
+ x: int
+ y: int
+ width: int
+ height: int
+
+class CompatSelection(TypedDict):
+ items: list
+
+class Rectangle(TypedDict):
+ x: int
+ y: int
+ width: int
+ height: int
+
+class GridSelectionCurrent(TypedDict):
+ cell: tuple[int, int]
+ range: Rectangle
+ rangeStack: list[Rectangle]
+
+class GridSelection(TypedDict):
+ current: Optional[GridSelectionCurrent]
+ columns: CompatSelection
+ rows: CompatSelection
+
+class GroupHeaderClickedEventArgs(TypedDict):
+ kind: str
+ group: str
+ location: tuple[int, int]
+ bounds: Bounds
+ isEdge: bool
+ shiftKey: bool
+ ctrlKey: bool
+ metaKey: bool
+ isTouch: bool
+ localEventX: int
+ localEventY: int
+ button: int
+ buttons: int
+ scrollEdge: tuple[int, int]
+
+class GridCell(TypedDict):
+ span: Optional[List[int]]
+
+class GridColumn(TypedDict):
+ title: str
+ group: Optional[str]
class DataEditor(NoSSRComponent):
def add_imports(self) -> ImportDict: ...
@@ -136,24 +184,28 @@ class DataEditor(NoSSRComponent):
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
on_blur: Optional[EventType[[]]] = None,
- on_cell_activated: Optional[EventType] = None,
- on_cell_clicked: Optional[EventType] = None,
- on_cell_context_menu: Optional[EventType] = None,
- on_cell_edited: Optional[EventType[[]]] = None,
+ on_cell_activated: Optional[EventType[tuple[int, int]]] = None,
+ on_cell_clicked: Optional[EventType[tuple[int, int]]] = None,
+ on_cell_context_menu: Optional[EventType[tuple[int, int]]] = None,
+ on_cell_edited: Optional[EventType[tuple[int, int], GridCell]] = None,
on_click: Optional[EventType[[]]] = None,
- on_column_resize: Optional[EventType[[]]] = None,
+ on_column_resize: Optional[EventType[GridColumn, int]] = None,
on_context_menu: Optional[EventType[[]]] = None,
- on_delete: Optional[EventType[[]]] = None,
+ on_delete: Optional[EventType[GridSelection]] = None,
on_double_click: Optional[EventType[[]]] = None,
- on_finished_editing: Optional[EventType[[]]] = None,
+ on_finished_editing: Optional[
+ EventType[Union[GridCell, None], tuple[int, int]]
+ ] = None,
on_focus: Optional[EventType[[]]] = None,
- on_group_header_clicked: Optional[EventType[[]]] = None,
- on_group_header_context_menu: Optional[EventType[[]]] = None,
- on_group_header_renamed: Optional[EventType[[]]] = None,
- on_header_clicked: Optional[EventType] = None,
- on_header_context_menu: Optional[EventType] = None,
- on_header_menu_click: Optional[EventType[[]]] = None,
- on_item_hovered: Optional[EventType] = None,
+ on_group_header_clicked: Optional[EventType[tuple[int, int], GridCell]] = None,
+ on_group_header_context_menu: Optional[
+ EventType[int, GroupHeaderClickedEventArgs]
+ ] = None,
+ on_group_header_renamed: Optional[EventType[str, str]] = None,
+ on_header_clicked: Optional[EventType[tuple[int, int]]] = None,
+ on_header_context_menu: Optional[EventType[tuple[int, int]]] = None,
+ on_header_menu_click: Optional[EventType[int, Rectangle]] = None,
+ on_item_hovered: Optional[EventType[tuple[int, int]]] = None,
on_mount: Optional[EventType[[]]] = None,
on_mouse_down: Optional[EventType[[]]] = None,
on_mouse_enter: Optional[EventType[[]]] = None,
diff --git a/reflex/components/datadisplay/shiki_code_block.py b/reflex/components/datadisplay/shiki_code_block.py
new file mode 100644
index 000000000..46199a6e4
--- /dev/null
+++ b/reflex/components/datadisplay/shiki_code_block.py
@@ -0,0 +1,813 @@
+"""Shiki syntax hghlighter component."""
+
+from __future__ import annotations
+
+import re
+from collections import defaultdict
+from typing import Any, Literal, Optional, Union
+
+from reflex.base import Base
+from reflex.components.component import Component, ComponentNamespace
+from reflex.components.core.colors import color
+from reflex.components.core.cond import color_mode_cond
+from reflex.components.el.elements.forms import Button
+from reflex.components.lucide.icon import Icon
+from reflex.components.radix.themes.layout.box import Box
+from reflex.event import call_script, set_clipboard
+from reflex.style import Style
+from reflex.utils.exceptions import VarTypeError
+from reflex.utils.imports import ImportVar
+from reflex.vars.base import LiteralVar, Var
+from reflex.vars.function import FunctionStringVar
+from reflex.vars.sequence import StringVar, string_replace_operation
+
+
+def copy_script() -> Any:
+ """Copy script for the code block and modify the child SVG element.
+
+
+ Returns:
+ Any: The result of calling the script.
+ """
+ return call_script(
+ f"""
+// Event listener for the parent click
+document.addEventListener('click', function(event) {{
+ // Find the closest div (parent element)
+ const parent = event.target.closest('div');
+ // If the parent is found
+ if (parent) {{
+ // Find the SVG element within the parent
+ const svgIcon = parent.querySelector('svg');
+ // If the SVG exists, proceed with the script
+ if (svgIcon) {{
+ const originalPath = svgIcon.innerHTML;
+ const checkmarkPath = ''; // Checkmark SVG path
+ function transition(element, scale, opacity) {{
+ element.style.transform = `scale(${{scale}})`;
+ element.style.opacity = opacity;
+ }}
+ // Animate the SVG
+ transition(svgIcon, 0, '0');
+ setTimeout(() => {{
+ svgIcon.innerHTML = checkmarkPath; // Replace content with checkmark
+ svgIcon.setAttribute('viewBox', '0 0 24 24'); // Adjust viewBox if necessary
+ transition(svgIcon, 1, '1');
+ setTimeout(() => {{
+ transition(svgIcon, 0, '0');
+ setTimeout(() => {{
+ svgIcon.innerHTML = originalPath; // Restore original SVG content
+ transition(svgIcon, 1, '1');
+ }}, 125);
+ }}, 600);
+ }}, 125);
+ }} else {{
+ // console.error('SVG element not found within the parent.');
+ }}
+ }} else {{
+ // console.error('Parent element not found.');
+ }}
+}});
+"""
+ )
+
+
+SHIKIJS_TRANSFORMER_FNS = {
+ "transformerNotationDiff",
+ "transformerNotationHighlight",
+ "transformerNotationWordHighlight",
+ "transformerNotationFocus",
+ "transformerNotationErrorLevel",
+ "transformerRenderWhitespace",
+ "transformerMetaHighlight",
+ "transformerMetaWordHighlight",
+ "transformerCompactLineOptions",
+ # TODO: this transformer when included adds a weird behavior which removes other code lines. Need to figure out why.
+ # "transformerRemoveLineBreak",
+ "transformerRemoveNotationEscape",
+}
+LINE_NUMBER_STYLING = {
+ "code": {
+ "counter-reset": "step",
+ "counter-increment": "step 0",
+ "display": "grid",
+ "line-height": "1.7",
+ "font-size": "0.875em",
+ },
+ "code .line::before": {
+ "content": "counter(step)",
+ "counter-increment": "step",
+ "width": "1rem",
+ "margin-right": "1.5rem",
+ "display": "inline-block",
+ "text-align": "right",
+ "color": "rgba(115,138,148,.4)",
+ },
+}
+BOX_PARENT_STYLING = {
+ "pre": {
+ "margin": "0",
+ "padding": "24px",
+ "background": "transparent",
+ "overflow-x": "auto",
+ "border-radius": "6px",
+ },
+}
+
+THEME_MAPPING = {
+ "light": "one-light",
+ "dark": "one-dark-pro",
+ "a11y-dark": "github-dark",
+}
+LANGUAGE_MAPPING = {"bash": "shellscript"}
+LiteralCodeLanguage = Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+]
+LiteralCodeTheme = Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+]
+
+
+class ShikiBaseTransformers(Base):
+ """Base for creating transformers."""
+
+ library: str
+ fns: list[FunctionStringVar]
+ style: Optional[Style]
+
+
+class ShikiJsTransformer(ShikiBaseTransformers):
+ """A Wrapped shikijs transformer."""
+
+ library: str = "@shikijs/transformers"
+ fns: list[FunctionStringVar] = [
+ FunctionStringVar.create(fn) for fn in SHIKIJS_TRANSFORMER_FNS
+ ]
+ style: Optional[Style] = Style(
+ {
+ "code": {"line-height": "1.7", "font-size": "0.875em", "display": "grid"},
+ # Diffs
+ ".diff": {
+ "margin": "0 -24px",
+ "padding": "0 24px",
+ "width": "calc(100% + 48px)",
+ "display": "inline-block",
+ },
+ ".diff.add": {
+ "background-color": "rgba(16, 185, 129, .14)",
+ "position": "relative",
+ },
+ ".diff.remove": {
+ "background-color": "rgba(244, 63, 94, .14)",
+ "opacity": "0.7",
+ "position": "relative",
+ },
+ ".diff.remove:after": {
+ "position": "absolute",
+ "left": "10px",
+ "content": "'-'",
+ "color": "#b34e52",
+ },
+ ".diff.add:after": {
+ "position": "absolute",
+ "left": "10px",
+ "content": "'+'",
+ "color": "#18794e",
+ },
+ # Highlight
+ ".highlighted": {
+ "background-color": "rgba(142, 150, 170, .14)",
+ "margin": "0 -24px",
+ "padding": "0 24px",
+ "width": "calc(100% + 48px)",
+ "display": "inline-block",
+ },
+ ".highlighted.error": {
+ "background-color": "rgba(244, 63, 94, .14)",
+ },
+ ".highlighted.warning": {
+ "background-color": "rgba(234, 179, 8, .14)",
+ },
+ # Highlighted Word
+ ".highlighted-word": {
+ "background-color": color("gray", 2),
+ "border": f"1px solid {color('gray', 5)}",
+ "padding": "1px 3px",
+ "margin": "-1px -3px",
+ "border-radius": "4px",
+ },
+ # Focused Lines
+ ".has-focused .line:not(.focused)": {
+ "opacity": "0.7",
+ "filter": "blur(0.095rem)",
+ "transition": "filter .35s, opacity .35s",
+ },
+ ".has-focused:hover .line:not(.focused)": {
+ "opacity": "1",
+ "filter": "none",
+ },
+ # White Space
+ # ".tab, .space": {
+ # "position": "relative",
+ # },
+ # ".tab::before": {
+ # "content": "'⇥'",
+ # "position": "absolute",
+ # "opacity": "0.3",
+ # },
+ # ".space::before": {
+ # "content": "'·'",
+ # "position": "absolute",
+ # "opacity": "0.3",
+ # },
+ }
+ )
+
+ def __init__(self, **kwargs):
+ """Initialize the transformer.
+
+ Args:
+ kwargs: Kwargs to initialize the props.
+
+ """
+ fns = kwargs.pop("fns", None)
+ style = kwargs.pop("style", None)
+ if fns:
+ kwargs["fns"] = [
+ (
+ FunctionStringVar.create(x)
+ if not isinstance(x, FunctionStringVar)
+ else x
+ )
+ for x in fns
+ ]
+
+ if style:
+ kwargs["style"] = Style(style)
+ super().__init__(**kwargs)
+
+
+class ShikiCodeBlock(Component):
+ """A Code block."""
+
+ library = "/components/shiki/code"
+
+ tag = "Code"
+
+ alias = "ShikiCode"
+
+ lib_dependencies: list[str] = ["shiki"]
+
+ # The language to use.
+ language: Var[LiteralCodeLanguage] = Var.create("python")
+
+ # The theme to use ("light" or "dark").
+ theme: Var[LiteralCodeTheme] = Var.create("one-light")
+
+ # The set of themes to use for different modes.
+ themes: Var[Union[list[dict[str, Any]], dict[str, str]]]
+
+ # The code to display.
+ code: Var[str]
+
+ # The transformers to use for the syntax highlighter.
+ transformers: Var[list[Union[ShikiBaseTransformers, dict[str, Any]]]] = Var.create(
+ []
+ )
+
+ @classmethod
+ def create(
+ cls,
+ *children,
+ **props,
+ ) -> Component:
+ """Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/).
+
+ Args:
+ *children: The children of the component.
+ **props: The props to pass to the component.
+
+ Returns:
+ The code block component.
+ """
+ # Separate props for the code block and the wrapper
+ code_block_props = {}
+ code_wrapper_props = {}
+
+ class_props = cls.get_props()
+
+ # Distribute props between the code block and wrapper
+ for key, value in props.items():
+ (code_block_props if key in class_props else code_wrapper_props)[key] = (
+ value
+ )
+
+ code_block_props["code"] = children[0]
+ code_block = super().create(**code_block_props)
+
+ transformer_styles = {}
+ # Collect styles from transformers and wrapper
+ for transformer in code_block.transformers._var_value: # type: ignore
+ if isinstance(transformer, ShikiBaseTransformers) and transformer.style:
+ transformer_styles.update(transformer.style)
+ transformer_styles.update(code_wrapper_props.pop("style", {}))
+
+ return Box.create(
+ code_block,
+ *children[1:],
+ style=Style({**transformer_styles, **BOX_PARENT_STYLING}),
+ **code_wrapper_props,
+ )
+
+ def add_imports(self) -> dict[str, list[str]]:
+ """Add the necessary imports.
+ We add all referenced transformer functions as imports from their corresponding
+ libraries.
+
+ Returns:
+ Imports for the component.
+ """
+ imports = defaultdict(list)
+ for transformer in self.transformers._var_value:
+ if isinstance(transformer, ShikiBaseTransformers):
+ imports[transformer.library].extend(
+ [ImportVar(tag=str(fn)) for fn in transformer.fns]
+ )
+ (
+ self.lib_dependencies.append(transformer.library)
+ if transformer.library not in self.lib_dependencies
+ else None
+ )
+ return imports
+
+ @classmethod
+ def create_transformer(cls, library: str, fns: list[str]) -> ShikiBaseTransformers:
+ """Create a transformer from a third party library.
+
+ Args:
+ library: The name of the library.
+ fns: The str names of the functions/callables to invoke from the library.
+
+ Returns:
+ A transformer for the specified library.
+
+ Raises:
+ ValueError: If a supplied function name is not valid str.
+ """
+ if any(not isinstance(fn_name, str) for fn_name in fns):
+ raise ValueError(
+ f"the function names should be str names of functions in the specified transformer: {library!r}"
+ )
+ return ShikiBaseTransformers( # type: ignore
+ library=library, fns=[FunctionStringVar.create(fn) for fn in fns]
+ )
+
+ def _render(self, props: dict[str, Any] | None = None):
+ """Renders the component with the given properties, processing transformers if present.
+
+ Args:
+ props: Optional properties to pass to the render function.
+
+ Returns:
+ Rendered component output.
+ """
+ # Ensure props is initialized from class attributes if not provided
+ props = props or {
+ attr.rstrip("_"): getattr(self, attr) for attr in self.get_props()
+ }
+
+ # Extract transformers and apply transformations
+ transformers = props.get("transformers")
+ if transformers is not None:
+ transformed_values = self._process_transformers(transformers._var_value)
+ props["transformers"] = LiteralVar.create(transformed_values)
+
+ return super()._render(props)
+
+ def _process_transformers(self, transformer_list: list) -> list:
+ """Processes a list of transformers, applying transformations where necessary.
+
+ Args:
+ transformer_list: List of transformer objects or values.
+
+ Returns:
+ list: A list of transformed values.
+ """
+ processed = []
+
+ for transformer in transformer_list:
+ if isinstance(transformer, ShikiBaseTransformers):
+ processed.extend(fn.call() for fn in transformer.fns)
+ else:
+ processed.append(transformer)
+
+ return processed
+
+
+class ShikiHighLevelCodeBlock(ShikiCodeBlock):
+ """High level component for the shiki syntax highlighter."""
+
+ # If this is enabled, the default transformers(shikijs transformer) will be used.
+ use_transformers: Var[bool]
+
+ # If this is enabled line numbers will be shown next to the code block.
+ show_line_numbers: Var[bool]
+
+ # Whether a copy button should appear.
+ can_copy: Var[bool] = Var.create(False)
+
+ # copy_button: A custom copy button to override the default one.
+ copy_button: Var[Optional[Union[Component, bool]]] = Var.create(None)
+
+ @classmethod
+ def create(
+ cls,
+ *children,
+ **props,
+ ) -> Component:
+ """Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/).
+
+ Args:
+ *children: The children of the component.
+ **props: The props to pass to the component.
+
+ Returns:
+ The code block component.
+ """
+ use_transformers = props.pop("use_transformers", False)
+ show_line_numbers = props.pop("show_line_numbers", False)
+ language = props.pop("language", None)
+ can_copy = props.pop("can_copy", False)
+ copy_button = props.pop("copy_button", None)
+
+ if use_transformers:
+ props["transformers"] = [ShikiJsTransformer()]
+
+ if language is not None:
+ props["language"] = cls._map_languages(language)
+
+ # line numbers are generated via css
+ if show_line_numbers:
+ props["style"] = {**LINE_NUMBER_STYLING, **props.get("style", {})}
+
+ theme = props.pop("theme", None)
+ props["theme"] = props["theme"] = (
+ cls._map_themes(theme)
+ if theme is not None
+ else color_mode_cond( # Default color scheme responds to global color mode.
+ light="one-light",
+ dark="one-dark-pro",
+ )
+ )
+
+ if can_copy:
+ code = children[0]
+ copy_button = ( # type: ignore
+ copy_button
+ if copy_button is not None
+ else Button.create(
+ Icon.create(tag="copy", size=16, color=color("gray", 11)),
+ on_click=[
+ set_clipboard(cls._strip_transformer_triggers(code)), # type: ignore
+ copy_script(),
+ ],
+ style=Style(
+ {
+ "position": "absolute",
+ "top": "4px",
+ "right": "4px",
+ "background": color("gray", 3),
+ "border": "1px solid",
+ "border-color": color("gray", 5),
+ "border-radius": "6px",
+ "padding": "5px",
+ "opacity": "1",
+ "cursor": "pointer",
+ "_hover": {
+ "background": color("gray", 4),
+ },
+ "transition": "background 0.250s ease-out",
+ "&>svg": {
+ "transition": "transform 0.250s ease-out, opacity 0.250s ease-out",
+ },
+ "_active": {
+ "background": color("gray", 5),
+ },
+ }
+ ),
+ )
+ )
+
+ if copy_button:
+ return ShikiCodeBlock.create(
+ children[0], copy_button, position="relative", **props
+ )
+ else:
+ return ShikiCodeBlock.create(children[0], **props)
+
+ @staticmethod
+ def _map_themes(theme: str) -> str:
+ if isinstance(theme, str) and theme in THEME_MAPPING:
+ return THEME_MAPPING[theme]
+ return theme
+
+ @staticmethod
+ def _map_languages(language: str) -> str:
+ if isinstance(language, str) and language in LANGUAGE_MAPPING:
+ return LANGUAGE_MAPPING[language]
+ return language
+
+ @staticmethod
+ def _strip_transformer_triggers(code: str | StringVar) -> StringVar | str:
+ if not isinstance(code, (StringVar, str)):
+ raise VarTypeError(
+ f"code should be string literal or a StringVar type. Got {type(code)} instead."
+ )
+ regex_pattern = r"[\/#]+ *\[!code.*?\]"
+
+ if isinstance(code, Var):
+ return string_replace_operation(
+ code, StringVar(_js_expr=f"/{regex_pattern}/g", _var_type=str), ""
+ )
+ if isinstance(code, str):
+ return re.sub(regex_pattern, "", code)
+
+
+class TransformerNamespace(ComponentNamespace):
+ """Namespace for the Transformers."""
+
+ shikijs = ShikiJsTransformer
+
+
+class CodeblockNamespace(ComponentNamespace):
+ """Namespace for the CodeBlock component."""
+
+ root = staticmethod(ShikiCodeBlock.create)
+ create_transformer = staticmethod(ShikiCodeBlock.create_transformer)
+ transformers = TransformerNamespace()
+ __call__ = staticmethod(ShikiHighLevelCodeBlock.create)
+
+
+code_block = CodeblockNamespace()
diff --git a/reflex/components/datadisplay/shiki_code_block.pyi b/reflex/components/datadisplay/shiki_code_block.pyi
new file mode 100644
index 000000000..bcf2719e9
--- /dev/null
+++ b/reflex/components/datadisplay/shiki_code_block.pyi
@@ -0,0 +1,2211 @@
+"""Stub file for reflex/components/datadisplay/shiki_code_block.py"""
+
+# ------------------- DO NOT EDIT ----------------------
+# This file was generated by `reflex/utils/pyi_generator.py`!
+# ------------------------------------------------------
+from typing import Any, Dict, Literal, Optional, Union, overload
+
+from reflex.base import Base
+from reflex.components.component import Component, ComponentNamespace
+from reflex.event import EventType
+from reflex.style import Style
+from reflex.vars.base import Var
+from reflex.vars.function import FunctionStringVar
+
+def copy_script() -> Any: ...
+
+SHIKIJS_TRANSFORMER_FNS = {
+ "transformerNotationDiff",
+ "transformerNotationHighlight",
+ "transformerNotationWordHighlight",
+ "transformerNotationFocus",
+ "transformerNotationErrorLevel",
+ "transformerRenderWhitespace",
+ "transformerMetaHighlight",
+ "transformerMetaWordHighlight",
+ "transformerCompactLineOptions",
+ "transformerRemoveNotationEscape",
+}
+LINE_NUMBER_STYLING = {
+ "code": {
+ "counter-reset": "step",
+ "counter-increment": "step 0",
+ "display": "grid",
+ "line-height": "1.7",
+ "font-size": "0.875em",
+ },
+ "code .line::before": {
+ "content": "counter(step)",
+ "counter-increment": "step",
+ "width": "1rem",
+ "margin-right": "1.5rem",
+ "display": "inline-block",
+ "text-align": "right",
+ "color": "rgba(115,138,148,.4)",
+ },
+}
+BOX_PARENT_STYLING = {
+ "pre": {
+ "margin": "0",
+ "padding": "24px",
+ "background": "transparent",
+ "overflow-x": "auto",
+ "border-radius": "6px",
+ }
+}
+THEME_MAPPING = {
+ "light": "one-light",
+ "dark": "one-dark-pro",
+ "a11y-dark": "github-dark",
+}
+LANGUAGE_MAPPING = {"bash": "shellscript"}
+LiteralCodeLanguage = Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+]
+LiteralCodeTheme = Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+]
+
+class ShikiBaseTransformers(Base):
+ library: str
+ fns: list[FunctionStringVar]
+ style: Optional[Style]
+
+class ShikiJsTransformer(ShikiBaseTransformers):
+ library: str
+ fns: list[FunctionStringVar]
+ style: Optional[Style]
+
+class ShikiCodeBlock(Component):
+ @overload
+ @classmethod
+ def create( # type: ignore
+ cls,
+ *children,
+ language: Optional[
+ Union[
+ Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+ ],
+ Var[
+ Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+ ]
+ ],
+ ]
+ ] = None,
+ theme: Optional[
+ Union[
+ Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+ ],
+ Var[
+ Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+ ]
+ ],
+ ]
+ ] = None,
+ themes: Optional[
+ Union[
+ Var[Union[dict[str, str], list[dict[str, Any]]]],
+ dict[str, str],
+ list[dict[str, Any]],
+ ]
+ ] = None,
+ code: Optional[Union[Var[str], str]] = None,
+ transformers: Optional[
+ Union[
+ Var[list[Union[ShikiBaseTransformers, dict[str, Any]]]],
+ list[Union[ShikiBaseTransformers, dict[str, Any]]],
+ ]
+ ] = 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[EventType[[]]] = None,
+ on_click: Optional[EventType[[]]] = None,
+ on_context_menu: Optional[EventType[[]]] = None,
+ on_double_click: Optional[EventType[[]]] = None,
+ on_focus: Optional[EventType[[]]] = None,
+ on_mount: Optional[EventType[[]]] = None,
+ on_mouse_down: Optional[EventType[[]]] = None,
+ on_mouse_enter: Optional[EventType[[]]] = None,
+ on_mouse_leave: Optional[EventType[[]]] = None,
+ on_mouse_move: Optional[EventType[[]]] = None,
+ on_mouse_out: Optional[EventType[[]]] = None,
+ on_mouse_over: Optional[EventType[[]]] = None,
+ on_mouse_up: Optional[EventType[[]]] = None,
+ on_scroll: Optional[EventType[[]]] = None,
+ on_unmount: Optional[EventType[[]]] = None,
+ **props,
+ ) -> "ShikiCodeBlock":
+ """Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/).
+
+ Args:
+ *children: The children of the component.
+ language: The language to use.
+ theme: The theme to use ("light" or "dark").
+ themes: The set of themes to use for different modes.
+ code: The code to display.
+ transformers: The transformers to use for the syntax highlighter.
+ 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 to pass to the component.
+
+ Returns:
+ The code block component.
+ """
+ ...
+
+ def add_imports(self) -> dict[str, list[str]]: ...
+ @classmethod
+ def create_transformer(
+ cls, library: str, fns: list[str]
+ ) -> ShikiBaseTransformers: ...
+
+class ShikiHighLevelCodeBlock(ShikiCodeBlock):
+ @overload
+ @classmethod
+ def create( # type: ignore
+ cls,
+ *children,
+ use_transformers: Optional[Union[Var[bool], bool]] = None,
+ show_line_numbers: Optional[Union[Var[bool], bool]] = None,
+ can_copy: Optional[Union[Var[bool], bool]] = None,
+ copy_button: Optional[
+ Union[Component, Var[Optional[Union[Component, bool]]], bool]
+ ] = None,
+ language: Optional[
+ Union[
+ Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+ ],
+ Var[
+ Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+ ]
+ ],
+ ]
+ ] = None,
+ theme: Optional[
+ Union[
+ Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+ ],
+ Var[
+ Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+ ]
+ ],
+ ]
+ ] = None,
+ themes: Optional[
+ Union[
+ Var[Union[dict[str, str], list[dict[str, Any]]]],
+ dict[str, str],
+ list[dict[str, Any]],
+ ]
+ ] = None,
+ code: Optional[Union[Var[str], str]] = None,
+ transformers: Optional[
+ Union[
+ Var[list[Union[ShikiBaseTransformers, dict[str, Any]]]],
+ list[Union[ShikiBaseTransformers, dict[str, Any]]],
+ ]
+ ] = 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[EventType[[]]] = None,
+ on_click: Optional[EventType[[]]] = None,
+ on_context_menu: Optional[EventType[[]]] = None,
+ on_double_click: Optional[EventType[[]]] = None,
+ on_focus: Optional[EventType[[]]] = None,
+ on_mount: Optional[EventType[[]]] = None,
+ on_mouse_down: Optional[EventType[[]]] = None,
+ on_mouse_enter: Optional[EventType[[]]] = None,
+ on_mouse_leave: Optional[EventType[[]]] = None,
+ on_mouse_move: Optional[EventType[[]]] = None,
+ on_mouse_out: Optional[EventType[[]]] = None,
+ on_mouse_over: Optional[EventType[[]]] = None,
+ on_mouse_up: Optional[EventType[[]]] = None,
+ on_scroll: Optional[EventType[[]]] = None,
+ on_unmount: Optional[EventType[[]]] = None,
+ **props,
+ ) -> "ShikiHighLevelCodeBlock":
+ """Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/).
+
+ Args:
+ *children: The children of the component.
+ use_transformers: If this is enabled, the default transformers(shikijs transformer) will be used.
+ show_line_numbers: If this is enabled line numbers will be shown next to the code block.
+ can_copy: Whether a copy button should appear.
+ copy_button: copy_button: A custom copy button to override the default one.
+ language: The language to use.
+ theme: The theme to use ("light" or "dark").
+ themes: The set of themes to use for different modes.
+ code: The code to display.
+ transformers: The transformers to use for the syntax highlighter.
+ 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 to pass to the component.
+
+ Returns:
+ The code block component.
+ """
+ ...
+
+class TransformerNamespace(ComponentNamespace):
+ shikijs = ShikiJsTransformer
+
+class CodeblockNamespace(ComponentNamespace):
+ root = staticmethod(ShikiCodeBlock.create)
+ create_transformer = staticmethod(ShikiCodeBlock.create_transformer)
+ transformers = TransformerNamespace()
+
+ @staticmethod
+ def __call__(
+ *children,
+ use_transformers: Optional[Union[Var[bool], bool]] = None,
+ show_line_numbers: Optional[Union[Var[bool], bool]] = None,
+ can_copy: Optional[Union[Var[bool], bool]] = None,
+ copy_button: Optional[
+ Union[Component, Var[Optional[Union[Component, bool]]], bool]
+ ] = None,
+ language: Optional[
+ Union[
+ Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+ ],
+ Var[
+ Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+ ]
+ ],
+ ]
+ ] = None,
+ theme: Optional[
+ Union[
+ Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+ ],
+ Var[
+ Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+ ]
+ ],
+ ]
+ ] = None,
+ themes: Optional[
+ Union[
+ Var[Union[dict[str, str], list[dict[str, Any]]]],
+ dict[str, str],
+ list[dict[str, Any]],
+ ]
+ ] = None,
+ code: Optional[Union[Var[str], str]] = None,
+ transformers: Optional[
+ Union[
+ Var[list[Union[ShikiBaseTransformers, dict[str, Any]]]],
+ list[Union[ShikiBaseTransformers, dict[str, Any]]],
+ ]
+ ] = 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[EventType[[]]] = None,
+ on_click: Optional[EventType[[]]] = None,
+ on_context_menu: Optional[EventType[[]]] = None,
+ on_double_click: Optional[EventType[[]]] = None,
+ on_focus: Optional[EventType[[]]] = None,
+ on_mount: Optional[EventType[[]]] = None,
+ on_mouse_down: Optional[EventType[[]]] = None,
+ on_mouse_enter: Optional[EventType[[]]] = None,
+ on_mouse_leave: Optional[EventType[[]]] = None,
+ on_mouse_move: Optional[EventType[[]]] = None,
+ on_mouse_out: Optional[EventType[[]]] = None,
+ on_mouse_over: Optional[EventType[[]]] = None,
+ on_mouse_up: Optional[EventType[[]]] = None,
+ on_scroll: Optional[EventType[[]]] = None,
+ on_unmount: Optional[EventType[[]]] = None,
+ **props,
+ ) -> "ShikiHighLevelCodeBlock":
+ """Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/).
+
+ Args:
+ *children: The children of the component.
+ use_transformers: If this is enabled, the default transformers(shikijs transformer) will be used.
+ show_line_numbers: If this is enabled line numbers will be shown next to the code block.
+ can_copy: Whether a copy button should appear.
+ copy_button: copy_button: A custom copy button to override the default one.
+ language: The language to use.
+ theme: The theme to use ("light" or "dark").
+ themes: The set of themes to use for different modes.
+ code: The code to display.
+ transformers: The transformers to use for the syntax highlighter.
+ 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 to pass to the component.
+
+ Returns:
+ The code block component.
+ """
+ ...
+
+code_block = CodeblockNamespace()
diff --git a/reflex/components/markdown/markdown.py b/reflex/components/markdown/markdown.py
index 1665144fd..b790bf7a1 100644
--- a/reflex/components/markdown/markdown.py
+++ b/reflex/components/markdown/markdown.py
@@ -20,6 +20,8 @@ from reflex.components.tags.tag import Tag
from reflex.utils import types
from reflex.utils.imports import ImportDict, ImportVar
from reflex.vars.base import LiteralVar, Var
+from reflex.vars.function import ARRAY_ISARRAY
+from reflex.vars.number import ternary_operation
# Special vars used in the component map.
_CHILDREN = Var(_js_expr="children", _var_type=str)
@@ -199,7 +201,16 @@ class Markdown(Component):
raise ValueError(f"No markdown component found for tag: {tag}.")
special_props = [_PROPS_IN_TAG]
- children = [_CHILDREN]
+ children = [
+ _CHILDREN
+ if tag != "codeblock"
+ # For codeblock, the mapping for some cases returns an array of elements. Let's join them into a string.
+ else ternary_operation(
+ ARRAY_ISARRAY.call(_CHILDREN), # type: ignore
+ _CHILDREN.to(list).join("\n"),
+ _CHILDREN,
+ ).to(str)
+ ]
# For certain tags, the props from the markdown renderer are not actually valid for the component.
if tag in NO_PROPS_TAGS:
diff --git a/reflex/components/moment/moment.pyi b/reflex/components/moment/moment.pyi
index 4f58fda7d..ccffbb8d1 100644
--- a/reflex/components/moment/moment.pyi
+++ b/reflex/components/moment/moment.pyi
@@ -58,7 +58,7 @@ class Moment(NoSSRComponent):
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
on_blur: Optional[EventType[[]]] = None,
- on_change: Optional[EventType] = None,
+ on_change: Optional[EventType[str]] = None,
on_click: Optional[EventType[[]]] = None,
on_context_menu: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
diff --git a/reflex/components/radix/primitives/drawer.pyi b/reflex/components/radix/primitives/drawer.pyi
index 9c5463e56..c4493ee9b 100644
--- a/reflex/components/radix/primitives/drawer.pyi
+++ b/reflex/components/radix/primitives/drawer.pyi
@@ -101,7 +101,7 @@ class DrawerRoot(DrawerComponent):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
@@ -511,7 +511,7 @@ class Drawer(ComponentNamespace):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
diff --git a/reflex/components/radix/themes/color_mode.pyi b/reflex/components/radix/themes/color_mode.pyi
index 43703dc37..d856b0bbd 100644
--- a/reflex/components/radix/themes/color_mode.pyi
+++ b/reflex/components/radix/themes/color_mode.pyi
@@ -383,7 +383,7 @@ class ColorModeSwitch(Switch):
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
on_blur: Optional[EventType[[]]] = None,
- on_change: Optional[EventType] = None,
+ on_change: Optional[EventType[bool]] = None,
on_click: Optional[EventType[[]]] = None,
on_context_menu: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
diff --git a/reflex/components/radix/themes/components/alert_dialog.pyi b/reflex/components/radix/themes/components/alert_dialog.pyi
index d63fcae53..771def7d9 100644
--- a/reflex/components/radix/themes/components/alert_dialog.pyi
+++ b/reflex/components/radix/themes/components/alert_dialog.pyi
@@ -42,7 +42,7 @@ class AlertDialogRoot(RadixThemesComponent):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
diff --git a/reflex/components/radix/themes/components/checkbox.pyi b/reflex/components/radix/themes/components/checkbox.pyi
index fad4f5210..90a9220ef 100644
--- a/reflex/components/radix/themes/components/checkbox.pyi
+++ b/reflex/components/radix/themes/components/checkbox.pyi
@@ -116,7 +116,7 @@ class Checkbox(RadixThemesComponent):
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
on_blur: Optional[EventType[[]]] = None,
- on_change: Optional[EventType] = None,
+ on_change: Optional[EventType[bool]] = None,
on_click: Optional[EventType[[]]] = None,
on_context_menu: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
@@ -263,7 +263,7 @@ class HighLevelCheckbox(RadixThemesComponent):
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
on_blur: Optional[EventType[[]]] = None,
- on_change: Optional[EventType] = None,
+ on_change: Optional[EventType[bool]] = None,
on_click: Optional[EventType[[]]] = None,
on_context_menu: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
@@ -407,7 +407,7 @@ class CheckboxNamespace(ComponentNamespace):
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
on_blur: Optional[EventType[[]]] = None,
- on_change: Optional[EventType] = None,
+ on_change: Optional[EventType[bool]] = None,
on_click: Optional[EventType[[]]] = None,
on_context_menu: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
diff --git a/reflex/components/radix/themes/components/context_menu.pyi b/reflex/components/radix/themes/components/context_menu.pyi
index fbefa88de..56d8200e0 100644
--- a/reflex/components/radix/themes/components/context_menu.pyi
+++ b/reflex/components/radix/themes/components/context_menu.pyi
@@ -39,7 +39,7 @@ class ContextMenuRoot(RadixThemesComponent):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
diff --git a/reflex/components/radix/themes/components/dialog.pyi b/reflex/components/radix/themes/components/dialog.pyi
index e3f17d7e8..0713461e9 100644
--- a/reflex/components/radix/themes/components/dialog.pyi
+++ b/reflex/components/radix/themes/components/dialog.pyi
@@ -40,7 +40,7 @@ class DialogRoot(RadixThemesComponent):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
@@ -382,7 +382,7 @@ class Dialog(ComponentNamespace):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
diff --git a/reflex/components/radix/themes/components/dropdown_menu.pyi b/reflex/components/radix/themes/components/dropdown_menu.pyi
index dba619e7d..8de273be9 100644
--- a/reflex/components/radix/themes/components/dropdown_menu.pyi
+++ b/reflex/components/radix/themes/components/dropdown_menu.pyi
@@ -49,7 +49,7 @@ class DropdownMenuRoot(RadixThemesComponent):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
@@ -363,7 +363,7 @@ class DropdownMenuSub(RadixThemesComponent):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
diff --git a/reflex/components/radix/themes/components/hover_card.pyi b/reflex/components/radix/themes/components/hover_card.pyi
index 8924ef1a8..fa169c852 100644
--- a/reflex/components/radix/themes/components/hover_card.pyi
+++ b/reflex/components/radix/themes/components/hover_card.pyi
@@ -43,7 +43,7 @@ class HoverCardRoot(RadixThemesComponent):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
@@ -256,7 +256,7 @@ class HoverCard(ComponentNamespace):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
diff --git a/reflex/components/radix/themes/components/popover.pyi b/reflex/components/radix/themes/components/popover.pyi
index 984a139d0..218392517 100644
--- a/reflex/components/radix/themes/components/popover.pyi
+++ b/reflex/components/radix/themes/components/popover.pyi
@@ -41,7 +41,7 @@ class PopoverRoot(RadixThemesComponent):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
diff --git a/reflex/components/radix/themes/components/radio_cards.pyi b/reflex/components/radix/themes/components/radio_cards.pyi
index d73447622..d2f6a1425 100644
--- a/reflex/components/radix/themes/components/radio_cards.pyi
+++ b/reflex/components/radix/themes/components/radio_cards.pyi
@@ -177,7 +177,7 @@ class RadioCardsRoot(RadixThemesComponent):
on_mouse_up: Optional[EventType[[]]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
- on_value_change: Optional[EventType] = None,
+ on_value_change: Optional[EventType[str]] = None,
**props,
) -> "RadioCardsRoot":
"""Create a new component instance.
diff --git a/reflex/components/radix/themes/components/radio_group.pyi b/reflex/components/radix/themes/components/radio_group.pyi
index c984fa1f2..f928421c5 100644
--- a/reflex/components/radix/themes/components/radio_group.pyi
+++ b/reflex/components/radix/themes/components/radio_group.pyi
@@ -113,7 +113,7 @@ class RadioGroupRoot(RadixThemesComponent):
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
on_blur: Optional[EventType[[]]] = None,
- on_change: Optional[EventType] = None,
+ on_change: Optional[EventType[str]] = None,
on_click: Optional[EventType[[]]] = None,
on_context_menu: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
diff --git a/reflex/components/radix/themes/components/select.pyi b/reflex/components/radix/themes/components/select.pyi
index c43d58ada..e0e184482 100644
--- a/reflex/components/radix/themes/components/select.pyi
+++ b/reflex/components/radix/themes/components/select.pyi
@@ -44,7 +44,7 @@ class SelectRoot(RadixThemesComponent):
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
on_blur: Optional[EventType[[]]] = None,
- on_change: Optional[EventType] = None,
+ on_change: Optional[EventType[str]] = None,
on_click: Optional[EventType[[]]] = None,
on_context_menu: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
@@ -57,7 +57,7 @@ class SelectRoot(RadixThemesComponent):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
@@ -680,7 +680,7 @@ class HighLevelSelect(SelectRoot):
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
on_blur: Optional[EventType[[]]] = None,
- on_change: Optional[EventType] = None,
+ on_change: Optional[EventType[str]] = None,
on_click: Optional[EventType[[]]] = None,
on_context_menu: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
@@ -693,7 +693,7 @@ class HighLevelSelect(SelectRoot):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
@@ -854,7 +854,7 @@ class Select(ComponentNamespace):
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
on_blur: Optional[EventType[[]]] = None,
- on_change: Optional[EventType] = None,
+ on_change: Optional[EventType[str]] = None,
on_click: Optional[EventType[[]]] = None,
on_context_menu: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
@@ -867,7 +867,7 @@ class Select(ComponentNamespace):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
diff --git a/reflex/components/radix/themes/components/switch.pyi b/reflex/components/radix/themes/components/switch.pyi
index ba9c2595e..f8871872a 100644
--- a/reflex/components/radix/themes/components/switch.pyi
+++ b/reflex/components/radix/themes/components/switch.pyi
@@ -119,7 +119,7 @@ class Switch(RadixThemesComponent):
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
on_blur: Optional[EventType[[]]] = None,
- on_change: Optional[EventType] = None,
+ on_change: Optional[EventType[bool]] = None,
on_click: Optional[EventType[[]]] = None,
on_context_menu: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
diff --git a/reflex/components/radix/themes/components/tabs.pyi b/reflex/components/radix/themes/components/tabs.pyi
index 7b67bad6e..4272bf2a3 100644
--- a/reflex/components/radix/themes/components/tabs.pyi
+++ b/reflex/components/radix/themes/components/tabs.pyi
@@ -41,7 +41,7 @@ class TabsRoot(RadixThemesComponent):
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
on_blur: Optional[EventType[[]]] = None,
- on_change: Optional[EventType] = None,
+ on_change: Optional[EventType[str]] = None,
on_click: Optional[EventType[[]]] = None,
on_context_menu: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
@@ -340,7 +340,7 @@ class Tabs(ComponentNamespace):
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
on_blur: Optional[EventType[[]]] = None,
- on_change: Optional[EventType] = None,
+ on_change: Optional[EventType[str]] = None,
on_click: Optional[EventType[[]]] = None,
on_context_menu: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
diff --git a/reflex/components/radix/themes/components/tooltip.pyi b/reflex/components/radix/themes/components/tooltip.pyi
index ad7c4402f..e78dd926d 100644
--- a/reflex/components/radix/themes/components/tooltip.pyi
+++ b/reflex/components/radix/themes/components/tooltip.pyi
@@ -5,7 +5,9 @@
# ------------------------------------------------------
from typing import Any, Dict, Literal, Optional, Union, overload
-from reflex.event import EventType
+from reflex.event import (
+ EventType,
+)
from reflex.style import Style
from reflex.vars.base import Var
@@ -76,7 +78,7 @@ class Tooltip(RadixThemesComponent):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_pointer_down_outside: Optional[EventType[[]]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
diff --git a/reflex/components/react_player/__init__.py b/reflex/components/react_player/__init__.py
index 8c4a4486f..3f807b1a0 100644
--- a/reflex/components/react_player/__init__.py
+++ b/reflex/components/react_player/__init__.py
@@ -1,5 +1,6 @@
"""React Player component for audio and video."""
+from . import react_player
from .audio import Audio
from .video import Video
diff --git a/reflex/components/react_player/audio.pyi b/reflex/components/react_player/audio.pyi
index 4b566d898..1841829af 100644
--- a/reflex/components/react_player/audio.pyi
+++ b/reflex/components/react_player/audio.pyi
@@ -5,6 +5,7 @@
# ------------------------------------------------------
from typing import Any, Dict, Optional, Union, overload
+import reflex
from reflex.components.react_player.react_player import ReactPlayer
from reflex.event import EventType
from reflex.style import Style
@@ -41,7 +42,7 @@ class Audio(ReactPlayer):
on_context_menu: Optional[EventType[[]]] = None,
on_disable_pip: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
- on_duration: Optional[EventType] = None,
+ on_duration: Optional[EventType[float]] = None,
on_enable_pip: Optional[EventType[[]]] = None,
on_ended: Optional[EventType[[]]] = None,
on_error: Optional[EventType[[]]] = None,
@@ -58,10 +59,12 @@ class Audio(ReactPlayer):
on_play: Optional[EventType[[]]] = None,
on_playback_quality_change: Optional[EventType[[]]] = None,
on_playback_rate_change: Optional[EventType[[]]] = None,
- on_progress: Optional[EventType[[]]] = None,
+ on_progress: Optional[
+ EventType[reflex.components.react_player.react_player.Progress]
+ ] = None,
on_ready: Optional[EventType[[]]] = None,
on_scroll: Optional[EventType[[]]] = None,
- on_seek: Optional[EventType] = None,
+ on_seek: Optional[EventType[float]] = None,
on_start: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
diff --git a/reflex/components/react_player/react_player.py b/reflex/components/react_player/react_player.py
index 7ad45b093..b2c58b754 100644
--- a/reflex/components/react_player/react_player.py
+++ b/reflex/components/react_player/react_player.py
@@ -2,11 +2,22 @@
from __future__ import annotations
+from typing_extensions import TypedDict
+
from reflex.components.component import NoSSRComponent
from reflex.event import EventHandler, empty_event, identity_event
from reflex.vars.base import Var
+class Progress(TypedDict):
+ """Callback containing played and loaded progress as a fraction, and playedSeconds and loadedSeconds in seconds."""
+
+ played: float
+ playedSeconds: float
+ loaded: float
+ loadedSeconds: float
+
+
class ReactPlayer(NoSSRComponent):
"""Using react-player and not implement all props and callback yet.
reference: https://github.com/cookpete/react-player.
@@ -55,7 +66,7 @@ class ReactPlayer(NoSSRComponent):
on_play: EventHandler[empty_event]
# Callback containing played and loaded progress as a fraction, and playedSeconds and loadedSeconds in seconds. eg { played: 0.12, playedSeconds: 11.3, loaded: 0.34, loadedSeconds: 16.7 }
- on_progress: EventHandler[lambda progress: [progress]]
+ on_progress: EventHandler[identity_event(Progress)]
# Callback containing duration of the media, in seconds.
on_duration: EventHandler[identity_event(float)]
diff --git a/reflex/components/react_player/react_player.pyi b/reflex/components/react_player/react_player.pyi
index 1977eaa00..e4027cf40 100644
--- a/reflex/components/react_player/react_player.pyi
+++ b/reflex/components/react_player/react_player.pyi
@@ -5,11 +5,19 @@
# ------------------------------------------------------
from typing import Any, Dict, Optional, Union, overload
+from typing_extensions import TypedDict
+
from reflex.components.component import NoSSRComponent
from reflex.event import EventType
from reflex.style import Style
from reflex.vars.base import Var
+class Progress(TypedDict):
+ played: float
+ playedSeconds: float
+ loaded: float
+ loadedSeconds: float
+
class ReactPlayer(NoSSRComponent):
@overload
@classmethod
@@ -39,7 +47,7 @@ class ReactPlayer(NoSSRComponent):
on_context_menu: Optional[EventType[[]]] = None,
on_disable_pip: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
- on_duration: Optional[EventType] = None,
+ on_duration: Optional[EventType[float]] = None,
on_enable_pip: Optional[EventType[[]]] = None,
on_ended: Optional[EventType[[]]] = None,
on_error: Optional[EventType[[]]] = None,
@@ -56,10 +64,10 @@ class ReactPlayer(NoSSRComponent):
on_play: Optional[EventType[[]]] = None,
on_playback_quality_change: Optional[EventType[[]]] = None,
on_playback_rate_change: Optional[EventType[[]]] = None,
- on_progress: Optional[EventType[[]]] = None,
+ on_progress: Optional[EventType[Progress]] = None,
on_ready: Optional[EventType[[]]] = None,
on_scroll: Optional[EventType[[]]] = None,
- on_seek: Optional[EventType] = None,
+ on_seek: Optional[EventType[float]] = None,
on_start: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
diff --git a/reflex/components/react_player/video.pyi b/reflex/components/react_player/video.pyi
index 6e4047d06..a05e3747b 100644
--- a/reflex/components/react_player/video.pyi
+++ b/reflex/components/react_player/video.pyi
@@ -5,6 +5,7 @@
# ------------------------------------------------------
from typing import Any, Dict, Optional, Union, overload
+import reflex
from reflex.components.react_player.react_player import ReactPlayer
from reflex.event import EventType
from reflex.style import Style
@@ -41,7 +42,7 @@ class Video(ReactPlayer):
on_context_menu: Optional[EventType[[]]] = None,
on_disable_pip: Optional[EventType[[]]] = None,
on_double_click: Optional[EventType[[]]] = None,
- on_duration: Optional[EventType] = None,
+ on_duration: Optional[EventType[float]] = None,
on_enable_pip: Optional[EventType[[]]] = None,
on_ended: Optional[EventType[[]]] = None,
on_error: Optional[EventType[[]]] = None,
@@ -58,10 +59,12 @@ class Video(ReactPlayer):
on_play: Optional[EventType[[]]] = None,
on_playback_quality_change: Optional[EventType[[]]] = None,
on_playback_rate_change: Optional[EventType[[]]] = None,
- on_progress: Optional[EventType[[]]] = None,
+ on_progress: Optional[
+ EventType[reflex.components.react_player.react_player.Progress]
+ ] = None,
on_ready: Optional[EventType[[]]] = None,
on_scroll: Optional[EventType[[]]] = None,
- on_seek: Optional[EventType] = None,
+ on_seek: Optional[EventType[float]] = None,
on_start: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
diff --git a/reflex/components/recharts/cartesian.py b/reflex/components/recharts/cartesian.py
index 153d3fb2a..865b50a32 100644
--- a/reflex/components/recharts/cartesian.py
+++ b/reflex/components/recharts/cartesian.py
@@ -252,7 +252,7 @@ class Brush(Recharts):
A dict mapping the event trigger to the var that is passed to the handler.
"""
return {
- EventTriggers.ON_CHANGE: lambda: [],
+ EventTriggers.ON_CHANGE: empty_event,
}
@@ -293,10 +293,10 @@ class Cartesian(Recharts):
name: Var[Union[str, int]]
# The customized event handler of animation start
- on_animation_start: EventHandler[lambda: []]
+ on_animation_start: EventHandler[empty_event]
# The customized event handler of animation end
- on_animation_end: EventHandler[lambda: []]
+ on_animation_end: EventHandler[empty_event]
# The customized event handler of click on the component in this group
on_click: EventHandler[empty_event]
diff --git a/reflex/components/recharts/charts.py b/reflex/components/recharts/charts.py
index d4785f6c4..d7e07b2d8 100644
--- a/reflex/components/recharts/charts.py
+++ b/reflex/components/recharts/charts.py
@@ -330,9 +330,9 @@ class RadarChart(ChartBase):
A dict mapping the event trigger to the var that is passed to the handler.
"""
return {
- EventTriggers.ON_CLICK: lambda: [],
- EventTriggers.ON_MOUSE_ENTER: lambda: [],
- EventTriggers.ON_MOUSE_LEAVE: lambda: [],
+ EventTriggers.ON_CLICK: empty_event,
+ EventTriggers.ON_MOUSE_ENTER: empty_event,
+ EventTriggers.ON_MOUSE_LEAVE: empty_event,
}
@@ -419,14 +419,14 @@ class ScatterChart(ChartBase):
A dict mapping the event trigger to the var that is passed to the handler.
"""
return {
- EventTriggers.ON_CLICK: lambda: [],
- EventTriggers.ON_MOUSE_DOWN: lambda: [],
- EventTriggers.ON_MOUSE_UP: lambda: [],
- EventTriggers.ON_MOUSE_MOVE: lambda: [],
- EventTriggers.ON_MOUSE_OVER: lambda: [],
- EventTriggers.ON_MOUSE_OUT: lambda: [],
- EventTriggers.ON_MOUSE_ENTER: lambda: [],
- EventTriggers.ON_MOUSE_LEAVE: lambda: [],
+ EventTriggers.ON_CLICK: empty_event,
+ EventTriggers.ON_MOUSE_DOWN: empty_event,
+ EventTriggers.ON_MOUSE_UP: empty_event,
+ EventTriggers.ON_MOUSE_MOVE: empty_event,
+ EventTriggers.ON_MOUSE_OVER: empty_event,
+ EventTriggers.ON_MOUSE_OUT: empty_event,
+ EventTriggers.ON_MOUSE_ENTER: empty_event,
+ EventTriggers.ON_MOUSE_LEAVE: empty_event,
}
diff --git a/reflex/components/recharts/polar.py b/reflex/components/recharts/polar.py
index bcbd5abd3..ccb96f180 100644
--- a/reflex/components/recharts/polar.py
+++ b/reflex/components/recharts/polar.py
@@ -103,14 +103,14 @@ class Pie(Recharts):
A dict mapping the event trigger to the var that is passed to the handler.
"""
return {
- EventTriggers.ON_ANIMATION_START: lambda: [],
- EventTriggers.ON_ANIMATION_END: lambda: [],
- EventTriggers.ON_CLICK: lambda: [],
- EventTriggers.ON_MOUSE_MOVE: lambda: [],
- EventTriggers.ON_MOUSE_OVER: lambda: [],
- EventTriggers.ON_MOUSE_OUT: lambda: [],
- EventTriggers.ON_MOUSE_ENTER: lambda: [],
- EventTriggers.ON_MOUSE_LEAVE: lambda: [],
+ EventTriggers.ON_ANIMATION_START: empty_event,
+ EventTriggers.ON_ANIMATION_END: empty_event,
+ EventTriggers.ON_CLICK: empty_event,
+ EventTriggers.ON_MOUSE_MOVE: empty_event,
+ EventTriggers.ON_MOUSE_OVER: empty_event,
+ EventTriggers.ON_MOUSE_OUT: empty_event,
+ EventTriggers.ON_MOUSE_ENTER: empty_event,
+ EventTriggers.ON_MOUSE_LEAVE: empty_event,
}
@@ -167,8 +167,8 @@ class Radar(Recharts):
A dict mapping the event trigger to the var that is passed to the handler.
"""
return {
- EventTriggers.ON_ANIMATION_START: lambda: [],
- EventTriggers.ON_ANIMATION_END: lambda: [],
+ EventTriggers.ON_ANIMATION_START: empty_event,
+ EventTriggers.ON_ANIMATION_END: empty_event,
}
@@ -219,14 +219,14 @@ class RadialBar(Recharts):
A dict mapping the event trigger to the var that is passed to the handler.
"""
return {
- EventTriggers.ON_CLICK: lambda: [],
- EventTriggers.ON_MOUSE_MOVE: lambda: [],
- EventTriggers.ON_MOUSE_OVER: lambda: [],
- EventTriggers.ON_MOUSE_OUT: lambda: [],
- EventTriggers.ON_MOUSE_ENTER: lambda: [],
- EventTriggers.ON_MOUSE_LEAVE: lambda: [],
- EventTriggers.ON_ANIMATION_START: lambda: [],
- EventTriggers.ON_ANIMATION_END: lambda: [],
+ EventTriggers.ON_CLICK: empty_event,
+ EventTriggers.ON_MOUSE_MOVE: empty_event,
+ EventTriggers.ON_MOUSE_OVER: empty_event,
+ EventTriggers.ON_MOUSE_OUT: empty_event,
+ EventTriggers.ON_MOUSE_ENTER: empty_event,
+ EventTriggers.ON_MOUSE_LEAVE: empty_event,
+ EventTriggers.ON_ANIMATION_START: empty_event,
+ EventTriggers.ON_ANIMATION_END: empty_event,
}
@@ -392,12 +392,12 @@ class PolarRadiusAxis(Recharts):
A dict mapping the event trigger to the var that is passed to the handler.
"""
return {
- EventTriggers.ON_CLICK: lambda: [],
- EventTriggers.ON_MOUSE_MOVE: lambda: [],
- EventTriggers.ON_MOUSE_OVER: lambda: [],
- EventTriggers.ON_MOUSE_OUT: lambda: [],
- EventTriggers.ON_MOUSE_ENTER: lambda: [],
- EventTriggers.ON_MOUSE_LEAVE: lambda: [],
+ EventTriggers.ON_CLICK: empty_event,
+ EventTriggers.ON_MOUSE_MOVE: empty_event,
+ EventTriggers.ON_MOUSE_OVER: empty_event,
+ EventTriggers.ON_MOUSE_OUT: empty_event,
+ EventTriggers.ON_MOUSE_ENTER: empty_event,
+ EventTriggers.ON_MOUSE_LEAVE: empty_event,
}
diff --git a/reflex/components/recharts/recharts.py b/reflex/components/recharts/recharts.py
index 9068cb396..a0d683f72 100644
--- a/reflex/components/recharts/recharts.py
+++ b/reflex/components/recharts/recharts.py
@@ -9,7 +9,7 @@ from reflex.utils import console
class Recharts(Component):
"""A component that wraps a recharts lib."""
- library = "recharts@2.12.7"
+ library = "recharts@2.13.0"
def render(self) -> Dict:
"""Render the tag.
@@ -29,7 +29,7 @@ class Recharts(Component):
class RechartsCharts(NoSSRComponent, MemoizationLeaf):
"""A component that wraps a recharts lib."""
- library = "recharts@2.12.7"
+ library = "recharts@2.13.0"
LiteralAnimationEasing = Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"]
diff --git a/reflex/components/suneditor/editor.py b/reflex/components/suneditor/editor.py
index 6f5b6e4b4..3bca8a3f6 100644
--- a/reflex/components/suneditor/editor.py
+++ b/reflex/components/suneditor/editor.py
@@ -3,11 +3,11 @@
from __future__ import annotations
import enum
-from typing import Dict, List, Literal, Optional, Union
+from typing import Dict, List, Literal, Optional, Tuple, Union
from reflex.base import Base
from reflex.components.component import Component, NoSSRComponent
-from reflex.event import EventHandler
+from reflex.event import EventHandler, empty_event, identity_event
from reflex.utils.format import to_camel_case
from reflex.utils.imports import ImportDict, ImportVar
from reflex.vars.base import Var
@@ -68,6 +68,35 @@ class EditorOptions(Base):
button_list: Optional[List[Union[List[str], str]]]
+def on_blur_spec(e: Var, content: Var[str]) -> Tuple[Var[str]]:
+ """A helper function to specify the on_blur event handler.
+
+ Args:
+ e: The event.
+ content: The content of the editor.
+
+ Returns:
+ A tuple containing the content of the editor.
+ """
+ return (content,)
+
+
+def on_paste_spec(
+ e: Var, clean_data: Var[str], max_char_count: Var[bool]
+) -> Tuple[Var[str], Var[bool]]:
+ """A helper function to specify the on_paste event handler.
+
+ Args:
+ e: The event.
+ clean_data: The clean data.
+ max_char_count: The maximum character count.
+
+ Returns:
+ A tuple containing the clean data and the maximum character count.
+ """
+ return (clean_data, max_char_count)
+
+
class Editor(NoSSRComponent):
"""A Rich Text Editor component based on SunEditor.
Not every JS prop is listed here (some are not easily usable from python),
@@ -178,36 +207,31 @@ class Editor(NoSSRComponent):
disable_toolbar: Var[bool]
# Fired when the editor content changes.
- on_change: EventHandler[lambda content: [content]]
+ on_change: EventHandler[identity_event(str)]
# Fired when the something is inputted in the editor.
- on_input: EventHandler[lambda e: [e]]
+ on_input: EventHandler[empty_event]
# Fired when the editor loses focus.
- on_blur: EventHandler[lambda e, content: [content]]
+ on_blur: EventHandler[on_blur_spec]
# Fired when the editor is loaded.
- on_load: EventHandler[lambda reload: [reload]]
-
- # Fired when the editor is resized.
- on_resize_editor: EventHandler[lambda height, prev_height: [height, prev_height]]
+ on_load: EventHandler[identity_event(bool)]
# Fired when the editor content is copied.
- on_copy: EventHandler[lambda e, clipboard_data: [clipboard_data]]
+ on_copy: EventHandler[empty_event]
# Fired when the editor content is cut.
- on_cut: EventHandler[lambda e, clipboard_data: [clipboard_data]]
+ on_cut: EventHandler[empty_event]
# Fired when the editor content is pasted.
- on_paste: EventHandler[
- lambda e, clean_data, max_char_count: [clean_data, max_char_count]
- ]
+ on_paste: EventHandler[on_paste_spec]
# Fired when the code view is toggled.
- toggle_code_view: EventHandler[lambda is_code_view: [is_code_view]]
+ toggle_code_view: EventHandler[identity_event(bool)]
# Fired when the full screen mode is toggled.
- toggle_full_screen: EventHandler[lambda is_full_screen: [is_full_screen]]
+ toggle_full_screen: EventHandler[identity_event(bool)]
def add_imports(self) -> ImportDict:
"""Add imports for the Editor component.
diff --git a/reflex/components/suneditor/editor.pyi b/reflex/components/suneditor/editor.pyi
index bcc0b64ac..73dd38fdc 100644
--- a/reflex/components/suneditor/editor.pyi
+++ b/reflex/components/suneditor/editor.pyi
@@ -4,7 +4,7 @@
# This file was generated by `reflex/utils/pyi_generator.py`!
# ------------------------------------------------------
import enum
-from typing import Any, Dict, List, Literal, Optional, Union, overload
+from typing import Any, Dict, List, Literal, Optional, Tuple, Union, overload
from reflex.base import Base
from reflex.components.component import NoSSRComponent
@@ -44,6 +44,11 @@ class EditorOptions(Base):
rtl: Optional[bool]
button_list: Optional[List[Union[List[str], str]]]
+def on_blur_spec(e: Var, content: Var[str]) -> Tuple[Var[str]]: ...
+def on_paste_spec(
+ e: Var, clean_data: Var[str], max_char_count: Var[bool]
+) -> Tuple[Var[str], Var[bool]]: ...
+
class Editor(NoSSRComponent):
def add_imports(self) -> ImportDict: ...
@overload
@@ -122,8 +127,8 @@ class Editor(NoSSRComponent):
class_name: Optional[Any] = None,
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
- on_blur: Optional[EventType[[]]] = None,
- on_change: Optional[EventType[[]]] = None,
+ on_blur: Optional[EventType[str]] = None,
+ on_change: Optional[EventType[str]] = None,
on_click: Optional[EventType[[]]] = None,
on_context_menu: Optional[EventType[[]]] = None,
on_copy: Optional[EventType[[]]] = None,
@@ -131,7 +136,7 @@ class Editor(NoSSRComponent):
on_double_click: Optional[EventType[[]]] = None,
on_focus: Optional[EventType[[]]] = None,
on_input: Optional[EventType[[]]] = None,
- on_load: Optional[EventType[[]]] = None,
+ on_load: Optional[EventType[bool]] = None,
on_mount: Optional[EventType[[]]] = None,
on_mouse_down: Optional[EventType[[]]] = None,
on_mouse_enter: Optional[EventType[[]]] = None,
@@ -140,12 +145,11 @@ class Editor(NoSSRComponent):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_paste: Optional[EventType[[]]] = None,
- on_resize_editor: Optional[EventType[[]]] = None,
+ on_paste: Optional[EventType[str, bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
- toggle_code_view: Optional[EventType[[]]] = None,
- toggle_full_screen: Optional[EventType[[]]] = None,
+ toggle_code_view: Optional[EventType[bool]] = None,
+ toggle_full_screen: Optional[EventType[bool]] = None,
**props,
) -> "Editor":
"""Create an instance of Editor. No children allowed.
diff --git a/reflex/config.py b/reflex/config.py
index 719d5c21f..eb319c5dd 100644
--- a/reflex/config.py
+++ b/reflex/config.py
@@ -2,6 +2,7 @@
from __future__ import annotations
+import dataclasses
import importlib
import os
import sys
@@ -9,7 +10,10 @@ import urllib.parse
from pathlib import Path
from typing import Any, Dict, List, Optional, Set, Union
-from reflex.utils.exceptions import ConfigError
+from typing_extensions import get_type_hints
+
+from reflex.utils.exceptions import ConfigError, EnvironmentVarValueError
+from reflex.utils.types import value_inside_optional
try:
import pydantic.v1 as pydantic
@@ -131,6 +135,198 @@ class DBConfig(Base):
return f"{self.engine}://{path}/{self.database}"
+def get_default_value_for_field(field: dataclasses.Field) -> Any:
+ """Get the default value for a field.
+
+ Args:
+ field: The field.
+
+ Returns:
+ The default value.
+
+ Raises:
+ ValueError: If no default value is found.
+ """
+ if field.default != dataclasses.MISSING:
+ return field.default
+ elif field.default_factory != dataclasses.MISSING:
+ return field.default_factory()
+ else:
+ raise ValueError(
+ f"Missing value for environment variable {field.name} and no default value found"
+ )
+
+
+def interpret_boolean_env(value: str) -> bool:
+ """Interpret a boolean environment variable value.
+
+ Args:
+ value: The environment variable value.
+
+ Returns:
+ The interpreted value.
+
+ Raises:
+ EnvironmentVarValueError: If the value is invalid.
+ """
+ true_values = ["true", "1", "yes", "y"]
+ false_values = ["false", "0", "no", "n"]
+
+ if value.lower() in true_values:
+ return True
+ elif value.lower() in false_values:
+ return False
+ raise EnvironmentVarValueError(f"Invalid boolean value: {value}")
+
+
+def interpret_int_env(value: str) -> int:
+ """Interpret an integer environment variable value.
+
+ Args:
+ value: The environment variable value.
+
+ Returns:
+ The interpreted value.
+
+ Raises:
+ EnvironmentVarValueError: If the value is invalid.
+ """
+ try:
+ return int(value)
+ except ValueError as ve:
+ raise EnvironmentVarValueError(f"Invalid integer value: {value}") from ve
+
+
+def interpret_path_env(value: str) -> Path:
+ """Interpret a path environment variable value.
+
+ Args:
+ value: The environment variable value.
+
+ Returns:
+ The interpreted value.
+
+ Raises:
+ EnvironmentVarValueError: If the path does not exist.
+ """
+ path = Path(value)
+ if not path.exists():
+ raise EnvironmentVarValueError(f"Path does not exist: {path}")
+ return path
+
+
+def interpret_env_var_value(value: str, field: dataclasses.Field) -> Any:
+ """Interpret an environment variable value based on the field type.
+
+ Args:
+ value: The environment variable value.
+ field: The field.
+
+ Returns:
+ The interpreted value.
+
+ Raises:
+ ValueError: If the value is invalid.
+ """
+ field_type = value_inside_optional(field.type)
+
+ if field_type is bool:
+ return interpret_boolean_env(value)
+ elif field_type is str:
+ return value
+ elif field_type is int:
+ return interpret_int_env(value)
+ elif field_type is Path:
+ return interpret_path_env(value)
+
+ else:
+ raise ValueError(
+ f"Invalid type for environment variable {field.name}: {field_type}. This is probably an issue in Reflex."
+ )
+
+
+@dataclasses.dataclass(init=False)
+class EnvironmentVariables:
+ """Environment variables class to instantiate environment variables."""
+
+ # Whether to use npm over bun to install frontend packages.
+ REFLEX_USE_NPM: bool = False
+
+ # The npm registry to use.
+ NPM_CONFIG_REGISTRY: Optional[str] = None
+
+ # Whether to use Granian for the backend. Otherwise, use Uvicorn.
+ REFLEX_USE_GRANIAN: bool = False
+
+ # The username to use for authentication on python package repository. Username and password must both be provided.
+ TWINE_USERNAME: Optional[str] = None
+
+ # The password to use for authentication on python package repository. Username and password must both be provided.
+ TWINE_PASSWORD: Optional[str] = None
+
+ # Whether to use the system installed bun. If set to false, bun will be bundled with the app.
+ REFLEX_USE_SYSTEM_BUN: bool = False
+
+ # Whether to use the system installed node and npm. If set to false, node and npm will be bundled with the app.
+ REFLEX_USE_SYSTEM_NODE: bool = False
+
+ # The working directory for the next.js commands.
+ REFLEX_WEB_WORKDIR: Path = Path(constants.Dirs.WEB)
+
+ # Path to the alembic config file
+ ALEMBIC_CONFIG: Path = Path(constants.ALEMBIC_CONFIG)
+
+ # Disable SSL verification for HTTPX requests.
+ SSL_NO_VERIFY: bool = False
+
+ # The directory to store uploaded files.
+ REFLEX_UPLOADED_FILES_DIR: Path = Path(constants.Dirs.UPLOADED_FILES)
+
+ # Whether to use seperate processes to compile the frontend and how many. If not set, defaults to thread executor.
+ REFLEX_COMPILE_PROCESSES: Optional[int] = None
+
+ # Whether to use seperate threads to compile the frontend and how many. Defaults to `min(32, os.cpu_count() + 4)`.
+ REFLEX_COMPILE_THREADS: Optional[int] = None
+
+ # The directory to store reflex dependencies.
+ REFLEX_DIR: Path = Path(constants.Reflex.DIR)
+
+ # Whether to print the SQL queries if the log level is INFO or lower.
+ SQLALCHEMY_ECHO: bool = False
+
+ # Whether to ignore the redis config error. Some redis servers only allow out-of-band configuration.
+ REFLEX_IGNORE_REDIS_CONFIG_ERROR: bool = False
+
+ # Whether to skip purging the web directory in dev mode.
+ REFLEX_PERSIST_WEB_DIR: bool = False
+
+ # The reflex.build frontend host.
+ REFLEX_BUILD_FRONTEND: str = constants.Templates.REFLEX_BUILD_FRONTEND
+
+ # The reflex.build backend host.
+ REFLEX_BUILD_BACKEND: str = constants.Templates.REFLEX_BUILD_BACKEND
+
+ def __init__(self):
+ """Initialize the environment variables."""
+ type_hints = get_type_hints(type(self))
+
+ for field in dataclasses.fields(self):
+ raw_value = os.getenv(field.name, None)
+
+ field.type = type_hints.get(field.name) or field.type
+
+ value = (
+ interpret_env_var_value(raw_value, field)
+ if raw_value is not None
+ else get_default_value_for_field(field)
+ )
+
+ setattr(self, field.name, value)
+
+
+environment = EnvironmentVariables()
+
+
class Config(Base):
"""The config defines runtime settings for the app.
@@ -222,6 +418,12 @@ class Config(Base):
# Number of gunicorn workers from user
gunicorn_workers: Optional[int] = None
+ # Number of requests before a worker is restarted
+ gunicorn_max_requests: int = 100
+
+ # Variance limit for max requests; gunicorn only
+ gunicorn_max_requests_jitter: int = 25
+
# Indicate which type of state manager to use
state_manager_mode: constants.StateManagerMode = constants.StateManagerMode.DISK
@@ -234,6 +436,9 @@ class Config(Base):
# Attributes that were explicitly set by the user.
_non_default_attributes: Set[str] = pydantic.PrivateAttr(set())
+ # Path to file containing key-values pairs to override in the environment; Dotenv format.
+ env_file: Optional[str] = None
+
def __init__(self, *args, **kwargs):
"""Initialize the config values.
@@ -275,6 +480,7 @@ class Config(Base):
def update_from_env(self) -> dict[str, Any]:
"""Update the config values based on set environment variables.
+ If there is a set env_file, it is loaded first.
Returns:
The updated config values.
@@ -284,6 +490,12 @@ class Config(Base):
"""
from reflex.utils.exceptions import EnvVarValueError
+ if self.env_file:
+ from dotenv import load_dotenv
+
+ # load env file if exists
+ load_dotenv(self.env_file, override=True)
+
updated_values = {}
# Iterate over the fields.
for key, field in self.__fields__.items():
diff --git a/reflex/constants/__init__.py b/reflex/constants/__init__.py
index 8e61a3717..a540805b5 100644
--- a/reflex/constants/__init__.py
+++ b/reflex/constants/__init__.py
@@ -2,6 +2,8 @@
from .base import (
COOKIES,
+ ENV_BACKEND_ONLY_ENV_VAR,
+ ENV_FRONTEND_ONLY_ENV_VAR,
ENV_MODE_ENV_VAR,
IS_WINDOWS,
LOCAL_STORAGE,
diff --git a/reflex/constants/base.py b/reflex/constants/base.py
index b86f083cc..bba53d625 100644
--- a/reflex/constants/base.py
+++ b/reflex/constants/base.py
@@ -2,7 +2,6 @@
from __future__ import annotations
-import os
import platform
from enum import Enum
from importlib import metadata
@@ -11,6 +10,8 @@ from types import SimpleNamespace
from platformdirs import PlatformDirs
+from .utils import classproperty
+
IS_WINDOWS = platform.system() == "Windows"
@@ -20,6 +21,8 @@ class Dirs(SimpleNamespace):
# The frontend directories in a project.
# The web folder where the NextJS app is compiled to.
WEB = ".web"
+ # The directory where uploaded files are stored.
+ UPLOADED_FILES = "uploaded_files"
# The name of the assets directory.
APP_ASSETS = "assets"
# The name of the assets directory for external ressource (a subfolder of APP_ASSETS).
@@ -64,21 +67,13 @@ class Reflex(SimpleNamespace):
# Files and directories used to init a new project.
# The directory to store reflex dependencies.
- # Get directory value from enviroment variables if it exists.
- _dir = os.environ.get("REFLEX_DIR", "")
+ # on windows, we use C:/Users//AppData/Local/reflex.
+ # on macOS, we use ~/Library/Application Support/reflex.
+ # on linux, we use ~/.local/share/reflex.
+ # If user sets REFLEX_DIR envroment variable use that instead.
+ DIR = PlatformDirs(MODULE_NAME, False).user_data_path
- DIR = Path(
- _dir
- or (
- # on windows, we use C:/Users//AppData/Local/reflex.
- # on macOS, we use ~/Library/Application Support/reflex.
- # on linux, we use ~/.local/share/reflex.
- # If user sets REFLEX_DIR envroment variable use that instead.
- PlatformDirs(MODULE_NAME, False).user_data_dir
- )
- )
# The root directory of the reflex library.
-
ROOT_DIR = Path(__file__).parents[2]
RELEASES_URL = f"https://api.github.com/repos/reflex-dev/templates/releases"
@@ -101,27 +96,51 @@ class Templates(SimpleNamespace):
DEFAULT = "blank"
# The reflex.build frontend host
- REFLEX_BUILD_FRONTEND = os.environ.get(
- "REFLEX_BUILD_FRONTEND", "https://flexgen.reflex.run"
- )
+ REFLEX_BUILD_FRONTEND = "https://flexgen.reflex.run"
# The reflex.build backend host
- REFLEX_BUILD_BACKEND = os.environ.get(
- "REFLEX_BUILD_BACKEND", "https://flexgen-prod-flexgen.fly.dev"
- )
+ REFLEX_BUILD_BACKEND = "https://flexgen-prod-flexgen.fly.dev"
- # The URL to redirect to reflex.build
- REFLEX_BUILD_URL = (
- REFLEX_BUILD_FRONTEND + "/gen?reflex_init_token={reflex_init_token}"
- )
+ @classproperty
+ @classmethod
+ def REFLEX_BUILD_URL(cls):
+ """The URL to redirect to reflex.build.
- # The URL to poll waiting for the user to select a generation.
- REFLEX_BUILD_POLL_URL = REFLEX_BUILD_BACKEND + "/api/init/{reflex_init_token}"
+ Returns:
+ The URL to redirect to reflex.build.
+ """
+ from reflex.config import environment
- # The URL to fetch the generation's reflex code
- REFLEX_BUILD_CODE_URL = (
- REFLEX_BUILD_BACKEND + "/api/gen/{generation_hash}/refactored"
- )
+ return (
+ environment.REFLEX_BUILD_FRONTEND
+ + "/gen?reflex_init_token={reflex_init_token}"
+ )
+
+ @classproperty
+ @classmethod
+ def REFLEX_BUILD_POLL_URL(cls):
+ """The URL to poll waiting for the user to select a generation.
+
+ Returns:
+ The URL to poll waiting for the user to select a generation.
+ """
+ from reflex.config import environment
+
+ return environment.REFLEX_BUILD_BACKEND + "/api/init/{reflex_init_token}"
+
+ @classproperty
+ @classmethod
+ def REFLEX_BUILD_CODE_URL(cls):
+ """The URL to fetch the generation's reflex code.
+
+ Returns:
+ The URL to fetch the generation's reflex code.
+ """
+ from reflex.config import environment
+
+ return (
+ environment.REFLEX_BUILD_BACKEND + "/api/gen/{generation_hash}/refactored"
+ )
class Dirs(SimpleNamespace):
"""Folders used by the template system of Reflex."""
@@ -226,6 +245,9 @@ SKIP_COMPILE_ENV_VAR = "__REFLEX_SKIP_COMPILE"
# This env var stores the execution mode of the app
ENV_MODE_ENV_VAR = "REFLEX_ENV_MODE"
+ENV_BACKEND_ONLY_ENV_VAR = "REFLEX_BACKEND_ONLY"
+ENV_FRONTEND_ONLY_ENV_VAR = "REFLEX_FRONTEND_ONLY"
+
# Testing variables.
# Testing os env set by pytest when running a test case.
PYTEST_CURRENT_TEST = "PYTEST_CURRENT_TEST"
diff --git a/reflex/constants/compiler.py b/reflex/constants/compiler.py
index 557a92092..318a93783 100644
--- a/reflex/constants/compiler.py
+++ b/reflex/constants/compiler.py
@@ -132,16 +132,6 @@ class Hooks(SimpleNamespace):
}
})"""
- FRONTEND_ERRORS = f"""
- const logFrontendError = (error, info) => {{
- if (process.env.NODE_ENV === "production") {{
- addEvents([Event("{CompileVars.FRONTEND_EXCEPTION_STATE_FULL}.handle_frontend_exception", {{
- stack: error.stack,
- }})])
- }}
- }}
- """
-
class MemoizationDisposition(enum.Enum):
"""The conditions under which a component should be memoized."""
diff --git a/reflex/constants/config.py b/reflex/constants/config.py
index 3ff7aade5..970e67844 100644
--- a/reflex/constants/config.py
+++ b/reflex/constants/config.py
@@ -1,6 +1,5 @@
"""Config constants."""
-import os
from pathlib import Path
from types import SimpleNamespace
@@ -9,7 +8,7 @@ from reflex.constants.base import Dirs, Reflex
from .compiler import Ext
# Alembic migrations
-ALEMBIC_CONFIG = os.environ.get("ALEMBIC_CONFIG", "alembic.ini")
+ALEMBIC_CONFIG = "alembic.ini"
class Config(SimpleNamespace):
diff --git a/reflex/constants/installer.py b/reflex/constants/installer.py
index b12d56c78..766dcf5be 100644
--- a/reflex/constants/installer.py
+++ b/reflex/constants/installer.py
@@ -3,9 +3,11 @@
from __future__ import annotations
import platform
+from pathlib import Path
from types import SimpleNamespace
-from .base import IS_WINDOWS, Reflex
+from .base import IS_WINDOWS
+from .utils import classproperty
def get_fnm_name() -> str | None:
@@ -36,12 +38,9 @@ class Bun(SimpleNamespace):
# The Bun version.
VERSION = "1.1.29"
+
# Min Bun Version
MIN_VERSION = "0.7.0"
- # The directory to store the bun.
- ROOT_PATH = Reflex.DIR / "bun"
- # Default bun path.
- DEFAULT_PATH = ROOT_PATH / "bin" / ("bun" if not IS_WINDOWS else "bun.exe")
# URL to bun install script.
INSTALL_URL = "https://raw.githubusercontent.com/reflex-dev/reflex/main/scripts/bun_install.sh"
@@ -50,11 +49,31 @@ class Bun(SimpleNamespace):
WINDOWS_INSTALL_URL = (
"https://raw.githubusercontent.com/reflex-dev/reflex/main/scripts/install.ps1"
)
+
# Path of the bunfig file
CONFIG_PATH = "bunfig.toml"
- # The environment variable to use the system installed bun.
- USE_SYSTEM_VAR = "REFLEX_USE_SYSTEM_BUN"
+ @classproperty
+ @classmethod
+ def ROOT_PATH(cls):
+ """The directory to store the bun.
+
+ Returns:
+ The directory to store the bun.
+ """
+ from reflex.config import environment
+
+ return environment.REFLEX_DIR / "bun"
+
+ @classproperty
+ @classmethod
+ def DEFAULT_PATH(cls):
+ """Default bun path.
+
+ Returns:
+ The default bun path.
+ """
+ return cls.ROOT_PATH / "bin" / ("bun" if not IS_WINDOWS else "bun.exe")
# FNM config.
@@ -63,44 +82,81 @@ class Fnm(SimpleNamespace):
# The FNM version.
VERSION = "1.35.1"
- # The directory to store fnm.
- DIR = Reflex.DIR / "fnm"
+
FILENAME = get_fnm_name()
- # The fnm executable binary.
- EXE = DIR / ("fnm.exe" if IS_WINDOWS else "fnm")
# The URL to the fnm release binary
INSTALL_URL = (
f"https://github.com/Schniz/fnm/releases/download/v{VERSION}/{FILENAME}.zip"
)
+ @classproperty
+ @classmethod
+ def DIR(cls) -> Path:
+ """The directory to store fnm.
+
+ Returns:
+ The directory to store fnm.
+ """
+ from reflex.config import environment
+
+ return environment.REFLEX_DIR / "fnm"
+
+ @classproperty
+ @classmethod
+ def EXE(cls):
+ """The fnm executable binary.
+
+ Returns:
+ The fnm executable binary.
+ """
+ return cls.DIR / ("fnm.exe" if IS_WINDOWS else "fnm")
+
# Node / NPM config
class Node(SimpleNamespace):
"""Node/ NPM constants."""
# The Node version.
- VERSION = "20.18.0"
+ VERSION = "22.10.0"
# The minimum required node version.
MIN_VERSION = "18.17.0"
- # The node bin path.
- BIN_PATH = (
- Fnm.DIR
- / "node-versions"
- / f"v{VERSION}"
- / "installation"
- / ("bin" if not IS_WINDOWS else "")
- )
+ @classproperty
+ @classmethod
+ def BIN_PATH(cls):
+ """The node bin path.
- # The default path where node is installed.
- PATH = BIN_PATH / ("node.exe" if IS_WINDOWS else "node")
+ Returns:
+ The node bin path.
+ """
+ return (
+ Fnm.DIR
+ / "node-versions"
+ / f"v{cls.VERSION}"
+ / "installation"
+ / ("bin" if not IS_WINDOWS else "")
+ )
- # The default path where npm is installed.
- NPM_PATH = BIN_PATH / "npm"
+ @classproperty
+ @classmethod
+ def PATH(cls):
+ """The default path where node is installed.
- # The environment variable to use the system installed node.
- USE_SYSTEM_VAR = "REFLEX_USE_SYSTEM_NODE"
+ Returns:
+ The default path where node is installed.
+ """
+ return cls.BIN_PATH / ("node.exe" if IS_WINDOWS else "node")
+
+ @classproperty
+ @classmethod
+ def NPM_PATH(cls):
+ """The default path where npm is installed.
+
+ Returns:
+ The default path where npm is installed.
+ """
+ return cls.BIN_PATH / "npm"
class PackageJson(SimpleNamespace):
@@ -117,18 +173,18 @@ class PackageJson(SimpleNamespace):
PATH = "package.json"
DEPENDENCIES = {
- "@babel/standalone": "7.25.7",
+ "@babel/standalone": "7.25.8",
"@emotion/react": "11.13.3",
"axios": "1.7.7",
"json5": "2.2.3",
- "next": "14.2.14",
+ "next": "14.2.15",
"next-sitemap": "4.2.3",
"next-themes": "0.3.0",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-focus-lock": "2.13.2",
"socket.io-client": "4.8.0",
- "universal-cookie": "7.2.0",
+ "universal-cookie": "7.2.1",
}
DEV_DEPENDENCIES = {
"autoprefixer": "10.4.20",
diff --git a/reflex/constants/style.py b/reflex/constants/style.py
index 9cd51da79..403acd4ba 100644
--- a/reflex/constants/style.py
+++ b/reflex/constants/style.py
@@ -7,7 +7,7 @@ class Tailwind(SimpleNamespace):
"""Tailwind constants."""
# The Tailwindcss version
- VERSION = "tailwindcss@3.4.13"
+ VERSION = "tailwindcss@3.4.14"
# The Tailwind config.
CONFIG = "tailwind.config.js"
# Default Tailwind content paths
diff --git a/reflex/constants/utils.py b/reflex/constants/utils.py
new file mode 100644
index 000000000..48797afbf
--- /dev/null
+++ b/reflex/constants/utils.py
@@ -0,0 +1,32 @@
+"""Utility functions for constants."""
+
+from typing import Any, Callable, Generic, Type
+
+from typing_extensions import TypeVar
+
+T = TypeVar("T")
+V = TypeVar("V")
+
+
+class classproperty(Generic[T, V]):
+ """A class property decorator."""
+
+ def __init__(self, getter: Callable[[Type[T]], V]) -> None:
+ """Initialize the class property.
+
+ Args:
+ getter: The getter function.
+ """
+ self.getter = getattr(getter, "__func__", getter)
+
+ def __get__(self, instance: Any, owner: Type[T]) -> V:
+ """Get the value of the class property.
+
+ Args:
+ instance: The instance of the class.
+ owner: The class itself.
+
+ Returns:
+ The value of the class property.
+ """
+ return self.getter(owner)
diff --git a/reflex/custom_components/custom_components.py b/reflex/custom_components/custom_components.py
index ee24a7cd0..ddda3de56 100644
--- a/reflex/custom_components/custom_components.py
+++ b/reflex/custom_components/custom_components.py
@@ -17,7 +17,7 @@ import typer
from tomlkit.exceptions import TOMLKitError
from reflex import constants
-from reflex.config import get_config
+from reflex.config import environment, get_config
from reflex.constants import CustomComponents
from reflex.utils import console
@@ -609,14 +609,14 @@ def publish(
help="The API token to use for authentication on python package repository. If token is provided, no username/password should be provided at the same time",
),
username: Optional[str] = typer.Option(
- os.getenv("TWINE_USERNAME"),
+ environment.TWINE_USERNAME,
"-u",
"--username",
show_default="TWINE_USERNAME environment variable value if set",
help="The username to use for authentication on python package repository. Username and password must both be provided.",
),
password: Optional[str] = typer.Option(
- os.getenv("TWINE_PASSWORD"),
+ environment.TWINE_PASSWORD,
"-p",
"--password",
show_default="TWINE_PASSWORD environment variable value if set",
diff --git a/reflex/event.py b/reflex/event.py
index 1fd611776..e5ed60c2e 100644
--- a/reflex/event.py
+++ b/reflex/event.py
@@ -12,7 +12,6 @@ from functools import partial
from typing import (
Any,
Callable,
- ClassVar,
Dict,
Generic,
List,
@@ -22,9 +21,10 @@ from typing import (
TypeVar,
Union,
get_type_hints,
+ overload,
)
-from typing_extensions import ParamSpec, get_args, get_origin
+from typing_extensions import ParamSpec, Protocol, get_args, get_origin
from reflex import constants
from reflex.utils import console, format
@@ -36,14 +36,15 @@ from reflex.utils.exceptions import (
from reflex.utils.types import ArgsSpec, GenericType
from reflex.vars import VarData
from reflex.vars.base import (
- CachedVarOperation,
- LiteralNoneVar,
LiteralVar,
- ToOperation,
Var,
- cached_property_no_lock,
)
-from reflex.vars.function import ArgsFunctionOperation, FunctionStringVar, FunctionVar
+from reflex.vars.function import (
+ ArgsFunctionOperation,
+ FunctionStringVar,
+ FunctionVar,
+ VarOperationCall,
+)
from reflex.vars.object import ObjectVar
try:
@@ -399,11 +400,6 @@ class EventChain(EventActionsMixin):
invocation: Optional[Var] = dataclasses.field(default=None)
-# These chains can be used for their side effects when no other events are desired.
-stop_propagation = EventChain(events=[], args_spec=lambda: []).stop_propagation
-prevent_default = EventChain(events=[], args_spec=lambda: []).prevent_default
-
-
@dataclasses.dataclass(
init=True,
frozen=True,
@@ -467,34 +463,103 @@ def empty_event() -> Tuple[()]:
return tuple() # type: ignore
+# These chains can be used for their side effects when no other events are desired.
+stop_propagation = EventChain(events=[], args_spec=empty_event).stop_propagation
+prevent_default = EventChain(events=[], args_spec=empty_event).prevent_default
+
+
T = TypeVar("T")
+U = TypeVar("U")
-def identity_event(event_type: Type[T]) -> Callable[[Var[T]], Tuple[Var[T]]]:
+# def identity_event(event_type: Type[T]) -> Callable[[Var[T]], Tuple[Var[T]]]:
+# """A helper function that returns the input event as output.
+
+# Args:
+# event_type: The type of the event.
+
+# Returns:
+# A function that returns the input event as output.
+# """
+
+# def inner(ev: Var[T]) -> Tuple[Var[T]]:
+# return (ev,)
+
+# inner.__signature__ = inspect.signature(inner).replace( # type: ignore
+# parameters=[
+# inspect.Parameter(
+# "ev",
+# kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
+# annotation=Var[event_type],
+# )
+# ],
+# return_annotation=Tuple[Var[event_type]],
+# )
+# inner.__annotations__["ev"] = Var[event_type]
+# inner.__annotations__["return"] = Tuple[Var[event_type]]
+
+# return inner
+
+
+class IdentityEventReturn(Generic[T], Protocol):
+ """Protocol for an identity event return."""
+
+ def __call__(self, *values: Var[T]) -> Tuple[Var[T], ...]:
+ """Return the input values.
+
+ Args:
+ *values: The values to return.
+
+ Returns:
+ The input values.
+ """
+ return values
+
+
+@overload
+def identity_event(event_type: Type[T], /) -> Callable[[Var[T]], Tuple[Var[T]]]: ... # type: ignore
+
+
+@overload
+def identity_event(
+ event_type_1: Type[T], event_type2: Type[U], /
+) -> Callable[[Var[T], Var[U]], Tuple[Var[T], Var[U]]]: ...
+
+
+@overload
+def identity_event(*event_types: Type[T]) -> IdentityEventReturn[T]: ...
+
+
+def identity_event(*event_types: Type[T]) -> IdentityEventReturn[T]: # type: ignore
"""A helper function that returns the input event as output.
Args:
- event_type: The type of the event.
+ *event_types: The types of the events.
Returns:
A function that returns the input event as output.
"""
- def inner(ev: Var[T]) -> Tuple[Var[T]]:
- return (ev,)
+ def inner(*values: Var[T]) -> Tuple[Var[T], ...]:
+ return values
+
+ inner_type = tuple(Var[event_type] for event_type in event_types)
+ return_annotation = Tuple[inner_type] # type: ignore
inner.__signature__ = inspect.signature(inner).replace( # type: ignore
parameters=[
inspect.Parameter(
- "ev",
+ f"ev_{i}",
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
annotation=Var[event_type],
)
+ for i, event_type in enumerate(event_types)
],
- return_annotation=Tuple[Var[event_type]],
+ return_annotation=return_annotation,
)
- inner.__annotations__["ev"] = Var[event_type]
- inner.__annotations__["return"] = Tuple[Var[event_type]]
+ for i, event_type in enumerate(event_types):
+ inner.__annotations__[f"ev_{i}"] = Var[event_type]
+ inner.__annotations__["return"] = return_annotation
return inner
@@ -1116,7 +1181,8 @@ def resolve_annotation(annotations: dict[str, Any], arg_name: str):
deprecation_version="0.6.3",
removal_version="0.7.0",
)
- return JavascriptInputEvent
+ # Allow arbitrary attribute access two levels deep until removed.
+ return Dict[str, dict]
return annotation
@@ -1334,7 +1400,7 @@ def get_fn_signature(fn: Callable) -> inspect.Signature:
return signature.replace(parameters=(new_param, *signature.parameters.values()))
-class EventVar(ObjectVar):
+class EventVar(ObjectVar, python_types=EventSpec):
"""Base class for event vars."""
@@ -1343,7 +1409,7 @@ class EventVar(ObjectVar):
frozen=True,
**{"slots": True} if sys.version_info >= (3, 10) else {},
)
-class LiteralEventVar(CachedVarOperation, LiteralVar, EventVar):
+class LiteralEventVar(VarOperationCall, LiteralVar, EventVar):
"""A literal event var."""
_var_value: EventSpec = dataclasses.field(default=None) # type: ignore
@@ -1356,35 +1422,6 @@ class LiteralEventVar(CachedVarOperation, LiteralVar, EventVar):
"""
return hash((self.__class__.__name__, self._js_expr))
- @cached_property_no_lock
- def _cached_var_name(self) -> str:
- """The name of the var.
-
- Returns:
- The name of the var.
- """
- return str(
- FunctionStringVar("Event").call(
- # event handler name
- ".".join(
- filter(
- None,
- format.get_event_handler_parts(self._var_value.handler),
- )
- ),
- # event handler args
- {str(name): value for name, value in self._var_value.args},
- # event actions
- self._var_value.event_actions,
- # client handler name
- *(
- [self._var_value.client_handler_name]
- if self._var_value.client_handler_name
- else []
- ),
- )
- )
-
@classmethod
def create(
cls,
@@ -1405,10 +1442,26 @@ class LiteralEventVar(CachedVarOperation, LiteralVar, EventVar):
_var_type=EventSpec,
_var_data=_var_data,
_var_value=value,
+ _func=FunctionStringVar("Event"),
+ _args=(
+ # event handler name
+ ".".join(
+ filter(
+ None,
+ format.get_event_handler_parts(value.handler),
+ )
+ ),
+ # event handler args
+ {str(name): value for name, value in value.args},
+ # event actions
+ value.event_actions,
+ # client handler name
+ *([value.client_handler_name] if value.client_handler_name else []),
+ ),
)
-class EventChainVar(FunctionVar):
+class EventChainVar(FunctionVar, python_types=EventChain):
"""Base class for event chain vars."""
@@ -1417,7 +1470,10 @@ class EventChainVar(FunctionVar):
frozen=True,
**{"slots": True} if sys.version_info >= (3, 10) else {},
)
-class LiteralEventChainVar(CachedVarOperation, LiteralVar, EventChainVar):
+# Note: LiteralVar is second in the inheritance list allowing it act like a
+# CachedVarOperation (ArgsFunctionOperation) and get the _js_expr from the
+# _cached_var_name property.
+class LiteralEventChainVar(ArgsFunctionOperation, LiteralVar, EventChainVar):
"""A literal event chain var."""
_var_value: EventChain = dataclasses.field(default=None) # type: ignore
@@ -1430,41 +1486,6 @@ class LiteralEventChainVar(CachedVarOperation, LiteralVar, EventChainVar):
"""
return hash((self.__class__.__name__, self._js_expr))
- @cached_property_no_lock
- def _cached_var_name(self) -> str:
- """The name of the var.
-
- Returns:
- The name of the var.
- """
- sig = inspect.signature(self._var_value.args_spec) # type: ignore
- if sig.parameters:
- arg_def = tuple((f"_{p}" for p in sig.parameters))
- arg_def_expr = LiteralVar.create([Var(_js_expr=arg) for arg in arg_def])
- else:
- # add a default argument for addEvents if none were specified in value.args_spec
- # used to trigger the preventDefault() on the event.
- arg_def = ("...args",)
- arg_def_expr = Var(_js_expr="args")
-
- if self._var_value.invocation is None:
- invocation = FunctionStringVar.create("addEvents")
- else:
- invocation = self._var_value.invocation
-
- return str(
- ArgsFunctionOperation.create(
- arg_def,
- invocation.call(
- LiteralVar.create(
- [LiteralVar.create(event) for event in self._var_value.events]
- ),
- arg_def_expr,
- self._var_value.event_actions,
- ),
- )
- )
-
@classmethod
def create(
cls,
@@ -1480,48 +1501,48 @@ class LiteralEventChainVar(CachedVarOperation, LiteralVar, EventChainVar):
Returns:
The created LiteralEventChainVar instance.
"""
+ sig = inspect.signature(value.args_spec) # type: ignore
+ if sig.parameters:
+ arg_def = tuple((f"_{p}" for p in sig.parameters))
+ arg_def_expr = LiteralVar.create([Var(_js_expr=arg) for arg in arg_def])
+ else:
+ # add a default argument for addEvents if none were specified in value.args_spec
+ # used to trigger the preventDefault() on the event.
+ arg_def = ("...args",)
+ arg_def_expr = Var(_js_expr="args")
+
+ if value.invocation is None:
+ invocation = FunctionStringVar.create("addEvents")
+ else:
+ invocation = value.invocation
+
return cls(
_js_expr="",
_var_type=EventChain,
_var_data=_var_data,
+ _args_names=arg_def,
+ _return_expr=invocation.call(
+ LiteralVar.create([LiteralVar.create(event) for event in value.events]),
+ arg_def_expr,
+ value.event_actions,
+ ),
_var_value=value,
)
-@dataclasses.dataclass(
- eq=False,
- frozen=True,
- **{"slots": True} if sys.version_info >= (3, 10) else {},
-)
-class ToEventVarOperation(ToOperation, EventVar):
- """Result of a cast to an event var."""
-
- _original: Var = dataclasses.field(default_factory=lambda: LiteralNoneVar.create())
-
- _default_var_type: ClassVar[Type] = EventSpec
-
-
-@dataclasses.dataclass(
- eq=False,
- frozen=True,
- **{"slots": True} if sys.version_info >= (3, 10) else {},
-)
-class ToEventChainVarOperation(ToOperation, EventChainVar):
- """Result of a cast to an event chain var."""
-
- _original: Var = dataclasses.field(default_factory=lambda: LiteralNoneVar.create())
-
- _default_var_type: ClassVar[Type] = EventChain
-
-
G = ParamSpec("G")
-IndividualEventType = Union[EventSpec, EventHandler, Callable[G, Any], Var]
+IndividualEventType = Union[EventSpec, EventHandler, Callable[G, Any], Var[Any]]
EventType = Union[IndividualEventType[G], List[IndividualEventType[G]]]
P = ParamSpec("P")
T = TypeVar("T")
+V = TypeVar("V")
+V2 = TypeVar("V2")
+V3 = TypeVar("V3")
+V4 = TypeVar("V4")
+V5 = TypeVar("V5")
if sys.version_info >= (3, 10):
from typing import Concatenate
@@ -1537,7 +1558,55 @@ if sys.version_info >= (3, 10):
"""
self.func = func
- def __get__(self, instance, owner) -> Callable[P, T]:
+ @overload
+ def __get__(
+ self: EventCallback[[V], T], instance: None, owner
+ ) -> Callable[[Union[Var[V], V]], EventSpec]: ...
+
+ @overload
+ def __get__(
+ self: EventCallback[[V, V2], T], instance: None, owner
+ ) -> Callable[[Union[Var[V], V], Union[Var[V2], V2]], EventSpec]: ...
+
+ @overload
+ def __get__(
+ self: EventCallback[[V, V2, V3], T], instance: None, owner
+ ) -> Callable[
+ [Union[Var[V], V], Union[Var[V2], V2], Union[Var[V3], V3]],
+ EventSpec,
+ ]: ...
+
+ @overload
+ def __get__(
+ self: EventCallback[[V, V2, V3, V4], T], instance: None, owner
+ ) -> Callable[
+ [
+ Union[Var[V], V],
+ Union[Var[V2], V2],
+ Union[Var[V3], V3],
+ Union[Var[V4], V4],
+ ],
+ EventSpec,
+ ]: ...
+
+ @overload
+ def __get__(
+ self: EventCallback[[V, V2, V3, V4, V5], T], instance: None, owner
+ ) -> Callable[
+ [
+ Union[Var[V], V],
+ Union[Var[V2], V2],
+ Union[Var[V3], V3],
+ Union[Var[V4], V4],
+ Union[Var[V5], V5],
+ ],
+ EventSpec,
+ ]: ...
+
+ @overload
+ def __get__(self, instance, owner) -> Callable[P, T]: ...
+
+ def __get__(self, instance, owner) -> Callable:
"""Get the function with the instance bound to it.
Args:
@@ -1588,8 +1657,6 @@ class EventNamespace(types.SimpleNamespace):
LiteralEventVar = LiteralEventVar
EventChainVar = EventChainVar
LiteralEventChainVar = LiteralEventChainVar
- ToEventVarOperation = ToEventVarOperation
- ToEventChainVarOperation = ToEventChainVarOperation
EventType = EventType
__call__ = staticmethod(event_handler)
diff --git a/reflex/experimental/__init__.py b/reflex/experimental/__init__.py
index 0c11deb85..164790fe5 100644
--- a/reflex/experimental/__init__.py
+++ b/reflex/experimental/__init__.py
@@ -2,6 +2,7 @@
from types import SimpleNamespace
+from reflex.components.datadisplay.shiki_code_block import code_block as code_block
from reflex.components.props import PropsBase
from reflex.components.radix.themes.components.progress import progress as progress
from reflex.components.sonner.toast import toast as toast
@@ -67,4 +68,5 @@ _x = ExperimentalNamespace(
layout=layout,
PropsBase=PropsBase,
run_in_thread=run_in_thread,
+ code_block=code_block,
)
diff --git a/reflex/experimental/layout.pyi b/reflex/experimental/layout.pyi
index e4c82b351..dcdac5b5d 100644
--- a/reflex/experimental/layout.pyi
+++ b/reflex/experimental/layout.pyi
@@ -129,7 +129,7 @@ class DrawerSidebar(DrawerRoot):
on_mouse_out: Optional[EventType[[]]] = None,
on_mouse_over: Optional[EventType[[]]] = None,
on_mouse_up: Optional[EventType[[]]] = None,
- on_open_change: Optional[EventType] = None,
+ on_open_change: Optional[EventType[bool]] = None,
on_scroll: Optional[EventType[[]]] = None,
on_unmount: Optional[EventType[[]]] = None,
**props,
diff --git a/reflex/istate/storage.py b/reflex/istate/storage.py
new file mode 100644
index 000000000..85e21ffa7
--- /dev/null
+++ b/reflex/istate/storage.py
@@ -0,0 +1,144 @@
+"""Client-side storage classes for reflex state variables."""
+
+from __future__ import annotations
+
+from typing import Any
+
+from reflex.utils import format
+
+
+class ClientStorageBase:
+ """Base class for client-side storage."""
+
+ def options(self) -> dict[str, Any]:
+ """Get the options for the storage.
+
+ Returns:
+ All set options for the storage (not None).
+ """
+ return {
+ format.to_camel_case(k): v for k, v in vars(self).items() if v is not None
+ }
+
+
+class Cookie(ClientStorageBase, str):
+ """Represents a state Var that is stored as a cookie in the browser."""
+
+ name: str | None
+ path: str
+ max_age: int | None
+ domain: str | None
+ secure: bool | None
+ same_site: str
+
+ def __new__(
+ cls,
+ object: Any = "",
+ encoding: str | None = None,
+ errors: str | None = None,
+ /,
+ name: str | None = None,
+ path: str = "/",
+ max_age: int | None = None,
+ domain: str | None = None,
+ secure: bool | None = None,
+ same_site: str = "lax",
+ ):
+ """Create a client-side Cookie (str).
+
+ Args:
+ object: The initial object.
+ encoding: The encoding to use.
+ errors: The error handling scheme to use.
+ name: The name of the cookie on the client side.
+ path: Cookie path. Use / as the path if the cookie should be accessible on all pages.
+ max_age: Relative max age of the cookie in seconds from when the client receives it.
+ domain: Domain for the cookie (sub.domain.com or .allsubdomains.com).
+ secure: Is the cookie only accessible through HTTPS?
+ same_site: Whether the cookie is sent with third party requests.
+ One of (true|false|none|lax|strict)
+
+ Returns:
+ The client-side Cookie object.
+
+ Note: expires (absolute Date) is not supported at this time.
+ """
+ if encoding or errors:
+ inst = super().__new__(cls, object, encoding or "utf-8", errors or "strict")
+ else:
+ inst = super().__new__(cls, object)
+ inst.name = name
+ inst.path = path
+ inst.max_age = max_age
+ inst.domain = domain
+ inst.secure = secure
+ inst.same_site = same_site
+ return inst
+
+
+class LocalStorage(ClientStorageBase, str):
+ """Represents a state Var that is stored in localStorage in the browser."""
+
+ name: str | None
+ sync: bool = False
+
+ def __new__(
+ cls,
+ object: Any = "",
+ encoding: str | None = None,
+ errors: str | None = None,
+ /,
+ name: str | None = None,
+ sync: bool = False,
+ ) -> "LocalStorage":
+ """Create a client-side localStorage (str).
+
+ Args:
+ object: The initial object.
+ encoding: The encoding to use.
+ errors: The error handling scheme to use.
+ name: The name of the storage key on the client side.
+ sync: Whether changes should be propagated to other tabs.
+
+ Returns:
+ The client-side localStorage object.
+ """
+ if encoding or errors:
+ inst = super().__new__(cls, object, encoding or "utf-8", errors or "strict")
+ else:
+ inst = super().__new__(cls, object)
+ inst.name = name
+ inst.sync = sync
+ return inst
+
+
+class SessionStorage(ClientStorageBase, str):
+ """Represents a state Var that is stored in sessionStorage in the browser."""
+
+ name: str | None
+
+ def __new__(
+ cls,
+ object: Any = "",
+ encoding: str | None = None,
+ errors: str | None = None,
+ /,
+ name: str | None = None,
+ ) -> "SessionStorage":
+ """Create a client-side sessionStorage (str).
+
+ Args:
+ object: The initial object.
+ encoding: The encoding to use.
+ errors: The error handling scheme to use
+ name: The name of the storage on the client side
+
+ Returns:
+ The client-side sessionStorage object.
+ """
+ if encoding or errors:
+ inst = super().__new__(cls, object, encoding or "utf-8", errors or "strict")
+ else:
+ inst = super().__new__(cls, object)
+ inst.name = name
+ return inst
diff --git a/reflex/model.py b/reflex/model.py
index 0e8d62e90..b269044c5 100644
--- a/reflex/model.py
+++ b/reflex/model.py
@@ -2,9 +2,7 @@
from __future__ import annotations
-import os
from collections import defaultdict
-from pathlib import Path
from typing import Any, ClassVar, Optional, Type, Union
import alembic.autogenerate
@@ -18,9 +16,8 @@ import sqlalchemy
import sqlalchemy.exc
import sqlalchemy.orm
-from reflex import constants
from reflex.base import Base
-from reflex.config import get_config
+from reflex.config import environment, get_config
from reflex.utils import console
from reflex.utils.compat import sqlmodel, sqlmodel_field_has_primary_key
@@ -41,12 +38,12 @@ def get_engine(url: str | None = None) -> sqlalchemy.engine.Engine:
url = url or conf.db_url
if url is None:
raise ValueError("No database url configured")
- if not Path(constants.ALEMBIC_CONFIG).exists():
+ if environment.ALEMBIC_CONFIG.exists():
console.warn(
"Database is not initialized, run [bold]reflex db init[/bold] first."
)
# Print the SQL queries if the log level is INFO or lower.
- echo_db_query = os.environ.get("SQLALCHEMY_ECHO") == "True"
+ echo_db_query = environment.SQLALCHEMY_ECHO
# Needed for the admin dash on sqlite.
connect_args = {"check_same_thread": False} if url.startswith("sqlite") else {}
return sqlmodel.create_engine(url, echo=echo_db_query, connect_args=connect_args)
@@ -234,7 +231,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
Returns:
tuple of (config, script_directory)
"""
- config = alembic.config.Config(constants.ALEMBIC_CONFIG)
+ config = alembic.config.Config(environment.ALEMBIC_CONFIG)
return config, alembic.script.ScriptDirectory(
config.get_main_option("script_location", default="version"),
)
@@ -269,8 +266,8 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
def alembic_init(cls):
"""Initialize alembic for the project."""
alembic.command.init(
- config=alembic.config.Config(constants.ALEMBIC_CONFIG),
- directory=str(Path(constants.ALEMBIC_CONFIG).parent / "alembic"),
+ config=alembic.config.Config(environment.ALEMBIC_CONFIG),
+ directory=str(environment.ALEMBIC_CONFIG.parent / "alembic"),
)
@classmethod
@@ -290,7 +287,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
Returns:
True when changes have been detected.
"""
- if not Path(constants.ALEMBIC_CONFIG).exists():
+ if not environment.ALEMBIC_CONFIG.exists():
return False
config, script_directory = cls._alembic_config()
@@ -391,7 +388,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
True - indicating the process was successful.
None - indicating the process was skipped.
"""
- if not Path(constants.ALEMBIC_CONFIG).exists():
+ if not environment.ALEMBIC_CONFIG.exists():
return
with cls.get_db_engine().connect() as connection:
diff --git a/reflex/reflex.py b/reflex/reflex.py
index 4608ed171..7bef8b7e5 100644
--- a/reflex/reflex.py
+++ b/reflex/reflex.py
@@ -4,7 +4,6 @@ from __future__ import annotations
import atexit
import os
-import webbrowser
from pathlib import Path
from typing import List, Optional
@@ -14,7 +13,7 @@ from reflex_cli.deployments import deployments_cli
from reflex_cli.utils import dependency
from reflex import constants
-from reflex.config import get_config
+from reflex.config import environment, get_config
from reflex.custom_components.custom_components import custom_components_cli
from reflex.state import reset_disk_state_manager
from reflex.utils import console, redir, telemetry
@@ -275,9 +274,17 @@ def run(
constants.Env.DEV, help="The environment to run the app in."
),
frontend: bool = typer.Option(
- False, "--frontend-only", help="Execute only frontend."
+ False,
+ "--frontend-only",
+ help="Execute only frontend.",
+ envvar=constants.ENV_FRONTEND_ONLY_ENV_VAR,
+ ),
+ backend: bool = typer.Option(
+ False,
+ "--backend-only",
+ help="Execute only backend.",
+ envvar=constants.ENV_BACKEND_ONLY_ENV_VAR,
),
- backend: bool = typer.Option(False, "--backend-only", help="Execute only backend."),
frontend_port: str = typer.Option(
config.frontend_port, help="Specify a different frontend port."
),
@@ -292,6 +299,12 @@ def run(
),
):
"""Run the app in the current directory."""
+ if frontend and backend:
+ console.error("Cannot use both --frontend-only and --backend-only options.")
+ raise typer.Exit(1)
+ os.environ[constants.ENV_BACKEND_ONLY_ENV_VAR] = str(backend).lower()
+ os.environ[constants.ENV_FRONTEND_ONLY_ENV_VAR] = str(frontend).lower()
+
_run(env, frontend, backend, frontend_port, backend_port, backend_host, loglevel)
@@ -407,7 +420,7 @@ def db_init():
return
# Check the alembic config.
- if Path(constants.ALEMBIC_CONFIG).exists():
+ if environment.ALEMBIC_CONFIG.exists():
console.error(
"Database is already initialized. Use "
"[bold]reflex db makemigrations[/bold] to create schema change "
@@ -586,18 +599,6 @@ def deploy(
)
-@cli.command()
-def demo(
- frontend_port: str = typer.Option(
- "3001", help="Specify a different frontend port."
- ),
- backend_port: str = typer.Option("8001", help="Specify a different backend port."),
-):
- """Run the demo app."""
- # Open the demo app in a terminal.
- webbrowser.open("https://demo.reflex.run")
-
-
cli.add_typer(db_cli, name="db", help="Subcommands for managing the database schema.")
cli.add_typer(script_cli, name="script", help="Subcommands running helper scripts.")
cli.add_typer(
diff --git a/reflex/state.py b/reflex/state.py
index 7b338b4d6..dcd576b3a 100644
--- a/reflex/state.py
+++ b/reflex/state.py
@@ -8,7 +8,6 @@ import copy
import dataclasses
import functools
import inspect
-import os
import pickle
import sys
import uuid
@@ -40,8 +39,12 @@ from typing import (
from sqlalchemy.orm import DeclarativeBase
from typing_extensions import Self
+from reflex import event
from reflex.config import get_config
from reflex.istate.data import RouterData
+from reflex.istate.storage import (
+ ClientStorageBase,
+)
from reflex.vars.base import (
ComputedVar,
DynamicRouteVar,
@@ -64,6 +67,7 @@ from redis.exceptions import ResponseError
import reflex.istate.dynamic
from reflex import constants
from reflex.base import Base
+from reflex.config import environment
from reflex.event import (
BACKGROUND_TASK_MARKER,
Event,
@@ -2094,7 +2098,8 @@ class State(BaseState):
class FrontendEventExceptionState(State):
"""Substate for handling frontend exceptions."""
- def handle_frontend_exception(self, stack: str) -> None:
+ @event
+ def handle_frontend_exception(self, stack: str, component_stack: str) -> None:
"""Handle frontend exceptions.
If a frontend exception handler is provided, it will be called.
@@ -2102,6 +2107,7 @@ class FrontendEventExceptionState(State):
Args:
stack: The stack trace of the exception.
+ component_stack: The stack trace of the component where the exception occurred.
"""
app_instance = getattr(prerequisites.get_app(), constants.CompileVars.APP)
@@ -2566,9 +2572,11 @@ class StateManager(Base, ABC):
The state manager (either disk, memory or redis).
"""
config = get_config()
- if config.state_manager_mode == constants.StateManagerMode.DISK:
- return StateManagerMemory(state=state)
+ if prerequisites.parse_redis_url() is not None:
+ config.state_manager_mode = constants.StateManagerMode.REDIS
if config.state_manager_mode == constants.StateManagerMode.MEMORY:
+ return StateManagerMemory(state=state)
+ if config.state_manager_mode == constants.StateManagerMode.DISK:
return StateManagerDisk(state=state)
if config.state_manager_mode == constants.StateManagerMode.REDIS:
redis = prerequisites.get_redis()
@@ -3272,11 +3280,7 @@ class StateManagerRedis(StateManager):
)
except ResponseError:
# Some redis servers only allow out-of-band configuration, so ignore errors here.
- ignore_config_error = os.environ.get(
- "REFLEX_IGNORE_REDIS_CONFIG_ERROR",
- None,
- )
- if not ignore_config_error:
+ if not environment.REFLEX_IGNORE_REDIS_CONFIG_ERROR:
raise
async with self.redis.pubsub() as pubsub:
await pubsub.psubscribe(lock_key_channel)
@@ -3348,143 +3352,6 @@ def get_state_manager() -> StateManager:
return app.state_manager
-class ClientStorageBase:
- """Base class for client-side storage."""
-
- def options(self) -> dict[str, Any]:
- """Get the options for the storage.
-
- Returns:
- All set options for the storage (not None).
- """
- return {
- format.to_camel_case(k): v for k, v in vars(self).items() if v is not None
- }
-
-
-class Cookie(ClientStorageBase, str):
- """Represents a state Var that is stored as a cookie in the browser."""
-
- name: str | None
- path: str
- max_age: int | None
- domain: str | None
- secure: bool | None
- same_site: str
-
- def __new__(
- cls,
- object: Any = "",
- encoding: str | None = None,
- errors: str | None = None,
- /,
- name: str | None = None,
- path: str = "/",
- max_age: int | None = None,
- domain: str | None = None,
- secure: bool | None = None,
- same_site: str = "lax",
- ):
- """Create a client-side Cookie (str).
-
- Args:
- object: The initial object.
- encoding: The encoding to use.
- errors: The error handling scheme to use.
- name: The name of the cookie on the client side.
- path: Cookie path. Use / as the path if the cookie should be accessible on all pages.
- max_age: Relative max age of the cookie in seconds from when the client receives it.
- domain: Domain for the cookie (sub.domain.com or .allsubdomains.com).
- secure: Is the cookie only accessible through HTTPS?
- same_site: Whether the cookie is sent with third party requests.
- One of (true|false|none|lax|strict)
-
- Returns:
- The client-side Cookie object.
-
- Note: expires (absolute Date) is not supported at this time.
- """
- if encoding or errors:
- inst = super().__new__(cls, object, encoding or "utf-8", errors or "strict")
- else:
- inst = super().__new__(cls, object)
- inst.name = name
- inst.path = path
- inst.max_age = max_age
- inst.domain = domain
- inst.secure = secure
- inst.same_site = same_site
- return inst
-
-
-class LocalStorage(ClientStorageBase, str):
- """Represents a state Var that is stored in localStorage in the browser."""
-
- name: str | None
- sync: bool = False
-
- def __new__(
- cls,
- object: Any = "",
- encoding: str | None = None,
- errors: str | None = None,
- /,
- name: str | None = None,
- sync: bool = False,
- ) -> "LocalStorage":
- """Create a client-side localStorage (str).
-
- Args:
- object: The initial object.
- encoding: The encoding to use.
- errors: The error handling scheme to use.
- name: The name of the storage key on the client side.
- sync: Whether changes should be propagated to other tabs.
-
- Returns:
- The client-side localStorage object.
- """
- if encoding or errors:
- inst = super().__new__(cls, object, encoding or "utf-8", errors or "strict")
- else:
- inst = super().__new__(cls, object)
- inst.name = name
- inst.sync = sync
- return inst
-
-
-class SessionStorage(ClientStorageBase, str):
- """Represents a state Var that is stored in sessionStorage in the browser."""
-
- name: str | None
-
- def __new__(
- cls,
- object: Any = "",
- encoding: str | None = None,
- errors: str | None = None,
- /,
- name: str | None = None,
- ) -> "SessionStorage":
- """Create a client-side sessionStorage (str).
-
- Args:
- object: The initial object.
- encoding: The encoding to use.
- errors: The error handling scheme to use
- name: The name of the storage on the client side
-
- Returns:
- The client-side sessionStorage object.
- """
- if encoding or errors:
- inst = super().__new__(cls, object, encoding or "utf-8", errors or "strict")
- else:
- inst = super().__new__(cls, object)
- inst.name = name
- return inst
-
-
class MutableProxy(wrapt.ObjectProxy):
"""A proxy for a mutable object that tracks changes."""
diff --git a/reflex/style.py b/reflex/style.py
index 4ebd42ac3..8e24e9b6b 100644
--- a/reflex/style.py
+++ b/reflex/style.py
@@ -10,6 +10,7 @@ from reflex.event import EventChain, EventHandler
from reflex.utils import format
from reflex.utils.exceptions import ReflexError
from reflex.utils.imports import ImportVar
+from reflex.utils.types import get_origin
from reflex.vars import VarData
from reflex.vars.base import CallableVar, LiteralVar, Var
from reflex.vars.function import FunctionVar
@@ -196,6 +197,10 @@ def convert(
isinstance(value, Breakpoints)
and all(not isinstance(v, dict) for v in value.values())
)
+ or (
+ isinstance(value, ObjectVar)
+ and not issubclass(get_origin(value._var_type) or value._var_type, dict)
+ )
else (key,)
)
diff --git a/reflex/utils/build.py b/reflex/utils/build.py
index 770809015..14709d99c 100644
--- a/reflex/utils/build.py
+++ b/reflex/utils/build.py
@@ -23,18 +23,6 @@ def set_env_json():
)
-def set_os_env(**kwargs):
- """Set os environment variables.
-
- Args:
- kwargs: env key word args.
- """
- for key, value in kwargs.items():
- if not value:
- continue
- os.environ[key.upper()] = value
-
-
def generate_sitemap_config(deploy_url: str, export=False):
"""Generate the sitemap config file.
diff --git a/reflex/utils/exceptions.py b/reflex/utils/exceptions.py
index 024f5931b..ee4b8f54e 100644
--- a/reflex/utils/exceptions.py
+++ b/reflex/utils/exceptions.py
@@ -139,3 +139,7 @@ class SetUndefinedStateVarError(ReflexError, AttributeError):
class StateSchemaMismatchError(ReflexError, TypeError):
"""Raised when the serialized schema of a state class does not match the current schema."""
+
+
+class EnvironmentVarValueError(ReflexError, ValueError):
+ """Raised when an environment variable is set to an invalid value."""
diff --git a/reflex/utils/exec.py b/reflex/utils/exec.py
index acb69ee19..bdc9be4ae 100644
--- a/reflex/utils/exec.py
+++ b/reflex/utils/exec.py
@@ -15,7 +15,7 @@ from urllib.parse import urljoin
import psutil
from reflex import constants
-from reflex.config import get_config
+from reflex.config import environment, get_config
from reflex.constants.base import LogLevel
from reflex.utils import console, path_ops
from reflex.utils.prerequisites import get_web_dir
@@ -184,7 +184,7 @@ def should_use_granian():
Returns:
True if Granian should be used.
"""
- return os.getenv("REFLEX_USE_GRANIAN", "0") == "1"
+ return environment.REFLEX_USE_GRANIAN
def get_app_module():
@@ -337,8 +337,8 @@ def run_uvicorn_backend_prod(host, port, loglevel):
app_module = get_app_module()
- RUN_BACKEND_PROD = f"gunicorn --worker-class {config.gunicorn_worker_class} --preload --timeout {config.timeout} --log-level critical".split()
- RUN_BACKEND_PROD_WINDOWS = f"uvicorn --timeout-keep-alive {config.timeout}".split()
+ RUN_BACKEND_PROD = f"gunicorn --worker-class {config.gunicorn_worker_class} --max-requests {config.gunicorn_max_requests} --max-requests-jitter {config.gunicorn_max_requests_jitter} --preload --timeout {config.timeout} --log-level critical".split()
+ RUN_BACKEND_PROD_WINDOWS = f"uvicorn --limit-max-requests {config.gunicorn_max_requests} --timeout-keep-alive {config.timeout}".split()
command = (
[
*RUN_BACKEND_PROD_WINDOWS,
@@ -496,6 +496,24 @@ def is_prod_mode() -> bool:
return current_mode == constants.Env.PROD.value
+def is_frontend_only() -> bool:
+ """Check if the app is running in frontend-only mode.
+
+ Returns:
+ True if the app is running in frontend-only mode.
+ """
+ return os.environ.get(constants.ENV_FRONTEND_ONLY_ENV_VAR, "").lower() == "true"
+
+
+def is_backend_only() -> bool:
+ """Check if the app is running in backend-only mode.
+
+ Returns:
+ True if the app is running in backend-only mode.
+ """
+ return os.environ.get(constants.ENV_BACKEND_ONLY_ENV_VAR, "").lower() == "true"
+
+
def should_skip_compile() -> bool:
"""Whether the app should skip compile.
diff --git a/reflex/utils/net.py b/reflex/utils/net.py
index 83e25559c..2c6f22764 100644
--- a/reflex/utils/net.py
+++ b/reflex/utils/net.py
@@ -1,9 +1,8 @@
"""Helpers for downloading files from the network."""
-import os
-
import httpx
+from ..config import environment
from . import console
@@ -13,8 +12,7 @@ def _httpx_verify_kwarg() -> bool:
Returns:
True if SSL verification is enabled, False otherwise
"""
- ssl_no_verify = os.environ.get("SSL_NO_VERIFY", "").lower() in ["true", "1", "yes"]
- return not ssl_no_verify
+ return not environment.SSL_NO_VERIFY
def get(url: str, **kwargs) -> httpx.Response:
diff --git a/reflex/utils/path_ops.py b/reflex/utils/path_ops.py
index f597e0075..ee93b24cf 100644
--- a/reflex/utils/path_ops.py
+++ b/reflex/utils/path_ops.py
@@ -9,6 +9,7 @@ import shutil
from pathlib import Path
from reflex import constants
+from reflex.config import environment
# Shorthand for join.
join = os.linesep.join
@@ -129,30 +130,13 @@ def which(program: str | Path) -> str | Path | None:
return shutil.which(str(program))
-def use_system_install(var_name: str) -> bool:
- """Check if the system install should be used.
-
- Args:
- var_name: The name of the environment variable.
-
- Raises:
- ValueError: If the variable name is invalid.
-
- Returns:
- Whether the associated env var should use the system install.
- """
- if not var_name.startswith("REFLEX_USE_SYSTEM_"):
- raise ValueError("Invalid system install variable name.")
- return os.getenv(var_name, "").lower() in ["true", "1", "yes"]
-
-
def use_system_node() -> bool:
"""Check if the system node should be used.
Returns:
Whether the system node should be used.
"""
- return use_system_install(constants.Node.USE_SYSTEM_VAR)
+ return environment.REFLEX_USE_SYSTEM_NODE
def use_system_bun() -> bool:
@@ -161,7 +145,7 @@ def use_system_bun() -> bool:
Returns:
Whether the system bun should be used.
"""
- return use_system_install(constants.Bun.USE_SYSTEM_VAR)
+ return environment.REFLEX_USE_SYSTEM_BUN
def get_node_bin_path() -> Path | None:
@@ -185,7 +169,8 @@ def get_node_path() -> str | None:
"""
node_path = Path(constants.Node.PATH)
if use_system_node() or not node_path.exists():
- return str(which("node"))
+ system_node_path = which("node")
+ return str(system_node_path) if system_node_path else None
return str(node_path)
@@ -197,7 +182,8 @@ def get_npm_path() -> str | None:
"""
npm_path = Path(constants.Node.NPM_PATH)
if use_system_node() or not npm_path.exists():
- return str(which("npm"))
+ system_npm_path = which("npm")
+ return str(system_npm_path) if system_npm_path else None
return str(npm_path)
diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py
index 34ed5f53f..33165af0e 100644
--- a/reflex/utils/prerequisites.py
+++ b/reflex/utils/prerequisites.py
@@ -33,7 +33,7 @@ from redis.asyncio import Redis
from reflex import constants, model
from reflex.compiler import templates
-from reflex.config import Config, get_config
+from reflex.config import Config, environment, get_config
from reflex.utils import console, net, path_ops, processes
from reflex.utils.exceptions import GeneratedCodeHasNoFunctionDefs
from reflex.utils.format import format_library_name
@@ -69,8 +69,7 @@ def get_web_dir() -> Path:
Returns:
The working directory.
"""
- workdir = Path(os.getenv("REFLEX_WEB_WORKDIR", constants.Dirs.WEB))
- return workdir
+ return environment.REFLEX_WEB_WORKDIR
def _python_version_check():
@@ -146,14 +145,9 @@ def check_node_version() -> bool:
Whether the version of Node.js is valid.
"""
current_version = get_node_version()
- if current_version:
- # Compare the version numbers
- return (
- current_version >= version.parse(constants.Node.MIN_VERSION)
- if constants.IS_WINDOWS or path_ops.use_system_node()
- else current_version == version.parse(constants.Node.VERSION)
- )
- return False
+ return current_version is not None and current_version >= version.parse(
+ constants.Node.MIN_VERSION
+ )
def get_node_version() -> version.Version | None:
@@ -255,7 +249,7 @@ def windows_npm_escape_hatch() -> bool:
Returns:
If the user has set REFLEX_USE_NPM.
"""
- return os.environ.get("REFLEX_USE_NPM", "").lower() in ["true", "1", "yes"]
+ return environment.REFLEX_USE_NPM
def get_app(reload: bool = False) -> ModuleType:
@@ -997,7 +991,7 @@ def needs_reinit(frontend: bool = True) -> bool:
return False
# Make sure the .reflex directory exists.
- if not constants.Reflex.DIR.exists():
+ if not environment.REFLEX_DIR.exists():
return True
# Make sure the .web directory exists in frontend mode.
@@ -1102,7 +1096,7 @@ def ensure_reflex_installation_id() -> Optional[int]:
"""
try:
initialize_reflex_user_directory()
- installation_id_file = constants.Reflex.DIR / "installation_id"
+ installation_id_file = environment.REFLEX_DIR / "installation_id"
installation_id = None
if installation_id_file.exists():
@@ -1127,7 +1121,7 @@ def ensure_reflex_installation_id() -> Optional[int]:
def initialize_reflex_user_directory():
"""Initialize the reflex user directory."""
# Create the reflex directory.
- path_ops.mkdir(constants.Reflex.DIR)
+ path_ops.mkdir(environment.REFLEX_DIR)
def initialize_frontend_dependencies():
@@ -1150,7 +1144,7 @@ def check_db_initialized() -> bool:
Returns:
True if alembic is initialized (or if database is not used).
"""
- if get_config().db_url is not None and not Path(constants.ALEMBIC_CONFIG).exists():
+ if get_config().db_url is not None and not environment.ALEMBIC_CONFIG.exists():
console.error(
"Database is not initialized. Run [bold]reflex db init[/bold] first."
)
@@ -1160,7 +1154,7 @@ def check_db_initialized() -> bool:
def check_schema_up_to_date():
"""Check if the sqlmodel metadata matches the current database schema."""
- if get_config().db_url is None or not Path(constants.ALEMBIC_CONFIG).exists():
+ if get_config().db_url is None or not environment.ALEMBIC_CONFIG.exists():
return
with model.Model.get_db_engine().connect() as connection:
try:
diff --git a/reflex/utils/pyi_generator.py b/reflex/utils/pyi_generator.py
index 1df8e6fa0..1fc17341b 100644
--- a/reflex/utils/pyi_generator.py
+++ b/reflex/utils/pyi_generator.py
@@ -16,7 +16,7 @@ from itertools import chain
from multiprocessing import Pool, cpu_count
from pathlib import Path
from types import ModuleType, SimpleNamespace
-from typing import Any, Callable, Iterable, Type, get_args
+from typing import Any, Callable, Iterable, Type, get_args, get_origin
from reflex.components.component import Component
from reflex.utils import types as rx_types
@@ -214,7 +214,9 @@ def _get_type_hint(value, type_hint_globals, is_optional=True) -> str:
return res
-def _generate_imports(typing_imports: Iterable[str]) -> list[ast.ImportFrom]:
+def _generate_imports(
+ typing_imports: Iterable[str],
+) -> list[ast.ImportFrom | ast.Import]:
"""Generate the import statements for the stub file.
Args:
@@ -228,6 +230,7 @@ def _generate_imports(typing_imports: Iterable[str]) -> list[ast.ImportFrom]:
ast.ImportFrom(module=name, names=[ast.alias(name=val) for val in values])
for name, values in DEFAULT_IMPORTS.items()
],
+ ast.Import([ast.alias("reflex")]),
]
@@ -372,6 +375,64 @@ def _extract_class_props_as_ast_nodes(
return kwargs
+def type_to_ast(typ, cls: type) -> ast.AST:
+ """Converts any type annotation into its AST representation.
+ Handles nested generic types, unions, etc.
+
+ Args:
+ typ: The type annotation to convert.
+ cls: The class where the type annotation is used.
+
+ Returns:
+ The AST representation of the type annotation.
+ """
+ if typ is type(None):
+ return ast.Name(id="None")
+
+ origin = get_origin(typ)
+
+ # Handle plain types (int, str, custom classes, etc.)
+ if origin is None:
+ if hasattr(typ, "__name__"):
+ if typ.__module__.startswith("reflex."):
+ typ_parts = typ.__module__.split(".")
+ cls_parts = cls.__module__.split(".")
+
+ zipped = list(zip(typ_parts, cls_parts, strict=False))
+
+ if all(a == b for a, b in zipped) and len(typ_parts) == len(cls_parts):
+ return ast.Name(id=typ.__name__)
+
+ return ast.Name(id=typ.__module__ + "." + typ.__name__)
+ return ast.Name(id=typ.__name__)
+ elif hasattr(typ, "_name"):
+ return ast.Name(id=typ._name)
+ return ast.Name(id=str(typ))
+
+ # Get the base type name (List, Dict, Optional, etc.)
+ base_name = origin._name if hasattr(origin, "_name") else origin.__name__
+
+ # Get type arguments
+ args = get_args(typ)
+
+ # Handle empty type arguments
+ if not args:
+ return ast.Name(id=base_name)
+
+ # Convert all type arguments recursively
+ arg_nodes = [type_to_ast(arg, cls) for arg in args]
+
+ # Special case for single-argument types (like List[T] or Optional[T])
+ if len(arg_nodes) == 1:
+ slice_value = arg_nodes[0]
+ else:
+ slice_value = ast.Tuple(elts=arg_nodes, ctx=ast.Load())
+
+ return ast.Subscript(
+ value=ast.Name(id=base_name), slice=ast.Index(value=slice_value), ctx=ast.Load()
+ )
+
+
def _get_parent_imports(func):
_imports = {"reflex.vars": ["Var"]}
for type_hint in inspect.get_annotations(func).values():
@@ -429,14 +490,41 @@ def _generate_component_create_functiondef(
def figure_out_return_type(annotation: Any):
if inspect.isclass(annotation) and issubclass(annotation, inspect._empty):
- return ast.Name(id="Optional[EventType[[]]]")
+ return ast.Name(id="Optional[EventType]")
+
+ if not isinstance(annotation, str) and get_origin(annotation) is tuple:
+ arguments = get_args(annotation)
+
+ arguments_without_var = [
+ get_args(argument)[0] if get_origin(argument) == Var else argument
+ for argument in arguments
+ ]
+
+ # Convert each argument type to its AST representation
+ type_args = [type_to_ast(arg, cls=clz) for arg in arguments_without_var]
+
+ # Join the type arguments with commas for EventType
+ args_str = ", ".join(ast.unparse(arg) for arg in type_args)
+
+ # Create EventType using the joined string
+ event_type = ast.Name(id=f"EventType[{args_str}]")
+
+ # Wrap in Optional
+ optional_type = ast.Subscript(
+ value=ast.Name(id="Optional"),
+ slice=ast.Index(value=event_type),
+ ctx=ast.Load(),
+ )
+
+ return ast.Name(id=ast.unparse(optional_type))
+
if isinstance(annotation, str) and annotation.startswith("Tuple["):
inside_of_tuple = annotation.removeprefix("Tuple[").removesuffix("]")
if inside_of_tuple == "()":
return ast.Name(id="Optional[EventType[[]]]")
- arguments: list[str] = [""]
+ arguments = [""]
bracket_count = 0
diff --git a/reflex/utils/registry.py b/reflex/utils/registry.py
index 6b87c163d..77c3d31cd 100644
--- a/reflex/utils/registry.py
+++ b/reflex/utils/registry.py
@@ -1,9 +1,8 @@
"""Utilities for working with registries."""
-import os
-
import httpx
+from reflex.config import environment
from reflex.utils import console, net
@@ -56,7 +55,4 @@ def _get_npm_registry() -> str:
Returns:
str:
"""
- if npm_registry := os.environ.get("NPM_CONFIG_REGISTRY", ""):
- return npm_registry
- else:
- return get_best_registry()
+ return environment.NPM_CONFIG_REGISTRY or get_best_registry()
diff --git a/reflex/utils/types.py b/reflex/utils/types.py
index 0a3aed110..3d7992011 100644
--- a/reflex/utils/types.py
+++ b/reflex/utils/types.py
@@ -274,6 +274,20 @@ def is_optional(cls: GenericType) -> bool:
return is_union(cls) and type(None) in get_args(cls)
+def value_inside_optional(cls: GenericType) -> GenericType:
+ """Get the value inside an Optional type or the original type.
+
+ Args:
+ cls: The class to check.
+
+ Returns:
+ The value inside the Optional type or the original type.
+ """
+ if is_union(cls) and len(args := get_args(cls)) >= 2 and type(None) in args:
+ return unionize(*[arg for arg in args if arg is not type(None)])
+ return cls
+
+
def get_property_hint(attr: Any | None) -> GenericType | None:
"""Check if an attribute is a property and return its type hint.
diff --git a/reflex/vars/base.py b/reflex/vars/base.py
index 14e7251bb..6df8eec6f 100644
--- a/reflex/vars/base.py
+++ b/reflex/vars/base.py
@@ -19,6 +19,7 @@ from typing import (
TYPE_CHECKING,
Any,
Callable,
+ ClassVar,
Dict,
FrozenSet,
Generic,
@@ -37,7 +38,13 @@ from typing import (
overload,
)
-from typing_extensions import ParamSpec, TypeGuard, deprecated, get_type_hints, override
+from typing_extensions import (
+ ParamSpec,
+ TypeGuard,
+ deprecated,
+ get_type_hints,
+ override,
+)
from reflex import constants
from reflex.base import Base
@@ -61,15 +68,13 @@ from reflex.utils.types import GenericType, Self, get_origin, has_args, unionize
if TYPE_CHECKING:
from reflex.state import BaseState
- from .function import FunctionVar, ToFunctionOperation
+ from .function import FunctionVar
from .number import (
BooleanVar,
NumberVar,
- ToBooleanVarOperation,
- ToNumberVarOperation,
)
- from .object import ObjectVar, ToObjectOperation
- from .sequence import ArrayVar, StringVar, ToArrayOperation, ToStringOperation
+ from .object import ObjectVar
+ from .sequence import ArrayVar, StringVar
VAR_TYPE = TypeVar("VAR_TYPE", covariant=True)
@@ -78,6 +83,184 @@ OTHER_VAR_TYPE = TypeVar("OTHER_VAR_TYPE")
warnings.filterwarnings("ignore", message="fields may not start with an underscore")
+@dataclasses.dataclass(
+ eq=False,
+ frozen=True,
+)
+class VarSubclassEntry:
+ """Entry for a Var subclass."""
+
+ var_subclass: Type[Var]
+ to_var_subclass: Type[ToOperation]
+ python_types: Tuple[GenericType, ...]
+
+
+_var_subclasses: List[VarSubclassEntry] = []
+_var_literal_subclasses: List[Tuple[Type[LiteralVar], VarSubclassEntry]] = []
+
+
+@dataclasses.dataclass(
+ eq=True,
+ frozen=True,
+)
+class VarData:
+ """Metadata associated with a x."""
+
+ # The name of the enclosing state.
+ state: str = dataclasses.field(default="")
+
+ # The name of the field in the state.
+ field_name: str = dataclasses.field(default="")
+
+ # Imports needed to render this var
+ imports: ImmutableParsedImportDict = dataclasses.field(default_factory=tuple)
+
+ # Hooks that need to be present in the component to render this var
+ hooks: Tuple[str, ...] = dataclasses.field(default_factory=tuple)
+
+ def __init__(
+ self,
+ state: str = "",
+ field_name: str = "",
+ imports: ImportDict | ParsedImportDict | None = None,
+ hooks: dict[str, None] | None = None,
+ ):
+ """Initialize the var data.
+
+ Args:
+ state: The name of the enclosing state.
+ field_name: The name of the field in the state.
+ imports: Imports needed to render this var.
+ hooks: Hooks that need to be present in the component to render this var.
+ """
+ immutable_imports: ImmutableParsedImportDict = tuple(
+ sorted(
+ ((k, tuple(sorted(v))) for k, v in parse_imports(imports or {}).items())
+ )
+ )
+ object.__setattr__(self, "state", state)
+ object.__setattr__(self, "field_name", field_name)
+ object.__setattr__(self, "imports", immutable_imports)
+ object.__setattr__(self, "hooks", tuple(hooks or {}))
+
+ def old_school_imports(self) -> ImportDict:
+ """Return the imports as a mutable dict.
+
+ Returns:
+ The imports as a mutable dict.
+ """
+ return dict((k, list(v)) for k, v in self.imports)
+
+ @classmethod
+ def merge(cls, *others: VarData | None) -> VarData | None:
+ """Merge multiple var data objects.
+
+ Args:
+ *others: The var data objects to merge.
+
+ Returns:
+ The merged var data object.
+ """
+ state = ""
+ field_name = ""
+ _imports = {}
+ hooks = {}
+ for var_data in others:
+ if var_data is None:
+ continue
+ state = state or var_data.state
+ field_name = field_name or var_data.field_name
+ _imports = imports.merge_imports(_imports, var_data.imports)
+ hooks.update(
+ var_data.hooks
+ if isinstance(var_data.hooks, dict)
+ else {k: None for k in var_data.hooks}
+ )
+
+ if state or _imports or hooks or field_name:
+ return VarData(
+ state=state,
+ field_name=field_name,
+ imports=_imports,
+ hooks=hooks,
+ )
+ return None
+
+ def __bool__(self) -> bool:
+ """Check if the var data is non-empty.
+
+ Returns:
+ True if any field is set to a non-default value.
+ """
+ return bool(self.state or self.imports or self.hooks or self.field_name)
+
+ @classmethod
+ def from_state(cls, state: Type[BaseState] | str, field_name: str = "") -> VarData:
+ """Set the state of the var.
+
+ Args:
+ state: The state to set or the full name of the state.
+ field_name: The name of the field in the state. Optional.
+
+ Returns:
+ The var with the set state.
+ """
+ from reflex.utils import format
+
+ state_name = state if isinstance(state, str) else state.get_full_name()
+ return VarData(
+ state=state_name,
+ field_name=field_name,
+ hooks={
+ "const {0} = useContext(StateContexts.{0})".format(
+ format.format_state_name(state_name)
+ ): None
+ },
+ imports={
+ f"/{constants.Dirs.CONTEXTS_PATH}": [ImportVar(tag="StateContexts")],
+ "react": [ImportVar(tag="useContext")],
+ },
+ )
+
+
+def _decode_var_immutable(value: str) -> tuple[VarData | None, str]:
+ """Decode the state name from a formatted var.
+
+ Args:
+ value: The value to extract the state name from.
+
+ Returns:
+ The extracted state name and the value without the state name.
+ """
+ var_datas = []
+ if isinstance(value, str):
+ # fast path if there is no encoded VarData
+ if constants.REFLEX_VAR_OPENING_TAG not in value:
+ return None, value
+
+ offset = 0
+
+ # Find all tags.
+ while m := _decode_var_pattern.search(value):
+ start, end = m.span()
+ value = value[:start] + value[end:]
+
+ serialized_data = m.group(1)
+
+ if serialized_data.isnumeric() or (
+ serialized_data[0] == "-" and serialized_data[1:].isnumeric()
+ ):
+ # This is a global immutable var.
+ var = _global_vars[int(serialized_data)]
+ var_data = var._get_all_var_data()
+
+ if var_data is not None:
+ var_datas.append(var_data)
+ offset += end - start
+
+ return VarData.merge(*var_datas) if var_datas else None, value
+
+
@dataclasses.dataclass(
eq=False,
frozen=True,
@@ -151,6 +334,40 @@ class Var(Generic[VAR_TYPE]):
"""
return False
+ def __init_subclass__(
+ cls, python_types: Tuple[GenericType, ...] | GenericType = types.Unset, **kwargs
+ ):
+ """Initialize the subclass.
+
+ Args:
+ python_types: The python types that the var represents.
+ **kwargs: Additional keyword arguments.
+ """
+ super().__init_subclass__(**kwargs)
+
+ if python_types is not types.Unset:
+ python_types = (
+ python_types if isinstance(python_types, tuple) else (python_types,)
+ )
+
+ @dataclasses.dataclass(
+ eq=False,
+ frozen=True,
+ **{"slots": True} if sys.version_info >= (3, 10) else {},
+ )
+ class ToVarOperation(ToOperation, cls):
+ """Base class of converting a var to another var type."""
+
+ _original: Var = dataclasses.field(
+ default=Var(_js_expr="null", _var_type=None),
+ )
+
+ _default_var_type: ClassVar[GenericType] = python_types[0]
+
+ ToVarOperation.__name__ = f'To{cls.__name__.removesuffix("Var")}Operation'
+
+ _var_subclasses.append(VarSubclassEntry(cls, ToVarOperation, python_types))
+
def __post_init__(self):
"""Post-initialize the var."""
# Decode any inline Var markup and apply it to the instance
@@ -331,35 +548,35 @@ class Var(Generic[VAR_TYPE]):
return f"{constants.REFLEX_VAR_OPENING_TAG}{hashed_var}{constants.REFLEX_VAR_CLOSING_TAG}{self._js_expr}"
@overload
- def to(self, output: Type[StringVar]) -> ToStringOperation: ...
+ def to(self, output: Type[StringVar]) -> StringVar: ...
@overload
- def to(self, output: Type[str]) -> ToStringOperation: ...
+ def to(self, output: Type[str]) -> StringVar: ...
@overload
- def to(self, output: Type[BooleanVar]) -> ToBooleanVarOperation: ...
+ def to(self, output: Type[BooleanVar]) -> BooleanVar: ...
@overload
def to(
self, output: Type[NumberVar], var_type: type[int] | type[float] = float
- ) -> ToNumberVarOperation: ...
+ ) -> NumberVar: ...
@overload
def to(
self,
output: Type[ArrayVar],
var_type: type[list] | type[tuple] | type[set] = list,
- ) -> ToArrayOperation: ...
+ ) -> ArrayVar: ...
@overload
def to(
self, output: Type[ObjectVar], var_type: types.GenericType = dict
- ) -> ToObjectOperation: ...
+ ) -> ObjectVar: ...
@overload
def to(
self, output: Type[FunctionVar], var_type: Type[Callable] = Callable
- ) -> ToFunctionOperation: ...
+ ) -> FunctionVar: ...
@overload
def to(
@@ -379,56 +596,26 @@ class Var(Generic[VAR_TYPE]):
output: The output type.
var_type: The type of the var.
- Raises:
- TypeError: If the var_type is not a supported type for the output.
-
Returns:
The converted var.
"""
- from reflex.event import (
- EventChain,
- EventChainVar,
- EventSpec,
- EventVar,
- ToEventChainVarOperation,
- ToEventVarOperation,
- )
-
- from .function import FunctionVar, ToFunctionOperation
- from .number import (
- BooleanVar,
- NumberVar,
- ToBooleanVarOperation,
- ToNumberVarOperation,
- )
- from .object import ObjectVar, ToObjectOperation
- from .sequence import ArrayVar, StringVar, ToArrayOperation, ToStringOperation
+ from .object import ObjectVar
base_type = var_type
if types.is_optional(base_type):
base_type = types.get_args(base_type)[0]
- fixed_type = get_origin(base_type) or base_type
-
fixed_output_type = get_origin(output) or output
# If the first argument is a python type, we map it to the corresponding Var type.
- if fixed_output_type is dict:
- return self.to(ObjectVar, output)
- if fixed_output_type in (list, tuple, set):
- return self.to(ArrayVar, output)
- if fixed_output_type in (int, float):
- return self.to(NumberVar, output)
- if fixed_output_type is str:
- return self.to(StringVar, output)
- if fixed_output_type is bool:
- return self.to(BooleanVar, output)
+ for var_subclass in _var_subclasses[::-1]:
+ if fixed_output_type in var_subclass.python_types:
+ return self.to(var_subclass.var_subclass, output)
+
if fixed_output_type is None:
- return ToNoneOperation.create(self)
- if fixed_output_type is EventSpec:
- return self.to(EventVar, output)
- if fixed_output_type is EventChain:
- return self.to(EventChainVar, output)
+ return get_to_operation(NoneVar).create(self) # type: ignore
+
+ # Handle fixed_output_type being Base or a dataclass.
try:
if issubclass(fixed_output_type, Base):
return self.to(ObjectVar, output)
@@ -440,57 +627,12 @@ class Var(Generic[VAR_TYPE]):
return self.to(ObjectVar, output)
if inspect.isclass(output):
- if issubclass(output, BooleanVar):
- return ToBooleanVarOperation.create(self)
-
- if issubclass(output, NumberVar):
- if fixed_type is not None:
- if fixed_type in types.UnionTypes:
- inner_types = get_args(base_type)
- if not all(issubclass(t, (int, float)) for t in inner_types):
- raise TypeError(
- f"Unsupported type {var_type} for NumberVar. Must be int or float."
- )
-
- elif not issubclass(fixed_type, (int, float)):
- raise TypeError(
- f"Unsupported type {var_type} for NumberVar. Must be int or float."
- )
- return ToNumberVarOperation.create(self, var_type or float)
-
- if issubclass(output, ArrayVar):
- if fixed_type is not None and not issubclass(
- fixed_type, (list, tuple, set)
- ):
- raise TypeError(
- f"Unsupported type {var_type} for ArrayVar. Must be list, tuple, or set."
+ for var_subclass in _var_subclasses[::-1]:
+ if issubclass(output, var_subclass.var_subclass):
+ to_operation_return = var_subclass.to_var_subclass.create(
+ value=self, _var_type=var_type
)
- return ToArrayOperation.create(self, var_type or list)
-
- if issubclass(output, StringVar):
- return ToStringOperation.create(self, var_type or str)
-
- if issubclass(output, EventVar):
- return ToEventVarOperation.create(self, var_type or EventSpec)
-
- if issubclass(output, EventChainVar):
- return ToEventChainVarOperation.create(self, var_type or EventChain)
-
- if issubclass(output, (ObjectVar, Base)):
- return ToObjectOperation.create(self, var_type or dict)
-
- if issubclass(output, FunctionVar):
- # if fixed_type is not None and not issubclass(fixed_type, Callable):
- # raise TypeError(
- # f"Unsupported type {var_type} for FunctionVar. Must be Callable."
- # )
- return ToFunctionOperation.create(self, var_type or Callable)
-
- if issubclass(output, NoneVar):
- return ToNoneOperation.create(self)
-
- if dataclasses.is_dataclass(output):
- return ToObjectOperation.create(self, var_type or dict)
+ return to_operation_return # type: ignore
# If we can't determine the first argument, we just replace the _var_type.
if not issubclass(output, Var) or var_type is None:
@@ -508,6 +650,18 @@ class Var(Generic[VAR_TYPE]):
return self
+ @overload
+ def guess_type(self: Var[str]) -> StringVar: ...
+
+ @overload
+ def guess_type(self: Var[bool]) -> BooleanVar: ...
+
+ @overload
+ def guess_type(self: Var[int] | Var[float] | Var[int | float]) -> NumberVar: ...
+
+ @overload
+ def guess_type(self) -> Self: ...
+
def guess_type(self) -> Var:
"""Guesses the type of the variable based on its `_var_type` attribute.
@@ -517,11 +671,8 @@ class Var(Generic[VAR_TYPE]):
Raises:
TypeError: If the type is not supported for guessing.
"""
- from reflex.event import EventChain, EventChainVar, EventSpec, EventVar
-
- from .number import BooleanVar, NumberVar
+ from .number import NumberVar
from .object import ObjectVar
- from .sequence import ArrayVar, StringVar
var_type = self._var_type
if var_type is None:
@@ -558,20 +709,13 @@ class Var(Generic[VAR_TYPE]):
if not inspect.isclass(fixed_type):
raise TypeError(f"Unsupported type {var_type} for guess_type.")
- if issubclass(fixed_type, bool):
- return self.to(BooleanVar, self._var_type)
- if issubclass(fixed_type, (int, float)):
- return self.to(NumberVar, self._var_type)
- if issubclass(fixed_type, dict):
- return self.to(ObjectVar, self._var_type)
- if issubclass(fixed_type, (list, tuple, set)):
- return self.to(ArrayVar, self._var_type)
- if issubclass(fixed_type, str):
- return self.to(StringVar, self._var_type)
- if issubclass(fixed_type, EventSpec):
- return self.to(EventVar, self._var_type)
- if issubclass(fixed_type, EventChain):
- return self.to(EventChainVar, self._var_type)
+ if fixed_type is None:
+ return self.to(None)
+
+ for var_subclass in _var_subclasses[::-1]:
+ if issubclass(fixed_type, var_subclass.python_types):
+ return self.to(var_subclass.var_subclass, self._var_type)
+
try:
if issubclass(fixed_type, Base):
return self.to(ObjectVar, self._var_type)
@@ -782,16 +926,23 @@ class Var(Generic[VAR_TYPE]):
"""
return ~self.bool()
- def to_string(self):
+ def to_string(self, use_json: bool = True) -> StringVar:
"""Convert the var to a string.
+ Args:
+ use_json: Whether to use JSON stringify. If False, uses Object.prototype.toString.
+
Returns:
The string var.
"""
- from .function import JSON_STRINGIFY
+ from .function import JSON_STRINGIFY, PROTOTYPE_TO_STRING
from .sequence import StringVar
- return JSON_STRINGIFY.call(self).to(StringVar)
+ return (
+ JSON_STRINGIFY.call(self).to(StringVar)
+ if use_json
+ else PROTOTYPE_TO_STRING.call(self).to(StringVar)
+ )
def as_ref(self) -> Var:
"""Get a reference to the var.
@@ -1017,9 +1168,129 @@ class Var(Generic[VAR_TYPE]):
OUTPUT = TypeVar("OUTPUT", bound=Var)
+class ToOperation:
+ """A var operation that converts a var to another type."""
+
+ def __getattr__(self, name: str) -> Any:
+ """Get an attribute of the var.
+
+ Args:
+ name: The name of the attribute.
+
+ Returns:
+ The attribute of the var.
+ """
+ from .object import ObjectVar
+
+ if isinstance(self, ObjectVar) and name != "_js_expr":
+ return ObjectVar.__getattr__(self, name)
+ return getattr(self._original, name)
+
+ def __post_init__(self):
+ """Post initialization."""
+ object.__delattr__(self, "_js_expr")
+
+ def __hash__(self) -> int:
+ """Calculate the hash value of the object.
+
+ Returns:
+ int: The hash value of the object.
+ """
+ return hash(self._original)
+
+ def _get_all_var_data(self) -> VarData | None:
+ """Get all the var data.
+
+ Returns:
+ The var data.
+ """
+ return VarData.merge(
+ self._original._get_all_var_data(),
+ self._var_data, # type: ignore
+ )
+
+ @classmethod
+ def create(
+ cls,
+ value: Var,
+ _var_type: GenericType | None = None,
+ _var_data: VarData | None = None,
+ ):
+ """Create a ToOperation.
+
+ Args:
+ value: The value of the var.
+ _var_type: The type of the Var.
+ _var_data: Additional hooks and imports associated with the Var.
+
+ Returns:
+ The ToOperation.
+ """
+ return cls(
+ _js_expr="", # type: ignore
+ _var_data=_var_data, # type: ignore
+ _var_type=_var_type or cls._default_var_type, # type: ignore
+ _original=value, # type: ignore
+ )
+
+
class LiteralVar(Var):
"""Base class for immutable literal vars."""
+ def __init_subclass__(cls, **kwargs):
+ """Initialize the subclass.
+
+ Args:
+ **kwargs: Additional keyword arguments.
+
+ Raises:
+ TypeError: If the LiteralVar subclass does not have a corresponding Var subclass.
+ """
+ super().__init_subclass__(**kwargs)
+
+ bases = cls.__bases__
+
+ bases_normalized = [
+ base if inspect.isclass(base) else get_origin(base) for base in bases
+ ]
+
+ possible_bases = [
+ base
+ for base in bases_normalized
+ if issubclass(base, Var) and base != LiteralVar
+ ]
+
+ if not possible_bases:
+ raise TypeError(
+ f"LiteralVar subclass {cls} must have a base class that is a subclass of Var and not LiteralVar."
+ )
+
+ var_subclasses = [
+ var_subclass
+ for var_subclass in _var_subclasses
+ if var_subclass.var_subclass in possible_bases
+ ]
+
+ if not var_subclasses:
+ raise TypeError(
+ f"LiteralVar {cls} must have a base class annotated with `python_types`."
+ )
+
+ if len(var_subclasses) != 1:
+ raise TypeError(
+ f"LiteralVar {cls} must have exactly one base class annotated with `python_types`."
+ )
+
+ var_subclass = var_subclasses[0]
+
+ # Remove the old subclass, happens because __init_subclass__ is called twice
+ # for each subclass. This is because of __slots__ in dataclasses.
+ for var_literal_subclass in list(_var_literal_subclasses):
+ if var_literal_subclass[1] is var_subclass:
+ _var_literal_subclasses.remove(var_literal_subclass)
+
+ _var_literal_subclasses.append((cls, var_subclass))
+
@classmethod
def create(
cls,
@@ -1038,50 +1309,21 @@ class LiteralVar(Var):
Raises:
TypeError: If the value is not a supported type for LiteralVar.
"""
- from .number import LiteralBooleanVar, LiteralNumberVar
from .object import LiteralObjectVar
- from .sequence import LiteralArrayVar, LiteralStringVar
+ from .sequence import LiteralStringVar
if isinstance(value, Var):
if _var_data is None:
return value
return value._replace(merge_var_data=_var_data)
- if isinstance(value, str):
- return LiteralStringVar.create(value, _var_data=_var_data)
+ for literal_subclass, var_subclass in _var_literal_subclasses[::-1]:
+ if isinstance(value, var_subclass.python_types):
+ return literal_subclass.create(value, _var_data=_var_data)
- if isinstance(value, bool):
- return LiteralBooleanVar.create(value, _var_data=_var_data)
-
- if isinstance(value, (int, float)):
- return LiteralNumberVar.create(value, _var_data=_var_data)
-
- if isinstance(value, dict):
- return LiteralObjectVar.create(value, _var_data=_var_data)
-
- if isinstance(value, (list, tuple, set)):
- return LiteralArrayVar.create(value, _var_data=_var_data)
-
- if value is None:
- return LiteralNoneVar.create(_var_data=_var_data)
-
- from reflex.event import (
- EventChain,
- EventHandler,
- EventSpec,
- LiteralEventChainVar,
- LiteralEventVar,
- )
+ from reflex.event import EventHandler
from reflex.utils.format import get_event_handler_parts
- from .object import LiteralObjectVar
-
- if isinstance(value, EventSpec):
- return LiteralEventVar.create(value, _var_data=_var_data)
-
- if isinstance(value, EventChain):
- return LiteralEventChainVar.create(value, _var_data=_var_data)
-
if isinstance(value, EventHandler):
return Var(_js_expr=".".join(filter(None, get_event_handler_parts(value))))
@@ -1155,6 +1397,22 @@ def serialize_literal(value: LiteralVar):
return value._var_value
+def get_python_literal(value: Union[LiteralVar, Any]) -> Any | None:
+ """Get the Python literal value.
+
+ Args:
+ value: The value to get the Python literal value of.
+
+ Returns:
+ The Python literal value.
+ """
+ if isinstance(value, LiteralVar):
+ return value._var_value
+ if isinstance(value, Var):
+ return None
+ return value
+
+
P = ParamSpec("P")
T = TypeVar("T")
@@ -1205,6 +1463,12 @@ def var_operation(
) -> Callable[P, ObjectVar[OBJECT_TYPE]]: ...
+@overload
+def var_operation(
+ func: Callable[P, CustomVarOperationReturn[T]],
+) -> Callable[P, Var[T]]: ...
+
+
def var_operation(
func: Callable[P, CustomVarOperationReturn[T]],
) -> Callable[P, Var[T]]:
@@ -1237,6 +1501,7 @@ def var_operation(
}
return CustomVarOperation.create(
+ name=func.__name__,
args=tuple(list(args_vars.items()) + list(kwargs_vars.items())),
return_var=func(*args_vars.values(), **kwargs_vars), # type: ignore
).guess_type()
@@ -1557,8 +1822,8 @@ class ComputedVar(Var[RETURN_TYPE]):
"return", Any
)
- kwargs["_js_expr"] = kwargs.pop("_js_expr", fget.__name__)
- kwargs["_var_type"] = kwargs.pop("_var_type", hint)
+ kwargs.setdefault("_js_expr", fget.__name__)
+ kwargs.setdefault("_var_type", hint)
Var.__init__(
self,
@@ -1567,6 +1832,9 @@ class ComputedVar(Var[RETURN_TYPE]):
_var_data=kwargs.pop("_var_data", None),
)
+ if kwargs:
+ raise TypeError(f"Unexpected keyword arguments: {tuple(kwargs)}")
+
if backend is None:
backend = fget.__name__.startswith("_")
@@ -2059,6 +2327,8 @@ def var_operation_return(
class CustomVarOperation(CachedVarOperation, Var[T]):
"""Base class for custom var operations."""
+ _name: str = dataclasses.field(default="")
+
_args: Tuple[Tuple[str, Var], ...] = dataclasses.field(default_factory=tuple)
_return: CustomVarOperationReturn[T] = dataclasses.field(
@@ -2093,6 +2363,7 @@ class CustomVarOperation(CachedVarOperation, Var[T]):
@classmethod
def create(
cls,
+ name: str,
args: Tuple[Tuple[str, Var], ...],
return_var: CustomVarOperationReturn[T],
_var_data: VarData | None = None,
@@ -2100,6 +2371,7 @@ class CustomVarOperation(CachedVarOperation, Var[T]):
"""Create a CustomVarOperation.
Args:
+ name: The name of the operation.
args: The arguments to the operation.
return_var: The return var.
_var_data: Additional hooks and imports associated with the Var.
@@ -2111,12 +2383,13 @@ class CustomVarOperation(CachedVarOperation, Var[T]):
_js_expr="",
_var_type=return_var._var_type,
_var_data=_var_data,
+ _name=name,
_args=args,
_return=return_var,
)
-class NoneVar(Var[None]):
+class NoneVar(Var[None], python_types=type(None)):
"""A var representing None."""
@@ -2141,11 +2414,13 @@ class LiteralNoneVar(LiteralVar, NoneVar):
@classmethod
def create(
cls,
+ value: None = None,
_var_data: VarData | None = None,
) -> LiteralNoneVar:
"""Create a var from a value.
Args:
+ value: The value of the var. Must be None. Existed for compatibility with LiteralVar.
_var_data: Additional hooks and imports associated with the Var.
Returns:
@@ -2158,48 +2433,26 @@ class LiteralNoneVar(LiteralVar, NoneVar):
)
-@dataclasses.dataclass(
- eq=False,
- frozen=True,
- **{"slots": True} if sys.version_info >= (3, 10) else {},
-)
-class ToNoneOperation(CachedVarOperation, NoneVar):
- """A var operation that converts a var to None."""
+def get_to_operation(var_subclass: Type[Var]) -> Type[ToOperation]:
+ """Get the ToOperation class for a given Var subclass.
- _original_var: Var = dataclasses.field(
- default_factory=lambda: LiteralNoneVar.create()
- )
+ Args:
+ var_subclass: The Var subclass.
- @cached_property_no_lock
- def _cached_var_name(self) -> str:
- """Get the cached var name.
+ Returns:
+ The ToOperation class.
- Returns:
- The cached var name.
- """
- return str(self._original_var)
-
- @classmethod
- def create(
- cls,
- var: Var,
- _var_data: VarData | None = None,
- ) -> ToNoneOperation:
- """Create a ToNoneOperation.
-
- Args:
- var: The var to convert to None.
- _var_data: Additional hooks and imports associated with the Var.
-
- Returns:
- The ToNoneOperation.
- """
- return ToNoneOperation(
- _js_expr="",
- _var_type=None,
- _var_data=_var_data,
- _original_var=var,
- )
+ Raises:
+ ValueError: If the ToOperation class cannot be found.
+ """
+ possible_classes = [
+ saved_var_subclass.to_var_subclass
+ for saved_var_subclass in _var_subclasses
+ if saved_var_subclass.var_subclass is var_subclass
+ ]
+ if not possible_classes:
+ raise ValueError(f"Could not find ToOperation for {var_subclass}.")
+ return possible_classes[0]
@dataclasses.dataclass(
@@ -2262,68 +2515,6 @@ class StateOperation(CachedVarOperation, Var):
)
-class ToOperation:
- """A var operation that converts a var to another type."""
-
- def __getattr__(self, name: str) -> Any:
- """Get an attribute of the var.
-
- Args:
- name: The name of the attribute.
-
- Returns:
- The attribute of the var.
- """
- return getattr(object.__getattribute__(self, "_original"), name)
-
- def __post_init__(self):
- """Post initialization."""
- object.__delattr__(self, "_js_expr")
-
- def __hash__(self) -> int:
- """Calculate the hash value of the object.
-
- Returns:
- int: The hash value of the object.
- """
- return hash(object.__getattribute__(self, "_original"))
-
- def _get_all_var_data(self) -> VarData | None:
- """Get all the var data.
-
- Returns:
- The var data.
- """
- return VarData.merge(
- object.__getattribute__(self, "_original")._get_all_var_data(),
- self._var_data, # type: ignore
- )
-
- @classmethod
- def create(
- cls,
- value: Var,
- _var_type: GenericType | None = None,
- _var_data: VarData | None = None,
- ):
- """Create a ToOperation.
-
- Args:
- value: The value of the var.
- _var_type: The type of the Var.
- _var_data: Additional hooks and imports associated with the Var.
-
- Returns:
- The ToOperation.
- """
- return cls(
- _js_expr="", # type: ignore
- _var_data=_var_data, # type: ignore
- _var_type=_var_type or cls._default_var_type, # type: ignore
- _original=value, # type: ignore
- )
-
-
def get_uuid_string_var() -> Var:
"""Return a Var that generates a single memoized UUID via .web/utils/state.js.
@@ -2369,168 +2560,6 @@ def get_unique_variable_name() -> str:
return get_unique_variable_name()
-@dataclasses.dataclass(
- eq=True,
- frozen=True,
-)
-class VarData:
- """Metadata associated with a x."""
-
- # The name of the enclosing state.
- state: str = dataclasses.field(default="")
-
- # The name of the field in the state.
- field_name: str = dataclasses.field(default="")
-
- # Imports needed to render this var
- imports: ImmutableParsedImportDict = dataclasses.field(default_factory=tuple)
-
- # Hooks that need to be present in the component to render this var
- hooks: Tuple[str, ...] = dataclasses.field(default_factory=tuple)
-
- def __init__(
- self,
- state: str = "",
- field_name: str = "",
- imports: ImportDict | ParsedImportDict | None = None,
- hooks: dict[str, None] | None = None,
- ):
- """Initialize the var data.
-
- Args:
- state: The name of the enclosing state.
- field_name: The name of the field in the state.
- imports: Imports needed to render this var.
- hooks: Hooks that need to be present in the component to render this var.
- """
- immutable_imports: ImmutableParsedImportDict = tuple(
- sorted(
- ((k, tuple(sorted(v))) for k, v in parse_imports(imports or {}).items())
- )
- )
- object.__setattr__(self, "state", state)
- object.__setattr__(self, "field_name", field_name)
- object.__setattr__(self, "imports", immutable_imports)
- object.__setattr__(self, "hooks", tuple(hooks or {}))
-
- def old_school_imports(self) -> ImportDict:
- """Return the imports as a mutable dict.
-
- Returns:
- The imports as a mutable dict.
- """
- return dict((k, list(v)) for k, v in self.imports)
-
- @classmethod
- def merge(cls, *others: VarData | None) -> VarData | None:
- """Merge multiple var data objects.
-
- Args:
- *others: The var data objects to merge.
-
- Returns:
- The merged var data object.
- """
- state = ""
- field_name = ""
- _imports = {}
- hooks = {}
- for var_data in others:
- if var_data is None:
- continue
- state = state or var_data.state
- field_name = field_name or var_data.field_name
- _imports = imports.merge_imports(_imports, var_data.imports)
- hooks.update(
- var_data.hooks
- if isinstance(var_data.hooks, dict)
- else {k: None for k in var_data.hooks}
- )
-
- if state or _imports or hooks or field_name:
- return VarData(
- state=state,
- field_name=field_name,
- imports=_imports,
- hooks=hooks,
- )
- return None
-
- def __bool__(self) -> bool:
- """Check if the var data is non-empty.
-
- Returns:
- True if any field is set to a non-default value.
- """
- return bool(self.state or self.imports or self.hooks or self.field_name)
-
- @classmethod
- def from_state(cls, state: Type[BaseState] | str, field_name: str = "") -> VarData:
- """Set the state of the var.
-
- Args:
- state: The state to set or the full name of the state.
- field_name: The name of the field in the state. Optional.
-
- Returns:
- The var with the set state.
- """
- from reflex.utils import format
-
- state_name = state if isinstance(state, str) else state.get_full_name()
- return VarData(
- state=state_name,
- field_name=field_name,
- hooks={
- "const {0} = useContext(StateContexts.{0})".format(
- format.format_state_name(state_name)
- ): None
- },
- imports={
- f"/{constants.Dirs.CONTEXTS_PATH}": [ImportVar(tag="StateContexts")],
- "react": [ImportVar(tag="useContext")],
- },
- )
-
-
-def _decode_var_immutable(value: str) -> tuple[VarData | None, str]:
- """Decode the state name from a formatted var.
-
- Args:
- value: The value to extract the state name from.
-
- Returns:
- The extracted state name and the value without the state name.
- """
- var_datas = []
- if isinstance(value, str):
- # fast path if there is no encoded VarData
- if constants.REFLEX_VAR_OPENING_TAG not in value:
- return None, value
-
- offset = 0
-
- # Find all tags.
- while m := _decode_var_pattern.search(value):
- start, end = m.span()
- value = value[:start] + value[end:]
-
- serialized_data = m.group(1)
-
- if serialized_data.isnumeric() or (
- serialized_data[0] == "-" and serialized_data[1:].isnumeric()
- ):
- # This is a global immutable var.
- var = _global_vars[int(serialized_data)]
- var_data = var._get_all_var_data()
-
- if var_data is not None:
- var_datas.append(var_data)
- offset += end - start
-
- return VarData.merge(*var_datas) if var_datas else None, value
-
-
# Compile regex for finding reflex var tags.
_decode_var_pattern_re = (
rf"{constants.REFLEX_VAR_OPENING_TAG}(.*?){constants.REFLEX_VAR_CLOSING_TAG}"
diff --git a/reflex/vars/function.py b/reflex/vars/function.py
index a512432b9..9d734a458 100644
--- a/reflex/vars/function.py
+++ b/reflex/vars/function.py
@@ -4,21 +4,20 @@ from __future__ import annotations
import dataclasses
import sys
-from typing import Any, Callable, ClassVar, Optional, Tuple, Type, Union
+from typing import Any, Callable, Optional, Tuple, Type, Union
from reflex.utils.types import GenericType
from .base import (
CachedVarOperation,
LiteralVar,
- ToOperation,
Var,
VarData,
cached_property_no_lock,
)
-class FunctionVar(Var[Callable]):
+class FunctionVar(Var[Callable], python_types=Callable):
"""Base class for immutable function vars."""
def __call__(self, *args: Var | Any) -> ArgsFunctionOperation:
@@ -180,17 +179,8 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar):
)
-@dataclasses.dataclass(
- eq=False,
- frozen=True,
- **{"slots": True} if sys.version_info >= (3, 10) else {},
-)
-class ToFunctionOperation(ToOperation, FunctionVar):
- """Base class of converting a var to a function."""
-
- _original: Var = dataclasses.field(default_factory=lambda: LiteralVar.create(None))
-
- _default_var_type: ClassVar[GenericType] = Callable
-
-
JSON_STRINGIFY = FunctionStringVar.create("JSON.stringify")
+ARRAY_ISARRAY = FunctionStringVar.create("Array.isArray")
+PROTOTYPE_TO_STRING = FunctionStringVar.create(
+ "((__to_string) => __to_string.toString())"
+)
diff --git a/reflex/vars/number.py b/reflex/vars/number.py
index 0aaa7a068..77c728d13 100644
--- a/reflex/vars/number.py
+++ b/reflex/vars/number.py
@@ -10,7 +10,6 @@ from typing import (
TYPE_CHECKING,
Any,
Callable,
- ClassVar,
NoReturn,
Type,
TypeVar,
@@ -25,9 +24,7 @@ from reflex.utils.types import is_optional
from .base import (
CustomVarOperationReturn,
- LiteralNoneVar,
LiteralVar,
- ToOperation,
Var,
VarData,
unionize,
@@ -58,7 +55,7 @@ def raise_unsupported_operand_types(
)
-class NumberVar(Var[NUMBER_T]):
+class NumberVar(Var[NUMBER_T], python_types=(int, float)):
"""Base class for immutable number vars."""
@overload
@@ -760,7 +757,7 @@ def number_trunc_operation(value: NumberVar):
return var_operation_return(js_expression=f"Math.trunc({value})", var_type=int)
-class BooleanVar(NumberVar[bool]):
+class BooleanVar(NumberVar[bool], python_types=bool):
"""Base class for immutable boolean vars."""
def __invert__(self):
@@ -984,51 +981,6 @@ def boolean_not_operation(value: BooleanVar):
return var_operation_return(js_expression=f"!({value})", var_type=bool)
-@dataclasses.dataclass(
- eq=False,
- frozen=True,
- **{"slots": True} if sys.version_info >= (3, 10) else {},
-)
-class LiteralBooleanVar(LiteralVar, BooleanVar):
- """Base class for immutable literal boolean vars."""
-
- _var_value: bool = dataclasses.field(default=False)
-
- def json(self) -> str:
- """Get the JSON representation of the var.
-
- Returns:
- The JSON representation of the var.
- """
- return "true" if self._var_value else "false"
-
- def __hash__(self) -> int:
- """Calculate the hash value of the object.
-
- Returns:
- int: The hash value of the object.
- """
- return hash((self.__class__.__name__, self._var_value))
-
- @classmethod
- def create(cls, value: bool, _var_data: VarData | None = None):
- """Create the boolean var.
-
- Args:
- value: The value of the var.
- _var_data: Additional hooks and imports associated with the Var.
-
- Returns:
- The boolean var.
- """
- return cls(
- _js_expr="true" if value else "false",
- _var_type=bool,
- _var_data=_var_data,
- _var_value=value,
- )
-
-
@dataclasses.dataclass(
eq=False,
frozen=True,
@@ -1088,36 +1040,55 @@ class LiteralNumberVar(LiteralVar, NumberVar):
)
+@dataclasses.dataclass(
+ eq=False,
+ frozen=True,
+ **{"slots": True} if sys.version_info >= (3, 10) else {},
+)
+class LiteralBooleanVar(LiteralVar, BooleanVar):
+ """Base class for immutable literal boolean vars."""
+
+ _var_value: bool = dataclasses.field(default=False)
+
+ def json(self) -> str:
+ """Get the JSON representation of the var.
+
+ Returns:
+ The JSON representation of the var.
+ """
+ return "true" if self._var_value else "false"
+
+ def __hash__(self) -> int:
+ """Calculate the hash value of the object.
+
+ Returns:
+ int: The hash value of the object.
+ """
+ return hash((self.__class__.__name__, self._var_value))
+
+ @classmethod
+ def create(cls, value: bool, _var_data: VarData | None = None):
+ """Create the boolean var.
+
+ Args:
+ value: The value of the var.
+ _var_data: Additional hooks and imports associated with the Var.
+
+ Returns:
+ The boolean var.
+ """
+ return cls(
+ _js_expr="true" if value else "false",
+ _var_type=bool,
+ _var_data=_var_data,
+ _var_value=value,
+ )
+
+
number_types = Union[NumberVar, int, float]
boolean_types = Union[BooleanVar, bool]
-@dataclasses.dataclass(
- eq=False,
- frozen=True,
- **{"slots": True} if sys.version_info >= (3, 10) else {},
-)
-class ToNumberVarOperation(ToOperation, NumberVar):
- """Base class for immutable number vars that are the result of a number operation."""
-
- _original: Var = dataclasses.field(default_factory=lambda: LiteralNoneVar.create())
-
- _default_var_type: ClassVar[Type] = float
-
-
-@dataclasses.dataclass(
- eq=False,
- frozen=True,
- **{"slots": True} if sys.version_info >= (3, 10) else {},
-)
-class ToBooleanVarOperation(ToOperation, BooleanVar):
- """Base class for immutable boolean vars that are the result of a boolean operation."""
-
- _original: Var = dataclasses.field(default_factory=lambda: LiteralNoneVar.create())
-
- _default_var_type: ClassVar[Type] = bool
-
-
_IS_TRUE_IMPORT: ImportDict = {
f"/{Dirs.STATE_PATH}": [ImportVar(tag="isTrue")],
}
@@ -1140,8 +1111,12 @@ def boolify(value: Var):
)
+T = TypeVar("T")
+U = TypeVar("U")
+
+
@var_operation
-def ternary_operation(condition: BooleanVar, if_true: Var, if_false: Var):
+def ternary_operation(condition: BooleanVar, if_true: Var[T], if_false: Var[U]):
"""Create a ternary operation.
Args:
@@ -1152,10 +1127,14 @@ def ternary_operation(condition: BooleanVar, if_true: Var, if_false: Var):
Returns:
The ternary operation.
"""
- return var_operation_return(
- js_expression=f"({condition} ? {if_true} : {if_false})",
- var_type=unionize(if_true._var_type, if_false._var_type),
+ type_value: Union[Type[T], Type[U]] = unionize(
+ if_true._var_type, if_false._var_type
)
+ value: CustomVarOperationReturn[Union[T, U]] = var_operation_return(
+ js_expression=f"({condition} ? {if_true} : {if_false})",
+ var_type=type_value,
+ )
+ return value
NUMBER_TYPES = (int, float, NumberVar)
diff --git a/reflex/vars/object.py b/reflex/vars/object.py
index 38add7779..56f3535d8 100644
--- a/reflex/vars/object.py
+++ b/reflex/vars/object.py
@@ -8,7 +8,6 @@ import typing
from inspect import isclass
from typing import (
Any,
- ClassVar,
Dict,
List,
NoReturn,
@@ -27,7 +26,6 @@ from reflex.utils.types import GenericType, get_attribute_access_type, get_origi
from .base import (
CachedVarOperation,
LiteralVar,
- ToOperation,
Var,
VarData,
cached_property_no_lock,
@@ -48,7 +46,7 @@ ARRAY_INNER_TYPE = TypeVar("ARRAY_INNER_TYPE")
OTHER_KEY_TYPE = TypeVar("OTHER_KEY_TYPE")
-class ObjectVar(Var[OBJECT_TYPE]):
+class ObjectVar(Var[OBJECT_TYPE], python_types=dict):
"""Base class for immutable object vars."""
def _key_type(self) -> Type:
@@ -521,34 +519,6 @@ class ObjectItemOperation(CachedVarOperation, Var):
)
-@dataclasses.dataclass(
- eq=False,
- frozen=True,
- **{"slots": True} if sys.version_info >= (3, 10) else {},
-)
-class ToObjectOperation(ToOperation, ObjectVar):
- """Operation to convert a var to an object."""
-
- _original: Var = dataclasses.field(
- default_factory=lambda: LiteralObjectVar.create({})
- )
-
- _default_var_type: ClassVar[GenericType] = dict
-
- def __getattr__(self, name: str) -> Any:
- """Get an attribute of the var.
-
- Args:
- name: The name of the attribute.
-
- Returns:
- The attribute of the var.
- """
- if name == "_js_expr":
- return self._original._js_expr
- return ObjectVar.__getattr__(self, name)
-
-
@var_operation
def object_has_own_property_operation(object: ObjectVar, key: Var):
"""Check if an object has a key.
diff --git a/reflex/vars/sequence.py b/reflex/vars/sequence.py
index 9b65507b7..39139ce3f 100644
--- a/reflex/vars/sequence.py
+++ b/reflex/vars/sequence.py
@@ -11,7 +11,6 @@ import typing
from typing import (
TYPE_CHECKING,
Any,
- ClassVar,
Dict,
List,
Literal,
@@ -19,27 +18,28 @@ from typing import (
Set,
Tuple,
Type,
- TypeVar,
Union,
overload,
)
+from typing_extensions import TypeVar
+
from reflex import constants
from reflex.constants.base import REFLEX_VAR_OPENING_TAG
+from reflex.constants.colors import Color
from reflex.utils.exceptions import VarTypeError
from reflex.utils.types import GenericType, get_origin
from .base import (
CachedVarOperation,
CustomVarOperationReturn,
- LiteralNoneVar,
LiteralVar,
- ToOperation,
Var,
VarData,
_global_vars,
cached_property_no_lock,
figure_out_type,
+ get_python_literal,
get_unique_variable_name,
unionize,
var_operation,
@@ -50,13 +50,16 @@ from .number import (
LiteralNumberVar,
NumberVar,
raise_unsupported_operand_types,
+ ternary_operation,
)
if TYPE_CHECKING:
from .object import ObjectVar
+STRING_TYPE = TypeVar("STRING_TYPE", default=str)
-class StringVar(Var[str]):
+
+class StringVar(Var[STRING_TYPE], python_types=str):
"""Base class for immutable string vars."""
@overload
@@ -350,7 +353,7 @@ class StringVar(Var[str]):
@var_operation
-def string_lt_operation(lhs: StringVar | str, rhs: StringVar | str):
+def string_lt_operation(lhs: StringVar[Any] | str, rhs: StringVar[Any] | str):
"""Check if a string is less than another string.
Args:
@@ -364,7 +367,7 @@ def string_lt_operation(lhs: StringVar | str, rhs: StringVar | str):
@var_operation
-def string_gt_operation(lhs: StringVar | str, rhs: StringVar | str):
+def string_gt_operation(lhs: StringVar[Any] | str, rhs: StringVar[Any] | str):
"""Check if a string is greater than another string.
Args:
@@ -378,7 +381,7 @@ def string_gt_operation(lhs: StringVar | str, rhs: StringVar | str):
@var_operation
-def string_le_operation(lhs: StringVar | str, rhs: StringVar | str):
+def string_le_operation(lhs: StringVar[Any] | str, rhs: StringVar[Any] | str):
"""Check if a string is less than or equal to another string.
Args:
@@ -392,7 +395,7 @@ def string_le_operation(lhs: StringVar | str, rhs: StringVar | str):
@var_operation
-def string_ge_operation(lhs: StringVar | str, rhs: StringVar | str):
+def string_ge_operation(lhs: StringVar[Any] | str, rhs: StringVar[Any] | str):
"""Check if a string is greater than or equal to another string.
Args:
@@ -406,7 +409,7 @@ def string_ge_operation(lhs: StringVar | str, rhs: StringVar | str):
@var_operation
-def string_lower_operation(string: StringVar):
+def string_lower_operation(string: StringVar[Any]):
"""Convert a string to lowercase.
Args:
@@ -419,7 +422,7 @@ def string_lower_operation(string: StringVar):
@var_operation
-def string_upper_operation(string: StringVar):
+def string_upper_operation(string: StringVar[Any]):
"""Convert a string to uppercase.
Args:
@@ -432,7 +435,7 @@ def string_upper_operation(string: StringVar):
@var_operation
-def string_strip_operation(string: StringVar):
+def string_strip_operation(string: StringVar[Any]):
"""Strip a string.
Args:
@@ -446,7 +449,7 @@ def string_strip_operation(string: StringVar):
@var_operation
def string_contains_field_operation(
- haystack: StringVar, needle: StringVar | str, field: StringVar | str
+ haystack: StringVar[Any], needle: StringVar[Any] | str, field: StringVar[Any] | str
):
"""Check if a string contains another string.
@@ -465,7 +468,7 @@ def string_contains_field_operation(
@var_operation
-def string_contains_operation(haystack: StringVar, needle: StringVar | str):
+def string_contains_operation(haystack: StringVar[Any], needle: StringVar[Any] | str):
"""Check if a string contains another string.
Args:
@@ -481,7 +484,9 @@ def string_contains_operation(haystack: StringVar, needle: StringVar | str):
@var_operation
-def string_starts_with_operation(full_string: StringVar, prefix: StringVar | str):
+def string_starts_with_operation(
+ full_string: StringVar[Any], prefix: StringVar[Any] | str
+):
"""Check if a string starts with a prefix.
Args:
@@ -497,7 +502,7 @@ def string_starts_with_operation(full_string: StringVar, prefix: StringVar | str
@var_operation
-def string_item_operation(string: StringVar, index: NumberVar | int):
+def string_item_operation(string: StringVar[Any], index: NumberVar | int):
"""Get an item from a string.
Args:
@@ -511,7 +516,7 @@ def string_item_operation(string: StringVar, index: NumberVar | int):
@var_operation
-def array_join_operation(array: ArrayVar, sep: StringVar | str = ""):
+def array_join_operation(array: ArrayVar, sep: StringVar[Any] | str = ""):
"""Join the elements of an array.
Args:
@@ -524,6 +529,26 @@ def array_join_operation(array: ArrayVar, sep: StringVar | str = ""):
return var_operation_return(js_expression=f"{array}.join({sep})", var_type=str)
+@var_operation
+def string_replace_operation(
+ string: StringVar, search_value: StringVar | str, new_value: StringVar | str
+):
+ """Replace a string with a value.
+
+ Args:
+ string: The string.
+ search_value: The string to search.
+ new_value: The value to be replaced with.
+
+ Returns:
+ The string replace operation.
+ """
+ return var_operation_return(
+ js_expression=f"{string}.replace({search_value}, {new_value})",
+ var_type=str,
+ )
+
+
# Compile regex for finding reflex var tags.
_decode_var_pattern_re = (
rf"{constants.REFLEX_VAR_OPENING_TAG}(.*?){constants.REFLEX_VAR_CLOSING_TAG}"
@@ -536,7 +561,7 @@ _decode_var_pattern = re.compile(_decode_var_pattern_re, flags=re.DOTALL)
frozen=True,
**{"slots": True} if sys.version_info >= (3, 10) else {},
)
-class LiteralStringVar(LiteralVar, StringVar):
+class LiteralStringVar(LiteralVar, StringVar[str]):
"""Base class for immutable literal string vars."""
_var_value: str = dataclasses.field(default="")
@@ -658,7 +683,7 @@ class LiteralStringVar(LiteralVar, StringVar):
frozen=True,
**{"slots": True} if sys.version_info >= (3, 10) else {},
)
-class ConcatVarOperation(CachedVarOperation, StringVar):
+class ConcatVarOperation(CachedVarOperation, StringVar[str]):
"""Representing a concatenation of literal string vars."""
_var_value: Tuple[Var, ...] = dataclasses.field(default_factory=tuple)
@@ -742,7 +767,7 @@ KEY_TYPE = TypeVar("KEY_TYPE")
VALUE_TYPE = TypeVar("VALUE_TYPE")
-class ArrayVar(Var[ARRAY_VAR_TYPE]):
+class ArrayVar(Var[ARRAY_VAR_TYPE], python_types=(list, tuple, set)):
"""Base class for immutable array vars."""
@overload
@@ -1155,7 +1180,7 @@ class ArrayVar(Var[ARRAY_VAR_TYPE]):
function_var = ArgsFunctionOperation.create(tuple(), return_value)
else:
# generic number var
- number_var = Var("").to(NumberVar)
+ number_var = Var("").to(NumberVar, int)
first_arg_type = self[number_var]._var_type
@@ -1167,7 +1192,10 @@ class ArrayVar(Var[ARRAY_VAR_TYPE]):
_var_type=first_arg_type,
).guess_type()
- function_var = ArgsFunctionOperation.create((arg_name,), fn(first_arg))
+ function_var = ArgsFunctionOperation.create(
+ (arg_name,),
+ Var.create(fn(first_arg)),
+ )
return map_array_operation(self, function_var)
@@ -1272,7 +1300,7 @@ class LiteralArrayVar(CachedVarOperation, LiteralVar, ArrayVar[ARRAY_VAR_TYPE]):
@var_operation
-def string_split_operation(string: StringVar, sep: StringVar | str = ""):
+def string_split_operation(string: StringVar[Any], sep: StringVar | str = ""):
"""Split a string.
Args:
@@ -1569,32 +1597,6 @@ def array_contains_operation(haystack: ArrayVar, needle: Any | Var):
)
-@dataclasses.dataclass(
- eq=False,
- frozen=True,
- **{"slots": True} if sys.version_info >= (3, 10) else {},
-)
-class ToStringOperation(ToOperation, StringVar):
- """Base class for immutable string vars that are the result of a to string operation."""
-
- _original: Var = dataclasses.field(default_factory=lambda: LiteralNoneVar.create())
-
- _default_var_type: ClassVar[Type] = str
-
-
-@dataclasses.dataclass(
- eq=False,
- frozen=True,
- **{"slots": True} if sys.version_info >= (3, 10) else {},
-)
-class ToArrayOperation(ToOperation, ArrayVar):
- """Base class for immutable array vars that are the result of a to array operation."""
-
- _original: Var = dataclasses.field(default_factory=lambda: LiteralNoneVar.create())
-
- _default_var_type: ClassVar[Type] = List[Any]
-
-
@var_operation
def repeat_array_operation(
array: ArrayVar[ARRAY_VAR_TYPE], count: NumberVar | int
@@ -1654,3 +1656,134 @@ def array_concat_operation(
js_expression=f"[...{lhs}, ...{rhs}]",
var_type=Union[lhs._var_type, rhs._var_type],
)
+
+
+class ColorVar(StringVar[Color], python_types=Color):
+ """Base class for immutable color vars."""
+
+
+@dataclasses.dataclass(
+ eq=False,
+ frozen=True,
+ **{"slots": True} if sys.version_info >= (3, 10) else {},
+)
+class LiteralColorVar(CachedVarOperation, LiteralVar, ColorVar):
+ """Base class for immutable literal color vars."""
+
+ _var_value: Color = dataclasses.field(default_factory=lambda: Color(color="black"))
+
+ @classmethod
+ def create(
+ cls,
+ value: Color,
+ _var_type: Type[Color] | None = None,
+ _var_data: VarData | None = None,
+ ) -> ColorVar:
+ """Create a var from a string value.
+
+ Args:
+ value: The value to create the var from.
+ _var_type: The type of the var.
+ _var_data: Additional hooks and imports associated with the Var.
+
+ Returns:
+ The var.
+ """
+ return cls(
+ _js_expr="",
+ _var_type=_var_type or Color,
+ _var_data=_var_data,
+ _var_value=value,
+ )
+
+ def __hash__(self) -> int:
+ """Get the hash of the var.
+
+ Returns:
+ The hash of the var.
+ """
+ return hash(
+ (
+ self.__class__.__name__,
+ self._var_value.color,
+ self._var_value.alpha,
+ self._var_value.shade,
+ )
+ )
+
+ @cached_property_no_lock
+ def _cached_var_name(self) -> str:
+ """The name of the var.
+
+ Returns:
+ The name of the var.
+ """
+ alpha = self._var_value.alpha
+ alpha = (
+ ternary_operation(
+ alpha,
+ LiteralStringVar.create("a"),
+ LiteralStringVar.create(""),
+ )
+ if isinstance(alpha, Var)
+ else LiteralStringVar.create("a" if alpha else "")
+ )
+
+ shade = self._var_value.shade
+ shade = (
+ shade.to_string(use_json=False)
+ if isinstance(shade, Var)
+ else LiteralStringVar.create(str(shade))
+ )
+ return str(
+ ConcatVarOperation.create(
+ LiteralStringVar.create("var(--"),
+ self._var_value.color,
+ LiteralStringVar.create("-"),
+ alpha,
+ shade,
+ LiteralStringVar.create(")"),
+ )
+ )
+
+ @cached_property_no_lock
+ def _cached_get_all_var_data(self) -> VarData | None:
+ """Get all the var data.
+
+ Returns:
+ The var data.
+ """
+ return VarData.merge(
+ *[
+ LiteralVar.create(var)._get_all_var_data()
+ for var in (
+ self._var_value.color,
+ self._var_value.alpha,
+ self._var_value.shade,
+ )
+ ],
+ self._var_data,
+ )
+
+ def json(self) -> str:
+ """Get the JSON representation of the var.
+
+ Returns:
+ The JSON representation of the var.
+
+ Raises:
+ TypeError: If the color is not a valid color.
+ """
+ color, alpha, shade = map(
+ get_python_literal,
+ (self._var_value.color, self._var_value.alpha, self._var_value.shade),
+ )
+ if color is None or alpha is None or shade is None:
+ raise TypeError("Cannot serialize color that contains non-literal vars.")
+ if (
+ not isinstance(color, str)
+ or not isinstance(alpha, bool)
+ or not isinstance(shade, int)
+ ):
+ raise TypeError("Color is not a valid color.")
+ return f"var(--{color}-{'a' if alpha else ''}{shade})"
diff --git a/tests/integration/test_lifespan.py b/tests/integration/test_lifespan.py
index f8bcf2397..22c399c07 100644
--- a/tests/integration/test_lifespan.py
+++ b/tests/integration/test_lifespan.py
@@ -51,6 +51,7 @@ def LifespanApp():
def context_global(self) -> int:
return lifespan_context_global
+ @rx.event
def tick(self, date):
pass
diff --git a/tests/units/components/core/test_colors.py b/tests/units/components/core/test_colors.py
index a6175d56a..74fbeb20f 100644
--- a/tests/units/components/core/test_colors.py
+++ b/tests/units/components/core/test_colors.py
@@ -14,6 +14,7 @@ class ColorState(rx.State):
color: str = "mint"
color_part: str = "tom"
shade: int = 4
+ alpha: bool = False
color_state_name = ColorState.get_full_name().replace(".", "__")
@@ -31,7 +32,14 @@ def create_color_var(color):
(create_color_var(rx.color("mint", 3, True)), '"var(--mint-a3)"', Color),
(
create_color_var(rx.color(ColorState.color, ColorState.shade)), # type: ignore
- f'("var(--"+{str(color_state_name)}.color+"-"+{str(color_state_name)}.shade+")")',
+ f'("var(--"+{str(color_state_name)}.color+"-"+(((__to_string) => __to_string.toString())({str(color_state_name)}.shade))+")")',
+ Color,
+ ),
+ (
+ create_color_var(
+ rx.color(ColorState.color, ColorState.shade, ColorState.alpha) # type: ignore
+ ),
+ f'("var(--"+{str(color_state_name)}.color+"-"+({str(color_state_name)}.alpha ? "a" : "")+(((__to_string) => __to_string.toString())({str(color_state_name)}.shade))+")")',
Color,
),
(
@@ -43,7 +51,7 @@ def create_color_var(color):
create_color_var(
rx.color(f"{ColorState.color_part}ato", f"{ColorState.shade}") # type: ignore
),
- f'("var(--"+{str(color_state_name)}.color_part+"ato-"+{str(color_state_name)}.shade+")")',
+ f'("var(--"+({str(color_state_name)}.color_part+"ato")+"-"+{str(color_state_name)}.shade+")")',
Color,
),
(
diff --git a/tests/units/components/datadisplay/test_shiki_code.py b/tests/units/components/datadisplay/test_shiki_code.py
new file mode 100644
index 000000000..eb473ba06
--- /dev/null
+++ b/tests/units/components/datadisplay/test_shiki_code.py
@@ -0,0 +1,172 @@
+import pytest
+
+from reflex.components.datadisplay.shiki_code_block import (
+ ShikiBaseTransformers,
+ ShikiCodeBlock,
+ ShikiHighLevelCodeBlock,
+ ShikiJsTransformer,
+)
+from reflex.components.el.elements.forms import Button
+from reflex.components.lucide.icon import Icon
+from reflex.components.radix.themes.layout.box import Box
+from reflex.style import Style
+from reflex.vars import Var
+
+
+@pytest.mark.parametrize(
+ "library, fns, expected_output, raises_exception",
+ [
+ ("some_library", ["function_one"], ["function_one"], False),
+ ("some_library", [123], None, True),
+ ("some_library", [], [], False),
+ (
+ "some_library",
+ ["function_one", "function_two"],
+ ["function_one", "function_two"],
+ False,
+ ),
+ ("", ["function_one"], ["function_one"], False),
+ ("some_library", ["function_one", 789], None, True),
+ ("", [], [], False),
+ ],
+)
+def test_create_transformer(library, fns, expected_output, raises_exception):
+ if raises_exception:
+ # Ensure ValueError is raised for invalid cases
+ with pytest.raises(ValueError):
+ ShikiCodeBlock.create_transformer(library, fns)
+ else:
+ transformer = ShikiCodeBlock.create_transformer(library, fns)
+ assert isinstance(transformer, ShikiBaseTransformers)
+ assert transformer.library == library
+
+ # Verify that the functions are correctly wrapped in FunctionStringVar
+ function_names = [str(fn) for fn in transformer.fns]
+ assert function_names == expected_output
+
+
+@pytest.mark.parametrize(
+ "code_block, children, props, expected_first_child, expected_styles",
+ [
+ ("print('Hello')", ["print('Hello')"], {}, "print('Hello')", {}),
+ (
+ "print('Hello')",
+ ["print('Hello')", "More content"],
+ {},
+ "print('Hello')",
+ {},
+ ),
+ (
+ "print('Hello')",
+ ["print('Hello')"],
+ {
+ "transformers": [
+ ShikiBaseTransformers(
+ library="lib", fns=[], style=Style({"color": "red"})
+ )
+ ]
+ },
+ "print('Hello')",
+ {"color": "red"},
+ ),
+ (
+ "print('Hello')",
+ ["print('Hello')"],
+ {
+ "transformers": [
+ ShikiBaseTransformers(
+ library="lib", fns=[], style=Style({"color": "red"})
+ )
+ ],
+ "style": {"background": "blue"},
+ },
+ "print('Hello')",
+ {"color": "red", "background": "blue"},
+ ),
+ ],
+)
+def test_create_shiki_code_block(
+ code_block, children, props, expected_first_child, expected_styles
+):
+ component = ShikiCodeBlock.create(code_block, *children, **props)
+
+ # Test that the created component is a Box
+ assert isinstance(component, Box)
+
+ # Test that the first child is the code
+ code_block_component = component.children[0]
+ assert code_block_component.code._var_value == expected_first_child # type: ignore
+
+ applied_styles = component.style
+ for key, value in expected_styles.items():
+ assert Var.create(applied_styles[key])._var_value == value
+
+
+@pytest.mark.parametrize(
+ "children, props, expected_transformers, expected_button_type",
+ [
+ (["print('Hello')"], {"use_transformers": True}, [ShikiJsTransformer], None),
+ (["print('Hello')"], {"can_copy": True}, None, Button),
+ (
+ ["print('Hello')"],
+ {
+ "can_copy": True,
+ "copy_button": Button.create(Icon.create(tag="a_arrow_down")),
+ },
+ None,
+ Button,
+ ),
+ ],
+)
+def test_create_shiki_high_level_code_block(
+ children, props, expected_transformers, expected_button_type
+):
+ component = ShikiHighLevelCodeBlock.create(*children, **props)
+
+ # Test that the created component is a Box
+ assert isinstance(component, Box)
+
+ # Test that the first child is the code block component
+ code_block_component = component.children[0]
+ assert code_block_component.code._var_value == children[0] # type: ignore
+
+ # Check if the transformer is set correctly if expected
+ if expected_transformers:
+ exp_trans_names = [t.__name__ for t in expected_transformers]
+ for transformer in code_block_component.transformers._var_value: # type: ignore
+ assert type(transformer).__name__ in exp_trans_names
+
+ # Check if the second child is the copy button if can_copy is True
+ if props.get("can_copy", False):
+ if props.get("copy_button"):
+ assert isinstance(component.children[1], expected_button_type)
+ assert component.children[1] == props["copy_button"]
+ else:
+ assert isinstance(component.children[1], expected_button_type)
+ else:
+ assert len(component.children) == 1
+
+
+@pytest.mark.parametrize(
+ "children, props",
+ [
+ (["print('Hello')"], {"theme": "dark"}),
+ (["print('Hello')"], {"language": "javascript"}),
+ ],
+)
+def test_shiki_high_level_code_block_theme_language_mapping(children, props):
+ component = ShikiHighLevelCodeBlock.create(*children, **props)
+
+ # Test that the theme is mapped correctly
+ if "theme" in props:
+ assert component.children[
+ 0
+ ].theme._var_value == ShikiHighLevelCodeBlock._map_themes(props["theme"]) # type: ignore
+
+ # Test that the language is mapped correctly
+ if "language" in props:
+ assert component.children[
+ 0
+ ].language._var_value == ShikiHighLevelCodeBlock._map_languages( # type: ignore
+ props["language"]
+ )
diff --git a/tests/units/test_config.py b/tests/units/test_config.py
index a6c6fe697..c4a143bc5 100644
--- a/tests/units/test_config.py
+++ b/tests/units/test_config.py
@@ -5,6 +5,7 @@ import pytest
import reflex as rx
import reflex.config
+from reflex.config import environment
from reflex.constants import Endpoint
@@ -178,7 +179,7 @@ def test_replace_defaults(
def reflex_dir_constant():
- return rx.constants.Reflex.DIR
+ return environment.REFLEX_DIR
def test_reflex_dir_env_var(monkeypatch, tmp_path):
diff --git a/tests/units/test_event.py b/tests/units/test_event.py
index 3996a6101..d7b7cf7a2 100644
--- a/tests/units/test_event.py
+++ b/tests/units/test_event.py
@@ -2,11 +2,18 @@ from typing import List
import pytest
-from reflex import event
-from reflex.event import Event, EventHandler, EventSpec, call_event_handler, fix_events
+from reflex.event import (
+ Event,
+ EventChain,
+ EventHandler,
+ EventSpec,
+ call_event_handler,
+ event,
+ fix_events,
+)
from reflex.state import BaseState
from reflex.utils import format
-from reflex.vars.base import LiteralVar, Var
+from reflex.vars.base import Field, LiteralVar, Var, field
def make_var(value) -> Var:
@@ -388,3 +395,28 @@ def test_event_actions_on_state():
assert sp_handler.event_actions == {"stopPropagation": True}
# should NOT affect other references to the handler
assert not handler.event_actions
+
+
+def test_event_var_data():
+ class S(BaseState):
+ x: Field[int] = field(0)
+
+ @event
+ def s(self, value: int):
+ pass
+
+ # Handler doesn't have any _var_data because it's just a str
+ handler_var = Var.create(S.s)
+ assert handler_var._get_all_var_data() is None
+
+ # Ensure spec carries _var_data
+ spec_var = Var.create(S.s(S.x))
+ assert spec_var._get_all_var_data() == S.x._get_all_var_data()
+
+ # Needed to instantiate the EventChain
+ def _args_spec(value: Var[int]) -> tuple[Var[int]]:
+ return (value,)
+
+ # Ensure chain carries _var_data
+ chain_var = Var.create(EventChain(events=[S.s(S.x)], args_spec=_args_spec))
+ assert chain_var._get_all_var_data() == S.x._get_all_var_data()
diff --git a/tests/units/test_var.py b/tests/units/test_var.py
index c04e554a9..a8b4b759d 100644
--- a/tests/units/test_var.py
+++ b/tests/units/test_var.py
@@ -519,8 +519,8 @@ def test_var_indexing_types(var, type_):
type_ : The type on indexed object.
"""
- assert var[2]._var_type == type_[0]
- assert var[3]._var_type == type_[1]
+ assert var[0]._var_type == type_[0]
+ assert var[1]._var_type == type_[1]
def test_var_indexing_str():