From 109b272bc290afdebdd2fa1b01cf2efca8185787 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Wed, 22 Jan 2025 15:18:05 -0800 Subject: [PATCH 01/12] Bump frontend and backend deps (#4667) * relock backend deps * bump frontend library versions * go back to react 18.3 * revert to react 18.3.1 (as it was before) * reflex-web keep reflex from current revision, rather than main * relock backend deps (again) * don't check ag-grid version on main repo * config_path is passed via `extra` to avoid pyright error when None * bump next again --------- Co-authored-by: Lendemor --- .../workflows/check_outdated_dependencies.yml | 4 +- poetry.lock | 367 +++++++++--------- reflex/components/core/upload.py | 2 +- reflex/components/datadisplay/code.py | 2 +- reflex/components/plotly/plotly.py | 2 +- reflex/components/recharts/recharts.py | 4 +- reflex/components/sonner/toast.py | 2 +- reflex/constants/installer.py | 14 +- reflex/constants/style.py | 2 +- 9 files changed, 201 insertions(+), 198 deletions(-) diff --git a/.github/workflows/check_outdated_dependencies.yml b/.github/workflows/check_outdated_dependencies.yml index 29a19d615..34bfa23bf 100644 --- a/.github/workflows/check_outdated_dependencies.yml +++ b/.github/workflows/check_outdated_dependencies.yml @@ -55,7 +55,7 @@ jobs: path: reflex-web - name: Install Requirements for reflex-web working-directory: ./reflex-web - run: poetry run uv pip install -r requirements.txt + run: poetry run uv pip install $(grep -ivE "reflex " requirements.txt) - name: Install additional dependencies for DB access run: poetry run uv pip install psycopg - name: Init Website for reflex-web @@ -73,7 +73,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|remark-unwrap-images' || 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|ag-grid' || true) no_extra=$(echo "$filtered_outdated" | grep -vE '\|\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-' || true) diff --git a/poetry.lock b/poetry.lock index 4cf859611..5cc673489 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,13 +2,13 @@ [[package]] name = "alembic" -version = "1.14.0" +version = "1.14.1" description = "A database migration tool for SQLAlchemy." optional = false python-versions = ">=3.8" files = [ - {file = "alembic-1.14.0-py3-none-any.whl", hash = "sha256:99bd884ca390466db5e27ffccff1d179ec5c05c965cfefc0607e69f9e411cb25"}, - {file = "alembic-1.14.0.tar.gz", hash = "sha256:b00892b53b3642d0b8dbedba234dbf1924b69be83a9a769d5a624b01094e304b"}, + {file = "alembic-1.14.1-py3-none-any.whl", hash = "sha256:1acdd7a3a478e208b0503cd73614d5e4c6efafa4e73518bb60e4f2846a37b1c5"}, + {file = "alembic-1.14.1.tar.gz", hash = "sha256:496e888245a53adf1498fcab31713a469c65836f8de76e01399aa1c3e90dd213"}, ] [package.dependencies] @@ -17,7 +17,7 @@ SQLAlchemy = ">=1.3.0" typing-extensions = ">=4" [package.extras] -tz = ["backports.zoneinfo"] +tz = ["backports.zoneinfo", "tzdata"] [[package]] name = "annotated-types" @@ -461,7 +461,6 @@ files = [ {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543"}, - {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e"}, {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e"}, {file = "cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053"}, @@ -472,7 +471,6 @@ files = [ {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7"}, {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c"}, - {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64"}, {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285"}, {file = "cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417"}, @@ -594,18 +592,18 @@ standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "htt [[package]] name = "filelock" -version = "3.16.1" +version = "3.17.0" description = "A platform independent file lock." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, - {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, + {file = "filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338"}, + {file = "filelock-3.17.0.tar.gz", hash = "sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e"}, ] [package.extras] -docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-asyncio (>=0.25.2)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.28.1)"] typing = ["typing-extensions (>=4.12.2)"] [[package]] @@ -771,15 +769,34 @@ http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] zstd = ["zstandard (>=0.18.0)"] +[[package]] +name = "id" +version = "1.5.0" +description = "A tool for generating OIDC identities" +optional = false +python-versions = ">=3.8" +files = [ + {file = "id-1.5.0-py3-none-any.whl", hash = "sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658"}, + {file = "id-1.5.0.tar.gz", hash = "sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d"}, +] + +[package.dependencies] +requests = "*" + +[package.extras] +dev = ["build", "bump (>=1.3.2)", "id[lint,test]"] +lint = ["bandit", "interrogate", "mypy", "ruff (<0.8.2)", "types-requests"] +test = ["coverage[toml]", "pretend", "pytest", "pytest-cov"] + [[package]] name = "identify" -version = "2.6.5" +version = "2.6.6" description = "File identification library for Python" optional = false python-versions = ">=3.9" files = [ - {file = "identify-2.6.5-py2.py3-none-any.whl", hash = "sha256:14181a47091eb75b337af4c23078c9d09225cd4c48929f521f3bf16b09d02566"}, - {file = "identify-2.6.5.tar.gz", hash = "sha256:c10b33f250e5bba374fae86fb57f3adcebf1161bce7cdf92031915fd480c13bc"}, + {file = "identify-2.6.6-py2.py3-none-any.whl", hash = "sha256:cbd1810bce79f8b671ecb20f53ee0ae8e86ae84b557de31d89709dc2a48ba881"}, + {file = "identify-2.6.6.tar.gz", hash = "sha256:7bec12768ed44ea4761efb47806f0a41f86e7c0a5fdf5950d4648c90eca7e251"}, ] [package.extras] @@ -801,13 +818,13 @@ all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2 [[package]] name = "importlib-metadata" -version = "8.5.0" +version = "8.6.1" description = "Read metadata from Python packages" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, - {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, + {file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"}, + {file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"}, ] [package.dependencies] @@ -819,7 +836,7 @@ cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +test = ["flufl.flake8", "importlib_resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] type = ["pytest-mypy"] [[package]] @@ -1097,13 +1114,13 @@ files = [ [[package]] name = "more-itertools" -version = "10.5.0" +version = "10.6.0" description = "More routines for operating on iterables, beyond itertools" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "more-itertools-10.5.0.tar.gz", hash = "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6"}, - {file = "more_itertools-10.5.0-py3-none-any.whl", hash = "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef"}, + {file = "more-itertools-10.6.0.tar.gz", hash = "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b"}, + {file = "more_itertools-10.6.0-py3-none-any.whl", hash = "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89"}, ] [[package]] @@ -1152,66 +1169,66 @@ files = [ [[package]] name = "numpy" -version = "2.2.1" +version = "2.2.2" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.10" files = [ - {file = "numpy-2.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5edb4e4caf751c1518e6a26a83501fda79bff41cc59dac48d70e6d65d4ec4440"}, - {file = "numpy-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aa3017c40d513ccac9621a2364f939d39e550c542eb2a894b4c8da92b38896ab"}, - {file = "numpy-2.2.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:61048b4a49b1c93fe13426e04e04fdf5a03f456616f6e98c7576144677598675"}, - {file = "numpy-2.2.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:7671dc19c7019103ca44e8d94917eba8534c76133523ca8406822efdd19c9308"}, - {file = "numpy-2.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4250888bcb96617e00bfa28ac24850a83c9f3a16db471eca2ee1f1714df0f957"}, - {file = "numpy-2.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7746f235c47abc72b102d3bce9977714c2444bdfaea7888d241b4c4bb6a78bf"}, - {file = "numpy-2.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:059e6a747ae84fce488c3ee397cee7e5f905fd1bda5fb18c66bc41807ff119b2"}, - {file = "numpy-2.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f62aa6ee4eb43b024b0e5a01cf65a0bb078ef8c395e8713c6e8a12a697144528"}, - {file = "numpy-2.2.1-cp310-cp310-win32.whl", hash = "sha256:48fd472630715e1c1c89bf1feab55c29098cb403cc184b4859f9c86d4fcb6a95"}, - {file = "numpy-2.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:b541032178a718c165a49638d28272b771053f628382d5e9d1c93df23ff58dbf"}, - {file = "numpy-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:40f9e544c1c56ba8f1cf7686a8c9b5bb249e665d40d626a23899ba6d5d9e1484"}, - {file = "numpy-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9b57eaa3b0cd8db52049ed0330747b0364e899e8a606a624813452b8203d5f7"}, - {file = "numpy-2.2.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:bc8a37ad5b22c08e2dbd27df2b3ef7e5c0864235805b1e718a235bcb200cf1cb"}, - {file = "numpy-2.2.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:9036d6365d13b6cbe8f27a0eaf73ddcc070cae584e5ff94bb45e3e9d729feab5"}, - {file = "numpy-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51faf345324db860b515d3f364eaa93d0e0551a88d6218a7d61286554d190d73"}, - {file = "numpy-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38efc1e56b73cc9b182fe55e56e63b044dd26a72128fd2fbd502f75555d92591"}, - {file = "numpy-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:31b89fa67a8042e96715c68e071a1200c4e172f93b0fbe01a14c0ff3ff820fc8"}, - {file = "numpy-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4c86e2a209199ead7ee0af65e1d9992d1dce7e1f63c4b9a616500f93820658d0"}, - {file = "numpy-2.2.1-cp311-cp311-win32.whl", hash = "sha256:b34d87e8a3090ea626003f87f9392b3929a7bbf4104a05b6667348b6bd4bf1cd"}, - {file = "numpy-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:360137f8fb1b753c5cde3ac388597ad680eccbbbb3865ab65efea062c4a1fd16"}, - {file = "numpy-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:694f9e921a0c8f252980e85bce61ebbd07ed2b7d4fa72d0e4246f2f8aa6642ab"}, - {file = "numpy-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3683a8d166f2692664262fd4900f207791d005fb088d7fdb973cc8d663626faa"}, - {file = "numpy-2.2.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:780077d95eafc2ccc3ced969db22377b3864e5b9a0ea5eb347cc93b3ea900315"}, - {file = "numpy-2.2.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:55ba24ebe208344aa7a00e4482f65742969a039c2acfcb910bc6fcd776eb4355"}, - {file = "numpy-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b1d07b53b78bf84a96898c1bc139ad7f10fda7423f5fd158fd0f47ec5e01ac7"}, - {file = "numpy-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5062dc1a4e32a10dc2b8b13cedd58988261416e811c1dc4dbdea4f57eea61b0d"}, - {file = "numpy-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:fce4f615f8ca31b2e61aa0eb5865a21e14f5629515c9151850aa936c02a1ee51"}, - {file = "numpy-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:67d4cda6fa6ffa073b08c8372aa5fa767ceb10c9a0587c707505a6d426f4e046"}, - {file = "numpy-2.2.1-cp312-cp312-win32.whl", hash = "sha256:32cb94448be47c500d2c7a95f93e2f21a01f1fd05dd2beea1ccd049bb6001cd2"}, - {file = "numpy-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:ba5511d8f31c033a5fcbda22dd5c813630af98c70b2661f2d2c654ae3cdfcfc8"}, - {file = "numpy-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f1d09e520217618e76396377c81fba6f290d5f926f50c35f3a5f72b01a0da780"}, - {file = "numpy-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3ecc47cd7f6ea0336042be87d9e7da378e5c7e9b3c8ad0f7c966f714fc10d821"}, - {file = "numpy-2.2.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f419290bc8968a46c4933158c91a0012b7a99bb2e465d5ef5293879742f8797e"}, - {file = "numpy-2.2.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:5b6c390bfaef8c45a260554888966618328d30e72173697e5cabe6b285fb2348"}, - {file = "numpy-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:526fc406ab991a340744aad7e25251dd47a6720a685fa3331e5c59fef5282a59"}, - {file = "numpy-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f74e6fdeb9a265624ec3a3918430205dff1df7e95a230779746a6af78bc615af"}, - {file = "numpy-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:53c09385ff0b72ba79d8715683c1168c12e0b6e84fb0372e97553d1ea91efe51"}, - {file = "numpy-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f3eac17d9ec51be534685ba877b6ab5edc3ab7ec95c8f163e5d7b39859524716"}, - {file = "numpy-2.2.1-cp313-cp313-win32.whl", hash = "sha256:9ad014faa93dbb52c80d8f4d3dcf855865c876c9660cb9bd7553843dd03a4b1e"}, - {file = "numpy-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:164a829b6aacf79ca47ba4814b130c4020b202522a93d7bff2202bfb33b61c60"}, - {file = "numpy-2.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4dfda918a13cc4f81e9118dea249e192ab167a0bb1966272d5503e39234d694e"}, - {file = "numpy-2.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:733585f9f4b62e9b3528dd1070ec4f52b8acf64215b60a845fa13ebd73cd0712"}, - {file = "numpy-2.2.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:89b16a18e7bba224ce5114db863e7029803c179979e1af6ad6a6b11f70545008"}, - {file = "numpy-2.2.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:676f4eebf6b2d430300f1f4f4c2461685f8269f94c89698d832cdf9277f30b84"}, - {file = "numpy-2.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27f5cdf9f493b35f7e41e8368e7d7b4bbafaf9660cba53fb21d2cd174ec09631"}, - {file = "numpy-2.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1ad395cf254c4fbb5b2132fee391f361a6e8c1adbd28f2cd8e79308a615fe9d"}, - {file = "numpy-2.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:08ef779aed40dbc52729d6ffe7dd51df85796a702afbf68a4f4e41fafdc8bda5"}, - {file = "numpy-2.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:26c9c4382b19fcfbbed3238a14abf7ff223890ea1936b8890f058e7ba35e8d71"}, - {file = "numpy-2.2.1-cp313-cp313t-win32.whl", hash = "sha256:93cf4e045bae74c90ca833cba583c14b62cb4ba2cba0abd2b141ab52548247e2"}, - {file = "numpy-2.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:bff7d8ec20f5f42607599f9994770fa65d76edca264a87b5e4ea5629bce12268"}, - {file = "numpy-2.2.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7ba9cc93a91d86365a5d270dee221fdc04fb68d7478e6bf6af650de78a8339e3"}, - {file = "numpy-2.2.1-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:3d03883435a19794e41f147612a77a8f56d4e52822337844fff3d4040a142964"}, - {file = "numpy-2.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4511d9e6071452b944207c8ce46ad2f897307910b402ea5fa975da32e0102800"}, - {file = "numpy-2.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5c5cc0cbabe9452038ed984d05ac87910f89370b9242371bd9079cb4af61811e"}, - {file = "numpy-2.2.1.tar.gz", hash = "sha256:45681fd7128c8ad1c379f0ca0776a8b0c6583d2f69889ddac01559dfe4390918"}, + {file = "numpy-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7079129b64cb78bdc8d611d1fd7e8002c0a2565da6a47c4df8062349fee90e3e"}, + {file = "numpy-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ec6c689c61df613b783aeb21f945c4cbe6c51c28cb70aae8430577ab39f163e"}, + {file = "numpy-2.2.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:40c7ff5da22cd391944a28c6a9c638a5eef77fcf71d6e3a79e1d9d9e82752715"}, + {file = "numpy-2.2.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:995f9e8181723852ca458e22de5d9b7d3ba4da3f11cc1cb113f093b271d7965a"}, + {file = "numpy-2.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b78ea78450fd96a498f50ee096f69c75379af5138f7881a51355ab0e11286c97"}, + {file = "numpy-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fbe72d347fbc59f94124125e73fc4976a06927ebc503ec5afbfb35f193cd957"}, + {file = "numpy-2.2.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8e6da5cffbbe571f93588f562ed130ea63ee206d12851b60819512dd3e1ba50d"}, + {file = "numpy-2.2.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:09d6a2032faf25e8d0cadde7fd6145118ac55d2740132c1d845f98721b5ebcfd"}, + {file = "numpy-2.2.2-cp310-cp310-win32.whl", hash = "sha256:159ff6ee4c4a36a23fe01b7c3d07bd8c14cc433d9720f977fcd52c13c0098160"}, + {file = "numpy-2.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:64bd6e1762cd7f0986a740fee4dff927b9ec2c5e4d9a28d056eb17d332158014"}, + {file = "numpy-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:642199e98af1bd2b6aeb8ecf726972d238c9877b0f6e8221ee5ab945ec8a2189"}, + {file = "numpy-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6d9fc9d812c81e6168b6d405bf00b8d6739a7f72ef22a9214c4241e0dc70b323"}, + {file = "numpy-2.2.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:c7d1fd447e33ee20c1f33f2c8e6634211124a9aabde3c617687d8b739aa69eac"}, + {file = "numpy-2.2.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:451e854cfae0febe723077bd0cf0a4302a5d84ff25f0bfece8f29206c7bed02e"}, + {file = "numpy-2.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd249bc894af67cbd8bad2c22e7cbcd46cf87ddfca1f1289d1e7e54868cc785c"}, + {file = "numpy-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02935e2c3c0c6cbe9c7955a8efa8908dd4221d7755644c59d1bba28b94fd334f"}, + {file = "numpy-2.2.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a972cec723e0563aa0823ee2ab1df0cb196ed0778f173b381c871a03719d4826"}, + {file = "numpy-2.2.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d6d6a0910c3b4368d89dde073e630882cdb266755565155bc33520283b2d9df8"}, + {file = "numpy-2.2.2-cp311-cp311-win32.whl", hash = "sha256:860fd59990c37c3ef913c3ae390b3929d005243acca1a86facb0773e2d8d9e50"}, + {file = "numpy-2.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:da1eeb460ecce8d5b8608826595c777728cdf28ce7b5a5a8c8ac8d949beadcf2"}, + {file = "numpy-2.2.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ac9bea18d6d58a995fac1b2cb4488e17eceeac413af014b1dd26170b766d8467"}, + {file = "numpy-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23ae9f0c2d889b7b2d88a3791f6c09e2ef827c2446f1c4a3e3e76328ee4afd9a"}, + {file = "numpy-2.2.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3074634ea4d6df66be04f6728ee1d173cfded75d002c75fac79503a880bf3825"}, + {file = "numpy-2.2.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:8ec0636d3f7d68520afc6ac2dc4b8341ddb725039de042faf0e311599f54eb37"}, + {file = "numpy-2.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ffbb1acd69fdf8e89dd60ef6182ca90a743620957afb7066385a7bbe88dc748"}, + {file = "numpy-2.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0349b025e15ea9d05c3d63f9657707a4e1d471128a3b1d876c095f328f8ff7f0"}, + {file = "numpy-2.2.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:463247edcee4a5537841d5350bc87fe8e92d7dd0e8c71c995d2c6eecb8208278"}, + {file = "numpy-2.2.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9dd47ff0cb2a656ad69c38da850df3454da88ee9a6fde0ba79acceee0e79daba"}, + {file = "numpy-2.2.2-cp312-cp312-win32.whl", hash = "sha256:4525b88c11906d5ab1b0ec1f290996c0020dd318af8b49acaa46f198b1ffc283"}, + {file = "numpy-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:5acea83b801e98541619af398cc0109ff48016955cc0818f478ee9ef1c5c3dcb"}, + {file = "numpy-2.2.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b208cfd4f5fe34e1535c08983a1a6803fdbc7a1e86cf13dd0c61de0b51a0aadc"}, + {file = "numpy-2.2.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d0bbe7dd86dca64854f4b6ce2ea5c60b51e36dfd597300057cf473d3615f2369"}, + {file = "numpy-2.2.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:22ea3bb552ade325530e72a0c557cdf2dea8914d3a5e1fecf58fa5dbcc6f43cd"}, + {file = "numpy-2.2.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:128c41c085cab8a85dc29e66ed88c05613dccf6bc28b3866cd16050a2f5448be"}, + {file = "numpy-2.2.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:250c16b277e3b809ac20d1f590716597481061b514223c7badb7a0f9993c7f84"}, + {file = "numpy-2.2.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0c8854b09bc4de7b041148d8550d3bd712b5c21ff6a8ed308085f190235d7ff"}, + {file = "numpy-2.2.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b6fb9c32a91ec32a689ec6410def76443e3c750e7cfc3fb2206b985ffb2b85f0"}, + {file = "numpy-2.2.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:57b4012e04cc12b78590a334907e01b3a85efb2107df2b8733ff1ed05fce71de"}, + {file = "numpy-2.2.2-cp313-cp313-win32.whl", hash = "sha256:4dbd80e453bd34bd003b16bd802fac70ad76bd463f81f0c518d1245b1c55e3d9"}, + {file = "numpy-2.2.2-cp313-cp313-win_amd64.whl", hash = "sha256:5a8c863ceacae696aff37d1fd636121f1a512117652e5dfb86031c8d84836369"}, + {file = "numpy-2.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b3482cb7b3325faa5f6bc179649406058253d91ceda359c104dac0ad320e1391"}, + {file = "numpy-2.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9491100aba630910489c1d0158034e1c9a6546f0b1340f716d522dc103788e39"}, + {file = "numpy-2.2.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:41184c416143defa34cc8eb9d070b0a5ba4f13a0fa96a709e20584638254b317"}, + {file = "numpy-2.2.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7dca87ca328f5ea7dafc907c5ec100d187911f94825f8700caac0b3f4c384b49"}, + {file = "numpy-2.2.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bc61b307655d1a7f9f4b043628b9f2b721e80839914ede634e3d485913e1fb2"}, + {file = "numpy-2.2.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fad446ad0bc886855ddf5909cbf8cb5d0faa637aaa6277fb4b19ade134ab3c7"}, + {file = "numpy-2.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:149d1113ac15005652e8d0d3f6fd599360e1a708a4f98e43c9c77834a28238cb"}, + {file = "numpy-2.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:106397dbbb1896f99e044efc90360d098b3335060375c26aa89c0d8a97c5f648"}, + {file = "numpy-2.2.2-cp313-cp313t-win32.whl", hash = "sha256:0eec19f8af947a61e968d5429f0bd92fec46d92b0008d0a6685b40d6adf8a4f4"}, + {file = "numpy-2.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:97b974d3ba0fb4612b77ed35d7627490e8e3dff56ab41454d9e8b23448940576"}, + {file = "numpy-2.2.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b0531f0b0e07643eb089df4c509d30d72c9ef40defa53e41363eca8a8cc61495"}, + {file = "numpy-2.2.2-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:e9e82dcb3f2ebbc8cb5ce1102d5f1c5ed236bf8a11730fb45ba82e2841ec21df"}, + {file = "numpy-2.2.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0d4142eb40ca6f94539e4db929410f2a46052a0fe7a2c1c59f6179c39938d2a"}, + {file = "numpy-2.2.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:356ca982c188acbfa6af0d694284d8cf20e95b1c3d0aefa8929376fea9146f60"}, + {file = "numpy-2.2.2.tar.gz", hash = "sha256:ed6906f61834d687738d25988ae117683705636936cc605be0bb208b23df4d8f"}, ] [[package]] @@ -1442,20 +1459,6 @@ pip = ">=23.1.2" graphviz = ["graphviz (>=0.20.1)"] test = ["covdefaults (>=2.3)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "virtualenv (>=20.25,<21)"] -[[package]] -name = "pkginfo" -version = "1.12.0" -description = "Query metadata from sdists / bdists / installed packages." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pkginfo-1.12.0-py3-none-any.whl", hash = "sha256:dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088"}, - {file = "pkginfo-1.12.0.tar.gz", hash = "sha256:8ad91a0445a036782b9366ef8b8c2c50291f83a553478ba8580c73d3215700cf"}, -] - -[package.extras] -testing = ["pytest", "pytest-cov", "wheel"] - [[package]] name = "platformdirs" version = "4.3.6" @@ -1524,13 +1527,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "4.0.1" +version = "4.1.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" files = [ - {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"}, + {file = "pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b"}, + {file = "pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4"}, ] [package.dependencies] @@ -2264,13 +2267,13 @@ jeepney = ">=0.6" [[package]] name = "selenium" -version = "4.27.1" +version = "4.28.0" description = "Official Python bindings for Selenium WebDriver" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "selenium-4.27.1-py3-none-any.whl", hash = "sha256:b89b1f62b5cfe8025868556fe82360d6b649d464f75d2655cb966c8f8447ea18"}, - {file = "selenium-4.27.1.tar.gz", hash = "sha256:5296c425a75ff1b44d0d5199042b36a6d1ef76c04fb775b97b40be739a9caae2"}, + {file = "selenium-4.28.0-py3-none-any.whl", hash = "sha256:3d6a2e8e1b850a1078884ea19f4e011ecdc12263434d87a0b78769836fb82dd8"}, + {file = "selenium-4.28.0.tar.gz", hash = "sha256:a9fae6eef48d470a1b0c6e45185d96f0dafb025e8da4b346cc41e4da3ac54fa0"}, ] [package.dependencies] @@ -2654,19 +2657,19 @@ wsproto = ">=0.14" [[package]] name = "twine" -version = "6.0.1" +version = "6.1.0" description = "Collection of utilities for publishing packages on PyPI" optional = false python-versions = ">=3.8" files = [ - {file = "twine-6.0.1-py3-none-any.whl", hash = "sha256:9c6025b203b51521d53e200f4a08b116dee7500a38591668c6a6033117bdc218"}, - {file = "twine-6.0.1.tar.gz", hash = "sha256:36158b09df5406e1c9c1fb8edb24fc2be387709443e7376689b938531582ee27"}, + {file = "twine-6.1.0-py3-none-any.whl", hash = "sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384"}, + {file = "twine-6.1.0.tar.gz", hash = "sha256:be324f6272eff91d07ee93f251edf232fc647935dd585ac003539b42404a8dbd"}, ] [package.dependencies] +id = "*" keyring = {version = ">=15.1", markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\""} -packaging = "*" -pkginfo = ">=1.8.1" +packaging = ">=24.0" readme-renderer = ">=35.0" requests = ">=2.20" requests-toolbelt = ">=0.8.0,<0.9.0 || >0.9.0" @@ -2707,13 +2710,13 @@ files = [ [[package]] name = "tzdata" -version = "2024.2" +version = "2025.1" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, - {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, + {file = "tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"}, + {file = "tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694"}, ] [[package]] @@ -2757,13 +2760,13 @@ standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", [[package]] name = "virtualenv" -version = "20.28.1" +version = "20.29.1" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" files = [ - {file = "virtualenv-20.28.1-py3-none-any.whl", hash = "sha256:412773c85d4dab0409b83ec36f7a6499e72eaf08c80e81e9576bca61831c71cb"}, - {file = "virtualenv-20.28.1.tar.gz", hash = "sha256:5d34ab240fdb5d21549b76f9e8ff3af28252f5499fb6d6f031adac4e5a8c5329"}, + {file = "virtualenv-20.29.1-py3-none-any.whl", hash = "sha256:4e4cb403c0b0da39e13b46b1b2476e505cb0046b25f242bee80f62bf990b2779"}, + {file = "virtualenv-20.29.1.tar.gz", hash = "sha256:b8b8970138d32fb606192cb97f6cd4bb644fa486be9308fb9b63f81091b5dc35"}, ] [package.dependencies] @@ -2793,80 +2796,80 @@ test = ["websockets"] [[package]] name = "websockets" -version = "14.1" +version = "14.2" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false python-versions = ">=3.9" files = [ - {file = "websockets-14.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a0adf84bc2e7c86e8a202537b4fd50e6f7f0e4a6b6bf64d7ccb96c4cd3330b29"}, - {file = "websockets-14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90b5d9dfbb6d07a84ed3e696012610b6da074d97453bd01e0e30744b472c8179"}, - {file = "websockets-14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2177ee3901075167f01c5e335a6685e71b162a54a89a56001f1c3e9e3d2ad250"}, - {file = "websockets-14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f14a96a0034a27f9d47fd9788913924c89612225878f8078bb9d55f859272b0"}, - {file = "websockets-14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f874ba705deea77bcf64a9da42c1f5fc2466d8f14daf410bc7d4ceae0a9fcb0"}, - {file = "websockets-14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9607b9a442392e690a57909c362811184ea429585a71061cd5d3c2b98065c199"}, - {file = "websockets-14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bea45f19b7ca000380fbd4e02552be86343080120d074b87f25593ce1700ad58"}, - {file = "websockets-14.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:219c8187b3ceeadbf2afcf0f25a4918d02da7b944d703b97d12fb01510869078"}, - {file = "websockets-14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad2ab2547761d79926effe63de21479dfaf29834c50f98c4bf5b5480b5838434"}, - {file = "websockets-14.1-cp310-cp310-win32.whl", hash = "sha256:1288369a6a84e81b90da5dbed48610cd7e5d60af62df9851ed1d1d23a9069f10"}, - {file = "websockets-14.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0744623852f1497d825a49a99bfbec9bea4f3f946df6eb9d8a2f0c37a2fec2e"}, - {file = "websockets-14.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:449d77d636f8d9c17952628cc7e3b8faf6e92a17ec581ec0c0256300717e1512"}, - {file = "websockets-14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a35f704be14768cea9790d921c2c1cc4fc52700410b1c10948511039be824aac"}, - {file = "websockets-14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b1f3628a0510bd58968c0f60447e7a692933589b791a6b572fcef374053ca280"}, - {file = "websockets-14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c3deac3748ec73ef24fc7be0b68220d14d47d6647d2f85b2771cb35ea847aa1"}, - {file = "websockets-14.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7048eb4415d46368ef29d32133134c513f507fff7d953c18c91104738a68c3b3"}, - {file = "websockets-14.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cf0ad281c979306a6a34242b371e90e891bce504509fb6bb5246bbbf31e7b6"}, - {file = "websockets-14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cc1fc87428c1d18b643479caa7b15db7d544652e5bf610513d4a3478dbe823d0"}, - {file = "websockets-14.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f95ba34d71e2fa0c5d225bde3b3bdb152e957150100e75c86bc7f3964c450d89"}, - {file = "websockets-14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9481a6de29105d73cf4515f2bef8eb71e17ac184c19d0b9918a3701c6c9c4f23"}, - {file = "websockets-14.1-cp311-cp311-win32.whl", hash = "sha256:368a05465f49c5949e27afd6fbe0a77ce53082185bbb2ac096a3a8afaf4de52e"}, - {file = "websockets-14.1-cp311-cp311-win_amd64.whl", hash = "sha256:6d24fc337fc055c9e83414c94e1ee0dee902a486d19d2a7f0929e49d7d604b09"}, - {file = "websockets-14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed907449fe5e021933e46a3e65d651f641975a768d0649fee59f10c2985529ed"}, - {file = "websockets-14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:87e31011b5c14a33b29f17eb48932e63e1dcd3fa31d72209848652310d3d1f0d"}, - {file = "websockets-14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bc6ccf7d54c02ae47a48ddf9414c54d48af9c01076a2e1023e3b486b6e72c707"}, - {file = "websockets-14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9777564c0a72a1d457f0848977a1cbe15cfa75fa2f67ce267441e465717dcf1a"}, - {file = "websockets-14.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a655bde548ca98f55b43711b0ceefd2a88a71af6350b0c168aa77562104f3f45"}, - {file = "websockets-14.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3dfff83ca578cada2d19e665e9c8368e1598d4e787422a460ec70e531dbdd58"}, - {file = "websockets-14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6a6c9bcf7cdc0fd41cc7b7944447982e8acfd9f0d560ea6d6845428ed0562058"}, - {file = "websockets-14.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4b6caec8576e760f2c7dd878ba817653144d5f369200b6ddf9771d64385b84d4"}, - {file = "websockets-14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eb6d38971c800ff02e4a6afd791bbe3b923a9a57ca9aeab7314c21c84bf9ff05"}, - {file = "websockets-14.1-cp312-cp312-win32.whl", hash = "sha256:1d045cbe1358d76b24d5e20e7b1878efe578d9897a25c24e6006eef788c0fdf0"}, - {file = "websockets-14.1-cp312-cp312-win_amd64.whl", hash = "sha256:90f4c7a069c733d95c308380aae314f2cb45bd8a904fb03eb36d1a4983a4993f"}, - {file = "websockets-14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3630b670d5057cd9e08b9c4dab6493670e8e762a24c2c94ef312783870736ab9"}, - {file = "websockets-14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36ebd71db3b89e1f7b1a5deaa341a654852c3518ea7a8ddfdf69cc66acc2db1b"}, - {file = "websockets-14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5b918d288958dc3fa1c5a0b9aa3256cb2b2b84c54407f4813c45d52267600cd3"}, - {file = "websockets-14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00fe5da3f037041da1ee0cf8e308374e236883f9842c7c465aa65098b1c9af59"}, - {file = "websockets-14.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8149a0f5a72ca36720981418eeffeb5c2729ea55fa179091c81a0910a114a5d2"}, - {file = "websockets-14.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77569d19a13015e840b81550922056acabc25e3f52782625bc6843cfa034e1da"}, - {file = "websockets-14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cf5201a04550136ef870aa60ad3d29d2a59e452a7f96b94193bee6d73b8ad9a9"}, - {file = "websockets-14.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:88cf9163ef674b5be5736a584c999e98daf3aabac6e536e43286eb74c126b9c7"}, - {file = "websockets-14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:836bef7ae338a072e9d1863502026f01b14027250a4545672673057997d5c05a"}, - {file = "websockets-14.1-cp313-cp313-win32.whl", hash = "sha256:0d4290d559d68288da9f444089fd82490c8d2744309113fc26e2da6e48b65da6"}, - {file = "websockets-14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8621a07991add373c3c5c2cf89e1d277e49dc82ed72c75e3afc74bd0acc446f0"}, - {file = "websockets-14.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:01bb2d4f0a6d04538d3c5dfd27c0643269656c28045a53439cbf1c004f90897a"}, - {file = "websockets-14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:414ffe86f4d6f434a8c3b7913655a1a5383b617f9bf38720e7c0799fac3ab1c6"}, - {file = "websockets-14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8fda642151d5affdee8a430bd85496f2e2517be3a2b9d2484d633d5712b15c56"}, - {file = "websockets-14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd7c11968bc3860d5c78577f0dbc535257ccec41750675d58d8dc66aa47fe52c"}, - {file = "websockets-14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a032855dc7db987dff813583d04f4950d14326665d7e714d584560b140ae6b8b"}, - {file = "websockets-14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7e7ea2f782408c32d86b87a0d2c1fd8871b0399dd762364c731d86c86069a78"}, - {file = "websockets-14.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:39450e6215f7d9f6f7bc2a6da21d79374729f5d052333da4d5825af8a97e6735"}, - {file = "websockets-14.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ceada5be22fa5a5a4cdeec74e761c2ee7db287208f54c718f2df4b7e200b8d4a"}, - {file = "websockets-14.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3fc753451d471cff90b8f467a1fc0ae64031cf2d81b7b34e1811b7e2691bc4bc"}, - {file = "websockets-14.1-cp39-cp39-win32.whl", hash = "sha256:14839f54786987ccd9d03ed7f334baec0f02272e7ec4f6e9d427ff584aeea8b4"}, - {file = "websockets-14.1-cp39-cp39-win_amd64.whl", hash = "sha256:d9fd19ecc3a4d5ae82ddbfb30962cf6d874ff943e56e0c81f5169be2fda62979"}, - {file = "websockets-14.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e5dc25a9dbd1a7f61eca4b7cb04e74ae4b963d658f9e4f9aad9cd00b688692c8"}, - {file = "websockets-14.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:04a97aca96ca2acedf0d1f332c861c5a4486fdcba7bcef35873820f940c4231e"}, - {file = "websockets-14.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df174ece723b228d3e8734a6f2a6febbd413ddec39b3dc592f5a4aa0aff28098"}, - {file = "websockets-14.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:034feb9f4286476f273b9a245fb15f02c34d9586a5bc936aff108c3ba1b21beb"}, - {file = "websockets-14.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c308dabd2b380807ab64b62985eaccf923a78ebc572bd485375b9ca2b7dc7"}, - {file = "websockets-14.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5a42d3ecbb2db5080fc578314439b1d79eef71d323dc661aa616fb492436af5d"}, - {file = "websockets-14.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddaa4a390af911da6f680be8be4ff5aaf31c4c834c1a9147bc21cbcbca2d4370"}, - {file = "websockets-14.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a4c805c6034206143fbabd2d259ec5e757f8b29d0a2f0bf3d2fe5d1f60147a4a"}, - {file = "websockets-14.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:205f672a6c2c671a86d33f6d47c9b35781a998728d2c7c2a3e1cf3333fcb62b7"}, - {file = "websockets-14.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef440054124728cc49b01c33469de06755e5a7a4e83ef61934ad95fc327fbb0"}, - {file = "websockets-14.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7591d6f440af7f73c4bd9404f3772bfee064e639d2b6cc8c94076e71b2471c1"}, - {file = "websockets-14.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:25225cc79cfebc95ba1d24cd3ab86aaa35bcd315d12fa4358939bd55e9bd74a5"}, - {file = "websockets-14.1-py3-none-any.whl", hash = "sha256:4d4fc827a20abe6d544a119896f6b78ee13fe81cbfef416f3f2ddf09a03f0e2e"}, - {file = "websockets-14.1.tar.gz", hash = "sha256:398b10c77d471c0aab20a845e7a60076b6390bfdaac7a6d2edb0d2c59d75e8d8"}, + {file = "websockets-14.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e8179f95323b9ab1c11723e5d91a89403903f7b001828161b480a7810b334885"}, + {file = "websockets-14.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d8c3e2cdb38f31d8bd7d9d28908005f6fa9def3324edb9bf336d7e4266fd397"}, + {file = "websockets-14.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:714a9b682deb4339d39ffa674f7b674230227d981a37d5d174a4a83e3978a610"}, + {file = "websockets-14.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e53c72052f2596fb792a7acd9704cbc549bf70fcde8a99e899311455974ca3"}, + {file = "websockets-14.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3fbd68850c837e57373d95c8fe352203a512b6e49eaae4c2f4088ef8cf21980"}, + {file = "websockets-14.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b27ece32f63150c268593d5fdb82819584831a83a3f5809b7521df0685cd5d8"}, + {file = "websockets-14.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4daa0faea5424d8713142b33825fff03c736f781690d90652d2c8b053345b0e7"}, + {file = "websockets-14.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:bc63cee8596a6ec84d9753fd0fcfa0452ee12f317afe4beae6b157f0070c6c7f"}, + {file = "websockets-14.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a570862c325af2111343cc9b0257b7119b904823c675b22d4ac547163088d0d"}, + {file = "websockets-14.2-cp310-cp310-win32.whl", hash = "sha256:75862126b3d2d505e895893e3deac0a9339ce750bd27b4ba515f008b5acf832d"}, + {file = "websockets-14.2-cp310-cp310-win_amd64.whl", hash = "sha256:cc45afb9c9b2dc0852d5c8b5321759cf825f82a31bfaf506b65bf4668c96f8b2"}, + {file = "websockets-14.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3bdc8c692c866ce5fefcaf07d2b55c91d6922ac397e031ef9b774e5b9ea42166"}, + {file = "websockets-14.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c93215fac5dadc63e51bcc6dceca72e72267c11def401d6668622b47675b097f"}, + {file = "websockets-14.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c9b6535c0e2cf8a6bf938064fb754aaceb1e6a4a51a80d884cd5db569886910"}, + {file = "websockets-14.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a52a6d7cf6938e04e9dceb949d35fbdf58ac14deea26e685ab6368e73744e4c"}, + {file = "websockets-14.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f05702e93203a6ff5226e21d9b40c037761b2cfb637187c9802c10f58e40473"}, + {file = "websockets-14.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22441c81a6748a53bfcb98951d58d1af0661ab47a536af08920d129b4d1c3473"}, + {file = "websockets-14.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd9b868d78b194790e6236d9cbc46d68aba4b75b22497eb4ab64fa640c3af56"}, + {file = "websockets-14.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1a5a20d5843886d34ff8c57424cc65a1deda4375729cbca4cb6b3353f3ce4142"}, + {file = "websockets-14.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:34277a29f5303d54ec6468fb525d99c99938607bc96b8d72d675dee2b9f5bf1d"}, + {file = "websockets-14.2-cp311-cp311-win32.whl", hash = "sha256:02687db35dbc7d25fd541a602b5f8e451a238ffa033030b172ff86a93cb5dc2a"}, + {file = "websockets-14.2-cp311-cp311-win_amd64.whl", hash = "sha256:862e9967b46c07d4dcd2532e9e8e3c2825e004ffbf91a5ef9dde519ee2effb0b"}, + {file = "websockets-14.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1f20522e624d7ffbdbe259c6b6a65d73c895045f76a93719aa10cd93b3de100c"}, + {file = "websockets-14.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:647b573f7d3ada919fd60e64d533409a79dcf1ea21daeb4542d1d996519ca967"}, + {file = "websockets-14.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6af99a38e49f66be5a64b1e890208ad026cda49355661549c507152113049990"}, + {file = "websockets-14.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:091ab63dfc8cea748cc22c1db2814eadb77ccbf82829bac6b2fbe3401d548eda"}, + {file = "websockets-14.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b374e8953ad477d17e4851cdc66d83fdc2db88d9e73abf755c94510ebddceb95"}, + {file = "websockets-14.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a39d7eceeea35db85b85e1169011bb4321c32e673920ae9c1b6e0978590012a3"}, + {file = "websockets-14.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a6f3efd47ffd0d12080594f434faf1cd2549b31e54870b8470b28cc1d3817d9"}, + {file = "websockets-14.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:065ce275e7c4ffb42cb738dd6b20726ac26ac9ad0a2a48e33ca632351a737267"}, + {file = "websockets-14.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e9d0e53530ba7b8b5e389c02282f9d2aa47581514bd6049d3a7cffe1385cf5fe"}, + {file = "websockets-14.2-cp312-cp312-win32.whl", hash = "sha256:20e6dd0984d7ca3037afcb4494e48c74ffb51e8013cac71cf607fffe11df7205"}, + {file = "websockets-14.2-cp312-cp312-win_amd64.whl", hash = "sha256:44bba1a956c2c9d268bdcdf234d5e5ff4c9b6dc3e300545cbe99af59dda9dcce"}, + {file = "websockets-14.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f1372e511c7409a542291bce92d6c83320e02c9cf392223272287ce55bc224e"}, + {file = "websockets-14.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4da98b72009836179bb596a92297b1a61bb5a830c0e483a7d0766d45070a08ad"}, + {file = "websockets-14.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8a86a269759026d2bde227652b87be79f8a734e582debf64c9d302faa1e9f03"}, + {file = "websockets-14.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86cf1aaeca909bf6815ea714d5c5736c8d6dd3a13770e885aafe062ecbd04f1f"}, + {file = "websockets-14.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b0f6c3ba3b1240f602ebb3971d45b02cc12bd1845466dd783496b3b05783a5"}, + {file = "websockets-14.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669c3e101c246aa85bc8534e495952e2ca208bd87994650b90a23d745902db9a"}, + {file = "websockets-14.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eabdb28b972f3729348e632ab08f2a7b616c7e53d5414c12108c29972e655b20"}, + {file = "websockets-14.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2066dc4cbcc19f32c12a5a0e8cc1b7ac734e5b64ac0a325ff8353451c4b15ef2"}, + {file = "websockets-14.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ab95d357cd471df61873dadf66dd05dd4709cae001dd6342edafc8dc6382f307"}, + {file = "websockets-14.2-cp313-cp313-win32.whl", hash = "sha256:a9e72fb63e5f3feacdcf5b4ff53199ec8c18d66e325c34ee4c551ca748623bbc"}, + {file = "websockets-14.2-cp313-cp313-win_amd64.whl", hash = "sha256:b439ea828c4ba99bb3176dc8d9b933392a2413c0f6b149fdcba48393f573377f"}, + {file = "websockets-14.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7cd5706caec1686c5d233bc76243ff64b1c0dc445339bd538f30547e787c11fe"}, + {file = "websockets-14.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ec607328ce95a2f12b595f7ae4c5d71bf502212bddcea528290b35c286932b12"}, + {file = "websockets-14.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da85651270c6bfb630136423037dd4975199e5d4114cae6d3066641adcc9d1c7"}, + {file = "websockets-14.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ecadc7ce90accf39903815697917643f5b7cfb73c96702318a096c00aa71f5"}, + {file = "websockets-14.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1979bee04af6a78608024bad6dfcc0cc930ce819f9e10342a29a05b5320355d0"}, + {file = "websockets-14.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dddacad58e2614a24938a50b85969d56f88e620e3f897b7d80ac0d8a5800258"}, + {file = "websockets-14.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:89a71173caaf75fa71a09a5f614f450ba3ec84ad9fca47cb2422a860676716f0"}, + {file = "websockets-14.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6af6a4b26eea4fc06c6818a6b962a952441e0e39548b44773502761ded8cc1d4"}, + {file = "websockets-14.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:80c8efa38957f20bba0117b48737993643204645e9ec45512579132508477cfc"}, + {file = "websockets-14.2-cp39-cp39-win32.whl", hash = "sha256:2e20c5f517e2163d76e2729104abc42639c41cf91f7b1839295be43302713661"}, + {file = "websockets-14.2-cp39-cp39-win_amd64.whl", hash = "sha256:b4c8cef610e8d7c70dea92e62b6814a8cd24fbd01d7103cc89308d2bfe1659ef"}, + {file = "websockets-14.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d7d9cafbccba46e768be8a8ad4635fa3eae1ffac4c6e7cb4eb276ba41297ed29"}, + {file = "websockets-14.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c76193c1c044bd1e9b3316dcc34b174bbf9664598791e6fb606d8d29000e070c"}, + {file = "websockets-14.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd475a974d5352390baf865309fe37dec6831aafc3014ffac1eea99e84e83fc2"}, + {file = "websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c6c0097a41968b2e2b54ed3424739aab0b762ca92af2379f152c1aef0187e1c"}, + {file = "websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d7ff794c8b36bc402f2e07c0b2ceb4a2424147ed4785ff03e2a7af03711d60a"}, + {file = "websockets-14.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dec254fcabc7bd488dab64846f588fc5b6fe0d78f641180030f8ea27b76d72c3"}, + {file = "websockets-14.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bbe03eb853e17fd5b15448328b4ec7fb2407d45fb0245036d06a3af251f8e48f"}, + {file = "websockets-14.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3c4aa3428b904d5404a0ed85f3644d37e2cb25996b7f096d77caeb0e96a3b42"}, + {file = "websockets-14.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:577a4cebf1ceaf0b65ffc42c54856214165fb8ceeba3935852fc33f6b0c55e7f"}, + {file = "websockets-14.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad1c1d02357b7665e700eca43a31d52814ad9ad9b89b58118bdabc365454b574"}, + {file = "websockets-14.2-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f390024a47d904613577df83ba700bd189eedc09c57af0a904e5c39624621270"}, + {file = "websockets-14.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3c1426c021c38cf92b453cdf371228d3430acd775edee6bac5a4d577efc72365"}, + {file = "websockets-14.2-py3-none-any.whl", hash = "sha256:7a6ceec4ea84469f15cf15807a747e9efe57e369c384fa86e022b3bea679b79b"}, + {file = "websockets-14.2.tar.gz", hash = "sha256:5059ed9c54945efb321f097084b4c7e52c246f2c869815876a69d1efc4ad6eb5"}, ] [[package]] diff --git a/reflex/components/core/upload.py b/reflex/components/core/upload.py index 14205cc6b..4666a8f1b 100644 --- a/reflex/components/core/upload.py +++ b/reflex/components/core/upload.py @@ -192,7 +192,7 @@ class GhostUpload(Fragment): class Upload(MemoizationLeaf): """A file upload component.""" - library = "react-dropzone@14.2.10" + library = "react-dropzone@14.3.5" tag = "" diff --git a/reflex/components/datadisplay/code.py b/reflex/components/datadisplay/code.py index dca2393cd..242e812b2 100644 --- a/reflex/components/datadisplay/code.py +++ b/reflex/components/datadisplay/code.py @@ -382,7 +382,7 @@ for theme_name in dir(Theme): class CodeBlock(Component, MarkdownComponentMap): """A code block.""" - library = "react-syntax-highlighter@15.6.0" + library = "react-syntax-highlighter@15.6.1" tag = "PrismAsyncLight" diff --git a/reflex/components/plotly/plotly.py b/reflex/components/plotly/plotly.py index 3bdef7875..68efd4545 100644 --- a/reflex/components/plotly/plotly.py +++ b/reflex/components/plotly/plotly.py @@ -95,7 +95,7 @@ class Plotly(NoSSRComponent): library = "react-plotly.js@2.6.0" - lib_dependencies: List[str] = ["plotly.js@2.35.2"] + lib_dependencies: List[str] = ["plotly.js@2.35.3"] tag = "Plot" diff --git a/reflex/components/recharts/recharts.py b/reflex/components/recharts/recharts.py index b5a4ed113..d3fc20dc1 100644 --- a/reflex/components/recharts/recharts.py +++ b/reflex/components/recharts/recharts.py @@ -8,7 +8,7 @@ from reflex.components.component import Component, MemoizationLeaf, NoSSRCompone class Recharts(Component): """A component that wraps a recharts lib.""" - library = "recharts@2.13.0" + library = "recharts@2.15.0" def _get_style(self) -> Dict: return {"wrapperStyle": self.style} @@ -17,7 +17,7 @@ class Recharts(Component): class RechartsCharts(NoSSRComponent, MemoizationLeaf): """A component that wraps a recharts lib.""" - library = "recharts@2.13.0" + library = "recharts@2.15.0" LiteralAnimationEasing = Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"] diff --git a/reflex/components/sonner/toast.py b/reflex/components/sonner/toast.py index b978409ab..7177c6473 100644 --- a/reflex/components/sonner/toast.py +++ b/reflex/components/sonner/toast.py @@ -167,7 +167,7 @@ class ToastProps(PropsBase, NoExtrasAllowedProps): class Toaster(Component): """A Toaster Component for displaying toast notifications.""" - library: str = "sonner@1.7.1" + library: str = "sonner@1.7.2" tag = "Toaster" diff --git a/reflex/constants/installer.py b/reflex/constants/installer.py index f9dd26b5a..2176bdf3a 100644 --- a/reflex/constants/installer.py +++ b/reflex/constants/installer.py @@ -178,21 +178,21 @@ class PackageJson(SimpleNamespace): PATH = "package.json" DEPENDENCIES = { - "@babel/standalone": "7.26.0", - "@emotion/react": "11.13.3", - "axios": "1.7.7", + "@babel/standalone": "7.26.6", + "@emotion/react": "11.14.0", + "axios": "1.7.9", "json5": "2.2.3", - "next": "15.1.4", + "next": "15.1.6", "next-sitemap": "4.2.3", - "next-themes": "0.4.3", + "next-themes": "0.4.4", "react": "18.3.1", "react-dom": "18.3.1", - "react-focus-lock": "2.13.2", + "react-focus-lock": "2.13.5", "socket.io-client": "4.8.1", "universal-cookie": "7.2.2", } DEV_DEPENDENCIES = { "autoprefixer": "10.4.20", - "postcss": "8.4.49", + "postcss": "8.5.1", "postcss-import": "16.1.0", } diff --git a/reflex/constants/style.py b/reflex/constants/style.py index a1d30bcca..5b31ce9b3 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.15" + VERSION = "tailwindcss@3.4.17" # The Tailwind config. CONFIG = "tailwind.config.js" # Default Tailwind content paths From 1106aae76ecd3906d0ccbf482b5f945615927019 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 22 Jan 2025 15:18:35 -0800 Subject: [PATCH 02/12] remove integration screenshots (#4677) --- .github/workflows/integration_app_harness.yml | 7 ----- reflex/config.py | 3 -- tests/integration/conftest.py | 30 ------------------- 3 files changed, 40 deletions(-) diff --git a/.github/workflows/integration_app_harness.yml b/.github/workflows/integration_app_harness.yml index 5e88fc412..0bafd3601 100644 --- a/.github/workflows/integration_app_harness.yml +++ b/.github/workflows/integration_app_harness.yml @@ -50,14 +50,7 @@ jobs: - run: poetry run uv pip install pyvirtualdisplay pillow pytest-split pytest-retry - name: Run app harness tests env: - SCREENSHOT_DIR: /tmp/screenshots/${{ matrix.state_manager }}/${{ matrix.python-version }}/${{ matrix.split_index }} REDIS_URL: ${{ matrix.state_manager == 'redis' && 'redis://localhost:6379' || '' }} run: | poetry run playwright install chromium poetry run pytest tests/integration --retries 3 --maxfail=5 --splits 2 --group ${{matrix.split_index}} - - uses: actions/upload-artifact@v4 - name: Upload failed test screenshots - if: always() - with: - name: failed_test_screenshots - path: /tmp/screenshots diff --git a/reflex/config.py b/reflex/config.py index 8511694fb..d5eee8dfd 100644 --- a/reflex/config.py +++ b/reflex/config.py @@ -556,9 +556,6 @@ class EnvironmentVariables: # Arguments to pass to the app harness driver. APP_HARNESS_DRIVER_ARGS: EnvVar[str] = env_var("") - # Where to save screenshots when tests fail. - SCREENSHOT_DIR: EnvVar[Optional[Path]] = env_var(None) - # Whether to check for outdated package versions. REFLEX_CHECK_LATEST_VERSION: EnvVar[bool] = env_var(True) diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index d11344903..67bd26c49 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -1,8 +1,6 @@ """Shared conftest for all integration tests.""" import os -import re -from pathlib import Path import pytest @@ -36,34 +34,6 @@ def xvfb(): yield None -def pytest_exception_interact(node, call, report): - """Take and upload screenshot when tests fail. - - Args: - node: The pytest item that failed. - call: The pytest call describing when/where the test was invoked. - report: The pytest log report object. - """ - screenshot_dir = environment.SCREENSHOT_DIR.get() - if DISPLAY is None or screenshot_dir is None: - return - - screenshot_dir = Path(screenshot_dir) - screenshot_dir.mkdir(parents=True, exist_ok=True) - safe_filename = re.sub( - r"(?u)[^-\w.]", - "_", - str(node.nodeid).strip().replace(" ", "_").replace(":", "_").replace(".py", ""), - ) - - try: - DISPLAY.waitgrab().save( - (Path(screenshot_dir) / safe_filename).with_suffix(".png"), - ) - except Exception as e: - print(f"Failed to take screenshot for {node}: {e}") - - @pytest.fixture( scope="session", params=[AppHarness, AppHarnessProd], ids=["dev", "prod"] ) From 8dea68278126645ae31b6eb20af188d6b5b84c38 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 22 Jan 2025 15:19:25 -0800 Subject: [PATCH 03/12] update bun to 1.2.0 (#4678) --- reflex/constants/installer.py | 4 ++-- reflex/utils/prerequisites.py | 1 + scripts/bun_install.sh | 29 ++++++++++++++++++++--------- scripts/install.ps1 | 4 ++++ 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/reflex/constants/installer.py b/reflex/constants/installer.py index 2176bdf3a..0a89240b3 100644 --- a/reflex/constants/installer.py +++ b/reflex/constants/installer.py @@ -37,10 +37,10 @@ class Bun(SimpleNamespace): """Bun constants.""" # The Bun version. - VERSION = "1.1.29" + VERSION = "1.2.0" # Min Bun Version - MIN_VERSION = "0.7.0" + MIN_VERSION = "1.1.0" # URL to bun install script. INSTALL_URL = "https://raw.githubusercontent.com/reflex-dev/reflex/main/scripts/bun_install.sh" diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index 1411e4970..1f898d1a1 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -921,6 +921,7 @@ def install_bun(): constants.Bun.INSTALL_URL, f"bun-v{constants.Bun.VERSION}", BUN_INSTALL=str(constants.Bun.ROOT_PATH), + BUN_VERSION=str(constants.Bun.VERSION), ) diff --git a/scripts/bun_install.sh b/scripts/bun_install.sh index 08a0817f6..6961544ad 100644 --- a/scripts/bun_install.sh +++ b/scripts/bun_install.sh @@ -78,6 +78,14 @@ case $platform in ;; esac +case "$target" in +'linux'*) + if [ -f /etc/alpine-release ]; then + target="$target-musl" + fi + ;; +esac + if [[ $target = darwin-x64 ]]; then # Is this process running in Rosetta? # redirect stderr to devnull to avoid error message when not running in Rosetta @@ -91,19 +99,20 @@ GITHUB=${GITHUB-"https://github.com"} github_repo="$GITHUB/oven-sh/bun" -if [[ $target = darwin-x64 ]]; then - # If AVX2 isn't supported, use the -baseline build +# If AVX2 isn't supported, use the -baseline build +case "$target" in +'darwin-x64'*) if [[ $(sysctl -a | grep machdep.cpu | grep AVX2) == '' ]]; then - target=darwin-x64-baseline + target="$target-baseline" fi -fi - -if [[ $target = linux-x64 ]]; then + ;; +'linux-x64'*) # If AVX2 isn't supported, use the -baseline build if [[ $(cat /proc/cpuinfo | grep avx2) = '' ]]; then - target=linux-x64-baseline + target="$target-baseline" fi -fi + ;; +esac exe_name=bun @@ -113,8 +122,10 @@ if [[ $# = 2 && $2 = debug-info ]]; then info "You requested a debug build of bun. More information will be shown if a crash occurs." fi +bun_version=BUN_VERSION + if [[ $# = 0 ]]; then - bun_uri=$github_repo/releases/latest/download/bun-$target.zip + bun_uri=$github_repo/releases/download/bun-v$bun_version/bun-$target.zip else bun_uri=$github_repo/releases/download/$1/bun-$target.zip fi diff --git a/scripts/install.ps1 b/scripts/install.ps1 index 3c432ac3b..52f1bcc14 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -214,8 +214,12 @@ function Install-Bun { # http://community.sqlbackupandftp.com/t/error-1073741515-solved/1305 if (($LASTEXITCODE -eq 3221225781) -or ($LASTEXITCODE -eq -1073741515)) # STATUS_DLL_NOT_FOUND { + # TODO: as of July 2024, Bun has no external dependencies. + # I want to keep this error message in for a few months to ensure that + # if someone somehow runs into this, it can be reported. Write-Output "Install Failed - You are missing a DLL required to run bun.exe" Write-Output "This can be solved by installing the Visual C++ Redistributable from Microsoft:`nSee https://learn.microsoft.com/cpp/windows/latest-supported-vc-redist`nDirect Download -> https://aka.ms/vs/17/release/vc_redist.x64.exe`n`n" + Write-Output "The error above should be unreachable as Bun does not depend on this library. Please comment in https://github.com/oven-sh/bun/issues/8598 or open a new issue.`n`n" Write-Output "The command '${BunBin}\bun.exe --revision' exited with code ${LASTEXITCODE}`n" return 1 } From 0139cab13f6813bc4a52bfc3b5a5430b065c581e Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 22 Jan 2025 15:23:06 -0800 Subject: [PATCH 04/12] refactor client state to restore prior API (#4674) * refactor client state to restore prior API * maybe add that --- reflex/experimental/client_state.py | 74 ++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 23 deletions(-) diff --git a/reflex/experimental/client_state.py b/reflex/experimental/client_state.py index 45dfef237..ca91905ae 100644 --- a/reflex/experimental/client_state.py +++ b/reflex/experimental/client_state.py @@ -34,6 +34,18 @@ def _client_state_ref(var_name: str) -> str: return f"refs['_client_state_{var_name}']" +def _client_state_ref_dict(var_name: str) -> str: + """Get the ref path for a ClientStateVar. + + Args: + var_name: The name of the variable. + + Returns: + An accessor for ClientStateVar ref as a string. + """ + return f"refs['_client_state_dict_{var_name}']" + + @dataclasses.dataclass( eq=False, frozen=True, @@ -115,10 +127,41 @@ class ClientStateVar(Var): "react": [ImportVar(tag="useState"), ImportVar(tag="useId")], } if global_ref: - hooks[f"{_client_state_ref(var_name)} ??= {{}}"] = None - hooks[f"{_client_state_ref(setter_name)} ??= {{}}"] = None - hooks[f"{_client_state_ref(var_name)}[{id_name}] = {var_name}"] = None - hooks[f"{_client_state_ref(setter_name)}[{id_name}] = {setter_name}"] = None + arg_name = get_unique_variable_name() + func = ArgsFunctionOperationBuilder.create( + args_names=(arg_name,), + return_expr=Var("Array.prototype.forEach.call") + .to(FunctionVar) + .call( + ( + Var("Object.values") + .to(FunctionVar) + .call(Var(_client_state_ref_dict(setter_name))) + .to(list) + .to(list) + ) + + Var.create( + [ + Var( + f"(value) => {{ {_client_state_ref(var_name)} = value; }}" + ) + ] + ).to(list), + ArgsFunctionOperationBuilder.create( + args_names=("setter",), + return_expr=Var("setter").to(FunctionVar).call(Var(arg_name)), + ), + ), + ) + + hooks[f"{_client_state_ref(setter_name)} = {func!s}"] = None + hooks[f"{_client_state_ref(var_name)} ??= {var_name!s}"] = None + hooks[f"{_client_state_ref_dict(var_name)} ??= {{}}"] = None + hooks[f"{_client_state_ref_dict(setter_name)} ??= {{}}"] = None + hooks[f"{_client_state_ref_dict(var_name)}[{id_name}] = {var_name}"] = None + hooks[ + f"{_client_state_ref_dict(setter_name)}[{id_name}] = {setter_name}" + ] = None imports.update(_refs_import) return cls( _js_expr="", @@ -150,7 +193,7 @@ class ClientStateVar(Var): return ( Var( _js_expr=( - _client_state_ref(self._getter_name) + f"[{self._id_name}]" + _client_state_ref_dict(self._getter_name) + f"[{self._id_name}]" if self._global_ref else self._getter_name ), @@ -179,26 +222,11 @@ class ClientStateVar(Var): """ _var_data = VarData(imports=_refs_import if self._global_ref else {}) - arg_name = get_unique_variable_name() setter = ( - ArgsFunctionOperationBuilder.create( - args_names=(arg_name,), - return_expr=Var("Array.prototype.forEach.call") - .to(FunctionVar) - .call( - Var("Object.values") - .to(FunctionVar) - .call(Var(_client_state_ref(self._setter_name))), - ArgsFunctionOperationBuilder.create( - args_names=("setter",), - return_expr=Var("setter").to(FunctionVar).call(Var(arg_name)), - ), - ), - _var_data=_var_data, - ) + Var(_client_state_ref(self._setter_name)) if self._global_ref - else Var(self._setter_name, _var_data=_var_data).to(FunctionVar) - ) + else Var(self._setter_name, _var_data=_var_data) + ).to(FunctionVar) if value is not NoValue: # This is a hack to make it work like an EventSpec taking an arg From 818788da633c6cf28eac3045d8d00267f564ffd8 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Wed, 22 Jan 2025 15:23:34 -0800 Subject: [PATCH 05/12] Do not track compile in posthog metrics (#4669) --- reflex/app_module_for_backend.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/reflex/app_module_for_backend.py b/reflex/app_module_for_backend.py index b0ae0a29f..28be30410 100644 --- a/reflex/app_module_for_backend.py +++ b/reflex/app_module_for_backend.py @@ -5,14 +5,12 @@ Only the app attribute is explicitly exposed. from concurrent.futures import ThreadPoolExecutor from reflex import constants -from reflex.utils import telemetry from reflex.utils.exec import is_prod_mode from reflex.utils.prerequisites import get_and_validate_app if constants.CompileVars.APP != "app": raise AssertionError("unexpected variable name for 'app'") -telemetry.send("compile") app, app_module = get_and_validate_app(reload=False) # For py3.9 compatibility when redis is used, we MUST add any decorator pages # before compiling the app in a thread to avoid event loop error (REF-2172). @@ -31,6 +29,5 @@ del app_module del compile_future del get_and_validate_app del is_prod_mode -del telemetry del constants del ThreadPoolExecutor From 1ca36fa6c157c27caef4e733dfc1db2e23f8d52e Mon Sep 17 00:00:00 2001 From: Elijah Ahianyo Date: Wed, 22 Jan 2025 23:26:12 +0000 Subject: [PATCH 06/12] [ENG-1796]`reflex rename`- B (#4668) * `reflex rename`- B * add unit tests * precommit * dont need this comment * move loglevel * calm down, darglint * add current dir to sys path --- reflex/constants/compiler.py | 2 + reflex/reflex.py | 14 +++ reflex/utils/prerequisites.py | 162 ++++++++++++++++++++++++++++++ tests/units/test_prerequisites.py | 161 +++++++++++++++++++++++++++++ 4 files changed, 339 insertions(+) diff --git a/reflex/constants/compiler.py b/reflex/constants/compiler.py index d98c04d76..dc5d80fe0 100644 --- a/reflex/constants/compiler.py +++ b/reflex/constants/compiler.py @@ -28,6 +28,8 @@ class Ext(SimpleNamespace): ZIP = ".zip" # The extension for executable files on Windows. EXE = ".exe" + # The extension for markdown files. + MD = ".md" class CompileVars(SimpleNamespace): diff --git a/reflex/reflex.py b/reflex/reflex.py index 29aef024f..34a4a58a5 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -573,6 +573,20 @@ def deploy( ) +@cli.command() +def rename( + new_name: str = typer.Argument(..., help="The new name for the app."), + loglevel: constants.LogLevel = typer.Option( + config.loglevel, help="The log level to use." + ), +): + """Rename the app in the current directory.""" + from reflex.utils import prerequisites + + prerequisites.validate_app_name(new_name) + prerequisites.rename_app(new_name, loglevel) + + 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/utils/prerequisites.py b/reflex/utils/prerequisites.py index 1f898d1a1..1e33c4b8a 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -7,6 +7,7 @@ import dataclasses import functools import importlib import importlib.metadata +import importlib.util import json import os import platform @@ -463,6 +464,167 @@ def validate_app_name(app_name: str | None = None) -> str: return app_name +def rename_path_up_tree(full_path: str | Path, old_name: str, new_name: str) -> Path: + """Rename all instances of `old_name` in the path (file and directories) to `new_name`. + The renaming stops when we reach the directory containing `rxconfig.py`. + + Args: + full_path: The full path to start renaming from. + old_name: The name to be replaced. + new_name: The replacement name. + + Returns: + The updated path after renaming. + """ + current_path = Path(full_path) + new_path = None + + while True: + directory, base = current_path.parent, current_path.name + # Stop renaming when we reach the root dir (which contains rxconfig.py) + if current_path.is_dir() and (current_path / "rxconfig.py").exists(): + new_path = current_path + break + + if old_name == base.removesuffix(constants.Ext.PY): + new_base = base.replace(old_name, new_name) + new_path = directory / new_base + current_path.rename(new_path) + console.debug(f"Renamed {current_path} -> {new_path}") + current_path = new_path + else: + new_path = current_path + + # Move up the directory tree + current_path = directory + + return new_path + + +def rename_app(new_app_name: str, loglevel: constants.LogLevel): + """Rename the app directory. + + Args: + new_app_name: The new name for the app. + loglevel: The log level to use. + + Raises: + Exit: If the command is not ran in the root dir or the app module cannot be imported. + """ + # Set the log level. + console.set_log_level(loglevel) + + if not constants.Config.FILE.exists(): + console.error( + "No rxconfig.py found. Make sure you are in the root directory of your app." + ) + raise typer.Exit(1) + + sys.path.insert(0, str(Path.cwd())) + + config = get_config() + module_path = importlib.util.find_spec(config.module) + if module_path is None: + console.error(f"Could not find module {config.module}.") + raise typer.Exit(1) + + if not module_path.origin: + console.error(f"Could not find origin for module {config.module}.") + raise typer.Exit(1) + console.info(f"Renaming app directory to {new_app_name}.") + process_directory( + Path.cwd(), + config.app_name, + new_app_name, + exclude_dirs=[constants.Dirs.WEB, constants.Dirs.APP_ASSETS], + ) + + rename_path_up_tree(Path(module_path.origin), config.app_name, new_app_name) + + console.success(f"App directory renamed to [bold]{new_app_name}[/bold].") + + +def rename_imports_and_app_name(file_path: str | Path, old_name: str, new_name: str): + """Rename imports the file using string replacement as well as app_name in rxconfig.py. + + Args: + file_path: The file to process. + old_name: The old name to replace. + new_name: The new name to use. + """ + file_path = Path(file_path) + content = file_path.read_text() + + # Replace `from old_name.` or `from old_name` with `from new_name` + content = re.sub( + rf"\bfrom {re.escape(old_name)}(\b|\.|\s)", + lambda match: f"from {new_name}{match.group(1)}", + content, + ) + + # Replace `import old_name` with `import new_name` + content = re.sub( + rf"\bimport {re.escape(old_name)}\b", + f"import {new_name}", + content, + ) + + # Replace `app_name="old_name"` in rx.Config + content = re.sub( + rf'\bapp_name\s*=\s*["\']{re.escape(old_name)}["\']', + f'app_name="{new_name}"', + content, + ) + + # Replace positional argument `"old_name"` in rx.Config + content = re.sub( + rf'\brx\.Config\(\s*["\']{re.escape(old_name)}["\']', + f'rx.Config("{new_name}"', + content, + ) + + file_path.write_text(content) + + +def process_directory( + directory: str | Path, + old_name: str, + new_name: str, + exclude_dirs: list | None = None, + extensions: list | None = None, +): + """Process files with specified extensions in a directory, excluding specified directories. + + Args: + directory: The root directory to process. + old_name: The old name to replace. + new_name: The new name to use. + exclude_dirs: List of directory names to exclude. Defaults to None. + extensions: List of file extensions to process. + """ + exclude_dirs = exclude_dirs or [] + extensions = extensions or [ + constants.Ext.PY, + constants.Ext.MD, + ] # include .md files, typically used in reflex-web. + extensions_set = {ext.lstrip(".") for ext in extensions} + directory = Path(directory) + + root_exclude_dirs = {directory / exclude_dir for exclude_dir in exclude_dirs} + + files = ( + p.resolve() + for p in directory.glob("**/*") + if p.is_file() and p.suffix.lstrip(".") in extensions_set + ) + + for file_path in files: + if not any( + file_path.is_relative_to(exclude_dir) for exclude_dir in root_exclude_dirs + ): + rename_imports_and_app_name(file_path, old_name, new_name) + + def create_config(app_name: str): """Create a new rxconfig file. diff --git a/tests/units/test_prerequisites.py b/tests/units/test_prerequisites.py index 90afe0963..cf655d6cd 100644 --- a/tests/units/test_prerequisites.py +++ b/tests/units/test_prerequisites.py @@ -1,20 +1,28 @@ import json import re +import shutil import tempfile +from pathlib import Path from unittest.mock import Mock, mock_open import pytest +from typer.testing import CliRunner from reflex import constants from reflex.config import Config +from reflex.reflex import cli +from reflex.testing import chdir from reflex.utils.prerequisites import ( CpuInfo, _update_next_config, cached_procedure, get_cpu_info, initialize_requirements_txt, + rename_imports_and_app_name, ) +runner = CliRunner() + @pytest.mark.parametrize( "config, export, expected_output", @@ -224,3 +232,156 @@ def test_get_cpu_info(): for attr in ("manufacturer_id", "model_name", "address_width"): value = getattr(cpu_info, attr) assert value.strip() if attr != "address_width" else value + + +@pytest.fixture +def temp_directory(): + temp_dir = tempfile.mkdtemp() + yield Path(temp_dir) + shutil.rmtree(temp_dir) + + +@pytest.mark.parametrize( + "config_code,expected", + [ + ("rx.Config(app_name='old_name')", 'rx.Config(app_name="new_name")'), + ('rx.Config(app_name="old_name")', 'rx.Config(app_name="new_name")'), + ("rx.Config('old_name')", 'rx.Config("new_name")'), + ('rx.Config("old_name")', 'rx.Config("new_name")'), + ], +) +def test_rename_imports_and_app_name(temp_directory, config_code, expected): + file_path = temp_directory / "rxconfig.py" + content = f""" +config = {config_code} +""" + file_path.write_text(content) + + rename_imports_and_app_name(file_path, "old_name", "new_name") + + updated_content = file_path.read_text() + expected_content = f""" +config = {expected} +""" + assert updated_content == expected_content + + +def test_regex_edge_cases(temp_directory): + file_path = temp_directory / "example.py" + content = """ +from old_name.module import something +import old_name +from old_name import something_else as alias +from old_name +""" + file_path.write_text(content) + + rename_imports_and_app_name(file_path, "old_name", "new_name") + + updated_content = file_path.read_text() + expected_content = """ +from new_name.module import something +import new_name +from new_name import something_else as alias +from new_name +""" + assert updated_content == expected_content + + +def test_cli_rename_command(temp_directory): + foo_dir = temp_directory / "foo" + foo_dir.mkdir() + (foo_dir / "__init__").touch() + (foo_dir / ".web").mkdir() + (foo_dir / "assets").mkdir() + (foo_dir / "foo").mkdir() + (foo_dir / "foo" / "__init__.py").touch() + (foo_dir / "rxconfig.py").touch() + (foo_dir / "rxconfig.py").write_text( + """ +import reflex as rx + +config = rx.Config( + app_name="foo", +) +""" + ) + (foo_dir / "foo" / "components").mkdir() + (foo_dir / "foo" / "components" / "__init__.py").touch() + (foo_dir / "foo" / "components" / "base.py").touch() + (foo_dir / "foo" / "components" / "views.py").touch() + (foo_dir / "foo" / "components" / "base.py").write_text( + """ +import reflex as rx +from foo.components import views +from foo.components.views import * +from .base import * + +def random_component(): + return rx.fragment() +""" + ) + (foo_dir / "foo" / "foo.py").touch() + (foo_dir / "foo" / "foo.py").write_text( + """ +import reflex as rx +import foo.components.base +from foo.components.base import random_component + +class State(rx.State): + pass + + +def index(): + return rx.text("Hello, World!") + +app = rx.App() +app.add_page(index) +""" + ) + + with chdir(temp_directory / "foo"): + result = runner.invoke(cli, ["rename", "bar"]) + + assert result.exit_code == 0 + assert (foo_dir / "rxconfig.py").read_text() == ( + """ +import reflex as rx + +config = rx.Config( + app_name="bar", +) +""" + ) + assert (foo_dir / "bar").exists() + assert not (foo_dir / "foo").exists() + assert (foo_dir / "bar" / "components" / "base.py").read_text() == ( + """ +import reflex as rx +from bar.components import views +from bar.components.views import * +from .base import * + +def random_component(): + return rx.fragment() +""" + ) + assert (foo_dir / "bar" / "bar.py").exists() + assert not (foo_dir / "bar" / "foo.py").exists() + assert (foo_dir / "bar" / "bar.py").read_text() == ( + """ +import reflex as rx +import bar.components.base +from bar.components.base import random_component + +class State(rx.State): + pass + + +def index(): + return rx.text("Hello, World!") + +app = rx.App() +app.add_page(index) +""" + ) From 6d314d10c58c21673a613c80d25d0f3b25e4b281 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Wed, 22 Jan 2025 15:30:11 -0800 Subject: [PATCH 07/12] Fix setting default color mode in dev mode (#4616) * Fix setting default color mode in dev mode Without this, the last_compiled_timestamp local storage never gets set because it's always `null` until it gets set. * test_client_storage: also pop `theme` key from next-themes --- .../components/reflex/radix_themes_color_mode_provider.js | 5 +---- tests/integration/test_client_storage.py | 2 ++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js b/reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js index dd7886c89..823eeea99 100644 --- a/reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +++ b/reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js @@ -16,10 +16,7 @@ export default function RadixThemesColorModeProvider({ children }) { if (isDevMode) { const lastCompiledTimeInLocalStorage = localStorage.getItem("last_compiled_time"); - if ( - lastCompiledTimeInLocalStorage && - lastCompiledTimeInLocalStorage !== lastCompiledTimeStamp - ) { + if (lastCompiledTimeInLocalStorage !== lastCompiledTimeStamp) { // on app startup, make sure the application color mode is persisted correctly. setTheme(defaultColorMode); localStorage.setItem("last_compiled_time", lastCompiledTimeStamp); diff --git a/tests/integration/test_client_storage.py b/tests/integration/test_client_storage.py index 9273de70f..367409b1b 100644 --- a/tests/integration/test_client_storage.py +++ b/tests/integration/test_client_storage.py @@ -321,6 +321,7 @@ async def test_client_side_state( assert not driver.get_cookies() local_storage_items = local_storage.items() local_storage_items.pop("last_compiled_time", None) + local_storage_items.pop("theme", None) assert not local_storage_items # set some cookies and local storage values @@ -436,6 +437,7 @@ async def test_client_side_state( local_storage_items = local_storage.items() local_storage_items.pop("last_compiled_time", None) + local_storage_items.pop("theme", None) assert local_storage_items.pop(f"{sub_state_name}.l1") == "l1 value" assert local_storage_items.pop(f"{sub_state_name}.l2") == "l2 value" assert local_storage_items.pop("l3") == "l3 value" From 3aaa26c82f48d76a56751f31023684caf2204f9d Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 22 Jan 2025 17:56:41 -0800 Subject: [PATCH 08/12] attempt to upgrade windows latest python version (#4679) * attempt to upgrade windows latest python version * remove that silly one --- .github/workflows/benchmarks.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 13c93bef1..ec8c1409f 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -81,18 +81,18 @@ jobs: matrix: # Show OS combos first in GUI os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ['3.10.16', '3.11.11', '3.12.8'] + python-version: ["3.10.16", "3.11.11", "3.12.8"] exclude: - os: windows-latest - python-version: '3.10.16' + python-version: "3.10.16" # keep only one python version for MacOS - os: macos-latest - python-version: '3.10.16' + python-version: "3.10.16" - os: macos-latest python-version: "3.11.11" include: - os: windows-latest - python-version: '3.10.11' + python-version: "3.10.11" runs-on: ${{ matrix.os }} steps: @@ -155,7 +155,11 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - + - name: Set up python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} - name: Install Poetry uses: snok/install-poetry@v1 with: From c58db4d0050481005bc6818e9205c129c9e8e3dd Mon Sep 17 00:00:00 2001 From: Ahmad Hakim <84860195+LineIndent@users.noreply.github.com> Date: Thu, 23 Jan 2025 15:52:25 +0200 Subject: [PATCH 09/12] pie chart type annotation fix (#4681) Co-authored-by: pourhakimi <84860195+pourhakimi@users.noreply.github.com> --- reflex/components/recharts/general.py | 4 ++-- reflex/components/recharts/general.pyi | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/reflex/components/recharts/general.py b/reflex/components/recharts/general.py index 9a5c276b6..4b8c527d3 100644 --- a/reflex/components/recharts/general.py +++ b/reflex/components/recharts/general.py @@ -250,10 +250,10 @@ class Cell(Recharts): alias = "RechartsCell" # The presentation attribute of a rectangle in bar or a sector in pie. - fill: Var[str] + fill: Var[str | Color] # The presentation attribute of a rectangle in bar or a sector in pie. - stroke: Var[str] + stroke: Var[str | Color] responsive_container = ResponsiveContainer.create diff --git a/reflex/components/recharts/general.pyi b/reflex/components/recharts/general.pyi index eae08a5cc..9c63d6de9 100644 --- a/reflex/components/recharts/general.pyi +++ b/reflex/components/recharts/general.pyi @@ -488,8 +488,8 @@ class Cell(Recharts): def create( # type: ignore cls, *children, - fill: Optional[Union[Var[str], str]] = None, - stroke: Optional[Union[Var[str], str]] = None, + fill: Optional[Union[Color, Var[Union[Color, str]], str]] = None, + stroke: Optional[Union[Color, Var[Union[Color, str]], str]] = None, style: Optional[Style] = None, key: Optional[Any] = None, id: Optional[Any] = None, From 858a85a4dc904d9fbc52c88374f7122b30a3ce0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Thu, 23 Jan 2025 06:28:56 -0800 Subject: [PATCH 10/12] rename private fields with leading underscore in App (#4642) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * rename private fields with leading underscore in App * fix constants API * fix public API for some attributes of App() * fix conflicts properly 🙈 * remove extra private --------- Co-authored-by: Masen Furer Co-authored-by: Khaleel Al-Adhami --- .../test_benchmark_compile_components.py | 6 +- benchmarks/test_benchmark_compile_pages.py | 10 +- reflex/app.py | 145 +++++++++++------- reflex/testing.py | 8 +- tests/integration/test_background_task.py | 4 +- tests/integration/test_call_script.py | 2 +- tests/integration/test_client_storage.py | 2 +- tests/integration/test_component_state.py | 2 +- tests/integration/test_connection_banner.py | 2 +- tests/integration/test_deploy_url.py | 2 +- tests/integration/test_dynamic_routes.py | 2 +- tests/integration/test_event_actions.py | 2 +- tests/integration/test_event_chain.py | 2 +- tests/integration/test_exception_handlers.py | 2 +- tests/integration/test_form_submit.py | 4 +- tests/integration/test_input.py | 2 +- tests/integration/test_login_flow.py | 2 +- tests/integration/test_server_side_event.py | 2 +- tests/integration/test_upload.py | 2 +- tests/integration/test_var_operations.py | 2 +- .../test_datetime_operations.py | 2 +- .../tests_playwright/test_table.py | 2 +- .../middleware/test_hydrate_middleware.py | 2 +- tests/units/test_app.py | 100 ++++++------ tests/units/test_route.py | 4 +- tests/units/test_state.py | 28 ++-- tests/units/test_state_tree.py | 2 +- tests/units/test_testing.py | 2 +- 28 files changed, 191 insertions(+), 156 deletions(-) diff --git a/benchmarks/test_benchmark_compile_components.py b/benchmarks/test_benchmark_compile_components.py index 81d0c2e89..ba7e9c571 100644 --- a/benchmarks/test_benchmark_compile_components.py +++ b/benchmarks/test_benchmark_compile_components.py @@ -122,7 +122,7 @@ def AppWithTenComponentsOnePage(): def index() -> rx.Component: return rx.center(rx.vstack(*render_component(1))) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) @@ -133,7 +133,7 @@ def AppWithHundredComponentOnePage(): def index() -> rx.Component: return rx.center(rx.vstack(*render_component(100))) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) @@ -144,7 +144,7 @@ def AppWithThousandComponentsOnePage(): def index() -> rx.Component: return rx.center(rx.vstack(*render_component(1000))) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) diff --git a/benchmarks/test_benchmark_compile_pages.py b/benchmarks/test_benchmark_compile_pages.py index 292882b74..a5c85810e 100644 --- a/benchmarks/test_benchmark_compile_pages.py +++ b/benchmarks/test_benchmark_compile_pages.py @@ -162,7 +162,7 @@ def AppWithOnePage(): height="100vh", ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) @@ -170,7 +170,7 @@ def AppWithTenPages(): """A reflex app with 10 pages.""" import reflex as rx - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) render_multiple_pages(app, 10) @@ -178,7 +178,7 @@ def AppWithHundredPages(): """A reflex app with 100 pages.""" import reflex as rx - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) render_multiple_pages(app, 100) @@ -186,7 +186,7 @@ def AppWithThousandPages(): """A reflex app with Thousand pages.""" import reflex as rx - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) render_multiple_pages(app, 1000) @@ -194,7 +194,7 @@ def AppWithTenThousandPages(): """A reflex app with ten thousand pages.""" import reflex as rx - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) render_multiple_pages(app, 10000) diff --git a/reflex/app.py b/reflex/app.py index 7e868e730..f0f4baaa4 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -251,36 +251,36 @@ class App(MiddlewareMixin, LifespanMixin): # Attributes to add to the html root tag of every page. html_custom_attrs: Optional[Dict[str, str]] = None - # A map from a route to an unevaluated page. PRIVATE. - unevaluated_pages: Dict[str, UnevaluatedPage] = dataclasses.field( + # A map from a route to an unevaluated page. + _unevaluated_pages: Dict[str, UnevaluatedPage] = dataclasses.field( default_factory=dict ) - # A map from a page route to the component to render. Users should use `add_page`. PRIVATE. - pages: Dict[str, Component] = dataclasses.field(default_factory=dict) + # A map from a page route to the component to render. Users should use `add_page`. + _pages: Dict[str, Component] = dataclasses.field(default_factory=dict) - # The backend API object. PRIVATE. - api: FastAPI = None # type: ignore + # The backend API object. + _api: FastAPI | None = None - # The state class to use for the app. PRIVATE. - state: Optional[Type[BaseState]] = None + # The state class to use for the app. + _state: Optional[Type[BaseState]] = None # Class to manage many client states. _state_manager: Optional[StateManager] = None - # Mapping from a route to event handlers to trigger when the page loads. PRIVATE. - load_events: Dict[str, List[IndividualEventType[[], Any]]] = dataclasses.field( + # Mapping from a route to event handlers to trigger when the page loads. + _load_events: Dict[str, List[IndividualEventType[[], Any]]] = dataclasses.field( default_factory=dict ) - # Admin dashboard to view and manage the database. PRIVATE. + # Admin dashboard to view and manage the database. admin_dash: Optional[AdminDash] = None - # The async server name space. PRIVATE. - event_namespace: Optional[EventNamespace] = None + # The async server name space. + _event_namespace: Optional[EventNamespace] = None - # Background tasks that are currently running. PRIVATE. - background_tasks: Set[asyncio.Task] = dataclasses.field(default_factory=set) + # Background tasks that are currently running. + _background_tasks: Set[asyncio.Task] = dataclasses.field(default_factory=set) # Frontend Error Handler Function frontend_exception_handler: Callable[[Exception], None] = ( @@ -292,6 +292,24 @@ class App(MiddlewareMixin, LifespanMixin): [Exception], Union[EventSpec, List[EventSpec], None] ] = default_backend_exception_handler + @property + def api(self) -> FastAPI | None: + """Get the backend api. + + Returns: + The backend api. + """ + return self._api + + @property + def event_namespace(self) -> EventNamespace | None: + """Get the event namespace. + + Returns: + The event namespace. + """ + return self._event_namespace + def __post_init__(self): """Initialize the app. @@ -311,7 +329,7 @@ class App(MiddlewareMixin, LifespanMixin): set_breakpoints(self.style.pop("breakpoints")) # Set up the API. - self.api = FastAPI(lifespan=self._run_lifespan_tasks) + self._api = FastAPI(lifespan=self._run_lifespan_tasks) self._add_cors() self._add_default_endpoints() @@ -334,8 +352,8 @@ class App(MiddlewareMixin, LifespanMixin): def _enable_state(self) -> None: """Enable state for the app.""" - if not self.state: - self.state = State + if not self._state: + self._state = State self._setup_state() def _setup_state(self) -> None: @@ -344,13 +362,13 @@ class App(MiddlewareMixin, LifespanMixin): Raises: RuntimeError: If the socket server is invalid. """ - if not self.state: + if not self._state: return config = get_config() # Set up the state manager. - self._state_manager = StateManager.create(state=self.state) + self._state_manager = StateManager.create(state=self._state) # Set up the Socket.IO AsyncServer. if not self.sio: @@ -381,12 +399,13 @@ class App(MiddlewareMixin, LifespanMixin): namespace = config.get_event_namespace() # Create the event namespace and attach the main app. Not related to any paths. - self.event_namespace = EventNamespace(namespace, self) + self._event_namespace = EventNamespace(namespace, self) # Register the event namespace with the socket. self.sio.register_namespace(self.event_namespace) # Mount the socket app with the API. - self.api.mount(str(constants.Endpoint.EVENT), socket_app) + if self.api: + self.api.mount(str(constants.Endpoint.EVENT), socket_app) # Check the exception handlers self._validate_exception_handlers() @@ -397,24 +416,35 @@ class App(MiddlewareMixin, LifespanMixin): Returns: The string representation of the app. """ - return f"" + return f"" def __call__(self) -> FastAPI: """Run the backend api instance. + Raises: + ValueError: If the app has not been initialized. + Returns: The backend api. """ + if not self.api: + raise ValueError("The app has not been initialized.") return self.api def _add_default_endpoints(self): """Add default api endpoints (ping).""" # To test the server. + if not self.api: + return + self.api.get(str(constants.Endpoint.PING))(ping) self.api.get(str(constants.Endpoint.HEALTH))(health) def _add_optional_endpoints(self): """Add optional api endpoints (_upload).""" + if not self.api: + return + if Upload.is_used: # To upload files. self.api.post(str(constants.Endpoint.UPLOAD))(upload(self)) @@ -432,6 +462,8 @@ class App(MiddlewareMixin, LifespanMixin): def _add_cors(self): """Add CORS middleware to the app.""" + if not self.api: + return self.api.add_middleware( cors.CORSMiddleware, allow_credentials=True, @@ -521,13 +553,13 @@ class App(MiddlewareMixin, LifespanMixin): # Check if the route given is valid verify_route_validity(route) - if route in self.unevaluated_pages and environment.RELOAD_CONFIG.is_set(): + if route in self._unevaluated_pages and environment.RELOAD_CONFIG.is_set(): # when the app is reloaded(typically for app harness tests), we should maintain # the latest render function of a route.This applies typically to decorated pages # since they are only added when app._compile is called. - self.unevaluated_pages.pop(route) + self._unevaluated_pages.pop(route) - if route in self.unevaluated_pages: + if route in self._unevaluated_pages: route_name = ( f"`{route}` or `/`" if route == constants.PageNames.INDEX_ROUTE @@ -540,15 +572,15 @@ class App(MiddlewareMixin, LifespanMixin): # Setup dynamic args for the route. # this state assignment is only required for tests using the deprecated state kwarg for App - state = self.state if self.state else State + state = self._state if self._state else State state.setup_dynamic_args(get_route_args(route)) if on_load: - self.load_events[route] = ( + self._load_events[route] = ( on_load if isinstance(on_load, list) else [on_load] ) - self.unevaluated_pages[route] = UnevaluatedPage( + self._unevaluated_pages[route] = UnevaluatedPage( component=component, route=route, title=title, @@ -563,10 +595,10 @@ class App(MiddlewareMixin, LifespanMixin): Args: route: The route of the page to compile. - save_page: If True, the compiled page is saved to self.pages. + save_page: If True, the compiled page is saved to self._pages. """ component, enable_state = compiler.compile_unevaluated_page( - route, self.unevaluated_pages[route], self.state, self.style, self.theme + route, self._unevaluated_pages[route], self._state, self.style, self.theme ) if enable_state: @@ -575,7 +607,7 @@ class App(MiddlewareMixin, LifespanMixin): # Add the page. self._check_routes_conflict(route) if save_page: - self.pages[route] = component + self._pages[route] = component def get_load_events(self, route: str) -> list[IndividualEventType[[], Any]]: """Get the load events for a route. @@ -589,7 +621,7 @@ class App(MiddlewareMixin, LifespanMixin): route = route.lstrip("/") if route == "": route = constants.PageNames.INDEX_ROUTE - return self.load_events.get(route, []) + return self._load_events.get(route, []) def _check_routes_conflict(self, new_route: str): """Verify if there is any conflict between the new route and any existing route. @@ -613,7 +645,7 @@ class App(MiddlewareMixin, LifespanMixin): constants.RouteRegex.SINGLE_CATCHALL_SEGMENT, constants.RouteRegex.DOUBLE_CATCHALL_SEGMENT, ) - for route in self.pages: + for route in self._pages: replaced_route = replace_brackets_with_keywords(route) for rw, r, nr in zip( replaced_route.split("/"), route.split("/"), new_route.split("/") @@ -671,6 +703,9 @@ class App(MiddlewareMixin, LifespanMixin): def _setup_admin_dash(self): """Setup the admin dash.""" # Get the admin dash. + if not self.api: + return + admin_dash = self.admin_dash if admin_dash and admin_dash.models: @@ -775,10 +810,10 @@ class App(MiddlewareMixin, LifespanMixin): def _setup_overlay_component(self): """If a State is not used and no overlay_component is specified, do not render the connection modal.""" - if self.state is None and self.overlay_component is default_overlay_component: + if self._state is None and self.overlay_component is default_overlay_component: self.overlay_component = None - for k, component in self.pages.items(): - self.pages[k] = self._add_overlay_to_component(component) + for k, component in self._pages.items(): + self._pages[k] = self._add_overlay_to_component(component) def _add_error_boundary_to_component(self, component: Component) -> Component: if self.error_boundary is None: @@ -790,14 +825,14 @@ class App(MiddlewareMixin, LifespanMixin): def _setup_error_boundary(self): """If a State is not used and no error_boundary is specified, do not render the error boundary.""" - if self.state is None and self.error_boundary is default_error_boundary: + if self._state is None and self.error_boundary is default_error_boundary: self.error_boundary = None - for k, component in self.pages.items(): + for k, component in self._pages.items(): # Skip the 404 page if k == constants.Page404.SLUG: continue - self.pages[k] = self._add_error_boundary_to_component(component) + self._pages[k] = self._add_error_boundary_to_component(component) def _apply_decorated_pages(self): """Add @rx.page decorated pages to the app. @@ -823,11 +858,11 @@ class App(MiddlewareMixin, LifespanMixin): Raises: VarDependencyError: When a computed var has an invalid dependency. """ - if not self.state: + if not self._state: return if not state: - state = self.state + state = self._state for var in state.computed_vars.values(): if not var._cache: @@ -853,13 +888,13 @@ class App(MiddlewareMixin, LifespanMixin): """ from reflex.utils.exceptions import ReflexRuntimeError - self.pages = {} + self._pages = {} def get_compilation_time() -> str: return str(datetime.now().time()).split(".")[0] # Render a default 404 page if the user didn't supply one - if constants.Page404.SLUG not in self.unevaluated_pages: + if constants.Page404.SLUG not in self._unevaluated_pages: self.add_page(route=constants.Page404.SLUG) # Fix up the style. @@ -877,7 +912,7 @@ class App(MiddlewareMixin, LifespanMixin): should_compile = self._should_compile() - for route in self.unevaluated_pages: + for route in self._unevaluated_pages: console.debug(f"Evaluating page: {route}") self._compile_page(route, save_page=should_compile) @@ -904,7 +939,7 @@ class App(MiddlewareMixin, LifespanMixin): progress.start() task = progress.add_task( f"[{get_compilation_time()}] Compiling:", - total=len(self.pages) + total=len(self._pages) + fixed_pages_within_executor + adhoc_steps_without_executor, ) @@ -923,7 +958,7 @@ class App(MiddlewareMixin, LifespanMixin): # This has to happen before compiling stateful components as that # prevents recursive functions from reaching all components. - for component in self.pages.values(): + for component in self._pages.values(): # Add component._get_all_imports() to all_imports. all_imports.update(component._get_all_imports()) @@ -938,12 +973,12 @@ class App(MiddlewareMixin, LifespanMixin): stateful_components_path, stateful_components_code, page_components, - ) = compiler.compile_stateful_components(self.pages.values()) + ) = compiler.compile_stateful_components(self._pages.values()) progress.advance(task) # Catch "static" apps (that do not define a rx.State subclass) which are trying to access rx.State. - if code_uses_state_contexts(stateful_components_code) and self.state is None: + if code_uses_state_contexts(stateful_components_code) and self._state is None: raise ReflexRuntimeError( "To access rx.State in frontend components, at least one " "subclass of rx.State must be defined in the app." @@ -980,10 +1015,10 @@ class App(MiddlewareMixin, LifespanMixin): max_workers=environment.REFLEX_COMPILE_THREADS.get() or None ) - for route, component in zip(self.pages, page_components): + for route, component in zip(self._pages, page_components): ExecutorSafeFunctions.COMPONENTS[route] = component - ExecutorSafeFunctions.STATE = self.state + ExecutorSafeFunctions.STATE = self._state with executor: result_futures = [] @@ -993,7 +1028,7 @@ class App(MiddlewareMixin, LifespanMixin): result_futures.append(f) # Compile the pre-compiled pages. - for route in self.pages: + for route in self._pages: _submit_work( ExecutorSafeFunctions.compile_page, route, @@ -1028,7 +1063,7 @@ class App(MiddlewareMixin, LifespanMixin): # Compile the contexts. compile_results.append( - compiler.compile_contexts(self.state, self.theme), + compiler.compile_contexts(self._state, self.theme), ) if self.theme is not None: # Fix #2992 by removing the top-level appearance prop @@ -1150,9 +1185,9 @@ class App(MiddlewareMixin, LifespanMixin): ) task = asyncio.create_task(_coro()) - self.background_tasks.add(task) + self._background_tasks.add(task) # Clean up task from background_tasks set when complete. - task.add_done_callback(self.background_tasks.discard) + task.add_done_callback(self._background_tasks.discard) return task def _validate_exception_handlers(self): diff --git a/reflex/testing.py b/reflex/testing.py index 00b29a1df..ec8b80f66 100644 --- a/reflex/testing.py +++ b/reflex/testing.py @@ -296,7 +296,7 @@ class AppHarness: self.app_instance = self.app_module.app if isinstance(self.app_instance._state_manager, StateManagerRedis): # Create our own redis connection for testing. - self.state_manager = StateManagerRedis.create(self.app_instance.state) + self.state_manager = StateManagerRedis.create(self.app_instance._state) else: self.state_manager = self.app_instance._state_manager @@ -324,7 +324,7 @@ class AppHarness: return _shutdown_redis def _start_backend(self, port=0): - if self.app_instance is None: + if self.app_instance is None or self.app_instance.api is None: raise RuntimeError("App was not initialized.") self.backend = uvicorn.Server( uvicorn.Config( @@ -353,12 +353,12 @@ class AppHarness: self.app_instance.state_manager, StateManagerRedis, ) - and self.app_instance.state is not None + and self.app_instance._state is not None ): with contextlib.suppress(RuntimeError): await self.app_instance.state_manager.close() self.app_instance._state_manager = StateManagerRedis.create( - state=self.app_instance.state, + state=self.app_instance._state, ) if not isinstance(self.app_instance.state_manager, StateManagerRedis): raise RuntimeError("Failed to reset state manager.") diff --git a/tests/integration/test_background_task.py b/tests/integration/test_background_task.py index d7fe20824..cb8fda019 100644 --- a/tests/integration/test_background_task.py +++ b/tests/integration/test_background_task.py @@ -172,7 +172,7 @@ def BackgroundTask(): rx.button("Reset", on_click=State.reset_counter, id="reset"), ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) @@ -288,7 +288,7 @@ def test_background_task( assert background_task._poll_for(lambda: counter.text == "620", timeout=40) # all tasks should have exited and cleaned up assert background_task._poll_for( - lambda: not background_task.app_instance.background_tasks # type: ignore + lambda: not background_task.app_instance._background_tasks # type: ignore ) diff --git a/tests/integration/test_call_script.py b/tests/integration/test_call_script.py index be0bafdbb..f57dd2850 100644 --- a/tests/integration/test_call_script.py +++ b/tests/integration/test_call_script.py @@ -188,7 +188,7 @@ def CallScript(): yield rx.call_script("inline_counter = 0; external_counter = 0") self.reset() - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) Path("assets/external.js").write_text(external_scripts) @app.add_page diff --git a/tests/integration/test_client_storage.py b/tests/integration/test_client_storage.py index 367409b1b..3618c779d 100644 --- a/tests/integration/test_client_storage.py +++ b/tests/integration/test_client_storage.py @@ -127,7 +127,7 @@ def ClientSide(): rx.box(ClientSideSubSubState.s1s, id="s1s"), ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) app.add_page(index, route="/foo") diff --git a/tests/integration/test_component_state.py b/tests/integration/test_component_state.py index 97624e7c5..381c1d23a 100644 --- a/tests/integration/test_component_state.py +++ b/tests/integration/test_component_state.py @@ -72,7 +72,7 @@ def ComponentStateApp(): State=_Counter, ) - app = rx.App(state=rx.State) # noqa + app = rx.App(_state=rx.State) # noqa @rx.page() def index(): diff --git a/tests/integration/test_connection_banner.py b/tests/integration/test_connection_banner.py index 18259fe3f..c2a912af6 100644 --- a/tests/integration/test_connection_banner.py +++ b/tests/integration/test_connection_banner.py @@ -36,7 +36,7 @@ def ConnectionBanner(): rx.button("Delay", id="delay", on_click=State.delay), ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) diff --git a/tests/integration/test_deploy_url.py b/tests/integration/test_deploy_url.py index 5c840d24d..8b5776260 100644 --- a/tests/integration/test_deploy_url.py +++ b/tests/integration/test_deploy_url.py @@ -26,7 +26,7 @@ def DeployUrlSample() -> None: rx.button("GOTO SELF", on_click=State.goto_self, id="goto_self") ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) diff --git a/tests/integration/test_dynamic_routes.py b/tests/integration/test_dynamic_routes.py index c210bde69..9032fd84c 100644 --- a/tests/integration/test_dynamic_routes.py +++ b/tests/integration/test_dynamic_routes.py @@ -138,7 +138,7 @@ def DynamicRoute(): def redirect_page(): return rx.fragment(rx.text("redirecting...")) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index, route="/page/[page_id]", on_load=DynamicState.on_load) # type: ignore app.add_page(index, route="/static/x", on_load=DynamicState.on_load) # type: ignore app.add_page(index) diff --git a/tests/integration/test_event_actions.py b/tests/integration/test_event_actions.py index 15f3c9877..cc8e97b09 100644 --- a/tests/integration/test_event_actions.py +++ b/tests/integration/test_event_actions.py @@ -156,7 +156,7 @@ def TestEventAction(): on_click=EventActionState.on_click("outer"), # type: ignore ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) diff --git a/tests/integration/test_event_chain.py b/tests/integration/test_event_chain.py index c4121ee94..5a933253a 100644 --- a/tests/integration/test_event_chain.py +++ b/tests/integration/test_event_chain.py @@ -144,7 +144,7 @@ def EventChain(): time.sleep(0.5) self.interim_value = "final" - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) token_input = rx.input( value=State.router.session.client_token, is_read_only=True, id="token" diff --git a/tests/integration/test_exception_handlers.py b/tests/integration/test_exception_handlers.py index a645d1de6..4d15bbf01 100644 --- a/tests/integration/test_exception_handlers.py +++ b/tests/integration/test_exception_handlers.py @@ -39,7 +39,7 @@ def TestApp(): """ print(1 / number) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) @app.add_page def index(): diff --git a/tests/integration/test_form_submit.py b/tests/integration/test_form_submit.py index ea8750595..bdf54173c 100644 --- a/tests/integration/test_form_submit.py +++ b/tests/integration/test_form_submit.py @@ -30,7 +30,7 @@ def FormSubmit(form_component): def form_submit(self, form_data: Dict): self.form_data = form_data - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) @app.add_page def index(): @@ -90,7 +90,7 @@ def FormSubmitName(form_component): def form_submit(self, form_data: Dict): self.form_data = form_data - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) @app.add_page def index(): diff --git a/tests/integration/test_input.py b/tests/integration/test_input.py index e9fec7dc1..bddeca45f 100644 --- a/tests/integration/test_input.py +++ b/tests/integration/test_input.py @@ -16,7 +16,7 @@ def FullyControlledInput(): class State(rx.State): text: str = "initial" - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) @app.add_page def index(): diff --git a/tests/integration/test_login_flow.py b/tests/integration/test_login_flow.py index 1938672a3..7eb46ab39 100644 --- a/tests/integration/test_login_flow.py +++ b/tests/integration/test_login_flow.py @@ -45,7 +45,7 @@ def LoginSample(): rx.button("Do it", on_click=State.login, id="doit"), ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) app.add_page(login) diff --git a/tests/integration/test_server_side_event.py b/tests/integration/test_server_side_event.py index f04cc3beb..3050a4e36 100644 --- a/tests/integration/test_server_side_event.py +++ b/tests/integration/test_server_side_event.py @@ -38,7 +38,7 @@ def ServerSideEvent(): def set_value_return_c(self): return rx.set_value("c", "") - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) @app.add_page def index(): diff --git a/tests/integration/test_upload.py b/tests/integration/test_upload.py index 0331c15d6..07c3997b4 100644 --- a/tests/integration/test_upload.py +++ b/tests/integration/test_upload.py @@ -166,7 +166,7 @@ def UploadFile(): rx.text(UploadState.event_order.to_string(), id="event-order"), ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) diff --git a/tests/integration/test_var_operations.py b/tests/integration/test_var_operations.py index 7a7c8328d..86d68340a 100644 --- a/tests/integration/test_var_operations.py +++ b/tests/integration/test_var_operations.py @@ -39,7 +39,7 @@ def VarOperations(): dict2: Dict[int, int] = {3: 4} html_str: str = "
hello
" - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) @rx.memo def memo_comp(list1: List[int], int_var1: int, id: str): diff --git a/tests/integration/tests_playwright/test_datetime_operations.py b/tests/integration/tests_playwright/test_datetime_operations.py index fafd15c42..5e4506776 100644 --- a/tests/integration/tests_playwright/test_datetime_operations.py +++ b/tests/integration/tests_playwright/test_datetime_operations.py @@ -16,7 +16,7 @@ def DatetimeOperationsApp(): date2: datetime = datetime(2031, 1, 1) date3: datetime = datetime(2021, 1, 1) - app = rx.App(state=DtOperationsState) + app = rx.App(_state=DtOperationsState) @app.add_page def index(): diff --git a/tests/integration/tests_playwright/test_table.py b/tests/integration/tests_playwright/test_table.py index db716aa5b..bd399a840 100644 --- a/tests/integration/tests_playwright/test_table.py +++ b/tests/integration/tests_playwright/test_table.py @@ -20,7 +20,7 @@ def Table(): """App using table component.""" import reflex as rx - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) @app.add_page def index(): diff --git a/tests/units/middleware/test_hydrate_middleware.py b/tests/units/middleware/test_hydrate_middleware.py index 9ee8d8d25..7b02f8515 100644 --- a/tests/units/middleware/test_hydrate_middleware.py +++ b/tests/units/middleware/test_hydrate_middleware.py @@ -41,7 +41,7 @@ async def test_preprocess_no_events(hydrate_middleware, event1, mocker): mocker.patch("reflex.state.State.class_subclasses", {TestState}) state = State() update = await hydrate_middleware.preprocess( - app=App(state=State), + app=App(_state=State), event=event1, state=state, ) diff --git a/tests/units/test_app.py b/tests/units/test_app.py index f805f83ec..80e0be5fd 100644 --- a/tests/units/test_app.py +++ b/tests/units/test_app.py @@ -236,14 +236,14 @@ def test_add_page_default_route(app: App, index_page, about_page): index_page: The index page. about_page: The about page. """ - assert app.pages == {} - assert app.unevaluated_pages == {} + assert app._pages == {} + assert app._unevaluated_pages == {} app.add_page(index_page) app._compile_page("index") - assert app.pages.keys() == {"index"} + assert app._pages.keys() == {"index"} app.add_page(about_page) app._compile_page("about") - assert app.pages.keys() == {"index", "about"} + assert app._pages.keys() == {"index", "about"} def test_add_page_set_route(app: App, index_page, windows_platform: bool): @@ -255,10 +255,10 @@ def test_add_page_set_route(app: App, index_page, windows_platform: bool): windows_platform: Whether the system is windows. """ route = "test" if windows_platform else "/test" - assert app.unevaluated_pages == {} + assert app._unevaluated_pages == {} app.add_page(index_page, route=route) app._compile_page("test") - assert app.pages.keys() == {"test"} + assert app._pages.keys() == {"test"} def test_add_page_set_route_dynamic(index_page, windows_platform: bool): @@ -268,18 +268,18 @@ def test_add_page_set_route_dynamic(index_page, windows_platform: bool): index_page: The index page. windows_platform: Whether the system is windows. """ - app = App(state=EmptyState) - assert app.state is not None + app = App(_state=EmptyState) + assert app._state is not None route = "/test/[dynamic]" - assert app.unevaluated_pages == {} + assert app._unevaluated_pages == {} app.add_page(index_page, route=route) app._compile_page("test/[dynamic]") - assert app.pages.keys() == {"test/[dynamic]"} - assert "dynamic" in app.state.computed_vars - assert app.state.computed_vars["dynamic"]._deps(objclass=EmptyState) == { + assert app._pages.keys() == {"test/[dynamic]"} + assert "dynamic" in app._state.computed_vars + assert app._state.computed_vars["dynamic"]._deps(objclass=EmptyState) == { constants.ROUTER } - assert constants.ROUTER in app.state()._computed_var_dependencies + assert constants.ROUTER in app._state()._computed_var_dependencies def test_add_page_set_route_nested(app: App, index_page, windows_platform: bool): @@ -291,9 +291,9 @@ def test_add_page_set_route_nested(app: App, index_page, windows_platform: bool) windows_platform: Whether the system is windows. """ route = "test\\nested" if windows_platform else "/test/nested" - assert app.unevaluated_pages == {} + assert app._unevaluated_pages == {} app.add_page(index_page, route=route) - assert app.unevaluated_pages.keys() == {route.strip(os.path.sep)} + assert app._unevaluated_pages.keys() == {route.strip(os.path.sep)} def test_add_page_invalid_api_route(app: App, index_page): @@ -413,8 +413,8 @@ async def test_initialize_with_state(test_state: Type[ATestState], token: str): test_state: The default state. token: a Token. """ - app = App(state=test_state) - assert app.state == test_state + app = App(_state=test_state) + assert app._state == test_state # Get a state for a given token. state = await app.state_manager.get_state(_substate_key(token, test_state)) @@ -432,7 +432,7 @@ async def test_set_and_get_state(test_state): Args: test_state: The default state. """ - app = App(state=test_state) + app = App(_state=test_state) # Create two tokens. token1 = str(uuid.uuid4()) + f"_{test_state.get_full_name()}" @@ -827,7 +827,7 @@ async def test_upload_file_without_annotation(state, tmp_path, token): token: a Token. """ state._tmp_path = tmp_path - app = App(state=State) + app = App(_state=State) request_mock = unittest.mock.Mock() request_mock.headers = { @@ -861,7 +861,7 @@ async def test_upload_file_background(state, tmp_path, token): token: a Token. """ state._tmp_path = tmp_path - app = App(state=State) + app = App(_state=State) request_mock = unittest.mock.Mock() request_mock.headers = { @@ -938,8 +938,8 @@ def test_dynamic_arg_shadow( """ arg_name = "counter" route = f"/test/[{arg_name}]" - app = app_module_mock.app = App(state=DynamicState) - assert app.state is not None + app = app_module_mock.app = App(_state=DynamicState) + assert app._state is not None with pytest.raises(NameError): app.add_page(index_page, route=route, on_load=DynamicState.on_load) # type: ignore @@ -963,7 +963,7 @@ def test_multiple_dynamic_args( arg_name = "my_arg" route = f"/test/[{arg_name}]" route2 = f"/test2/[{arg_name}]" - app = app_module_mock.app = App(state=EmptyState) + app = app_module_mock.app = App(_state=EmptyState) app.add_page(index_page, route=route) app.add_page(index_page, route=route2) @@ -990,16 +990,16 @@ async def test_dynamic_route_var_route_change_completed_on_load( """ arg_name = "dynamic" route = f"/test/[{arg_name}]" - app = app_module_mock.app = App(state=DynamicState) - assert app.state is not None - assert arg_name not in app.state.vars + app = app_module_mock.app = App(_state=DynamicState) + assert app._state is not None + assert arg_name not in app._state.vars app.add_page(index_page, route=route, on_load=DynamicState.on_load) # type: ignore - assert arg_name in app.state.vars - assert arg_name in app.state.computed_vars - assert app.state.computed_vars[arg_name]._deps(objclass=DynamicState) == { + assert arg_name in app._state.vars + assert arg_name in app._state.computed_vars + assert app._state.computed_vars[arg_name]._deps(objclass=DynamicState) == { constants.ROUTER } - assert constants.ROUTER in app.state()._computed_var_dependencies + assert constants.ROUTER in app._state()._computed_var_dependencies substate_token = _substate_key(token, DynamicState) sid = "mock_sid" @@ -1174,7 +1174,7 @@ async def test_process_events(mocker, token: str): "headers": {}, "ip": "127.0.0.1", } - app = App(state=GenState) + app = App(_state=GenState) mocker.patch.object(app, "_postprocess", AsyncMock()) event = Event( @@ -1220,7 +1220,7 @@ def test_overlay_component( overlay_component: The overlay_component to pass to App. exp_page_child: The type of the expected child in the page fragment. """ - app = App(state=state, overlay_component=overlay_component) + app = App(_state=state, overlay_component=overlay_component) app._setup_overlay_component() if exp_page_child is None: assert app.overlay_component is None @@ -1243,7 +1243,7 @@ def test_overlay_component( # overlay components are wrapped during compile only app._compile_page("test") app._setup_overlay_component() - page = app.pages["test"] + page = app._pages["test"] if exp_page_child is not None: assert len(page.children) == 3 @@ -1361,52 +1361,52 @@ def test_app_wrap_priority(compilable_app: tuple[App, Path]): def test_app_state_determination(): """Test that the stateless status of an app is determined correctly.""" a1 = App() - assert a1.state is None + assert a1._state is None # No state, no router, no event handlers. a1.add_page(rx.box("Index"), route="/") - assert a1.state is None + assert a1._state is None # Add a page with `on_load` enables state. a1.add_page(rx.box("About"), route="/about", on_load=rx.console_log("")) a1._compile_page("about") - assert a1.state is not None + assert a1._state is not None a2 = App() - assert a2.state is None + assert a2._state is None # Referencing a state Var enables state. a2.add_page(rx.box(rx.text(GenState.value)), route="/") a2._compile_page("index") - assert a2.state is not None + assert a2._state is not None a3 = App() - assert a3.state is None + assert a3._state is None # Referencing router enables state. a3.add_page(rx.box(rx.text(State.router.page.full_path)), route="/") a3._compile_page("index") - assert a3.state is not None + assert a3._state is not None a4 = App() - assert a4.state is None + assert a4._state is None a4.add_page(rx.box(rx.button("Click", on_click=rx.console_log(""))), route="/") - assert a4.state is None + assert a4._state is None a4.add_page( rx.box(rx.button("Click", on_click=DynamicState.on_counter)), route="/page2" ) a4._compile_page("page2") - assert a4.state is not None + assert a4._state is not None def test_raise_on_state(): """Test that the state is set.""" # state kwargs is deprecated, we just make sure the app is created anyway. - _app = App(state=State) - assert _app.state is not None - assert issubclass(_app.state, State) + _app = App(_state=State) + assert _app._state is not None + assert issubclass(_app._state, State) def test_call_app(): @@ -1473,7 +1473,7 @@ def test_add_page_component_returning_tuple(): app._compile_page("index") app._compile_page("page2") - fragment_wrapper = app.pages["index"].children[0] + fragment_wrapper = app._pages["index"].children[0] assert isinstance(fragment_wrapper, Fragment) first_text = fragment_wrapper.children[0] assert isinstance(first_text, Text) @@ -1483,7 +1483,7 @@ def test_add_page_component_returning_tuple(): assert str(second_text.children[0].contents) == '"second"' # type: ignore # Test page with trailing comma. - page2_fragment_wrapper = app.pages["page2"].children[0] + page2_fragment_wrapper = app._pages["page2"].children[0] assert isinstance(page2_fragment_wrapper, Fragment) third_text = page2_fragment_wrapper.children[0] assert isinstance(third_text, Text) @@ -1557,7 +1557,7 @@ def test_app_with_valid_var_dependencies(compilable_app: tuple[App, Path]): def bar(self) -> str: return "bar" - app.state = ValidDepState + app._state = ValidDepState app._compile() @@ -1569,7 +1569,7 @@ def test_app_with_invalid_var_dependencies(compilable_app: tuple[App, Path]): def bar(self) -> str: return "bar" - app.state = InvalidDepState + app._state = InvalidDepState with pytest.raises(exceptions.VarDependencyError): app._compile() diff --git a/tests/units/test_route.py b/tests/units/test_route.py index 851c9cf35..62f1788d3 100644 --- a/tests/units/test_route.py +++ b/tests/units/test_route.py @@ -89,7 +89,7 @@ def app(): ], ) def test_check_routes_conflict_invalid(mocker, app, route1, route2): - mocker.patch.object(app, "pages", {route1: []}) + mocker.patch.object(app, "_pages", {route1: []}) with pytest.raises(ValueError): app._check_routes_conflict(route2) @@ -117,6 +117,6 @@ def test_check_routes_conflict_invalid(mocker, app, route1, route2): ], ) def test_check_routes_conflict_valid(mocker, app, route1, route2): - mocker.patch.object(app, "pages", {route1: []}) + mocker.patch.object(app, "_pages", {route1: []}) # test that running this does not throw an error. app._check_routes_conflict(route2) diff --git a/tests/units/test_state.py b/tests/units/test_state.py index b1e73a1f0..dfb068626 100644 --- a/tests/units/test_state.py +++ b/tests/units/test_state.py @@ -1907,12 +1907,12 @@ def mock_app_simple(monkeypatch) -> rx.App: Returns: The app, after mocking out prerequisites.get_app() """ - app = App(state=TestState) + app = App(_state=TestState) app_module = Mock() setattr(app_module, CompileVars.APP, app) - app.state = TestState + app._state = TestState app.event_namespace.emit = CopyingAsyncMock() # type: ignore def _mock_get_app(*args, **kwargs): @@ -2153,7 +2153,7 @@ async def test_background_task_no_block(mock_app: rx.App, token: str): token: A token. """ router_data = {"query": {}} - mock_app.state_manager.state = mock_app.state = BackgroundTaskState + mock_app.state_manager.state = mock_app._state = BackgroundTaskState async for update in rx.app.process( # type: ignore mock_app, Event( @@ -2171,7 +2171,7 @@ async def test_background_task_no_block(mock_app: rx.App, token: str): # wait for the coroutine to start await asyncio.sleep(0.5 if CI else 0.1) - assert len(mock_app.background_tasks) == 1 + assert len(mock_app._background_tasks) == 1 # Process another normal event async for update in rx.app.process( # type: ignore @@ -2203,9 +2203,9 @@ async def test_background_task_no_block(mock_app: rx.App, token: str): ) # Explicit wait for background tasks - for task in tuple(mock_app.background_tasks): + for task in tuple(mock_app._background_tasks): await task - assert not mock_app.background_tasks + assert not mock_app._background_tasks exp_order = [ "background_task:start", @@ -2280,7 +2280,7 @@ async def test_background_task_reset(mock_app: rx.App, token: str): token: A token. """ router_data = {"query": {}} - mock_app.state_manager.state = mock_app.state = BackgroundTaskState + mock_app.state_manager.state = mock_app._state = BackgroundTaskState async for update in rx.app.process( # type: ignore mock_app, Event( @@ -2297,9 +2297,9 @@ async def test_background_task_reset(mock_app: rx.App, token: str): assert update == StateUpdate() # Explicit wait for background tasks - for task in tuple(mock_app.background_tasks): + for task in tuple(mock_app._background_tasks): await task - assert not mock_app.background_tasks + assert not mock_app._background_tasks assert ( await mock_app.state_manager.get_state( @@ -2884,7 +2884,7 @@ async def test_preprocess(app_module_mock, token, test_state, expected, mocker): "reflex.state.State.class_subclasses", {test_state, OnLoadInternalState} ) app = app_module_mock.app = App( - state=State, load_events={"index": [test_state.test_handler]} + _state=State, _load_events={"index": [test_state.test_handler]} ) async with app.state_manager.modify_state(_substate_key(token, State)) as state: state.router_data = {"simulate": "hydrate"} @@ -2931,8 +2931,8 @@ async def test_preprocess_multiple_load_events(app_module_mock, token, mocker): "reflex.state.State.class_subclasses", {OnLoadState, OnLoadInternalState} ) app = app_module_mock.app = App( - state=State, - load_events={"index": [OnLoadState.test_handler, OnLoadState.test_handler]}, + _state=State, + _load_events={"index": [OnLoadState.test_handler, OnLoadState.test_handler]}, ) async with app.state_manager.modify_state(_substate_key(token, State)) as state: state.router_data = {"simulate": "hydrate"} @@ -2977,7 +2977,7 @@ async def test_get_state(mock_app: rx.App, token: str): mock_app: An app that will be returned by `get_app()` token: A token. """ - mock_app.state_manager.state = mock_app.state = TestState + mock_app.state_manager.state = mock_app._state = TestState # Get instance of ChildState2. test_state = await mock_app.state_manager.get_state( @@ -3147,7 +3147,7 @@ async def test_get_state_from_sibling_not_cached(mock_app: rx.App, token: str): pass - mock_app.state_manager.state = mock_app.state = Parent + mock_app.state_manager.state = mock_app._state = Parent # Get the top level state via unconnected sibling. root = await mock_app.state_manager.get_state(_substate_key(token, Child)) diff --git a/tests/units/test_state_tree.py b/tests/units/test_state_tree.py index 6fe828819..70ef71cb8 100644 --- a/tests/units/test_state_tree.py +++ b/tests/units/test_state_tree.py @@ -222,7 +222,7 @@ async def state_manager_redis( Yields: A state manager instance """ - app_module_mock.app = rx.App(state=Root) + app_module_mock.app = rx.App(_state=Root) state_manager = app_module_mock.app.state_manager if not isinstance(state_manager, StateManagerRedis): diff --git a/tests/units/test_testing.py b/tests/units/test_testing.py index 83a03ad83..8c8f1461b 100644 --- a/tests/units/test_testing.py +++ b/tests/units/test_testing.py @@ -23,7 +23,7 @@ def test_app_harness(tmp_path): class State(rx.State): pass - app = rx.App(state=State) + app = rx.App(_state=State) app.add_page(lambda: rx.text("Basic App"), route="/", title="index") app._compile() From 7f1aee6dc8a9359eb86d55634cd35082bc9655f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Thu, 23 Jan 2025 06:29:17 -0800 Subject: [PATCH 11/12] enable N rules for naming conventions (#4666) * enable N rules for naming conventions * fix pyi * address comments * remove unneeded code --- benchmarks/benchmark_package_size.py | 2 +- pyproject.toml | 9 ++-- reflex/app.py | 8 ++-- reflex/app_mixins/lifespan.py | 6 +-- reflex/components/core/html.py | 2 +- reflex/components/dynamic.py | 8 ++-- reflex/components/next/image.py | 16 +++++-- reflex/components/next/image.pyi | 6 ++- .../components/radix/primitives/accordion.py | 8 ++-- reflex/components/radix/primitives/drawer.py | 2 +- reflex/components/radix/primitives/drawer.pyi | 8 ++-- .../radix/themes/components/icon_button.py | 4 +- .../radix/themes/components/icon_button.pyi | 1 + .../radix/themes/components/tooltip.py | 4 +- .../radix/themes/components/tooltip.pyi | 1 + reflex/components/recharts/polar.py | 2 +- reflex/components/recharts/recharts.py | 4 +- reflex/config.py | 8 ++-- reflex/event.py | 8 ++-- reflex/experimental/hooks.py | 8 ++-- reflex/experimental/layout.pyi | 2 +- reflex/state.py | 47 +++++++++---------- reflex/testing.py | 2 +- reflex/utils/codespaces.py | 5 +- reflex/utils/exceptions.py | 20 ++++---- reflex/utils/exec.py | 8 ++-- reflex/utils/prerequisites.py | 6 +-- reflex/vars/base.py | 2 +- reflex/vars/number.py | 6 +-- tests/units/conftest.py | 31 +----------- tests/units/test_var.py | 4 +- 31 files changed, 118 insertions(+), 130 deletions(-) diff --git a/benchmarks/benchmark_package_size.py b/benchmarks/benchmark_package_size.py index 6a0c37821..778b52769 100644 --- a/benchmarks/benchmark_package_size.py +++ b/benchmarks/benchmark_package_size.py @@ -21,7 +21,7 @@ def get_package_size(venv_path: Path, os_name): ValueError: when venv does not exist or python version is None. """ python_version = get_python_version(venv_path, os_name) - print("Python version:", python_version) # noqa: T201 + print("Python version:", python_version) if python_version is None: raise ValueError("Error: Failed to determine Python version.") diff --git a/pyproject.toml b/pyproject.toml index 160cfc535..03580cd0f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -85,15 +85,18 @@ build-backend = "poetry.core.masonry.api" target-version = "py39" output-format = "concise" lint.isort.split-on-trailing-comma = false -lint.select = ["B", "C4", "D", "E", "ERA", "F", "FURB", "I", "PERF", "PTH", "RUF", "SIM", "T", "TRY", "W"] +lint.select = ["B", "C4", "D", "E", "ERA", "F", "FURB", "I", "N", "PERF", "PTH", "RUF", "SIM", "T", "TRY", "W"] lint.ignore = ["B008", "D205", "E501", "F403", "SIM115", "RUF006", "RUF012", "TRY0"] lint.pydocstyle.convention = "google" [tool.ruff.lint.per-file-ignores] "__init__.py" = ["F401"] -"tests/*.py" = ["D100", "D103", "D104", "B018", "PERF", "T"] +"tests/*.py" = ["D100", "D103", "D104", "B018", "PERF", "T", "N"] +"benchmarks/*.py" = ["D100", "D103", "D104", "B018", "PERF", "T", "N"] "reflex/.templates/*.py" = ["D100", "D103", "D104"] -"*.pyi" = ["D301", "D415", "D417", "D418", "E742"] +"*.pyi" = ["D301", "D415", "D417", "D418", "E742", "N"] +"pyi_generator.py" = ["N802"] +"reflex/constants/*.py" = ["N"] "*/blank.py" = ["I001"] [tool.pytest.ini_options] diff --git a/reflex/app.py b/reflex/app.py index f0f4baaa4..5ee424719 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -1197,11 +1197,11 @@ class App(MiddlewareMixin, LifespanMixin): ValueError: If the custom exception handlers are invalid. """ - FRONTEND_ARG_SPEC = { + frontend_arg_spec = { "exception": Exception, } - BACKEND_ARG_SPEC = { + backend_arg_spec = { "exception": Exception, } @@ -1209,8 +1209,8 @@ class App(MiddlewareMixin, LifespanMixin): ["frontend", "backend"], [self.frontend_exception_handler, self.backend_exception_handler], [ - FRONTEND_ARG_SPEC, - BACKEND_ARG_SPEC, + frontend_arg_spec, + backend_arg_spec, ], ): if hasattr(handler_fn, "__name__"): diff --git a/reflex/app_mixins/lifespan.py b/reflex/app_mixins/lifespan.py index 52bf0be1d..9403e0f35 100644 --- a/reflex/app_mixins/lifespan.py +++ b/reflex/app_mixins/lifespan.py @@ -12,7 +12,7 @@ from typing import Callable, Coroutine, Set, Union from fastapi import FastAPI from reflex.utils import console -from reflex.utils.exceptions import InvalidLifespanTaskType +from reflex.utils.exceptions import InvalidLifespanTaskTypeError from .mixin import AppMixin @@ -64,10 +64,10 @@ class LifespanMixin(AppMixin): task_kwargs: The kwargs of the task. Raises: - InvalidLifespanTaskType: If the task is a generator function. + InvalidLifespanTaskTypeError: If the task is a generator function. """ if inspect.isgeneratorfunction(task) or inspect.isasyncgenfunction(task): - raise InvalidLifespanTaskType( + raise InvalidLifespanTaskTypeError( f"Task {task.__name__} of type generator must be decorated with contextlib.asynccontextmanager." ) diff --git a/reflex/components/core/html.py b/reflex/components/core/html.py index cfe46e591..2cad4f331 100644 --- a/reflex/components/core/html.py +++ b/reflex/components/core/html.py @@ -14,7 +14,7 @@ class Html(Div): """ # The HTML to render. - dangerouslySetInnerHTML: Var[Dict[str, str]] + dangerouslySetInnerHTML: Var[Dict[str, str]] # noqa: N815 @classmethod def create(cls, *children, **props): diff --git a/reflex/components/dynamic.py b/reflex/components/dynamic.py index 806d610df..d4efcd293 100644 --- a/reflex/components/dynamic.py +++ b/reflex/components/dynamic.py @@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Union from reflex import constants from reflex.utils import imports -from reflex.utils.exceptions import DynamicComponentMissingLibrary +from reflex.utils.exceptions import DynamicComponentMissingLibraryError from reflex.utils.format import format_library_name from reflex.utils.serializers import serializer from reflex.vars import Var, get_unique_variable_name @@ -36,13 +36,15 @@ def bundle_library(component: Union["Component", str]): component: The component to bundle the library with. Raises: - DynamicComponentMissingLibrary: Raised when a dynamic component is missing a library. + DynamicComponentMissingLibraryError: Raised when a dynamic component is missing a library. """ if isinstance(component, str): bundled_libraries.add(component) return if component.library is None: - raise DynamicComponentMissingLibrary("Component must have a library to bundle.") + raise DynamicComponentMissingLibraryError( + "Component must have a library to bundle." + ) bundled_libraries.add(format_library_name(component.library)) diff --git a/reflex/components/next/image.py b/reflex/components/next/image.py index 2011505d8..00821ddaf 100644 --- a/reflex/components/next/image.py +++ b/reflex/components/next/image.py @@ -3,11 +3,13 @@ from typing import Any, Literal, Optional, Union from reflex.event import EventHandler, no_args_event_spec -from reflex.utils import types +from reflex.utils import console, types from reflex.vars.base import Var from .base import NextComponent +DEFAULT_W_H = "100%" + class Image(NextComponent): """Display an image.""" @@ -53,7 +55,7 @@ class Image(NextComponent): loading: Var[Literal["lazy", "eager"]] # A Data URL to be used as a placeholder image before the src image successfully loads. Only takes effect when combined with placeholder="blur". - blurDataURL: Var[str] + blur_data_url: Var[str] # Fires when the image has loaded. on_load: EventHandler[no_args_event_spec] @@ -80,8 +82,16 @@ class Image(NextComponent): Returns: _type_: _description_ """ + if "blurDataURL" in props: + console.deprecate( + feature_name="blurDataURL", + reason="Use blur_data_url instead", + deprecation_version="0.7.0", + removal_version="0.8.0", + ) + props["blur_data_url"] = props.pop("blurDataURL") + style = props.get("style", {}) - DEFAULT_W_H = "100%" def check_prop_type(prop_name, prop_value): if types.check_prop_in_allowed_types(prop_value, allowed_types=[int]): diff --git a/reflex/components/next/image.pyi b/reflex/components/next/image.pyi index dd9dd38c3..b8da4973d 100644 --- a/reflex/components/next/image.pyi +++ b/reflex/components/next/image.pyi @@ -11,6 +11,8 @@ from reflex.vars.base import Var from .base import NextComponent +DEFAULT_W_H = "100%" + class Image(NextComponent): @overload @classmethod @@ -30,7 +32,7 @@ class Image(NextComponent): loading: Optional[ Union[Literal["eager", "lazy"], Var[Literal["eager", "lazy"]]] ] = None, - blurDataURL: Optional[Union[Var[str], str]] = None, + blur_data_url: Optional[Union[Var[str], str]] = None, style: Optional[Style] = None, key: Optional[Any] = None, id: Optional[Any] = None, @@ -71,7 +73,7 @@ class Image(NextComponent): priority: When true, the image will be considered high priority and preload. Lazy loading is automatically disabled for images using priority. placeholder: A placeholder to use while the image is loading. Possible values are blur, empty, or data:image/.... Defaults to empty. loading: The loading behavior of the image. Defaults to lazy. Can hurt performance, recommended to use `priority` instead. - blurDataURL: A Data URL to be used as a placeholder image before the src image successfully loads. Only takes effect when combined with placeholder="blur". + blur_data_url: A Data URL to be used as a placeholder image before the src image successfully loads. Only takes effect when combined with placeholder="blur". on_load: Fires when the image has loaded. on_error: Fires when the image has an error. style: The style of the component. diff --git a/reflex/components/radix/primitives/accordion.py b/reflex/components/radix/primitives/accordion.py index 0ba618e21..170b3ed9c 100644 --- a/reflex/components/radix/primitives/accordion.py +++ b/reflex/components/radix/primitives/accordion.py @@ -485,11 +485,11 @@ to { Returns: The style of the component. """ - slideDown = LiteralVar.create( + slide_down = LiteralVar.create( "${slideDown} var(--animation-duration) var(--animation-easing)", ) - slideUp = LiteralVar.create( + slide_up = LiteralVar.create( "${slideUp} var(--animation-duration) var(--animation-easing)", ) @@ -503,8 +503,8 @@ to { "display": "block", "height": "var(--space-3)", }, - "&[data-state='open']": {"animation": slideDown}, - "&[data-state='closed']": {"animation": slideUp}, + "&[data-state='open']": {"animation": slide_down}, + "&[data-state='closed']": {"animation": slide_up}, _inherited_variant_selector("classic"): { "color": "var(--accent-contrast)", }, diff --git a/reflex/components/radix/primitives/drawer.py b/reflex/components/radix/primitives/drawer.py index ed57dcbd8..534b97ac1 100644 --- a/reflex/components/radix/primitives/drawer.py +++ b/reflex/components/radix/primitives/drawer.py @@ -66,7 +66,7 @@ class DrawerRoot(DrawerComponent): scroll_lock_timeout: Var[int] # When `True`, it prevents scroll restoration. Defaults to `True`. - preventScrollRestoration: Var[bool] + prevent_scroll_restoration: Var[bool] # Enable background scaling, it requires container element with `vaul-drawer-wrapper` attribute to scale its background. should_scale_background: Var[bool] diff --git a/reflex/components/radix/primitives/drawer.pyi b/reflex/components/radix/primitives/drawer.pyi index 1ca1e4325..bb2890fea 100644 --- a/reflex/components/radix/primitives/drawer.pyi +++ b/reflex/components/radix/primitives/drawer.pyi @@ -81,7 +81,7 @@ class DrawerRoot(DrawerComponent): snap_points: Optional[List[Union[float, str]]] = None, fade_from_index: Optional[Union[Var[int], int]] = None, scroll_lock_timeout: Optional[Union[Var[int], int]] = None, - preventScrollRestoration: Optional[Union[Var[bool], bool]] = None, + prevent_scroll_restoration: Optional[Union[Var[bool], bool]] = None, should_scale_background: Optional[Union[Var[bool], bool]] = None, close_threshold: Optional[Union[Var[float], float]] = None, as_child: Optional[Union[Var[bool], bool]] = None, @@ -129,7 +129,7 @@ class DrawerRoot(DrawerComponent): snap_points: Array of numbers from 0 to 100 that corresponds to % of the screen a given snap point should take up. Should go from least visible. Also Accept px values, which doesn't take screen height into account. fade_from_index: Index of a snapPoint from which the overlay fade should be applied. Defaults to the last snap point. scroll_lock_timeout: Duration for which the drawer is not draggable after scrolling content inside of the drawer. Defaults to 500ms - preventScrollRestoration: When `True`, it prevents scroll restoration. Defaults to `True`. + prevent_scroll_restoration: When `True`, it prevents scroll restoration. Defaults to `True`. should_scale_background: Enable background scaling, it requires container element with `vaul-drawer-wrapper` attribute to scale its background. close_threshold: Number between 0 and 1 that determines when the drawer should be closed. as_child: Change the default rendered element for the one passed as a child. @@ -567,7 +567,7 @@ class Drawer(ComponentNamespace): snap_points: Optional[List[Union[float, str]]] = None, fade_from_index: Optional[Union[Var[int], int]] = None, scroll_lock_timeout: Optional[Union[Var[int], int]] = None, - preventScrollRestoration: Optional[Union[Var[bool], bool]] = None, + prevent_scroll_restoration: Optional[Union[Var[bool], bool]] = None, should_scale_background: Optional[Union[Var[bool], bool]] = None, close_threshold: Optional[Union[Var[float], float]] = None, as_child: Optional[Union[Var[bool], bool]] = None, @@ -615,7 +615,7 @@ class Drawer(ComponentNamespace): snap_points: Array of numbers from 0 to 100 that corresponds to % of the screen a given snap point should take up. Should go from least visible. Also Accept px values, which doesn't take screen height into account. fade_from_index: Index of a snapPoint from which the overlay fade should be applied. Defaults to the last snap point. scroll_lock_timeout: Duration for which the drawer is not draggable after scrolling content inside of the drawer. Defaults to 500ms - preventScrollRestoration: When `True`, it prevents scroll restoration. Defaults to `True`. + prevent_scroll_restoration: When `True`, it prevents scroll restoration. Defaults to `True`. should_scale_background: Enable background scaling, it requires container element with `vaul-drawer-wrapper` attribute to scale its background. close_threshold: Number between 0 and 1 that determines when the drawer should be closed. as_child: Change the default rendered element for the one passed as a child. diff --git a/reflex/components/radix/themes/components/icon_button.py b/reflex/components/radix/themes/components/icon_button.py index 68c67485a..aafb9e1eb 100644 --- a/reflex/components/radix/themes/components/icon_button.py +++ b/reflex/components/radix/themes/components/icon_button.py @@ -22,6 +22,8 @@ from ..base import ( LiteralButtonSize = Literal["1", "2", "3", "4"] +RADIX_TO_LUCIDE_SIZE = {"1": 12, "2": 24, "3": 36, "4": 48} + class IconButton(elements.Button, RadixLoadingProp, RadixThemesComponent): """A button designed specifically for usage with a single icon.""" @@ -72,8 +74,6 @@ class IconButton(elements.Button, RadixLoadingProp, RadixThemesComponent): "IconButton requires a child icon. Pass a string as the first child or a rx.icon." ) if "size" in props: - RADIX_TO_LUCIDE_SIZE = {"1": 12, "2": 24, "3": 36, "4": 48} - if isinstance(props["size"], str): children[0].size = RADIX_TO_LUCIDE_SIZE[props["size"]] else: diff --git a/reflex/components/radix/themes/components/icon_button.pyi b/reflex/components/radix/themes/components/icon_button.pyi index abf77e07b..bdb0fe845 100644 --- a/reflex/components/radix/themes/components/icon_button.pyi +++ b/reflex/components/radix/themes/components/icon_button.pyi @@ -14,6 +14,7 @@ from reflex.vars.base import Var from ..base import RadixLoadingProp, RadixThemesComponent LiteralButtonSize = Literal["1", "2", "3", "4"] +RADIX_TO_LUCIDE_SIZE = {"1": 12, "2": 24, "3": 36, "4": 48} class IconButton(elements.Button, RadixLoadingProp, RadixThemesComponent): @overload diff --git a/reflex/components/radix/themes/components/tooltip.py b/reflex/components/radix/themes/components/tooltip.py index 07bab1a4a..53ec35264 100644 --- a/reflex/components/radix/themes/components/tooltip.py +++ b/reflex/components/radix/themes/components/tooltip.py @@ -28,6 +28,9 @@ LiteralStickyType = Literal[ ] +ARIA_LABEL_KEY = "aria_label" + + # The Tooltip inherits props from the Tooltip.Root, Tooltip.Portal, Tooltip.Content class Tooltip(RadixThemesComponent): """Floating element that provides a control with contextual information via pointer or focus.""" @@ -104,7 +107,6 @@ class Tooltip(RadixThemesComponent): Returns: The created component. """ - ARIA_LABEL_KEY = "aria_label" if props.get(ARIA_LABEL_KEY) is not None: props[format.to_kebab_case(ARIA_LABEL_KEY)] = props.pop(ARIA_LABEL_KEY) diff --git a/reflex/components/radix/themes/components/tooltip.pyi b/reflex/components/radix/themes/components/tooltip.pyi index fab1d0c12..0786bfada 100644 --- a/reflex/components/radix/themes/components/tooltip.pyi +++ b/reflex/components/radix/themes/components/tooltip.pyi @@ -14,6 +14,7 @@ from ..base import RadixThemesComponent LiteralSideType = Literal["top", "right", "bottom", "left"] LiteralAlignType = Literal["start", "center", "end"] LiteralStickyType = Literal["partial", "always"] +ARIA_LABEL_KEY = "aria_label" class Tooltip(RadixThemesComponent): @overload diff --git a/reflex/components/recharts/polar.py b/reflex/components/recharts/polar.py index 1f4974d4c..7bb623d34 100644 --- a/reflex/components/recharts/polar.py +++ b/reflex/components/recharts/polar.py @@ -73,7 +73,7 @@ class Pie(Recharts): data: Var[List[Dict[str, Any]]] # Valid children components - _valid_children: List[str] = ["Cell", "LabelList"] + _valid_children: List[str] = ["Cell", "LabelList", "Bare"] # Stoke color. Default: rx.color("accent", 9) stroke: Var[Union[str, Color]] = LiteralVar.create(Color("accent", 9)) diff --git a/reflex/components/recharts/recharts.py b/reflex/components/recharts/recharts.py index d3fc20dc1..0d1b692f1 100644 --- a/reflex/components/recharts/recharts.py +++ b/reflex/components/recharts/recharts.py @@ -1,6 +1,6 @@ """A component that wraps a recharts lib.""" -from typing import Dict, Literal +from typing import Literal from reflex.components.component import Component, MemoizationLeaf, NoSSRComponent @@ -10,7 +10,7 @@ class Recharts(Component): library = "recharts@2.15.0" - def _get_style(self) -> Dict: + def _get_style(self) -> dict: return {"wrapperStyle": self.style} diff --git a/reflex/config.py b/reflex/config.py index d5eee8dfd..2daf8ef1d 100644 --- a/reflex/config.py +++ b/reflex/config.py @@ -390,7 +390,7 @@ class EnvVar(Generic[T]): os.environ[self.name] = str(value) -class env_var: # type: ignore +class env_var: # type: ignore # noqa: N801 """Descriptor for environment variables.""" name: str @@ -823,16 +823,16 @@ class Config(Base): if "api_url" not in self._non_default_attributes: # If running in Github Codespaces, override API_URL codespace_name = os.getenv("CODESPACE_NAME") - GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN = os.getenv( + github_codespaces_port_forwarding_domain = os.getenv( "GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN" ) # If running on Replit.com interactively, override API_URL to ensure we maintain the backend_port replit_dev_domain = os.getenv("REPLIT_DEV_DOMAIN") backend_port = kwargs.get("backend_port", self.backend_port) - if codespace_name and GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN: + if codespace_name and github_codespaces_port_forwarding_domain: self.api_url = ( f"https://{codespace_name}-{kwargs.get('backend_port', self.backend_port)}" - f".{GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}" + f".{github_codespaces_port_forwarding_domain}" ) elif replit_dev_domain and backend_port: self.api_url = f"https://{replit_dev_domain}:{backend_port}" diff --git a/reflex/event.py b/reflex/event.py index f44fa2b1c..6da65c366 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -534,10 +534,10 @@ class JavasciptKeyboardEvent: """Interface for a Javascript KeyboardEvent https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.""" key: str = "" - altKey: bool = False - ctrlKey: bool = False - metaKey: bool = False - shiftKey: bool = False + altKey: bool = False # noqa: N815 + ctrlKey: bool = False # noqa: N815 + metaKey: bool = False # noqa: N815 + shiftKey: bool = False # noqa: N815 def input_event(e: Var[JavascriptInputEvent]) -> Tuple[Var[str]]: diff --git a/reflex/experimental/hooks.py b/reflex/experimental/hooks.py index 7d648225a..e0d3b4a56 100644 --- a/reflex/experimental/hooks.py +++ b/reflex/experimental/hooks.py @@ -26,7 +26,7 @@ def const(name, value) -> Var: return Var(_js_expr=f"const {name} = {value}") -def useCallback(func, deps) -> Var: +def useCallback(func, deps) -> Var: # noqa: N802 """Create a useCallback hook with a function and dependencies. Args: @@ -42,7 +42,7 @@ def useCallback(func, deps) -> Var: ) -def useContext(context) -> Var: +def useContext(context) -> Var: # noqa: N802 """Create a useContext hook with a context. Args: @@ -57,7 +57,7 @@ def useContext(context) -> Var: ) -def useRef(default) -> Var: +def useRef(default) -> Var: # noqa: N802 """Create a useRef hook with a default value. Args: @@ -72,7 +72,7 @@ def useRef(default) -> Var: ) -def useState(var_name, default=None) -> Var: +def useState(var_name, default=None) -> Var: # noqa: N802 """Create a useState hook with a variable name and setter name. Args: diff --git a/reflex/experimental/layout.pyi b/reflex/experimental/layout.pyi index 4c7fc8d47..93c8c0137 100644 --- a/reflex/experimental/layout.pyi +++ b/reflex/experimental/layout.pyi @@ -109,7 +109,7 @@ class DrawerSidebar(DrawerRoot): snap_points: Optional[List[Union[float, str]]] = None, fade_from_index: Optional[Union[Var[int], int]] = None, scroll_lock_timeout: Optional[Union[Var[int], int]] = None, - preventScrollRestoration: Optional[Union[Var[bool], bool]] = None, + prevent_scroll_restoration: Optional[Union[Var[bool], bool]] = None, should_scale_background: Optional[Union[Var[bool], bool]] = None, close_threshold: Optional[Union[Var[float], float]] = None, as_child: Optional[Union[Var[bool], bool]] = None, diff --git a/reflex/state.py b/reflex/state.py index cb5b2b706..8085a92ec 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -93,14 +93,14 @@ from reflex.event import ( ) from reflex.utils import console, format, path_ops, prerequisites, types from reflex.utils.exceptions import ( - ComputedVarShadowsBaseVars, - ComputedVarShadowsStateVar, - DynamicComponentInvalidSignature, - DynamicRouteArgShadowsStateVar, - EventHandlerShadowsBuiltInStateMethod, + ComputedVarShadowsBaseVarsError, + ComputedVarShadowsStateVarError, + DynamicComponentInvalidSignatureError, + DynamicRouteArgShadowsStateVarError, + EventHandlerShadowsBuiltInStateMethodError, ImmutableStateError, InvalidLockWarningThresholdError, - InvalidStateManagerMode, + InvalidStateManagerModeError, LockExpiredError, ReflexRuntimeError, SetUndefinedStateVarError, @@ -815,7 +815,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): """Check for shadow methods and raise error if any. Raises: - EventHandlerShadowsBuiltInStateMethod: When an event handler shadows an inbuilt state method. + EventHandlerShadowsBuiltInStateMethodError: When an event handler shadows an inbuilt state method. """ overridden_methods = set() state_base_functions = cls._get_base_functions() @@ -829,7 +829,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): overridden_methods.add(method.__name__) for method_name in overridden_methods: - raise EventHandlerShadowsBuiltInStateMethod( + raise EventHandlerShadowsBuiltInStateMethodError( f"The event handler name `{method_name}` shadows a builtin State method; use a different name instead" ) @@ -838,11 +838,11 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): """Check for shadow base vars and raise error if any. Raises: - ComputedVarShadowsBaseVars: When a computed var shadows a base var. + ComputedVarShadowsBaseVarsError: When a computed var shadows a base var. """ for computed_var_ in cls._get_computed_vars(): if computed_var_._js_expr in cls.__annotations__: - raise ComputedVarShadowsBaseVars( + raise ComputedVarShadowsBaseVarsError( f"The computed var name `{computed_var_._js_expr}` shadows a base var in {cls.__module__}.{cls.__name__}; use a different name instead" ) @@ -851,14 +851,14 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): """Check for shadow computed vars and raise error if any. Raises: - ComputedVarShadowsStateVar: When a computed var shadows another. + ComputedVarShadowsStateVarError: When a computed var shadows another. """ for name, cv in cls.__dict__.items(): if not is_computed_var(cv): continue name = cv._js_expr if name in cls.inherited_vars or name in cls.inherited_backend_vars: - raise ComputedVarShadowsStateVar( + raise ComputedVarShadowsStateVarError( f"The computed var name `{cv._js_expr}` shadows a var in {cls.__module__}.{cls.__name__}; use a different name instead" ) @@ -1218,14 +1218,14 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): args: a dict of args Raises: - DynamicRouteArgShadowsStateVar: If a dynamic arg is shadowing an existing var. + DynamicRouteArgShadowsStateVarError: If a dynamic arg is shadowing an existing var. """ for arg in args: if ( arg in cls.computed_vars and not isinstance(cls.computed_vars[arg], DynamicRouteVar) ) or arg in cls.base_vars: - raise DynamicRouteArgShadowsStateVar( + raise DynamicRouteArgShadowsStateVarError( f"Dynamic route arg '{arg}' is shadowing an existing var in {cls.__module__}.{cls.__name__}" ) for substate in cls.get_substates(): @@ -2353,8 +2353,7 @@ def dynamic(func: Callable[[T], Component]): The dynamically generated component. Raises: - DynamicComponentInvalidSignature: If the function does not have exactly one parameter. - DynamicComponentInvalidSignature: If the function does not have a type hint for the state class. + DynamicComponentInvalidSignatureError: If the function does not have exactly one parameter or a type hint for the state class. """ number_of_parameters = len(inspect.signature(func).parameters) @@ -2366,12 +2365,12 @@ def dynamic(func: Callable[[T], Component]): values = list(func_signature.values()) if number_of_parameters != 1: - raise DynamicComponentInvalidSignature( + raise DynamicComponentInvalidSignatureError( "The function must have exactly one parameter, which is the state class." ) if len(values) != 1: - raise DynamicComponentInvalidSignature( + raise DynamicComponentInvalidSignatureError( "You must provide a type hint for the state class in the function." ) @@ -2875,7 +2874,7 @@ class StateManager(Base, ABC): state: The state class to use. Raises: - InvalidStateManagerMode: If the state manager mode is invalid. + InvalidStateManagerModeError: If the state manager mode is invalid. Returns: The state manager (either disk, memory or redis). @@ -2898,7 +2897,7 @@ class StateManager(Base, ABC): lock_expiration=config.redis_lock_expiration, lock_warning_threshold=config.redis_lock_warning_threshold, ) - raise InvalidStateManagerMode( + raise InvalidStateManagerModeError( f"Expected one of: DISK, MEMORY, REDIS, got {config.state_manager_mode}" ) @@ -4056,10 +4055,10 @@ def serialize_mutable_proxy(mp: MutableProxy): return mp.__wrapped__ -_orig_json_JSONEncoder_default = json.JSONEncoder.default +_orig_json_encoder_default = json.JSONEncoder.default -def _json_JSONEncoder_default_wrapper(self: json.JSONEncoder, o: Any) -> Any: +def _json_encoder_default_wrapper(self: json.JSONEncoder, o: Any) -> Any: """Wrap JSONEncoder.default to handle MutableProxy objects. Args: @@ -4073,10 +4072,10 @@ def _json_JSONEncoder_default_wrapper(self: json.JSONEncoder, o: Any) -> Any: return o.__wrapped__ except AttributeError: pass - return _orig_json_JSONEncoder_default(self, o) + return _orig_json_encoder_default(self, o) -json.JSONEncoder.default = _json_JSONEncoder_default_wrapper +json.JSONEncoder.default = _json_encoder_default_wrapper class ImmutableMutableProxy(MutableProxy): diff --git a/reflex/testing.py b/reflex/testing.py index ec8b80f66..7c6aab93b 100644 --- a/reflex/testing.py +++ b/reflex/testing.py @@ -87,7 +87,7 @@ else: # borrowed from py3.11 -class chdir(contextlib.AbstractContextManager): +class chdir(contextlib.AbstractContextManager): # noqa: N801 """Non thread-safe context manager to change the current working directory.""" def __init__(self, path): diff --git a/reflex/utils/codespaces.py b/reflex/utils/codespaces.py index 7ff686129..bb5286e31 100644 --- a/reflex/utils/codespaces.py +++ b/reflex/utils/codespaces.py @@ -42,10 +42,7 @@ def codespaces_port_forwarding_domain() -> str | None: Returns: The domain for port forwarding in Github Codespaces, or None if not running in Codespaces. """ - GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN = os.getenv( - "GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN" - ) - return GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN + return os.getenv("GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN") def is_running_in_codespaces() -> bool: diff --git a/reflex/utils/exceptions.py b/reflex/utils/exceptions.py index d35643753..692c7d64b 100644 --- a/reflex/utils/exceptions.py +++ b/reflex/utils/exceptions.py @@ -11,7 +11,7 @@ class ConfigError(ReflexError): """Custom exception for config related errors.""" -class InvalidStateManagerMode(ReflexError, ValueError): +class InvalidStateManagerModeError(ReflexError, ValueError): """Raised when an invalid state manager mode is provided.""" @@ -143,35 +143,35 @@ class EventFnArgMismatchError(ReflexError, TypeError): """Raised when the number of args required by an event handler is more than provided by the event trigger.""" -class DynamicRouteArgShadowsStateVar(ReflexError, NameError): +class DynamicRouteArgShadowsStateVarError(ReflexError, NameError): """Raised when a dynamic route arg shadows a state var.""" -class ComputedVarShadowsStateVar(ReflexError, NameError): +class ComputedVarShadowsStateVarError(ReflexError, NameError): """Raised when a computed var shadows a state var.""" -class ComputedVarShadowsBaseVars(ReflexError, NameError): +class ComputedVarShadowsBaseVarsError(ReflexError, NameError): """Raised when a computed var shadows a base var.""" -class EventHandlerShadowsBuiltInStateMethod(ReflexError, NameError): +class EventHandlerShadowsBuiltInStateMethodError(ReflexError, NameError): """Raised when an event handler shadows a built-in state method.""" -class GeneratedCodeHasNoFunctionDefs(ReflexError): +class GeneratedCodeHasNoFunctionDefsError(ReflexError): """Raised when refactored code generated with flexgen has no functions defined.""" -class PrimitiveUnserializableToJSON(ReflexError, ValueError): +class PrimitiveUnserializableToJSONError(ReflexError, ValueError): """Raised when a primitive type is unserializable to JSON. Usually with NaN and Infinity.""" -class InvalidLifespanTaskType(ReflexError, TypeError): +class InvalidLifespanTaskTypeError(ReflexError, TypeError): """Raised when an invalid task type is registered as a lifespan task.""" -class DynamicComponentMissingLibrary(ReflexError, ValueError): +class DynamicComponentMissingLibraryError(ReflexError, ValueError): """Raised when a dynamic component is missing a library.""" @@ -187,7 +187,7 @@ class EnvironmentVarValueError(ReflexError, ValueError): """Raised when an environment variable is set to an invalid value.""" -class DynamicComponentInvalidSignature(ReflexError, TypeError): +class DynamicComponentInvalidSignatureError(ReflexError, TypeError): """Raised when a dynamic component has an invalid signature.""" diff --git a/reflex/utils/exec.py b/reflex/utils/exec.py index 9ee0f1018..9a5b70112 100644 --- a/reflex/utils/exec.py +++ b/reflex/utils/exec.py @@ -364,11 +364,11 @@ def run_uvicorn_backend_prod(host, port, loglevel): app_module = get_app_module() - 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() + 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, + *run_backend_prod_windows, "--host", host, "--port", @@ -377,7 +377,7 @@ def run_uvicorn_backend_prod(host, port, loglevel): ] if constants.IS_WINDOWS else [ - *RUN_BACKEND_PROD, + *run_backend_prod, "--bind", f"{host}:{port}", "--threads", diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index 1e33c4b8a..94d8f8fbd 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -38,7 +38,7 @@ from reflex.compiler import templates from reflex.config import Config, environment, get_config from reflex.utils import console, net, path_ops, processes, redir from reflex.utils.exceptions import ( - GeneratedCodeHasNoFunctionDefs, + GeneratedCodeHasNoFunctionDefsError, SystemPackageMissingError, ) from reflex.utils.format import format_library_name @@ -1816,7 +1816,7 @@ def initialize_main_module_index_from_generation(app_name: str, generation_hash: generation_hash: The generation hash from reflex.build. Raises: - GeneratedCodeHasNoFunctionDefs: If the fetched code has no function definitions + GeneratedCodeHasNoFunctionDefsError: If the fetched code has no function definitions (the refactored reflex code is expected to have at least one root function defined). """ # Download the reflex code for the generation. @@ -1833,7 +1833,7 @@ def initialize_main_module_index_from_generation(app_name: str, generation_hash: # Determine the name of the last function, which renders the generated code. defined_funcs = re.findall(r"def ([a-zA-Z_]+)\(", resp.text) if not defined_funcs: - raise GeneratedCodeHasNoFunctionDefs( + raise GeneratedCodeHasNoFunctionDefsError( f"No function definitions found in generated code from {url!r}." ) render_func_name = defined_funcs[-1] diff --git a/reflex/vars/base.py b/reflex/vars/base.py index 1bb346c65..8fb543c99 100644 --- a/reflex/vars/base.py +++ b/reflex/vars/base.py @@ -1555,7 +1555,7 @@ def figure_out_type(value: Any) -> types.GenericType: return type(value) -class cached_property_no_lock(functools.cached_property): +class cached_property_no_lock(functools.cached_property): # noqa: N801 """A special version of functools.cached_property that does not use a lock.""" def __init__(self, func): diff --git a/reflex/vars/number.py b/reflex/vars/number.py index a2a0293d5..082334450 100644 --- a/reflex/vars/number.py +++ b/reflex/vars/number.py @@ -18,7 +18,7 @@ from typing import ( ) from reflex.constants.base import Dirs -from reflex.utils.exceptions import PrimitiveUnserializableToJSON, VarTypeError +from reflex.utils.exceptions import PrimitiveUnserializableToJSONError, VarTypeError from reflex.utils.imports import ImportDict, ImportVar from .base import ( @@ -987,10 +987,10 @@ class LiteralNumberVar(LiteralVar, NumberVar): The JSON representation of the var. Raises: - PrimitiveUnserializableToJSON: If the var is unserializable to JSON. + PrimitiveUnserializableToJSONError: If the var is unserializable to JSON. """ if math.isinf(self._var_value) or math.isnan(self._var_value): - raise PrimitiveUnserializableToJSON( + raise PrimitiveUnserializableToJSONError( f"No valid JSON representation for {self}" ) return json.dumps(self._var_value) diff --git a/tests/units/conftest.py b/tests/units/conftest.py index fb6229aca..8c1ffe532 100644 --- a/tests/units/conftest.py +++ b/tests/units/conftest.py @@ -1,11 +1,8 @@ """Test fixtures.""" import asyncio -import contextlib -import os import platform import uuid -from pathlib import Path from typing import Dict, Generator, Type from unittest import mock @@ -14,6 +11,7 @@ import pytest from reflex.app import App from reflex.event import EventSpec from reflex.model import ModelRegistry +from reflex.testing import chdir from reflex.utils import prerequisites from .states import ( @@ -191,33 +189,6 @@ def router_data(router_data_headers) -> Dict[str, str]: } -# borrowed from py3.11 -class chdir(contextlib.AbstractContextManager): - """Non thread-safe context manager to change the current working directory.""" - - def __init__(self, path): - """Prepare contextmanager. - - Args: - path: the path to change to - """ - self.path = path - self._old_cwd = [] - - def __enter__(self): - """Save current directory and perform chdir.""" - self._old_cwd.append(Path.cwd()) - os.chdir(self.path) - - def __exit__(self, *excinfo): - """Change back to previous directory on stack. - - Args: - excinfo: sys.exc_info captured in the context block - """ - os.chdir(self._old_cwd.pop()) - - @pytest.fixture def tmp_working_dir(tmp_path): """Create a temporary directory and chdir to it. diff --git a/tests/units/test_var.py b/tests/units/test_var.py index d071d1dba..88f05a53e 100644 --- a/tests/units/test_var.py +++ b/tests/units/test_var.py @@ -12,7 +12,7 @@ from reflex.base import Base from reflex.constants.base import REFLEX_VAR_CLOSING_TAG, REFLEX_VAR_OPENING_TAG from reflex.state import BaseState from reflex.utils.exceptions import ( - PrimitiveUnserializableToJSON, + PrimitiveUnserializableToJSONError, UntypedComputedVarError, ) from reflex.utils.imports import ImportVar @@ -1061,7 +1061,7 @@ def test_inf_and_nan(var, expected_js): assert str(var) == expected_js assert isinstance(var, NumberVar) assert isinstance(var, LiteralVar) - with pytest.raises(PrimitiveUnserializableToJSON): + with pytest.raises(PrimitiveUnserializableToJSONError): var.json() From 9dba8cd49430537ce44ecb255e3d618db7b14bfd Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Thu, 23 Jan 2025 06:29:31 -0800 Subject: [PATCH 12/12] use older version of python for windows simple benchmarks (#4680) --- .github/workflows/benchmarks.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index ec8c1409f..6da40ef6f 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -85,6 +85,8 @@ jobs: exclude: - os: windows-latest python-version: "3.10.16" + - os: windows-latest + python-version: "3.11.11" # keep only one python version for MacOS - os: macos-latest python-version: "3.10.16" @@ -93,6 +95,8 @@ jobs: include: - os: windows-latest python-version: "3.10.11" + - os: windows-latest + python-version: "3.11.9" runs-on: ${{ matrix.os }} steps: