From 79a5409a8ef4bb30393ff7abf7ffec6578fe41f8 Mon Sep 17 00:00:00 2001 From: Alek Petuskey Date: Wed, 13 Nov 2024 20:42:29 -0800 Subject: [PATCH 01/71] Update bug_report.md (#4382) --- .github/ISSUE_TEMPLATE/bug_report.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 4ba472338..b3966b5d0 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -2,7 +2,6 @@ name: Bug report about: Create a report to help us improve title: '' -labels: bug assignees: '' --- From e45b76c01e1e9abf832e88b34a86b539125e1d97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Fri, 15 Nov 2024 12:43:55 -0800 Subject: [PATCH 02/71] fix noSSRComponent imports (#4386) --- reflex/components/component.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/reflex/components/component.py b/reflex/components/component.py index face5d557..4b850ba7d 100644 --- a/reflex/components/component.py +++ b/reflex/components/component.py @@ -1904,6 +1904,11 @@ memo = custom_component class NoSSRComponent(Component): """A dynamic component that is not rendered on the server.""" + def _get_import_name(self) -> None | str: + if not self.library: + return None + return f"${self.library}" if self.library.startswith("/") else self.library + def _get_imports(self) -> ParsedImportDict: """Get the imports for the component. @@ -1917,8 +1922,9 @@ class NoSSRComponent(Component): _imports = super()._get_imports() # Do NOT import the main library/tag statically. - if self.library is not None: - _imports[self.library] = [ + import_name = self._get_import_name() + if import_name is not None: + _imports[import_name] = [ imports.ImportVar( tag=None, render=False, @@ -1936,10 +1942,10 @@ class NoSSRComponent(Component): opts_fragment = ", { ssr: false });" # extract the correct import name from library name - if self.library is None: + base_import_name = self._get_import_name() + if base_import_name is None: raise ValueError("Undefined library for NoSSRComponent") - - import_name = format.format_library_name(self.library) + import_name = format.format_library_name(base_import_name) library_import = f"const {self.alias if self.alias else self.tag} = dynamic(() => import('{import_name}')" mod_import = ( From dc347d10b3bcb8caec9dc8247a17bbd2b4f179de Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Sat, 16 Nov 2024 01:27:05 +0100 Subject: [PATCH 03/71] fix: Failed to CreateArtifact (#4339) --- .github/workflows/integration_app_harness.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration_app_harness.yml b/.github/workflows/integration_app_harness.yml index ee9394b7e..6ac5fe6ab 100644 --- a/.github/workflows/integration_app_harness.yml +++ b/.github/workflows/integration_app_harness.yml @@ -50,7 +50,7 @@ jobs: - run: poetry run uv pip install pyvirtualdisplay pillow pytest-split - name: Run app harness tests env: - SCREENSHOT_DIR: /tmp/screenshots + 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 --with-deps From 34c11fdf108395fcacbe2488655969fef5c7958c Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Mon, 18 Nov 2024 10:31:11 -0800 Subject: [PATCH 04/71] require typing_extensions >= 4.6.0 (#4373) * require typing_extensions >= 4.6.0 TypeAliasType was added in 4.6 https://github.com/python/typing_extensions/blob/main/CHANGELOG.md#release-460-may-22-2023 * update lock file, even though nothing has changed --- poetry.lock | 2 +- pyproject.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 8199c975a..55ce64a09 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3050,4 +3050,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "937f0cadb1a4566117dad8d0be6018ad1a8fe9aeb19c499d2a010d36ef391ee1" +content-hash = "8975c9e30cd8e1d1968f2344218ea4fa0548462edff4bee4046513882b7bad25" diff --git a/pyproject.toml b/pyproject.toml index 20bf81d92..f251b0ba8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,6 +59,7 @@ twine = ">=4.0.0,<6.0" tomlkit = ">=0.12.4,<1.0" lazy_loader = ">=0.4" reflex-chakra = ">=0.6.0" +typing_extensions = ">=4.6.0" [tool.poetry.group.dev.dependencies] pytest = ">=7.1.2,<9.0" From 6494683c275b82ccfad503a302a6c04f1e78cfb4 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Mon, 18 Nov 2024 15:11:04 -0800 Subject: [PATCH 05/71] Fix ternary logic when printing template name (#4393) --- reflex/reflex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reflex/reflex.py b/reflex/reflex.py index b0aa51090..a9a1e5455 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -120,7 +120,7 @@ def _init( # Initialize the requirements.txt. prerequisites.initialize_requirements_txt() - template_msg = "" if template else f" using the {template} template" + template_msg = "" if not template else f" using the {template} template" # Finish initializing the app. console.success(f"Initialized {app_name}{template_msg}") From 3f58ceef955f9c22c2f217ee2fc0a0761378800b Mon Sep 17 00:00:00 2001 From: Simon Young <40179067+Kastier1@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:59:54 -0800 Subject: [PATCH 06/71] update cli version (#4394) Co-authored-by: simon --- poetry.lock | 371 ++++++++++++++++++++++------------------------- pyproject.toml | 2 +- reflex/reflex.py | 15 +- 3 files changed, 187 insertions(+), 201 deletions(-) diff --git a/poetry.lock b/poetry.lock index 55ce64a09..c19780931 100644 --- a/poetry.lock +++ b/poetry.lock @@ -386,73 +386,73 @@ files = [ [[package]] name = "coverage" -version = "7.6.4" +version = "7.6.7" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" files = [ - {file = "coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07"}, - {file = "coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0"}, - {file = "coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72"}, - {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51"}, - {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491"}, - {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b"}, - {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea"}, - {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a"}, - {file = "coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa"}, - {file = "coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172"}, - {file = "coverage-7.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b"}, - {file = "coverage-7.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25"}, - {file = "coverage-7.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546"}, - {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b"}, - {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e"}, - {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718"}, - {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db"}, - {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522"}, - {file = "coverage-7.6.4-cp311-cp311-win32.whl", hash = "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf"}, - {file = "coverage-7.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19"}, - {file = "coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2"}, - {file = "coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117"}, - {file = "coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613"}, - {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27"}, - {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52"}, - {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2"}, - {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1"}, - {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5"}, - {file = "coverage-7.6.4-cp312-cp312-win32.whl", hash = "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17"}, - {file = "coverage-7.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08"}, - {file = "coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9"}, - {file = "coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba"}, - {file = "coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c"}, - {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06"}, - {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f"}, - {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b"}, - {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21"}, - {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a"}, - {file = "coverage-7.6.4-cp313-cp313-win32.whl", hash = "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e"}, - {file = "coverage-7.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963"}, - {file = "coverage-7.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f"}, - {file = "coverage-7.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806"}, - {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11"}, - {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3"}, - {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a"}, - {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc"}, - {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70"}, - {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef"}, - {file = "coverage-7.6.4-cp313-cp313t-win32.whl", hash = "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e"}, - {file = "coverage-7.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1"}, - {file = "coverage-7.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3"}, - {file = "coverage-7.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c"}, - {file = "coverage-7.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076"}, - {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376"}, - {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0"}, - {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858"}, - {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111"}, - {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901"}, - {file = "coverage-7.6.4-cp39-cp39-win32.whl", hash = "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09"}, - {file = "coverage-7.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f"}, - {file = "coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e"}, - {file = "coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73"}, + {file = "coverage-7.6.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:108bb458827765d538abcbf8288599fee07d2743357bdd9b9dad456c287e121e"}, + {file = "coverage-7.6.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c973b2fe4dc445cb865ab369df7521df9c27bf40715c837a113edaa2aa9faf45"}, + {file = "coverage-7.6.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c6b24007c4bcd0b19fac25763a7cac5035c735ae017e9a349b927cfc88f31c1"}, + {file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acbb8af78f8f91b3b51f58f288c0994ba63c646bc1a8a22ad072e4e7e0a49f1c"}, + {file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad32a981bcdedb8d2ace03b05e4fd8dace8901eec64a532b00b15217d3677dd2"}, + {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:34d23e28ccb26236718a3a78ba72744212aa383141961dd6825f6595005c8b06"}, + {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e25bacb53a8c7325e34d45dddd2f2fbae0dbc230d0e2642e264a64e17322a777"}, + {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af05bbba896c4472a29408455fe31b3797b4d8648ed0a2ccac03e074a77e2314"}, + {file = "coverage-7.6.7-cp310-cp310-win32.whl", hash = "sha256:796c9b107d11d2d69e1849b2dfe41730134b526a49d3acb98ca02f4985eeff7a"}, + {file = "coverage-7.6.7-cp310-cp310-win_amd64.whl", hash = "sha256:987a8e3da7da4eed10a20491cf790589a8e5e07656b6dc22d3814c4d88faf163"}, + {file = "coverage-7.6.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e61b0e77ff4dddebb35a0e8bb5a68bf0f8b872407d8d9f0c726b65dfabe2469"}, + {file = "coverage-7.6.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a5407a75ca4abc20d6252efeb238377a71ce7bda849c26c7a9bece8680a5d99"}, + {file = "coverage-7.6.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df002e59f2d29e889c37abd0b9ee0d0e6e38c24f5f55d71ff0e09e3412a340ec"}, + {file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:673184b3156cba06154825f25af33baa2671ddae6343f23175764e65a8c4c30b"}, + {file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e69ad502f1a2243f739f5bd60565d14a278be58be4c137d90799f2c263e7049a"}, + {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60dcf7605c50ea72a14490d0756daffef77a5be15ed1b9fea468b1c7bda1bc3b"}, + {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9c2eb378bebb2c8f65befcb5147877fc1c9fbc640fc0aad3add759b5df79d55d"}, + {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c0317288f032221d35fa4cbc35d9f4923ff0dfd176c79c9b356e8ef8ef2dff4"}, + {file = "coverage-7.6.7-cp311-cp311-win32.whl", hash = "sha256:951aade8297358f3618a6e0660dc74f6b52233c42089d28525749fc8267dccd2"}, + {file = "coverage-7.6.7-cp311-cp311-win_amd64.whl", hash = "sha256:5e444b8e88339a2a67ce07d41faabb1d60d1004820cee5a2c2b54e2d8e429a0f"}, + {file = "coverage-7.6.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f07ff574986bc3edb80e2c36391678a271d555f91fd1d332a1e0f4b5ea4b6ea9"}, + {file = "coverage-7.6.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:49ed5ee4109258973630c1f9d099c7e72c5c36605029f3a91fe9982c6076c82b"}, + {file = "coverage-7.6.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3e8796434a8106b3ac025fd15417315d7a58ee3e600ad4dbcfddc3f4b14342c"}, + {file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3b925300484a3294d1c70f6b2b810d6526f2929de954e5b6be2bf8caa1f12c1"}, + {file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c42ec2c522e3ddd683dec5cdce8e62817afb648caedad9da725001fa530d354"}, + {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0266b62cbea568bd5e93a4da364d05de422110cbed5056d69339bd5af5685433"}, + {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e5f2a0f161d126ccc7038f1f3029184dbdf8f018230af17ef6fd6a707a5b881f"}, + {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c132b5a22821f9b143f87446805e13580b67c670a548b96da945a8f6b4f2efbb"}, + {file = "coverage-7.6.7-cp312-cp312-win32.whl", hash = "sha256:7c07de0d2a110f02af30883cd7dddbe704887617d5c27cf373362667445a4c76"}, + {file = "coverage-7.6.7-cp312-cp312-win_amd64.whl", hash = "sha256:fd49c01e5057a451c30c9b892948976f5d38f2cbd04dc556a82743ba8e27ed8c"}, + {file = "coverage-7.6.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:46f21663e358beae6b368429ffadf14ed0a329996248a847a4322fb2e35d64d3"}, + {file = "coverage-7.6.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:40cca284c7c310d622a1677f105e8507441d1bb7c226f41978ba7c86979609ab"}, + {file = "coverage-7.6.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77256ad2345c29fe59ae861aa11cfc74579c88d4e8dbf121cbe46b8e32aec808"}, + {file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87ea64b9fa52bf395272e54020537990a28078478167ade6c61da7ac04dc14bc"}, + {file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d608a7808793e3615e54e9267519351c3ae204a6d85764d8337bd95993581a8"}, + {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdd94501d65adc5c24f8a1a0eda110452ba62b3f4aeaba01e021c1ed9cb8f34a"}, + {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82c809a62e953867cf57e0548c2b8464207f5f3a6ff0e1e961683e79b89f2c55"}, + {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb684694e99d0b791a43e9fc0fa58efc15ec357ac48d25b619f207c41f2fd384"}, + {file = "coverage-7.6.7-cp313-cp313-win32.whl", hash = "sha256:963e4a08cbb0af6623e61492c0ec4c0ec5c5cf74db5f6564f98248d27ee57d30"}, + {file = "coverage-7.6.7-cp313-cp313-win_amd64.whl", hash = "sha256:14045b8bfd5909196a90da145a37f9d335a5d988a83db34e80f41e965fb7cb42"}, + {file = "coverage-7.6.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f2c7a045eef561e9544359a0bf5784b44e55cefc7261a20e730baa9220c83413"}, + {file = "coverage-7.6.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dd4e4a49d9c72a38d18d641135d2fb0bdf7b726ca60a103836b3d00a1182acd"}, + {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c95e0fa3d1547cb6f021ab72f5c23402da2358beec0a8e6d19a368bd7b0fb37"}, + {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f63e21ed474edd23f7501f89b53280014436e383a14b9bd77a648366c81dce7b"}, + {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead9b9605c54d15be228687552916c89c9683c215370c4a44f1f217d2adcc34d"}, + {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0573f5cbf39114270842d01872952d301027d2d6e2d84013f30966313cadb529"}, + {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:e2c8e3384c12dfa19fa9a52f23eb091a8fad93b5b81a41b14c17c78e23dd1d8b"}, + {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:70a56a2ec1869e6e9fa69ef6b76b1a8a7ef709972b9cc473f9ce9d26b5997ce3"}, + {file = "coverage-7.6.7-cp313-cp313t-win32.whl", hash = "sha256:dbba8210f5067398b2c4d96b4e64d8fb943644d5eb70be0d989067c8ca40c0f8"}, + {file = "coverage-7.6.7-cp313-cp313t-win_amd64.whl", hash = "sha256:dfd14bcae0c94004baba5184d1c935ae0d1231b8409eb6c103a5fd75e8ecdc56"}, + {file = "coverage-7.6.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37a15573f988b67f7348916077c6d8ad43adb75e478d0910957394df397d2874"}, + {file = "coverage-7.6.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b6cce5c76985f81da3769c52203ee94722cd5d5889731cd70d31fee939b74bf0"}, + {file = "coverage-7.6.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ab9763d291a17b527ac6fd11d1a9a9c358280adb320e9c2672a97af346ac2c"}, + {file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cf96ceaa275f071f1bea3067f8fd43bec184a25a962c754024c973af871e1b7"}, + {file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aee9cf6b0134d6f932d219ce253ef0e624f4fa588ee64830fcba193269e4daa3"}, + {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2bc3e45c16564cc72de09e37413262b9f99167803e5e48c6156bccdfb22c8327"}, + {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:623e6965dcf4e28a3debaa6fcf4b99ee06d27218f46d43befe4db1c70841551c"}, + {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:850cfd2d6fc26f8346f422920ac204e1d28814e32e3a58c19c91980fa74d8289"}, + {file = "coverage-7.6.7-cp39-cp39-win32.whl", hash = "sha256:c296263093f099da4f51b3dff1eff5d4959b527d4f2f419e16508c5da9e15e8c"}, + {file = "coverage-7.6.7-cp39-cp39-win_amd64.whl", hash = "sha256:90746521206c88bdb305a4bf3342b1b7316ab80f804d40c536fc7d329301ee13"}, + {file = "coverage-7.6.7-pp39.pp310-none-any.whl", hash = "sha256:0ddcb70b3a3a57581b450571b31cb774f23eb9519c2aaa6176d3a84c9fc57671"}, + {file = "coverage-7.6.7.tar.gz", hash = "sha256:d79d4826e41441c9a118ff045e4bccb9fdbdcb1d02413e7ea6eb5c87b5439d24"}, ] [package.dependencies] @@ -585,13 +585,13 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.115.4" +version = "0.115.5" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.115.4-py3-none-any.whl", hash = "sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742"}, - {file = "fastapi-0.115.4.tar.gz", hash = "sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349"}, + {file = "fastapi-0.115.5-py3-none-any.whl", hash = "sha256:596b95adbe1474da47049e802f9a65ab2ffa9c2b07e7efee70eb8a66c9f2f796"}, + {file = "fastapi-0.115.5.tar.gz", hash = "sha256:0e7a4d0dc0d01c68df21887cce0945e72d3c48b9f4f79dfe7a7d53aa08fbb289"}, ] [package.dependencies] @@ -739,13 +739,13 @@ files = [ [[package]] name = "httpcore" -version = "1.0.6" +version = "1.0.7" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f"}, - {file = "httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f"}, + {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, + {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, ] [package.dependencies] @@ -785,13 +785,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "identify" -version = "2.6.1" +version = "2.6.2" description = "File identification library for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"}, - {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"}, + {file = "identify-2.6.2-py2.py3-none-any.whl", hash = "sha256:c097384259f49e372f4ea00a19719d95ae27dd5ff0fd77ad630aa891306b82f3"}, + {file = "identify-2.6.2.tar.gz", hash = "sha256:fab5c716c24d7a789775228823797296a2994b075fb6080ac83a102772a98cbd"}, ] [package.extras] @@ -1288,13 +1288,13 @@ attrs = ">=19.2.0" [[package]] name = "packaging" -version = "24.1" +version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -1350,8 +1350,8 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.23.2", markers = "python_version == \"3.11\""}, {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, + {version = ">=1.23.2", markers = "python_version == \"3.11\""}, {version = ">=1.22.4", markers = "python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" @@ -1669,8 +1669,8 @@ files = [ annotated-types = ">=0.6.0" pydantic-core = "2.23.4" typing-extensions = [ - {version = ">=4.6.1", markers = "python_version < \"3.13\""}, {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, ] [package.extras] @@ -2198,13 +2198,13 @@ reflex = ">=0.6.0a" [[package]] name = "reflex-hosting-cli" -version = "0.1.15" +version = "0.1.16" description = "Reflex Hosting CLI" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "reflex_hosting_cli-0.1.15-py3-none-any.whl", hash = "sha256:c471f5570b8797e290844edcc079241aa27457112c01188dc0f8a5ccc2364003"}, - {file = "reflex_hosting_cli-0.1.15.tar.gz", hash = "sha256:42a2a030b8bfba728cbd2c5cc37df0fcc8c2966efc649c57806c6616efb994c4"}, + {file = "reflex_hosting_cli-0.1.16-py3-none-any.whl", hash = "sha256:1b12c2a76a27571102cacf5ec3028fb09816a51568bff793735e66aaad886605"}, + {file = "reflex_hosting_cli-0.1.16.tar.gz", hash = "sha256:9c9826318fd3d388b706be70f1f500a35e355f8f86f54138e7789fd6096a4ab9"}, ] [package.dependencies] @@ -2350,23 +2350,23 @@ websocket-client = ">=1.8,<2.0" [[package]] name = "setuptools" -version = "75.3.0" +version = "75.5.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "setuptools-75.3.0-py3-none-any.whl", hash = "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd"}, - {file = "setuptools-75.3.0.tar.gz", hash = "sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686"}, + {file = "setuptools-75.5.0-py3-none-any.whl", hash = "sha256:87cb777c3b96d638ca02031192d40390e0ad97737e27b6b4fa831bea86f2f829"}, + {file = "setuptools-75.5.0.tar.gz", hash = "sha256:5c4ccb41111392671f02bb5f8436dfc5a9a7185e80500531b133f5775c4163ef"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.7.0)"] +core = ["importlib-metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.12.*)", "pytest-mypy"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (>=1.12,<1.14)", "pytest-mypy"] [[package]] name = "shellingham" @@ -2542,13 +2542,13 @@ SQLAlchemy = ">=2.0.14,<2.1.0" [[package]] name = "starlette" -version = "0.41.2" +version = "0.41.3" description = "The little ASGI library that shines." optional = false python-versions = ">=3.8" files = [ - {file = "starlette-0.41.2-py3-none-any.whl", hash = "sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d"}, - {file = "starlette-0.41.2.tar.gz", hash = "sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62"}, + {file = "starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7"}, + {file = "starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835"}, ] [package.dependencies] @@ -2634,13 +2634,13 @@ files = [ [[package]] name = "tomli" -version = "2.0.2" +version = "2.1.0" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" files = [ - {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, - {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, + {file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"}, + {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"}, ] [[package]] @@ -2714,13 +2714,13 @@ urllib3 = ">=1.26.0" [[package]] name = "typer" -version = "0.13.0" +version = "0.13.1" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false python-versions = ">=3.7" files = [ - {file = "typer-0.13.0-py3-none-any.whl", hash = "sha256:d85fe0b777b2517cc99c8055ed735452f2659cd45e451507c76f48ce5c1d00e2"}, - {file = "typer-0.13.0.tar.gz", hash = "sha256:f1c7198347939361eec90139ffa0fd8b3df3a2259d5852a0f7400e476d95985c"}, + {file = "typer-0.13.1-py3-none-any.whl", hash = "sha256:5b59580fd925e89463a29d363e0a43245ec02765bde9fb77d39e5d0f29dd7157"}, + {file = "typer-0.13.1.tar.gz", hash = "sha256:9d444cb96cc268ce6f8b94e13b4335084cef4c079998a9f4851a90229a3bd25c"}, ] [package.dependencies] @@ -2828,108 +2828,91 @@ test = ["websockets"] [[package]] name = "websockets" -version = "13.1" +version = "14.1" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"}, - {file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"}, - {file = "websockets-13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f"}, - {file = "websockets-13.1-cp310-cp310-win32.whl", hash = "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe"}, - {file = "websockets-13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a"}, - {file = "websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19"}, - {file = "websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5"}, - {file = "websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9"}, - {file = "websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f"}, - {file = "websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557"}, - {file = "websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc"}, - {file = "websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49"}, - {file = "websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf"}, - {file = "websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c"}, - {file = "websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3"}, - {file = "websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6"}, - {file = "websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708"}, - {file = "websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6"}, - {file = "websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d"}, - {file = "websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2"}, - {file = "websockets-13.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c7934fd0e920e70468e676fe7f1b7261c1efa0d6c037c6722278ca0228ad9d0d"}, - {file = "websockets-13.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:149e622dc48c10ccc3d2760e5f36753db9cacf3ad7bc7bbbfd7d9c819e286f23"}, - {file = "websockets-13.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a569eb1b05d72f9bce2ebd28a1ce2054311b66677fcd46cf36204ad23acead8c"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95df24ca1e1bd93bbca51d94dd049a984609687cb2fb08a7f2c56ac84e9816ea"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8dbb1bf0c0a4ae8b40bdc9be7f644e2f3fb4e8a9aca7145bfa510d4a374eeb7"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:035233b7531fb92a76beefcbf479504db8c72eb3bff41da55aecce3a0f729e54"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e4450fc83a3df53dec45922b576e91e94f5578d06436871dce3a6be38e40f5db"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:463e1c6ec853202dd3657f156123d6b4dad0c546ea2e2e38be2b3f7c5b8e7295"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6d6855bbe70119872c05107e38fbc7f96b1d8cb047d95c2c50869a46c65a8e96"}, - {file = "websockets-13.1-cp38-cp38-win32.whl", hash = "sha256:204e5107f43095012b00f1451374693267adbb832d29966a01ecc4ce1db26faf"}, - {file = "websockets-13.1-cp38-cp38-win_amd64.whl", hash = "sha256:485307243237328c022bc908b90e4457d0daa8b5cf4b3723fd3c4a8012fce4c6"}, - {file = "websockets-13.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9b37c184f8b976f0c0a231a5f3d6efe10807d41ccbe4488df8c74174805eea7d"}, - {file = "websockets-13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:163e7277e1a0bd9fb3c8842a71661ad19c6aa7bb3d6678dc7f89b17fbcc4aeb7"}, - {file = "websockets-13.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b889dbd1342820cc210ba44307cf75ae5f2f96226c0038094455a96e64fb07a"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:586a356928692c1fed0eca68b4d1c2cbbd1ca2acf2ac7e7ebd3b9052582deefa"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7bd6abf1e070a6b72bfeb71049d6ad286852e285f146682bf30d0296f5fbadfa"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2aad13a200e5934f5a6767492fb07151e1de1d6079c003ab31e1823733ae79"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:df01aea34b6e9e33572c35cd16bae5a47785e7d5c8cb2b54b2acdb9678315a17"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e54affdeb21026329fb0744ad187cf812f7d3c2aa702a5edb562b325191fcab6"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9ef8aa8bdbac47f4968a5d66462a2a0935d044bf35c0e5a8af152d58516dbeb5"}, - {file = "websockets-13.1-cp39-cp39-win32.whl", hash = "sha256:deeb929efe52bed518f6eb2ddc00cc496366a14c726005726ad62c2dd9017a3c"}, - {file = "websockets-13.1-cp39-cp39-win_amd64.whl", hash = "sha256:7c65ffa900e7cc958cd088b9a9157a8141c991f8c53d11087e6fb7277a03f81d"}, - {file = "websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238"}, - {file = "websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a"}, - {file = "websockets-13.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23"}, - {file = "websockets-13.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9156c45750b37337f7b0b00e6248991a047be4aa44554c9886fe6bdd605aab3b"}, - {file = "websockets-13.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80c421e07973a89fbdd93e6f2003c17d20b69010458d3a8e37fb47874bd67d51"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82d0ba76371769d6a4e56f7e83bb8e81846d17a6190971e38b5de108bde9b0d7"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9875a0143f07d74dc5e1ded1c4581f0d9f7ab86c78994e2ed9e95050073c94d"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11e38ad8922c7961447f35c7b17bffa15de4d17c70abd07bfbe12d6faa3e027"}, - {file = "websockets-13.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4059f790b6ae8768471cddb65d3c4fe4792b0ab48e154c9f0a04cefaabcd5978"}, - {file = "websockets-13.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25c35bf84bf7c7369d247f0b8cfa157f989862c49104c5cf85cb5436a641d93e"}, - {file = "websockets-13.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:83f91d8a9bb404b8c2c41a707ac7f7f75b9442a0a876df295de27251a856ad09"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a43cfdcddd07f4ca2b1afb459824dd3c6d53a51410636a2c7fc97b9a8cf4842"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a2ef1381632a2f0cb4efeff34efa97901c9fbc118e01951ad7cfc10601a9bb"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459bf774c754c35dbb487360b12c5727adab887f1622b8aed5755880a21c4a20"}, - {file = "websockets-13.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:95858ca14a9f6fa8413d29e0a585b31b278388aa775b8a81fa24830123874678"}, - {file = "websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f"}, - {file = "websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878"}, + {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"}, ] [[package]] name = "wheel" -version = "0.44.0" +version = "0.45.0" description = "A built-package format for Python" optional = false python-versions = ">=3.8" files = [ - {file = "wheel-0.44.0-py3-none-any.whl", hash = "sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f"}, - {file = "wheel-0.44.0.tar.gz", hash = "sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49"}, + {file = "wheel-0.45.0-py3-none-any.whl", hash = "sha256:52f0baa5e6522155090a09c6bd95718cc46956d1b51d537ea5454249edb671c7"}, + {file = "wheel-0.45.0.tar.gz", hash = "sha256:a57353941a3183b3d5365346b567a260a0602a0f8a635926a7dede41b94c674a"}, ] [package.extras] @@ -3030,13 +3013,13 @@ h11 = ">=0.9.0,<1" [[package]] name = "zipp" -version = "3.20.2" +version = "3.21.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, - {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, ] [package.extras] @@ -3050,4 +3033,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "8975c9e30cd8e1d1968f2344218ea4fa0548462edff4bee4046513882b7bad25" +content-hash = "600773827321e7a0fdb2fe7d6af650a039dff759ce6df9c51ca22f0d7df4c290" diff --git a/pyproject.toml b/pyproject.toml index f251b0ba8..b2b7b79d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ wrapt = [ {version = ">=1.11.0,<2.0", python = "<3.11"}, ] packaging = ">=23.1,<25.0" -reflex-hosting-cli = ">=0.1.15,<2.0" +reflex-hosting-cli = ">=0.1.16,<2.0" charset-normalizer = ">=3.3.2,<4.0" wheel = ">=0.42.0,<1.0" build = ">=1.0.3,<2.0" diff --git a/reflex/reflex.py b/reflex/reflex.py index a9a1e5455..3fedc2ef5 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -11,7 +11,7 @@ import typer import typer.core from reflex_cli.deployments import deployments_cli from reflex_cli.utils import dependency -from reflex_cli.v2.deployments import hosting_cli +from reflex_cli.v2.deployments import check_version, hosting_cli from reflex import constants from reflex.config import environment, get_config @@ -390,6 +390,8 @@ def loginv2(loglevel: constants.LogLevel = typer.Option(config.loglevel)): """Authenicate with experimental Reflex hosting service.""" from reflex_cli.v2 import cli as hosting_cli + check_version() + hosting_cli.login() @@ -418,6 +420,8 @@ def logoutv2( """Log out of access to Reflex hosting service.""" from reflex_cli.v2.utils import hosting + check_version() + console.set_log_level(loglevel) hosting.log_out_on_browser() @@ -637,7 +641,7 @@ def deployv2( list(), "-r", "--region", - help="The regions to deploy to. For multiple envs, repeat this option, e.g. --region sjc --region iad", + help="The regions to deploy to. `reflex apps regions` For multiple envs, repeat this option, e.g. --region sjc --region iad", ), envs: List[str] = typer.Option( list(), @@ -647,13 +651,12 @@ def deployv2( vmtype: Optional[str] = typer.Option( None, "--vmtype", - help="Vm type id. Run reflex apps vmtypes list to get options.", + help="Vm type id. Run `reflex apps vmtypes` to get options.", ), hostname: Optional[str] = typer.Option( None, "--hostname", help="The hostname of the frontend.", - hidden=True, ), interactive: bool = typer.Option( True, @@ -663,7 +666,6 @@ def deployv2( None, "--envfile", help="The path to an env file to use. Will override any envs set manually.", - hidden=True, ), loglevel: constants.LogLevel = typer.Option( config.loglevel, help="The log level to use." @@ -678,7 +680,6 @@ def deployv2( None, "--token", help="token to use for auth", - hidden=True, ), ): """Deploy the app to the Reflex hosting service.""" @@ -688,6 +689,8 @@ def deployv2( from reflex.utils import export as export_utils from reflex.utils import prerequisites + check_version() + # Set the log level. console.set_log_level(loglevel) From 22329e592edb48aa514a1081c5c59a4827b3d69d Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Mon, 18 Nov 2024 18:21:45 -0800 Subject: [PATCH 07/71] add debug statement to evaluate page (#4396) --- reflex/app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/reflex/app.py b/reflex/app.py index a8a6e69c6..26b2cce20 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -854,6 +854,7 @@ class App(MiddlewareMixin, LifespanMixin): self.theme.appearance = None for route in self.unevaluated_pages: + console.debug(f"Evaluating page: {route}") self._compile_page(route) # Add the optional endpoints (_upload) From adaf49e4f9bd6c22b6816ca23938a2611b2c771a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Mon, 18 Nov 2024 18:22:01 -0800 Subject: [PATCH 08/71] make list suggestions work in rx.input (#4391) * make list suggestions work * fix pyi --- reflex/components/el/__init__.pyi | 2 ++ reflex/components/el/elements/__init__.py | 1 + reflex/components/el/elements/__init__.pyi | 3 +++ reflex/components/el/elements/forms.py | 1 + reflex/components/el/elements/forms.pyi | 1 + reflex/components/radix/themes/components/text_field.py | 3 +++ reflex/components/radix/themes/components/text_field.pyi | 4 ++++ 7 files changed, 15 insertions(+) diff --git a/reflex/components/el/__init__.pyi b/reflex/components/el/__init__.pyi index 4815bcd27..cbfb65f58 100644 --- a/reflex/components/el/__init__.pyi +++ b/reflex/components/el/__init__.pyi @@ -5,6 +5,7 @@ from . import elements as elements from .elements.forms import Button as Button +from .elements.forms import Datalist as Datalist from .elements.forms import Fieldset as Fieldset from .elements.forms import Form as Form from .elements.forms import Input as Input @@ -18,6 +19,7 @@ from .elements.forms import Progress as Progress from .elements.forms import Select as Select from .elements.forms import Textarea as Textarea from .elements.forms import button as button +from .elements.forms import datalist as datalist from .elements.forms import fieldset as fieldset from .elements.forms import form as form from .elements.forms import input as input diff --git a/reflex/components/el/elements/__init__.py b/reflex/components/el/elements/__init__.py index 17fdb77ca..45a7e04b8 100644 --- a/reflex/components/el/elements/__init__.py +++ b/reflex/components/el/elements/__init__.py @@ -7,6 +7,7 @@ from reflex.utils import lazy_loader _MAPPING = { "forms": [ "button", + "datalist", "fieldset", "form", "input", diff --git a/reflex/components/el/elements/__init__.pyi b/reflex/components/el/elements/__init__.pyi index b35e70dd2..c96a80987 100644 --- a/reflex/components/el/elements/__init__.pyi +++ b/reflex/components/el/elements/__init__.pyi @@ -4,6 +4,7 @@ # ------------------------------------------------------ from .forms import Button as Button +from .forms import Datalist as Datalist from .forms import Fieldset as Fieldset from .forms import Form as Form from .forms import Input as Input @@ -17,6 +18,7 @@ from .forms import Progress as Progress from .forms import Select as Select from .forms import Textarea as Textarea from .forms import button as button +from .forms import datalist as datalist from .forms import fieldset as fieldset from .forms import form as form from .forms import input as input @@ -226,6 +228,7 @@ from .typography import ul as ul _MAPPING = { "forms": [ "button", + "datalist", "fieldset", "form", "input", diff --git a/reflex/components/el/elements/forms.py b/reflex/components/el/elements/forms.py index a84718de1..7a94a9c2d 100644 --- a/reflex/components/el/elements/forms.py +++ b/reflex/components/el/elements/forms.py @@ -681,6 +681,7 @@ class Textarea(BaseHTML): button = Button.create +datalist = Datalist.create fieldset = Fieldset.create form = Form.create input = Input.create diff --git a/reflex/components/el/elements/forms.pyi b/reflex/components/el/elements/forms.pyi index f494d8076..a32eb8c5d 100644 --- a/reflex/components/el/elements/forms.pyi +++ b/reflex/components/el/elements/forms.pyi @@ -1490,6 +1490,7 @@ class Textarea(BaseHTML): ... button = Button.create +datalist = Datalist.create fieldset = Fieldset.create form = Form.create input = Input.create diff --git a/reflex/components/radix/themes/components/text_field.py b/reflex/components/radix/themes/components/text_field.py index d5d851839..3dabe0936 100644 --- a/reflex/components/radix/themes/components/text_field.py +++ b/reflex/components/radix/themes/components/text_field.py @@ -67,6 +67,9 @@ class TextFieldRoot(elements.Div, RadixThemesComponent): # Value of the input value: Var[Union[str, int, float]] + # References a datalist for suggested options + list: Var[Union[str, int, bool]] + # Fired when the value of the textarea changes. on_change: EventHandler[input_event] diff --git a/reflex/components/radix/themes/components/text_field.pyi b/reflex/components/radix/themes/components/text_field.pyi index 874ac07a0..edce803eb 100644 --- a/reflex/components/radix/themes/components/text_field.pyi +++ b/reflex/components/radix/themes/components/text_field.pyi @@ -119,6 +119,7 @@ class TextFieldRoot(elements.Div, RadixThemesComponent): required: Optional[Union[Var[bool], bool]] = None, type: Optional[Union[Var[str], str]] = None, value: Optional[Union[Var[Union[float, int, str]], float, int, str]] = None, + list: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, auto_capitalize: Optional[ Union[Var[Union[bool, int, str]], bool, int, str] @@ -206,6 +207,7 @@ class TextFieldRoot(elements.Div, RadixThemesComponent): required: Indicates that the input is required type: Specifies the type of input value: Value of the input + list: References a datalist for suggested options on_change: Fired when the value of the textarea changes. on_focus: Fired when the textarea is focused. on_blur: Fired when the textarea is blurred. @@ -454,6 +456,7 @@ class TextField(ComponentNamespace): required: Optional[Union[Var[bool], bool]] = None, type: Optional[Union[Var[str], str]] = None, value: Optional[Union[Var[Union[float, int, str]], float, int, str]] = None, + list: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, auto_capitalize: Optional[ Union[Var[Union[bool, int, str]], bool, int, str] @@ -541,6 +544,7 @@ class TextField(ComponentNamespace): required: Indicates that the input is required type: Specifies the type of input value: Value of the input + list: References a datalist for suggested options on_change: Fired when the value of the textarea changes. on_focus: Fired when the textarea is focused. on_blur: Fired when the textarea is blurred. From af4fe4842881e8e596d8a8aec4ca8410622e123a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Mon, 18 Nov 2024 18:56:28 -0800 Subject: [PATCH 09/71] [maintenance] bump some packages versions (#4385) * bump some versions * update ruff to 0.7.4 * bump tailwind version * relock deps --------- Co-authored-by: Masen Furer --- .pre-commit-config.yaml | 2 +- poetry.lock | 44 +++++++++++++++++------------------ pyproject.toml | 2 +- reflex/constants/installer.py | 6 ++--- reflex/constants/style.py | 2 +- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 41372d4e2..4046bad2d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ fail_fast: true repos: - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.7.2 + rev: v0.7.4 hooks: - id: ruff-format args: [reflex, tests] diff --git a/poetry.lock b/poetry.lock index c19780931..8f0b61666 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1350,8 +1350,8 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, {version = ">=1.23.2", markers = "python_version == \"3.11\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, {version = ">=1.22.4", markers = "python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" @@ -1669,8 +1669,8 @@ files = [ annotated-types = ">=0.6.0" pydantic-core = "2.23.4" typing-extensions = [ - {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, {version = ">=4.6.1", markers = "python_version < \"3.13\""}, + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, ] [package.extras] @@ -2289,29 +2289,29 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "ruff" -version = "0.7.2" +version = "0.7.4" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.7.2-py3-none-linux_armv6l.whl", hash = "sha256:b73f873b5f52092e63ed540adefc3c36f1f803790ecf2590e1df8bf0a9f72cb8"}, - {file = "ruff-0.7.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5b813ef26db1015953daf476202585512afd6a6862a02cde63f3bafb53d0b2d4"}, - {file = "ruff-0.7.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:853277dbd9675810c6826dad7a428d52a11760744508340e66bf46f8be9701d9"}, - {file = "ruff-0.7.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21aae53ab1490a52bf4e3bf520c10ce120987b047c494cacf4edad0ba0888da2"}, - {file = "ruff-0.7.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ccc7e0fc6e0cb3168443eeadb6445285abaae75142ee22b2b72c27d790ab60ba"}, - {file = "ruff-0.7.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd77877a4e43b3a98e5ef4715ba3862105e299af0c48942cc6d51ba3d97dc859"}, - {file = "ruff-0.7.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e00163fb897d35523c70d71a46fbaa43bf7bf9af0f4534c53ea5b96b2e03397b"}, - {file = "ruff-0.7.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3c54b538633482dc342e9b634d91168fe8cc56b30a4b4f99287f4e339103e88"}, - {file = "ruff-0.7.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b792468e9804a204be221b14257566669d1db5c00d6bb335996e5cd7004ba80"}, - {file = "ruff-0.7.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dba53ed84ac19ae4bfb4ea4bf0172550a2285fa27fbb13e3746f04c80f7fa088"}, - {file = "ruff-0.7.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b19fafe261bf741bca2764c14cbb4ee1819b67adb63ebc2db6401dcd652e3748"}, - {file = "ruff-0.7.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:28bd8220f4d8f79d590db9e2f6a0674f75ddbc3847277dd44ac1f8d30684b828"}, - {file = "ruff-0.7.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9fd67094e77efbea932e62b5d2483006154794040abb3a5072e659096415ae1e"}, - {file = "ruff-0.7.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:576305393998b7bd6c46018f8104ea3a9cb3fa7908c21d8580e3274a3b04b691"}, - {file = "ruff-0.7.2-py3-none-win32.whl", hash = "sha256:fa993cfc9f0ff11187e82de874dfc3611df80852540331bc85c75809c93253a8"}, - {file = "ruff-0.7.2-py3-none-win_amd64.whl", hash = "sha256:dd8800cbe0254e06b8fec585e97554047fb82c894973f7ff18558eee33d1cb88"}, - {file = "ruff-0.7.2-py3-none-win_arm64.whl", hash = "sha256:bb8368cd45bba3f57bb29cbb8d64b4a33f8415d0149d2655c5c8539452ce7760"}, - {file = "ruff-0.7.2.tar.gz", hash = "sha256:2b14e77293380e475b4e3a7a368e14549288ed2931fce259a6f99978669e844f"}, + {file = "ruff-0.7.4-py3-none-linux_armv6l.whl", hash = "sha256:a4919925e7684a3f18e18243cd6bea7cfb8e968a6eaa8437971f681b7ec51478"}, + {file = "ruff-0.7.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:cfb365c135b830778dda8c04fb7d4280ed0b984e1aec27f574445231e20d6c63"}, + {file = "ruff-0.7.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:63a569b36bc66fbadec5beaa539dd81e0527cb258b94e29e0531ce41bacc1f20"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d06218747d361d06fd2fdac734e7fa92df36df93035db3dc2ad7aa9852cb109"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0cea28d0944f74ebc33e9f934238f15c758841f9f5edd180b5315c203293452"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80094ecd4793c68b2571b128f91754d60f692d64bc0d7272ec9197fdd09bf9ea"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:997512325c6620d1c4c2b15db49ef59543ef9cd0f4aa8065ec2ae5103cedc7e7"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00b4cf3a6b5fad6d1a66e7574d78956bbd09abfd6c8a997798f01f5da3d46a05"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7dbdc7d8274e1422722933d1edddfdc65b4336abf0b16dfcb9dedd6e6a517d06"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e92dfb5f00eaedb1501b2f906ccabfd67b2355bdf117fea9719fc99ac2145bc"}, + {file = "ruff-0.7.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3bd726099f277d735dc38900b6a8d6cf070f80828877941983a57bca1cd92172"}, + {file = "ruff-0.7.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2e32829c429dd081ee5ba39aef436603e5b22335c3d3fff013cd585806a6486a"}, + {file = "ruff-0.7.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:662a63b4971807623f6f90c1fb664613f67cc182dc4d991471c23c541fee62dd"}, + {file = "ruff-0.7.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:876f5e09eaae3eb76814c1d3b68879891d6fde4824c015d48e7a7da4cf066a3a"}, + {file = "ruff-0.7.4-py3-none-win32.whl", hash = "sha256:75c53f54904be42dd52a548728a5b572344b50d9b2873d13a3f8c5e3b91f5cac"}, + {file = "ruff-0.7.4-py3-none-win_amd64.whl", hash = "sha256:745775c7b39f914238ed1f1b0bebed0b9155a17cd8bc0b08d3c87e4703b990d6"}, + {file = "ruff-0.7.4-py3-none-win_arm64.whl", hash = "sha256:11bff065102c3ae9d3ea4dc9ecdfe5a5171349cdd0787c1fc64761212fc9cf1f"}, + {file = "ruff-0.7.4.tar.gz", hash = "sha256:cd12e35031f5af6b9b93715d8c4f40360070b2041f81273d0527683d5708fce2"}, ] [[package]] @@ -3033,4 +3033,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "600773827321e7a0fdb2fe7d6af650a039dff759ce6df9c51ca22f0d7df4c290" +content-hash = "a610d4c4bfd852f30e69ad2fbb288c2d9cbdf49e05b9d4936fe5e9b2a7cdefdb" diff --git a/pyproject.toml b/pyproject.toml index b2b7b79d3..2e271d719 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,7 +70,7 @@ dill = ">=0.3.8" toml = ">=0.10.2,<1.0" pytest-asyncio = ">=0.24.0" pytest-cov = ">=4.0.0,<7.0" -ruff = "0.7.2" +ruff = "0.7.4" pandas = ">=2.1.1,<3.0" pillow = ">=10.0.0,<12.0" plotly = ">=5.13.0,<6.0" diff --git a/reflex/constants/installer.py b/reflex/constants/installer.py index 04c563f92..0b45586dd 100644 --- a/reflex/constants/installer.py +++ b/reflex/constants/installer.py @@ -184,15 +184,15 @@ class PackageJson(SimpleNamespace): "json5": "2.2.3", "next": "14.2.16", "next-sitemap": "4.2.3", - "next-themes": "0.3.0", + "next-themes": "0.4.3", "react": "18.3.1", "react-dom": "18.3.1", "react-focus-lock": "2.13.2", "socket.io-client": "4.8.1", - "universal-cookie": "7.2.1", + "universal-cookie": "7.2.2", } DEV_DEPENDENCIES = { "autoprefixer": "10.4.20", - "postcss": "8.4.47", + "postcss": "8.4.49", "postcss-import": "16.1.0", } diff --git a/reflex/constants/style.py b/reflex/constants/style.py index 403acd4ba..a1d30bcca 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.14" + VERSION = "tailwindcss@3.4.15" # The Tailwind config. CONFIG = "tailwind.config.js" # Default Tailwind content paths From 1f9a17539cc21e652cac783c9d9a34be320240b4 Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Tue, 19 Nov 2024 04:15:01 +0100 Subject: [PATCH 10/71] fix: do not allow instantiation of State mixins (#4347) * fix: do not allow instantiation of State mixins Closes #4343 * improve error message for ComponentState mixins * fix typo Co-authored-by: Masen Furer --------- Co-authored-by: Masen Furer --- reflex/state.py | 22 +++++++++++++++++++ .../units/components/test_component_state.py | 21 ++++++++++++++++++ tests/units/test_state.py | 18 ++++++++++++++- 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/reflex/state.py b/reflex/state.py index 719ff43b3..9ff6f0ea8 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -87,6 +87,7 @@ from reflex.utils.exceptions import ( ImmutableStateError, InvalidStateManagerMode, LockExpiredError, + ReflexRuntimeError, SetUndefinedStateVarError, StateSchemaMismatchError, ) @@ -387,6 +388,10 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): "State classes should not be instantiated directly in a Reflex app. " "See https://reflex.dev/docs/state/ for further information." ) + if type(self)._mixin: + raise ReflexRuntimeError( + f"{type(self).__name__} is a state mixin and cannot be instantiated directly." + ) kwargs["parent_state"] = parent_state super().__init__() for name, value in kwargs.items(): @@ -2367,6 +2372,23 @@ class ComponentState(State, mixin=True): # The number of components created from this class. _per_component_state_instance_count: ClassVar[int] = 0 + def __init__(self, *args, **kwargs): + """Do not allow direct initialization of the ComponentState. + + Args: + *args: The args to pass to the State init method. + **kwargs: The kwargs to pass to the State init method. + + Raises: + ReflexRuntimeError: If the ComponentState is initialized directly. + """ + if type(self)._mixin: + raise ReflexRuntimeError( + f"{ComponentState.__name__} {type(self).__name__} is not meant to be initialized directly. " + + "Use the `create` method to create a new instance and access the state via the `State` attribute." + ) + super().__init__(*args, **kwargs) + @classmethod def __init_subclass__(cls, mixin: bool = True, **kwargs): """Overwrite mixin default to True. diff --git a/tests/units/components/test_component_state.py b/tests/units/components/test_component_state.py index 574997ba5..1b62e35c8 100644 --- a/tests/units/components/test_component_state.py +++ b/tests/units/components/test_component_state.py @@ -1,7 +1,10 @@ """Ensure that Components returned by ComponentState.create have independent State classes.""" +import pytest + import reflex as rx from reflex.components.base.bare import Bare +from reflex.utils.exceptions import ReflexRuntimeError def test_component_state(): @@ -40,3 +43,21 @@ def test_component_state(): assert len(cs2.children) == 1 assert cs2.children[0].render() == Bare.create("b").render() assert cs2.id == "b" + + +def test_init_component_state() -> None: + """Ensure that ComponentState subclasses cannot be instantiated directly.""" + + class CS(rx.ComponentState): + @classmethod + def get_component(cls, *children, **props): + return rx.el.div() + + with pytest.raises(ReflexRuntimeError): + CS() + + class SubCS(CS): + pass + + with pytest.raises(ReflexRuntimeError): + SubCS() diff --git a/tests/units/test_state.py b/tests/units/test_state.py index a69b9916a..7cebaff8e 100644 --- a/tests/units/test_state.py +++ b/tests/units/test_state.py @@ -43,7 +43,7 @@ from reflex.state import ( ) from reflex.testing import chdir from reflex.utils import format, prerequisites, types -from reflex.utils.exceptions import SetUndefinedStateVarError +from reflex.utils.exceptions import ReflexRuntimeError, SetUndefinedStateVarError from reflex.utils.format import json_dumps from reflex.vars.base import Var, computed_var from tests.units.states.mutation import MutableSQLAModel, MutableTestState @@ -3441,3 +3441,19 @@ def test_get_value(): "bar": "foo", } } + + +def test_init_mixin() -> None: + """Ensure that State mixins can not be instantiated directly.""" + + class Mixin(BaseState, mixin=True): + pass + + with pytest.raises(ReflexRuntimeError): + Mixin() + + class SubMixin(Mixin, mixin=True): + pass + + with pytest.raises(ReflexRuntimeError): + SubMixin() From bcea79cd45646ed3a589c5d5532e28465953fc41 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Mon, 18 Nov 2024 19:28:38 -0800 Subject: [PATCH 11/71] add typed dict type checking (#4340) * add typed dict type checking * technically it has to be a mapping, not specifically a dict --- reflex/components/component.py | 20 ++++++++++++-- reflex/utils/types.py | 49 +++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/reflex/components/component.py b/reflex/components/component.py index 4b850ba7d..18dedbf0e 100644 --- a/reflex/components/component.py +++ b/reflex/components/component.py @@ -186,6 +186,23 @@ ComponentStyle = Dict[ ComponentChild = Union[types.PrimitiveType, Var, BaseComponent] +def satisfies_type_hint(obj: Any, type_hint: Any) -> bool: + """Check if an object satisfies a type hint. + + Args: + obj: The object to check. + type_hint: The type hint to check against. + + Returns: + Whether the object satisfies the type hint. + """ + if isinstance(obj, LiteralVar): + return types._isinstance(obj._var_value, type_hint) + if isinstance(obj, Var): + return types._issubclass(obj._var_type, type_hint) + return types._isinstance(obj, type_hint) + + class Component(BaseComponent, ABC): """A component with style, event trigger and other props.""" @@ -460,8 +477,7 @@ class Component(BaseComponent, ABC): ) ) or ( # Else just check if the passed var type is valid. - not passed_types - and not types._issubclass(passed_type, expected_type, value) + not passed_types and not satisfies_type_hint(value, expected_type) ): value_name = value._js_expr if isinstance(value, Var) else value diff --git a/reflex/utils/types.py b/reflex/utils/types.py index 27b6e7ce7..9361c1ce4 100644 --- a/reflex/utils/types.py +++ b/reflex/utils/types.py @@ -14,9 +14,11 @@ from typing import ( Callable, ClassVar, Dict, + FrozenSet, Iterable, List, Literal, + Mapping, Optional, Sequence, Tuple, @@ -29,6 +31,7 @@ from typing import ( from typing import get_origin as get_origin_og import sqlalchemy +from typing_extensions import is_typeddict import reflex from reflex.components.core.breakpoints import Breakpoints @@ -494,6 +497,14 @@ def _issubclass(cls: GenericType, cls_check: GenericType, instance: Any = None) if isinstance(instance, Breakpoints): return _breakpoints_satisfies_typing(cls_check, instance) + if isinstance(cls_check_base, tuple): + cls_check_base = tuple( + cls_check_one if not is_typeddict(cls_check_one) else dict + for cls_check_one in cls_check_base + ) + if is_typeddict(cls_check_base): + cls_check_base = dict + # Check if the types match. try: return cls_check_base == Any or issubclass(cls_base, cls_check_base) @@ -503,6 +514,36 @@ def _issubclass(cls: GenericType, cls_check: GenericType, instance: Any = None) raise TypeError(f"Invalid type for issubclass: {cls_base}") from te +def does_obj_satisfy_typed_dict(obj: Any, cls: GenericType) -> bool: + """Check if an object satisfies a typed dict. + + Args: + obj: The object to check. + cls: The typed dict to check against. + + Returns: + Whether the object satisfies the typed dict. + """ + if not isinstance(obj, Mapping): + return False + + key_names_to_values = get_type_hints(cls) + required_keys: FrozenSet[str] = getattr(cls, "__required_keys__", frozenset()) + + if not all( + isinstance(key, str) + and key in key_names_to_values + and _isinstance(value, key_names_to_values[key]) + for key, value in obj.items() + ): + return False + + # TODO in 3.14: Implement https://peps.python.org/pep-0728/ if it's approved + + # required keys are all present + return required_keys.issubset(required_keys) + + def _isinstance(obj: Any, cls: GenericType, nested: bool = False) -> bool: """Check if an object is an instance of a class. @@ -529,6 +570,12 @@ def _isinstance(obj: Any, cls: GenericType, nested: bool = False) -> bool: origin = get_origin(cls) if origin is None: + # cls is a typed dict + if is_typeddict(cls): + if nested: + return does_obj_satisfy_typed_dict(obj, cls) + return isinstance(obj, dict) + # cls is a simple class return isinstance(obj, cls) @@ -553,7 +600,7 @@ def _isinstance(obj: Any, cls: GenericType, nested: bool = False) -> bool: and len(obj) == len(args) and all(_isinstance(item, arg) for item, arg in zip(obj, args)) ) - if origin is dict: + if origin in (dict, Breakpoints): return isinstance(obj, dict) and all( _isinstance(key, args[0]) and _isinstance(value, args[1]) for key, value in obj.items() From bffff01acbc6e1c747cc561d4490846f6aaf1a79 Mon Sep 17 00:00:00 2001 From: Alek Petuskey Date: Tue, 19 Nov 2024 09:29:11 -0800 Subject: [PATCH 12/71] Add datetime to moment (#4381) * Add datetime to moment * Remove recharts update * Support other formats * simplify * Precommit * PYI * change imports for pyi compat --------- Co-authored-by: Alek Petuskey Co-authored-by: Masen Furer --- reflex/components/moment/moment.py | 7 ++++--- reflex/components/moment/moment.pyi | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/reflex/components/moment/moment.py b/reflex/components/moment/moment.py index d5d6d8f7c..80940d228 100644 --- a/reflex/components/moment/moment.py +++ b/reflex/components/moment/moment.py @@ -1,7 +1,8 @@ """Moment component for humanized date rendering.""" import dataclasses -from typing import List, Optional +from datetime import date, datetime, time, timedelta +from typing import List, Optional, Union from reflex.components.component import NoSSRComponent from reflex.event import EventHandler, passthrough_event_spec @@ -19,7 +20,7 @@ class MomentDelta: weeks: Optional[int] = dataclasses.field(default=None) days: Optional[int] = dataclasses.field(default=None) hours: Optional[int] = dataclasses.field(default=None) - minutess: Optional[int] = dataclasses.field(default=None) + minutes: Optional[int] = dataclasses.field(default=None) seconds: Optional[int] = dataclasses.field(default=None) milliseconds: Optional[int] = dataclasses.field(default=None) @@ -78,7 +79,7 @@ class Moment(NoSSRComponent): duration: Var[str] # The date to display (also work if passed as children). - date: Var[str] + date: Var[Union[str, datetime, date, time, timedelta]] # Shows the duration (elapsed time) between now and the provided datetime. duration_from_now: Var[bool] diff --git a/reflex/components/moment/moment.pyi b/reflex/components/moment/moment.pyi index 57fbb3d0a..83ab670b0 100644 --- a/reflex/components/moment/moment.pyi +++ b/reflex/components/moment/moment.pyi @@ -4,6 +4,7 @@ # This file was generated by `reflex/utils/pyi_generator.py`! # ------------------------------------------------------ import dataclasses +from datetime import date, datetime, time, timedelta from typing import Any, Dict, Optional, Union, overload from reflex.components.component import NoSSRComponent @@ -20,7 +21,7 @@ class MomentDelta: weeks: Optional[int] days: Optional[int] hours: Optional[int] - minutess: Optional[int] + minutes: Optional[int] seconds: Optional[int] milliseconds: Optional[int] @@ -46,7 +47,16 @@ class Moment(NoSSRComponent): decimal: Optional[Union[Var[bool], bool]] = None, unit: Optional[Union[Var[str], str]] = None, duration: Optional[Union[Var[str], str]] = None, - date: Optional[Union[Var[str], str]] = None, + date: Optional[ + Union[ + Var[Union[date, datetime, str, time, timedelta]], + date, + datetime, + str, + time, + timedelta, + ] + ] = None, duration_from_now: Optional[Union[Var[bool], bool]] = None, unix: Optional[Union[Var[bool], bool]] = None, local: Optional[Union[Var[bool], bool]] = None, From 67296d43c094a977ac03e6b6436188ac6cca0f7f Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Tue, 19 Nov 2024 16:33:27 -0800 Subject: [PATCH 13/71] Don't skip serialization when Var is callable (#4399) --- reflex/utils/serializers.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/reflex/utils/serializers.py b/reflex/utils/serializers.py index b87909aec..b0ad935c8 100644 --- a/reflex/utils/serializers.py +++ b/reflex/utils/serializers.py @@ -263,7 +263,11 @@ def serialize_base(value: Base) -> dict: Returns: The serialized Base. """ - return {k: v for k, v in value.dict().items() if not callable(v)} + from reflex.vars.base import Var + + return { + k: v for k, v in value.dict().items() if isinstance(v, Var) or not callable(v) + } @serializer From 229df1ce09e391ac5b0c8c98260e76be2eb3c9e9 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Tue, 19 Nov 2024 16:46:55 -0800 Subject: [PATCH 14/71] ignore rxconfig not in cwd (#4398) * ignore rxconfig not in cwd * no type ignore * resolve paths * Remove rxconfig module from sys.modules cache when reloading * modify sys path * add try except * refactor inner function --------- Co-authored-by: Masen Furer --- reflex/config.py | 48 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/reflex/config.py b/reflex/config.py index 049cc2e83..e86959e57 100644 --- a/reflex/config.py +++ b/reflex/config.py @@ -9,6 +9,7 @@ import inspect import os import sys import urllib.parse +from importlib.util import find_spec from pathlib import Path from typing import ( TYPE_CHECKING, @@ -798,6 +799,23 @@ class Config(Base): self._replace_defaults(**kwargs) +def _get_config() -> Config: + """Get the app config. + + Returns: + The app config. + """ + # only import the module if it exists. If a module spec exists then + # the module exists. + spec = find_spec(constants.Config.MODULE) + if not spec: + # we need this condition to ensure that a ModuleNotFound error is not thrown when + # running unit/integration tests or during `reflex init`. + return Config(app_name="") + rxconfig = importlib.import_module(constants.Config.MODULE) + return rxconfig.config + + def get_config(reload: bool = False) -> Config: """Get the app config. @@ -807,15 +825,21 @@ def get_config(reload: bool = False) -> Config: Returns: The app config. """ - sys.path.insert(0, os.getcwd()) - # only import the module if it exists. If a module spec exists then - # the module exists. - spec = importlib.util.find_spec(constants.Config.MODULE) # type: ignore - if not spec: - # we need this condition to ensure that a ModuleNotFound error is not thrown when - # running unit/integration tests. - return Config(app_name="") - rxconfig = importlib.import_module(constants.Config.MODULE) - if reload: - importlib.reload(rxconfig) - return rxconfig.config + # Remove any cached module when `reload` is requested. + if reload and constants.Config.MODULE in sys.modules: + del sys.modules[constants.Config.MODULE] + + sys_path = sys.path.copy() + sys.path.clear() + sys.path.append(os.getcwd()) + try: + # Try to import the module with only the current directory in the path. + return _get_config() + except Exception: + # If the module import fails, try to import with the original sys.path. + sys.path.extend(sys_path) + return _get_config() + finally: + # Restore the original sys.path. + sys.path.clear() + sys.path.extend(sys_path) From 681b61600025c67e1438c2252917ff078ff0db2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Wed, 20 Nov 2024 11:12:52 -0800 Subject: [PATCH 15/71] fix appearance broken by #3812 (#4403) * fix appearance broken by #3812 * fix again to pass tests --- reflex/app.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/reflex/app.py b/reflex/app.py index 26b2cce20..afc40e3b8 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -850,8 +850,6 @@ class App(MiddlewareMixin, LifespanMixin): if self.theme is not None: # If a theme component was provided, wrap the app with it app_wrappers[(20, "Theme")] = self.theme - # Fix #2992 by removing the top-level appearance prop - self.theme.appearance = None for route in self.unevaluated_pages: console.debug(f"Evaluating page: {route}") @@ -1007,6 +1005,9 @@ class App(MiddlewareMixin, LifespanMixin): compile_results.append( compiler.compile_contexts(self.state, self.theme), ) + if self.theme is not None: + # Fix #2992 by removing the top-level appearance prop + self.theme.appearance = None progress.advance(task) # Compile the app root. From 4571524e1c4556c8be8963ddeebae269f817a3d9 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Thu, 21 Nov 2024 04:11:34 -0800 Subject: [PATCH 16/71] [ENG-4130] Disable typer/rich integration appropriately (#4412) The `rich` module should be set to `None`, indicating that rich should not be used. Setting it to `False` worked before, but recently added code in typer fails when checking `if rich is not None`. ref: https://github.com/fastapi/typer/pull/847 --- reflex/reflex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reflex/reflex.py b/reflex/reflex.py index 3fedc2ef5..8c26e0470 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -20,7 +20,7 @@ from reflex.state import reset_disk_state_manager from reflex.utils import console, redir, telemetry # Disable typer+rich integration for help panels -typer.core.rich = False # type: ignore +typer.core.rich = None # type: ignore # Create the app. try: From 81583d45cafe80757bcd07be0d26ada6d928009a Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Thu, 21 Nov 2024 10:27:44 -0800 Subject: [PATCH 17/71] [HOS-313] state.js: when a routing error occurs, delete it (#4410) In some cases, a routing failure can cause the failure to be cached. When the router has a cached failure, pushing such a route will never call routeChangeComplete, and thus on_load event will never be fired for that route. Purposely clearing the error from the router allows the page to properly load on subsequent attempts without refreshing the app. --- reflex/.templates/web/utils/state.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/reflex/.templates/web/utils/state.js b/reflex/.templates/web/utils/state.js index 3899ddc89..72733777e 100644 --- a/reflex/.templates/web/utils/state.js +++ b/reflex/.templates/web/utils/state.js @@ -762,7 +762,7 @@ export const useEventLoop = ( window.onunhandledrejection = function (event) { addEvents([ Event(`${exception_state_name}.handle_frontend_exception`, { - stack: event.reason.stack, + stack: event.reason?.stack, component_stack: "", }), ]); @@ -837,11 +837,20 @@ export const useEventLoop = ( } }; const change_complete = () => addEvents(onLoadInternalEvent()); + const change_error = () => { + // Remove cached error state from router for this page, otherwise the + // page will never send on_load events again. + if (router.components[router.pathname].error) { + delete router.components[router.pathname].error; + } + } router.events.on("routeChangeStart", change_start); router.events.on("routeChangeComplete", change_complete); + router.events.on("routeChangeError", change_error); return () => { router.events.off("routeChangeStart", change_start); router.events.off("routeChangeComplete", change_complete); + router.events.off("routeChangeError", change_error); }; }, [router]); From 05956c84a7bea98d1d54e4584924cfaf432e9f55 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Thu, 21 Nov 2024 10:29:40 -0800 Subject: [PATCH 18/71] protect sys.path manipulation with a mutex (#4408) Compiling pages in separate threads can result in `sys.path` being cleared, which breaks subsequent imports. --- reflex/config.py | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/reflex/config.py b/reflex/config.py index e86959e57..962d6fec9 100644 --- a/reflex/config.py +++ b/reflex/config.py @@ -8,6 +8,7 @@ import importlib import inspect import os import sys +import threading import urllib.parse from importlib.util import find_spec from pathlib import Path @@ -816,6 +817,10 @@ def _get_config() -> Config: return rxconfig.config +# Protect sys.path from concurrent modification +_config_lock = threading.RLock() + + def get_config(reload: bool = False) -> Config: """Get the app config. @@ -825,21 +830,26 @@ def get_config(reload: bool = False) -> Config: Returns: The app config. """ - # Remove any cached module when `reload` is requested. - if reload and constants.Config.MODULE in sys.modules: - del sys.modules[constants.Config.MODULE] + cached_rxconfig = sys.modules.get(constants.Config.MODULE, None) + if cached_rxconfig is not None: + if reload: + # Remove any cached module when `reload` is requested. + del sys.modules[constants.Config.MODULE] + else: + return cached_rxconfig.config - sys_path = sys.path.copy() - sys.path.clear() - sys.path.append(os.getcwd()) - try: - # Try to import the module with only the current directory in the path. - return _get_config() - except Exception: - # If the module import fails, try to import with the original sys.path. - sys.path.extend(sys_path) - return _get_config() - finally: - # Restore the original sys.path. + with _config_lock: + sys_path = sys.path.copy() sys.path.clear() - sys.path.extend(sys_path) + sys.path.append(os.getcwd()) + try: + # Try to import the module with only the current directory in the path. + return _get_config() + except Exception: + # If the module import fails, try to import with the original sys.path. + sys.path.extend(sys_path) + return _get_config() + finally: + # Restore the original sys.path. + sys.path.clear() + sys.path.extend(sys_path) From 095c1e5b7f965e44425eccd7772102c0f17e50e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Thu, 21 Nov 2024 11:05:02 -0800 Subject: [PATCH 19/71] remove deprecation for these events (#4415) --- reflex/components/radix/primitives/drawer.py | 28 ++++---------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/reflex/components/radix/primitives/drawer.py b/reflex/components/radix/primitives/drawer.py index f99342a58..ed57dcbd8 100644 --- a/reflex/components/radix/primitives/drawer.py +++ b/reflex/components/radix/primitives/drawer.py @@ -11,7 +11,6 @@ from reflex.components.radix.primitives.base import RadixPrimitiveComponent from reflex.components.radix.themes.base import Theme from reflex.components.radix.themes.layout.flex import Flex from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec -from reflex.utils import console from reflex.vars.base import Var @@ -140,19 +139,19 @@ class DrawerContent(DrawerComponent): base_style.update(style) return {"css": base_style} - # Fired when the drawer content is opened. Deprecated. + # Fired when the drawer content is opened. on_open_auto_focus: EventHandler[no_args_event_spec] - # Fired when the drawer content is closed. Deprecated. + # Fired when the drawer content is closed. on_close_auto_focus: EventHandler[no_args_event_spec] - # Fired when the escape key is pressed. Deprecated. + # Fired when the escape key is pressed. on_escape_key_down: EventHandler[no_args_event_spec] - # Fired when the pointer is down outside the drawer content. Deprecated. + # Fired when the pointer is down outside the drawer content. on_pointer_down_outside: EventHandler[no_args_event_spec] - # Fired when interacting outside the drawer content. Deprecated. + # Fired when interacting outside the drawer content. on_interact_outside: EventHandler[no_args_event_spec] @classmethod @@ -170,23 +169,6 @@ class DrawerContent(DrawerComponent): Returns: The drawer content. """ - deprecated_properties = [ - "on_open_auto_focus", - "on_close_auto_focus", - "on_escape_key_down", - "on_pointer_down_outside", - "on_interact_outside", - ] - - for prop in deprecated_properties: - if prop in props: - console.deprecate( - feature_name="drawer content events", - reason=f"The `{prop}` event is deprecated and will be removed in 0.7.0.", - deprecation_version="0.6.3", - removal_version="0.7.0", - ) - comp = super().create(*children, **props) return Theme.create(comp) From ecb52651c3a134056bac5a59be1078685ec99d7d Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Thu, 21 Nov 2024 20:06:47 +0100 Subject: [PATCH 20/71] allow to disable checking for the latest package version via env (#4407) --- reflex/config.py | 3 +++ reflex/utils/prerequisites.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/reflex/config.py b/reflex/config.py index 962d6fec9..953a92b64 100644 --- a/reflex/config.py +++ b/reflex/config.py @@ -547,6 +547,9 @@ class EnvironmentVariables: # 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) + environment = EnvironmentVariables() diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index b2b3b7f3b..68d198711 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -93,6 +93,8 @@ def check_latest_package_version(package_name: str): Args: package_name: The name of the package. """ + if environment.REFLEX_CHECK_LATEST_VERSION.get() is False: + return try: # Get the latest version from PyPI current_version = importlib.metadata.version(package_name) From e0984aa83431bc70a31a99f48c98e87470e1be48 Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Thu, 21 Nov 2024 20:53:50 +0100 Subject: [PATCH 21/71] Allow bound method as event handler (#4348) * subtract 1 arg if the method is a bound method * fix it early in user_args * only bound methods pls * add test --- reflex/event.py | 4 ++++ tests/units/test_event.py | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/reflex/event.py b/reflex/event.py index 312c9887f..a9e92b635 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -1346,6 +1346,10 @@ def check_fn_match_arg_spec( EventFnArgMismatch: Raised if the number of mandatory arguments do not match """ user_args = inspect.getfullargspec(user_func).args + # Drop the first argument if it's a bound method + if inspect.ismethod(user_func) and user_func.__self__ is not None: + user_args = user_args[1:] + user_default_args = inspect.getfullargspec(user_func).defaults number_of_user_args = len(user_args) - number_of_bound_args number_of_user_default_args = len(user_default_args) if user_default_args else 0 diff --git a/tests/units/test_event.py b/tests/units/test_event.py index f17b3c4e4..4399ab2a0 100644 --- a/tests/units/test_event.py +++ b/tests/units/test_event.py @@ -2,6 +2,7 @@ from typing import Callable, List import pytest +import reflex as rx from reflex.event import ( Event, EventChain, @@ -439,3 +440,17 @@ def test_event_var_data(): # Ensure chain carries _var_data chain_var = Var.create(EventChain(events=[S.s(S.x)], args_spec=_args_spec)) assert chain_var._get_all_var_data() == S.x._get_all_var_data() + + +def test_event_bound_method() -> None: + class S(BaseState): + @event + def e(self, arg: str): + print(arg) + + class Wrapper: + def get_handler(self, arg: str): + return S.e(arg) + + w = Wrapper() + _ = rx.input(on_change=w.get_handler) From d4b197b517e91aa216a4b35669ee5b4369c27877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Thu, 21 Nov 2024 12:41:48 -0800 Subject: [PATCH 22/71] fix for event handlers in py3.9 (#4416) --- .../radix/themes/components/segmented_control.py | 4 +++- .../radix/themes/components/segmented_control.pyi | 9 +++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/reflex/components/radix/themes/components/segmented_control.py b/reflex/components/radix/themes/components/segmented_control.py index 22725eaa6..f2dd9dc7c 100644 --- a/reflex/components/radix/themes/components/segmented_control.py +++ b/reflex/components/radix/themes/components/segmented_control.py @@ -12,7 +12,9 @@ from reflex.vars.base import Var from ..base import LiteralAccentColor, RadixThemesComponent -def on_value_change(value: Var[str | List[str]]) -> Tuple[Var[str | List[str]]]: +def on_value_change( + value: Var[Union[str, List[str]]], +) -> Tuple[Var[Union[str, List[str]]]]: """Handle the on_value_change event. Args: diff --git a/reflex/components/radix/themes/components/segmented_control.pyi b/reflex/components/radix/themes/components/segmented_control.pyi index 7ad115800..c7e87ca34 100644 --- a/reflex/components/radix/themes/components/segmented_control.pyi +++ b/reflex/components/radix/themes/components/segmented_control.pyi @@ -13,7 +13,9 @@ from reflex.vars.base import Var from ..base import RadixThemesComponent -def on_value_change(value: Var[str | List[str]]) -> Tuple[Var[str | List[str]]]: ... +def on_value_change( + value: Var[Union[str, List[str]]], +) -> Tuple[Var[Union[str, List[str]]]]: ... class SegmentedControlRoot(RadixThemesComponent): @overload @@ -118,7 +120,10 @@ class SegmentedControlRoot(RadixThemesComponent): custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None, on_blur: Optional[EventType[[], BASE_STATE]] = None, on_change: Optional[ - Union[EventType[[], BASE_STATE], EventType[[str | List[str]], BASE_STATE]] + Union[ + EventType[[], BASE_STATE], + EventType[[Union[str, List[str]]], BASE_STATE], + ] ] = None, on_click: Optional[EventType[[], BASE_STATE]] = None, on_context_menu: Optional[EventType[[], BASE_STATE]] = None, From bbfbc82c9d70afcdb8b0e65398b5f7e75e3c8cac Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Thu, 21 Nov 2024 16:15:01 -0800 Subject: [PATCH 23/71] Handle Var passed to `rx.toast` (#4405) * Handle Var passed to `rx.toast` If the user provides a `Var` for `message` then apply it as `props["title"]` to avoid a var operations error. * remove unnecessary parentheses * remove weird hacks * get it right pyright --------- Co-authored-by: Khaleel Al-Adhami --- reflex/components/sonner/toast.py | 41 +++++++++++++++++++----------- reflex/components/sonner/toast.pyi | 12 ++++----- reflex/utils/types.py | 4 +++ 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/reflex/components/sonner/toast.py b/reflex/components/sonner/toast.py index c7db55a40..8f5362dba 100644 --- a/reflex/components/sonner/toast.py +++ b/reflex/components/sonner/toast.py @@ -15,6 +15,8 @@ from reflex.utils.imports import ImportVar from reflex.utils.serializers import serializer from reflex.vars import VarData from reflex.vars.base import LiteralVar, Var +from reflex.vars.function import FunctionVar +from reflex.vars.object import ObjectVar LiteralPosition = Literal[ "top-left", @@ -232,7 +234,9 @@ class Toaster(Component): return [hook] @staticmethod - def send_toast(message: str = "", level: str | None = None, **props) -> EventSpec: + def send_toast( + message: str | Var = "", level: str | None = None, **props + ) -> EventSpec: """Send a toast message. Args: @@ -250,20 +254,27 @@ class Toaster(Component): raise ValueError( "Toaster component must be created before sending a toast. (use `rx.toast.provider()`)" ) - toast_command = f"{toast_ref}.{level}" if level is not None else toast_ref - if message == "" and ("title" not in props or "description" not in props): - raise ValueError("Toast message or title or description must be provided.") - if props: - args = LiteralVar.create(ToastProps(component_name="rx.toast", **props)) # type: ignore - toast = f"{toast_command}(`{message}`, {str(args)})" - else: - toast = f"{toast_command}(`{message}`)" - toast_action = Var(_js_expr=toast) - return run_script(toast_action) + toast_command = ( + ObjectVar.__getattr__(toast_ref.to(dict), level) if level else toast_ref + ).to(FunctionVar) + + if isinstance(message, Var): + props.setdefault("title", message) + message = "" + elif message == "" and "title" not in props and "description" not in props: + raise ValueError("Toast message or title or description must be provided.") + + if props: + args = LiteralVar.create(ToastProps(component_name="rx.toast", **props)) # pyright: ignore [reportCallIssue, reportGeneralTypeIssues] + toast = toast_command.call(message, args) + else: + toast = toast_command.call(message) + + return run_script(toast) @staticmethod - def toast_info(message: str = "", **kwargs): + def toast_info(message: str | Var = "", **kwargs): """Display an info toast message. Args: @@ -276,7 +287,7 @@ class Toaster(Component): return Toaster.send_toast(message, level="info", **kwargs) @staticmethod - def toast_warning(message: str = "", **kwargs): + def toast_warning(message: str | Var = "", **kwargs): """Display a warning toast message. Args: @@ -289,7 +300,7 @@ class Toaster(Component): return Toaster.send_toast(message, level="warning", **kwargs) @staticmethod - def toast_error(message: str = "", **kwargs): + def toast_error(message: str | Var = "", **kwargs): """Display an error toast message. Args: @@ -302,7 +313,7 @@ class Toaster(Component): return Toaster.send_toast(message, level="error", **kwargs) @staticmethod - def toast_success(message: str = "", **kwargs): + def toast_success(message: str | Var = "", **kwargs): """Display a success toast message. Args: diff --git a/reflex/components/sonner/toast.pyi b/reflex/components/sonner/toast.pyi index f4f1028bd..7fd9fdf54 100644 --- a/reflex/components/sonner/toast.pyi +++ b/reflex/components/sonner/toast.pyi @@ -59,16 +59,16 @@ class Toaster(Component): def add_hooks(self) -> list[Var | str]: ... @staticmethod def send_toast( - message: str = "", level: str | None = None, **props + message: str | Var = "", level: str | None = None, **props ) -> EventSpec: ... @staticmethod - def toast_info(message: str = "", **kwargs): ... + def toast_info(message: str | Var = "", **kwargs): ... @staticmethod - def toast_warning(message: str = "", **kwargs): ... + def toast_warning(message: str | Var = "", **kwargs): ... @staticmethod - def toast_error(message: str = "", **kwargs): ... + def toast_error(message: str | Var = "", **kwargs): ... @staticmethod - def toast_success(message: str = "", **kwargs): ... + def toast_success(message: str | Var = "", **kwargs): ... @staticmethod def toast_dismiss(id: Var | str | None = None): ... @overload @@ -176,7 +176,7 @@ class ToastNamespace(ComponentNamespace): @staticmethod def __call__( - message: str = "", level: Optional[str] = None, **props + message: Union[str, Var] = "", level: Optional[str] = None, **props ) -> "Optional[EventSpec]": """Send a toast message. diff --git a/reflex/utils/types.py b/reflex/utils/types.py index 9361c1ce4..0c39eacc4 100644 --- a/reflex/utils/types.py +++ b/reflex/utils/types.py @@ -576,6 +576,10 @@ def _isinstance(obj: Any, cls: GenericType, nested: bool = False) -> bool: return does_obj_satisfy_typed_dict(obj, cls) return isinstance(obj, dict) + # cls is a float + if cls is float: + return isinstance(obj, (float, int)) + # cls is a simple class return isinstance(obj, cls) From b5e4b02d9c1be39ccc34fc218adcabfbfa040ab0 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Thu, 21 Nov 2024 16:32:38 -0800 Subject: [PATCH 24/71] New Event Action: temporal (#4404) When an event/event spec is marked as "temporal", it will not be queued unless the backend is up. This can be used to prevent periodic events (like from `rx.moment`) from queueing up while the backend is down, and then stampeding when the backend comes up and the queue is drained. It can be used to avoid processing many periodic events at once when the app is only expecting to process such an event every so often. --- reflex/.templates/web/utils/state.js | 5 +++++ reflex/event.py | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/reflex/.templates/web/utils/state.js b/reflex/.templates/web/utils/state.js index 72733777e..e14c669f5 100644 --- a/reflex/.templates/web/utils/state.js +++ b/reflex/.templates/web/utils/state.js @@ -705,6 +705,11 @@ export const useEventLoop = ( _e.stopPropagation(); } const combined_name = events.map((e) => e.name).join("+++"); + if (event_actions?.temporal) { + if (!socket.current || !socket.current.connected) { + return; // don't queue when the backend is not connected + } + } if (event_actions?.throttle) { // If throttle returns false, the events are not added to the queue. if (!throttle(combined_name, event_actions.throttle)) { diff --git a/reflex/event.py b/reflex/event.py index a9e92b635..624bc1728 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -181,6 +181,18 @@ class EventActionsMixin: event_actions={"debounce": delay_ms, **self.event_actions}, ) + @property + def temporal(self): + """Do not queue the event if the backend is down. + + Returns: + New EventHandler-like with temporal set to True. + """ + return dataclasses.replace( + self, + event_actions={"temporal": True, **self.event_actions}, + ) + @dataclasses.dataclass( init=True, From c13cec3d8a40bf900653096dd98398c5d53b36dc Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Fri, 22 Nov 2024 01:33:47 +0100 Subject: [PATCH 25/71] implement performance mode for existing state size check (#4392) --- reflex/config.py | 14 ++++++++++++++ reflex/state.py | 28 +++++++++++++++++++--------- reflex/utils/exceptions.py | 4 ++++ 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/reflex/config.py b/reflex/config.py index 953a92b64..88230cefe 100644 --- a/reflex/config.py +++ b/reflex/config.py @@ -454,6 +454,14 @@ class PathExistsFlag: ExistingPath = Annotated[Path, PathExistsFlag] +class PerformanceMode(enum.Enum): + """Performance mode for the app.""" + + WARN = "warn" + RAISE = "raise" + OFF = "off" + + class EnvironmentVariables: """Environment variables class to instantiate environment variables.""" @@ -550,6 +558,12 @@ class EnvironmentVariables: # Whether to check for outdated package versions. REFLEX_CHECK_LATEST_VERSION: EnvVar[bool] = env_var(True) + # In which performance mode to run the app. + REFLEX_PERF_MODE: EnvVar[Optional[PerformanceMode]] = env_var(PerformanceMode.WARN) + + # The maximum size of the reflex state in kilobytes. + REFLEX_STATE_SIZE_LIMIT: EnvVar[int] = env_var(1000) + environment = EnvironmentVariables() diff --git a/reflex/state.py b/reflex/state.py index 9ff6f0ea8..442fa57b2 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -43,7 +43,7 @@ from sqlalchemy.orm import DeclarativeBase from typing_extensions import Self from reflex import event -from reflex.config import get_config +from reflex.config import PerformanceMode, get_config from reflex.istate.data import RouterData from reflex.istate.storage import ClientStorageBase from reflex.model import Model @@ -90,6 +90,7 @@ from reflex.utils.exceptions import ( ReflexRuntimeError, SetUndefinedStateVarError, StateSchemaMismatchError, + StateTooLargeError, ) from reflex.utils.exec import is_testing_env from reflex.utils.serializers import serializer @@ -110,10 +111,11 @@ Delta = Dict[str, Any] var = computed_var -# If the state is this large, it's considered a performance issue. -TOO_LARGE_SERIALIZED_STATE = 100 * 1024 # 100kb -# Only warn about each state class size once. -_WARNED_ABOUT_STATE_SIZE: Set[str] = set() +if environment.REFLEX_PERF_MODE.get() != PerformanceMode.OFF: + # If the state is this large, it's considered a performance issue. + TOO_LARGE_SERIALIZED_STATE = environment.REFLEX_STATE_SIZE_LIMIT.get() * 1024 + # Only warn about each state class size once. + _WARNED_ABOUT_STATE_SIZE: Set[str] = set() # Errors caught during pickling of state HANDLED_PICKLE_ERRORS = ( @@ -2097,7 +2099,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): state["__dict__"].pop(inherited_var_name, None) return state - def _warn_if_too_large( + def _check_state_size( self, pickle_state_size: int, ): @@ -2105,6 +2107,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): Args: pickle_state_size: The size of the pickled state. + + Raises: + StateTooLargeError: If the state is too large. """ state_full_name = self.get_full_name() if ( @@ -2112,10 +2117,14 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): and pickle_state_size > TOO_LARGE_SERIALIZED_STATE and self.substates ): - console.warn( + msg = ( f"State {state_full_name} serializes to {pickle_state_size} bytes " - "which may present performance issues. Consider reducing the size of this state." + + "which may present performance issues. Consider reducing the size of this state." ) + if environment.REFLEX_PERF_MODE.get() == PerformanceMode.WARN: + console.warn(msg) + elif environment.REFLEX_PERF_MODE.get() == PerformanceMode.RAISE: + raise StateTooLargeError(msg) _WARNED_ABOUT_STATE_SIZE.add(state_full_name) @classmethod @@ -2157,7 +2166,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): """ try: pickle_state = pickle.dumps((self._to_schema(), self)) - self._warn_if_too_large(len(pickle_state)) + if environment.REFLEX_PERF_MODE.get() != PerformanceMode.OFF: + self._check_state_size(len(pickle_state)) return pickle_state except HANDLED_PICKLE_ERRORS as og_pickle_error: error = ( diff --git a/reflex/utils/exceptions.py b/reflex/utils/exceptions.py index 7611e5a4d..714dc912c 100644 --- a/reflex/utils/exceptions.py +++ b/reflex/utils/exceptions.py @@ -151,6 +151,10 @@ class InvalidPropValueError(ReflexError): """Raised when a prop value is invalid.""" +class StateTooLargeError(ReflexError): + """Raised when the state is too large to be serialized.""" + + class SystemPackageMissingError(ReflexError): """Raised when a system package is missing.""" From 9faa5d6fd926f3ec4572f2091d030cf84c7ceec0 Mon Sep 17 00:00:00 2001 From: Elijah Ahianyo Date: Fri, 22 Nov 2024 00:54:15 +0000 Subject: [PATCH 26/71] Downgrade syntax highlighter to fix `wrapLongLines` (#4368) --- reflex/components/datadisplay/code.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reflex/components/datadisplay/code.py b/reflex/components/datadisplay/code.py index 9d5052df1..b514bc888 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.1" + library = "react-syntax-highlighter@15.6.0" tag = "PrismAsyncLight" From 5702a18502ebcbbef1161ef3d999d1b49fc69099 Mon Sep 17 00:00:00 2001 From: Elijah Ahianyo Date: Fri, 22 Nov 2024 00:58:12 +0000 Subject: [PATCH 27/71] [GTM-836]Rework Init workflow (#4377) * Rework Init workflow * minor format * refactor * add comments * fix pyright alongside some improvements * add demolink for blank template * fix darglint * Add more templates and keep template name in kebab case * revert getting other templates since we'll use the submodules approach * remove debug statement * Improvements based on standup comments * Add redirect logic * changes based on new flow --------- Co-authored-by: Masen Furer --- reflex/constants/base.py | 12 ++ reflex/reflex.py | 28 +---- reflex/utils/prerequisites.py | 212 +++++++++++++++++++++++++++------- reflex/utils/redir.py | 17 ++- 4 files changed, 198 insertions(+), 71 deletions(-) diff --git a/reflex/constants/base.py b/reflex/constants/base.py index 798ac7dc6..3266043c5 100644 --- a/reflex/constants/base.py +++ b/reflex/constants/base.py @@ -97,6 +97,18 @@ class Templates(SimpleNamespace): # The default template DEFAULT = "blank" + # The AI template + AI = "ai" + + # The option for the user to choose a remote template. + CHOOSE_TEMPLATES = "choose-templates" + + # The URL to find reflex templates. + REFLEX_TEMPLATES_URL = "https://reflex.dev/templates" + + # Demo url for the default template. + DEFAULT_TEMPLATE_URL = "https://blank-template.reflex.run" + # The reflex.build frontend host REFLEX_BUILD_FRONTEND = "https://flexgen.reflex.run" diff --git a/reflex/reflex.py b/reflex/reflex.py index 8c26e0470..9d8199148 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -17,7 +17,7 @@ from reflex import constants from reflex.config import environment, get_config from reflex.custom_components.custom_components import custom_components_cli from reflex.state import reset_disk_state_manager -from reflex.utils import console, redir, telemetry +from reflex.utils import console, telemetry # Disable typer+rich integration for help panels typer.core.rich = None # type: ignore @@ -89,30 +89,8 @@ def _init( # Set up the web project. prerequisites.initialize_frontend_dependencies() - # Integrate with reflex.build. - generation_hash = None - if ai: - if template is None: - # If AI is requested and no template specified, redirect the user to reflex.build. - generation_hash = redir.reflex_build_redirect() - elif prerequisites.is_generation_hash(template): - # Otherwise treat the template as a generation hash. - generation_hash = template - else: - console.error( - "Cannot use `--template` option with `--ai` option. Please remove `--template` option." - ) - raise typer.Exit(2) - template = constants.Templates.DEFAULT - # Initialize the app. - template = prerequisites.initialize_app(app_name, template) - - # If a reflex.build generation hash is available, download the code and apply it to the main module. - if generation_hash: - prerequisites.initialize_main_module_index_from_generation( - app_name, generation_hash=generation_hash - ) + template = prerequisites.initialize_app(app_name, template, ai) # Initialize the .gitignore. prerequisites.initialize_gitignore() @@ -120,7 +98,7 @@ def _init( # Initialize the requirements.txt. prerequisites.initialize_requirements_txt() - template_msg = "" if not template else f" using the {template} template" + template_msg = f" using the {template} template" if template else "" # Finish initializing the app. console.success(f"Initialized {app_name}{template_msg}") diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index 68d198711..ec79b3297 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -34,7 +34,7 @@ from redis.asyncio import Redis from reflex import constants, model from reflex.compiler import templates from reflex.config import Config, environment, get_config -from reflex.utils import console, net, path_ops, processes +from reflex.utils import console, net, path_ops, processes, redir from reflex.utils.exceptions import ( GeneratedCodeHasNoFunctionDefs, raise_system_package_missing_error, @@ -1211,7 +1211,7 @@ def check_schema_up_to_date(): ) -def prompt_for_template(templates: list[Template]) -> str: +def prompt_for_template_options(templates: list[Template]) -> str: """Prompt the user to specify a template. Args: @@ -1223,9 +1223,14 @@ def prompt_for_template(templates: list[Template]) -> str: # Show the user the URLs of each template to preview. console.print("\nGet started with a template:") + def format_demo_url_str(url: str) -> str: + return f" ({url})" if url else "" + # Prompt the user to select a template. id_to_name = { - str(idx): f"{template.name} ({template.demo_url}) - {template.description}" + str( + idx + ): f"{template.name.replace('_', ' ').replace('-', ' ')}{format_demo_url_str(template.demo_url)} - {template.description}" for idx, template in enumerate(templates) } for id in range(len(id_to_name)): @@ -1380,15 +1385,119 @@ def create_config_init_app_from_remote_template(app_name: str, template_url: str shutil.rmtree(unzip_dir) -def initialize_app(app_name: str, template: str | None = None) -> str | None: +def initialize_default_app(app_name: str): + """Initialize the default app. + + Args: + app_name: The name of the app. + """ + create_config(app_name) + initialize_app_directory(app_name) + + +def validate_and_create_app_using_remote_template(app_name, template, templates): + """Validate and create an app using a remote template. + + Args: + app_name: The name of the app. + template: The name of the template. + templates: The available templates. + + Raises: + Exit: If the template is not found. + """ + # If user selects a template, it needs to exist. + if template in templates: + template_url = templates[template].code_url + else: + # Check if the template is a github repo. + if template.startswith("https://github.com"): + template_url = f"{template.strip('/').replace('.git', '')}/archive/main.zip" + else: + console.error(f"Template `{template}` not found.") + raise typer.Exit(1) + + if template_url is None: + return + + create_config_init_app_from_remote_template( + app_name=app_name, template_url=template_url + ) + + +def generate_template_using_ai(template: str | None = None) -> str: + """Generate a template using AI(Flexgen). + + Args: + template: The name of the template. + + Returns: + The generation hash. + + Raises: + Exit: If the template and ai flags are used. + """ + if template is None: + # If AI is requested and no template specified, redirect the user to reflex.build. + return redir.reflex_build_redirect() + elif is_generation_hash(template): + # Otherwise treat the template as a generation hash. + return template + else: + console.error( + "Cannot use `--template` option with `--ai` option. Please remove `--template` option." + ) + raise typer.Exit(2) + + +def fetch_remote_templates( + template: Optional[str] = None, +) -> tuple[str, dict[str, Template]]: + """Fetch the available remote templates. + + Args: + template: The name of the template. + + Returns: + The selected template and the available templates. + + Raises: + Exit: If the template is not valid or if the template is not specified. + """ + available_templates = {} + + try: + # Get the available templates + available_templates = fetch_app_templates(constants.Reflex.VERSION) + except Exception as e: + console.warn("Failed to fetch templates. Falling back to default template.") + console.debug(f"Error while fetching templates: {e}") + template = constants.Templates.DEFAULT + + if template == constants.Templates.DEFAULT: + return template, available_templates + + if template in available_templates: + return template, available_templates + + else: + if template is not None: + console.error(f"{template!r} is not a valid template name.") + console.print( + f"Go to the templates page ({constants.Templates.REFLEX_TEMPLATES_URL}) and copy the command to init with a template." + ) + raise typer.Exit(0) + + +def initialize_app( + app_name: str, template: str | None = None, ai: bool = False +) -> str | None: """Initialize the app either from a remote template or a blank app. If the config file exists, it is considered as reinit. Args: app_name: The name of the app. template: The name of the template to use. - - Raises: - Exit: If template is directly provided in the command flag and is invalid. + ai: Whether to use AI to generate the template. Returns: The name of the template. @@ -1401,54 +1510,73 @@ def initialize_app(app_name: str, template: str | None = None) -> str | None: telemetry.send("reinit") return + generation_hash = None + if ai: + generation_hash = generate_template_using_ai(template) + template = constants.Templates.DEFAULT + templates: dict[str, Template] = {} # Don't fetch app templates if the user directly asked for DEFAULT. - if template is None or (template != constants.Templates.DEFAULT): - try: - # Get the available templates - templates = fetch_app_templates(constants.Reflex.VERSION) - if template is None and len(templates) > 0: - template = prompt_for_template(list(templates.values())) - except Exception as e: - console.warn("Failed to fetch templates. Falling back to default template.") - console.debug(f"Error while fetching templates: {e}") - finally: - template = template or constants.Templates.DEFAULT + if template is not None and (template not in (constants.Templates.DEFAULT,)): + template, templates = fetch_remote_templates(template) + + if template is None: + template = prompt_for_template_options(get_init_cli_prompt_options()) + if template == constants.Templates.AI: + generation_hash = generate_template_using_ai() + # change to the default to allow creation of default app + template = constants.Templates.DEFAULT + elif template == constants.Templates.CHOOSE_TEMPLATES: + template, templates = fetch_remote_templates() # If the blank template is selected, create a blank app. - if template == constants.Templates.DEFAULT: + if template in (constants.Templates.DEFAULT,): # Default app creation behavior: a blank app. - create_config(app_name) - initialize_app_directory(app_name) + initialize_default_app(app_name) else: - # Fetch App templates from the backend server. - console.debug(f"Available templates: {templates}") - - # If user selects a template, it needs to exist. - if template in templates: - template_url = templates[template].code_url - else: - # Check if the template is a github repo. - if template.startswith("https://github.com"): - template_url = ( - f"{template.strip('/').replace('.git', '')}/archive/main.zip" - ) - else: - console.error(f"Template `{template}` not found.") - raise typer.Exit(1) - - if template_url is None: - return - - create_config_init_app_from_remote_template( - app_name=app_name, template_url=template_url + validate_and_create_app_using_remote_template( + app_name=app_name, template=template, templates=templates ) + # If a reflex.build generation hash is available, download the code and apply it to the main module. + if generation_hash: + initialize_main_module_index_from_generation( + app_name, generation_hash=generation_hash + ) telemetry.send("init", template=template) + return template +def get_init_cli_prompt_options() -> list[Template]: + """Get the CLI options for initializing a Reflex app. + + Returns: + The CLI options. + """ + return [ + Template( + name=constants.Templates.DEFAULT, + description="A blank Reflex app.", + demo_url=constants.Templates.DEFAULT_TEMPLATE_URL, + code_url="", + ), + Template( + name=constants.Templates.AI, + description="Generate a template using AI [Experimental]", + demo_url="", + code_url="", + ), + Template( + name=constants.Templates.CHOOSE_TEMPLATES, + description="Choose an existing template.", + demo_url="", + code_url="", + ), + ] + + def initialize_main_module_index_from_generation(app_name: str, generation_hash: str): """Overwrite the `index` function in the main module with reflex.build generated code. diff --git a/reflex/utils/redir.py b/reflex/utils/redir.py index 1dbd989e9..b35cbe26e 100644 --- a/reflex/utils/redir.py +++ b/reflex/utils/redir.py @@ -10,6 +10,18 @@ from .. import constants from . import console +def open_browser(target_url: str) -> None: + """Open a browser window to target_url. + + Args: + target_url: The URL to open in the browser. + """ + if not webbrowser.open(target_url): + console.warn( + f"Unable to automatically open the browser. Please navigate to {target_url} in your browser." + ) + + def open_browser_and_wait( target_url: str, poll_url: str, interval: int = 2 ) -> httpx.Response: @@ -23,10 +35,7 @@ def open_browser_and_wait( Returns: The response from the poll_url. """ - if not webbrowser.open(target_url): - console.warn( - f"Unable to automatically open the browser. Please navigate to {target_url} in your browser." - ) + open_browser(target_url) console.info("[b]Complete the workflow in the browser to continue.[/b]") while True: try: From a6b324bd3ec99af827ed15818bd520d4dbcae0a9 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Thu, 21 Nov 2024 17:01:14 -0800 Subject: [PATCH 28/71] [ENG-3953] Support pydantic BaseModel (v1 and v2) as state var (#4338) * [ENG-3953] Support pydantic BaseModel (v1 and v2) as state var Provide serializers and mutable proxy tracking for pydantic models directly. * conditionally define v2 serializer Co-authored-by: Khaleel Al-Adhami * Add `MutableProxy._is_mutable_value` to avoid duplicate logic * Conditionally import BaseModel to handle older pydantic v1 versions * pre-commit fu --------- Co-authored-by: Khaleel Al-Adhami --- reflex/state.py | 38 +++++++++++++++++++++++----- reflex/utils/serializers.py | 47 +++++++++++++++++++++++++++++++++++ tests/units/test_state.py | 49 +++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 6 deletions(-) diff --git a/reflex/state.py b/reflex/state.py index 442fa57b2..349dc59e9 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -62,6 +62,13 @@ try: except ModuleNotFoundError: import pydantic +from pydantic import BaseModel as BaseModelV2 + +try: + from pydantic.v1 import BaseModel as BaseModelV1 +except ModuleNotFoundError: + BaseModelV1 = BaseModelV2 + import wrapt from redis.asyncio import Redis from redis.exceptions import ResponseError @@ -1250,7 +1257,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): if parent_state is not None: return getattr(parent_state, name) - if isinstance(value, MutableProxy.__mutable_types__) and ( + if MutableProxy._is_mutable_type(value) and ( name in super().__getattribute__("base_vars") or name in backend_vars ): # track changes in mutable containers (list, dict, set, etc) @@ -3558,7 +3565,16 @@ class MutableProxy(wrapt.ObjectProxy): pydantic.BaseModel.__dict__ ) - __mutable_types__ = (list, dict, set, Base, DeclarativeBase) + # These types will be wrapped in MutableProxy + __mutable_types__ = ( + list, + dict, + set, + Base, + DeclarativeBase, + BaseModelV2, + BaseModelV1, + ) def __init__(self, wrapped: Any, state: BaseState, field_name: str): """Create a proxy for a mutable object that tracks changes. @@ -3598,6 +3614,18 @@ class MutableProxy(wrapt.ObjectProxy): if wrapped is not None: return wrapped(*args, **(kwargs or {})) + @classmethod + def _is_mutable_type(cls, value: Any) -> bool: + """Check if a value is of a mutable type and should be wrapped. + + Args: + value: The value to check. + + Returns: + Whether the value is of a mutable type. + """ + return isinstance(value, cls.__mutable_types__) + def _wrap_recursive(self, value: Any) -> Any: """Wrap a value recursively if it is mutable. @@ -3608,9 +3636,7 @@ class MutableProxy(wrapt.ObjectProxy): The wrapped value. """ # Recursively wrap mutable types, but do not re-wrap MutableProxy instances. - if isinstance(value, self.__mutable_types__) and not isinstance( - value, MutableProxy - ): + if self._is_mutable_type(value) and not isinstance(value, MutableProxy): return type(self)( wrapped=value, state=self._self_state, @@ -3668,7 +3694,7 @@ class MutableProxy(wrapt.ObjectProxy): self._wrap_recursive_decorator, ) - if isinstance(value, self.__mutable_types__) and __name not in ( + if self._is_mutable_type(value) and __name not in ( "__wrapped__", "_self_state", ): diff --git a/reflex/utils/serializers.py b/reflex/utils/serializers.py index b0ad935c8..4bb8dea92 100644 --- a/reflex/utils/serializers.py +++ b/reflex/utils/serializers.py @@ -270,6 +270,53 @@ def serialize_base(value: Base) -> dict: } +try: + from pydantic.v1 import BaseModel as BaseModelV1 + + @serializer(to=dict) + def serialize_base_model_v1(model: BaseModelV1) -> dict: + """Serialize a pydantic v1 BaseModel instance. + + Args: + model: The BaseModel to serialize. + + Returns: + The serialized BaseModel. + """ + return model.dict() + + from pydantic import BaseModel as BaseModelV2 + + if BaseModelV1 is not BaseModelV2: + + @serializer(to=dict) + def serialize_base_model_v2(model: BaseModelV2) -> dict: + """Serialize a pydantic v2 BaseModel instance. + + Args: + model: The BaseModel to serialize. + + Returns: + The serialized BaseModel. + """ + return model.model_dump() +except ImportError: + # Older pydantic v1 import + from pydantic import BaseModel as BaseModelV1 + + @serializer(to=dict) + def serialize_base_model_v1(model: BaseModelV1) -> dict: + """Serialize a pydantic v1 BaseModel instance. + + Args: + model: The BaseModel to serialize. + + Returns: + The serialized BaseModel. + """ + return model.dict() + + @serializer def serialize_set(value: Set) -> list: """Serialize a set to a JSON serializable list. diff --git a/tests/units/test_state.py b/tests/units/test_state.py index 7cebaff8e..c8a52e6c0 100644 --- a/tests/units/test_state.py +++ b/tests/units/test_state.py @@ -16,6 +16,8 @@ from unittest.mock import AsyncMock, Mock import pytest import pytest_asyncio from plotly.graph_objects import Figure +from pydantic import BaseModel as BaseModelV2 +from pydantic.v1 import BaseModel as BaseModelV1 import reflex as rx import reflex.config @@ -3413,6 +3415,53 @@ def test_typed_state() -> None: _ = TypedState(field="str") +class ModelV1(BaseModelV1): + """A pydantic BaseModel v1.""" + + foo: str = "bar" + + +class ModelV2(BaseModelV2): + """A pydantic BaseModel v2.""" + + foo: str = "bar" + + +@dataclasses.dataclass +class ModelDC: + """A dataclass.""" + + foo: str = "bar" + + +class PydanticState(rx.State): + """A state with pydantic BaseModel vars.""" + + v1: ModelV1 = ModelV1() + v2: ModelV2 = ModelV2() + dc: ModelDC = ModelDC() + + +def test_mutable_models(): + """Test that dataclass and pydantic BaseModel v1 and v2 use dep tracking.""" + state = PydanticState() + assert isinstance(state.v1, MutableProxy) + state.v1.foo = "baz" + assert state.dirty_vars == {"v1"} + state.dirty_vars.clear() + + assert isinstance(state.v2, MutableProxy) + state.v2.foo = "baz" + assert state.dirty_vars == {"v2"} + state.dirty_vars.clear() + + # Not yet supported ENG-4083 + # assert isinstance(state.dc, MutableProxy) + # state.dc.foo = "baz" + # assert state.dirty_vars == {"dc"} + # state.dirty_vars.clear() + + def test_get_value(): class GetValueState(rx.State): foo: str = "FOO" From a5486335a35c70d5656e24c500d9cd1e04eac37e Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Fri, 22 Nov 2024 02:16:43 +0100 Subject: [PATCH 29/71] rx._x.asset improvements (#3624) * wip rx._x.asset improvements * only add symlink if it doesn't already exist * minor improvements, add more tests * use deprecated Generator for python3.8 support * improve docstring * only allow explicit shared, only validate local assets if not backend_only * fix darglint * allow setting backend only env to false. * use new is_backend_only in assets * ruffing * Move to `rx.asset`, retain old API in `rx._x.asset` --------- Co-authored-by: Masen Furer --- reflex/__init__.py | 1 + reflex/__init__.pyi | 1 + reflex/assets.py | 95 +++++++++++++++++++ reflex/experimental/assets.py | 50 +++------- .../{experimental => assets}/custom_script.js | 0 tests/units/assets/test_assets.py | 94 ++++++++++++++++++ tests/units/experimental/test_assets.py | 36 ------- 7 files changed, 205 insertions(+), 72 deletions(-) create mode 100644 reflex/assets.py rename tests/units/{experimental => assets}/custom_script.js (100%) create mode 100644 tests/units/assets/test_assets.py delete mode 100644 tests/units/experimental/test_assets.py diff --git a/reflex/__init__.py b/reflex/__init__.py index 3941542f2..562524416 100644 --- a/reflex/__init__.py +++ b/reflex/__init__.py @@ -264,6 +264,7 @@ _MAPPING: dict = { "experimental": ["_x"], "admin": ["AdminDash"], "app": ["App", "UploadFile"], + "assets": ["asset"], "base": ["Base"], "components.component": [ "Component", diff --git a/reflex/__init__.pyi b/reflex/__init__.pyi index 30a498db4..6f61435e6 100644 --- a/reflex/__init__.pyi +++ b/reflex/__init__.pyi @@ -19,6 +19,7 @@ from . import vars as vars from .admin import AdminDash as AdminDash from .app import App as App from .app import UploadFile as UploadFile +from .assets import asset as asset from .base import Base as Base from .components import el as el from .components import lucide as lucide diff --git a/reflex/assets.py b/reflex/assets.py new file mode 100644 index 000000000..8a50664b6 --- /dev/null +++ b/reflex/assets.py @@ -0,0 +1,95 @@ +"""Helper functions for adding assets to the app.""" + +import inspect +from pathlib import Path +from typing import Optional + +from reflex import constants +from reflex.utils.exec import is_backend_only + + +def asset( + path: str, + shared: bool = False, + subfolder: Optional[str] = None, + _stack_level: int = 1, +) -> str: + """Add an asset to the app, either shared as a symlink or local. + + Shared/External/Library assets: + Place the file next to your including python file. + Links the file to the app's external assets directory. + + Example: + ```python + # my_custom_javascript.js is a shared asset located next to the including python file. + rx.script(src=rx.asset(path="my_custom_javascript.js", shared=True)) + rx.image(src=rx.asset(path="test_image.png", shared=True, subfolder="subfolder")) + ``` + + Local/Internal assets: + Place the file in the app's assets/ directory. + + Example: + ```python + # local_image.png is an asset located in the app's assets/ directory. It cannot be shared when developing a library. + rx.image(src=rx.asset(path="local_image.png")) + ``` + + Args: + path: The relative path of the asset. + subfolder: The directory to place the shared asset in. + shared: Whether to expose the asset to other apps. + _stack_level: The stack level to determine the calling file, defaults to + the immediate caller 1. When using rx.asset via a helper function, + increase this number for each helper function in the stack. + + Raises: + FileNotFoundError: If the file does not exist. + ValueError: If subfolder is provided for local assets. + + Returns: + The relative URL to the asset. + """ + assets = constants.Dirs.APP_ASSETS + backend_only = is_backend_only() + + # Local asset handling + if not shared: + cwd = Path.cwd() + src_file_local = cwd / assets / path + if subfolder is not None: + raise ValueError("Subfolder is not supported for local assets.") + if not backend_only and not src_file_local.exists(): + raise FileNotFoundError(f"File not found: {src_file_local}") + return f"/{path}" + + # Shared asset handling + # Determine the file by which the asset is exposed. + frame = inspect.stack()[_stack_level] + calling_file = frame.filename + module = inspect.getmodule(frame[0]) + assert module is not None + + external = constants.Dirs.EXTERNAL_APP_ASSETS + src_file_shared = Path(calling_file).parent / path + if not src_file_shared.exists(): + raise FileNotFoundError(f"File not found: {src_file_shared}") + + caller_module_path = module.__name__.replace(".", "/") + subfolder = f"{caller_module_path}/{subfolder}" if subfolder else caller_module_path + + # Symlink the asset to the app's external assets directory if running frontend. + if not backend_only: + # Create the asset folder in the currently compiling app. + asset_folder = Path.cwd() / assets / external / subfolder + asset_folder.mkdir(parents=True, exist_ok=True) + + dst_file = asset_folder / path + + if not dst_file.exists() and ( + not dst_file.is_symlink() or dst_file.resolve() != src_file_shared.resolve() + ): + dst_file.symlink_to(src_file_shared) + + return f"/{external}/{subfolder}/{path}" diff --git a/reflex/experimental/assets.py b/reflex/experimental/assets.py index dcf386d8d..e9be19aaf 100644 --- a/reflex/experimental/assets.py +++ b/reflex/experimental/assets.py @@ -1,14 +1,15 @@ """Helper functions for adding assets to the app.""" -import inspect -from pathlib import Path from typing import Optional -from reflex import constants +from reflex import assets +from reflex.utils import console def asset(relative_filename: str, subfolder: Optional[str] = None) -> str: - """Add an asset to the app. + """DEPRECATED: use `rx.asset` with `shared=True` instead. + + Add an asset to the app. Place the file next to your including python file. Copies the file to the app's external assets directory. @@ -22,38 +23,15 @@ def asset(relative_filename: str, subfolder: Optional[str] = None) -> str: relative_filename: The relative filename of the asset. subfolder: The directory to place the asset in. - Raises: - FileNotFoundError: If the file does not exist. - ValueError: If the module is None. - Returns: The relative URL to the copied asset. """ - # Determine the file by which the asset is exposed. - calling_file = inspect.stack()[1].filename - module = inspect.getmodule(inspect.stack()[1][0]) - if module is None: - raise ValueError("Module is None") - caller_module_path = module.__name__.replace(".", "/") - - subfolder = f"{caller_module_path}/{subfolder}" if subfolder else caller_module_path - - src_file = Path(calling_file).parent / relative_filename - - assets = constants.Dirs.APP_ASSETS - external = constants.Dirs.EXTERNAL_APP_ASSETS - - if not src_file.exists(): - raise FileNotFoundError(f"File not found: {src_file}") - - # Create the asset folder in the currently compiling app. - asset_folder = Path.cwd() / assets / external / subfolder - asset_folder.mkdir(parents=True, exist_ok=True) - - dst_file = asset_folder / relative_filename - - if not dst_file.exists(): - dst_file.symlink_to(src_file) - - asset_url = f"/{external}/{subfolder}/{relative_filename}" - return asset_url + console.deprecate( + feature_name="rx._x.asset", + reason="Use `rx.asset` with `shared=True` instead of `rx._x.asset`.", + deprecation_version="0.6.6", + removal_version="0.7.0", + ) + return assets.asset( + relative_filename, shared=True, subfolder=subfolder, _stack_level=2 + ) diff --git a/tests/units/experimental/custom_script.js b/tests/units/assets/custom_script.js similarity index 100% rename from tests/units/experimental/custom_script.js rename to tests/units/assets/custom_script.js diff --git a/tests/units/assets/test_assets.py b/tests/units/assets/test_assets.py new file mode 100644 index 000000000..b957f1902 --- /dev/null +++ b/tests/units/assets/test_assets.py @@ -0,0 +1,94 @@ +import shutil +from pathlib import Path +from typing import Generator + +import pytest + +import reflex as rx +import reflex.constants as constants + + +def test_shared_asset() -> None: + """Test shared assets.""" + # The asset function copies a file to the app's external assets directory. + asset = rx.asset(path="custom_script.js", shared=True, subfolder="subfolder") + assert asset == "/external/test_assets/subfolder/custom_script.js" + result_file = Path( + Path.cwd(), "assets/external/test_assets/subfolder/custom_script.js" + ) + assert result_file.exists() + + # Running a second time should not raise an error. + asset = rx.asset(path="custom_script.js", shared=True, subfolder="subfolder") + + # Test the asset function without a subfolder. + asset = rx.asset(path="custom_script.js", shared=True) + assert asset == "/external/test_assets/custom_script.js" + result_file = Path(Path.cwd(), "assets/external/test_assets/custom_script.js") + assert result_file.exists() + + # clean up + shutil.rmtree(Path.cwd() / "assets/external") + + with pytest.raises(FileNotFoundError): + asset = rx.asset("non_existent_file.js") + + # Nothing is done to assets when file does not exist. + assert not Path(Path.cwd() / "assets/external").exists() + + +def test_deprecated_x_asset(capsys) -> None: + """Test that the deprecated asset function raises a warning. + + Args: + capsys: Pytest fixture that captures stdout and stderr. + """ + assert rx.asset("custom_script.js", shared=True) == rx._x.asset("custom_script.js") + assert ( + "DeprecationWarning: rx._x.asset has been deprecated in version 0.6.6" + in capsys.readouterr().out + ) + + +@pytest.mark.parametrize( + "path,shared", + [ + pytest.param("non_existing_file", True), + pytest.param("non_existing_file", False), + ], +) +def test_invalid_assets(path: str, shared: bool) -> None: + """Test that asset raises an error when the file does not exist. + + Args: + path: The path to the asset. + shared: Whether the asset should be shared. + """ + with pytest.raises(FileNotFoundError): + _ = rx.asset(path, shared=shared) + + +@pytest.fixture +def custom_script_in_asset_dir() -> Generator[Path, None, None]: + """Create a custom_script.js file in the app's assets directory. + + Yields: + The path to the custom_script.js file. + """ + asset_dir = Path.cwd() / constants.Dirs.APP_ASSETS + asset_dir.mkdir(exist_ok=True) + path = asset_dir / "custom_script.js" + path.touch() + yield path + path.unlink() + + +def test_local_asset(custom_script_in_asset_dir: Path) -> None: + """Test that no error is raised if shared is set and both files exist. + + Args: + custom_script_in_asset_dir: Fixture that creates a custom_script.js file in the app's assets directory. + + """ + asset = rx.asset("custom_script.js", shared=False) + assert asset == "/custom_script.js" diff --git a/tests/units/experimental/test_assets.py b/tests/units/experimental/test_assets.py deleted file mode 100644 index 8037bcc75..000000000 --- a/tests/units/experimental/test_assets.py +++ /dev/null @@ -1,36 +0,0 @@ -import shutil -from pathlib import Path - -import pytest - -import reflex as rx - - -def test_asset(): - # Test the asset function. - - # The asset function copies a file to the app's external assets directory. - asset = rx._x.asset("custom_script.js", "subfolder") - assert asset == "/external/test_assets/subfolder/custom_script.js" - result_file = Path( - Path.cwd(), "assets/external/test_assets/subfolder/custom_script.js" - ) - assert result_file.exists() - - # Running a second time should not raise an error. - asset = rx._x.asset("custom_script.js", "subfolder") - - # Test the asset function without a subfolder. - asset = rx._x.asset("custom_script.js") - assert asset == "/external/test_assets/custom_script.js" - result_file = Path(Path.cwd(), "assets/external/test_assets/custom_script.js") - assert result_file.exists() - - # clean up - shutil.rmtree(Path.cwd() / "assets/external") - - with pytest.raises(FileNotFoundError): - asset = rx._x.asset("non_existent_file.js") - - # Nothing is done to assets when file does not exist. - assert not Path(Path.cwd() / "assets/external").exists() From c29c6b657ab05fc54e37081319af9ba57e8fcc04 Mon Sep 17 00:00:00 2001 From: Simon Young <40179067+Kastier1@users.noreply.github.com> Date: Thu, 21 Nov 2024 17:50:35 -0800 Subject: [PATCH 30/71] Simon/hosting cli upgrades (#4417) * update cli version * little change man * thats ruff * v bump --------- Co-authored-by: simon --- poetry.lock | 230 ++++++++++++++++++++++++----------------------- pyproject.toml | 2 +- reflex/reflex.py | 3 +- 3 files changed, 121 insertions(+), 114 deletions(-) diff --git a/poetry.lock b/poetry.lock index 8f0b61666..3310f106a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1656,22 +1656,19 @@ files = [ [[package]] name = "pydantic" -version = "2.9.2" +version = "2.10.1" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"}, - {file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"}, + {file = "pydantic-2.10.1-py3-none-any.whl", hash = "sha256:a8d20db84de64cf4a7d59e899c2caf0fe9d660c7cfc482528e7020d7dd189a7e"}, + {file = "pydantic-2.10.1.tar.gz", hash = "sha256:a4daca2dc0aa429555e0656d6bf94873a7dc5f54ee42b1f5873d666fb3f35560"}, ] [package.dependencies] annotated-types = ">=0.6.0" -pydantic-core = "2.23.4" -typing-extensions = [ - {version = ">=4.6.1", markers = "python_version < \"3.13\""}, - {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, -] +pydantic-core = "2.27.1" +typing-extensions = ">=4.12.2" [package.extras] email = ["email-validator (>=2.0.0)"] @@ -1679,100 +1676,111 @@ timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.23.4" +version = "2.27.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"}, - {file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2"}, - {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f"}, - {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3"}, - {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071"}, - {file = "pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119"}, - {file = "pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f"}, - {file = "pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8"}, - {file = "pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e"}, - {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b"}, - {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0"}, - {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64"}, - {file = "pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f"}, - {file = "pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3"}, - {file = "pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231"}, - {file = "pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36"}, - {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126"}, - {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e"}, - {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24"}, - {file = "pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84"}, - {file = "pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9"}, - {file = "pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc"}, - {file = "pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b"}, - {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327"}, - {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6"}, - {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f"}, - {file = "pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769"}, - {file = "pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5"}, - {file = "pydantic_core-2.23.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555"}, - {file = "pydantic_core-2.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad"}, - {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12"}, - {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2"}, - {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb"}, - {file = "pydantic_core-2.23.4-cp38-none-win32.whl", hash = "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6"}, - {file = "pydantic_core-2.23.4-cp38-none-win_amd64.whl", hash = "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556"}, - {file = "pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a"}, - {file = "pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c"}, - {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55"}, - {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040"}, - {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605"}, - {file = "pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6"}, - {file = "pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433"}, - {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8"}, - {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e"}, - {file = "pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863"}, + {file = "pydantic_core-2.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a"}, + {file = "pydantic_core-2.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206"}, + {file = "pydantic_core-2.27.1-cp310-none-win32.whl", hash = "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c"}, + {file = "pydantic_core-2.27.1-cp310-none-win_amd64.whl", hash = "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17"}, + {file = "pydantic_core-2.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8"}, + {file = "pydantic_core-2.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc"}, + {file = "pydantic_core-2.27.1-cp311-none-win32.whl", hash = "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9"}, + {file = "pydantic_core-2.27.1-cp311-none-win_amd64.whl", hash = "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5"}, + {file = "pydantic_core-2.27.1-cp311-none-win_arm64.whl", hash = "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89"}, + {file = "pydantic_core-2.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f"}, + {file = "pydantic_core-2.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae"}, + {file = "pydantic_core-2.27.1-cp312-none-win32.whl", hash = "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c"}, + {file = "pydantic_core-2.27.1-cp312-none-win_amd64.whl", hash = "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16"}, + {file = "pydantic_core-2.27.1-cp312-none-win_arm64.whl", hash = "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e"}, + {file = "pydantic_core-2.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073"}, + {file = "pydantic_core-2.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23"}, + {file = "pydantic_core-2.27.1-cp313-none-win32.whl", hash = "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05"}, + {file = "pydantic_core-2.27.1-cp313-none-win_amd64.whl", hash = "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337"}, + {file = "pydantic_core-2.27.1-cp313-none-win_arm64.whl", hash = "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5"}, + {file = "pydantic_core-2.27.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62"}, + {file = "pydantic_core-2.27.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b"}, + {file = "pydantic_core-2.27.1-cp38-none-win32.whl", hash = "sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618"}, + {file = "pydantic_core-2.27.1-cp38-none-win_amd64.whl", hash = "sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4"}, + {file = "pydantic_core-2.27.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967"}, + {file = "pydantic_core-2.27.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131"}, + {file = "pydantic_core-2.27.1-cp39-none-win32.whl", hash = "sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3"}, + {file = "pydantic_core-2.27.1-cp39-none-win_amd64.whl", hash = "sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840"}, + {file = "pydantic_core-2.27.1.tar.gz", hash = "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235"}, ] [package.dependencies] @@ -2198,13 +2206,13 @@ reflex = ">=0.6.0a" [[package]] name = "reflex-hosting-cli" -version = "0.1.16" +version = "0.1.17" description = "Reflex Hosting CLI" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "reflex_hosting_cli-0.1.16-py3-none-any.whl", hash = "sha256:1b12c2a76a27571102cacf5ec3028fb09816a51568bff793735e66aaad886605"}, - {file = "reflex_hosting_cli-0.1.16.tar.gz", hash = "sha256:9c9826318fd3d388b706be70f1f500a35e355f8f86f54138e7789fd6096a4ab9"}, + {file = "reflex_hosting_cli-0.1.17-py3-none-any.whl", hash = "sha256:cf1accec70745557a40125ffa2a8929e6ef9834808afe78e4f4a01933ac0cb67"}, + {file = "reflex_hosting_cli-0.1.17.tar.gz", hash = "sha256:263d8dc217eb24d4198ac0bcfd710980bd7795d9818a5e522027657f94752710"}, ] [package.dependencies] @@ -2350,23 +2358,23 @@ websocket-client = ">=1.8,<2.0" [[package]] name = "setuptools" -version = "75.5.0" +version = "75.6.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.9" files = [ - {file = "setuptools-75.5.0-py3-none-any.whl", hash = "sha256:87cb777c3b96d638ca02031192d40390e0ad97737e27b6b4fa831bea86f2f829"}, - {file = "setuptools-75.5.0.tar.gz", hash = "sha256:5c4ccb41111392671f02bb5f8436dfc5a9a7185e80500531b133f5775c4163ef"}, + {file = "setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d"}, + {file = "setuptools-75.6.0.tar.gz", hash = "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6"}, ] [package.extras] check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.7.0)"] -core = ["importlib-metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (>=1.12,<1.14)", "pytest-mypy"] +type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (>=1.12,<1.14)", "pytest-mypy"] [[package]] name = "shellingham" @@ -2773,13 +2781,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" -version = "0.32.0" +version = "0.32.1" description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.8" files = [ - {file = "uvicorn-0.32.0-py3-none-any.whl", hash = "sha256:60b8f3a5ac027dcd31448f411ced12b5ef452c646f76f02f8cc3f25d8d26fd82"}, - {file = "uvicorn-0.32.0.tar.gz", hash = "sha256:f78b36b143c16f54ccdb8190d0a26b5f1901fe5a3c777e1ab29f26391af8551e"}, + {file = "uvicorn-0.32.1-py3-none-any.whl", hash = "sha256:82ad92fd58da0d12af7482ecdb5f2470a04c9c9a53ced65b9bbb4a205377602e"}, + {file = "uvicorn-0.32.1.tar.gz", hash = "sha256:ee9519c246a72b1c084cea8d3b44ed6026e78a4a309cbedae9c37e4cb9fbb175"}, ] [package.dependencies] @@ -2788,7 +2796,7 @@ h11 = ">=0.8" typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} [package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] +standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] [[package]] name = "virtualenv" @@ -3033,4 +3041,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "a610d4c4bfd852f30e69ad2fbb288c2d9cbdf49e05b9d4936fe5e9b2a7cdefdb" +content-hash = "8000601d48cfc1b10d0ae18c6046cc59a50cb6c45e6d3ef4775a3203769f2154" diff --git a/pyproject.toml b/pyproject.toml index 2e271d719..980c16f97 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ wrapt = [ {version = ">=1.11.0,<2.0", python = "<3.11"}, ] packaging = ">=23.1,<25.0" -reflex-hosting-cli = ">=0.1.16,<2.0" +reflex-hosting-cli = ">=0.1.17,<2.0" charset-normalizer = ">=3.3.2,<4.0" wheel = ">=0.42.0,<1.0" build = ">=1.0.3,<2.0" diff --git a/reflex/reflex.py b/reflex/reflex.py index 9d8199148..9781c393a 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -651,8 +651,7 @@ def deployv2( project: Optional[str] = typer.Option( None, "--project", - help="project to deploy to", - hidden=True, + help="project id to deploy to", ), token: Optional[str] = typer.Option( None, From 000938414f46aeaff20256e63d84c96612ae014d Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Fri, 22 Nov 2024 12:31:59 -0800 Subject: [PATCH 31/71] Avoid `set_log_level` foot gun (#4422) --- reflex/utils/console.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/reflex/utils/console.py b/reflex/utils/console.py index 04e590910..b3ba7163d 100644 --- a/reflex/utils/console.py +++ b/reflex/utils/console.py @@ -26,7 +26,22 @@ def set_log_level(log_level: LogLevel): Args: log_level: The log level to set. + + Raises: + ValueError: If the log level is invalid. """ + if not isinstance(log_level, LogLevel): + deprecate( + feature_name="Passing a string to set_log_level", + reason="use reflex.constants.LogLevel enum instead", + deprecation_version="0.6.6", + removal_version="0.7.0", + ) + try: + log_level = getattr(LogLevel, log_level.upper()) + except AttributeError as ae: + raise ValueError(f"Invalid log level: {log_level}") from ae + global _LOG_LEVEL _LOG_LEVEL = log_level From c7d3876fe63ff91cfe82fba45cab0752dd0d9645 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Sat, 23 Nov 2024 10:48:50 -0800 Subject: [PATCH 32/71] [ENG-4137] Handle generic alias passing inspect.isclass check (#4427) On py3.9 and py3.10, `dict[str, str]` and other typing forms are kinda considered classes, but they still fail when doing `issubclass`, so specifically exclude generic aliases before calling issubclass. Fix #4424 Bonus fix: support upcasting of pydantic v1 and v2 models --- reflex/state.py | 8 ++- tests/units/test_state.py | 136 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 137 insertions(+), 7 deletions(-) diff --git a/reflex/state.py b/reflex/state.py index 349dc59e9..95f7f64f6 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -1748,7 +1748,11 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): if value is None: continue hinted_args = value_inside_optional(hinted_args) - if isinstance(value, dict) and inspect.isclass(hinted_args): + if ( + isinstance(value, dict) + and inspect.isclass(hinted_args) + and not types.is_generic_alias(hinted_args) # py3.9-py3.10 + ): if issubclass(hinted_args, Model): # Remove non-fields from the payload payload[arg] = hinted_args( @@ -1759,7 +1763,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): } ) elif dataclasses.is_dataclass(hinted_args) or issubclass( - hinted_args, Base + hinted_args, (Base, BaseModelV1, BaseModelV2) ): payload[arg] = hinted_args(**value) if isinstance(value, list) and (hinted_args is set or hinted_args is Set): diff --git a/tests/units/test_state.py b/tests/units/test_state.py index c8a52e6c0..45c021bd8 100644 --- a/tests/units/test_state.py +++ b/tests/units/test_state.py @@ -10,7 +10,17 @@ import os import sys import threading from textwrap import dedent -from typing import Any, AsyncGenerator, Callable, Dict, List, Optional, Union +from typing import ( + Any, + AsyncGenerator, + Callable, + Dict, + List, + Optional, + Set, + Tuple, + Union, +) from unittest.mock import AsyncMock, Mock import pytest @@ -1828,12 +1838,11 @@ async def test_state_manager_lock_expire_contend( @pytest.fixture(scope="function") -def mock_app(monkeypatch, state_manager: StateManager) -> rx.App: - """Mock app fixture. +def mock_app_simple(monkeypatch) -> rx.App: + """Simple Mock app fixture. Args: monkeypatch: Pytest monkeypatch object. - state_manager: A state manager. Returns: The app, after mocking out prerequisites.get_app() @@ -1844,7 +1853,6 @@ def mock_app(monkeypatch, state_manager: StateManager) -> rx.App: setattr(app_module, CompileVars.APP, app) app.state = TestState - app._state_manager = state_manager app.event_namespace.emit = AsyncMock() # type: ignore def _mock_get_app(*args, **kwargs): @@ -1854,6 +1862,21 @@ def mock_app(monkeypatch, state_manager: StateManager) -> rx.App: return app +@pytest.fixture(scope="function") +def mock_app(mock_app_simple: rx.App, state_manager: StateManager) -> rx.App: + """Mock app fixture. + + Args: + mock_app_simple: A simple mock app. + state_manager: A state manager. + + Returns: + The app, after mocking out prerequisites.get_app() + """ + mock_app_simple._state_manager = state_manager + return mock_app_simple + + @pytest.mark.asyncio async def test_state_proxy(grandchild_state: GrandchildState, mock_app: rx.App): """Test that the state proxy works. @@ -3506,3 +3529,106 @@ def test_init_mixin() -> None: with pytest.raises(ReflexRuntimeError): SubMixin() + + +class ReflexModel(rx.Model): + """A model for testing.""" + + foo: str + + +class UpcastState(rx.State): + """A state for testing upcasting.""" + + passed: bool = False + + def rx_model(self, m: ReflexModel): # noqa: D102 + assert isinstance(m, ReflexModel) + self.passed = True + + def rx_base(self, o: Object): # noqa: D102 + assert isinstance(o, Object) + self.passed = True + + def rx_base_or_none(self, o: Optional[Object]): # noqa: D102 + if o is not None: + assert isinstance(o, Object) + self.passed = True + + def rx_basemodelv1(self, m: ModelV1): # noqa: D102 + assert isinstance(m, ModelV1) + self.passed = True + + def rx_basemodelv2(self, m: ModelV2): # noqa: D102 + assert isinstance(m, ModelV2) + self.passed = True + + def rx_dataclass(self, dc: ModelDC): # noqa: D102 + assert isinstance(dc, ModelDC) + self.passed = True + + def py_set(self, s: set): # noqa: D102 + assert isinstance(s, set) + self.passed = True + + def py_Set(self, s: Set): # noqa: D102 + assert isinstance(s, Set) + self.passed = True + + def py_tuple(self, t: tuple): # noqa: D102 + assert isinstance(t, tuple) + self.passed = True + + def py_Tuple(self, t: Tuple): # noqa: D102 + assert isinstance(t, tuple) + self.passed = True + + def py_dict(self, d: dict[str, str]): # noqa: D102 + assert isinstance(d, dict) + self.passed = True + + def py_list(self, ls: list[str]): # noqa: D102 + assert isinstance(ls, list) + self.passed = True + + def py_Any(self, a: Any): # noqa: D102 + assert isinstance(a, list) + self.passed = True + + def py_unresolvable(self, u: "Unresolvable"): # noqa: D102, F821 # type: ignore + assert isinstance(u, list) + self.passed = True + + +@pytest.mark.asyncio +@pytest.mark.usefixtures("mock_app_simple") +@pytest.mark.parametrize( + ("handler", "payload"), + [ + (UpcastState.rx_model, {"m": {"foo": "bar"}}), + (UpcastState.rx_base, {"o": {"foo": "bar"}}), + (UpcastState.rx_base_or_none, {"o": {"foo": "bar"}}), + (UpcastState.rx_base_or_none, {"o": None}), + (UpcastState.rx_basemodelv1, {"m": {"foo": "bar"}}), + (UpcastState.rx_basemodelv2, {"m": {"foo": "bar"}}), + (UpcastState.rx_dataclass, {"dc": {"foo": "bar"}}), + (UpcastState.py_set, {"s": ["foo", "foo"]}), + (UpcastState.py_Set, {"s": ["foo", "foo"]}), + (UpcastState.py_tuple, {"t": ["foo", "foo"]}), + (UpcastState.py_Tuple, {"t": ["foo", "foo"]}), + (UpcastState.py_dict, {"d": {"foo": "bar"}}), + (UpcastState.py_list, {"ls": ["foo", "foo"]}), + (UpcastState.py_Any, {"a": ["foo"]}), + (UpcastState.py_unresolvable, {"u": ["foo"]}), + ], +) +async def test_upcast_event_handler_arg(handler, payload): + """Test that upcast event handler args work correctly. + + Args: + handler: The handler to test. + payload: The payload to test. + """ + state = UpcastState() + async for update in state._process_event(handler, state, payload): + assert update.delta == {UpcastState.get_full_name(): {"passed": True}} From 697e26c25b8953d7be99ca2af365ba9cf71e85a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Sat, 23 Nov 2024 10:51:07 -0800 Subject: [PATCH 33/71] fix mutable default in EventNamespace (#4420) --- reflex/app.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/reflex/app.py b/reflex/app.py index afc40e3b8..fc8efb420 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -1462,10 +1462,10 @@ class EventNamespace(AsyncNamespace): app: App # Keep a mapping between socket ID and client token. - token_to_sid: dict[str, str] = {} + token_to_sid: dict[str, str] # Keep a mapping between client token and socket ID. - sid_to_token: dict[str, str] = {} + sid_to_token: dict[str, str] def __init__(self, namespace: str, app: App): """Initialize the event namespace. @@ -1475,6 +1475,8 @@ class EventNamespace(AsyncNamespace): app: The application object. """ super().__init__(namespace) + self.token_to_sid = {} + self.sid_to_token = {} self.app = app def on_connect(self, sid, environ): From d7d46e431b6b14dee6bcc389d7b3807fb3e36d8e Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Mon, 25 Nov 2024 19:38:52 +0100 Subject: [PATCH 34/71] fix: state size was not checked for dill (#4431) --- reflex/state.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/reflex/state.py b/reflex/state.py index 95f7f64f6..127fe98cc 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -2175,11 +2175,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): Returns: The serialized state. """ + payload = b"" try: - pickle_state = pickle.dumps((self._to_schema(), self)) - if environment.REFLEX_PERF_MODE.get() != PerformanceMode.OFF: - self._check_state_size(len(pickle_state)) - return pickle_state + payload = pickle.dumps((self._to_schema(), self)) except HANDLED_PICKLE_ERRORS as og_pickle_error: error = ( f"Failed to serialize state {self.get_full_name()} due to unpicklable object. " @@ -2188,7 +2186,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): try: import dill - return dill.dumps((self._to_schema(), self)) + payload = dill.dumps((self._to_schema(), self)) except ImportError: error += ( f"Pickle error: {og_pickle_error}. " @@ -2196,8 +2194,10 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): ) except HANDLED_PICKLE_ERRORS as ex: error += f"Dill was also unable to pickle the state: {ex}" - console.warn(error) - return b"" + console.warn(error) + if environment.REFLEX_PERF_MODE.get() != PerformanceMode.OFF: + self._check_state_size(len(payload)) + return payload @classmethod def _deserialize( From 51ca89bc5c0e487226bf5d9f357dbe49f77bd6ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Mon, 25 Nov 2024 10:45:29 -0800 Subject: [PATCH 35/71] allow for 'go.Figure | None' annotation in State (#4426) --- reflex/components/plotly/plotly.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reflex/components/plotly/plotly.py b/reflex/components/plotly/plotly.py index 1e551ce87..f07a743cb 100644 --- a/reflex/components/plotly/plotly.py +++ b/reflex/components/plotly/plotly.py @@ -255,7 +255,7 @@ const extractPoints = (points) => { def _render(self): tag = super()._render() - figure = self.data.to(dict) + figure = self.data.to(dict) if self.data is not None else {} merge_dicts = [] # Data will be merged and spread from these dict Vars if self.layout is not None: # Why is this not a literal dict? Great question... it didn't work From f490643b252acbef7df4280baf1d79ff89f3af3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Mon, 25 Nov 2024 11:27:07 -0800 Subject: [PATCH 36/71] follow up to #4426 (#4436) --- reflex/components/plotly/plotly.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reflex/components/plotly/plotly.py b/reflex/components/plotly/plotly.py index f07a743cb..2c0dccd3e 100644 --- a/reflex/components/plotly/plotly.py +++ b/reflex/components/plotly/plotly.py @@ -255,7 +255,7 @@ const extractPoints = (points) => { def _render(self): tag = super()._render() - figure = self.data.to(dict) if self.data is not None else {} + figure = self.data.to(dict) if self.data is not None else Var.create({}) merge_dicts = [] # Data will be merged and spread from these dict Vars if self.layout is not None: # Why is this not a literal dict? Great question... it didn't work From 80696fec635291cee70e19df08a8ba3e8ad233b2 Mon Sep 17 00:00:00 2001 From: Elijah Ahianyo Date: Mon, 25 Nov 2024 20:14:50 +0000 Subject: [PATCH 37/71] Remove invitation code logic from reflex logoutv2 (#4433) * what happened there? * we should do this for v2 instead --- reflex/reflex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reflex/reflex.py b/reflex/reflex.py index 9781c393a..f71fc5f86 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -404,7 +404,7 @@ def logoutv2( hosting.log_out_on_browser() console.debug("Deleting access token from config locally") - hosting.delete_token_from_config(include_invitation_code=True) + hosting.delete_token_from_config() db_cli = typer.Typer() From 24ff29f74d89ff89828442e7e7b4e6bdb08f3ad2 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Tue, 26 Nov 2024 14:04:36 -0800 Subject: [PATCH 38/71] bump to 0.6.7dev1 for further development (#4434) --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 980c16f97..619c4ff47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "reflex" -version = "0.6.6dev1" +version = "0.6.7dev1" description = "Web apps in pure Python." license = "Apache-2.0" authors = [ From 39cdce6960fef0cdf73b76f6b99f3f174d83059d Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Thu, 28 Nov 2024 04:56:41 -0800 Subject: [PATCH 39/71] [HOS-333] Send a "reload" message to the frontend after state expiry (#4442) * Unit test updates * test_client_storage: simulate backend state expiry * [HOS-333] Send a "reload" message to the frontend after state expiry 1. a state instance expires on the backing store 2. frontend attempts to process an event against the expired token and gets a fresh instance of the state without router_data set 3. backend sends a "reload" message on the websocket containing the event and immediately stops processing 4. in response to the "reload" message, frontend sends [hydrate, update client storage, on_load, ] This allows the frontend and backend to re-syncronize on the state of the app before continuing to process regular events. If the event in (2) is a special hydrate event, then it is processed normally by the middleware and the "reload" logic is skipped since this indicates an initial load or a browser refresh. * unit tests working with redis --- reflex/.templates/web/utils/state.js | 4 + reflex/app.py | 16 ++++ reflex/state.py | 3 + tests/integration/test_client_storage.py | 113 ++++++++++++++++++++++- tests/units/test_app.py | 8 +- tests/units/test_state.py | 12 ++- 6 files changed, 150 insertions(+), 6 deletions(-) diff --git a/reflex/.templates/web/utils/state.js b/reflex/.templates/web/utils/state.js index e14c669f5..f6541c7ae 100644 --- a/reflex/.templates/web/utils/state.js +++ b/reflex/.templates/web/utils/state.js @@ -454,6 +454,10 @@ export const connect = async ( queueEvents(update.events, socket); } }); + socket.current.on("reload", async (event) => { + event_processing = false; + queueEvents([...initialEvents(), JSON5.parse(event)], socket); + }) document.addEventListener("visibilitychange", checkVisibility); }; diff --git a/reflex/app.py b/reflex/app.py index fc8efb420..cdf21aa35 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -73,6 +73,7 @@ from reflex.event import ( EventSpec, EventType, IndividualEventType, + get_hydrate_event, window_alert, ) from reflex.model import Model, get_db_status @@ -1259,6 +1260,21 @@ async def process( ) # Get the state for the session exclusively. async with app.state_manager.modify_state(event.substate_token) as state: + # When this is a brand new instance of the state, signal the + # frontend to reload before processing it. + if ( + not state.router_data + and event.name != get_hydrate_event(state) + and app.event_namespace is not None + ): + await asyncio.create_task( + app.event_namespace.emit( + "reload", + data=format.json_dumps(event), + to=sid, + ) + ) + return # re-assign only when the value is different if state.router_data != router_data: # assignment will recurse into substates and force recalculation of diff --git a/reflex/state.py b/reflex/state.py index 127fe98cc..55f29cf45 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -1959,6 +1959,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): if var in self.base_vars or var in self._backend_vars: self._was_touched = True break + if var == constants.ROUTER_DATA and self.parent_state is None: + self._was_touched = True + break def _get_was_touched(self) -> bool: """Check current dirty_vars and flag to determine if state instance was modified. diff --git a/tests/integration/test_client_storage.py b/tests/integration/test_client_storage.py index e8c95ab71..236d3e14e 100644 --- a/tests/integration/test_client_storage.py +++ b/tests/integration/test_client_storage.py @@ -10,6 +10,13 @@ from selenium.webdriver import Firefox from selenium.webdriver.common.by import By from selenium.webdriver.remote.webdriver import WebDriver +from reflex.state import ( + State, + StateManagerDisk, + StateManagerMemory, + StateManagerRedis, + _substate_key, +) from reflex.testing import AppHarness from . import utils @@ -74,7 +81,7 @@ def ClientSide(): return rx.fragment( rx.input( value=ClientSideState.router.session.client_token, - is_read_only=True, + read_only=True, id="token", ), rx.input( @@ -604,6 +611,110 @@ async def test_client_side_state( assert s2.text == "s2 value" assert s3.text == "s3 value" + # Simulate state expiration + if isinstance(client_side.state_manager, StateManagerRedis): + await client_side.state_manager.redis.delete( + _substate_key(token, State.get_full_name()) + ) + await client_side.state_manager.redis.delete(_substate_key(token, state_name)) + await client_side.state_manager.redis.delete( + _substate_key(token, sub_state_name) + ) + await client_side.state_manager.redis.delete( + _substate_key(token, sub_sub_state_name) + ) + elif isinstance(client_side.state_manager, (StateManagerMemory, StateManagerDisk)): + del client_side.state_manager.states[token] + if isinstance(client_side.state_manager, StateManagerDisk): + client_side.state_manager.token_expiration = 0 + client_side.state_manager._purge_expired_states() + + # Ensure the state is gone (not hydrated) + async def poll_for_not_hydrated(): + state = await client_side.get_state(_substate_key(token or "", state_name)) + return not state.is_hydrated + + assert await AppHarness._poll_for_async(poll_for_not_hydrated) + + # Trigger event to get a new instance of the state since the old was expired. + state_var_input = driver.find_element(By.ID, "state_var") + state_var_input.send_keys("re-triggering") + + # get new references to all cookie and local storage elements (again) + c1 = driver.find_element(By.ID, "c1") + c2 = driver.find_element(By.ID, "c2") + c3 = driver.find_element(By.ID, "c3") + c4 = driver.find_element(By.ID, "c4") + c5 = driver.find_element(By.ID, "c5") + c6 = driver.find_element(By.ID, "c6") + c7 = driver.find_element(By.ID, "c7") + l1 = driver.find_element(By.ID, "l1") + l2 = driver.find_element(By.ID, "l2") + l3 = driver.find_element(By.ID, "l3") + l4 = driver.find_element(By.ID, "l4") + s1 = driver.find_element(By.ID, "s1") + s2 = driver.find_element(By.ID, "s2") + s3 = driver.find_element(By.ID, "s3") + c1s = driver.find_element(By.ID, "c1s") + l1s = driver.find_element(By.ID, "l1s") + s1s = driver.find_element(By.ID, "s1s") + + assert c1.text == "c1 value" + assert c2.text == "c2 value" + assert c3.text == "" # temporary cookie expired after reset state! + assert c4.text == "c4 value" + assert c5.text == "c5 value" + assert c6.text == "c6 value" + assert c7.text == "c7 value" + assert l1.text == "l1 value" + assert l2.text == "l2 value" + assert l3.text == "l3 value" + assert l4.text == "l4 value" + assert s1.text == "s1 value" + assert s2.text == "s2 value" + assert s3.text == "s3 value" + assert c1s.text == "c1s value" + assert l1s.text == "l1s value" + assert s1s.text == "s1s value" + + # Get the backend state and ensure the values are still set + async def get_sub_state(): + root_state = await client_side.get_state( + _substate_key(token or "", sub_state_name) + ) + state = root_state.substates[client_side.get_state_name("_client_side_state")] + sub_state = state.substates[ + client_side.get_state_name("_client_side_sub_state") + ] + return sub_state + + async def poll_for_c1_set(): + sub_state = await get_sub_state() + return sub_state.c1 == "c1 value" + + assert await AppHarness._poll_for_async(poll_for_c1_set) + sub_state = await get_sub_state() + assert sub_state.c1 == "c1 value" + assert sub_state.c2 == "c2 value" + assert sub_state.c3 == "" + assert sub_state.c4 == "c4 value" + assert sub_state.c5 == "c5 value" + assert sub_state.c6 == "c6 value" + assert sub_state.c7 == "c7 value" + assert sub_state.l1 == "l1 value" + assert sub_state.l2 == "l2 value" + assert sub_state.l3 == "l3 value" + assert sub_state.l4 == "l4 value" + assert sub_state.s1 == "s1 value" + assert sub_state.s2 == "s2 value" + assert sub_state.s3 == "s3 value" + sub_sub_state = sub_state.substates[ + client_side.get_state_name("_client_side_sub_sub_state") + ] + assert sub_sub_state.c1s == "c1s value" + assert sub_sub_state.l1s == "l1s value" + assert sub_sub_state.s1s == "s1s value" + # clear the cookie jar and local storage, ensure state reset to default driver.delete_all_cookies() local_storage.clear() diff --git a/tests/units/test_app.py b/tests/units/test_app.py index 5d3aee6c7..216d36f62 100644 --- a/tests/units/test_app.py +++ b/tests/units/test_app.py @@ -1007,8 +1007,9 @@ async def test_dynamic_route_var_route_change_completed_on_load( substate_token = _substate_key(token, DynamicState) sid = "mock_sid" client_ip = "127.0.0.1" - state = await app.state_manager.get_state(substate_token) - assert state.dynamic == "" + async with app.state_manager.modify_state(substate_token) as state: + state.router_data = {"simulate": "hydrated"} + assert state.dynamic == "" exp_vals = ["foo", "foobar", "baz"] def _event(name, val, **kwargs): @@ -1180,6 +1181,7 @@ async def test_process_events(mocker, token: str): "ip": "127.0.0.1", } app = App(state=GenState) + mocker.patch.object(app, "_postprocess", AsyncMock()) event = Event( token=token, @@ -1187,6 +1189,8 @@ async def test_process_events(mocker, token: str): payload={"c": 5}, router_data=router_data, ) + async with app.state_manager.modify_state(event.substate_token) as state: + state.router_data = {"simulate": "hydrated"} async for _update in process(app, event, "mock_sid", {}, "127.0.0.1"): pass diff --git a/tests/units/test_state.py b/tests/units/test_state.py index 45c021bd8..8e61b8dae 100644 --- a/tests/units/test_state.py +++ b/tests/units/test_state.py @@ -1982,6 +1982,10 @@ class BackgroundTaskState(BaseState): order: List[str] = [] dict_list: Dict[str, List[int]] = {"foo": [1, 2, 3]} + def __init__(self, **kwargs): # noqa: D107 + super().__init__(**kwargs) + self.router_data = {"simulate": "hydrate"} + @rx.var def computed_order(self) -> List[str]: """Get the order as a computed var. @@ -2732,7 +2736,7 @@ def test_set_base_field_via_setter(): assert "c2" in bfss.dirty_vars -def exp_is_hydrated(state: State, is_hydrated: bool = True) -> Dict[str, Any]: +def exp_is_hydrated(state: BaseState, is_hydrated: bool = True) -> Dict[str, Any]: """Expected IS_HYDRATED delta that would be emitted by HydrateMiddleware. Args: @@ -2811,7 +2815,8 @@ async def test_preprocess(app_module_mock, token, test_state, expected, mocker): app = app_module_mock.app = App( state=State, load_events={"index": [test_state.test_handler]} ) - state = State() + async with app.state_manager.modify_state(_substate_key(token, State)) as state: + state.router_data = {"simulate": "hydrate"} updates = [] async for update in rx.app.process( @@ -2858,7 +2863,8 @@ async def test_preprocess_multiple_load_events(app_module_mock, token, mocker): state=State, load_events={"index": [OnLoadState.test_handler, OnLoadState.test_handler]}, ) - state = State() + async with app.state_manager.modify_state(_substate_key(token, State)) as state: + state.router_data = {"simulate": "hydrate"} updates = [] async for update in rx.app.process( From a320d062fb739235642c95fc4907f7d5f9531e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Mon, 2 Dec 2024 09:20:33 -0800 Subject: [PATCH 40/71] enable css props via wrapperStyle for recharts components (#4447) --- reflex/components/recharts/recharts.py | 16 ++-------------- reflex/components/recharts/recharts.pyi | 1 - 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/reflex/components/recharts/recharts.py b/reflex/components/recharts/recharts.py index a0d683f72..b5a4ed113 100644 --- a/reflex/components/recharts/recharts.py +++ b/reflex/components/recharts/recharts.py @@ -3,7 +3,6 @@ from typing import Dict, Literal from reflex.components.component import Component, MemoizationLeaf, NoSSRComponent -from reflex.utils import console class Recharts(Component): @@ -11,19 +10,8 @@ class Recharts(Component): library = "recharts@2.13.0" - def render(self) -> Dict: - """Render the tag. - - Returns: - The rendered tag. - """ - tag = super().render() - if any(p.startswith("css") for p in tag["props"]): - console.warn( - f"CSS props do not work for {self.__class__.__name__}. Consult docs to style it with its own prop." - ) - tag["props"] = [p for p in tag["props"] if not p.startswith("css")] - return tag + def _get_style(self) -> Dict: + return {"wrapperStyle": self.style} class RechartsCharts(NoSSRComponent, MemoizationLeaf): diff --git a/reflex/components/recharts/recharts.pyi b/reflex/components/recharts/recharts.pyi index 10e1b96c1..65e65bce1 100644 --- a/reflex/components/recharts/recharts.pyi +++ b/reflex/components/recharts/recharts.pyi @@ -11,7 +11,6 @@ from reflex.style import Style from reflex.vars.base import Var class Recharts(Component): - def render(self) -> Dict: ... @overload @classmethod def create( # type: ignore From 99d1b5fbdfaa05cfac3f61fdc4f4c991178567d4 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Mon, 2 Dec 2024 16:29:06 -0800 Subject: [PATCH 41/71] rx.upload must include _var_data from props (#4463) * rx.upload must include _var_data from props str-casting the dropzone arguments removed any VarData they depended on, like the state context. update test_upload to include passing a prop from a state var * Handle large payload delta from upload event handler Fix update chunk chaining logic; try/catch wasn't catching errors from the async inner function. --- reflex/.templates/web/utils/state.js | 39 ++++++++++++++++------------ reflex/components/core/upload.py | 13 ++++++---- tests/integration/test_upload.py | 10 ++++++- 3 files changed, 40 insertions(+), 22 deletions(-) diff --git a/reflex/.templates/web/utils/state.js b/reflex/.templates/web/utils/state.js index f6541c7ae..622f171ad 100644 --- a/reflex/.templates/web/utils/state.js +++ b/reflex/.templates/web/utils/state.js @@ -457,7 +457,7 @@ export const connect = async ( socket.current.on("reload", async (event) => { event_processing = false; queueEvents([...initialEvents(), JSON5.parse(event)], socket); - }) + }); document.addEventListener("visibilitychange", checkVisibility); }; @@ -490,23 +490,30 @@ export const uploadFiles = async ( return false; } + // Track how many partial updates have been processed for this upload. let resp_idx = 0; const eventHandler = (progressEvent) => { - // handle any delta / event streamed from the upload event handler + const event_callbacks = socket._callbacks.$event; + // Whenever called, responseText will contain the entire response so far. const chunks = progressEvent.event.target.responseText.trim().split("\n"); + // So only process _new_ chunks beyond resp_idx. chunks.slice(resp_idx).map((chunk) => { - try { - socket._callbacks.$event.map((f) => { - f(chunk); - }); - resp_idx += 1; - } catch (e) { - if (progressEvent.progress === 1) { - // Chunk may be incomplete, so only report errors when full response is available. - console.log("Error parsing chunk", chunk, e); - } - return; - } + event_callbacks.map((f, ix) => { + f(chunk) + .then(() => { + if (ix === event_callbacks.length - 1) { + // Mark this chunk as processed. + resp_idx += 1; + } + }) + .catch((e) => { + if (progressEvent.progress === 1) { + // Chunk may be incomplete, so only report errors when full response is available. + console.log("Error parsing chunk", chunk, e); + } + return; + }); + }); }); }; @@ -711,7 +718,7 @@ export const useEventLoop = ( const combined_name = events.map((e) => e.name).join("+++"); if (event_actions?.temporal) { if (!socket.current || !socket.current.connected) { - return; // don't queue when the backend is not connected + return; // don't queue when the backend is not connected } } if (event_actions?.throttle) { @@ -852,7 +859,7 @@ export const useEventLoop = ( if (router.components[router.pathname].error) { delete router.components[router.pathname].error; } - } + }; router.events.on("routeChangeStart", change_start); router.events.on("routeChangeComplete", change_complete); router.events.on("routeChangeError", change_error); diff --git a/reflex/components/core/upload.py b/reflex/components/core/upload.py index 33dfae40f..87488d98a 100644 --- a/reflex/components/core/upload.py +++ b/reflex/components/core/upload.py @@ -293,13 +293,15 @@ class Upload(MemoizationLeaf): format.to_camel_case(key): value for key, value in upload_props.items() } - use_dropzone_arguments = { - "onDrop": event_var, - **upload_props, - } + use_dropzone_arguments = Var.create( + { + "onDrop": event_var, + **upload_props, + } + ) left_side = f"const {{getRootProps: {root_props_unique_name}, getInputProps: {input_props_unique_name}}} " - right_side = f"useDropzone({str(Var.create(use_dropzone_arguments))})" + right_side = f"useDropzone({str(use_dropzone_arguments)})" var_data = VarData.merge( VarData( @@ -307,6 +309,7 @@ class Upload(MemoizationLeaf): hooks={Hooks.EVENTS: None}, ), event_var._get_all_var_data(), + use_dropzone_arguments._get_all_var_data(), VarData( hooks={ callback_str: None, diff --git a/tests/integration/test_upload.py b/tests/integration/test_upload.py index fe8ebb4d7..b7f14b03d 100644 --- a/tests/integration/test_upload.py +++ b/tests/integration/test_upload.py @@ -19,10 +19,14 @@ def UploadFile(): import reflex as rx + LARGE_DATA = "DUMMY" * 1024 * 512 + class UploadState(rx.State): _file_data: Dict[str, str] = {} event_order: List[str] = [] progress_dicts: List[dict] = [] + disabled: bool = False + large_data: str = "" async def handle_upload(self, files: List[rx.UploadFile]): for file in files: @@ -33,6 +37,7 @@ def UploadFile(): for file in files: upload_data = await file.read() self._file_data[file.filename or ""] = upload_data.decode("utf-8") + self.large_data = LARGE_DATA yield UploadState.chain_event def upload_progress(self, progress): @@ -41,13 +46,15 @@ def UploadFile(): self.progress_dicts.append(progress) def chain_event(self): + assert self.large_data == LARGE_DATA + self.large_data = "" self.event_order.append("chain_event") def index(): return rx.vstack( rx.input( value=UploadState.router.session.client_token, - is_read_only=True, + read_only=True, id="token", ), rx.heading("Default Upload"), @@ -56,6 +63,7 @@ def UploadFile(): rx.button("Select File"), rx.text("Drag and drop files here or click to select files"), ), + disabled=UploadState.disabled, ), rx.button( "Upload", From c721227a062ed6f977477e435d37b3fa5b0be509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Mon, 2 Dec 2024 16:31:32 -0800 Subject: [PATCH 42/71] add default value for text area (#4462) * add default_value prop in text_area * also support it for el.textarea --- reflex/components/el/elements/forms.py | 3 +++ reflex/components/el/elements/forms.pyi | 2 ++ reflex/components/radix/themes/components/text_area.py | 3 +++ reflex/components/radix/themes/components/text_area.pyi | 2 ++ 4 files changed, 10 insertions(+) diff --git a/reflex/components/el/elements/forms.py b/reflex/components/el/elements/forms.py index 7a94a9c2d..56dab5c7f 100644 --- a/reflex/components/el/elements/forms.py +++ b/reflex/components/el/elements/forms.py @@ -570,6 +570,9 @@ class Textarea(BaseHTML): # Visible width of the text control, in average character widths cols: Var[Union[str, int, bool]] + # The default value of the textarea when initially rendered + default_value: Var[str] + # Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted dirname: Var[Union[str, int, bool]] diff --git a/reflex/components/el/elements/forms.pyi b/reflex/components/el/elements/forms.pyi index a32eb8c5d..e2d659338 100644 --- a/reflex/components/el/elements/forms.pyi +++ b/reflex/components/el/elements/forms.pyi @@ -1350,6 +1350,7 @@ class Textarea(BaseHTML): auto_focus: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, auto_height: Optional[Union[Var[bool], bool]] = None, cols: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, + default_value: Optional[Union[Var[str], str]] = None, dirname: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, disabled: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, enter_key_submit: Optional[Union[Var[bool], bool]] = None, @@ -1439,6 +1440,7 @@ class Textarea(BaseHTML): auto_focus: Automatically focuses the textarea when the page loads auto_height: Automatically fit the content height to the text (use min-height with this prop) cols: Visible width of the text control, in average character widths + default_value: The default value of the textarea when initially rendered dirname: Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted disabled: Disables the textarea enter_key_submit: Enter key submits form (shift-enter adds new line) diff --git a/reflex/components/radix/themes/components/text_area.py b/reflex/components/radix/themes/components/text_area.py index 87f56e911..83fa8a593 100644 --- a/reflex/components/radix/themes/components/text_area.py +++ b/reflex/components/radix/themes/components/text_area.py @@ -41,6 +41,9 @@ class TextArea(RadixThemesComponent, elements.Textarea): # Automatically focuses the textarea when the page loads auto_focus: Var[bool] + # The default value of the textarea when initially rendered + default_value: Var[str] + # Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted dirname: Var[str] diff --git a/reflex/components/radix/themes/components/text_area.pyi b/reflex/components/radix/themes/components/text_area.pyi index 196346cf9..63d474842 100644 --- a/reflex/components/radix/themes/components/text_area.pyi +++ b/reflex/components/radix/themes/components/text_area.pyi @@ -123,6 +123,7 @@ class TextArea(RadixThemesComponent, elements.Textarea): ] = None, auto_complete: Optional[Union[Var[bool], bool]] = None, auto_focus: Optional[Union[Var[bool], bool]] = None, + default_value: Optional[Union[Var[str], str]] = None, dirname: Optional[Union[Var[str], str]] = None, disabled: Optional[Union[Var[bool], bool]] = None, form: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None, @@ -217,6 +218,7 @@ class TextArea(RadixThemesComponent, elements.Textarea): radius: The radius of the text area: "none" | "small" | "medium" | "large" | "full" auto_complete: Whether the form control should have autocomplete enabled auto_focus: Automatically focuses the textarea when the page loads + default_value: The default value of the textarea when initially rendered dirname: Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted disabled: Disables the textarea form: Associates the textarea with a form (by id) From a894f21ce50eb661feb9db349830770b7f67b1dd Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Wed, 4 Dec 2024 18:15:31 -0800 Subject: [PATCH 43/71] [ENG-4149] require login to deploy named templates (#4450) * integration_tests.yml: init masenf/rx_shout as a template fix test * [ENG-4149] require login to deploy template * Send loginv2 telemetry event --- .github/workflows/integration_tests.yml | 29 +++++++++++++++++++ reflex/reflex.py | 4 ++- reflex/utils/prerequisites.py | 38 ++++++++++++------------- reflex/utils/telemetry.py | 2 +- 4 files changed, 52 insertions(+), 21 deletions(-) diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index fc5935c2a..3e22234b8 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -162,7 +162,36 @@ jobs: --python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}" --pr-id "${{ github.event.pull_request.id }}" --branch-name "${{ github.head_ref || github.ref_name }}" --app-name "reflex-web" --path ./reflex-web/.web + + rx-shout-from-template: + strategy: + fail-fast: false + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup_build_env + with: + python-version: '3.11.4' + run-poetry-install: true + create-venv-at-path: .venv + - name: Create app directory + run: mkdir rx-shout-from-template + - name: Init reflex-web from template + run: poetry run reflex init --template https://github.com/masenf/rx_shout + working-directory: ./rx-shout-from-template + - name: ignore reflex pin in requirements + run: sed -i -e '/reflex==/d' requirements.txt + working-directory: ./rx-shout-from-template + - name: Install additional dependencies + run: poetry run uv pip install -r requirements.txt + working-directory: ./rx-shout-from-template + - name: Run Website and Check for errors + run: | + # Check that npm is home + npm -v + poetry run bash scripts/integration.sh ./rx-shout-from-template prod + reflex-web-macos: if: github.event_name == 'push' && github.ref == 'refs/heads/main' strategy: diff --git a/reflex/reflex.py b/reflex/reflex.py index f71fc5f86..f228f43d4 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -370,7 +370,9 @@ def loginv2(loglevel: constants.LogLevel = typer.Option(config.loglevel)): check_version() - hosting_cli.login() + validated_info = hosting_cli.login() + if validated_info is not None: + telemetry.send("loginv2", user_uuid=validated_info.get("user_id")) @cli.command() diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index ec79b3297..559f668a1 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -1408,13 +1408,22 @@ def validate_and_create_app_using_remote_template(app_name, template, templates) """ # If user selects a template, it needs to exist. if template in templates: + from reflex_cli.v2.utils import hosting + + authenticated_token = hosting.authenticated_token() + if not authenticated_token or not authenticated_token[0]: + console.print( + f"Please use `reflex loginv2` to access the '{template}' template." + ) + raise typer.Exit(3) + template_url = templates[template].code_url else: # Check if the template is a github repo. if template.startswith("https://github.com"): template_url = f"{template.strip('/').replace('.git', '')}/archive/main.zip" else: - console.error(f"Template `{template}` not found.") + console.error(f"Template `{template}` not found or invalid.") raise typer.Exit(1) if template_url is None: @@ -1451,7 +1460,7 @@ def generate_template_using_ai(template: str | None = None) -> str: def fetch_remote_templates( - template: Optional[str] = None, + template: str, ) -> tuple[str, dict[str, Template]]: """Fetch the available remote templates. @@ -1460,9 +1469,6 @@ def fetch_remote_templates( Returns: The selected template and the available templates. - - Raises: - Exit: If the template is not valid or if the template is not specified. """ available_templates = {} @@ -1474,19 +1480,7 @@ def fetch_remote_templates( console.debug(f"Error while fetching templates: {e}") template = constants.Templates.DEFAULT - if template == constants.Templates.DEFAULT: - return template, available_templates - - if template in available_templates: - return template, available_templates - - else: - if template is not None: - console.error(f"{template!r} is not a valid template name.") - console.print( - f"Go to the templates page ({constants.Templates.REFLEX_TEMPLATES_URL}) and copy the command to init with a template." - ) - raise typer.Exit(0) + return template, available_templates def initialize_app( @@ -1501,6 +1495,9 @@ def initialize_app( Returns: The name of the template. + + Raises: + Exit: If the template is not valid or unspecified. """ # Local imports to avoid circular imports. from reflex.utils import telemetry @@ -1528,7 +1525,10 @@ def initialize_app( # change to the default to allow creation of default app template = constants.Templates.DEFAULT elif template == constants.Templates.CHOOSE_TEMPLATES: - template, templates = fetch_remote_templates() + console.print( + f"Go to the templates page ({constants.Templates.REFLEX_TEMPLATES_URL}) and copy the command to init with a template." + ) + raise typer.Exit(0) # If the blank template is selected, create a blank app. if template in (constants.Templates.DEFAULT,): diff --git a/reflex/utils/telemetry.py b/reflex/utils/telemetry.py index 815d37a1b..b24b4d3bf 100644 --- a/reflex/utils/telemetry.py +++ b/reflex/utils/telemetry.py @@ -129,7 +129,7 @@ def _prepare_event(event: str, **kwargs) -> dict: cpuinfo = get_cpu_info() - additional_keys = ["template", "context", "detail"] + additional_keys = ["template", "context", "detail", "user_uuid"] additional_fields = { key: value for key in additional_keys if (value := kwargs.get(key)) is not None } From e23d9397810d8c14f058ea1ede3c57b401a6cd8e Mon Sep 17 00:00:00 2001 From: Elijah Ahianyo Date: Thu, 5 Dec 2024 02:17:22 +0000 Subject: [PATCH 44/71] [HOS-373][HOS-372]Logout should not open the browser (#4475) * Logout should not open the browser * check user login first before deploy --- reflex/reflex.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/reflex/reflex.py b/reflex/reflex.py index f228f43d4..0e2b54fcb 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -398,15 +398,10 @@ def logoutv2( ), ): """Log out of access to Reflex hosting service.""" - from reflex_cli.v2.utils import hosting + from reflex_cli.v2 import cli check_version() - - console.set_log_level(loglevel) - - hosting.log_out_on_browser() - console.debug("Deleting access token from config locally") - hosting.delete_token_from_config() + cli.logout() db_cli = typer.Typer() @@ -672,6 +667,8 @@ def deployv2( # Set the log level. console.set_log_level(loglevel) + # make sure user is logged in. + hosting_cli.login() # Only check requirements if interactive. # There is user interaction for requirements update. From 12771004cb5f53d3c3e5a5889a45711aab90b010 Mon Sep 17 00:00:00 2001 From: Simon Young <40179067+Kastier1@users.noreply.github.com> Date: Wed, 4 Dec 2024 23:21:18 -0800 Subject: [PATCH 45/71] remove v2 commands (#4478) * remove v2 commands * format * remove v2 * remove v2 * little fixes friend * add cloud * relock poetry deps * bump reflex-hosting-cli dep * test_dynamic_routes: wait for token attempt to avoid test flakiness * relock deps * test_dynamic_routes: increase polling timeout --------- Co-authored-by: simon Co-authored-by: Masen Furer --- poetry.lock | 16 +- pyproject.toml | 2 +- reflex/config.py | 4 +- reflex/custom_components/custom_components.py | 4 +- reflex/reflex.py | 191 +----------------- tests/integration/test_dynamic_routes.py | 10 +- 6 files changed, 30 insertions(+), 197 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3310f106a..74e5755a3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2206,13 +2206,13 @@ reflex = ">=0.6.0a" [[package]] name = "reflex-hosting-cli" -version = "0.1.17" +version = "0.1.28" description = "Reflex Hosting CLI" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "reflex_hosting_cli-0.1.17-py3-none-any.whl", hash = "sha256:cf1accec70745557a40125ffa2a8929e6ef9834808afe78e4f4a01933ac0cb67"}, - {file = "reflex_hosting_cli-0.1.17.tar.gz", hash = "sha256:263d8dc217eb24d4198ac0bcfd710980bd7795d9818a5e522027657f94752710"}, + {file = "reflex_hosting_cli-0.1.28-py3-none-any.whl", hash = "sha256:68c60e8b2cb8856d0b8eac1f06410d8fe192944884f54bfad47adf5db62bd395"}, + {file = "reflex_hosting_cli-0.1.28.tar.gz", hash = "sha256:9b4fb771396ffeba857ada0207fdfd78e2e40b8e35a5486b89cb07f1aa416867"}, ] [package.dependencies] @@ -2224,7 +2224,7 @@ pydantic = ">=1.10.2,<3.0" python-dateutil = ">=2.8.1" rich = ">=13.0.0,<14.0" tabulate = ">=0.9.0,<0.10.0" -typer = ">=0.4.2,<1" +typer = ">=0.15.0,<1" websockets = ">=10.4" [[package]] @@ -2722,13 +2722,13 @@ urllib3 = ">=1.26.0" [[package]] name = "typer" -version = "0.13.1" +version = "0.15.1" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false python-versions = ">=3.7" files = [ - {file = "typer-0.13.1-py3-none-any.whl", hash = "sha256:5b59580fd925e89463a29d363e0a43245ec02765bde9fb77d39e5d0f29dd7157"}, - {file = "typer-0.13.1.tar.gz", hash = "sha256:9d444cb96cc268ce6f8b94e13b4335084cef4c079998a9f4851a90229a3bd25c"}, + {file = "typer-0.15.1-py3-none-any.whl", hash = "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847"}, + {file = "typer-0.15.1.tar.gz", hash = "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a"}, ] [package.dependencies] @@ -3041,4 +3041,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "8000601d48cfc1b10d0ae18c6046cc59a50cb6c45e6d3ef4775a3203769f2154" +content-hash = "8d908859a32731cfe8ec4d0d855f5643a2d8150f4a2a27b3dd8d4485877862ea" diff --git a/pyproject.toml b/pyproject.toml index 619c4ff47..7c2297a68 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ wrapt = [ {version = ">=1.11.0,<2.0", python = "<3.11"}, ] packaging = ">=23.1,<25.0" -reflex-hosting-cli = ">=0.1.17,<2.0" +reflex-hosting-cli = ">=0.1.28,<2.0" charset-normalizer = ">=3.3.2,<4.0" wheel = ">=0.42.0,<1.0" build = ">=1.0.3,<2.0" diff --git a/reflex/config.py b/reflex/config.py index 88230cefe..1d952f4f0 100644 --- a/reflex/config.py +++ b/reflex/config.py @@ -652,9 +652,9 @@ class Config(Base): frontend_packages: List[str] = [] # The hosting service backend URL. - cp_backend_url: str = Hosting.CP_BACKEND_URL + cp_backend_url: str = Hosting.HOSTING_SERVICE # The hosting service frontend URL. - cp_web_url: str = Hosting.CP_WEB_URL + cp_web_url: str = Hosting.HOSTING_SERVICE_UI # The worker class used in production mode gunicorn_worker_class: str = "uvicorn.workers.UvicornH11Worker" diff --git a/reflex/custom_components/custom_components.py b/reflex/custom_components/custom_components.py index 6be64ae2d..41808d60a 100644 --- a/reflex/custom_components/custom_components.py +++ b/reflex/custom_components/custom_components.py @@ -827,11 +827,11 @@ def _collect_details_for_gallery(): Raises: Exit: If pyproject.toml file is ill-formed or the request to the backend services fails. """ - from reflex.reflex import _login + from reflex_cli.utils import hosting console.rule("[bold]Authentication with Reflex Services") console.print("First let's log in to Reflex backend services.") - access_token = _login() + access_token, _ = hosting.authenticated_token() console.rule("[bold]Custom Component Information") params = {} diff --git a/reflex/reflex.py b/reflex/reflex.py index 0e2b54fcb..26937e763 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -9,8 +9,6 @@ from typing import List, Optional import typer import typer.core -from reflex_cli.deployments import deployments_cli -from reflex_cli.utils import dependency from reflex_cli.v2.deployments import check_version, hosting_cli from reflex import constants @@ -330,41 +328,8 @@ def export( ) -def _login() -> str: - """Helper function to authenticate with Reflex hosting service.""" - from reflex_cli.utils import hosting - - access_token, invitation_code = hosting.authenticated_token() - if access_token: - console.print("You already logged in.") - return access_token - - # If not already logged in, open a browser window/tab to the login page. - access_token = hosting.authenticate_on_browser(invitation_code) - - if not access_token: - console.error("Unable to authenticate. Please try again or contact support.") - raise typer.Exit(1) - - console.print("Successfully logged in.") - return access_token - - @cli.command() -def login( - loglevel: constants.LogLevel = typer.Option( - config.loglevel, help="The log level to use." - ), -): - """Authenticate with Reflex hosting service.""" - # Set the log level. - console.set_log_level(loglevel) - - _login() - - -@cli.command() -def loginv2(loglevel: constants.LogLevel = typer.Option(config.loglevel)): +def login(loglevel: constants.LogLevel = typer.Option(config.loglevel)): """Authenicate with experimental Reflex hosting service.""" from reflex_cli.v2 import cli as hosting_cli @@ -382,26 +347,11 @@ def logout( ), ): """Log out of access to Reflex hosting service.""" - from reflex_cli.utils import hosting - - console.set_log_level(loglevel) - - hosting.log_out_on_browser() - console.debug("Deleting access token from config locally") - hosting.delete_token_from_config(include_invitation_code=True) - - -@cli.command() -def logoutv2( - loglevel: constants.LogLevel = typer.Option( - config.loglevel, help="The log level to use." - ), -): - """Log out of access to Reflex hosting service.""" - from reflex_cli.v2 import cli + from reflex_cli.v2.cli import logout check_version() - cli.logout() + + logout(loglevel) # type: ignore db_cli = typer.Typer() @@ -486,126 +436,6 @@ def makemigrations( @cli.command() def deploy( - key: Optional[str] = typer.Option( - None, - "-k", - "--deployment-key", - help="The name of the deployment. Domain name safe characters only.", - ), - app_name: str = typer.Option( - config.app_name, - "--app-name", - help="The name of the App to deploy under.", - hidden=True, - ), - regions: List[str] = typer.Option( - list(), - "-r", - "--region", - help="The regions to deploy to.", - ), - envs: List[str] = typer.Option( - list(), - "--env", - help="The environment variables to set: =. For multiple envs, repeat this option, e.g. --env k1=v2 --env k2=v2.", - ), - cpus: Optional[int] = typer.Option( - None, help="The number of CPUs to allocate.", hidden=True - ), - memory_mb: Optional[int] = typer.Option( - None, help="The amount of memory to allocate.", hidden=True - ), - auto_start: Optional[bool] = typer.Option( - None, - help="Whether to auto start the instance.", - hidden=True, - ), - auto_stop: Optional[bool] = typer.Option( - None, - help="Whether to auto stop the instance.", - hidden=True, - ), - frontend_hostname: Optional[str] = typer.Option( - None, - "--frontend-hostname", - help="The hostname of the frontend.", - hidden=True, - ), - interactive: bool = typer.Option( - True, - help="Whether to list configuration options and ask for confirmation.", - ), - with_metrics: Optional[str] = typer.Option( - None, - help="Setting for metrics scraping for the deployment. Setup required in user code.", - hidden=True, - ), - with_tracing: Optional[str] = typer.Option( - None, - help="Setting to export tracing for the deployment. Setup required in user code.", - hidden=True, - ), - upload_db_file: bool = typer.Option( - False, - help="Whether to include local sqlite db files when uploading to hosting service.", - hidden=True, - ), - loglevel: constants.LogLevel = typer.Option( - config.loglevel, help="The log level to use." - ), -): - """Deploy the app to the Reflex hosting service.""" - from reflex_cli import cli as hosting_cli - - from reflex.utils import export as export_utils - from reflex.utils import prerequisites - - # Set the log level. - console.set_log_level(loglevel) - - # Only check requirements if interactive. There is user interaction for requirements update. - if interactive: - dependency.check_requirements() - - # Check if we are set up. - if prerequisites.needs_reinit(frontend=True): - _init(name=config.app_name, loglevel=loglevel) - prerequisites.check_latest_package_version(constants.ReflexHostingCLI.MODULE_NAME) - - hosting_cli.deploy( - app_name=app_name, - export_fn=lambda zip_dest_dir, - api_url, - deploy_url, - frontend, - backend, - zipping: export_utils.export( - zip_dest_dir=zip_dest_dir, - api_url=api_url, - deploy_url=deploy_url, - frontend=frontend, - backend=backend, - zipping=zipping, - loglevel=loglevel.subprocess_level(), - upload_db_file=upload_db_file, - ), - key=key, - regions=regions, - envs=envs, - cpus=cpus, - memory_mb=memory_mb, - auto_start=auto_start, - auto_stop=auto_stop, - frontend_hostname=frontend_hostname, - interactive=interactive, - with_metrics=with_metrics, - with_tracing=with_tracing, - loglevel=loglevel.subprocess_level(), - ) - - -@cli.command() -def deployv2( app_name: str = typer.Option( config.app_name, "--app-name", @@ -657,8 +487,8 @@ def deployv2( ), ): """Deploy the app to the Reflex hosting service.""" + from reflex_cli.utils import dependency from reflex_cli.v2 import cli as hosting_cli - from reflex_cli.v2.utils import dependency from reflex.utils import export as export_utils from reflex.utils import prerequisites @@ -702,7 +532,7 @@ def deployv2( envfile=envfile, hostname=hostname, interactive=interactive, - loglevel=loglevel.subprocess_level(), + loglevel=type(loglevel).INFO, # type: ignore token=token, project=project, ) @@ -710,15 +540,10 @@ def deployv2( 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( - deployments_cli, - name="deployments", - help="Subcommands for managing the Deployments.", -) cli.add_typer( hosting_cli, - name="apps", - help="Subcommands for managing the Deployments.", + name="cloud", + help="Subcommands for managing the reflex cloud.", ) cli.add_typer( custom_components_cli, diff --git a/tests/integration/test_dynamic_routes.py b/tests/integration/test_dynamic_routes.py index eed066696..c226a4d8e 100644 --- a/tests/integration/test_dynamic_routes.py +++ b/tests/integration/test_dynamic_routes.py @@ -89,6 +89,11 @@ def DynamicRoute(): @rx.page(route="/arg/[arg_str]") def arg() -> rx.Component: return rx.vstack( + rx.input( + value=DynamicState.router.session.client_token, + read_only=True, + id="token", + ), rx.data_list.root( rx.data_list.item( rx.data_list.label("rx.State.arg_str (dynamic)"), @@ -373,12 +378,14 @@ async def test_on_load_navigate_non_dynamic( async def test_render_dynamic_arg( dynamic_route: AppHarness, driver: WebDriver, + token: str, ): """Assert that dynamic arg var is rendered correctly in different contexts. Args: dynamic_route: harness for DynamicRoute app. driver: WebDriver instance. + token: The token visible in the driver browser. """ assert dynamic_route.app_instance is not None with poll_for_navigation(driver): @@ -398,7 +405,8 @@ async def test_render_dynamic_arg( el = driver.find_element(By.ID, id) assert el assert ( - dynamic_route.poll_for_content(el, exp_not_equal=expect_not) == expected + dynamic_route.poll_for_content(el, timeout=30, exp_not_equal=expect_not) + == expected ) assert_content("0", "") From 3f4dca21a8cdd77e90483902e88c1e1134e8b6b8 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Thu, 5 Dec 2024 01:17:26 -0800 Subject: [PATCH 46/71] rename loginv2 to login (#4486) * rename loginv2 to login * reflex-hosting-cli bump to 0.1.29 * relock deps --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- reflex/reflex.py | 2 +- reflex/utils/prerequisites.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index 74e5755a3..7d46e4199 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2206,13 +2206,13 @@ reflex = ">=0.6.0a" [[package]] name = "reflex-hosting-cli" -version = "0.1.28" +version = "0.1.29" description = "Reflex Hosting CLI" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "reflex_hosting_cli-0.1.28-py3-none-any.whl", hash = "sha256:68c60e8b2cb8856d0b8eac1f06410d8fe192944884f54bfad47adf5db62bd395"}, - {file = "reflex_hosting_cli-0.1.28.tar.gz", hash = "sha256:9b4fb771396ffeba857ada0207fdfd78e2e40b8e35a5486b89cb07f1aa416867"}, + {file = "reflex_hosting_cli-0.1.29-py3-none-any.whl", hash = "sha256:fcbdad829762287f32397cd8a5d46536ab0db396e7fdb8a23c7f9343d7dc8de0"}, + {file = "reflex_hosting_cli-0.1.29.tar.gz", hash = "sha256:7b421fec6936c26549c8c65c9dda34fc042eaaec79b238dce6b9c020f848563b"}, ] [package.dependencies] @@ -3041,4 +3041,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "8d908859a32731cfe8ec4d0d855f5643a2d8150f4a2a27b3dd8d4485877862ea" +content-hash = "3810e99ff4d09952e62d88b2c26651a0d8e0ffe4007bc3274c2fb83b68243951" diff --git a/pyproject.toml b/pyproject.toml index 7c2297a68..b63fad319 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ wrapt = [ {version = ">=1.11.0,<2.0", python = "<3.11"}, ] packaging = ">=23.1,<25.0" -reflex-hosting-cli = ">=0.1.28,<2.0" +reflex-hosting-cli = ">=0.1.29,<2.0" charset-normalizer = ">=3.3.2,<4.0" wheel = ">=0.42.0,<1.0" build = ">=1.0.3,<2.0" diff --git a/reflex/reflex.py b/reflex/reflex.py index 26937e763..f9aea4982 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -337,7 +337,7 @@ def login(loglevel: constants.LogLevel = typer.Option(config.loglevel)): validated_info = hosting_cli.login() if validated_info is not None: - telemetry.send("loginv2", user_uuid=validated_info.get("user_id")) + telemetry.send("login", user_uuid=validated_info.get("user_id")) @cli.command() diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index 559f668a1..cc56bdf88 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -1413,7 +1413,7 @@ def validate_and_create_app_using_remote_template(app_name, template, templates) authenticated_token = hosting.authenticated_token() if not authenticated_token or not authenticated_token[0]: console.print( - f"Please use `reflex loginv2` to access the '{template}' template." + f"Please use `reflex login` to access the '{template}' template." ) raise typer.Exit(3) From 3a225c218006474a2d2e0d866310d36676d82f5e Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Fri, 6 Dec 2024 17:41:53 +0100 Subject: [PATCH 47/71] test dynamic route flakiness (can't reproduce locally) (#4496) * test dynamic route flakiness (can't reproduce locally) * fix typo --- tests/integration/test_dynamic_routes.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/integration/test_dynamic_routes.py b/tests/integration/test_dynamic_routes.py index c226a4d8e..8a3cde3a2 100644 --- a/tests/integration/test_dynamic_routes.py +++ b/tests/integration/test_dynamic_routes.py @@ -2,6 +2,7 @@ from __future__ import annotations +import time from typing import Callable, Coroutine, Generator, Type from urllib.parse import urlsplit @@ -177,6 +178,8 @@ def driver(dynamic_route: AppHarness) -> Generator[WebDriver, None, None]: """ assert dynamic_route.app_instance is not None, "app is not running" driver = dynamic_route.frontend() + # TODO: drop after flakiness is resolved + driver.implicitly_wait(30) try: yield driver finally: @@ -391,6 +394,9 @@ async def test_render_dynamic_arg( with poll_for_navigation(driver): driver.get(f"{dynamic_route.frontend_url}/arg/0") + # TODO: drop after flakiness is resolved + time.sleep(3) + def assert_content(expected: str, expect_not: str): ids = [ "state-arg_str", From a895eaaede10e99189cce9c6fcda995459eaa6be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Fri, 6 Dec 2024 13:16:21 -0800 Subject: [PATCH 48/71] fix non-interactive flag in deploy command (#4498) --- reflex/reflex.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/reflex/reflex.py b/reflex/reflex.py index f9aea4982..bad2ecb28 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -497,8 +497,13 @@ def deploy( # Set the log level. console.set_log_level(loglevel) - # make sure user is logged in. - hosting_cli.login() + + if not token: + # make sure user is logged in. + if interactive: + hosting_cli.login() + else: + raise SystemExit("Token is required for non-interactive mode.") # Only check requirements if interactive. # There is user interaction for requirements update. From 3d89d74bdcd5afb85408ebb67a672701579f4efc Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Mon, 9 Dec 2024 10:00:01 +0100 Subject: [PATCH 49/71] only mark backend vars as dirty if they have changed (#4494) --- reflex/state.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/reflex/state.py b/reflex/state.py index 55f29cf45..f38b9c863 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -1288,6 +1288,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): return if name in self.backend_vars: + # abort if unchanged + if self._backend_vars.get(name) == value: + return self._backend_vars.__setitem__(name, value) self.dirty_vars.add(name) self._mark_dirty() From 9ff386bf488fb670e5438123ffb9db8b05b2b629 Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Tue, 10 Dec 2024 00:17:51 +0100 Subject: [PATCH 50/71] add __repr__ method to MutableProxy (#4506) --- reflex/state.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/reflex/state.py b/reflex/state.py index f38b9c863..e90c62bb8 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -3599,6 +3599,14 @@ class MutableProxy(wrapt.ObjectProxy): self._self_state = state self._self_field_name = field_name + def __repr__(self) -> str: + """Get the representation of the wrapped object. + + Returns: + The representation of the wrapped object. + """ + return f"{self.__class__.__name__}({self.__wrapped__})" + def _mark_dirty( self, wrapped=None, From 0a34949019f3aaab9b624b13dc401435c2caf802 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Mon, 9 Dec 2024 15:26:48 -0800 Subject: [PATCH 51/71] Add production-one-port example (#4489) * Add production-one-port example A more complex version of simple-one-port that facilitates better layer caching to shorten build times and multi-stage build to reduce final image size. Harder to understand, but ultimately nicer to use. * fix Caddyfile format to avoid complaints * docker-examples: bump all base images to python:3.13 --- .../production-app-platform/Dockerfile | 4 +- docker-example/production-compose/Dockerfile | 4 +- .../production-one-port/.dockerignore | 3 + docker-example/production-one-port/Caddyfile | 14 +++++ docker-example/production-one-port/Dockerfile | 62 +++++++++++++++++++ docker-example/production-one-port/README.md | 37 +++++++++++ docker-example/simple-one-port/Caddyfile | 2 +- docker-example/simple-one-port/Dockerfile | 4 +- docker-example/simple-two-port/Dockerfile | 2 +- 9 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 docker-example/production-one-port/.dockerignore create mode 100644 docker-example/production-one-port/Caddyfile create mode 100644 docker-example/production-one-port/Dockerfile create mode 100644 docker-example/production-one-port/README.md diff --git a/docker-example/production-app-platform/Dockerfile b/docker-example/production-app-platform/Dockerfile index 3dd9f1fed..fec3b13f1 100644 --- a/docker-example/production-app-platform/Dockerfile +++ b/docker-example/production-app-platform/Dockerfile @@ -23,7 +23,7 @@ # for example, pass `docker build --platform=linux/amd64 ...` # Stage 1: init -FROM python:3.11 as init +FROM python:3.13 as init ARG uv=/root/.local/bin/uv @@ -48,7 +48,7 @@ RUN $uv pip install -r requirements.txt RUN reflex init # Stage 2: copy artifacts into slim image -FROM python:3.11-slim +FROM python:3.13-slim WORKDIR /app RUN adduser --disabled-password --home /app reflex COPY --chown=reflex --from=init /app /app diff --git a/docker-example/production-compose/Dockerfile b/docker-example/production-compose/Dockerfile index 42345af40..757c03b8e 100644 --- a/docker-example/production-compose/Dockerfile +++ b/docker-example/production-compose/Dockerfile @@ -2,7 +2,7 @@ # instance of a Reflex app. # Stage 1: init -FROM python:3.11 as init +FROM python:3.13 as init ARG uv=/root/.local/bin/uv @@ -35,7 +35,7 @@ RUN rm -rf .web && mkdir .web RUN mv /tmp/_static .web/_static # Stage 2: copy artifacts into slim image -FROM python:3.11-slim +FROM python:3.13-slim WORKDIR /app RUN adduser --disabled-password --home /app reflex COPY --chown=reflex --from=init /app /app diff --git a/docker-example/production-one-port/.dockerignore b/docker-example/production-one-port/.dockerignore new file mode 100644 index 000000000..26ae41b83 --- /dev/null +++ b/docker-example/production-one-port/.dockerignore @@ -0,0 +1,3 @@ +.web +!.web/bun.lockb +!.web/package.json diff --git a/docker-example/production-one-port/Caddyfile b/docker-example/production-one-port/Caddyfile new file mode 100644 index 000000000..28fb01861 --- /dev/null +++ b/docker-example/production-one-port/Caddyfile @@ -0,0 +1,14 @@ +:{$PORT} + +encode gzip + +@backend_routes path /_event/* /ping /_upload /_upload/* +handle @backend_routes { + reverse_proxy localhost:8000 +} + +root * /srv +route { + try_files {path} {path}/ /404.html + file_server +} diff --git a/docker-example/production-one-port/Dockerfile b/docker-example/production-one-port/Dockerfile new file mode 100644 index 000000000..f5e157bae --- /dev/null +++ b/docker-example/production-one-port/Dockerfile @@ -0,0 +1,62 @@ +# This Dockerfile is used to deploy a single-container Reflex app instance +# to services like Render, Railway, Heroku, GCP, and others. + +# If the service expects a different port, provide it here (f.e Render expects port 10000) +ARG PORT=8080 +# Only set for local/direct access. When TLS is used, the API_URL is assumed to be the same as the frontend. +ARG API_URL + +# It uses a reverse proxy to serve the frontend statically and proxy to backend +# from a single exposed port, expecting TLS termination to be handled at the +# edge by the given platform. +FROM python:3.13 as builder + +RUN mkdir -p /app/.web +RUN python -m venv /app/.venv +ENV PATH="/app/.venv/bin:$PATH" + +WORKDIR /app + +# Install python app requirements and reflex in the container +COPY requirements.txt . +RUN pip install -r requirements.txt + +# Install reflex helper utilities like bun/fnm/node +COPY rxconfig.py ./ +RUN reflex init + +# Install pre-cached frontend dependencies (if exist) +COPY *.web/bun.lockb *.web/package.json .web/ +RUN if [ -f .web/bun.lockb ]; then cd .web && ~/.local/share/reflex/bun/bin/bun install --frozen-lockfile; fi + +# Copy local context to `/app` inside container (see .dockerignore) +COPY . . + +ARG PORT API_URL +# Download other npm dependencies and compile frontend +RUN API_URL=${API_URL:-http://localhost:$PORT} reflex export --loglevel debug --frontend-only --no-zip && mv .web/_static/* /srv/ && rm -rf .web + + +# Final image with only necessary files +FROM python:3.13-slim + +# Install Caddy and redis server inside image +RUN apt-get update -y && apt-get install -y caddy redis-server && rm -rf /var/lib/apt/lists/* + +ARG PORT API_URL +ENV PATH="/app/.venv/bin:$PATH" PORT=$PORT API_URL=${API_URL:-http://localhost:$PORT} REDIS_URL=redis://localhost PYTHONUNBUFFERED=1 + +WORKDIR /app +COPY --from=builder /app /app +COPY --from=builder /srv /srv + +# Needed until Reflex properly passes SIGTERM on backend. +STOPSIGNAL SIGKILL + +EXPOSE $PORT + +# Apply migrations before starting the backend. +CMD [ -d alembic ] && reflex db migrate; \ + caddy start && \ + redis-server --daemonize yes && \ + exec reflex run --env prod --backend-only diff --git a/docker-example/production-one-port/README.md b/docker-example/production-one-port/README.md new file mode 100644 index 000000000..f6f76620a --- /dev/null +++ b/docker-example/production-one-port/README.md @@ -0,0 +1,37 @@ +# production-one-port + +This docker deployment runs Reflex in prod mode, exposing a single HTTP port: + * `8080` (`$PORT`) - Caddy server hosting the frontend statically and proxying requests to the backend. + +The deployment also runs a local Redis server to store state for each user. + +Conceptually it is similar to the `simple-one-port` example except it: + * has layer caching for python, reflex, and node dependencies + * uses multi-stage build to reduce the size of the final image + +Using this method may be preferable for deploying in memory constrained +environments, because it serves a static frontend export, rather than running +the NextJS server via node. + +## Build + +```console +docker build -t reflex-production-one-port . +``` + +## Run + +```console +docker run -p 8080:8080 reflex-production-one-port +``` + +Note that this container has _no persistence_ and will lose all data when +stopped. You can use bind mounts or named volumes to persist the database and +uploaded_files directories as needed. + +## Usage + +This container should be used with an existing load balancer or reverse proxy to +terminate TLS. + +It is also useful for deploying to simple app platforms, such as Render or Heroku. \ No newline at end of file diff --git a/docker-example/simple-one-port/Caddyfile b/docker-example/simple-one-port/Caddyfile index 13d94ce8e..28fb01861 100644 --- a/docker-example/simple-one-port/Caddyfile +++ b/docker-example/simple-one-port/Caddyfile @@ -11,4 +11,4 @@ root * /srv route { try_files {path} {path}/ /404.html file_server -} \ No newline at end of file +} diff --git a/docker-example/simple-one-port/Dockerfile b/docker-example/simple-one-port/Dockerfile index 4cd7e9a18..0b6dba0c4 100644 --- a/docker-example/simple-one-port/Dockerfile +++ b/docker-example/simple-one-port/Dockerfile @@ -4,7 +4,7 @@ # It uses a reverse proxy to serve the frontend statically and proxy to backend # from a single exposed port, expecting TLS termination to be handled at the # edge by the given platform. -FROM python:3.11 +FROM python:3.13 # If the service expects a different port, provide it here (f.e Render expects port 10000) ARG PORT=8080 @@ -38,4 +38,4 @@ EXPOSE $PORT CMD [ -d alembic ] && reflex db migrate; \ caddy start && \ redis-server --daemonize yes && \ - exec reflex run --env prod --backend-only \ No newline at end of file + exec reflex run --env prod --backend-only diff --git a/docker-example/simple-two-port/Dockerfile b/docker-example/simple-two-port/Dockerfile index 288f605a8..6d69fa390 100644 --- a/docker-example/simple-two-port/Dockerfile +++ b/docker-example/simple-two-port/Dockerfile @@ -1,5 +1,5 @@ # This Dockerfile is used to deploy a simple single-container Reflex app instance. -FROM python:3.12 +FROM python:3.13 RUN apt-get update && apt-get install -y redis-server && rm -rf /var/lib/apt/lists/* ENV REDIS_URL=redis://localhost PYTHONUNBUFFERED=1 From a68eef23aab3c65d9071ce8b6b826360f46bd3bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Tue, 10 Dec 2024 06:37:58 -0800 Subject: [PATCH 52/71] add issues templates (#4455) * add issues templates * fix typo --- .github/ISSUE_TEMPLATE/enhancement_request.md | 19 +++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/enhancement_request.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/enhancement_request.md b/.github/ISSUE_TEMPLATE/enhancement_request.md new file mode 100644 index 000000000..409524feb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement_request.md @@ -0,0 +1,19 @@ +--- +name: Enhancement Request +about: Suggest an enhancement for an existing Reflex feature. +title: '' +labels: 'enhancement' +assignees: '' +--- + +**Describe the Enhancement you want** +A clear and concise description of what the improvement does. + +- Which feature do you want to improve? (and what problem does it have) + +- What is the benefit of the enhancement? + +- Show an example/usecase were the improvement are needed. + +**Additional context** +Add any other context here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..7e217d83a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,18 @@ +--- +name: Feature Request +about: Suggest a new feature for Reflex +title: '' +labels: 'feature request' +assignees: '' + +--- + +**Describe the Features** +A clear and concise description of what the features does. + +- What is the purpose of the feature? + +- Show an example / use cases for the new feature. + +**Additional context** +Add any other context here. From 4ecb0b81ce8d68112ab2c6c1c09699b9cb1ae57a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Tue, 10 Dec 2024 09:11:50 -0800 Subject: [PATCH 53/71] enable RUF rules for linting (#4465) --- pyproject.toml | 4 +-- reflex/components/base/bare.py | 4 +-- reflex/components/component.py | 8 +++-- reflex/components/core/banner.py | 4 +-- reflex/components/core/clipboard.py | 2 +- reflex/components/core/cond.py | 2 +- reflex/components/core/foreach.py | 2 +- reflex/components/core/upload.py | 10 +++---- reflex/components/datadisplay/code.py | 10 +++---- reflex/components/datadisplay/dataeditor.py | 6 ++-- reflex/components/dynamic.py | 4 +-- reflex/components/el/elements/forms.py | 14 +++++---- reflex/components/el/elements/metadata.py | 10 +++---- reflex/components/el/elements/sectioning.py | 30 +++++++++---------- reflex/components/markdown/markdown.py | 6 ++-- reflex/components/plotly/plotly.py | 4 +-- .../components/radix/primitives/accordion.py | 3 +- .../radix/themes/components/radio_group.py | 6 ++-- reflex/components/sonner/toast.py | 4 +-- reflex/event.py | 2 +- reflex/experimental/client_state.py | 2 +- reflex/state.py | 2 +- reflex/style.py | 2 +- reflex/testing.py | 2 +- reflex/utils/exec.py | 10 +++---- reflex/utils/format.py | 10 +++---- reflex/utils/prerequisites.py | 18 ++++++----- reflex/utils/processes.py | 2 +- reflex/utils/pyi_generator.py | 2 +- reflex/utils/types.py | 2 +- reflex/vars/base.py | 12 ++++---- reflex/vars/function.py | 2 +- reflex/vars/object.py | 8 ++--- reflex/vars/sequence.py | 10 +++---- tests/integration/test_call_script.py | 8 ++--- .../tests_playwright/test_table.py | 3 +- tests/units/components/core/test_colors.py | 22 +++++++------- tests/units/components/core/test_cond.py | 2 +- tests/units/components/core/test_debounce.py | 2 +- tests/units/components/core/test_html.py | 4 +-- tests/units/components/test_component.py | 3 +- tests/units/test_app.py | 17 ++++++----- tests/units/test_event.py | 2 +- tests/units/test_state.py | 20 ++++++------- tests/units/test_var.py | 2 +- tests/units/utils/test_types.py | 2 +- 46 files changed, 156 insertions(+), 150 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b63fad319..f57c4069f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,8 +93,8 @@ build-backend = "poetry.core.masonry.api" [tool.ruff] target-version = "py39" lint.isort.split-on-trailing-comma = false -lint.select = ["B", "D", "E", "F", "I", "SIM", "W"] -lint.ignore = ["B008", "D205", "E501", "F403", "SIM115"] +lint.select = ["B", "D", "E", "F", "I", "SIM", "W", "RUF"] +lint.ignore = ["B008", "D205", "E501", "F403", "SIM115", "RUF006", "RUF012"] lint.pydocstyle.convention = "google" [tool.ruff.lint.per-file-ignores] diff --git a/reflex/components/base/bare.py b/reflex/components/base/bare.py index c70b4c844..e1b5d9237 100644 --- a/reflex/components/base/bare.py +++ b/reflex/components/base/bare.py @@ -103,8 +103,8 @@ class Bare(Component): def _render(self) -> Tag: if isinstance(self.contents, Var): if isinstance(self.contents, (BooleanVar, ObjectVar)): - return Tagless(contents=f"{{{str(self.contents.to_string())}}}") - return Tagless(contents=f"{{{str(self.contents)}}}") + return Tagless(contents=f"{{{self.contents.to_string()!s}}}") + return Tagless(contents=f"{{{self.contents!s}}}") return Tagless(contents=str(self.contents)) def _get_vars(self, include_children: bool = False) -> Iterator[Var]: diff --git a/reflex/components/component.py b/reflex/components/component.py index 18dedbf0e..5c1c4941d 100644 --- a/reflex/components/component.py +++ b/reflex/components/component.py @@ -583,7 +583,7 @@ class Component(BaseComponent, ABC): return self._create_event_chain(args_spec, value.guess_type(), key=key) else: raise ValueError( - f"Invalid event chain: {str(value)} of type {value._var_type}" + f"Invalid event chain: {value!s} of type {value._var_type}" ) elif isinstance(value, EventChain): # Trust that the caller knows what they're doing passing an EventChain directly @@ -1111,7 +1111,7 @@ class Component(BaseComponent, ABC): vars.append(prop_var) # Style keeps track of its own VarData instance, so embed in a temp Var that is yielded. - if isinstance(self.style, dict) and self.style or isinstance(self.style, Var): + if (isinstance(self.style, dict) and self.style) or isinstance(self.style, Var): vars.append( Var( _js_expr="style", @@ -1466,7 +1466,9 @@ class Component(BaseComponent, ABC): """ ref = self.get_ref() if ref is not None: - return f"const {ref} = useRef(null); {str(Var(_js_expr=ref)._as_ref())} = {ref};" + return ( + f"const {ref} = useRef(null); {Var(_js_expr=ref)._as_ref()!s} = {ref};" + ) def _get_vars_hooks(self) -> dict[str, None]: """Get the hooks required by vars referenced in this component. diff --git a/reflex/components/core/banner.py b/reflex/components/core/banner.py index f6abbab90..a5553800d 100644 --- a/reflex/components/core/banner.py +++ b/reflex/components/core/banner.py @@ -109,7 +109,7 @@ class ConnectionToaster(Toaster): ) individual_hooks = [ - f"const toast_props = {str(LiteralVar.create(props))};", + f"const toast_props = {LiteralVar.create(props)!s};", "const [userDismissed, setUserDismissed] = useState(false);", FunctionStringVar( "useEffect", @@ -124,7 +124,7 @@ class ConnectionToaster(Toaster): Var( _js_expr=f""" () => {{ - if ({str(has_too_many_connection_errors)}) {{ + if ({has_too_many_connection_errors!s}) {{ if (!userDismissed) {{ toast.error( `Cannot connect to server: ${{{connection_error}}}.`, diff --git a/reflex/components/core/clipboard.py b/reflex/components/core/clipboard.py index 6d6a38acc..938cd13c0 100644 --- a/reflex/components/core/clipboard.py +++ b/reflex/components/core/clipboard.py @@ -51,7 +51,7 @@ class Clipboard(Fragment): return super().create(*children, **props) def _exclude_props(self) -> list[str]: - return super()._exclude_props() + ["on_paste", "on_paste_event_actions"] + return [*super()._exclude_props(), "on_paste", "on_paste_event_actions"] def _render(self) -> Tag: tag = super()._render() diff --git a/reflex/components/core/cond.py b/reflex/components/core/cond.py index 5b6ee2a7f..b75667890 100644 --- a/reflex/components/core/cond.py +++ b/reflex/components/core/cond.py @@ -94,7 +94,7 @@ class Cond(MemoizationLeaf): ).set( props=tag.format_props(), ), - cond_state=f"isTrue({str(self.cond)})", + cond_state=f"isTrue({self.cond!s})", ) def add_imports(self) -> ImportDict: diff --git a/reflex/components/core/foreach.py b/reflex/components/core/foreach.py index a3f97d594..c9fbe5bc5 100644 --- a/reflex/components/core/foreach.py +++ b/reflex/components/core/foreach.py @@ -54,7 +54,7 @@ class Foreach(Component): iterable = LiteralVar.create(iterable) if iterable._var_type == Any: raise ForeachVarError( - f"Could not foreach over var `{str(iterable)}` of type Any. " + f"Could not foreach over var `{iterable!s}` of type Any. " "(If you are trying to foreach over a state var, add a type annotation to the var). " "See https://reflex.dev/docs/library/dynamic-rendering/foreach/" ) diff --git a/reflex/components/core/upload.py b/reflex/components/core/upload.py index 87488d98a..b5b701d6d 100644 --- a/reflex/components/core/upload.py +++ b/reflex/components/core/upload.py @@ -61,7 +61,7 @@ def upload_file(id_: str = DEFAULT_UPLOAD_ID) -> Var: id_var = LiteralStringVar.create(id_) var_name = f"""e => setFilesById(filesById => {{ const updatedFilesById = Object.assign({{}}, filesById); - updatedFilesById[{str(id_var)}] = e; + updatedFilesById[{id_var!s}] = e; return updatedFilesById; }}) """ @@ -87,7 +87,7 @@ def selected_files(id_: str = DEFAULT_UPLOAD_ID) -> Var: """ id_var = LiteralStringVar.create(id_) return Var( - _js_expr=f"(filesById[{str(id_var)}] ? filesById[{str(id_var)}].map((f) => (f.path || f.name)) : [])", + _js_expr=f"(filesById[{id_var!s}] ? filesById[{id_var!s}].map((f) => (f.path || f.name)) : [])", _var_type=List[str], _var_data=VarData.merge( upload_files_context_var_data, id_var._get_all_var_data() @@ -120,9 +120,7 @@ def cancel_upload(upload_id: str) -> EventSpec: Returns: An event spec that cancels the upload when triggered. """ - return run_script( - f"upload_controllers[{str(LiteralVar.create(upload_id))}]?.abort()" - ) + return run_script(f"upload_controllers[{LiteralVar.create(upload_id)!s}]?.abort()") def get_upload_dir() -> Path: @@ -301,7 +299,7 @@ class Upload(MemoizationLeaf): ) left_side = f"const {{getRootProps: {root_props_unique_name}, getInputProps: {input_props_unique_name}}} " - right_side = f"useDropzone({str(use_dropzone_arguments)})" + right_side = f"useDropzone({use_dropzone_arguments!s})" var_data = VarData.merge( VarData( diff --git a/reflex/components/datadisplay/code.py b/reflex/components/datadisplay/code.py index b514bc888..195aa6b66 100644 --- a/reflex/components/datadisplay/code.py +++ b/reflex/components/datadisplay/code.py @@ -519,13 +519,13 @@ class CodeBlock(Component, MarkdownComponentMap): The hook to register the language. """ return f""" - if ({str(_LANGUAGE)}) {{ + if ({_LANGUAGE!s}) {{ (async () => {{ try {{ - const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${{{str(_LANGUAGE)}}}`); - SyntaxHighlighter.registerLanguage({str(_LANGUAGE)}, module.default); + const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${{{_LANGUAGE!s}}}`); + SyntaxHighlighter.registerLanguage({_LANGUAGE!s}, module.default); }} catch (error) {{ - console.error(`Error importing language module for ${{{str(_LANGUAGE)}}}:`, error); + console.error(`Error importing language module for ${{{_LANGUAGE!s}}}:`, error); }} }})(); }} @@ -547,7 +547,7 @@ class CodeBlock(Component, MarkdownComponentMap): The hooks for the component. """ return [ - f"const {str(_LANGUAGE)} = {str(self.language)}", + f"const {_LANGUAGE!s} = {self.language!s}", self._get_language_registration_hook(), ] diff --git a/reflex/components/datadisplay/dataeditor.py b/reflex/components/datadisplay/dataeditor.py index e3f0b7117..93352c291 100644 --- a/reflex/components/datadisplay/dataeditor.py +++ b/reflex/components/datadisplay/dataeditor.py @@ -406,10 +406,8 @@ class DataEditor(NoSSRComponent): props["rows"] = data.length() if isinstance(data, Var) else len(data) if not isinstance(columns, Var) and len(columns): - if ( - types.is_dataframe(type(data)) - or isinstance(data, Var) - and types.is_dataframe(data._var_type) + if types.is_dataframe(type(data)) or ( + isinstance(data, Var) and types.is_dataframe(data._var_type) ): raise ValueError( "Cannot pass in both a pandas dataframe and columns to the data_editor component." diff --git a/reflex/components/dynamic.py b/reflex/components/dynamic.py index ce59c3f30..fbfc55f97 100644 --- a/reflex/components/dynamic.py +++ b/reflex/components/dynamic.py @@ -173,7 +173,7 @@ def load_dynamic_serializer(): f"const [{unique_var_name}, set_{unique_var_name}] = useState(null);": None, "useEffect(() => {" "let isMounted = true;" - f"evalReactComponent({str(js_string)})" + f"evalReactComponent({js_string!s})" ".then((component) => {" "if (isMounted) {" f"set_{unique_var_name}(component);" @@ -183,7 +183,7 @@ def load_dynamic_serializer(): "isMounted = false;" "};" "}" - f", [{str(js_string)}]);": None, + f", [{js_string!s}]);": None, }, ), ), diff --git a/reflex/components/el/elements/forms.py b/reflex/components/el/elements/forms.py index 56dab5c7f..a82d6bcdd 100644 --- a/reflex/components/el/elements/forms.py +++ b/reflex/components/el/elements/forms.py @@ -241,13 +241,13 @@ class Form(BaseHTML): if ref.startswith("refs_"): ref_var = Var(_js_expr=ref[:-3])._as_ref() form_refs[ref[len("refs_") : -3]] = Var( - _js_expr=f"getRefValues({str(ref_var)})", + _js_expr=f"getRefValues({ref_var!s})", _var_data=VarData.merge(ref_var._get_all_var_data()), ) else: ref_var = Var(_js_expr=ref)._as_ref() form_refs[ref[4:]] = Var( - _js_expr=f"getRefValue({str(ref_var)})", + _js_expr=f"getRefValue({ref_var!s})", _var_data=VarData.merge(ref_var._get_all_var_data()), ) # print(repr(form_refs)) @@ -258,7 +258,8 @@ class Form(BaseHTML): yield from self._get_form_refs().values() def _exclude_props(self) -> list[str]: - return super()._exclude_props() + [ + return [ + *super()._exclude_props(), "reset_on_submit", "handle_submit_unique_name", ] @@ -652,19 +653,20 @@ class Textarea(BaseHTML): "Cannot combine `enter_key_submit` with `on_key_down`.", ) custom_attrs["on_key_down"] = Var( - _js_expr=f"(e) => enterKeySubmitOnKeyDown(e, {str(enter_key_submit)})", + _js_expr=f"(e) => enterKeySubmitOnKeyDown(e, {enter_key_submit!s})", _var_data=VarData.merge(enter_key_submit._get_all_var_data()), ) if auto_height is not None: auto_height = Var.create(auto_height) custom_attrs["on_input"] = Var( - _js_expr=f"(e) => autoHeightOnInput(e, {str(auto_height)})", + _js_expr=f"(e) => autoHeightOnInput(e, {auto_height!s})", _var_data=VarData.merge(auto_height._get_all_var_data()), ) return super().create(*children, **props) def _exclude_props(self) -> list[str]: - return super()._exclude_props() + [ + return [ + *super()._exclude_props(), "auto_height", "enter_key_submit", ] diff --git a/reflex/components/el/elements/metadata.py b/reflex/components/el/elements/metadata.py index 983a8f3a0..94c1e8faa 100644 --- a/reflex/components/el/elements/metadata.py +++ b/reflex/components/el/elements/metadata.py @@ -8,7 +8,7 @@ from reflex.vars.base import Var from .base import BaseHTML -class Base(BaseHTML): # noqa: E742 +class Base(BaseHTML): """Display the base element.""" tag = "base" @@ -18,13 +18,13 @@ class Base(BaseHTML): # noqa: E742 target: Var[Union[str, int, bool]] -class Head(BaseHTML): # noqa: E742 +class Head(BaseHTML): """Display the head element.""" tag = "head" -class Link(BaseHTML): # noqa: E742 +class Link(BaseHTML): """Display the link element.""" tag = "link" @@ -75,14 +75,14 @@ class Meta(BaseHTML): # Inherits common attributes from BaseHTML name: Var[Union[str, int, bool]] -class Title(Element): # noqa: E742 +class Title(Element): """Display the title element.""" tag = "title" # Had to be named with an underscore so it doesnt conflict with reflex.style Style in pyi -class StyleEl(Element): # noqa: E742 +class StyleEl(Element): """Display the style element.""" tag = "style" diff --git a/reflex/components/el/elements/sectioning.py b/reflex/components/el/elements/sectioning.py index 6aea8c1e3..e74d7929c 100644 --- a/reflex/components/el/elements/sectioning.py +++ b/reflex/components/el/elements/sectioning.py @@ -3,91 +3,91 @@ from .base import BaseHTML -class Body(BaseHTML): # noqa: E742 +class Body(BaseHTML): """Display the body element.""" tag = "body" -class Address(BaseHTML): # noqa: E742 +class Address(BaseHTML): """Display the address element.""" tag = "address" -class Article(BaseHTML): # noqa: E742 +class Article(BaseHTML): """Display the article element.""" tag = "article" -class Aside(BaseHTML): # noqa: E742 +class Aside(BaseHTML): """Display the aside element.""" tag = "aside" -class Footer(BaseHTML): # noqa: E742 +class Footer(BaseHTML): """Display the footer element.""" tag = "footer" -class Header(BaseHTML): # noqa: E742 +class Header(BaseHTML): """Display the header element.""" tag = "header" -class H1(BaseHTML): # noqa: E742 +class H1(BaseHTML): """Display the h1 element.""" tag = "h1" -class H2(BaseHTML): # noqa: E742 +class H2(BaseHTML): """Display the h1 element.""" tag = "h2" -class H3(BaseHTML): # noqa: E742 +class H3(BaseHTML): """Display the h1 element.""" tag = "h3" -class H4(BaseHTML): # noqa: E742 +class H4(BaseHTML): """Display the h1 element.""" tag = "h4" -class H5(BaseHTML): # noqa: E742 +class H5(BaseHTML): """Display the h1 element.""" tag = "h5" -class H6(BaseHTML): # noqa: E742 +class H6(BaseHTML): """Display the h1 element.""" tag = "h6" -class Main(BaseHTML): # noqa: E742 +class Main(BaseHTML): """Display the main element.""" tag = "main" -class Nav(BaseHTML): # noqa: E742 +class Nav(BaseHTML): """Display the nav element.""" tag = "nav" -class Section(BaseHTML): # noqa: E742 +class Section(BaseHTML): """Display the section element.""" tag = "section" diff --git a/reflex/components/markdown/markdown.py b/reflex/components/markdown/markdown.py index 376cb8bd6..cd82d5903 100644 --- a/reflex/components/markdown/markdown.py +++ b/reflex/components/markdown/markdown.py @@ -283,7 +283,7 @@ class Markdown(Component): # Format the code to handle inline and block code. formatted_code = f""" const match = (className || '').match(/language-(?.*)/); -const {str(_LANGUAGE)} = match ? match[1] : ''; +const {_LANGUAGE!s} = match ? match[1] : ''; {codeblock_custom_code}; return inline ? ( {self.format_component("code")} @@ -340,7 +340,7 @@ const {str(_LANGUAGE)} = match ? match[1] : ''; # If the children are set as a prop, don't pass them as children. children_prop = props.pop("children", None) if children_prop is not None: - special_props.append(Var(_js_expr=f"children={{{str(children_prop)}}}")) + special_props.append(Var(_js_expr=f"children={{{children_prop!s}}}")) children = [] # Get the component. component = self.component_map[tag](*children, **props).set( @@ -429,7 +429,7 @@ const {str(_LANGUAGE)} = match ? match[1] : ''; function {self._get_component_map_name()} () {{ {formatted_hooks} return ( - {str(LiteralVar.create(self.format_component_map()))} + {LiteralVar.create(self.format_component_map())!s} ) }} """ diff --git a/reflex/components/plotly/plotly.py b/reflex/components/plotly/plotly.py index 2c0dccd3e..d69070ed3 100644 --- a/reflex/components/plotly/plotly.py +++ b/reflex/components/plotly/plotly.py @@ -270,11 +270,11 @@ const extractPoints = (points) => { tag.special_props.append( # Merge all dictionaries and spread the result over props. Var( - _js_expr=f"{{...mergician({str(figure)}," + _js_expr=f"{{...mergician({figure!s}," f"{','.join(str(md) for md in merge_dicts)})}}", ), ) else: # Spread the figure dict over props, nothing to merge. - tag.special_props.append(Var(_js_expr=f"{{...{str(figure)}}}")) + tag.special_props.append(Var(_js_expr=f"{{...{figure!s}}}")) return tag diff --git a/reflex/components/radix/primitives/accordion.py b/reflex/components/radix/primitives/accordion.py index 608fee69d..0ba618e21 100644 --- a/reflex/components/radix/primitives/accordion.py +++ b/reflex/components/radix/primitives/accordion.py @@ -129,7 +129,8 @@ class AccordionRoot(AccordionComponent): on_value_change: EventHandler[on_value_change] def _exclude_props(self) -> list[str]: - return super()._exclude_props() + [ + return [ + *super()._exclude_props(), "radius", "duration", "easing", diff --git a/reflex/components/radix/themes/components/radio_group.py b/reflex/components/radix/themes/components/radio_group.py index dc9c11f5a..80b3ee10c 100644 --- a/reflex/components/radix/themes/components/radio_group.py +++ b/reflex/components/radix/themes/components/radio_group.py @@ -140,10 +140,8 @@ class HighLevelRadioGroup(RadixThemesComponent): color_scheme = props.pop("color_scheme", None) default_value = props.pop("default_value", "") - if ( - not isinstance(items, (list, Var)) - or isinstance(items, Var) - and not types._issubclass(items._var_type, list) + if not isinstance(items, (list, Var)) or ( + isinstance(items, Var) and not types._issubclass(items._var_type, list) ): items_type = type(items) if not isinstance(items, Var) else items._var_type raise TypeError( diff --git a/reflex/components/sonner/toast.py b/reflex/components/sonner/toast.py index 8f5362dba..14694e6ad 100644 --- a/reflex/components/sonner/toast.py +++ b/reflex/components/sonner/toast.py @@ -64,7 +64,7 @@ def _toast_callback_signature(toast: Var) -> list[Var]: """ return [ Var( - _js_expr=f"(() => {{let {{action, cancel, onDismiss, onAutoClose, ...rest}} = {str(toast)}; return rest}})()" + _js_expr=f"(() => {{let {{action, cancel, onDismiss, onAutoClose, ...rest}} = {toast!s}; return rest}})()" ) ] @@ -338,7 +338,7 @@ class Toaster(Component): dismiss_var_data = None if isinstance(id, Var): - dismiss = f"{toast_ref}.dismiss({str(id)})" + dismiss = f"{toast_ref}.dismiss({id!s})" dismiss_var_data = id._get_all_var_data() elif isinstance(id, str): dismiss = f"{toast_ref}.dismiss('{id}')" diff --git a/reflex/event.py b/reflex/event.py index 624bc1728..3022de556 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -447,7 +447,7 @@ class JavascriptHTMLInputElement: class JavascriptInputEvent: """Interface for a Javascript InputEvent https://developer.mozilla.org/en-US/docs/Web/API/InputEvent.""" - target: JavascriptHTMLInputElement = JavascriptHTMLInputElement() + target: JavascriptHTMLInputElement = JavascriptHTMLInputElement() # noqa: RUF009 @dataclasses.dataclass( diff --git a/reflex/experimental/client_state.py b/reflex/experimental/client_state.py index a1abce3ea..6e9f9958d 100644 --- a/reflex/experimental/client_state.py +++ b/reflex/experimental/client_state.py @@ -106,7 +106,7 @@ class ClientStateVar(Var): default_var = default setter_name = f"set{var_name.capitalize()}" hooks = { - f"const [{var_name}, {setter_name}] = useState({str(default_var)})": None, + f"const [{var_name}, {setter_name}] = useState({default_var!s})": None, } imports = { "react": [ImportVar(tag="useState")], diff --git a/reflex/state.py b/reflex/state.py index e90c62bb8..c86bd9a1b 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -436,7 +436,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): """ return [ v - for mixin in cls._mixins() + [cls] + for mixin in [*cls._mixins(), cls] for name, v in mixin.__dict__.items() if is_computed_var(v) and name not in cls.inherited_vars ] diff --git a/reflex/style.py b/reflex/style.py index f0ee8c6a7..642d126ca 100644 --- a/reflex/style.py +++ b/reflex/style.py @@ -74,7 +74,7 @@ def set_color_mode( new_color_mode = LiteralVar.create(new_color_mode) return Var( - f"() => {str(base_setter)}({str(new_color_mode)})", + f"() => {base_setter!s}({new_color_mode!s})", _var_data=VarData.merge( base_setter._get_all_var_data(), new_color_mode._get_all_var_data() ), diff --git a/reflex/testing.py b/reflex/testing.py index 9ddb03504..319be7cba 100644 --- a/reflex/testing.py +++ b/reflex/testing.py @@ -879,7 +879,7 @@ class Subdir404TCPServer(socketserver.TCPServer): Args: request: the requesting socket - client_address: (host, port) referring to the client’s address. + client_address: (host, port) referring to the client's address. """ self.RequestHandlerClass( request, diff --git a/reflex/utils/exec.py b/reflex/utils/exec.py index 5291de095..3e69ecd0b 100644 --- a/reflex/utils/exec.py +++ b/reflex/utils/exec.py @@ -206,7 +206,9 @@ def get_granian_target(): app_module_path = Path(reflex.__file__).parent / "app_module_for_backend.py" - return f"{str(app_module_path)}:{constants.CompileVars.APP}.{constants.CompileVars.API}" + return ( + f"{app_module_path!s}:{constants.CompileVars.APP}.{constants.CompileVars.API}" + ) def run_backend( @@ -440,10 +442,8 @@ def output_system_info(): system = platform.system() - if ( - system != "Windows" - or system == "Windows" - and prerequisites.is_windows_bun_supported() + if system != "Windows" or ( + system == "Windows" and prerequisites.is_windows_bun_supported() ): dependencies.extend( [ diff --git a/reflex/utils/format.py b/reflex/utils/format.py index 1b3d1740f..6236a883e 100644 --- a/reflex/utils/format.py +++ b/reflex/utils/format.py @@ -329,12 +329,12 @@ def format_match( return_value = case[-1] case_conditions = " ".join( - [f"case JSON.stringify({str(condition)}):" for condition in conditions] + [f"case JSON.stringify({condition!s}):" for condition in conditions] ) - case_code = f"{case_conditions} return ({str(return_value)}); break;" + case_code = f"{case_conditions} return ({return_value!s}); break;" switch_code += case_code - switch_code += f"default: return ({str(default)}); break;" + switch_code += f"default: return ({default!s}); break;" switch_code += "};})()" return switch_code @@ -413,7 +413,7 @@ def format_props(*single_props, **key_value_props) -> list[str]: ) for name, prop in sorted(key_value_props.items()) if prop is not None - ] + [(f"{str(LiteralVar.create(prop))}") for prop in single_props] + ] + [(f"{LiteralVar.create(prop)!s}") for prop in single_props] def get_event_handler_parts(handler: EventHandler) -> tuple[str, str]: @@ -713,7 +713,7 @@ def format_array_ref(refs: str, idx: Var | None) -> str: clean_ref = re.sub(r"[^\w]+", "_", refs) if idx is not None: # idx._var_is_local = True - return f"refs_{clean_ref}[{str(idx)}]" + return f"refs_{clean_ref}[{idx!s}]" return f"refs_{clean_ref}" diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index cc56bdf88..88260fe45 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -219,9 +219,8 @@ def get_install_package_manager(on_failure_return_none: bool = False) -> str | N Returns: The path to the package manager. """ - if ( - constants.IS_WINDOWS - and not is_windows_bun_supported() + if constants.IS_WINDOWS and ( + not is_windows_bun_supported() or windows_check_onedrive_in_path() or windows_npm_escape_hatch() ): @@ -834,7 +833,7 @@ def install_bun(): """Install bun onto the user's system.""" win_supported = is_windows_bun_supported() one_drive_in_path = windows_check_onedrive_in_path() - if constants.IS_WINDOWS and not win_supported or one_drive_in_path: + if constants.IS_WINDOWS and (not win_supported or one_drive_in_path): if not win_supported: console.warn( "Bun for Windows is currently only available for x86 64-bit Windows. Installation will fall back on npm." @@ -926,7 +925,7 @@ def cached_procedure(cache_file: str, payload_fn: Callable[..., str]): @cached_procedure( cache_file=str(get_web_dir() / "reflex.install_frontend_packages.cached"), - payload_fn=lambda p, c: f"{repr(sorted(list(p)))},{c.json()}", + payload_fn=lambda p, c: f"{sorted(list(p))!r},{c.json()}", ) def install_frontend_packages(packages: set[str], config: Config): """Installs the base and custom frontend packages. @@ -946,9 +945,12 @@ def install_frontend_packages(packages: set[str], config: Config): get_package_manager(on_failure_return_none=True) if ( not constants.IS_WINDOWS - or constants.IS_WINDOWS - and is_windows_bun_supported() - and not windows_check_onedrive_in_path() + or ( + constants.IS_WINDOWS + and ( + is_windows_bun_supported() and not windows_check_onedrive_in_path() + ) + ) ) else None ) diff --git a/reflex/utils/processes.py b/reflex/utils/processes.py index a45676c01..4d0e64a96 100644 --- a/reflex/utils/processes.py +++ b/reflex/utils/processes.py @@ -364,7 +364,7 @@ def get_command_with_loglevel(command: list[str]) -> list[str]: npm_path = str(Path(npm_path).resolve()) if npm_path else npm_path if command[0] == npm_path: - return command + ["--loglevel", "silly"] + return [*command, "--loglevel", "silly"] return command diff --git a/reflex/utils/pyi_generator.py b/reflex/utils/pyi_generator.py index fb0a8f8c5..9b2cbe722 100644 --- a/reflex/utils/pyi_generator.py +++ b/reflex/utils/pyi_generator.py @@ -835,7 +835,7 @@ class StubGenerator(ast.NodeTransformer): self.inserted_imports = True default_imports = _generate_imports(self.typing_imports) self.import_statements.extend(ast.unparse(i) for i in default_imports) - return default_imports + [node] + return [*default_imports, node] return node def visit_ImportFrom( diff --git a/reflex/utils/types.py b/reflex/utils/types.py index 0c39eacc4..7138dafb1 100644 --- a/reflex/utils/types.py +++ b/reflex/utils/types.py @@ -783,7 +783,7 @@ def validate_literal(key: str, value: Any, expected_type: Type, comp_name: str): ) value_str = f"'{value}'" if isinstance(value, str) else value raise ValueError( - f"prop value for {str(key)} of the `{comp_name}` component should be one of the following: {allowed_value_str}. Got {value_str} instead" + f"prop value for {key!s} of the `{comp_name}` component should be one of the following: {allowed_value_str}. Got {value_str} instead" ) diff --git a/reflex/vars/base.py b/reflex/vars/base.py index 200f693de..ea78d1a89 100644 --- a/reflex/vars/base.py +++ b/reflex/vars/base.py @@ -1057,7 +1057,7 @@ class Var(Generic[VAR_TYPE]): if self._var_type is Any: raise TypeError( - f"You must provide an annotation for the state var `{str(self)}`. Annotation cannot be `{self._var_type}`." + f"You must provide an annotation for the state var `{self!s}`. Annotation cannot be `{self._var_type}`." ) if name in REPLACED_NAMES: @@ -2117,7 +2117,7 @@ class ComputedVar(Var[RETURN_TYPE]): ref_obj = None if instruction.argval in invalid_names: raise VarValueError( - f"Cached var {str(self)} cannot access arbitrary state via `{instruction.argval}`." + f"Cached var {self!s} cannot access arbitrary state via `{instruction.argval}`." ) if callable(ref_obj): # recurse into callable attributes @@ -2492,7 +2492,7 @@ class StateOperation(CachedVarOperation, Var): Returns: The cached var name. """ - return f"{str(self._state_name)}.{str(self._field)}" + return f"{self._state_name!s}.{self._field!s}" def __getattr__(self, name: str) -> Any: """Get an attribute of the var. @@ -2804,9 +2804,9 @@ def dispatch( if result_origin_var_type in dispatchers: fn = dispatchers[result_origin_var_type] - fn_first_arg_type = list(inspect.signature(fn).parameters.values())[ - 0 - ].annotation + fn_first_arg_type = next( + iter(inspect.signature(fn).parameters.values()) + ).annotation fn_return = inspect.signature(fn).return_annotation diff --git a/reflex/vars/function.py b/reflex/vars/function.py index c65b38f70..9879fdb5d 100644 --- a/reflex/vars/function.py +++ b/reflex/vars/function.py @@ -240,7 +240,7 @@ class VarOperationCall(Generic[P, R], CachedVarOperation, Var[R]): Returns: The name of the var. """ - return f"({str(self._func)}({', '.join([str(LiteralVar.create(arg)) for arg in self._args])}))" + return f"({self._func!s}({', '.join([str(LiteralVar.create(arg)) for arg in self._args])}))" @cached_property_no_lock def _cached_get_all_var_data(self) -> VarData | None: diff --git a/reflex/vars/object.py b/reflex/vars/object.py index e60ea09e3..032fc8058 100644 --- a/reflex/vars/object.py +++ b/reflex/vars/object.py @@ -272,7 +272,7 @@ class ObjectVar(Var[OBJECT_TYPE], python_types=dict): attribute_type = get_attribute_access_type(var_type, name) if attribute_type is None: raise VarAttributeError( - f"The State var `{str(self)}` has no attribute '{name}' or may have been annotated " + f"The State var `{self!s}` has no attribute '{name}' or may have been annotated " f"wrongly." ) return ObjectItemOperation.create(self, name, attribute_type).guess_type() @@ -332,7 +332,7 @@ class LiteralObjectVar(CachedVarOperation, ObjectVar[OBJECT_TYPE], LiteralVar): "({ " + ", ".join( [ - f"[{str(LiteralVar.create(key))}] : {str(LiteralVar.create(value))}" + f"[{LiteralVar.create(key)!s}] : {LiteralVar.create(value)!s}" for key, value in self._var_value.items() ] ) @@ -494,8 +494,8 @@ class ObjectItemOperation(CachedVarOperation, Var): The name of the operation. """ if types.is_optional(self._object._var_type): - return f"{str(self._object)}?.[{str(self._key)}]" - return f"{str(self._object)}[{str(self._key)}]" + return f"{self._object!s}?.[{self._key!s}]" + return f"{self._object!s}[{self._key!s}]" @classmethod def create( diff --git a/reflex/vars/sequence.py b/reflex/vars/sequence.py index 08429883f..f5639685f 100644 --- a/reflex/vars/sequence.py +++ b/reflex/vars/sequence.py @@ -1349,7 +1349,7 @@ class ArraySliceOperation(CachedVarOperation, ArrayVar): LiteralVar.create(end) if end is not None else Var(_js_expr="undefined") ) if step is None: - return f"{str(self._array)}.slice({str(normalized_start)}, {str(normalized_end)})" + return f"{self._array!s}.slice({normalized_start!s}, {normalized_end!s})" if not isinstance(step, Var): if step < 0: actual_start = end + 1 if end is not None else 0 @@ -1357,12 +1357,12 @@ class ArraySliceOperation(CachedVarOperation, ArrayVar): return str(self._array[actual_start:actual_end].reverse()[::-step]) if step == 0: raise ValueError("slice step cannot be zero") - return f"{str(self._array)}.slice({str(normalized_start)}, {str(normalized_end)}).filter((_, i) => i % {str(step)} === 0)" + return f"{self._array!s}.slice({normalized_start!s}, {normalized_end!s}).filter((_, i) => i % {step!s} === 0)" actual_start_reverse = end + 1 if end is not None else 0 actual_end_reverse = start + 1 if start is not None else self._array.length() - return f"{str(self.step)} > 0 ? {str(self._array)}.slice({str(normalized_start)}, {str(normalized_end)}).filter((_, i) => i % {str(step)} === 0) : {str(self._array)}.slice({str(actual_start_reverse)}, {str(actual_end_reverse)}).reverse().filter((_, i) => i % {str(-step)} === 0)" + return f"{self.step!s} > 0 ? {self._array!s}.slice({normalized_start!s}, {normalized_end!s}).filter((_, i) => i % {step!s} === 0) : {self._array!s}.slice({actual_start_reverse!s}, {actual_end_reverse!s}).reverse().filter((_, i) => i % {-step!s} === 0)" @classmethod def create( @@ -1535,7 +1535,7 @@ def array_item_operation(array: ArrayVar, index: NumberVar | int): element_type = unionize(*args) return var_operation_return( - js_expression=f"{str(array)}.at({str(index)})", + js_expression=f"{array!s}.at({index!s})", var_type=element_type, ) @@ -1555,7 +1555,7 @@ def array_range_operation( The range of numbers. """ return var_operation_return( - js_expression=f"Array.from({{ length: ({str(stop)} - {str(start)}) / {str(step)} }}, (_, i) => {str(start)} + i * {str(step)})", + js_expression=f"Array.from({{ length: ({stop!s} - {start!s}) / {step!s} }}, (_, i) => {start!s} + i * {step!s})", var_type=List[int], ) diff --git a/tests/integration/test_call_script.py b/tests/integration/test_call_script.py index 71200221b..8c4bab8ce 100644 --- a/tests/integration/test_call_script.py +++ b/tests/integration/test_call_script.py @@ -160,7 +160,7 @@ def CallScript(): @rx.event def call_with_var_str_cast(self): return rx.call_script( - f"{str(rx.Var('inline_counter'))} + {str(rx.Var('external_counter'))}", + f"{rx.Var('inline_counter')!s} + {rx.Var('external_counter')!s}", callback=CallScriptState.set_last_result, # type: ignore ) @@ -175,7 +175,7 @@ def CallScript(): def call_with_var_str_cast_wrapped(self): return rx.call_script( rx.Var( - f"{str(rx.Var('inline_counter'))} + {str(rx.Var('external_counter'))}" + f"{rx.Var('inline_counter')!s} + {rx.Var('external_counter')!s}" ), callback=CallScriptState.set_last_result, # type: ignore ) @@ -315,7 +315,7 @@ def CallScript(): rx.button( "call_with_var_str_cast_inline", on_click=rx.call_script( - f"{str(rx.Var('inline_counter'))} + {str(rx.Var('external_counter'))}", + f"{rx.Var('inline_counter')!s} + {rx.Var('external_counter')!s}", callback=CallScriptState.set_last_result, # type: ignore ), id="call_with_var_str_cast_inline", @@ -334,7 +334,7 @@ def CallScript(): "call_with_var_str_cast_wrapped_inline", on_click=rx.call_script( rx.Var( - f"{str(rx.Var('inline_counter'))} + {str(rx.Var('external_counter'))}" + f"{rx.Var('inline_counter')!s} + {rx.Var('external_counter')!s}" ), callback=CallScriptState.set_last_result, # type: ignore ), diff --git a/tests/integration/tests_playwright/test_table.py b/tests/integration/tests_playwright/test_table.py index 0a39b197e..db716aa5b 100644 --- a/tests/integration/tests_playwright/test_table.py +++ b/tests/integration/tests_playwright/test_table.py @@ -97,4 +97,5 @@ def test_table(page: Page, table_app: AppHarness): # Check cells rows = table.get_by_role("cell").all_inner_texts() for i, expected_row in enumerate(expected_cells_data): - assert [rows[idx := i * 2], rows[idx + 1]] == expected_row + idx = i * 2 + assert [rows[idx], rows[idx + 1]] == expected_row diff --git a/tests/units/components/core/test_colors.py b/tests/units/components/core/test_colors.py index 74fbeb20f..c1295fb41 100644 --- a/tests/units/components/core/test_colors.py +++ b/tests/units/components/core/test_colors.py @@ -32,38 +32,38 @@ def create_color_var(color): (create_color_var(rx.color("mint", 3, True)), '"var(--mint-a3)"', Color), ( create_color_var(rx.color(ColorState.color, ColorState.shade)), # type: ignore - f'("var(--"+{str(color_state_name)}.color+"-"+(((__to_string) => __to_string.toString())({str(color_state_name)}.shade))+")")', + f'("var(--"+{color_state_name!s}.color+"-"+(((__to_string) => __to_string.toString())({color_state_name!s}.shade))+")")', Color, ), ( create_color_var( rx.color(ColorState.color, ColorState.shade, ColorState.alpha) # type: ignore ), - f'("var(--"+{str(color_state_name)}.color+"-"+({str(color_state_name)}.alpha ? "a" : "")+(((__to_string) => __to_string.toString())({str(color_state_name)}.shade))+")")', + f'("var(--"+{color_state_name!s}.color+"-"+({color_state_name!s}.alpha ? "a" : "")+(((__to_string) => __to_string.toString())({color_state_name!s}.shade))+")")', Color, ), ( create_color_var(rx.color(f"{ColorState.color}", f"{ColorState.shade}")), # type: ignore - f'("var(--"+{str(color_state_name)}.color+"-"+{str(color_state_name)}.shade+")")', + f'("var(--"+{color_state_name!s}.color+"-"+{color_state_name!s}.shade+")")', Color, ), ( create_color_var( rx.color(f"{ColorState.color_part}ato", f"{ColorState.shade}") # type: ignore ), - f'("var(--"+({str(color_state_name)}.color_part+"ato")+"-"+{str(color_state_name)}.shade+")")', + f'("var(--"+({color_state_name!s}.color_part+"ato")+"-"+{color_state_name!s}.shade+")")', Color, ), ( create_color_var(f'{rx.color(ColorState.color, f"{ColorState.shade}")}'), # type: ignore - f'("var(--"+{str(color_state_name)}.color+"-"+{str(color_state_name)}.shade+")")', + f'("var(--"+{color_state_name!s}.color+"-"+{color_state_name!s}.shade+")")', str, ), ( create_color_var( f'{rx.color(f"{ColorState.color}", f"{ColorState.shade}")}' # type: ignore ), - f'("var(--"+{str(color_state_name)}.color+"-"+{str(color_state_name)}.shade+")")', + f'("var(--"+{color_state_name!s}.color+"-"+{color_state_name!s}.shade+")")', str, ), ], @@ -82,7 +82,7 @@ def test_color(color, expected, expected_type: Union[Type[str], Type[Color]]): ), ( rx.cond(True, rx.color(ColorState.color), rx.color(ColorState.color, 5)), # type: ignore - f'(true ? ("var(--"+{str(color_state_name)}.color+"-7)") : ("var(--"+{str(color_state_name)}.color+"-5)"))', + f'(true ? ("var(--"+{color_state_name!s}.color+"-7)") : ("var(--"+{color_state_name!s}.color+"-5)"))', ), ( rx.match( @@ -93,7 +93,7 @@ def test_color(color, expected, expected_type: Union[Type[str], Type[Color]]): ), '(() => { switch (JSON.stringify("condition")) {case JSON.stringify("first"): return ("var(--mint-7)");' ' break;case JSON.stringify("second"): return ("var(--tomato-5)"); break;default: ' - f'return (("var(--"+{str(color_state_name)}.color+"-2)")); break;}};}})()', + f'return (("var(--"+{color_state_name!s}.color+"-2)")); break;}};}})()', ), ( rx.match( @@ -103,9 +103,9 @@ def test_color(color, expected, expected_type: Union[Type[str], Type[Color]]): rx.color(ColorState.color, 2), # type: ignore ), '(() => { switch (JSON.stringify("condition")) {case JSON.stringify("first"): ' - f'return (("var(--"+{str(color_state_name)}.color+"-7)")); break;case JSON.stringify("second"): ' - f'return (("var(--"+{str(color_state_name)}.color+"-5)")); break;default: ' - f'return (("var(--"+{str(color_state_name)}.color+"-2)")); break;}};}})()', + f'return (("var(--"+{color_state_name!s}.color+"-7)")); break;case JSON.stringify("second"): ' + f'return (("var(--"+{color_state_name!s}.color+"-5)")); break;default: ' + f'return (("var(--"+{color_state_name!s}.color+"-2)")); break;}};}})()', ), ], ) diff --git a/tests/units/components/core/test_cond.py b/tests/units/components/core/test_cond.py index f9bdc7d60..8ad51158e 100644 --- a/tests/units/components/core/test_cond.py +++ b/tests/units/components/core/test_cond.py @@ -96,7 +96,7 @@ def test_prop_cond(c1: Any, c2: Any): c1 = json.dumps(c1) if not isinstance(c2, Var): c2 = json.dumps(c2) - assert str(prop_cond) == f"(true ? {str(c1)} : {str(c2)})" + assert str(prop_cond) == f"(true ? {c1!s} : {c2!s})" def test_cond_no_mix(): diff --git a/tests/units/components/core/test_debounce.py b/tests/units/components/core/test_debounce.py index 2fad9c925..29d3bcddc 100644 --- a/tests/units/components/core/test_debounce.py +++ b/tests/units/components/core/test_debounce.py @@ -108,7 +108,7 @@ def test_render_with_special_props(): ) )._render() assert len(tag.special_props) == 1 - assert list(tag.special_props)[0].equals(special_prop) + assert next(iter(tag.special_props)).equals(special_prop) def test_event_triggers(): diff --git a/tests/units/components/core/test_html.py b/tests/units/components/core/test_html.py index 4847e1d5a..79c258dfb 100644 --- a/tests/units/components/core/test_html.py +++ b/tests/units/components/core/test_html.py @@ -33,9 +33,9 @@ def test_html_fstring_create(): assert ( str(html.dangerouslySetInnerHTML) # type: ignore - == f'({{ ["__html"] : ("

Hello "+{str(TestState.myvar)}+"!

") }})' + == f'({{ ["__html"] : ("

Hello "+{TestState.myvar!s}+"!

") }})' ) assert ( str(html) - == f'
' # type: ignore + == f'
' # type: ignore ) diff --git a/tests/units/components/test_component.py b/tests/units/components/test_component.py index a2485d10e..e2b035a8f 100644 --- a/tests/units/components/test_component.py +++ b/tests/units/components/test_component.py @@ -810,7 +810,8 @@ def test_component_create_unpack_tuple_child(test_component, element, expected): comp = test_component.create(element) assert len(comp.children) == 1 - assert isinstance((fragment_wrapper := comp.children[0]), Fragment) + fragment_wrapper = comp.children[0] + assert isinstance(fragment_wrapper, Fragment) assert fragment_wrapper.render() == expected diff --git a/tests/units/test_app.py b/tests/units/test_app.py index 216d36f62..7c7455cba 100644 --- a/tests/units/test_app.py +++ b/tests/units/test_app.py @@ -1479,17 +1479,20 @@ def test_add_page_component_returning_tuple(): app._compile_page("index") app._compile_page("page2") - assert isinstance((fragment_wrapper := app.pages["index"].children[0]), Fragment) - assert isinstance((first_text := fragment_wrapper.children[0]), Text) + fragment_wrapper = app.pages["index"].children[0] + assert isinstance(fragment_wrapper, Fragment) + first_text = fragment_wrapper.children[0] + assert isinstance(first_text, Text) assert str(first_text.children[0].contents) == '"first"' # type: ignore - assert isinstance((second_text := fragment_wrapper.children[1]), Text) + second_text = fragment_wrapper.children[1] + assert isinstance(second_text, Text) assert str(second_text.children[0].contents) == '"second"' # type: ignore # Test page with trailing comma. - assert isinstance( - (page2_fragment_wrapper := app.pages["page2"].children[0]), Fragment - ) - assert isinstance((third_text := page2_fragment_wrapper.children[0]), Text) + 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) assert str(third_text.children[0].contents) == '"third"' # type: ignore diff --git a/tests/units/test_event.py b/tests/units/test_event.py index 4399ab2a0..4f7adfeb3 100644 --- a/tests/units/test_event.py +++ b/tests/units/test_event.py @@ -319,7 +319,7 @@ def test_remove_cookie_with_options(): assert spec.args[1][1].equals(LiteralVar.create(options)) assert ( format.format_event(spec) - == f'Event("_remove_cookie", {{key:"testkey",options:{str(LiteralVar.create(options))}}})' + == f'Event("_remove_cookie", {{key:"testkey",options:{LiteralVar.create(options)!s}}})' ) diff --git a/tests/units/test_state.py b/tests/units/test_state.py index 8e61b8dae..9dc2bc4e2 100644 --- a/tests/units/test_state.py +++ b/tests/units/test_state.py @@ -2552,7 +2552,7 @@ def test_duplicate_substate_class(mocker): class TestState(BaseState): pass - class ChildTestState(TestState): # type: ignore # noqa + class ChildTestState(TestState): # type: ignore pass class ChildTestState(TestState): # type: ignore # noqa @@ -2669,23 +2669,23 @@ def test_state_union_optional(): c3r: Custom3 = Custom3(c2r=Custom2(c1r=Custom1(foo=""))) custom_union: Union[Custom1, Custom2, Custom3] = Custom1(foo="") - assert str(UnionState.c3.c2) == f'{str(UnionState.c3)}?.["c2"]' # type: ignore - assert str(UnionState.c3.c2.c1) == f'{str(UnionState.c3)}?.["c2"]?.["c1"]' # type: ignore + assert str(UnionState.c3.c2) == f'{UnionState.c3!s}?.["c2"]' # type: ignore + assert str(UnionState.c3.c2.c1) == f'{UnionState.c3!s}?.["c2"]?.["c1"]' # type: ignore assert ( - str(UnionState.c3.c2.c1.foo) == f'{str(UnionState.c3)}?.["c2"]?.["c1"]?.["foo"]' # type: ignore + str(UnionState.c3.c2.c1.foo) == f'{UnionState.c3!s}?.["c2"]?.["c1"]?.["foo"]' # type: ignore ) assert ( - str(UnionState.c3.c2.c1r.foo) == f'{str(UnionState.c3)}?.["c2"]?.["c1r"]["foo"]' # type: ignore + str(UnionState.c3.c2.c1r.foo) == f'{UnionState.c3!s}?.["c2"]?.["c1r"]["foo"]' # type: ignore ) - assert str(UnionState.c3.c2r.c1) == f'{str(UnionState.c3)}?.["c2r"]["c1"]' # type: ignore + assert str(UnionState.c3.c2r.c1) == f'{UnionState.c3!s}?.["c2r"]["c1"]' # type: ignore assert ( - str(UnionState.c3.c2r.c1.foo) == f'{str(UnionState.c3)}?.["c2r"]["c1"]?.["foo"]' # type: ignore + str(UnionState.c3.c2r.c1.foo) == f'{UnionState.c3!s}?.["c2r"]["c1"]?.["foo"]' # type: ignore ) assert ( - str(UnionState.c3.c2r.c1r.foo) == f'{str(UnionState.c3)}?.["c2r"]["c1r"]["foo"]' # type: ignore + str(UnionState.c3.c2r.c1r.foo) == f'{UnionState.c3!s}?.["c2r"]["c1r"]["foo"]' # type: ignore ) - assert str(UnionState.c3i.c2) == f'{str(UnionState.c3i)}["c2"]' # type: ignore - assert str(UnionState.c3r.c2) == f'{str(UnionState.c3r)}["c2"]' # type: ignore + assert str(UnionState.c3i.c2) == f'{UnionState.c3i!s}["c2"]' # type: ignore + assert str(UnionState.c3r.c2) == f'{UnionState.c3r!s}["c2"]' # type: ignore assert UnionState.custom_union.foo is not None # type: ignore assert UnionState.custom_union.c1 is not None # type: ignore assert UnionState.custom_union.c1r is not None # type: ignore diff --git a/tests/units/test_var.py b/tests/units/test_var.py index 4940246e7..3176443a6 100644 --- a/tests/units/test_var.py +++ b/tests/units/test_var.py @@ -1770,7 +1770,7 @@ def test_valid_var_operations(operand1_var: Var, operand2_var, operators: List[s ) def test_invalid_var_operations(operand1_var: Var, operand2_var, operators: List[str]): for operator in operators: - print(f"testing {operator} on {str(operand1_var)} and {str(operand2_var)}") + print(f"testing {operator} on {operand1_var!s} and {operand2_var!s}") with pytest.raises(TypeError): print(eval(f"operand1_var {operator} operand2_var")) # operand1_var.operation(op=operator, other=operand2_var) diff --git a/tests/units/utils/test_types.py b/tests/units/utils/test_types.py index 623aacc1f..87790e979 100644 --- a/tests/units/utils/test_types.py +++ b/tests/units/utils/test_types.py @@ -17,7 +17,7 @@ def test_validate_literal_error_msg(params, allowed_value_str, value_str): types.validate_literal(*params) assert ( - err.value.args[0] == f"prop value for {str(params[0])} of the `{params[-1]}` " + err.value.args[0] == f"prop value for {params[0]!s} of the `{params[-1]}` " f"component should be one of the following: {allowed_value_str}. Got {value_str} instead" ) From 05b791653e26b60799f4feda6b89514095b9693b Mon Sep 17 00:00:00 2001 From: Elijah Ahianyo Date: Tue, 10 Dec 2024 17:14:29 +0000 Subject: [PATCH 54/71] Default `rx.link` href to `#` so underline prop works (#4509) --- reflex/components/radix/themes/typography/link.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/reflex/components/radix/themes/typography/link.py b/reflex/components/radix/themes/typography/link.py index 1cc673536..25a0902cc 100644 --- a/reflex/components/radix/themes/typography/link.py +++ b/reflex/components/radix/themes/typography/link.py @@ -77,13 +77,14 @@ class Link(RadixThemesComponent, A, MemoizationLeaf, MarkdownComponentMap): Component: The link component """ props.setdefault(":hover", {"color": color("accent", 8)}) + href = props.get("href") is_external = props.pop("is_external", None) if is_external is not None: props["target"] = cond(is_external, "_blank", "") - if props.get("href") is not None: + if href is not None: if not len(children): raise ValueError("Link without a child will not display") @@ -101,6 +102,9 @@ class Link(RadixThemesComponent, A, MemoizationLeaf, MarkdownComponentMap): as_child=True, **props, ) + else: + props["href"] = "#" + return super().create(*children, **props) From 6e3e632bbd64edaee5db85f3edb2be3de4a9e371 Mon Sep 17 00:00:00 2001 From: Elijah Ahianyo Date: Tue, 10 Dec 2024 17:15:22 +0000 Subject: [PATCH 55/71] reduce lock expiration time to 1s (#4507) --- reflex/constants/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reflex/constants/config.py b/reflex/constants/config.py index 970e67844..234ecbd84 100644 --- a/reflex/constants/config.py +++ b/reflex/constants/config.py @@ -26,7 +26,7 @@ class Expiration(SimpleNamespace): # Token expiration time in seconds TOKEN = 60 * 60 # Maximum time in milliseconds that a state can be locked for exclusive access. - LOCK = 10000 + LOCK = 1000 # The PING timeout PING = 120 From 6e42efd2b14ed77682024563186fa743854ff9ff Mon Sep 17 00:00:00 2001 From: Elijah Ahianyo Date: Tue, 10 Dec 2024 17:15:53 +0000 Subject: [PATCH 56/71] Fix deploy help text (#4508) --- reflex/reflex.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reflex/reflex.py b/reflex/reflex.py index bad2ecb28..829c7c0d2 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -446,7 +446,7 @@ def deploy( list(), "-r", "--region", - help="The regions to deploy to. `reflex apps regions` For multiple envs, repeat this option, e.g. --region sjc --region iad", + help="The regions to deploy to. `reflex cloud regions` For multiple envs, repeat this option, e.g. --region sjc --region iad", ), envs: List[str] = typer.Option( list(), @@ -456,7 +456,7 @@ def deploy( vmtype: Optional[str] = typer.Option( None, "--vmtype", - help="Vm type id. Run `reflex apps vmtypes` to get options.", + help="Vm type id. Run `reflex cloud vmtypes` to get options.", ), hostname: Optional[str] = typer.Option( None, From 49a8f813fed0cbdf679db38cbd26729a1c05d03c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Tue, 10 Dec 2024 09:17:57 -0800 Subject: [PATCH 57/71] bump ruff to 0.8 and relock poetry (#4451) * bump ruff to 0.8 and relock poetry * bump to 0.8.1 * relock poetry.lock * update again --- .pre-commit-config.yaml | 2 +- poetry.lock | 637 +++++++++++++++++++++------------------- pyproject.toml | 4 +- 3 files changed, 339 insertions(+), 304 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4046bad2d..1acf9ecb8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ fail_fast: true repos: - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.7.4 + rev: v0.8.2 hooks: - id: ruff-format args: [reflex, tests] diff --git a/poetry.lock b/poetry.lock index 7d46e4199..aa826e4b0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -32,24 +32,24 @@ files = [ [[package]] name = "anyio" -version = "4.6.2.post1" +version = "4.7.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" files = [ - {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, - {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, + {file = "anyio-4.7.0-py3-none-any.whl", hash = "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352"}, + {file = "anyio-4.7.0.tar.gz", hash = "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48"}, ] [package.dependencies] exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" -typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] trio = ["trio (>=0.26.1)"] [[package]] @@ -386,73 +386,73 @@ files = [ [[package]] name = "coverage" -version = "7.6.7" +version = "7.6.9" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" files = [ - {file = "coverage-7.6.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:108bb458827765d538abcbf8288599fee07d2743357bdd9b9dad456c287e121e"}, - {file = "coverage-7.6.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c973b2fe4dc445cb865ab369df7521df9c27bf40715c837a113edaa2aa9faf45"}, - {file = "coverage-7.6.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c6b24007c4bcd0b19fac25763a7cac5035c735ae017e9a349b927cfc88f31c1"}, - {file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acbb8af78f8f91b3b51f58f288c0994ba63c646bc1a8a22ad072e4e7e0a49f1c"}, - {file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad32a981bcdedb8d2ace03b05e4fd8dace8901eec64a532b00b15217d3677dd2"}, - {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:34d23e28ccb26236718a3a78ba72744212aa383141961dd6825f6595005c8b06"}, - {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e25bacb53a8c7325e34d45dddd2f2fbae0dbc230d0e2642e264a64e17322a777"}, - {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af05bbba896c4472a29408455fe31b3797b4d8648ed0a2ccac03e074a77e2314"}, - {file = "coverage-7.6.7-cp310-cp310-win32.whl", hash = "sha256:796c9b107d11d2d69e1849b2dfe41730134b526a49d3acb98ca02f4985eeff7a"}, - {file = "coverage-7.6.7-cp310-cp310-win_amd64.whl", hash = "sha256:987a8e3da7da4eed10a20491cf790589a8e5e07656b6dc22d3814c4d88faf163"}, - {file = "coverage-7.6.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e61b0e77ff4dddebb35a0e8bb5a68bf0f8b872407d8d9f0c726b65dfabe2469"}, - {file = "coverage-7.6.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a5407a75ca4abc20d6252efeb238377a71ce7bda849c26c7a9bece8680a5d99"}, - {file = "coverage-7.6.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df002e59f2d29e889c37abd0b9ee0d0e6e38c24f5f55d71ff0e09e3412a340ec"}, - {file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:673184b3156cba06154825f25af33baa2671ddae6343f23175764e65a8c4c30b"}, - {file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e69ad502f1a2243f739f5bd60565d14a278be58be4c137d90799f2c263e7049a"}, - {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60dcf7605c50ea72a14490d0756daffef77a5be15ed1b9fea468b1c7bda1bc3b"}, - {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9c2eb378bebb2c8f65befcb5147877fc1c9fbc640fc0aad3add759b5df79d55d"}, - {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c0317288f032221d35fa4cbc35d9f4923ff0dfd176c79c9b356e8ef8ef2dff4"}, - {file = "coverage-7.6.7-cp311-cp311-win32.whl", hash = "sha256:951aade8297358f3618a6e0660dc74f6b52233c42089d28525749fc8267dccd2"}, - {file = "coverage-7.6.7-cp311-cp311-win_amd64.whl", hash = "sha256:5e444b8e88339a2a67ce07d41faabb1d60d1004820cee5a2c2b54e2d8e429a0f"}, - {file = "coverage-7.6.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f07ff574986bc3edb80e2c36391678a271d555f91fd1d332a1e0f4b5ea4b6ea9"}, - {file = "coverage-7.6.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:49ed5ee4109258973630c1f9d099c7e72c5c36605029f3a91fe9982c6076c82b"}, - {file = "coverage-7.6.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3e8796434a8106b3ac025fd15417315d7a58ee3e600ad4dbcfddc3f4b14342c"}, - {file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3b925300484a3294d1c70f6b2b810d6526f2929de954e5b6be2bf8caa1f12c1"}, - {file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c42ec2c522e3ddd683dec5cdce8e62817afb648caedad9da725001fa530d354"}, - {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0266b62cbea568bd5e93a4da364d05de422110cbed5056d69339bd5af5685433"}, - {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e5f2a0f161d126ccc7038f1f3029184dbdf8f018230af17ef6fd6a707a5b881f"}, - {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c132b5a22821f9b143f87446805e13580b67c670a548b96da945a8f6b4f2efbb"}, - {file = "coverage-7.6.7-cp312-cp312-win32.whl", hash = "sha256:7c07de0d2a110f02af30883cd7dddbe704887617d5c27cf373362667445a4c76"}, - {file = "coverage-7.6.7-cp312-cp312-win_amd64.whl", hash = "sha256:fd49c01e5057a451c30c9b892948976f5d38f2cbd04dc556a82743ba8e27ed8c"}, - {file = "coverage-7.6.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:46f21663e358beae6b368429ffadf14ed0a329996248a847a4322fb2e35d64d3"}, - {file = "coverage-7.6.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:40cca284c7c310d622a1677f105e8507441d1bb7c226f41978ba7c86979609ab"}, - {file = "coverage-7.6.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77256ad2345c29fe59ae861aa11cfc74579c88d4e8dbf121cbe46b8e32aec808"}, - {file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87ea64b9fa52bf395272e54020537990a28078478167ade6c61da7ac04dc14bc"}, - {file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d608a7808793e3615e54e9267519351c3ae204a6d85764d8337bd95993581a8"}, - {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdd94501d65adc5c24f8a1a0eda110452ba62b3f4aeaba01e021c1ed9cb8f34a"}, - {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82c809a62e953867cf57e0548c2b8464207f5f3a6ff0e1e961683e79b89f2c55"}, - {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb684694e99d0b791a43e9fc0fa58efc15ec357ac48d25b619f207c41f2fd384"}, - {file = "coverage-7.6.7-cp313-cp313-win32.whl", hash = "sha256:963e4a08cbb0af6623e61492c0ec4c0ec5c5cf74db5f6564f98248d27ee57d30"}, - {file = "coverage-7.6.7-cp313-cp313-win_amd64.whl", hash = "sha256:14045b8bfd5909196a90da145a37f9d335a5d988a83db34e80f41e965fb7cb42"}, - {file = "coverage-7.6.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f2c7a045eef561e9544359a0bf5784b44e55cefc7261a20e730baa9220c83413"}, - {file = "coverage-7.6.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dd4e4a49d9c72a38d18d641135d2fb0bdf7b726ca60a103836b3d00a1182acd"}, - {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c95e0fa3d1547cb6f021ab72f5c23402da2358beec0a8e6d19a368bd7b0fb37"}, - {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f63e21ed474edd23f7501f89b53280014436e383a14b9bd77a648366c81dce7b"}, - {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead9b9605c54d15be228687552916c89c9683c215370c4a44f1f217d2adcc34d"}, - {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0573f5cbf39114270842d01872952d301027d2d6e2d84013f30966313cadb529"}, - {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:e2c8e3384c12dfa19fa9a52f23eb091a8fad93b5b81a41b14c17c78e23dd1d8b"}, - {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:70a56a2ec1869e6e9fa69ef6b76b1a8a7ef709972b9cc473f9ce9d26b5997ce3"}, - {file = "coverage-7.6.7-cp313-cp313t-win32.whl", hash = "sha256:dbba8210f5067398b2c4d96b4e64d8fb943644d5eb70be0d989067c8ca40c0f8"}, - {file = "coverage-7.6.7-cp313-cp313t-win_amd64.whl", hash = "sha256:dfd14bcae0c94004baba5184d1c935ae0d1231b8409eb6c103a5fd75e8ecdc56"}, - {file = "coverage-7.6.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37a15573f988b67f7348916077c6d8ad43adb75e478d0910957394df397d2874"}, - {file = "coverage-7.6.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b6cce5c76985f81da3769c52203ee94722cd5d5889731cd70d31fee939b74bf0"}, - {file = "coverage-7.6.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ab9763d291a17b527ac6fd11d1a9a9c358280adb320e9c2672a97af346ac2c"}, - {file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cf96ceaa275f071f1bea3067f8fd43bec184a25a962c754024c973af871e1b7"}, - {file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aee9cf6b0134d6f932d219ce253ef0e624f4fa588ee64830fcba193269e4daa3"}, - {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2bc3e45c16564cc72de09e37413262b9f99167803e5e48c6156bccdfb22c8327"}, - {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:623e6965dcf4e28a3debaa6fcf4b99ee06d27218f46d43befe4db1c70841551c"}, - {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:850cfd2d6fc26f8346f422920ac204e1d28814e32e3a58c19c91980fa74d8289"}, - {file = "coverage-7.6.7-cp39-cp39-win32.whl", hash = "sha256:c296263093f099da4f51b3dff1eff5d4959b527d4f2f419e16508c5da9e15e8c"}, - {file = "coverage-7.6.7-cp39-cp39-win_amd64.whl", hash = "sha256:90746521206c88bdb305a4bf3342b1b7316ab80f804d40c536fc7d329301ee13"}, - {file = "coverage-7.6.7-pp39.pp310-none-any.whl", hash = "sha256:0ddcb70b3a3a57581b450571b31cb774f23eb9519c2aaa6176d3a84c9fc57671"}, - {file = "coverage-7.6.7.tar.gz", hash = "sha256:d79d4826e41441c9a118ff045e4bccb9fdbdcb1d02413e7ea6eb5c87b5439d24"}, + {file = "coverage-7.6.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:85d9636f72e8991a1706b2b55b06c27545448baf9f6dbf51c4004609aacd7dcb"}, + {file = "coverage-7.6.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:608a7fd78c67bee8936378299a6cb9f5149bb80238c7a566fc3e6717a4e68710"}, + {file = "coverage-7.6.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96d636c77af18b5cb664ddf12dab9b15a0cfe9c0bde715da38698c8cea748bfa"}, + {file = "coverage-7.6.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75cded8a3cff93da9edc31446872d2997e327921d8eed86641efafd350e1df1"}, + {file = "coverage-7.6.9-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7b15f589593110ae767ce997775d645b47e5cbbf54fd322f8ebea6277466cec"}, + {file = "coverage-7.6.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:44349150f6811b44b25574839b39ae35291f6496eb795b7366fef3bd3cf112d3"}, + {file = "coverage-7.6.9-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d891c136b5b310d0e702e186d70cd16d1119ea8927347045124cb286b29297e5"}, + {file = "coverage-7.6.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:db1dab894cc139f67822a92910466531de5ea6034ddfd2b11c0d4c6257168073"}, + {file = "coverage-7.6.9-cp310-cp310-win32.whl", hash = "sha256:41ff7b0da5af71a51b53f501a3bac65fb0ec311ebed1632e58fc6107f03b9198"}, + {file = "coverage-7.6.9-cp310-cp310-win_amd64.whl", hash = "sha256:35371f8438028fdccfaf3570b31d98e8d9eda8bb1d6ab9473f5a390969e98717"}, + {file = "coverage-7.6.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:932fc826442132dde42ee52cf66d941f581c685a6313feebed358411238f60f9"}, + {file = "coverage-7.6.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:085161be5f3b30fd9b3e7b9a8c301f935c8313dcf928a07b116324abea2c1c2c"}, + {file = "coverage-7.6.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc660a77e1c2bf24ddbce969af9447a9474790160cfb23de6be4fa88e3951c7"}, + {file = "coverage-7.6.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c69e42c892c018cd3c8d90da61d845f50a8243062b19d228189b0224150018a9"}, + {file = "coverage-7.6.9-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0824a28ec542a0be22f60c6ac36d679e0e262e5353203bea81d44ee81fe9c6d4"}, + {file = "coverage-7.6.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4401ae5fc52ad8d26d2a5d8a7428b0f0c72431683f8e63e42e70606374c311a1"}, + {file = "coverage-7.6.9-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:98caba4476a6c8d59ec1eb00c7dd862ba9beca34085642d46ed503cc2d440d4b"}, + {file = "coverage-7.6.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ee5defd1733fd6ec08b168bd4f5387d5b322f45ca9e0e6c817ea6c4cd36313e3"}, + {file = "coverage-7.6.9-cp311-cp311-win32.whl", hash = "sha256:f2d1ec60d6d256bdf298cb86b78dd715980828f50c46701abc3b0a2b3f8a0dc0"}, + {file = "coverage-7.6.9-cp311-cp311-win_amd64.whl", hash = "sha256:0d59fd927b1f04de57a2ba0137166d31c1a6dd9e764ad4af552912d70428c92b"}, + {file = "coverage-7.6.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:99e266ae0b5d15f1ca8d278a668df6f51cc4b854513daab5cae695ed7b721cf8"}, + {file = "coverage-7.6.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9901d36492009a0a9b94b20e52ebfc8453bf49bb2b27bca2c9706f8b4f5a554a"}, + {file = "coverage-7.6.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abd3e72dd5b97e3af4246cdada7738ef0e608168de952b837b8dd7e90341f015"}, + {file = "coverage-7.6.9-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff74026a461eb0660366fb01c650c1d00f833a086b336bdad7ab00cc952072b3"}, + {file = "coverage-7.6.9-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65dad5a248823a4996724a88eb51d4b31587aa7aa428562dbe459c684e5787ae"}, + {file = "coverage-7.6.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:22be16571504c9ccea919fcedb459d5ab20d41172056206eb2994e2ff06118a4"}, + {file = "coverage-7.6.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f957943bc718b87144ecaee70762bc2bc3f1a7a53c7b861103546d3a403f0a6"}, + {file = "coverage-7.6.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ae1387db4aecb1f485fb70a6c0148c6cdaebb6038f1d40089b1fc84a5db556f"}, + {file = "coverage-7.6.9-cp312-cp312-win32.whl", hash = "sha256:1a330812d9cc7ac2182586f6d41b4d0fadf9be9049f350e0efb275c8ee8eb692"}, + {file = "coverage-7.6.9-cp312-cp312-win_amd64.whl", hash = "sha256:b12c6b18269ca471eedd41c1b6a1065b2f7827508edb9a7ed5555e9a56dcfc97"}, + {file = "coverage-7.6.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:899b8cd4781c400454f2f64f7776a5d87bbd7b3e7f7bda0cb18f857bb1334664"}, + {file = "coverage-7.6.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:61f70dc68bd36810972e55bbbe83674ea073dd1dcc121040a08cdf3416c5349c"}, + {file = "coverage-7.6.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a289d23d4c46f1a82d5db4abeb40b9b5be91731ee19a379d15790e53031c014"}, + {file = "coverage-7.6.9-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e216d8044a356fc0337c7a2a0536d6de07888d7bcda76febcb8adc50bdbbd00"}, + {file = "coverage-7.6.9-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c026eb44f744acaa2bda7493dad903aa5bf5fc4f2554293a798d5606710055d"}, + {file = "coverage-7.6.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e77363e8425325384f9d49272c54045bbed2f478e9dd698dbc65dbc37860eb0a"}, + {file = "coverage-7.6.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:777abfab476cf83b5177b84d7486497e034eb9eaea0d746ce0c1268c71652077"}, + {file = "coverage-7.6.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:447af20e25fdbe16f26e84eb714ba21d98868705cb138252d28bc400381f6ffb"}, + {file = "coverage-7.6.9-cp313-cp313-win32.whl", hash = "sha256:d872ec5aeb086cbea771c573600d47944eea2dcba8be5f3ee649bfe3cb8dc9ba"}, + {file = "coverage-7.6.9-cp313-cp313-win_amd64.whl", hash = "sha256:fd1213c86e48dfdc5a0cc676551db467495a95a662d2396ecd58e719191446e1"}, + {file = "coverage-7.6.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ba9e7484d286cd5a43744e5f47b0b3fb457865baf07bafc6bee91896364e1419"}, + {file = "coverage-7.6.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e5ea1cf0872ee455c03e5674b5bca5e3e68e159379c1af0903e89f5eba9ccc3a"}, + {file = "coverage-7.6.9-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d10e07aa2b91835d6abec555ec8b2733347956991901eea6ffac295f83a30e4"}, + {file = "coverage-7.6.9-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13a9e2d3ee855db3dd6ea1ba5203316a1b1fd8eaeffc37c5b54987e61e4194ae"}, + {file = "coverage-7.6.9-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c38bf15a40ccf5619fa2fe8f26106c7e8e080d7760aeccb3722664c8656b030"}, + {file = "coverage-7.6.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d5275455b3e4627c8e7154feaf7ee0743c2e7af82f6e3b561967b1cca755a0be"}, + {file = "coverage-7.6.9-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8f8770dfc6e2c6a2d4569f411015c8d751c980d17a14b0530da2d7f27ffdd88e"}, + {file = "coverage-7.6.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8d2dfa71665a29b153a9681edb1c8d9c1ea50dfc2375fb4dac99ea7e21a0bcd9"}, + {file = "coverage-7.6.9-cp313-cp313t-win32.whl", hash = "sha256:5e6b86b5847a016d0fbd31ffe1001b63355ed309651851295315031ea7eb5a9b"}, + {file = "coverage-7.6.9-cp313-cp313t-win_amd64.whl", hash = "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611"}, + {file = "coverage-7.6.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:adb697c0bd35100dc690de83154627fbab1f4f3c0386df266dded865fc50a902"}, + {file = "coverage-7.6.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:be57b6d56e49c2739cdf776839a92330e933dd5e5d929966fbbd380c77f060be"}, + {file = "coverage-7.6.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1592791f8204ae9166de22ba7e6705fa4ebd02936c09436a1bb85aabca3e599"}, + {file = "coverage-7.6.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e12ae8cc979cf83d258acb5e1f1cf2f3f83524d1564a49d20b8bec14b637f08"}, + {file = "coverage-7.6.9-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb5555cff66c4d3d6213a296b360f9e1a8e323e74e0426b6c10ed7f4d021e464"}, + {file = "coverage-7.6.9-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b9389a429e0e5142e69d5bf4a435dd688c14478a19bb901735cdf75e57b13845"}, + {file = "coverage-7.6.9-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:592ac539812e9b46046620341498caf09ca21023c41c893e1eb9dbda00a70cbf"}, + {file = "coverage-7.6.9-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a27801adef24cc30871da98a105f77995e13a25a505a0161911f6aafbd66e678"}, + {file = "coverage-7.6.9-cp39-cp39-win32.whl", hash = "sha256:8e3c3e38930cfb729cb8137d7f055e5a473ddaf1217966aa6238c88bd9fd50e6"}, + {file = "coverage-7.6.9-cp39-cp39-win_amd64.whl", hash = "sha256:e28bf44afa2b187cc9f41749138a64435bf340adfcacb5b2290c070ce99839d4"}, + {file = "coverage-7.6.9-pp39.pp310-none-any.whl", hash = "sha256:f3ca78518bc6bc92828cd11867b121891d75cae4ea9e908d72030609b996db1b"}, + {file = "coverage-7.6.9.tar.gz", hash = "sha256:4a8d8977b0c6ef5aeadcb644da9e69ae0dcfe66ec7f368c89c72e058bd71164d"}, ] [package.dependencies] @@ -585,13 +585,13 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.115.5" +version = "0.115.6" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.115.5-py3-none-any.whl", hash = "sha256:596b95adbe1474da47049e802f9a65ab2ffa9c2b07e7efee70eb8a66c9f2f796"}, - {file = "fastapi-0.115.5.tar.gz", hash = "sha256:0e7a4d0dc0d01c68df21887cce0945e72d3c48b9f4f79dfe7a7d53aa08fbb289"}, + {file = "fastapi-0.115.6-py3-none-any.whl", hash = "sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305"}, + {file = "fastapi-0.115.6.tar.gz", hash = "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654"}, ] [package.dependencies] @@ -760,13 +760,13 @@ trio = ["trio (>=0.22.0,<1.0)"] [[package]] name = "httpx" -version = "0.27.2" +version = "0.28.1" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"}, - {file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"}, + {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, + {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, ] [package.dependencies] @@ -774,7 +774,6 @@ anyio = "*" certifi = "*" httpcore = "==1.*" idna = "*" -sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] @@ -785,13 +784,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "identify" -version = "2.6.2" +version = "2.6.3" description = "File identification library for Python" optional = false python-versions = ">=3.9" files = [ - {file = "identify-2.6.2-py2.py3-none-any.whl", hash = "sha256:c097384259f49e372f4ea00a19719d95ae27dd5ff0fd77ad630aa891306b82f3"}, - {file = "identify-2.6.2.tar.gz", hash = "sha256:fab5c716c24d7a789775228823797296a2994b075fb6080ac83a102772a98cbd"}, + {file = "identify-2.6.3-py2.py3-none-any.whl", hash = "sha256:9edba65473324c2ea9684b1f944fe3191db3345e50b6d04571d10ed164f8d7bd"}, + {file = "identify-2.6.3.tar.gz", hash = "sha256:62f5dae9b5fef52c84cc188514e9ea4f3f636b1d8799ab5ebc475471f9e47a02"}, ] [package.extras] @@ -985,13 +984,13 @@ test = ["pytest (>=7.4)", "pytest-cov (>=4.1)"] [[package]] name = "mako" -version = "1.3.6" +version = "1.3.8" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." optional = false python-versions = ">=3.8" files = [ - {file = "Mako-1.3.6-py3-none-any.whl", hash = "sha256:a91198468092a2f1a0de86ca92690fb0cfc43ca90ee17e15d93662b4c04b241a"}, - {file = "mako-1.3.6.tar.gz", hash = "sha256:9ec3a1583713479fae654f83ed9fa8c9a4c16b7bb0daba0e6bbebff50c0d983d"}, + {file = "Mako-1.3.8-py3-none-any.whl", hash = "sha256:42f48953c7eb91332040ff567eb7eea69b22e7a4affbc5ba8e845e8f730f6627"}, + {file = "mako-1.3.8.tar.gz", hash = "sha256:577b97e414580d3e088d47c2dbbe9594aa7a5146ed2875d4dfa9075af2dd3cc8"}, ] [package.dependencies] @@ -1120,27 +1119,34 @@ files = [ [[package]] name = "nh3" -version = "0.2.18" +version = "0.2.19" description = "Python bindings to the ammonia HTML sanitization library." optional = false python-versions = "*" files = [ - {file = "nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86"}, - {file = "nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811"}, - {file = "nh3-0.2.18-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200"}, - {file = "nh3-0.2.18-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164"}, - {file = "nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189"}, - {file = "nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad"}, - {file = "nh3-0.2.18-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b"}, - {file = "nh3-0.2.18-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307"}, - {file = "nh3-0.2.18-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6955369e4d9f48f41e3f238a9e60f9410645db7e07435e62c6a9ea6135a4907f"}, - {file = "nh3-0.2.18-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe"}, - {file = "nh3-0.2.18-cp37-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a"}, - {file = "nh3-0.2.18-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:c8b3a1cebcba9b3669ed1a84cc65bf005728d2f0bc1ed2a6594a992e817f3a50"}, - {file = "nh3-0.2.18-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204"}, - {file = "nh3-0.2.18-cp37-abi3-win32.whl", hash = "sha256:a7f1b5b2c15866f2db413a3649a8fe4fd7b428ae58be2c0f6bca5eefd53ca2be"}, - {file = "nh3-0.2.18-cp37-abi3-win_amd64.whl", hash = "sha256:8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844"}, - {file = "nh3-0.2.18.tar.gz", hash = "sha256:94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4"}, + {file = "nh3-0.2.19-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:ec9c8bf86e397cb88c560361f60fdce478b5edb8b93f04ead419b72fbe937ea6"}, + {file = "nh3-0.2.19-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0adf00e2b2026fa10a42537b60d161e516f206781c7515e4e97e09f72a8c5d0"}, + {file = "nh3-0.2.19-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3805161c4e12088bd74752ba69630e915bc30fe666034f47217a2f16b16efc37"}, + {file = "nh3-0.2.19-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3dedd7858a21312f7675841529941035a2ac91057db13402c8fe907aa19205a"}, + {file = "nh3-0.2.19-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:0b6820fc64f2ff7ef3e7253a093c946a87865c877b3889149a6d21d322ed8dbd"}, + {file = "nh3-0.2.19-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:833b3b5f1783ce95834a13030300cea00cbdfd64ea29260d01af9c4821da0aa9"}, + {file = "nh3-0.2.19-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5d4f5e2189861b352b73acb803b5f4bb409c2f36275d22717e27d4e0c217ae55"}, + {file = "nh3-0.2.19-cp313-cp313t-win32.whl", hash = "sha256:2b926f179eb4bce72b651bfdf76f8aa05d167b2b72bc2f3657fd319f40232adc"}, + {file = "nh3-0.2.19-cp313-cp313t-win_amd64.whl", hash = "sha256:ac536a4b5c073fdadd8f5f4889adabe1cbdae55305366fb870723c96ca7f49c3"}, + {file = "nh3-0.2.19-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:c2e3f0d18cc101132fe10ab7ef5c4f41411297e639e23b64b5e888ccaad63f41"}, + {file = "nh3-0.2.19-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11270b16c1b012677e3e2dd166c1aa273388776bf99a3e3677179db5097ee16a"}, + {file = "nh3-0.2.19-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fc483dd8d20f8f8c010783a25a84db3bebeadced92d24d34b40d687f8043ac69"}, + {file = "nh3-0.2.19-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d53a4577b6123ca1d7e8483fad3e13cb7eda28913d516bd0a648c1a473aa21a9"}, + {file = "nh3-0.2.19-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fdb20740d24ab9f2a1341458a00a11205294e97e905de060eeab1ceca020c09c"}, + {file = "nh3-0.2.19-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d8325d51e47cb5b11f649d55e626d56c76041ba508cd59e0cb1cf687cc7612f1"}, + {file = "nh3-0.2.19-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8eb7affc590e542fa7981ef508cd1644f62176bcd10d4429890fc629b47f0bc"}, + {file = "nh3-0.2.19-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2eb021804e9df1761abeb844bb86648d77aa118a663c82f50ea04110d87ed707"}, + {file = "nh3-0.2.19-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a7b928862daddb29805a1010a0282f77f4b8b238a37b5f76bc6c0d16d930fd22"}, + {file = "nh3-0.2.19-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:ed06ed78f6b69d57463b46a04f68f270605301e69d80756a8adf7519002de57d"}, + {file = "nh3-0.2.19-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:df8eac98fec80bd6f5fd0ae27a65de14f1e1a65a76d8e2237eb695f9cd1121d9"}, + {file = "nh3-0.2.19-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:00810cd5275f5c3f44b9eb0e521d1a841ee2f8023622de39ffc7d88bd533d8e0"}, + {file = "nh3-0.2.19-cp38-abi3-win32.whl", hash = "sha256:7e98621856b0a911c21faa5eef8f8ea3e691526c2433f9afc2be713cb6fbdb48"}, + {file = "nh3-0.2.19-cp38-abi3-win_amd64.whl", hash = "sha256:75c7cafb840f24430b009f7368945cb5ca88b2b54bb384ebfba495f16bc9c121"}, ] [[package]] @@ -1210,66 +1216,66 @@ files = [ [[package]] name = "numpy" -version = "2.1.3" +version = "2.2.0" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.10" files = [ - {file = "numpy-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c894b4305373b9c5576d7a12b473702afdf48ce5369c074ba304cc5ad8730dff"}, - {file = "numpy-2.1.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b47fbb433d3260adcd51eb54f92a2ffbc90a4595f8970ee00e064c644ac788f5"}, - {file = "numpy-2.1.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:825656d0743699c529c5943554d223c021ff0494ff1442152ce887ef4f7561a1"}, - {file = "numpy-2.1.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a4825252fcc430a182ac4dee5a505053d262c807f8a924603d411f6718b88fd"}, - {file = "numpy-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e711e02f49e176a01d0349d82cb5f05ba4db7d5e7e0defd026328e5cfb3226d3"}, - {file = "numpy-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78574ac2d1a4a02421f25da9559850d59457bac82f2b8d7a44fe83a64f770098"}, - {file = "numpy-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c7662f0e3673fe4e832fe07b65c50342ea27d989f92c80355658c7f888fcc83c"}, - {file = "numpy-2.1.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fa2d1337dc61c8dc417fbccf20f6d1e139896a30721b7f1e832b2bb6ef4eb6c4"}, - {file = "numpy-2.1.3-cp310-cp310-win32.whl", hash = "sha256:72dcc4a35a8515d83e76b58fdf8113a5c969ccd505c8a946759b24e3182d1f23"}, - {file = "numpy-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:ecc76a9ba2911d8d37ac01de72834d8849e55473457558e12995f4cd53e778e0"}, - {file = "numpy-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4d1167c53b93f1f5d8a139a742b3c6f4d429b54e74e6b57d0eff40045187b15d"}, - {file = "numpy-2.1.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c80e4a09b3d95b4e1cac08643f1152fa71a0a821a2d4277334c88d54b2219a41"}, - {file = "numpy-2.1.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:576a1c1d25e9e02ed7fa5477f30a127fe56debd53b8d2c89d5578f9857d03ca9"}, - {file = "numpy-2.1.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:973faafebaae4c0aaa1a1ca1ce02434554d67e628b8d805e61f874b84e136b09"}, - {file = "numpy-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:762479be47a4863e261a840e8e01608d124ee1361e48b96916f38b119cfda04a"}, - {file = "numpy-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f24b3d1ecc1eebfbf5d6051faa49af40b03be1aaa781ebdadcbc090b4539b"}, - {file = "numpy-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:17ee83a1f4fef3c94d16dc1802b998668b5419362c8a4f4e8a491de1b41cc3ee"}, - {file = "numpy-2.1.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15cb89f39fa6d0bdfb600ea24b250e5f1a3df23f901f51c8debaa6a5d122b2f0"}, - {file = "numpy-2.1.3-cp311-cp311-win32.whl", hash = "sha256:d9beb777a78c331580705326d2367488d5bc473b49a9bc3036c154832520aca9"}, - {file = "numpy-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:d89dd2b6da69c4fff5e39c28a382199ddedc3a5be5390115608345dec660b9e2"}, - {file = "numpy-2.1.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f55ba01150f52b1027829b50d70ef1dafd9821ea82905b63936668403c3b471e"}, - {file = "numpy-2.1.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13138eadd4f4da03074851a698ffa7e405f41a0845a6b1ad135b81596e4e9958"}, - {file = "numpy-2.1.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:a6b46587b14b888e95e4a24d7b13ae91fa22386c199ee7b418f449032b2fa3b8"}, - {file = "numpy-2.1.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:0fa14563cc46422e99daef53d725d0c326e99e468a9320a240affffe87852564"}, - {file = "numpy-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8637dcd2caa676e475503d1f8fdb327bc495554e10838019651b76d17b98e512"}, - {file = "numpy-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2312b2aa89e1f43ecea6da6ea9a810d06aae08321609d8dc0d0eda6d946a541b"}, - {file = "numpy-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a38c19106902bb19351b83802531fea19dee18e5b37b36454f27f11ff956f7fc"}, - {file = "numpy-2.1.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02135ade8b8a84011cbb67dc44e07c58f28575cf9ecf8ab304e51c05528c19f0"}, - {file = "numpy-2.1.3-cp312-cp312-win32.whl", hash = "sha256:e6988e90fcf617da2b5c78902fe8e668361b43b4fe26dbf2d7b0f8034d4cafb9"}, - {file = "numpy-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:0d30c543f02e84e92c4b1f415b7c6b5326cbe45ee7882b6b77db7195fb971e3a"}, - {file = "numpy-2.1.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96fe52fcdb9345b7cd82ecd34547fca4321f7656d500eca497eb7ea5a926692f"}, - {file = "numpy-2.1.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f653490b33e9c3a4c1c01d41bc2aef08f9475af51146e4a7710c450cf9761598"}, - {file = "numpy-2.1.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:dc258a761a16daa791081d026f0ed4399b582712e6fc887a95af09df10c5ca57"}, - {file = "numpy-2.1.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:016d0f6f5e77b0f0d45d77387ffa4bb89816b57c835580c3ce8e099ef830befe"}, - {file = "numpy-2.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c181ba05ce8299c7aa3125c27b9c2167bca4a4445b7ce73d5febc411ca692e43"}, - {file = "numpy-2.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5641516794ca9e5f8a4d17bb45446998c6554704d888f86df9b200e66bdcce56"}, - {file = "numpy-2.1.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ea4dedd6e394a9c180b33c2c872b92f7ce0f8e7ad93e9585312b0c5a04777a4a"}, - {file = "numpy-2.1.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0df3635b9c8ef48bd3be5f862cf71b0a4716fa0e702155c45067c6b711ddcef"}, - {file = "numpy-2.1.3-cp313-cp313-win32.whl", hash = "sha256:50ca6aba6e163363f132b5c101ba078b8cbd3fa92c7865fd7d4d62d9779ac29f"}, - {file = "numpy-2.1.3-cp313-cp313-win_amd64.whl", hash = "sha256:747641635d3d44bcb380d950679462fae44f54b131be347d5ec2bce47d3df9ed"}, - {file = "numpy-2.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:996bb9399059c5b82f76b53ff8bb686069c05acc94656bb259b1d63d04a9506f"}, - {file = "numpy-2.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:45966d859916ad02b779706bb43b954281db43e185015df6eb3323120188f9e4"}, - {file = "numpy-2.1.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:baed7e8d7481bfe0874b566850cb0b85243e982388b7b23348c6db2ee2b2ae8e"}, - {file = "numpy-2.1.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a9f7f672a3388133335589cfca93ed468509cb7b93ba3105fce780d04a6576a0"}, - {file = "numpy-2.1.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7aac50327da5d208db2eec22eb11e491e3fe13d22653dce51b0f4109101b408"}, - {file = "numpy-2.1.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4394bc0dbd074b7f9b52024832d16e019decebf86caf909d94f6b3f77a8ee3b6"}, - {file = "numpy-2.1.3-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:50d18c4358a0a8a53f12a8ba9d772ab2d460321e6a93d6064fc22443d189853f"}, - {file = "numpy-2.1.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:14e253bd43fc6b37af4921b10f6add6925878a42a0c5fe83daee390bca80bc17"}, - {file = "numpy-2.1.3-cp313-cp313t-win32.whl", hash = "sha256:08788d27a5fd867a663f6fc753fd7c3ad7e92747efc73c53bca2f19f8bc06f48"}, - {file = "numpy-2.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2564fbdf2b99b3f815f2107c1bbc93e2de8ee655a69c261363a1172a79a257d4"}, - {file = "numpy-2.1.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4f2015dfe437dfebbfce7c85c7b53d81ba49e71ba7eadbf1df40c915af75979f"}, - {file = "numpy-2.1.3-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:3522b0dfe983a575e6a9ab3a4a4dfe156c3e428468ff08ce582b9bb6bd1d71d4"}, - {file = "numpy-2.1.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c006b607a865b07cd981ccb218a04fc86b600411d83d6fc261357f1c0966755d"}, - {file = "numpy-2.1.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e14e26956e6f1696070788252dcdff11b4aca4c3e8bd166e0df1bb8f315a67cb"}, - {file = "numpy-2.1.3.tar.gz", hash = "sha256:aa08e04e08aaf974d4458def539dece0d28146d866a39da5639596f4921fd761"}, + {file = "numpy-2.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1e25507d85da11ff5066269d0bd25d06e0a0f2e908415534f3e603d2a78e4ffa"}, + {file = "numpy-2.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a62eb442011776e4036af5c8b1a00b706c5bc02dc15eb5344b0c750428c94219"}, + {file = "numpy-2.2.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:b606b1aaf802e6468c2608c65ff7ece53eae1a6874b3765f69b8ceb20c5fa78e"}, + {file = "numpy-2.2.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:36b2b43146f646642b425dd2027730f99bac962618ec2052932157e213a040e9"}, + {file = "numpy-2.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fe8f3583e0607ad4e43a954e35c1748b553bfe9fdac8635c02058023277d1b3"}, + {file = "numpy-2.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:122fd2fcfafdefc889c64ad99c228d5a1f9692c3a83f56c292618a59aa60ae83"}, + {file = "numpy-2.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3f2f5cddeaa4424a0a118924b988746db6ffa8565e5829b1841a8a3bd73eb59a"}, + {file = "numpy-2.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7fe4bb0695fe986a9e4deec3b6857003b4cfe5c5e4aac0b95f6a658c14635e31"}, + {file = "numpy-2.2.0-cp310-cp310-win32.whl", hash = "sha256:b30042fe92dbd79f1ba7f6898fada10bdaad1847c44f2dff9a16147e00a93661"}, + {file = "numpy-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:54dc1d6d66f8d37843ed281773c7174f03bf7ad826523f73435deb88ba60d2d4"}, + {file = "numpy-2.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9874bc2ff574c40ab7a5cbb7464bf9b045d617e36754a7bc93f933d52bd9ffc6"}, + {file = "numpy-2.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0da8495970f6b101ddd0c38ace92edea30e7e12b9a926b57f5fabb1ecc25bb90"}, + {file = "numpy-2.2.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:0557eebc699c1c34cccdd8c3778c9294e8196df27d713706895edc6f57d29608"}, + {file = "numpy-2.2.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:3579eaeb5e07f3ded59298ce22b65f877a86ba8e9fe701f5576c99bb17c283da"}, + {file = "numpy-2.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40deb10198bbaa531509aad0cd2f9fadb26c8b94070831e2208e7df543562b74"}, + {file = "numpy-2.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2aed8fcf8abc3020d6a9ccb31dbc9e7d7819c56a348cc88fd44be269b37427e"}, + {file = "numpy-2.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a222d764352c773aa5ebde02dd84dba3279c81c6db2e482d62a3fa54e5ece69b"}, + {file = "numpy-2.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4e58666988605e251d42c2818c7d3d8991555381be26399303053b58a5bbf30d"}, + {file = "numpy-2.2.0-cp311-cp311-win32.whl", hash = "sha256:4723a50e1523e1de4fccd1b9a6dcea750c2102461e9a02b2ac55ffeae09a4410"}, + {file = "numpy-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:16757cf28621e43e252c560d25b15f18a2f11da94fea344bf26c599b9cf54b73"}, + {file = "numpy-2.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cff210198bb4cae3f3c100444c5eaa573a823f05c253e7188e1362a5555235b3"}, + {file = "numpy-2.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58b92a5828bd4d9aa0952492b7de803135038de47343b2aa3cc23f3b71a3dc4e"}, + {file = "numpy-2.2.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:ebe5e59545401fbb1b24da76f006ab19734ae71e703cdb4a8b347e84a0cece67"}, + {file = "numpy-2.2.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:e2b8cd48a9942ed3f85b95ca4105c45758438c7ed28fff1e4ce3e57c3b589d8e"}, + {file = "numpy-2.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57fcc997ffc0bef234b8875a54d4058afa92b0b0c4223fc1f62f24b3b5e86038"}, + {file = "numpy-2.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ad7d11b309bd132d74397fcf2920933c9d1dc865487128f5c03d580f2c3d03"}, + {file = "numpy-2.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cb24cca1968b21355cc6f3da1a20cd1cebd8a023e3c5b09b432444617949085a"}, + {file = "numpy-2.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0798b138c291d792f8ea40fe3768610f3c7dd2574389e37c3f26573757c8f7ef"}, + {file = "numpy-2.2.0-cp312-cp312-win32.whl", hash = "sha256:afe8fb968743d40435c3827632fd36c5fbde633b0423da7692e426529b1759b1"}, + {file = "numpy-2.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:3a4199f519e57d517ebd48cb76b36c82da0360781c6a0353e64c0cac30ecaad3"}, + {file = "numpy-2.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f8c8b141ef9699ae777c6278b52c706b653bf15d135d302754f6b2e90eb30367"}, + {file = "numpy-2.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f0986e917aca18f7a567b812ef7ca9391288e2acb7a4308aa9d265bd724bdae"}, + {file = "numpy-2.2.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:1c92113619f7b272838b8d6702a7f8ebe5edea0df48166c47929611d0b4dea69"}, + {file = "numpy-2.2.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:5a145e956b374e72ad1dff82779177d4a3c62bc8248f41b80cb5122e68f22d13"}, + {file = "numpy-2.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18142b497d70a34b01642b9feabb70156311b326fdddd875a9981f34a369b671"}, + {file = "numpy-2.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7d41d1612c1a82b64697e894b75db6758d4f21c3ec069d841e60ebe54b5b571"}, + {file = "numpy-2.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a98f6f20465e7618c83252c02041517bd2f7ea29be5378f09667a8f654a5918d"}, + {file = "numpy-2.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e09d40edfdb4e260cb1567d8ae770ccf3b8b7e9f0d9b5c2a9992696b30ce2742"}, + {file = "numpy-2.2.0-cp313-cp313-win32.whl", hash = "sha256:3905a5fffcc23e597ee4d9fb3fcd209bd658c352657548db7316e810ca80458e"}, + {file = "numpy-2.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:a184288538e6ad699cbe6b24859206e38ce5fba28f3bcfa51c90d0502c1582b2"}, + {file = "numpy-2.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7832f9e8eb00be32f15fdfb9a981d6955ea9adc8574c521d48710171b6c55e95"}, + {file = "numpy-2.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f0dd071b95bbca244f4cb7f70b77d2ff3aaaba7fa16dc41f58d14854a6204e6c"}, + {file = "numpy-2.2.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:b0b227dcff8cdc3efbce66d4e50891f04d0a387cce282fe1e66199146a6a8fca"}, + {file = "numpy-2.2.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6ab153263a7c5ccaf6dfe7e53447b74f77789f28ecb278c3b5d49db7ece10d6d"}, + {file = "numpy-2.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e500aba968a48e9019e42c0c199b7ec0696a97fa69037bea163b55398e390529"}, + {file = "numpy-2.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:440cfb3db4c5029775803794f8638fbdbf71ec702caf32735f53b008e1eaece3"}, + {file = "numpy-2.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a55dc7a7f0b6198b07ec0cd445fbb98b05234e8b00c5ac4874a63372ba98d4ab"}, + {file = "numpy-2.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4bddbaa30d78c86329b26bd6aaaea06b1e47444da99eddac7bf1e2fab717bd72"}, + {file = "numpy-2.2.0-cp313-cp313t-win32.whl", hash = "sha256:30bf971c12e4365153afb31fc73f441d4da157153f3400b82db32d04de1e4066"}, + {file = "numpy-2.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:d35717333b39d1b6bb8433fa758a55f1081543de527171543a2b710551d40881"}, + {file = "numpy-2.2.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e12c6c1ce84628c52d6367863773f7c8c8241be554e8b79686e91a43f1733773"}, + {file = "numpy-2.2.0-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:b6207dc8fb3c8cb5668e885cef9ec7f70189bec4e276f0ff70d5aa078d32c88e"}, + {file = "numpy-2.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a50aeff71d0f97b6450d33940c7181b08be1441c6c193e678211bff11aa725e7"}, + {file = "numpy-2.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:df12a1f99b99f569a7c2ae59aa2d31724e8d835fc7f33e14f4792e3071d11221"}, + {file = "numpy-2.2.0.tar.gz", hash = "sha256:140dd80ff8981a583a60980be1a655068f8adebf7a45a06a6858c873fcdcd4a0"}, ] [[package]] @@ -1506,13 +1512,13 @@ test = ["covdefaults (>=2.3)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pyte [[package]] name = "pkginfo" -version = "1.10.0" +version = "1.12.0" description = "Query metadata from sdists / bdists / installed packages." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "pkginfo-1.10.0-py3-none-any.whl", hash = "sha256:889a6da2ed7ffc58ab5b900d888ddce90bce912f2d2de1dc1c26f4cb9fe65097"}, - {file = "pkginfo-1.10.0.tar.gz", hash = "sha256:5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297"}, + {file = "pkginfo-1.12.0-py3-none-any.whl", hash = "sha256:dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088"}, + {file = "pkginfo-1.12.0.tar.gz", hash = "sha256:8ad91a0445a036782b9366ef8b8c2c50291f83a553478ba8580c73d3215700cf"}, ] [package.extras] @@ -1536,18 +1542,18 @@ type = ["mypy (>=1.11.2)"] [[package]] name = "playwright" -version = "1.48.0" +version = "1.49.0" description = "A high-level API to automate web browsers" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "playwright-1.48.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:082bce2739f1078acc7d0734da8cc0e23eb91b7fae553f3316d733276f09a6b1"}, - {file = "playwright-1.48.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7da2eb51a19c7f3b523e9faa9d98e7af92e52eb983a099979ea79c9668e3cbf7"}, - {file = "playwright-1.48.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:115b988d1da322358b77bc3bf2d3cc90f8c881e691461538e7df91614c4833c9"}, - {file = "playwright-1.48.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:8dabb80e62f667fe2640a8b694e26a7b884c0b4803f7514a3954fc849126227b"}, - {file = "playwright-1.48.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ff8303409ebed76bed4c3d655340320b768817d900ba208b394fdd7d7939a5c"}, - {file = "playwright-1.48.0-py3-none-win32.whl", hash = "sha256:85598c360c590076d4f435525be991246d74a905b654ac19d26eab7ed9b98b2d"}, - {file = "playwright-1.48.0-py3-none-win_amd64.whl", hash = "sha256:e0e87b0c4dc8fce83c725dd851aec37bc4e882bb225ec8a96bd83cf32d4f1623"}, + {file = "playwright-1.49.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:704532a2d8ba580ec9e1895bfeafddce2e3d52320d4eb8aa38e80376acc5cbb0"}, + {file = "playwright-1.49.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e453f02c4e5cc2db7e9759c47e7425f32e50ac76c76b7eb17c69eed72f01c4d8"}, + {file = "playwright-1.49.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:37ae985309184472946a6eb1a237e5d93c9e58a781fa73b75c8751325002a5d4"}, + {file = "playwright-1.49.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:68d94beffb3c9213e3ceaafa66171affd9a5d9162e0c8a3eed1b1132c2e57598"}, + {file = "playwright-1.49.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f12d2aecdb41fc25a624cb15f3e8391c252ebd81985e3d5c1c261fe93779345"}, + {file = "playwright-1.49.0-py3-none-win32.whl", hash = "sha256:91103de52d470594ad375b512d7143fa95d6039111ae11a93eb4fe2f2b4a4858"}, + {file = "playwright-1.49.0-py3-none-win_amd64.whl", hash = "sha256:34d28a2c2d46403368610be4339898dc9c34eb9f7c578207b4715c49743a072a"}, ] [package.dependencies] @@ -1656,13 +1662,13 @@ files = [ [[package]] name = "pydantic" -version = "2.10.1" +version = "2.10.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.10.1-py3-none-any.whl", hash = "sha256:a8d20db84de64cf4a7d59e899c2caf0fe9d660c7cfc482528e7020d7dd189a7e"}, - {file = "pydantic-2.10.1.tar.gz", hash = "sha256:a4daca2dc0aa429555e0656d6bf94873a7dc5f54ee42b1f5873d666fb3f35560"}, + {file = "pydantic-2.10.3-py3-none-any.whl", hash = "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d"}, + {file = "pydantic-2.10.3.tar.gz", hash = "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9"}, ] [package.dependencies] @@ -1860,13 +1866,13 @@ files = [ [[package]] name = "pytest" -version = "8.3.3" +version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, - {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, ] [package.dependencies] @@ -1973,13 +1979,13 @@ dev = ["pre-commit", "pytest-asyncio", "tox"] [[package]] name = "pytest-playwright" -version = "0.5.2" +version = "0.6.2" description = "A pytest wrapper with fixtures for Playwright to automate web browsers" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pytest_playwright-0.5.2-py3-none-any.whl", hash = "sha256:2c5720591364a1cdf66610b972ff8492512bc380953e043c85f705b78b2ed582"}, - {file = "pytest_playwright-0.5.2.tar.gz", hash = "sha256:c6d603df9e6c50b35f057b0528e11d41c0963283e98c257267117f5ed6ba1924"}, + {file = "pytest_playwright-0.6.2-py3-none-any.whl", hash = "sha256:0eff73bebe497b0158befed91e2f5fe94cfa17181f8b3acf575beed84e7e9043"}, + {file = "pytest_playwright-0.6.2.tar.gz", hash = "sha256:ff4054b19aa05df096ac6f74f0572591566aaf0f6d97f6cb9674db8a4d4ed06c"}, ] [package.dependencies] @@ -2023,13 +2029,13 @@ docs = ["sphinx"] [[package]] name = "python-multipart" -version = "0.0.17" +version = "0.0.19" description = "A streaming multipart parser for Python" optional = false python-versions = ">=3.8" files = [ - {file = "python_multipart-0.0.17-py3-none-any.whl", hash = "sha256:15dc4f487e0a9476cc1201261188ee0940165cffc94429b6fc565c4d3045cb5d"}, - {file = "python_multipart-0.0.17.tar.gz", hash = "sha256:41330d831cae6e2f22902704ead2826ea038d0419530eadff3ea80175aec5538"}, + {file = "python_multipart-0.0.19-py3-none-any.whl", hash = "sha256:f8d5b0b9c618575bf9df01c684ded1d94a338839bdd8223838afacfb4bb2082d"}, + {file = "python_multipart-0.0.19.tar.gz", hash = "sha256:905502ef39050557b7a6af411f454bc19526529ca46ae6831508438890ce12cc"}, ] [[package]] @@ -2174,13 +2180,13 @@ md = ["cmarkgfm (>=0.8.0)"] [[package]] name = "redis" -version = "5.2.0" +version = "5.2.1" description = "Python client for Redis database and key-value store" optional = false python-versions = ">=3.8" files = [ - {file = "redis-5.2.0-py3-none-any.whl", hash = "sha256:ae174f2bb3b1bf2b09d54bf3e51fbc1469cf6c10aa03e21141f51969801a7897"}, - {file = "redis-5.2.0.tar.gz", hash = "sha256:0b1087665a771b1ff2e003aa5bdd354f15a70c9e25d5a7dbf9c722c16528a7b0"}, + {file = "redis-5.2.1-py3-none-any.whl", hash = "sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4"}, + {file = "redis-5.2.1.tar.gz", hash = "sha256:16f2e22dff21d5125e8481515e386711a34cbec50f0e44413dd7d9c060a54e0f"}, ] [package.dependencies] @@ -2206,13 +2212,13 @@ reflex = ">=0.6.0a" [[package]] name = "reflex-hosting-cli" -version = "0.1.29" +version = "0.1.30" description = "Reflex Hosting CLI" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "reflex_hosting_cli-0.1.29-py3-none-any.whl", hash = "sha256:fcbdad829762287f32397cd8a5d46536ab0db396e7fdb8a23c7f9343d7dc8de0"}, - {file = "reflex_hosting_cli-0.1.29.tar.gz", hash = "sha256:7b421fec6936c26549c8c65c9dda34fc042eaaec79b238dce6b9c020f848563b"}, + {file = "reflex_hosting_cli-0.1.30-py3-none-any.whl", hash = "sha256:778c98d635003d8668158c22eaa0f7124d2bac92c8a1aabaed710960ca97796e"}, + {file = "reflex_hosting_cli-0.1.30.tar.gz", hash = "sha256:a0fdc73e595e6b9fd661e1307ae37267fb3815cc457b7f15938ba921c12fc0b6"}, ] [package.dependencies] @@ -2297,29 +2303,29 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "ruff" -version = "0.7.4" +version = "0.8.2" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.7.4-py3-none-linux_armv6l.whl", hash = "sha256:a4919925e7684a3f18e18243cd6bea7cfb8e968a6eaa8437971f681b7ec51478"}, - {file = "ruff-0.7.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:cfb365c135b830778dda8c04fb7d4280ed0b984e1aec27f574445231e20d6c63"}, - {file = "ruff-0.7.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:63a569b36bc66fbadec5beaa539dd81e0527cb258b94e29e0531ce41bacc1f20"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d06218747d361d06fd2fdac734e7fa92df36df93035db3dc2ad7aa9852cb109"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0cea28d0944f74ebc33e9f934238f15c758841f9f5edd180b5315c203293452"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80094ecd4793c68b2571b128f91754d60f692d64bc0d7272ec9197fdd09bf9ea"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:997512325c6620d1c4c2b15db49ef59543ef9cd0f4aa8065ec2ae5103cedc7e7"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00b4cf3a6b5fad6d1a66e7574d78956bbd09abfd6c8a997798f01f5da3d46a05"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7dbdc7d8274e1422722933d1edddfdc65b4336abf0b16dfcb9dedd6e6a517d06"}, - {file = "ruff-0.7.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e92dfb5f00eaedb1501b2f906ccabfd67b2355bdf117fea9719fc99ac2145bc"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3bd726099f277d735dc38900b6a8d6cf070f80828877941983a57bca1cd92172"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2e32829c429dd081ee5ba39aef436603e5b22335c3d3fff013cd585806a6486a"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:662a63b4971807623f6f90c1fb664613f67cc182dc4d991471c23c541fee62dd"}, - {file = "ruff-0.7.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:876f5e09eaae3eb76814c1d3b68879891d6fde4824c015d48e7a7da4cf066a3a"}, - {file = "ruff-0.7.4-py3-none-win32.whl", hash = "sha256:75c53f54904be42dd52a548728a5b572344b50d9b2873d13a3f8c5e3b91f5cac"}, - {file = "ruff-0.7.4-py3-none-win_amd64.whl", hash = "sha256:745775c7b39f914238ed1f1b0bebed0b9155a17cd8bc0b08d3c87e4703b990d6"}, - {file = "ruff-0.7.4-py3-none-win_arm64.whl", hash = "sha256:11bff065102c3ae9d3ea4dc9ecdfe5a5171349cdd0787c1fc64761212fc9cf1f"}, - {file = "ruff-0.7.4.tar.gz", hash = "sha256:cd12e35031f5af6b9b93715d8c4f40360070b2041f81273d0527683d5708fce2"}, + {file = "ruff-0.8.2-py3-none-linux_armv6l.whl", hash = "sha256:c49ab4da37e7c457105aadfd2725e24305ff9bc908487a9bf8d548c6dad8bb3d"}, + {file = "ruff-0.8.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ec016beb69ac16be416c435828be702ee694c0d722505f9c1f35e1b9c0cc1bf5"}, + {file = "ruff-0.8.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f05cdf8d050b30e2ba55c9b09330b51f9f97d36d4673213679b965d25a785f3c"}, + {file = "ruff-0.8.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60f578c11feb1d3d257b2fb043ddb47501ab4816e7e221fbb0077f0d5d4e7b6f"}, + {file = "ruff-0.8.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbd5cf9b0ae8f30eebc7b360171bd50f59ab29d39f06a670b3e4501a36ba5897"}, + {file = "ruff-0.8.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b402ddee3d777683de60ff76da801fa7e5e8a71038f57ee53e903afbcefdaa58"}, + {file = "ruff-0.8.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:705832cd7d85605cb7858d8a13d75993c8f3ef1397b0831289109e953d833d29"}, + {file = "ruff-0.8.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:32096b41aaf7a5cc095fa45b4167b890e4c8d3fd217603f3634c92a541de7248"}, + {file = "ruff-0.8.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e769083da9439508833cfc7c23e351e1809e67f47c50248250ce1ac52c21fb93"}, + {file = "ruff-0.8.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fe716592ae8a376c2673fdfc1f5c0c193a6d0411f90a496863c99cd9e2ae25d"}, + {file = "ruff-0.8.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:81c148825277e737493242b44c5388a300584d73d5774defa9245aaef55448b0"}, + {file = "ruff-0.8.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d261d7850c8367704874847d95febc698a950bf061c9475d4a8b7689adc4f7fa"}, + {file = "ruff-0.8.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1ca4e3a87496dc07d2427b7dd7ffa88a1e597c28dad65ae6433ecb9f2e4f022f"}, + {file = "ruff-0.8.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:729850feed82ef2440aa27946ab39c18cb4a8889c1128a6d589ffa028ddcfc22"}, + {file = "ruff-0.8.2-py3-none-win32.whl", hash = "sha256:ac42caaa0411d6a7d9594363294416e0e48fc1279e1b0e948391695db2b3d5b1"}, + {file = "ruff-0.8.2-py3-none-win_amd64.whl", hash = "sha256:2aae99ec70abf43372612a838d97bfe77d45146254568d94926e8ed5bbb409ea"}, + {file = "ruff-0.8.2-py3-none-win_arm64.whl", hash = "sha256:fb88e2a506b70cfbc2de6fae6681c4f944f7dd5f2fe87233a7233d888bad73e8"}, + {file = "ruff-0.8.2.tar.gz", hash = "sha256:b84f4f414dda8ac7f75075c1fa0b905ac0ff25361f42e6d5da681a465e0f78e5"}, ] [[package]] @@ -2339,13 +2345,13 @@ jeepney = ">=0.6" [[package]] name = "selenium" -version = "4.26.1" +version = "4.27.1" description = "Official Python bindings for Selenium WebDriver" optional = false python-versions = ">=3.8" files = [ - {file = "selenium-4.26.1-py3-none-any.whl", hash = "sha256:1db3f3a0cd5bb07624fa8a3905a6fdde1595a42185a0617077c361dc53d104fb"}, - {file = "selenium-4.26.1.tar.gz", hash = "sha256:7640f3f08ae7f4e450f895678e8a10a55eb4e4ca18311ed675ecc4684b96b683"}, + {file = "selenium-4.27.1-py3-none-any.whl", hash = "sha256:b89b1f62b5cfe8025868556fe82360d6b649d464f75d2655cb966c8f8447ea18"}, + {file = "selenium-4.27.1.tar.gz", hash = "sha256:5296c425a75ff1b44d0d5199042b36a6d1ef76c04fb775b97b40be739a9caae2"}, ] [package.dependencies] @@ -2407,13 +2413,13 @@ docs = ["sphinx"] [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] @@ -2642,13 +2648,43 @@ files = [ [[package]] name = "tomli" -version = "2.1.0" +version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" files = [ - {file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"}, - {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] [[package]] @@ -2700,19 +2736,20 @@ wsproto = ">=0.14" [[package]] name = "twine" -version = "5.1.1" +version = "6.0.1" description = "Collection of utilities for publishing packages on PyPI" optional = false python-versions = ">=3.8" files = [ - {file = "twine-5.1.1-py3-none-any.whl", hash = "sha256:215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997"}, - {file = "twine-5.1.1.tar.gz", hash = "sha256:9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db"}, + {file = "twine-6.0.1-py3-none-any.whl", hash = "sha256:9c6025b203b51521d53e200f4a08b116dee7500a38591668c6a6033117bdc218"}, + {file = "twine-6.0.1.tar.gz", hash = "sha256:36158b09df5406e1c9c1fb8edb24fc2be387709443e7376689b938531582ee27"}, ] [package.dependencies] -importlib-metadata = ">=3.6" -keyring = ">=15.1" -pkginfo = ">=1.8.1,<1.11" +importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""} +keyring = {version = ">=15.1", markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\""} +packaging = "*" +pkginfo = ">=1.8.1" readme-renderer = ">=35.0" requests = ">=2.20" requests-toolbelt = ">=0.8.0,<0.9.0 || >0.9.0" @@ -2720,6 +2757,9 @@ rfc3986 = ">=1.4.0" rich = ">=12.0.0" urllib3 = ">=1.26.0" +[package.extras] +keyring = ["keyring (>=15.1)"] + [[package]] name = "typer" version = "0.15.1" @@ -2800,13 +2840,13 @@ standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", [[package]] name = "virtualenv" -version = "20.27.1" +version = "20.28.0" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" files = [ - {file = "virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4"}, - {file = "virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba"}, + {file = "virtualenv-20.28.0-py3-none-any.whl", hash = "sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0"}, + {file = "virtualenv-20.28.0.tar.gz", hash = "sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa"}, ] [package.dependencies] @@ -2914,13 +2954,13 @@ files = [ [[package]] name = "wheel" -version = "0.45.0" +version = "0.45.1" description = "A built-package format for Python" optional = false python-versions = ">=3.8" files = [ - {file = "wheel-0.45.0-py3-none-any.whl", hash = "sha256:52f0baa5e6522155090a09c6bd95718cc46956d1b51d537ea5454249edb671c7"}, - {file = "wheel-0.45.0.tar.gz", hash = "sha256:a57353941a3183b3d5365346b567a260a0602a0f8a635926a7dede41b94c674a"}, + {file = "wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248"}, + {file = "wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729"}, ] [package.extras] @@ -2928,81 +2968,76 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [[package]] name = "wrapt" -version = "1.16.0" +version = "1.17.0" description = "Module for decorators, wrappers and monkey patching." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, - {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, - {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, - {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, - {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, - {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, - {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, - {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, - {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, - {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, - {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, - {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, - {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, - {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, - {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, - {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, - {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, - {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, + {file = "wrapt-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301"}, + {file = "wrapt-1.17.0-cp310-cp310-win32.whl", hash = "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22"}, + {file = "wrapt-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575"}, + {file = "wrapt-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b"}, + {file = "wrapt-1.17.0-cp311-cp311-win32.whl", hash = "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346"}, + {file = "wrapt-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a"}, + {file = "wrapt-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4"}, + {file = "wrapt-1.17.0-cp312-cp312-win32.whl", hash = "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635"}, + {file = "wrapt-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7"}, + {file = "wrapt-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a"}, + {file = "wrapt-1.17.0-cp313-cp313-win32.whl", hash = "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045"}, + {file = "wrapt-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838"}, + {file = "wrapt-1.17.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab"}, + {file = "wrapt-1.17.0-cp313-cp313t-win32.whl", hash = "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf"}, + {file = "wrapt-1.17.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a"}, + {file = "wrapt-1.17.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f"}, + {file = "wrapt-1.17.0-cp38-cp38-win32.whl", hash = "sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea"}, + {file = "wrapt-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed"}, + {file = "wrapt-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0"}, + {file = "wrapt-1.17.0-cp39-cp39-win32.whl", hash = "sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88"}, + {file = "wrapt-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977"}, + {file = "wrapt-1.17.0-py3-none-any.whl", hash = "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371"}, + {file = "wrapt-1.17.0.tar.gz", hash = "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801"}, ] [[package]] @@ -3041,4 +3076,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "3810e99ff4d09952e62d88b2c26651a0d8e0ffe4007bc3274c2fb83b68243951" +content-hash = "d62cd1897d8f73e9aad9e907beb82be509dc5e33d8f37b36ebf26ad1f3075a9f" diff --git a/pyproject.toml b/pyproject.toml index f57c4069f..6e995a85d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,7 @@ wheel = ">=0.42.0,<1.0" build = ">=1.0.3,<2.0" setuptools = ">=75.0" httpx = ">=0.25.1,<1.0" -twine = ">=4.0.0,<6.0" +twine = ">=4.0.0,<7.0" tomlkit = ">=0.12.4,<1.0" lazy_loader = ">=0.4" reflex-chakra = ">=0.6.0" @@ -70,7 +70,7 @@ dill = ">=0.3.8" toml = ">=0.10.2,<1.0" pytest-asyncio = ">=0.24.0" pytest-cov = ">=4.0.0,<7.0" -ruff = "0.7.4" +ruff = "0.8.2" pandas = ">=2.1.1,<3.0" pillow = ">=10.0.0,<12.0" plotly = ">=5.13.0,<6.0" From 2520c51aaf4c0a4af965026ae3a3fd5b03930288 Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Tue, 10 Dec 2024 18:49:56 +0100 Subject: [PATCH 58/71] fix: multiple mismatched-type-assignment fixes (#4482) * fix: only make type optional if it's not already, add helper to unwrap rx.Field * migrate unwrap_field_type to private function --- reflex/state.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/reflex/state.py b/reflex/state.py index c86bd9a1b..5e132ef65 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -104,6 +104,7 @@ from reflex.utils.serializers import serializer from reflex.utils.types import ( _isinstance, get_origin, + is_optional, is_union, override, value_inside_optional, @@ -278,6 +279,22 @@ if TYPE_CHECKING: from pydantic.v1.fields import ModelField +def _unwrap_field_type(type_: Type) -> Type: + """Unwrap rx.Field type annotations. + + Args: + type_: The type to unwrap. + + Returns: + The unwrapped type. + """ + from reflex.vars import Field + + if get_origin(type_) is Field: + return get_args(type_)[0] + return type_ + + def get_var_for_field(cls: Type[BaseState], f: ModelField): """Get a Var instance for a Pydantic field. @@ -288,16 +305,12 @@ def get_var_for_field(cls: Type[BaseState], f: ModelField): Returns: The Var instance. """ - from reflex.vars import Field - field_name = format.format_state_name(cls.get_full_name()) + "." + f.name return dispatch( field_name=field_name, var_data=VarData.from_state(cls, f.name), - result_var_type=f.outer_type_ - if get_origin(f.outer_type_) is not Field - else get_args(f.outer_type_)[0], + result_var_type=_unwrap_field_type(f.outer_type_), ) @@ -1313,8 +1326,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): if name in fields: field = fields[name] - field_type = field.outer_type_ - if field.allow_none: + field_type = _unwrap_field_type(field.outer_type_) + if field.allow_none and not is_optional(field_type): field_type = Union[field_type, None] if not _isinstance(value, field_type): console.deprecate( From fd0fd2c6d4fcd98c86e02ae1869af53d07f34a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Tue, 10 Dec 2024 09:52:03 -0800 Subject: [PATCH 59/71] enable REFURB rules in ruff (#4466) Co-authored-by: Masen Furer --- pyproject.toml | 2 +- reflex/utils/prerequisites.py | 2 +- reflex/utils/pyi_generator.py | 2 +- tests/units/conftest.py | 2 +- tests/units/utils/test_utils.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6e995a85d..1b47bb366 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,7 +93,7 @@ build-backend = "poetry.core.masonry.api" [tool.ruff] target-version = "py39" lint.isort.split-on-trailing-comma = false -lint.select = ["B", "D", "E", "F", "I", "SIM", "W", "RUF"] +lint.select = ["B", "D", "E", "F", "I", "SIM", "W", "RUF", "FURB"] lint.ignore = ["B008", "D205", "E501", "F403", "SIM115", "RUF006", "RUF012"] lint.pydocstyle.convention = "google" diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index 88260fe45..a83843eeb 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -495,7 +495,7 @@ def initialize_requirements_txt(): try: other_requirements_exist = False with open(fp, "r", encoding=encoding) as f: - for req in f.readlines(): + for req in f: # Check if we have a package name that is reflex if re.match(r"^reflex[^a-zA-Z0-9]", req): console.debug(f"{fp} already has reflex as dependency.") diff --git a/reflex/utils/pyi_generator.py b/reflex/utils/pyi_generator.py index 9b2cbe722..5e73e4dce 100644 --- a/reflex/utils/pyi_generator.py +++ b/reflex/utils/pyi_generator.py @@ -24,7 +24,7 @@ from reflex.vars.base import Var logger = logging.getLogger("pyi_generator") -PWD = Path(".").resolve() +PWD = Path.cwd() EXCLUDED_FILES = [ "app.py", diff --git a/tests/units/conftest.py b/tests/units/conftest.py index 2f619a941..fb6229aca 100644 --- a/tests/units/conftest.py +++ b/tests/units/conftest.py @@ -206,7 +206,7 @@ class chdir(contextlib.AbstractContextManager): def __enter__(self): """Save current directory and perform chdir.""" - self._old_cwd.append(Path(".").resolve()) + self._old_cwd.append(Path.cwd()) os.chdir(self.path) def __exit__(self, *excinfo): diff --git a/tests/units/utils/test_utils.py b/tests/units/utils/test_utils.py index dd1a3b3ef..20bad4146 100644 --- a/tests/units/utils/test_utils.py +++ b/tests/units/utils/test_utils.py @@ -298,7 +298,7 @@ def tmp_working_dir(tmp_path): Yields: subdirectory of tmp_path which is now the current working directory. """ - old_pwd = Path(".").resolve() + old_pwd = Path.cwd() working_dir = tmp_path / "working_dir" working_dir.mkdir() os.chdir(working_dir) From 37af2ee1ec1536c593a21be2d965d961e689fe13 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Tue, 10 Dec 2024 11:12:26 -0800 Subject: [PATCH 60/71] Revert "reduce lock expiration time to 1s (#4507)" (#4514) This reverts commit 6e3e632bbd64edaee5db85f3edb2be3de4a9e371. --- reflex/constants/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reflex/constants/config.py b/reflex/constants/config.py index 234ecbd84..970e67844 100644 --- a/reflex/constants/config.py +++ b/reflex/constants/config.py @@ -26,7 +26,7 @@ class Expiration(SimpleNamespace): # Token expiration time in seconds TOKEN = 60 * 60 # Maximum time in milliseconds that a state can be locked for exclusive access. - LOCK = 1000 + LOCK = 10000 # The PING timeout PING = 120 From 3ef7106e0e3b1d0980cc516c1450ebd02ae0dd54 Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Tue, 10 Dec 2024 21:35:46 +0100 Subject: [PATCH 61/71] style: prefer type() over __class__ (#4512) --- reflex/app.py | 2 +- reflex/components/component.py | 4 ++-- reflex/components/core/cond.py | 4 ++-- reflex/components/radix/themes/base.py | 4 +--- reflex/event.py | 4 ++-- reflex/state.py | 4 ++-- reflex/vars/base.py | 6 +++--- reflex/vars/number.py | 4 ++-- reflex/vars/object.py | 2 +- reflex/vars/sequence.py | 2 +- tests/integration/test_state_inheritance.py | 2 +- tests/units/test_model.py | 4 ++-- tests/units/test_state.py | 2 +- 13 files changed, 21 insertions(+), 23 deletions(-) diff --git a/reflex/app.py b/reflex/app.py index cdf21aa35..eb453bd0b 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -1157,7 +1157,7 @@ class App(MiddlewareMixin, LifespanMixin): if hasattr(handler_fn, "__name__"): _fn_name = handler_fn.__name__ else: - _fn_name = handler_fn.__class__.__name__ + _fn_name = type(handler_fn).__name__ if isinstance(handler_fn, functools.partial): raise ValueError( diff --git a/reflex/components/component.py b/reflex/components/component.py index 5c1c4941d..75a821ac8 100644 --- a/reflex/components/component.py +++ b/reflex/components/component.py @@ -161,7 +161,7 @@ class ComponentNamespace(SimpleNamespace): Returns: The hash of the namespace. """ - return hash(self.__class__.__name__) + return hash(type(self).__name__) def evaluate_style_namespaces(style: ComponentStyle) -> dict: @@ -2565,7 +2565,7 @@ class LiteralComponentVar(CachedVarOperation, LiteralVar, ComponentVar): Returns: The hash of the var. """ - return hash((self.__class__.__name__, self._js_expr)) + return hash((type(self).__name__, self._js_expr)) @classmethod def create( diff --git a/reflex/components/core/cond.py b/reflex/components/core/cond.py index b75667890..488990f54 100644 --- a/reflex/components/core/cond.py +++ b/reflex/components/core/cond.py @@ -49,9 +49,9 @@ class Cond(MemoizationLeaf): The conditional component. """ # Wrap everything in fragments. - if comp1.__class__.__name__ != "Fragment": + if type(comp1).__name__ != "Fragment": comp1 = Fragment.create(comp1) - if comp2 is None or comp2.__class__.__name__ != "Fragment": + if comp2 is None or type(comp2).__name__ != "Fragment": comp2 = Fragment.create(comp2) if comp2 else Fragment.create() return Fragment.create( cls( diff --git a/reflex/components/radix/themes/base.py b/reflex/components/radix/themes/base.py index 65a9ae835..9a8a2d7c0 100644 --- a/reflex/components/radix/themes/base.py +++ b/reflex/components/radix/themes/base.py @@ -139,9 +139,7 @@ class RadixThemesComponent(Component): component = super().create(*children, **props) if component.library is None: component.library = RadixThemesComponent.__fields__["library"].default - component.alias = "RadixThemes" + ( - component.tag or component.__class__.__name__ - ) + component.alias = "RadixThemes" + (component.tag or type(component).__name__) # value = props.get("value") # if value is not None and component.alias == "RadixThemesSelect.Root": # lv = LiteralVar.create(value) diff --git a/reflex/event.py b/reflex/event.py index 3022de556..9807b696b 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -1556,7 +1556,7 @@ class LiteralEventVar(VarOperationCall, LiteralVar, EventVar): Returns: The hash of the var. """ - return hash((self.__class__.__name__, self._js_expr)) + return hash((type(self).__name__, self._js_expr)) @classmethod def create( @@ -1620,7 +1620,7 @@ class LiteralEventChainVar(ArgsFunctionOperationBuilder, LiteralVar, EventChainV Returns: The hash of the var. """ - return hash((self.__class__.__name__, self._js_expr)) + return hash((type(self).__name__, self._js_expr)) @classmethod def create( diff --git a/reflex/state.py b/reflex/state.py index 5e132ef65..09e76159c 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -438,7 +438,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): Returns: The string representation of the state. """ - return f"{self.__class__.__name__}({self.dict()})" + return f"{type(self).__name__}({self.dict()})" @classmethod def _get_computed_vars(cls) -> list[ComputedVar]: @@ -3618,7 +3618,7 @@ class MutableProxy(wrapt.ObjectProxy): Returns: The representation of the wrapped object. """ - return f"{self.__class__.__name__}({self.__wrapped__})" + return f"{type(self).__name__}({self.__wrapped__})" def _mark_dirty( self, diff --git a/reflex/vars/base.py b/reflex/vars/base.py index ea78d1a89..941a9d81a 100644 --- a/reflex/vars/base.py +++ b/reflex/vars/base.py @@ -1569,7 +1569,7 @@ class CachedVarOperation: if name == "_js_expr": return self._cached_var_name - parent_classes = inspect.getmro(self.__class__) + parent_classes = inspect.getmro(type(self)) next_class = parent_classes[parent_classes.index(CachedVarOperation) + 1] @@ -1611,7 +1611,7 @@ class CachedVarOperation: """ return hash( ( - self.__class__.__name__, + type(self).__name__, *[ getattr(self, field.name) for field in dataclasses.fields(self) # type: ignore @@ -1733,7 +1733,7 @@ class CallableVar(Var): Returns: The hash of the object. """ - return hash((self.__class__.__name__, self.original_var)) + return hash((type(self).__name__, self.original_var)) RETURN_TYPE = TypeVar("RETURN_TYPE") diff --git a/reflex/vars/number.py b/reflex/vars/number.py index a762796e2..d14f9695b 100644 --- a/reflex/vars/number.py +++ b/reflex/vars/number.py @@ -1012,7 +1012,7 @@ class LiteralNumberVar(LiteralVar, NumberVar): Returns: int: The hash value of the object. """ - return hash((self.__class__.__name__, self._var_value)) + return hash((type(self).__name__, self._var_value)) @classmethod def create(cls, value: float | int, _var_data: VarData | None = None): @@ -1064,7 +1064,7 @@ class LiteralBooleanVar(LiteralVar, BooleanVar): Returns: int: The hash value of the object. """ - return hash((self.__class__.__name__, self._var_value)) + return hash((type(self).__name__, self._var_value)) @classmethod def create(cls, value: bool, _var_data: VarData | None = None): diff --git a/reflex/vars/object.py b/reflex/vars/object.py index 032fc8058..5de431f5a 100644 --- a/reflex/vars/object.py +++ b/reflex/vars/object.py @@ -362,7 +362,7 @@ class LiteralObjectVar(CachedVarOperation, ObjectVar[OBJECT_TYPE], LiteralVar): Returns: The hash of the var. """ - return hash((self.__class__.__name__, self._js_expr)) + return hash((type(self).__name__, self._js_expr)) @cached_property_no_lock def _cached_get_all_var_data(self) -> VarData | None: diff --git a/reflex/vars/sequence.py b/reflex/vars/sequence.py index f5639685f..a02645309 100644 --- a/reflex/vars/sequence.py +++ b/reflex/vars/sequence.py @@ -667,7 +667,7 @@ class LiteralStringVar(LiteralVar, StringVar[str]): Returns: The hash of the var. """ - return hash((self.__class__.__name__, self._var_value)) + return hash((type(self).__name__, self._var_value)) def json(self) -> str: """Get the JSON representation of the var. diff --git a/tests/integration/test_state_inheritance.py b/tests/integration/test_state_inheritance.py index 81512a67a..6b93a2ed7 100644 --- a/tests/integration/test_state_inheritance.py +++ b/tests/integration/test_state_inheritance.py @@ -73,7 +73,7 @@ def StateInheritance(): def on_click_other_mixin(self): self.other_mixin_clicks += 1 self.other_mixin = ( - f"{self.__class__.__name__}.clicked.{self.other_mixin_clicks}" + f"{type(self).__name__}.clicked.{self.other_mixin_clicks}" ) class Base1(Mixin, rx.State): diff --git a/tests/units/test_model.py b/tests/units/test_model.py index ac8187e03..0a83f39ec 100644 --- a/tests/units/test_model.py +++ b/tests/units/test_model.py @@ -46,7 +46,7 @@ def test_default_primary_key(model_default_primary: Model): Args: model_default_primary: Fixture. """ - assert "id" in model_default_primary.__class__.__fields__ + assert "id" in type(model_default_primary).__fields__ def test_custom_primary_key(model_custom_primary: Model): @@ -55,7 +55,7 @@ def test_custom_primary_key(model_custom_primary: Model): Args: model_custom_primary: Fixture. """ - assert "id" not in model_custom_primary.__class__.__fields__ + assert "id" not in type(model_custom_primary).__fields__ @pytest.mark.filterwarnings( diff --git a/tests/units/test_state.py b/tests/units/test_state.py index 9dc2bc4e2..5c062ccb2 100644 --- a/tests/units/test_state.py +++ b/tests/units/test_state.py @@ -1698,7 +1698,7 @@ async def test_state_manager_modify_state( assert not state_manager._states_locks[token].locked() # separate instances should NOT share locks - sm2 = state_manager.__class__(state=TestState) + sm2 = type(state_manager)(state=TestState) assert sm2._state_manager_lock is state_manager._state_manager_lock assert not sm2._states_locks if state_manager._states_locks: From 4922f7ba055ca579e9f2d05248e767a3190dee3a Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Tue, 10 Dec 2024 12:37:09 -0800 Subject: [PATCH 62/71] Reuse the sqlalchemy engine once it's created (#4493) * Reuse the sqlalchemy engine once it's created * Implement `rx.asession` for async database support Requires setting `async_db_url` to the same database as `db_url`, except using an async driver; this will vary by database. * resolve the url first, so the key into _ENGINE is correct * Ping db connections before returning them from pool Move connect engine kwargs to a separate function * the param is `echo` * sanity check that config db_url and async_db_url are the same throw a warning if the part following the `://` differs between these two * create_async_engine: use sqlalchemy async API update types * redact ASYNC_DB_URL similarly to DB_URL when overridden in config * update rx.asession docstring * use async_sessionmaker * Redact sensitive env vars instead of hiding them --- reflex/__init__.py | 2 +- reflex/__init__.pyi | 1 + reflex/config.py | 24 ++++++--- reflex/model.py | 126 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 141 insertions(+), 12 deletions(-) diff --git a/reflex/__init__.py b/reflex/__init__.py index 562524416..0be568b1a 100644 --- a/reflex/__init__.py +++ b/reflex/__init__.py @@ -331,7 +331,7 @@ _MAPPING: dict = { "SessionStorage", ], "middleware": ["middleware", "Middleware"], - "model": ["session", "Model"], + "model": ["asession", "session", "Model"], "state": [ "var", "ComponentState", diff --git a/reflex/__init__.pyi b/reflex/__init__.pyi index 6f61435e6..6bdfa11a0 100644 --- a/reflex/__init__.pyi +++ b/reflex/__init__.pyi @@ -186,6 +186,7 @@ from .istate.wrappers import get_state as get_state from .middleware import Middleware as Middleware from .middleware import middleware as middleware from .model import Model as Model +from .model import asession as asession from .model import session as session from .page import page as page from .state import ComponentState as ComponentState diff --git a/reflex/config.py b/reflex/config.py index 1d952f4f0..c40abcb39 100644 --- a/reflex/config.py +++ b/reflex/config.py @@ -512,6 +512,9 @@ class EnvironmentVariables: # Whether to print the SQL queries if the log level is INFO or lower. SQLALCHEMY_ECHO: EnvVar[bool] = env_var(False) + # Whether to check db connections before using them. + SQLALCHEMY_POOL_PRE_PING: EnvVar[bool] = env_var(True) + # Whether to ignore the redis config error. Some redis servers only allow out-of-band configuration. REFLEX_IGNORE_REDIS_CONFIG_ERROR: EnvVar[bool] = env_var(False) @@ -568,6 +571,10 @@ class EnvironmentVariables: environment = EnvironmentVariables() +# These vars are not logged because they may contain sensitive information. +_sensitive_env_vars = {"DB_URL", "ASYNC_DB_URL", "REDIS_URL"} + + class Config(Base): """The config defines runtime settings for the app. @@ -621,6 +628,9 @@ class Config(Base): # The database url used by rx.Model. db_url: Optional[str] = "sqlite:///reflex.db" + # The async database url used by rx.Model. + async_db_url: Optional[str] = None + # The redis url redis_url: Optional[str] = None @@ -748,18 +758,20 @@ class Config(Base): # If the env var is set, override the config value. if env_var is not None: - if key.upper() != "DB_URL": - console.info( - f"Overriding config value {key} with env var {key.upper()}={env_var}", - dedupe=True, - ) - # Interpret the value. value = interpret_env_var_value(env_var, field.outer_type_, field.name) # Set the value. updated_values[key] = value + if key.upper() in _sensitive_env_vars: + env_var = "***" + + console.info( + f"Overriding config value {key} with env var {key.upper()}={env_var}", + dedupe=True, + ) + return updated_values def get_event_namespace(self) -> str: diff --git a/reflex/model.py b/reflex/model.py index 4b070ec67..03b1cc828 100644 --- a/reflex/model.py +++ b/reflex/model.py @@ -2,6 +2,7 @@ from __future__ import annotations +import re from collections import defaultdict from typing import Any, ClassVar, Optional, Type, Union @@ -14,6 +15,7 @@ import alembic.script import alembic.util import sqlalchemy import sqlalchemy.exc +import sqlalchemy.ext.asyncio import sqlalchemy.orm from reflex.base import Base @@ -21,6 +23,48 @@ from reflex.config import environment, get_config from reflex.utils import console from reflex.utils.compat import sqlmodel, sqlmodel_field_has_primary_key +_ENGINE: dict[str, sqlalchemy.engine.Engine] = {} +_ASYNC_ENGINE: dict[str, sqlalchemy.ext.asyncio.AsyncEngine] = {} +_AsyncSessionLocal: dict[str | None, sqlalchemy.ext.asyncio.async_sessionmaker] = {} + +# Import AsyncSession _after_ reflex.utils.compat +from sqlmodel.ext.asyncio.session import AsyncSession # noqa: E402 + + +def _safe_db_url_for_logging(url: str) -> str: + """Remove username and password from the database URL for logging. + + Args: + url: The database URL. + + Returns: + The database URL with the username and password removed. + """ + return re.sub(r"://[^@]+@", "://:@", url) + + +def get_engine_args(url: str | None = None) -> dict[str, Any]: + """Get the database engine arguments. + + Args: + url: The database url. + + Returns: + The database engine arguments as a dict. + """ + kwargs: dict[str, Any] = dict( + # Print the SQL queries if the log level is INFO or lower. + echo=environment.SQLALCHEMY_ECHO.get(), + # Check connections before returning them. + pool_pre_ping=environment.SQLALCHEMY_POOL_PRE_PING.get(), + ) + conf = get_config() + url = url or conf.db_url + if url is not None and url.startswith("sqlite"): + # Needed for the admin dash on sqlite. + kwargs["connect_args"] = {"check_same_thread": False} + return kwargs + def get_engine(url: str | None = None) -> sqlalchemy.engine.Engine: """Get the database engine. @@ -38,15 +82,62 @@ def get_engine(url: str | None = None) -> sqlalchemy.engine.Engine: url = url or conf.db_url if url is None: raise ValueError("No database url configured") + + global _ENGINE + if url in _ENGINE: + return _ENGINE[url] + if not environment.ALEMBIC_CONFIG.get().exists(): console.warn( "Database is not initialized, run [bold]reflex db init[/bold] first." ) - # Print the SQL queries if the log level is INFO or lower. - echo_db_query = environment.SQLALCHEMY_ECHO.get() - # Needed for the admin dash on sqlite. - connect_args = {"check_same_thread": False} if url.startswith("sqlite") else {} - return sqlmodel.create_engine(url, echo=echo_db_query, connect_args=connect_args) + _ENGINE[url] = sqlmodel.create_engine( + url, + **get_engine_args(url), + ) + return _ENGINE[url] + + +def get_async_engine(url: str | None) -> sqlalchemy.ext.asyncio.AsyncEngine: + """Get the async database engine. + + Args: + url: The database url. + + Returns: + The async database engine. + + Raises: + ValueError: If the async database url is None. + """ + if url is None: + conf = get_config() + url = conf.async_db_url + if url is not None and conf.db_url is not None: + async_db_url_tail = url.partition("://")[2] + db_url_tail = conf.db_url.partition("://")[2] + if async_db_url_tail != db_url_tail: + console.warn( + f"async_db_url `{_safe_db_url_for_logging(url)}` " + "should reference the same database as " + f"db_url `{_safe_db_url_for_logging(conf.db_url)}`." + ) + if url is None: + raise ValueError("No async database url configured") + + global _ASYNC_ENGINE + if url in _ASYNC_ENGINE: + return _ASYNC_ENGINE[url] + + if not environment.ALEMBIC_CONFIG.get().exists(): + console.warn( + "Database is not initialized, run [bold]reflex db init[/bold] first." + ) + _ASYNC_ENGINE[url] = sqlalchemy.ext.asyncio.create_async_engine( + url, + **get_engine_args(url), + ) + return _ASYNC_ENGINE[url] async def get_db_status() -> bool: @@ -425,6 +516,31 @@ def session(url: str | None = None) -> sqlmodel.Session: return sqlmodel.Session(get_engine(url)) +def asession(url: str | None = None) -> AsyncSession: + """Get an async sqlmodel session to interact with the database. + + async with rx.asession() as asession: + ... + + Most operations against the `asession` must be awaited. + + Args: + url: The database url. + + Returns: + An async database session. + """ + global _AsyncSessionLocal + if url not in _AsyncSessionLocal: + _AsyncSessionLocal[url] = sqlalchemy.ext.asyncio.async_sessionmaker( + bind=get_async_engine(url), + class_=AsyncSession, + autocommit=False, + autoflush=False, + ) + return _AsyncSessionLocal[url]() + + def sqla_session(url: str | None = None) -> sqlalchemy.orm.Session: """Get a bare sqlalchemy session to interact with the database. From 06d743cda9eaadfe44e2829b471a0be6e8f03384 Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Wed, 11 Dec 2024 19:22:44 +0100 Subject: [PATCH 63/71] fix: migrate is_backend_only (deprecated) to EnvironmentVariables (#4495) --- reflex/assets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reflex/assets.py b/reflex/assets.py index 8a50664b6..a9aa7a6a9 100644 --- a/reflex/assets.py +++ b/reflex/assets.py @@ -5,7 +5,7 @@ from pathlib import Path from typing import Optional from reflex import constants -from reflex.utils.exec import is_backend_only +from reflex.config import EnvironmentVariables def asset( @@ -52,7 +52,7 @@ def asset( The relative URL to the asset. """ assets = constants.Dirs.APP_ASSETS - backend_only = is_backend_only() + backend_only = EnvironmentVariables.REFLEX_BACKEND_ONLY.get() # Local asset handling if not shared: From 862d7ec807cb3899936e87a0401b357e778b6856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Wed, 11 Dec 2024 10:57:51 -0800 Subject: [PATCH 64/71] add test for color mode (initial and toggle) (#4467) * add test for color mode (initial and toggle) * add css check * add page reload in the tests * update test to catch the appearance regression * don't render the appearance prop of rx.theme --- reflex/components/radix/themes/base.py | 1 + .../tests_playwright/test_appearance.py | 218 ++++++++++++++++++ 2 files changed, 219 insertions(+) create mode 100644 tests/integration/tests_playwright/test_appearance.py diff --git a/reflex/components/radix/themes/base.py b/reflex/components/radix/themes/base.py index 9a8a2d7c0..e90d41a5a 100644 --- a/reflex/components/radix/themes/base.py +++ b/reflex/components/radix/themes/base.py @@ -266,6 +266,7 @@ class Theme(RadixThemesComponent): _js_expr="{...theme.styles.global[':root'], ...theme.styles.global.body}" ), ) + tag.remove_props("appearance") return tag diff --git a/tests/integration/tests_playwright/test_appearance.py b/tests/integration/tests_playwright/test_appearance.py new file mode 100644 index 000000000..60aeeaa6b --- /dev/null +++ b/tests/integration/tests_playwright/test_appearance.py @@ -0,0 +1,218 @@ +from typing import Generator + +import pytest +from playwright.sync_api import Page, expect + +from reflex.testing import AppHarness + + +def DefaultLightModeApp(): + import reflex as rx + from reflex.style import color_mode + + app = rx.App(theme=rx.theme(appearance="light")) + + @app.add_page + def index(): + return rx.text(color_mode) + + +def DefaultDarkModeApp(): + import reflex as rx + from reflex.style import color_mode + + app = rx.App(theme=rx.theme(appearance="dark")) + + @app.add_page + def index(): + return rx.text(color_mode) + + +def DefaultSystemModeApp(): + import reflex as rx + from reflex.style import color_mode + + app = rx.App() + + @app.add_page + def index(): + return rx.text(color_mode) + + +def ColorToggleApp(): + import reflex as rx + from reflex.style import color_mode, resolved_color_mode, set_color_mode + + app = rx.App(theme=rx.theme(appearance="light")) + + @app.add_page + def index(): + return rx.box( + rx.segmented_control.root( + rx.segmented_control.item( + rx.icon(tag="monitor", size=20), + value="system", + ), + rx.segmented_control.item( + rx.icon(tag="sun", size=20), + value="light", + ), + rx.segmented_control.item( + rx.icon(tag="moon", size=20), + value="dark", + ), + on_change=set_color_mode, + variant="classic", + radius="large", + value=color_mode, + ), + rx.text(color_mode, id="current_color_mode"), + rx.text(resolved_color_mode, id="resolved_color_mode"), + rx.text(rx.color_mode_cond("LightMode", "DarkMode"), id="color_mode_cond"), + ) + + +@pytest.fixture() +def light_mode_app(tmp_path_factory) -> Generator[AppHarness, None, None]: + """Start DefaultLightMode app at tmp_path via AppHarness. + + Args: + tmp_path_factory: pytest tmp_path_factory fixture + + Yields: + running AppHarness instance + + """ + with AppHarness.create( + root=tmp_path_factory.mktemp("appearance_app"), + app_source=DefaultLightModeApp, # type: ignore + ) as harness: + assert harness.app_instance is not None, "app is not running" + yield harness + + +@pytest.fixture() +def dark_mode_app(tmp_path_factory) -> Generator[AppHarness, None, None]: + """Start DefaultDarkMode app at tmp_path via AppHarness. + + Args: + tmp_path_factory: pytest tmp_path_factory fixture + + Yields: + running AppHarness instance + + """ + with AppHarness.create( + root=tmp_path_factory.mktemp("appearance_app"), + app_source=DefaultDarkModeApp, # type: ignore + ) as harness: + assert harness.app_instance is not None, "app is not running" + yield harness + + +@pytest.fixture() +def system_mode_app(tmp_path_factory) -> Generator[AppHarness, None, None]: + """Start DefaultSystemMode app at tmp_path via AppHarness. + + Args: + tmp_path_factory: pytest tmp_path_factory fixture + + Yields: + running AppHarness instance + + """ + with AppHarness.create( + root=tmp_path_factory.mktemp("appearance_app"), + app_source=DefaultSystemModeApp, # type: ignore + ) as harness: + assert harness.app_instance is not None, "app is not running" + yield harness + + +@pytest.fixture() +def color_toggle_app(tmp_path_factory) -> Generator[AppHarness, None, None]: + """Start ColorToggle app at tmp_path via AppHarness. + + Args: + tmp_path_factory: pytest tmp_path_factory fixture + + Yields: + running AppHarness instance + + """ + with AppHarness.create( + root=tmp_path_factory.mktemp("appearance_app"), + app_source=ColorToggleApp, # type: ignore + ) as harness: + assert harness.app_instance is not None, "app is not running" + yield harness + + +def test_appearance_light_mode(light_mode_app: AppHarness, page: Page): + assert light_mode_app.frontend_url is not None + page.goto(light_mode_app.frontend_url) + + expect(page.get_by_text("light")).to_be_visible() + + +def test_appearance_dark_mode(dark_mode_app: AppHarness, page: Page): + assert dark_mode_app.frontend_url is not None + page.goto(dark_mode_app.frontend_url) + + expect(page.get_by_text("dark")).to_be_visible() + + +def test_appearance_system_mode(system_mode_app: AppHarness, page: Page): + assert system_mode_app.frontend_url is not None + page.goto(system_mode_app.frontend_url) + + expect(page.get_by_text("system")).to_be_visible() + + +def test_appearance_color_toggle(color_toggle_app: AppHarness, page: Page): + assert color_toggle_app.frontend_url is not None + page.goto(color_toggle_app.frontend_url) + + # Radio buttons locators. + radio_system = page.get_by_role("radio").nth(0) + radio_light = page.get_by_role("radio").nth(1) + radio_dark = page.get_by_role("radio").nth(2) + + # Text locators to check. + current_color_mode = page.locator("id=current_color_mode") + resolved_color_mode = page.locator("id=resolved_color_mode") + color_mode_cond = page.locator("id=color_mode_cond") + root_body = page.locator('div[data-is-root-theme="true"]') + + # Background colors. + dark_background = "rgb(17, 17, 19)" # value based on dark native appearance, can change depending on the browser + light_background = "rgb(255, 255, 255)" + + # check initial state + expect(current_color_mode).to_have_text("light") + expect(resolved_color_mode).to_have_text("light") + expect(color_mode_cond).to_have_text("LightMode") + expect(root_body).to_have_css("background-color", light_background) + + # click dark mode + radio_dark.click() + expect(current_color_mode).to_have_text("dark") + expect(resolved_color_mode).to_have_text("dark") + expect(color_mode_cond).to_have_text("DarkMode") + expect(root_body).to_have_css("background-color", dark_background) + + # click light mode + radio_light.click() + expect(current_color_mode).to_have_text("light") + expect(resolved_color_mode).to_have_text("light") + expect(color_mode_cond).to_have_text("LightMode") + expect(root_body).to_have_css("background-color", light_background) + page.reload() + expect(root_body).to_have_css("background-color", light_background) + + # click system mode + radio_system.click() + expect(current_color_mode).to_have_text("system") + expect(resolved_color_mode).to_have_text("light") + expect(color_mode_cond).to_have_text("LightMode") + expect(root_body).to_have_css("background-color", light_background) From 2ee201b52085ed2d0c14daf29588340530779ff9 Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Wed, 11 Dec 2024 20:08:18 +0100 Subject: [PATCH 65/71] raise StateSerializationError if the state cannot be serialized (#4453) * raise StateSerializationError if the state cannot be serialized * fix test --- reflex/state.py | 10 ++++++++++ reflex/utils/exceptions.py | 4 ++++ tests/units/test_state.py | 11 ++++++++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/reflex/state.py b/reflex/state.py index 09e76159c..c73b1ac46 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -97,6 +97,7 @@ from reflex.utils.exceptions import ( ReflexRuntimeError, SetUndefinedStateVarError, StateSchemaMismatchError, + StateSerializationError, StateTooLargeError, ) from reflex.utils.exec import is_testing_env @@ -2193,8 +2194,12 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): Returns: The serialized state. + + Raises: + StateSerializationError: If the state cannot be serialized. """ payload = b"" + error = "" try: payload = pickle.dumps((self._to_schema(), self)) except HANDLED_PICKLE_ERRORS as og_pickle_error: @@ -2214,8 +2219,13 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): except HANDLED_PICKLE_ERRORS as ex: error += f"Dill was also unable to pickle the state: {ex}" console.warn(error) + if environment.REFLEX_PERF_MODE.get() != PerformanceMode.OFF: self._check_state_size(len(payload)) + + if not payload: + raise StateSerializationError(error) + return payload @classmethod diff --git a/reflex/utils/exceptions.py b/reflex/utils/exceptions.py index 714dc912c..a89c4d4aa 100644 --- a/reflex/utils/exceptions.py +++ b/reflex/utils/exceptions.py @@ -155,6 +155,10 @@ class StateTooLargeError(ReflexError): """Raised when the state is too large to be serialized.""" +class StateSerializationError(ReflexError): + """Raised when the state cannot be serialized.""" + + class SystemPackageMissingError(ReflexError): """Raised when a system package is missing.""" diff --git a/tests/units/test_state.py b/tests/units/test_state.py index 5c062ccb2..790df1b7d 100644 --- a/tests/units/test_state.py +++ b/tests/units/test_state.py @@ -55,7 +55,11 @@ from reflex.state import ( ) from reflex.testing import chdir from reflex.utils import format, prerequisites, types -from reflex.utils.exceptions import ReflexRuntimeError, SetUndefinedStateVarError +from reflex.utils.exceptions import ( + ReflexRuntimeError, + SetUndefinedStateVarError, + StateSerializationError, +) from reflex.utils.format import json_dumps from reflex.vars.base import Var, computed_var from tests.units.states.mutation import MutableSQLAModel, MutableTestState @@ -3433,8 +3437,9 @@ def test_fallback_pickle(): # Some object, like generator, are still unpicklable with dill. state3 = DillState(_reflex_internal_init=True) # type: ignore state3._g = (i for i in range(10)) - pk3 = state3._serialize() - assert len(pk3) == 0 + + with pytest.raises(StateSerializationError): + _ = state3._serialize() def test_typed_state() -> None: From d75a708e6bf46ba49904fcce114fe84c42df2375 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Wed, 11 Dec 2024 12:29:33 -0800 Subject: [PATCH 66/71] Fix REFLEX_COMPILE_PROCESSES=0 (#4523) when zero is passed, that is short for "use the default", which is actually None in the code. fix for both processes and threads being set to zero --- reflex/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reflex/app.py b/reflex/app.py index eb453bd0b..6a17a56b6 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -947,12 +947,12 @@ class App(MiddlewareMixin, LifespanMixin): is not None ): executor = concurrent.futures.ProcessPoolExecutor( - max_workers=number_of_processes, + max_workers=number_of_processes or None, mp_context=multiprocessing.get_context("fork"), ) else: executor = concurrent.futures.ThreadPoolExecutor( - max_workers=environment.REFLEX_COMPILE_THREADS.get() + max_workers=environment.REFLEX_COMPILE_THREADS.get() or None ) for route, component in zip(self.pages, page_components): From 95eb66334704aee940fe8d3a0223d76282eaebeb Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Wed, 11 Dec 2024 17:15:17 -0800 Subject: [PATCH 67/71] client_state: create Var from value when pushing from backend (#4474) This ensures that the value is properly escaped/formatted for direct use in javascript code. --- reflex/experimental/client_state.py | 1 + 1 file changed, 1 insertion(+) diff --git a/reflex/experimental/client_state.py b/reflex/experimental/client_state.py index 6e9f9958d..1982b3dfe 100644 --- a/reflex/experimental/client_state.py +++ b/reflex/experimental/client_state.py @@ -242,4 +242,5 @@ class ClientStateVar(Var): """ if not self._global_ref: raise ValueError("ClientStateVar must be global to push the value.") + value = Var.create(value) return run_script(f"{_client_state_ref(self._setter_name)}({value})") From e4b57555682471ed3d7501ac02a7e6862d11983a Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Thu, 12 Dec 2024 03:22:31 +0100 Subject: [PATCH 68/71] fix: handle default_factory in get_attribute_access_type (#4517) * fix: handle default_factory in get_attribute_access_type, add tests for sqla dataclasses * only test classes which have default_factory + add test for no default --- reflex/utils/types.py | 6 +- tests/units/test_attribute_access_type.py | 128 +++++++++++++++++++--- 2 files changed, 117 insertions(+), 17 deletions(-) diff --git a/reflex/utils/types.py b/reflex/utils/types.py index 7138dafb1..fb26b14c9 100644 --- a/reflex/utils/types.py +++ b/reflex/utils/types.py @@ -331,7 +331,11 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None type_ = field.outer_type_ if isinstance(type_, ModelField): type_ = type_.type_ - if not field.required and field.default is None: + if ( + not field.required + and field.default is None + and field.default_factory is None + ): # Ensure frontend uses null coalescing when accessing. type_ = Optional[type_] return type_ diff --git a/tests/units/test_attribute_access_type.py b/tests/units/test_attribute_access_type.py index 0d490ec1e..d08c17c8c 100644 --- a/tests/units/test_attribute_access_type.py +++ b/tests/units/test_attribute_access_type.py @@ -3,11 +3,19 @@ from __future__ import annotations from typing import Dict, List, Optional, Type, Union import attrs +import pydantic.v1 import pytest import sqlalchemy +import sqlmodel from sqlalchemy import JSON, TypeDecorator from sqlalchemy.ext.hybrid import hybrid_property -from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship +from sqlalchemy.orm import ( + DeclarativeBase, + Mapped, + MappedAsDataclass, + mapped_column, + relationship, +) import reflex as rx from reflex.utils.types import GenericType, get_attribute_access_type @@ -53,6 +61,10 @@ class SQLALabel(SQLABase): id: Mapped[int] = mapped_column(primary_key=True) test_id: Mapped[int] = mapped_column(sqlalchemy.ForeignKey("test.id")) test: Mapped[SQLAClass] = relationship(back_populates="labels") + test_dataclass_id: Mapped[int] = mapped_column( + sqlalchemy.ForeignKey("test_dataclass.id") + ) + test_dataclass: Mapped[SQLAClassDataclass] = relationship(back_populates="labels") class SQLAClass(SQLABase): @@ -104,9 +116,64 @@ class SQLAClass(SQLABase): return self.labels[0] if self.labels else None +class SQLAClassDataclass(MappedAsDataclass, SQLABase): + """Test sqlalchemy model.""" + + id: Mapped[int] = mapped_column(primary_key=True) + no_default: Mapped[int] = mapped_column(nullable=True) + count: Mapped[int] = mapped_column() + name: Mapped[str] = mapped_column() + int_list: Mapped[List[int]] = mapped_column( + sqlalchemy.types.ARRAY(item_type=sqlalchemy.INTEGER) + ) + str_list: Mapped[List[str]] = mapped_column( + sqlalchemy.types.ARRAY(item_type=sqlalchemy.String) + ) + optional_int: Mapped[Optional[int]] = mapped_column(nullable=True) + sqla_tag_id: Mapped[int] = mapped_column(sqlalchemy.ForeignKey(SQLATag.id)) + sqla_tag: Mapped[Optional[SQLATag]] = relationship() + labels: Mapped[List[SQLALabel]] = relationship(back_populates="test_dataclass") + # do not use lower case dict here! + # https://github.com/sqlalchemy/sqlalchemy/issues/9902 + dict_str_str: Mapped[Dict[str, str]] = mapped_column() + default_factory: Mapped[List[int]] = mapped_column( + sqlalchemy.types.ARRAY(item_type=sqlalchemy.INTEGER), + default_factory=list, + ) + __tablename__: str = "test_dataclass" + + @property + def str_property(self) -> str: + """String property. + + Returns: + Name attribute + """ + return self.name + + @hybrid_property + def str_or_int_property(self) -> Union[str, int]: + """String or int property. + + Returns: + Name attribute + """ + return self.name + + @hybrid_property + def first_label(self) -> Optional[SQLALabel]: + """First label property. + + Returns: + First label + """ + return self.labels[0] if self.labels else None + + class ModelClass(rx.Model): """Test reflex model.""" + no_default: Optional[int] = sqlmodel.Field(nullable=True) count: int = 0 name: str = "test" int_list: List[int] = [] @@ -115,6 +182,7 @@ class ModelClass(rx.Model): sqla_tag: Optional[SQLATag] = None labels: List[SQLALabel] = [] dict_str_str: Dict[str, str] = {} + default_factory: List[int] = sqlmodel.Field(default_factory=list) @property def str_property(self) -> str: @@ -147,6 +215,7 @@ class ModelClass(rx.Model): class BaseClass(rx.Base): """Test rx.Base class.""" + no_default: Optional[int] = pydantic.v1.Field(required=False) count: int = 0 name: str = "test" int_list: List[int] = [] @@ -155,6 +224,7 @@ class BaseClass(rx.Base): sqla_tag: Optional[SQLATag] = None labels: List[SQLALabel] = [] dict_str_str: Dict[str, str] = {} + default_factory: List[int] = pydantic.v1.Field(default_factory=list) @property def str_property(self) -> str: @@ -236,6 +306,7 @@ class AttrClass: sqla_tag: Optional[SQLATag] = None labels: List[SQLALabel] = [] dict_str_str: Dict[str, str] = {} + default_factory: List[int] = attrs.field(factory=list) @property def str_property(self) -> str: @@ -265,27 +336,17 @@ class AttrClass: return self.labels[0] if self.labels else None -@pytest.fixture( - params=[ +@pytest.mark.parametrize( + "cls", + [ SQLAClass, + SQLAClassDataclass, BaseClass, BareClass, ModelClass, AttrClass, - ] + ], ) -def cls(request: pytest.FixtureRequest) -> type: - """Fixture for the class to test. - - Args: - request: pytest request object. - - Returns: - Class to test. - """ - return request.param - - @pytest.mark.parametrize( "attr, expected", [ @@ -311,3 +372,38 @@ def test_get_attribute_access_type(cls: type, attr: str, expected: GenericType) expected: Expected type. """ assert get_attribute_access_type(cls, attr) == expected + + +@pytest.mark.parametrize( + "cls", + [ + SQLAClassDataclass, + BaseClass, + ModelClass, + AttrClass, + ], +) +def test_get_attribute_access_type_default_factory(cls: type) -> None: + """Test get_attribute_access_type returns the correct type for default factory fields. + + Args: + cls: Class to test. + """ + assert get_attribute_access_type(cls, "default_factory") == List[int] + + +@pytest.mark.parametrize( + "cls", + [ + SQLAClassDataclass, + BaseClass, + ModelClass, + ], +) +def test_get_attribute_access_type_no_default(cls: type) -> None: + """Test get_attribute_access_type returns the correct type for fields with no default which are not required. + + Args: + cls: Class to test. + """ + assert get_attribute_access_type(cls, "no_default") == Optional[int] From fb444ad112d8e4d62a352e5d978a212b27b61dac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Wed, 11 Dec 2024 18:26:44 -0800 Subject: [PATCH 69/71] add ERA rules to detect commented out code (#4472) * add eradicate rules for commented out code * remove output change * fix pyi messed up indent * fix pyi again * fix layout docstring * fix pyi_generator to remove commented out props from docs * fix pyi_generator and regenerate some pyi * fix double strip * update all pyi * try to fix stuff in pyi_gen * whatever * remove that maybe? i don't know * fix that shit? * fix more shit, idk * better not see you ever again, extra line --- pyproject.toml | 2 +- reflex/app.py | 1 - reflex/components/component.py | 1 - reflex/components/core/banner.pyi | 2 +- reflex/components/core/html.pyi | 2 +- reflex/components/datadisplay/dataeditor.py | 23 +------- reflex/components/datadisplay/dataeditor.pyi | 2 +- .../datadisplay/shiki_code_block.py | 14 ++--- reflex/components/el/elements/base.py | 4 +- reflex/components/el/elements/base.pyi | 2 +- reflex/components/el/elements/forms.py | 5 +- reflex/components/el/elements/forms.pyi | 26 ++++----- reflex/components/el/elements/inline.py | 2 +- reflex/components/el/elements/inline.pyi | 56 +++++++++---------- reflex/components/el/elements/media.py | 5 +- reflex/components/el/elements/media.pyi | 51 +++++++++-------- reflex/components/el/elements/metadata.py | 2 +- reflex/components/el/elements/metadata.pyi | 8 +-- reflex/components/el/elements/other.py | 26 ++++++--- reflex/components/el/elements/other.pyi | 14 ++--- reflex/components/el/elements/scripts.py | 3 +- reflex/components/el/elements/scripts.pyi | 6 +- reflex/components/el/elements/sectioning.py | 2 +- reflex/components/el/elements/sectioning.pyi | 30 +++++----- reflex/components/el/elements/tables.py | 2 +- reflex/components/el/elements/tables.pyi | 20 +++---- reflex/components/el/elements/typography.py | 2 +- reflex/components/el/elements/typography.pyi | 30 +++++----- reflex/components/next/image.py | 2 +- reflex/components/next/image.pyi | 2 +- reflex/components/radix/primitives/form.pyi | 6 +- reflex/components/radix/primitives/slider.py | 2 +- reflex/components/radix/themes/base.py | 9 +-- reflex/components/radix/themes/color_mode.pyi | 4 +- .../radix/themes/components/alert_dialog.pyi | 2 +- .../radix/themes/components/badge.pyi | 2 +- .../radix/themes/components/button.pyi | 2 +- .../radix/themes/components/callout.pyi | 10 ++-- .../radix/themes/components/card.pyi | 2 +- .../radix/themes/components/checkbox.pyi | 6 +- .../radix/themes/components/dialog.pyi | 2 +- .../radix/themes/components/hover_card.pyi | 2 +- .../radix/themes/components/icon_button.pyi | 2 +- .../radix/themes/components/inset.pyi | 2 +- .../radix/themes/components/popover.pyi | 2 +- .../radix/themes/components/radio_group.pyi | 2 +- .../radix/themes/components/select.pyi | 6 +- .../radix/themes/components/slider.pyi | 2 +- .../radix/themes/components/switch.pyi | 2 +- .../radix/themes/components/table.pyi | 14 ++--- .../radix/themes/components/tabs.pyi | 4 +- .../radix/themes/components/text_area.pyi | 2 +- .../radix/themes/components/text_field.pyi | 4 +- reflex/components/radix/themes/layout/box.pyi | 2 +- .../components/radix/themes/layout/center.pyi | 2 +- .../components/radix/themes/layout/flex.pyi | 2 +- .../components/radix/themes/layout/grid.pyi | 2 +- reflex/components/radix/themes/layout/list.py | 4 -- .../components/radix/themes/layout/list.pyi | 11 +--- .../radix/themes/layout/section.pyi | 2 +- .../components/radix/themes/layout/spacer.pyi | 2 +- .../components/radix/themes/layout/stack.pyi | 6 +- .../radix/themes/typography/blockquote.pyi | 2 +- .../radix/themes/typography/code.pyi | 2 +- .../radix/themes/typography/heading.pyi | 2 +- .../radix/themes/typography/link.pyi | 2 +- .../radix/themes/typography/text.pyi | 14 ++--- reflex/components/recharts/cartesian.py | 2 +- reflex/components/recharts/polar.py | 2 +- reflex/components/recharts/polar.pyi | 2 +- reflex/components/sonner/toast.py | 7 +-- reflex/components/suneditor/editor.py | 12 ++-- reflex/components/suneditor/editor.pyi | 12 ++-- reflex/event.py | 2 +- reflex/experimental/layout.py | 6 -- reflex/style.py | 3 - reflex/testing.py | 3 +- reflex/utils/format.py | 1 - reflex/utils/pyi_generator.py | 12 ++-- reflex/utils/types.py | 1 - tests/integration/test_computed_vars.py | 1 - tests/integration/test_input.py | 6 +- tests/units/components/base/test_bare.py | 3 - tests/units/components/media/test_image.py | 2 +- tests/units/components/test_component.py | 18 +++--- tests/units/test_app.py | 6 -- tests/units/test_event.py | 4 -- tests/units/test_sqlalchemy.py | 4 +- tests/units/test_state.py | 9 ++- tests/units/test_telemetry.py | 6 -- tests/units/test_var.py | 4 -- 91 files changed, 272 insertions(+), 349 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1b47bb366..d59e7b8af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,7 +93,7 @@ build-backend = "poetry.core.masonry.api" [tool.ruff] target-version = "py39" lint.isort.split-on-trailing-comma = false -lint.select = ["B", "D", "E", "F", "I", "SIM", "W", "RUF", "FURB"] +lint.select = ["B", "D", "E", "F", "I", "SIM", "W", "RUF", "FURB", "ERA"] lint.ignore = ["B008", "D205", "E501", "F403", "SIM115", "RUF006", "RUF012"] lint.pydocstyle.convention = "google" diff --git a/reflex/app.py b/reflex/app.py index 6a17a56b6..3f981a6c3 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -965,7 +965,6 @@ class App(MiddlewareMixin, LifespanMixin): def _submit_work(fn, *args, **kwargs): f = executor.submit(fn, *args, **kwargs) - # f = executor.apipe(fn, *args, **kwargs) result_futures.append(f) # Compile the pre-compiled pages. diff --git a/reflex/components/component.py b/reflex/components/component.py index 75a821ac8..fd7c93cbd 100644 --- a/reflex/components/component.py +++ b/reflex/components/component.py @@ -653,7 +653,6 @@ class Component(BaseComponent, ABC): Returns: The event triggers. - """ default_triggers: Dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]] = { EventTriggers.ON_FOCUS: no_args_event_spec, diff --git a/reflex/components/core/banner.pyi b/reflex/components/core/banner.pyi index 3296b84ee..f44ee7992 100644 --- a/reflex/components/core/banner.pyi +++ b/reflex/components/core/banner.pyi @@ -321,7 +321,7 @@ class ConnectionPulser(Div): """Create a connection pulser component. Args: - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/core/html.pyi b/reflex/components/core/html.pyi index ffa7f88bb..e65549d0f 100644 --- a/reflex/components/core/html.pyi +++ b/reflex/components/core/html.pyi @@ -71,7 +71,7 @@ class Html(Div): Args: *children: The children of the component. dangerouslySetInnerHTML: The HTML to render. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/datadisplay/dataeditor.py b/reflex/components/datadisplay/dataeditor.py index 93352c291..79813205f 100644 --- a/reflex/components/datadisplay/dataeditor.py +++ b/reflex/components/datadisplay/dataeditor.py @@ -51,27 +51,6 @@ class GridColumnIcons(Enum): VideoUri = "video_uri" -# @serializer -# def serialize_gridcolumn_icon(icon: GridColumnIcons) -> str: -# """Serialize grid column icon. - -# Args: -# icon: the Icon to serialize. - -# Returns: -# The serialized value. -# """ -# return "prefix" + str(icon) - - -# class DataEditorColumn(Base): -# """Column.""" - -# title: str -# id: Optional[str] = None -# type_: str = "str" - - class DataEditorTheme(Base): """The theme for the DataEditor component.""" @@ -229,7 +208,7 @@ class DataEditor(NoSSRComponent): header_height: Var[int] # Additional header icons: - # header_icons: Var[Any] # (TODO: must be a map of name: svg) + # header_icons: Var[Any] # (TODO: must be a map of name: svg) #noqa: ERA001 # The maximum width a column can be automatically sized to. max_column_auto_width: Var[int] diff --git a/reflex/components/datadisplay/dataeditor.pyi b/reflex/components/datadisplay/dataeditor.pyi index aa4b3b2e8..17272d8dc 100644 --- a/reflex/components/datadisplay/dataeditor.pyi +++ b/reflex/components/datadisplay/dataeditor.pyi @@ -288,7 +288,7 @@ class DataEditor(NoSSRComponent): freeze_columns: The number of columns which should remain in place when scrolling horizontally. Doesn't include rowMarkers. group_header_height: Controls the header of the group header row. header_height: Controls the height of the header row. - max_column_auto_width: Additional header icons: header_icons: Var[Any] # (TODO: must be a map of name: svg) The maximum width a column can be automatically sized to. + max_column_auto_width: The maximum width a column can be automatically sized to. max_column_width: The maximum width a column can be resized to. min_column_width: The minimum width a column can be resized to. row_height: Determins the height of each row. diff --git a/reflex/components/datadisplay/shiki_code_block.py b/reflex/components/datadisplay/shiki_code_block.py index 2b4e1f506..3b6bce8a1 100644 --- a/reflex/components/datadisplay/shiki_code_block.py +++ b/reflex/components/datadisplay/shiki_code_block.py @@ -490,17 +490,17 @@ class ShikiJsTransformer(ShikiBaseTransformers): }, # White Space # ".tab, .space": { - # "position": "relative", + # "position": "relative", # noqa: ERA001 # }, # ".tab::before": { - # "content": "'⇥'", - # "position": "absolute", - # "opacity": "0.3", + # "content": "'⇥'", # noqa: ERA001 + # "position": "absolute", # noqa: ERA001 + # "opacity": "0.3",# noqa: ERA001 # }, # ".space::before": { - # "content": "'·'", - # "position": "absolute", - # "opacity": "0.3", + # "content": "'·'", # noqa: ERA001 + # "position": "absolute", # noqa: ERA001 + # "opacity": "0.3", # noqa: ERA001 # }, } ) diff --git a/reflex/components/el/elements/base.py b/reflex/components/el/elements/base.py index a9748ae25..f6e191f68 100644 --- a/reflex/components/el/elements/base.py +++ b/reflex/components/el/elements/base.py @@ -1,4 +1,4 @@ -"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" +"""Base classes.""" from typing import Union @@ -9,7 +9,7 @@ from reflex.vars.base import Var class BaseHTML(Element): """Base class for common attributes.""" - # Provides a hint for generating a keyboard shortcut for the current element. + # Provides a hint for generating a keyboard shortcut for the current element. access_key: Var[Union[str, int, bool]] # Controls whether and how text input is automatically capitalized as it is entered/edited by the user. diff --git a/reflex/components/el/elements/base.pyi b/reflex/components/el/elements/base.pyi index 4d1d2c5c4..b60dabe87 100644 --- a/reflex/components/el/elements/base.pyi +++ b/reflex/components/el/elements/base.pyi @@ -67,7 +67,7 @@ class BaseHTML(Element): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/el/elements/forms.py b/reflex/components/el/elements/forms.py index a82d6bcdd..205aae267 100644 --- a/reflex/components/el/elements/forms.py +++ b/reflex/components/el/elements/forms.py @@ -1,4 +1,4 @@ -"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" +"""Forms classes.""" from __future__ import annotations @@ -84,7 +84,6 @@ class Datalist(BaseHTML): """Display the datalist element.""" tag = "datalist" - # No unique attributes, only common ones are inherited class Fieldset(Element): @@ -250,7 +249,6 @@ class Form(BaseHTML): _js_expr=f"getRefValue({ref_var!s})", _var_data=VarData.merge(ref_var._get_all_var_data()), ) - # print(repr(form_refs)) return form_refs def _get_vars(self, include_children: bool = True) -> Iterator[Var]: @@ -401,7 +399,6 @@ class Legend(BaseHTML): """Display the legend element.""" tag = "legend" - # No unique attributes, only common ones are inherited class Meter(BaseHTML): diff --git a/reflex/components/el/elements/forms.pyi b/reflex/components/el/elements/forms.pyi index e2d659338..5870d4b22 100644 --- a/reflex/components/el/elements/forms.pyi +++ b/reflex/components/el/elements/forms.pyi @@ -103,7 +103,7 @@ class Button(BaseHTML): name: Name of the button, used when sending form data type: Type of the button (submit, reset, or button) value: Value of the button, used when sending form data - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -189,7 +189,7 @@ class Datalist(BaseHTML): Args: *children: The children of the component. - access_key: No unique attributes, only common ones are inherited Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -367,7 +367,7 @@ class Form(BaseHTML): reset_on_submit: If true, the form will be cleared after submit. handle_submit_unique_name: The name used to make this form's submit handler function unique. on_submit: Fired when the form is submitted - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -554,7 +554,7 @@ class Input(BaseHTML): on_blur: Fired when the input loses focus on_key_down: Fired when a key is pressed down on_key_up: Fired when a key is released - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -644,7 +644,7 @@ class Label(BaseHTML): *children: The children of the component. html_for: ID of a form control with which the label is associated form: Associates the label with a form (by id) - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -730,7 +730,7 @@ class Legend(BaseHTML): Args: *children: The children of the component. - access_key: No unique attributes, only common ones are inherited Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -830,7 +830,7 @@ class Meter(BaseHTML): min: Minimum value of the range optimum: Optimum value in the range value: Current value of the meter - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -920,7 +920,7 @@ class Optgroup(BaseHTML): *children: The children of the component. disabled: Disables the optgroup label: Label for the optgroup - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1014,7 +1014,7 @@ class Option(BaseHTML): label: Label for the option, if the text is not the label selected: Indicates that the option is initially selected value: Value to be sent as form data - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1106,7 +1106,7 @@ class Output(BaseHTML): html_for: Associates the output with one or more elements (by their IDs) form: Associates the output with a form (by id) name: Name of the output element for form submission - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1198,7 +1198,7 @@ class Progress(BaseHTML): form: Associates the progress element with a form (by id) max: Maximum value of the progress indicator value: Current value of the progress indicator - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1306,7 +1306,7 @@ class Select(BaseHTML): required: Indicates that the select control must have a selected option size: Number of visible options in a drop-down list on_change: Fired when the select value changes - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1459,7 +1459,7 @@ class Textarea(BaseHTML): on_blur: Fired when the input loses focus on_key_down: Fired when a key is pressed down on_key_up: Fired when a key is released - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/el/elements/inline.py b/reflex/components/el/elements/inline.py index d1bdf6b87..270eca28e 100644 --- a/reflex/components/el/elements/inline.py +++ b/reflex/components/el/elements/inline.py @@ -1,4 +1,4 @@ -"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" +"""Inline classes.""" from typing import Union diff --git a/reflex/components/el/elements/inline.pyi b/reflex/components/el/elements/inline.pyi index 1b4af4fc8..06aeeca76 100644 --- a/reflex/components/el/elements/inline.pyi +++ b/reflex/components/el/elements/inline.pyi @@ -88,7 +88,7 @@ class A(BaseHTML): rel: Specifies the relationship between the linked document and the current document shape: Specifies the shape of the area target: Specifies where to open the linked document - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -174,7 +174,7 @@ class Abbr(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -260,7 +260,7 @@ class B(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -346,7 +346,7 @@ class Bdi(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -432,7 +432,7 @@ class Bdo(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -518,7 +518,7 @@ class Br(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -604,7 +604,7 @@ class Cite(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -690,7 +690,7 @@ class Code(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -778,7 +778,7 @@ class Data(BaseHTML): Args: *children: The children of the component. value: Specifies the machine-readable translation of the data element. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -864,7 +864,7 @@ class Dfn(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -950,7 +950,7 @@ class Em(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1036,7 +1036,7 @@ class I(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1122,7 +1122,7 @@ class Kbd(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1208,7 +1208,7 @@ class Mark(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1296,7 +1296,7 @@ class Q(BaseHTML): Args: *children: The children of the component. cite: Specifies the source URL of the quote. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1382,7 +1382,7 @@ class Rp(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1468,7 +1468,7 @@ class Rt(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1554,7 +1554,7 @@ class Ruby(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1640,7 +1640,7 @@ class S(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1726,7 +1726,7 @@ class Samp(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1812,7 +1812,7 @@ class Small(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1898,7 +1898,7 @@ class Span(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1984,7 +1984,7 @@ class Strong(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -2070,7 +2070,7 @@ class Sub(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -2156,7 +2156,7 @@ class Sup(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -2244,7 +2244,7 @@ class Time(BaseHTML): Args: *children: The children of the component. date_time: Specifies the date and/or time of the element. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -2330,7 +2330,7 @@ class U(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -2416,7 +2416,7 @@ class Wbr(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/el/elements/media.py b/reflex/components/el/elements/media.py index 9935902ad..7d2f0e3e9 100644 --- a/reflex/components/el/elements/media.py +++ b/reflex/components/el/elements/media.py @@ -1,4 +1,4 @@ -"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" +"""Media classes.""" from typing import Any, Union @@ -129,7 +129,6 @@ class Img(BaseHTML): Returns: The component. - """ return ( super().create(src=children[0], **props) @@ -274,14 +273,12 @@ class Picture(BaseHTML): """Display the picture element.""" tag = "picture" - # No unique attributes, only common ones are inherited class Portal(BaseHTML): """Display the portal element.""" tag = "portal" - # No unique attributes, only common ones are inherited class Source(BaseHTML): diff --git a/reflex/components/el/elements/media.pyi b/reflex/components/el/elements/media.pyi index edaf1228e..b172d0c07 100644 --- a/reflex/components/el/elements/media.pyi +++ b/reflex/components/el/elements/media.pyi @@ -94,7 +94,7 @@ class Area(BaseHTML): rel: Specifies the relationship of the target object to the link object shape: Defines the shape of the area (rectangle, circle, polygon) target: Specifies where to open the linked document - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -198,7 +198,7 @@ class Audio(BaseHTML): muted: Indicates whether the audio is muted by default preload: Specifies how the audio file should be preloaded src: URL of the audio to play - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -314,7 +314,7 @@ class Img(BaseHTML): src: URL of the image to display src_set: A set of source sizes and URLs for responsive images use_map: The name of the map to use with the image - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -340,7 +340,6 @@ class Img(BaseHTML): Returns: The component. - """ ... @@ -403,7 +402,7 @@ class Map(BaseHTML): Args: *children: The children of the component. name: Name of the map, referenced by the 'usemap' attribute in 'img' and 'object' elements - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -499,7 +498,7 @@ class Track(BaseHTML): label: Title of the text track, used by the browser when listing available text tracks src: URL of the track file src_lang: Language of the track text data - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -609,7 +608,7 @@ class Video(BaseHTML): poster: URL of an image to show while the video is downloading, or until the user hits the play button preload: Specifies how the video file should be preloaded src: URL of the video to play - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -699,7 +698,7 @@ class Embed(BaseHTML): *children: The children of the component. src: URL of the embedded content type: Media type of the embedded content - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -805,7 +804,7 @@ class Iframe(BaseHTML): sandbox: Security restrictions for the content in the iframe src: URL of the document to display in the iframe src_doc: HTML content to embed directly within the iframe - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -901,7 +900,7 @@ class Object(BaseHTML): name: Name of the object, used for scripting or as a target for forms and links type: Media type of the data specified in the data attribute use_map: Name of an image map to use with the object - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -987,7 +986,7 @@ class Picture(BaseHTML): Args: *children: The children of the component. - access_key: No unique attributes, only common ones are inherited Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1073,7 +1072,7 @@ class Portal(BaseHTML): Args: *children: The children of the component. - access_key: No unique attributes, only common ones are inherited Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1169,7 +1168,7 @@ class Source(BaseHTML): src: URL of the media file or an image for the element to use src_set: A set of source sizes and URLs for responsive images type: Media type of the source - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1261,7 +1260,7 @@ class Svg(BaseHTML): width: The width of the svg. height: The height of the svg. xmlns: The XML namespace declaration. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1361,7 +1360,7 @@ class Text(BaseHTML): rotate: Rotates orientation of each individual glyph. length_adjust: How the text is stretched or compressed to fit the width defined by the text_length attribute. text_length: A width that the text should be scaled to fit. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1457,7 +1456,7 @@ class Line(BaseHTML): y1: The y-axis coordinate of the line starting point. y2: The y-axis coordinate of the the line ending point. path_length: The total path length, in user units. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1551,7 +1550,7 @@ class Circle(BaseHTML): cy: The y-axis coordinate of the center of the circle. r: The radius of the circle. path_length: The total length for the circle's circumference, in user units. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1647,7 +1646,7 @@ class Ellipse(BaseHTML): rx: The radius of the ellipse on the x axis. ry: The radius of the ellipse on the y axis. path_length: The total length for the ellipse's circumference, in user units. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1747,7 +1746,7 @@ class Rect(BaseHTML): rx: The horizontal corner radius of the rect. Defaults to ry if it is specified. ry: The vertical corner radius of the rect. Defaults to rx if it is specified. path_length: The total length of the rectangle's perimeter, in user units. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1837,7 +1836,7 @@ class Polygon(BaseHTML): *children: The children of the component. points: defines the list of points (pairs of x,y absolute coordinates) required to draw the polygon. path_length: This prop lets specify the total length for the path, in user units. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1923,7 +1922,7 @@ class Defs(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -2023,7 +2022,7 @@ class LinearGradient(BaseHTML): x2: X coordinate of the ending point of the gradient. y1: Y coordinate of the starting point of the gradient. y2: Y coordinate of the ending point of the gradient. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -2127,7 +2126,7 @@ class RadialGradient(BaseHTML): gradient_transform: Transform applied to the gradient. r: The radius of the end circle of the radial gradient. spread_method: Method used to spread the gradient. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -2223,7 +2222,7 @@ class Stop(BaseHTML): offset: Offset of the gradient stop. stop_color: Color of the gradient stop. stop_opacity: Opacity of the gradient stop. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -2311,7 +2310,7 @@ class Path(BaseHTML): Args: *children: The children of the component. d: Defines the shape of the path. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -2413,7 +2412,7 @@ class SVG(ComponentNamespace): width: The width of the svg. height: The height of the svg. xmlns: The XML namespace declaration. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/el/elements/metadata.py b/reflex/components/el/elements/metadata.py index 94c1e8faa..458253a01 100644 --- a/reflex/components/el/elements/metadata.py +++ b/reflex/components/el/elements/metadata.py @@ -1,4 +1,4 @@ -"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" +"""Metadata classes.""" from typing import List, Union diff --git a/reflex/components/el/elements/metadata.pyi b/reflex/components/el/elements/metadata.pyi index 5af92e2b2..08cd2fd76 100644 --- a/reflex/components/el/elements/metadata.pyi +++ b/reflex/components/el/elements/metadata.pyi @@ -71,7 +71,7 @@ class Base(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -157,7 +157,7 @@ class Head(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -265,7 +265,7 @@ class Link(BaseHTML): rel: Specifies the relationship between the current document and the linked one sizes: Specifies the sizes of icons for visual media type: Specifies the MIME type of the linked document - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -359,7 +359,7 @@ class Meta(BaseHTML): content: Defines the content of the metadata http_equiv: Provides an HTTP header for the information/value of the content attribute name: Specifies a name for the metadata - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/el/elements/other.py b/reflex/components/el/elements/other.py index fa7c6cdec..4e7f0f227 100644 --- a/reflex/components/el/elements/other.py +++ b/reflex/components/el/elements/other.py @@ -1,4 +1,4 @@ -"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" +"""Other classes.""" from typing import Union @@ -26,31 +26,39 @@ class Dialog(BaseHTML): class Summary(BaseHTML): - """Display the summary element.""" + """Display the summary element. + + Used as a summary or caption for a
element. + """ tag = "summary" - # No unique attributes, only common ones are inherited; used as a summary or caption for a
element class Slot(BaseHTML): - """Display the slot element.""" + """Display the slot element. + + Used as a placeholder inside a web component. + """ tag = "slot" - # No unique attributes, only common ones are inherited; used as a placeholder inside a web component class Template(BaseHTML): - """Display the template element.""" + """Display the template element. + + Used for declaring fragments of HTML that can be cloned and inserted in the document. + """ tag = "template" - # No unique attributes, only common ones are inherited; used for declaring fragments of HTML that can be cloned and inserted in the document class Math(BaseHTML): - """Display the math element.""" + """Display the math element. + + Represents a mathematical expression. + """ tag = "math" - # No unique attributes, only common ones are inherited; used for displaying mathematical expressions class Html(BaseHTML): diff --git a/reflex/components/el/elements/other.pyi b/reflex/components/el/elements/other.pyi index 3d65af647..57e4ab24b 100644 --- a/reflex/components/el/elements/other.pyi +++ b/reflex/components/el/elements/other.pyi @@ -70,7 +70,7 @@ class Details(BaseHTML): Args: *children: The children of the component. open: Indicates whether the details will be visible (expanded) to the user - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -158,7 +158,7 @@ class Dialog(BaseHTML): Args: *children: The children of the component. open: Indicates whether the dialog is active and can be interacted with - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -244,7 +244,7 @@ class Summary(BaseHTML): Args: *children: The children of the component. - access_key: No unique attributes, only common ones are inherited; used as a summary or caption for a
element Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -330,7 +330,7 @@ class Slot(BaseHTML): Args: *children: The children of the component. - access_key: No unique attributes, only common ones are inherited; used as a placeholder inside a web component Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -416,7 +416,7 @@ class Template(BaseHTML): Args: *children: The children of the component. - access_key: No unique attributes, only common ones are inherited; used for declaring fragments of HTML that can be cloned and inserted in the document Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -502,7 +502,7 @@ class Math(BaseHTML): Args: *children: The children of the component. - access_key: No unique attributes, only common ones are inherited; used for displaying mathematical expressions Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -590,7 +590,7 @@ class Html(BaseHTML): Args: *children: The children of the component. manifest: Specifies the URL of the document's cache manifest (obsolete in HTML5) - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/el/elements/scripts.py b/reflex/components/el/elements/scripts.py index b53306e02..c30931e99 100644 --- a/reflex/components/el/elements/scripts.py +++ b/reflex/components/el/elements/scripts.py @@ -1,4 +1,4 @@ -"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" +"""Scripts classes.""" from typing import Union @@ -17,7 +17,6 @@ class Noscript(BaseHTML): """Display the noscript element.""" tag = "noscript" - # No unique attributes, only common ones are inherited class Script(BaseHTML): diff --git a/reflex/components/el/elements/scripts.pyi b/reflex/components/el/elements/scripts.pyi index 6f03c20cb..c66e150af 100644 --- a/reflex/components/el/elements/scripts.pyi +++ b/reflex/components/el/elements/scripts.pyi @@ -68,7 +68,7 @@ class Canvas(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -154,7 +154,7 @@ class Noscript(BaseHTML): Args: *children: The children of the component. - access_key: No unique attributes, only common ones are inherited Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -262,7 +262,7 @@ class Script(BaseHTML): referrer_policy: Specifies which referrer information to send when fetching the script src: URL of an external script type: Specifies the MIME type of the script - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/el/elements/sectioning.py b/reflex/components/el/elements/sectioning.py index e74d7929c..cfe82b6d5 100644 --- a/reflex/components/el/elements/sectioning.py +++ b/reflex/components/el/elements/sectioning.py @@ -1,4 +1,4 @@ -"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" +"""Sectioning classes.""" from .base import BaseHTML diff --git a/reflex/components/el/elements/sectioning.pyi b/reflex/components/el/elements/sectioning.pyi index e34d53ee2..ecbabe516 100644 --- a/reflex/components/el/elements/sectioning.pyi +++ b/reflex/components/el/elements/sectioning.pyi @@ -68,7 +68,7 @@ class Body(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -154,7 +154,7 @@ class Address(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -240,7 +240,7 @@ class Article(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -326,7 +326,7 @@ class Aside(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -412,7 +412,7 @@ class Footer(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -498,7 +498,7 @@ class Header(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -584,7 +584,7 @@ class H1(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -670,7 +670,7 @@ class H2(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -756,7 +756,7 @@ class H3(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -842,7 +842,7 @@ class H4(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -928,7 +928,7 @@ class H5(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1014,7 +1014,7 @@ class H6(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1100,7 +1100,7 @@ class Main(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1186,7 +1186,7 @@ class Nav(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1272,7 +1272,7 @@ class Section(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/el/elements/tables.py b/reflex/components/el/elements/tables.py index 8f6cfcba4..a0c10d829 100644 --- a/reflex/components/el/elements/tables.py +++ b/reflex/components/el/elements/tables.py @@ -1,4 +1,4 @@ -"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" +"""Tables classes.""" from typing import Union diff --git a/reflex/components/el/elements/tables.pyi b/reflex/components/el/elements/tables.pyi index b0495009d..420bad585 100644 --- a/reflex/components/el/elements/tables.pyi +++ b/reflex/components/el/elements/tables.pyi @@ -70,7 +70,7 @@ class Caption(BaseHTML): Args: *children: The children of the component. align: Alignment of the caption - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -160,7 +160,7 @@ class Col(BaseHTML): *children: The children of the component. align: Alignment of the content within the column span: Number of columns the col element spans - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -250,7 +250,7 @@ class Colgroup(BaseHTML): *children: The children of the component. align: Alignment of the content within the column group span: Number of columns the colgroup element spans - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -340,7 +340,7 @@ class Table(BaseHTML): *children: The children of the component. align: Alignment of the table summary: Provides a summary of the table's purpose and structure - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -428,7 +428,7 @@ class Tbody(BaseHTML): Args: *children: The children of the component. align: Alignment of the content within the table body - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -522,7 +522,7 @@ class Td(BaseHTML): col_span: Number of columns a cell should span headers: IDs of the headers associated with this cell row_span: Number of rows a cell should span - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -610,7 +610,7 @@ class Tfoot(BaseHTML): Args: *children: The children of the component. align: Alignment of the content within the table footer - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -706,7 +706,7 @@ class Th(BaseHTML): headers: IDs of the headers associated with this header cell row_span: Number of rows a header cell should span scope: Scope of the header cell (row, col, rowgroup, colgroup) - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -794,7 +794,7 @@ class Thead(BaseHTML): Args: *children: The children of the component. align: Alignment of the content within the table header - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -882,7 +882,7 @@ class Tr(BaseHTML): Args: *children: The children of the component. align: Alignment of the content within the table row - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/el/elements/typography.py b/reflex/components/el/elements/typography.py index 7c55ecce7..9fa5c3a02 100644 --- a/reflex/components/el/elements/typography.py +++ b/reflex/components/el/elements/typography.py @@ -1,4 +1,4 @@ -"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py.""" +"""Typography classes.""" from typing import Union diff --git a/reflex/components/el/elements/typography.pyi b/reflex/components/el/elements/typography.pyi index b28af1c40..8332b3306 100644 --- a/reflex/components/el/elements/typography.pyi +++ b/reflex/components/el/elements/typography.pyi @@ -70,7 +70,7 @@ class Blockquote(BaseHTML): Args: *children: The children of the component. cite: Define the title of a work. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -156,7 +156,7 @@ class Dd(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -242,7 +242,7 @@ class Div(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -328,7 +328,7 @@ class Dl(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -414,7 +414,7 @@ class Dt(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -500,7 +500,7 @@ class Figcaption(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -588,7 +588,7 @@ class Hr(BaseHTML): Args: *children: The children of the component. align: Used to specify the alignment of text content of The Element. this attribute is used in all elements. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -674,7 +674,7 @@ class Li(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -762,7 +762,7 @@ class Menu(BaseHTML): Args: *children: The children of the component. type: Specifies that the menu element is a context menu. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -854,7 +854,7 @@ class Ol(BaseHTML): reversed: Reverses the order of the list. start: Specifies the start value of the first list item in an ordered list. type: Specifies the kind of marker to use in the list (letters or numbers). - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -940,7 +940,7 @@ class P(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1026,7 +1026,7 @@ class Pre(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1112,7 +1112,7 @@ class Ul(BaseHTML): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1202,7 +1202,7 @@ class Ins(BaseHTML): *children: The children of the component. cite: Specifies the URL of the document that explains the reason why the text was inserted/changed. date_time: Specifies the date and time of when the text was inserted/changed. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1292,7 +1292,7 @@ class Del(BaseHTML): *children: The children of the component. cite: Specifies the URL of the document that explains the reason why the text was deleted. date_time: Specifies the date and time of when the text was deleted. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/next/image.py b/reflex/components/next/image.py index 237c308ce..2011505d8 100644 --- a/reflex/components/next/image.py +++ b/reflex/components/next/image.py @@ -47,7 +47,7 @@ class Image(NextComponent): placeholder: Var[str] # Allows passing CSS styles to the underlying image element. - # style: Var[Any] + # style: Var[Any] #noqa: ERA001 # The loading behavior of the image. Defaults to lazy. Can hurt performance, recommended to use `priority` instead. loading: Var[Literal["lazy", "eager"]] diff --git a/reflex/components/next/image.pyi b/reflex/components/next/image.pyi index 0c1bf01f2..dd9dd38c3 100644 --- a/reflex/components/next/image.pyi +++ b/reflex/components/next/image.pyi @@ -70,7 +70,7 @@ class Image(NextComponent): quality: The quality of the optimized image, an integer between 1 and 100, where 100 is the best quality and therefore largest file size. Defaults to 75. 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: Allows passing CSS styles to the underlying image element. style: Var[Any] The loading behavior of the image. Defaults to lazy. Can hurt performance, recommended to use `priority` instead. + 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". on_load: Fires when the image has loaded. on_error: Fires when the image has an error. diff --git a/reflex/components/radix/primitives/form.pyi b/reflex/components/radix/primitives/form.pyi index 77c8be77c..83e65a54d 100644 --- a/reflex/components/radix/primitives/form.pyi +++ b/reflex/components/radix/primitives/form.pyi @@ -160,7 +160,7 @@ class FormRoot(FormComponent, HTMLForm): reset_on_submit: If true, the form will be cleared after submit. handle_submit_unique_name: The name used to make this form's submit handler function unique. on_submit: Fired when the form is submitted - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -636,7 +636,7 @@ class Form(FormRoot): reset_on_submit: If true, the form will be cleared after submit. handle_submit_unique_name: The name used to make this form's submit handler function unique. on_submit: Fired when the form is submitted - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -769,7 +769,7 @@ class FormNamespace(ComponentNamespace): reset_on_submit: If true, the form will be cleared after submit. handle_submit_unique_name: The name used to make this form's submit handler function unique. on_submit: Fired when the form is submitted - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/primitives/slider.py b/reflex/components/radix/primitives/slider.py index 10a0079a4..90d0920bd 100644 --- a/reflex/components/radix/primitives/slider.py +++ b/reflex/components/radix/primitives/slider.py @@ -188,7 +188,7 @@ class Slider(ComponentNamespace): else: children = [ track, - # Foreach.create(props.get("value"), lambda e: SliderThumb.create()), # foreach doesn't render Thumbs properly + # Foreach.create(props.get("value"), lambda e: SliderThumb.create()), # foreach doesn't render Thumbs properly # noqa: ERA001 ] return SliderRoot.create(*children, **props) diff --git a/reflex/components/radix/themes/base.py b/reflex/components/radix/themes/base.py index e90d41a5a..19e805f7a 100644 --- a/reflex/components/radix/themes/base.py +++ b/reflex/components/radix/themes/base.py @@ -53,7 +53,7 @@ LiteralAccentColor = Literal[ class CommonMarginProps(Component): """Many radix-themes elements accept shorthand margin props.""" - # Margin: "0" - "9" + # Margin: "0" - "9" # noqa: ERA001 m: Var[LiteralSpacing] # Margin horizontal: "0" - "9" @@ -78,7 +78,7 @@ class CommonMarginProps(Component): class CommonPaddingProps(Component): """Many radix-themes elements accept shorthand padding props.""" - # Padding: "0" - "9" + # Padding: "0" - "9" # noqa: ERA001 p: Var[Responsive[LiteralSpacing]] # Padding horizontal: "0" - "9" @@ -140,11 +140,6 @@ class RadixThemesComponent(Component): if component.library is None: component.library = RadixThemesComponent.__fields__["library"].default component.alias = "RadixThemes" + (component.tag or type(component).__name__) - # value = props.get("value") - # if value is not None and component.alias == "RadixThemesSelect.Root": - # lv = LiteralVar.create(value) - # print(repr(lv)) - # print(f"Warning: Value {value} is not used in {component.alias}.") return component @staticmethod diff --git a/reflex/components/radix/themes/color_mode.pyi b/reflex/components/radix/themes/color_mode.pyi index eb3c4234a..3a9347017 100644 --- a/reflex/components/radix/themes/color_mode.pyi +++ b/reflex/components/radix/themes/color_mode.pyi @@ -257,7 +257,7 @@ class ColorModeIconButton(IconButton): name: Name of the button, used when sending form data type: Type of the button (submit, reset, or button) value: Value of the button, used when sending form data - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -427,7 +427,7 @@ class ColorModeSwitch(Switch): color_scheme: Override theme color for switch high_contrast: Whether to render the switch with higher contrast color against background radius: Override theme radius for switch: "none" | "small" | "full" - on_change: Props to rename Fired when the value of the switch changes + on_change: Fired when the value of the switch changes style: The style of the component. key: A unique key for the component. id: The id for the component. diff --git a/reflex/components/radix/themes/components/alert_dialog.pyi b/reflex/components/radix/themes/components/alert_dialog.pyi index ad243df34..6188fdd45 100644 --- a/reflex/components/radix/themes/components/alert_dialog.pyi +++ b/reflex/components/radix/themes/components/alert_dialog.pyi @@ -194,7 +194,7 @@ class AlertDialogContent(elements.Div, RadixThemesComponent): on_open_auto_focus: Fired when the dialog is opened. on_close_auto_focus: Fired when the dialog is closed. on_escape_key_down: Fired when the escape key is pressed. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/components/badge.pyi b/reflex/components/radix/themes/components/badge.pyi index 3e4f19f6e..38f20efeb 100644 --- a/reflex/components/radix/themes/components/badge.pyi +++ b/reflex/components/radix/themes/components/badge.pyi @@ -164,7 +164,7 @@ class Badge(elements.Span, RadixThemesComponent): color_scheme: Color theme of the badge high_contrast: Whether to render the badge with higher contrast color against background radius: Override theme radius for badge: "none" | "small" | "medium" | "large" | "full" - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/components/button.pyi b/reflex/components/radix/themes/components/button.pyi index ea2b63fbe..cee24abc4 100644 --- a/reflex/components/radix/themes/components/button.pyi +++ b/reflex/components/radix/themes/components/button.pyi @@ -196,7 +196,7 @@ class Button(elements.Button, RadixLoadingProp, RadixThemesComponent): name: Name of the button, used when sending form data type: Type of the button (submit, reset, or button) value: Value of the button, used when sending form data - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/components/callout.pyi b/reflex/components/radix/themes/components/callout.pyi index b2643b558..2c469956f 100644 --- a/reflex/components/radix/themes/components/callout.pyi +++ b/reflex/components/radix/themes/components/callout.pyi @@ -162,7 +162,7 @@ class CalloutRoot(elements.Div, RadixThemesComponent): variant: Variant of button: "soft" | "surface" | "outline" color_scheme: Override theme color for button high_contrast: Whether to render the button with higher contrast color against background - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -251,7 +251,7 @@ class CalloutIcon(elements.Div, RadixThemesComponent): Args: *children: Child components. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -340,7 +340,7 @@ class CalloutText(elements.P, RadixThemesComponent): Args: *children: Child components. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -516,7 +516,7 @@ class Callout(CalloutRoot): variant: Variant of button: "soft" | "surface" | "outline" color_scheme: Override theme color for button high_contrast: Whether to render the button with higher contrast color against background - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -694,7 +694,7 @@ class CalloutNamespace(ComponentNamespace): variant: Variant of button: "soft" | "surface" | "outline" color_scheme: Override theme color for button high_contrast: Whether to render the button with higher contrast color against background - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/components/card.pyi b/reflex/components/radix/themes/components/card.pyi index 74b91f8ab..d8ab6c06b 100644 --- a/reflex/components/radix/themes/components/card.pyi +++ b/reflex/components/radix/themes/components/card.pyi @@ -95,7 +95,7 @@ class Card(elements.Div, RadixThemesComponent): as_child: Change the default rendered element for the one passed as a child, merging their props and behavior. size: Card size: "1" - "5" variant: Variant of Card: "solid" | "soft" | "outline" | "ghost" - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/components/checkbox.pyi b/reflex/components/radix/themes/components/checkbox.pyi index a8ac3a0b6..fb6b51434 100644 --- a/reflex/components/radix/themes/components/checkbox.pyi +++ b/reflex/components/radix/themes/components/checkbox.pyi @@ -153,7 +153,7 @@ class Checkbox(RadixThemesComponent): required: Whether the checkbox is required name: The name of the checkbox control when submitting the form. value: The value of the checkbox control when submitting the form. - on_change: Props to rename Fired when the checkbox is checked or unchecked. + on_change: Fired when the checkbox is checked or unchecked. style: The style of the component. key: A unique key for the component. id: The id for the component. @@ -302,7 +302,7 @@ class HighLevelCheckbox(RadixThemesComponent): required: Whether the checkbox is required name: The name of the checkbox control when submitting the form. value: The value of the checkbox control when submitting the form. - on_change: Props to rename Fired when the checkbox is checked or unchecked. + on_change: Fired when the checkbox is checked or unchecked. style: The style of the component. key: A unique key for the component. id: The id for the component. @@ -449,7 +449,7 @@ class CheckboxNamespace(ComponentNamespace): required: Whether the checkbox is required name: The name of the checkbox control when submitting the form. value: The value of the checkbox control when submitting the form. - on_change: Props to rename Fired when the checkbox is checked or unchecked. + on_change: Fired when the checkbox is checked or unchecked. style: The style of the component. key: A unique key for the component. id: The id for the component. diff --git a/reflex/components/radix/themes/components/dialog.pyi b/reflex/components/radix/themes/components/dialog.pyi index 4c3045741..b1dfc1b54 100644 --- a/reflex/components/radix/themes/components/dialog.pyi +++ b/reflex/components/radix/themes/components/dialog.pyi @@ -243,7 +243,7 @@ class DialogContent(elements.Div, RadixThemesComponent): on_escape_key_down: Fired when the escape key is pressed. on_pointer_down_outside: Fired when the pointer is down outside the dialog. on_interact_outside: Fired when the pointer interacts outside the dialog. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/components/hover_card.pyi b/reflex/components/radix/themes/components/hover_card.pyi index 4b1de0d89..d43b583c2 100644 --- a/reflex/components/radix/themes/components/hover_card.pyi +++ b/reflex/components/radix/themes/components/hover_card.pyi @@ -228,7 +228,7 @@ class HoverCardContent(elements.Div, RadixThemesComponent): sticky: The sticky behavior on the align axis. "partial" will keep the content in the boundary as long as the trigger is at least partially in the boundary whilst "always" will keep the content in the boundary regardless hide_when_detached: Whether to hide the content when the trigger becomes fully occluded. size: Hovercard size "1" - "3" - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/components/icon_button.pyi b/reflex/components/radix/themes/components/icon_button.pyi index e600a9bee..abf77e07b 100644 --- a/reflex/components/radix/themes/components/icon_button.pyi +++ b/reflex/components/radix/themes/components/icon_button.pyi @@ -193,7 +193,7 @@ class IconButton(elements.Button, RadixLoadingProp, RadixThemesComponent): name: Name of the button, used when sending form data type: Type of the button (submit, reset, or button) value: Value of the button, used when sending form data - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/components/inset.pyi b/reflex/components/radix/themes/components/inset.pyi index c4f07320b..f03275ec0 100644 --- a/reflex/components/radix/themes/components/inset.pyi +++ b/reflex/components/radix/themes/components/inset.pyi @@ -166,7 +166,7 @@ class Inset(elements.Div, RadixThemesComponent): pr: Padding on the right pb: Padding on the bottom pl: Padding on the left - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/components/popover.pyi b/reflex/components/radix/themes/components/popover.pyi index d4b324817..51f114dd2 100644 --- a/reflex/components/radix/themes/components/popover.pyi +++ b/reflex/components/radix/themes/components/popover.pyi @@ -233,7 +233,7 @@ class PopoverContent(elements.Div, RadixThemesComponent): on_pointer_down_outside: Fired when the pointer is down outside the dialog. on_focus_outside: Fired when focus moves outside the dialog. on_interact_outside: Fired when the pointer interacts outside the dialog. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/components/radio_group.pyi b/reflex/components/radix/themes/components/radio_group.pyi index f251f541f..e8e4e4254 100644 --- a/reflex/components/radix/themes/components/radio_group.pyi +++ b/reflex/components/radix/themes/components/radio_group.pyi @@ -148,7 +148,7 @@ class RadioGroupRoot(RadixThemesComponent): disabled: Whether the radio group is disabled name: The name of the group. Submitted with its owning form as part of a name/value pair. required: Whether the radio group is required - on_change: Props to rename Fired when the value of the radio group changes. + on_change: Fired when the value of the radio group changes. style: The style of the component. key: A unique key for the component. id: The id for the component. diff --git a/reflex/components/radix/themes/components/select.pyi b/reflex/components/radix/themes/components/select.pyi index 39caeef9c..a6c1ff144 100644 --- a/reflex/components/radix/themes/components/select.pyi +++ b/reflex/components/radix/themes/components/select.pyi @@ -81,7 +81,7 @@ class SelectRoot(RadixThemesComponent): name: The name of the select control when submitting the form. disabled: When True, prevents the user from interacting with select. required: When True, indicates that the user must select a value before the owning form can be submitted. - on_change: Props to rename Fired when the value of the select changes. + on_change: Fired when the value of the select changes. on_open_change: Fired when the select is opened or closed. style: The style of the component. key: A unique key for the component. @@ -732,7 +732,7 @@ class HighLevelSelect(SelectRoot): name: The name of the select control when submitting the form. disabled: When True, prevents the user from interacting with select. required: When True, indicates that the user must select a value before the owning form can be submitted. - on_change: Props to rename Fired when the value of the select changes. + on_change: Fired when the value of the select changes. on_open_change: Fired when the select is opened or closed. style: The style of the component. key: A unique key for the component. @@ -912,7 +912,7 @@ class Select(ComponentNamespace): name: The name of the select control when submitting the form. disabled: When True, prevents the user from interacting with select. required: When True, indicates that the user must select a value before the owning form can be submitted. - on_change: Props to rename Fired when the value of the select changes. + on_change: Fired when the value of the select changes. on_open_change: Fired when the select is opened or closed. style: The style of the component. key: A unique key for the component. diff --git a/reflex/components/radix/themes/components/slider.pyi b/reflex/components/radix/themes/components/slider.pyi index 972385e52..f2552fbc6 100644 --- a/reflex/components/radix/themes/components/slider.pyi +++ b/reflex/components/radix/themes/components/slider.pyi @@ -195,7 +195,7 @@ class Slider(RadixThemesComponent): step: The step value of the slider. disabled: Whether the slider is disabled orientation: The orientation of the slider. - on_change: Props to rename Fired when the value of the slider changes. + on_change: Fired when the value of the slider changes. on_value_commit: Fired when a thumb is released after being dragged. style: The style of the component. key: A unique key for the component. diff --git a/reflex/components/radix/themes/components/switch.pyi b/reflex/components/radix/themes/components/switch.pyi index 8a858040a..4aabd7da2 100644 --- a/reflex/components/radix/themes/components/switch.pyi +++ b/reflex/components/radix/themes/components/switch.pyi @@ -157,7 +157,7 @@ class Switch(RadixThemesComponent): color_scheme: Override theme color for switch high_contrast: Whether to render the switch with higher contrast color against background radius: Override theme radius for switch: "none" | "small" | "full" - on_change: Props to rename Fired when the value of the switch changes + on_change: Fired when the value of the switch changes style: The style of the component. key: A unique key for the component. id: The id for the component. diff --git a/reflex/components/radix/themes/components/table.pyi b/reflex/components/radix/themes/components/table.pyi index 9bc7bf730..99a0ba96d 100644 --- a/reflex/components/radix/themes/components/table.pyi +++ b/reflex/components/radix/themes/components/table.pyi @@ -94,7 +94,7 @@ class TableRoot(elements.Table, RadixThemesComponent): variant: The variant of the table align: Alignment of the table summary: Provides a summary of the table's purpose and structure - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -185,7 +185,7 @@ class TableHeader(elements.Thead, RadixThemesComponent): Args: *children: Child components. align: Alignment of the content within the table header - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -281,7 +281,7 @@ class TableRow(elements.Tr, RadixThemesComponent): Args: *children: Child components. align: Alignment of the content within the table row - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -395,7 +395,7 @@ class TableColumnHeaderCell(elements.Th, RadixThemesComponent): headers: IDs of the headers associated with this header cell row_span: Number of rows a header cell should span scope: Scope of the header cell (row, col, rowgroup, colgroup) - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -486,7 +486,7 @@ class TableBody(elements.Tbody, RadixThemesComponent): Args: *children: Child components. align: Alignment of the content within the table body - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -717,7 +717,7 @@ class TableCell(elements.Td, CommonPaddingProps, RadixThemesComponent): col_span: Number of columns a cell should span headers: IDs of the headers associated with this cell row_span: Number of rows a cell should span - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -957,7 +957,7 @@ class TableRowHeaderCell(elements.Th, CommonPaddingProps, RadixThemesComponent): headers: IDs of the headers associated with this header cell row_span: Number of rows a header cell should span scope: Scope of the header cell (row, col, rowgroup, colgroup) - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/components/tabs.pyi b/reflex/components/radix/themes/components/tabs.pyi index b5e7de5f4..8830c8e21 100644 --- a/reflex/components/radix/themes/components/tabs.pyi +++ b/reflex/components/radix/themes/components/tabs.pyi @@ -72,7 +72,7 @@ class TabsRoot(RadixThemesComponent): orientation: The orientation of the tabs. dir: Reading direction of the tabs. activation_mode: The mode of activation for the tabs. "automatic" will activate the tab when focused. "manual" will activate the tab when clicked. - on_change: Props to rename Fired when the value of the tabs changes. + on_change: Fired when the value of the tabs changes. style: The style of the component. key: A unique key for the component. id: The id for the component. @@ -374,7 +374,7 @@ class Tabs(ComponentNamespace): orientation: The orientation of the tabs. dir: Reading direction of the tabs. activation_mode: The mode of activation for the tabs. "automatic" will activate the tab when focused. "manual" will activate the tab when clicked. - on_change: Props to rename Fired when the value of the tabs changes. + on_change: Fired when the value of the tabs changes. style: The style of the component. key: A unique key for the component. id: The id for the component. diff --git a/reflex/components/radix/themes/components/text_area.pyi b/reflex/components/radix/themes/components/text_area.pyi index 63d474842..f0903ba98 100644 --- a/reflex/components/radix/themes/components/text_area.pyi +++ b/reflex/components/radix/themes/components/text_area.pyi @@ -239,7 +239,7 @@ class TextArea(RadixThemesComponent, elements.Textarea): on_blur: Fired when the input loses focus on_key_down: Fired when a key is pressed down on_key_up: Fired when a key is released - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/components/text_field.pyi b/reflex/components/radix/themes/components/text_field.pyi index edce803eb..09d58ed8f 100644 --- a/reflex/components/radix/themes/components/text_field.pyi +++ b/reflex/components/radix/themes/components/text_field.pyi @@ -213,7 +213,7 @@ class TextFieldRoot(elements.Div, RadixThemesComponent): on_blur: Fired when the textarea is blurred. on_key_down: Fired when a key is pressed down. on_key_up: Fired when a key is released. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -550,7 +550,7 @@ class TextField(ComponentNamespace): on_blur: Fired when the textarea is blurred. on_key_down: Fired when a key is pressed down. on_key_up: Fired when a key is released. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/layout/box.pyi b/reflex/components/radix/themes/layout/box.pyi index 648995b01..416e45f3a 100644 --- a/reflex/components/radix/themes/layout/box.pyi +++ b/reflex/components/radix/themes/layout/box.pyi @@ -72,7 +72,7 @@ class Box(elements.Div, RadixThemesComponent): Args: *children: Child components. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/layout/center.pyi b/reflex/components/radix/themes/layout/center.pyi index e932be6c8..c166b4c26 100644 --- a/reflex/components/radix/themes/layout/center.pyi +++ b/reflex/components/radix/themes/layout/center.pyi @@ -155,7 +155,7 @@ class Center(Flex): justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between" wrap: Whether children should wrap when they reach the end of their container: "nowrap" | "wrap" | "wrap-reverse" spacing: Gap between children: "0" - "9" - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/layout/flex.pyi b/reflex/components/radix/themes/layout/flex.pyi index 8462720d0..43f42107d 100644 --- a/reflex/components/radix/themes/layout/flex.pyi +++ b/reflex/components/radix/themes/layout/flex.pyi @@ -158,7 +158,7 @@ class Flex(elements.Div, RadixThemesComponent): justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between" wrap: Whether children should wrap when they reach the end of their container: "nowrap" | "wrap" | "wrap-reverse" spacing: Gap between children: "0" - "9" - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/layout/grid.pyi b/reflex/components/radix/themes/layout/grid.pyi index 0f4be760f..2b0e13365 100644 --- a/reflex/components/radix/themes/layout/grid.pyi +++ b/reflex/components/radix/themes/layout/grid.pyi @@ -190,7 +190,7 @@ class Grid(elements.Div, RadixThemesComponent): spacing: Gap between children: "0" - "9" spacing_x: Gap between children horizontal: "0" - "9" spacing_y: Gap between children vertical: "0" - "9" - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/layout/list.py b/reflex/components/radix/themes/layout/list.py index 96fa169a0..a306e19a4 100644 --- a/reflex/components/radix/themes/layout/list.py +++ b/reflex/components/radix/themes/layout/list.py @@ -64,7 +64,6 @@ class BaseList(Component, MarkdownComponentMap): Returns: The list component. - """ items = props.pop("items", None) list_style_type = props.pop("list_style_type", "none") @@ -114,7 +113,6 @@ class UnorderedList(BaseList, Ul): Returns: The list component. - """ items = props.pop("items", None) list_style_type = props.pop("list_style_type", "disc") @@ -144,7 +142,6 @@ class OrderedList(BaseList, Ol): Returns: The list component. - """ items = props.pop("items", None) list_style_type = props.pop("list_style_type", "decimal") @@ -168,7 +165,6 @@ class ListItem(Li, MarkdownComponentMap): Returns: The list item component. - """ for child in children: if isinstance(child, Text): diff --git a/reflex/components/radix/themes/layout/list.pyi b/reflex/components/radix/themes/layout/list.pyi index b42f689b9..8517a6897 100644 --- a/reflex/components/radix/themes/layout/list.pyi +++ b/reflex/components/radix/themes/layout/list.pyi @@ -118,7 +118,6 @@ class BaseList(Component, MarkdownComponentMap): Returns: The list component. - """ ... @@ -226,7 +225,7 @@ class UnorderedList(BaseList, Ul): *children: The children of the component. list_style_type: The style of the list. Default to "none". items: A list of items to add to the list. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -252,7 +251,6 @@ class UnorderedList(BaseList, Ul): Returns: The list component. - """ ... @@ -364,7 +362,7 @@ class OrderedList(BaseList, Ol): reversed: Reverses the order of the list. start: Specifies the start value of the first list item in an ordered list. type: Specifies the kind of marker to use in the list (letters or numbers). - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -390,7 +388,6 @@ class OrderedList(BaseList, Ol): Returns: The list component. - """ ... @@ -451,7 +448,7 @@ class ListItem(Li, MarkdownComponentMap): Args: *children: The children of the component. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -477,7 +474,6 @@ class ListItem(Li, MarkdownComponentMap): Returns: The list item component. - """ ... @@ -571,7 +567,6 @@ class List(ComponentNamespace): Returns: The list component. - """ ... diff --git a/reflex/components/radix/themes/layout/section.pyi b/reflex/components/radix/themes/layout/section.pyi index 7e909bf64..c005f273f 100644 --- a/reflex/components/radix/themes/layout/section.pyi +++ b/reflex/components/radix/themes/layout/section.pyi @@ -87,7 +87,7 @@ class Section(elements.Section, RadixThemesComponent): Args: *children: Child components. size: The size of the section: "1" - "3" (default "2") - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/layout/spacer.pyi b/reflex/components/radix/themes/layout/spacer.pyi index bd98ac656..8fb756741 100644 --- a/reflex/components/radix/themes/layout/spacer.pyi +++ b/reflex/components/radix/themes/layout/spacer.pyi @@ -155,7 +155,7 @@ class Spacer(Flex): justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between" wrap: Whether children should wrap when they reach the end of their container: "nowrap" | "wrap" | "wrap-reverse" spacing: Gap between children: "0" - "9" - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/layout/stack.pyi b/reflex/components/radix/themes/layout/stack.pyi index 712e050a8..cd4b90952 100644 --- a/reflex/components/radix/themes/layout/stack.pyi +++ b/reflex/components/radix/themes/layout/stack.pyi @@ -129,7 +129,7 @@ class Stack(Flex): direction: How child items are layed out: "row" | "column" | "row-reverse" | "column-reverse" justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between" wrap: Whether children should wrap when they reach the end of their container: "nowrap" | "wrap" | "wrap-reverse" - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -264,7 +264,7 @@ class VStack(Stack): as_child: Change the default rendered element for the one passed as a child, merging their props and behavior. justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between" wrap: Whether children should wrap when they reach the end of their container: "nowrap" | "wrap" | "wrap-reverse" - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -399,7 +399,7 @@ class HStack(Stack): as_child: Change the default rendered element for the one passed as a child, merging their props and behavior. justify: Alignment of children along the cross axis: "start" | "center" | "end" | "between" wrap: Whether children should wrap when they reach the end of their container: "nowrap" | "wrap" | "wrap-reverse" - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/typography/blockquote.pyi b/reflex/components/radix/themes/typography/blockquote.pyi index efb18a5b2..747724763 100644 --- a/reflex/components/radix/themes/typography/blockquote.pyi +++ b/reflex/components/radix/themes/typography/blockquote.pyi @@ -168,7 +168,7 @@ class Blockquote(elements.Blockquote, RadixThemesComponent): color_scheme: Overrides the accent color inherited from the Theme. high_contrast: Whether to render the text with higher contrast color cite: Define the title of a work. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/typography/code.pyi b/reflex/components/radix/themes/typography/code.pyi index 0276eb982..847df267c 100644 --- a/reflex/components/radix/themes/typography/code.pyi +++ b/reflex/components/radix/themes/typography/code.pyi @@ -174,7 +174,7 @@ class Code(elements.Code, RadixThemesComponent, MarkdownComponentMap): weight: Thickness of text: "light" | "regular" | "medium" | "bold" color_scheme: Overrides the accent color inherited from the Theme. high_contrast: Whether to render the text with higher contrast color - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/typography/heading.pyi b/reflex/components/radix/themes/typography/heading.pyi index b5cb5c9d3..4a1e30dbf 100644 --- a/reflex/components/radix/themes/typography/heading.pyi +++ b/reflex/components/radix/themes/typography/heading.pyi @@ -197,7 +197,7 @@ class Heading(elements.H1, RadixThemesComponent, MarkdownComponentMap): trim: Removes the leading trim space: "normal" | "start" | "end" | "both" color_scheme: Overrides the accent color inherited from the Theme. high_contrast: Whether to render the text with higher contrast color - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/typography/link.pyi b/reflex/components/radix/themes/typography/link.pyi index db963c6df..807f8dda0 100644 --- a/reflex/components/radix/themes/typography/link.pyi +++ b/reflex/components/radix/themes/typography/link.pyi @@ -215,7 +215,7 @@ class Link(RadixThemesComponent, A, MemoizationLeaf, MarkdownComponentMap): rel: Specifies the relationship between the linked document and the current document shape: Specifies the shape of the area target: Specifies where to open the linked document - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/radix/themes/typography/text.pyi b/reflex/components/radix/themes/typography/text.pyi index 824348b42..d96b5799b 100644 --- a/reflex/components/radix/themes/typography/text.pyi +++ b/reflex/components/radix/themes/typography/text.pyi @@ -264,7 +264,7 @@ class Text(elements.Span, RadixThemesComponent, MarkdownComponentMap): trim: Removes the leading trim space: "normal" | "start" | "end" | "both" color_scheme: Overrides the accent color inherited from the Theme. high_contrast: Whether to render the text with higher contrast color - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -521,7 +521,7 @@ class Span(Text): trim: Removes the leading trim space: "normal" | "start" | "end" | "both" color_scheme: Overrides the accent color inherited from the Theme. high_contrast: Whether to render the text with higher contrast color - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -610,7 +610,7 @@ class Em(elements.Em, RadixThemesComponent): Args: *children: Child components. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -706,7 +706,7 @@ class Kbd(elements.Kbd, RadixThemesComponent): Args: *children: Child components. size: Text size: "1" - "9" - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -797,7 +797,7 @@ class Quote(elements.Q, RadixThemesComponent): Args: *children: Child components. cite: Specifies the source URL of the quote. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -886,7 +886,7 @@ class Strong(elements.Strong, RadixThemesComponent): Args: *children: Child components. - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. @@ -1147,7 +1147,7 @@ class TextNamespace(ComponentNamespace): trim: Removes the leading trim space: "normal" | "start" | "end" | "both" color_scheme: Overrides the accent color inherited from the Theme. high_contrast: Whether to render the text with higher contrast color - access_key: Provides a hint for generating a keyboard shortcut for the current element. + access_key: Provides a hint for generating a keyboard shortcut for the current element. auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user. content_editable: Indicates whether the element's content is editable. context_menu: Defines the ID of a element which will serve as the element's context menu. diff --git a/reflex/components/recharts/cartesian.py b/reflex/components/recharts/cartesian.py index 028bcb4e4..7fc9a27a1 100644 --- a/reflex/components/recharts/cartesian.py +++ b/reflex/components/recharts/cartesian.py @@ -416,7 +416,7 @@ class Bar(Cartesian): radius: Var[Union[int, List[int]]] # The active bar is shown when a user enters a bar chart and this chart has tooltip. If set to false, no active bar will be drawn. If set to true, active bar will be drawn with the props calculated internally. If passed an object, active bar will be drawn, and the internally calculated props will be merged with the key value pairs of the passed object. - # active_bar: Var[Union[bool, Dict[str, Any]]] + # active_bar: Var[Union[bool, Dict[str, Any]]] #noqa: ERA001 # Valid children components _valid_children: List[str] = ["Cell", "LabelList", "ErrorBar"] diff --git a/reflex/components/recharts/polar.py b/reflex/components/recharts/polar.py index 0aedf4893..dea42af7b 100644 --- a/reflex/components/recharts/polar.py +++ b/reflex/components/recharts/polar.py @@ -136,7 +136,7 @@ class Radar(Recharts): # Fill color. Default: rx.color("accent", 3) fill: Var[str] = LiteralVar.create(Color("accent", 3)) - # opacity. Default: 0.6 + # The opacity to fill the chart. Default: 0.6 fill_opacity: Var[float] = LiteralVar.create(0.6) # The type of icon in legend. If set to 'none', no legend item will be rendered. Default: "rect" diff --git a/reflex/components/recharts/polar.pyi b/reflex/components/recharts/polar.pyi index 5ca96acb6..da0602fb0 100644 --- a/reflex/components/recharts/polar.pyi +++ b/reflex/components/recharts/polar.pyi @@ -204,7 +204,7 @@ class Radar(Recharts): dot: If false set, dots will not be drawn. Default: True stroke: Stoke color. Default: rx.color("accent", 9) fill: Fill color. Default: rx.color("accent", 3) - fill_opacity: opacity. Default: 0.6 + fill_opacity: The opacity to fill the chart. Default: 0.6 legend_type: The type of icon in legend. If set to 'none', no legend item will be rendered. Default: "rect" label: If false set, labels will not be drawn. Default: True is_animation_active: If set false, animation of polygon will be disabled. Default: True in CSR, and False in SSR diff --git a/reflex/components/sonner/toast.py b/reflex/components/sonner/toast.py index 14694e6ad..836c19bf9 100644 --- a/reflex/components/sonner/toast.py +++ b/reflex/components/sonner/toast.py @@ -98,7 +98,7 @@ class ToastProps(PropsBase, NoExtrasAllowedProps): # TODO: fix serialization of icons for toast? (might not be possible yet) # Icon displayed in front of toast's text, aligned vertically. - # icon: Optional[Icon] = None + # icon: Optional[Icon] = None # noqa: ERA001 # TODO: fix implementation for action / cancel buttons # Renders a primary button, clicking it will close the toast. @@ -364,9 +364,7 @@ class Toaster(Component): return super().create(*children, **props) -# TODO: figure out why loading toast stay open forever -# def toast_loading(message: str, **kwargs): -# return _toast(message, level="loading", **kwargs) +# TODO: figure out why loading toast stay open forever when using level="loading" in toast() class ToastNamespace(ComponentNamespace): @@ -379,7 +377,6 @@ class ToastNamespace(ComponentNamespace): error = staticmethod(Toaster.toast_error) success = staticmethod(Toaster.toast_success) dismiss = staticmethod(Toaster.toast_dismiss) - # loading = staticmethod(toast_loading) __call__ = staticmethod(Toaster.send_toast) diff --git a/reflex/components/suneditor/editor.py b/reflex/components/suneditor/editor.py index 16d5689e2..d40f0e9ad 100644 --- a/reflex/components/suneditor/editor.py +++ b/reflex/components/suneditor/editor.py @@ -116,7 +116,7 @@ class Editor(NoSSRComponent): # Please refer to the library docs for this. # options: "en" | "da" | "de" | "es" | "fr" | "ja" | "ko" | "pt_br" | # "ru" | "zh_cn" | "ro" | "pl" | "ckb" | "lv" | "se" | "ua" | "he" | "it" - # default : "en" + # default: "en". lang: Var[ Union[ Literal[ @@ -172,7 +172,7 @@ class Editor(NoSSRComponent): set_options: Var[Dict] # Whether all SunEditor plugins should be loaded. - # default: True + # default: True. set_all_plugins: Var[bool] # Set the content of the editor. @@ -191,19 +191,19 @@ class Editor(NoSSRComponent): set_default_style: Var[str] # Disable the editor - # default: False + # default: False. disable: Var[bool] # Hide the editor - # default: False + # default: False. hide: Var[bool] # Hide the editor toolbar - # default: False + # default: False. hide_toolbar: Var[bool] # Disable the editor toolbar - # default: False + # default: False. disable_toolbar: Var[bool] # Fired when the editor content changes. diff --git a/reflex/components/suneditor/editor.pyi b/reflex/components/suneditor/editor.pyi index 66ab4863e..b52fd43da 100644 --- a/reflex/components/suneditor/editor.pyi +++ b/reflex/components/suneditor/editor.pyi @@ -172,7 +172,7 @@ class Editor(NoSSRComponent): Args: set_options(Optional[EditorOptions]): Configuration object to further configure the instance. - lang: Language of the editor. Alternatively to a string, a dict of your language can be passed to this prop. Please refer to the library docs for this. options: "en" | "da" | "de" | "es" | "fr" | "ja" | "ko" | "pt_br" | "ru" | "zh_cn" | "ro" | "pl" | "ckb" | "lv" | "se" | "ua" | "he" | "it" default : "en" + lang: Language of the editor. Alternatively to a string, a dict of your language can be passed to this prop. Please refer to the library docs for this. options: "en" | "da" | "de" | "es" | "fr" | "ja" | "ko" | "pt_br" | "ru" | "zh_cn" | "ro" | "pl" | "ckb" | "lv" | "se" | "ua" | "he" | "it" default: "en". name: This is used to set the HTML form name of the editor. This means on HTML form submission, it will be submitted together with contents of the editor by the name provided. default_value: Sets the default value of the editor. This is useful if you don't want the on_change method to be called on render. If you want the on_change method to be called on render please use the set_contents prop width: Sets the width of the editor. px and percentage values are accepted, eg width="100%" or width="500px" default: 100% @@ -180,14 +180,14 @@ class Editor(NoSSRComponent): placeholder: Sets the placeholder of the editor. auto_focus: Should the editor receive focus when initialized? set_options: Pass an EditorOptions instance to modify the behaviour of Editor even more. - set_all_plugins: Whether all SunEditor plugins should be loaded. default: True + set_all_plugins: Whether all SunEditor plugins should be loaded. default: True. set_contents: Set the content of the editor. Note: To set the initial contents of the editor without calling the on_change event, please use the default_value prop. set_contents is used to set the contents of the editor programmatically. You must be aware that, when the set_contents's prop changes, the on_change event is triggered. append_contents: Append editor content set_default_style: Sets the default style of the editor's edit area - disable: Disable the editor default: False - hide: Hide the editor default: False - hide_toolbar: Hide the editor toolbar default: False - disable_toolbar: Disable the editor toolbar default: False + disable: Disable the editor default: False. + hide: Hide the editor default: False. + hide_toolbar: Hide the editor toolbar default: False. + disable_toolbar: Disable the editor toolbar default: False. on_change: Fired when the editor content changes. on_input: Fired when the something is inputted in the editor. on_blur: Fired when the editor loses focus. diff --git a/reflex/event.py b/reflex/event.py index 9807b696b..05a163d3e 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -1222,7 +1222,7 @@ def call_event_handler( except TypeError: # TODO: In 0.7.0, remove this block and raise the exception # raise TypeError( - # f"Could not compare types {args_types_without_vars[i]} and {type_hints_of_provided_callback[arg]} for argument {arg} of {event_handler.fn.__qualname__} provided for {key}." + # f"Could not compare types {args_types_without_vars[i]} and {type_hints_of_provided_callback[arg]} for argument {arg} of {event_handler.fn.__qualname__} provided for {key}." # noqa: ERA001 # ) from e console.warn( f"Could not compare types {args_types_without_vars[i]} and {type_hints_of_provided_callback[arg]} for argument {arg} of {event_callback.fn.__qualname__} provided for {key}." diff --git a/reflex/experimental/layout.py b/reflex/experimental/layout.py index d203ce714..e5a1bab04 100644 --- a/reflex/experimental/layout.py +++ b/reflex/experimental/layout.py @@ -33,12 +33,6 @@ class Sidebar(Box, MemoizationLeaf): Returns: The sidebar component. """ - # props.setdefault("border_right", f"1px solid {color('accent', 12)}") - # props.setdefault("background_color", color("accent", 1)) - # props.setdefault("width", "20vw") - # props.setdefault("height", "100vh") - # props.setdefault("position", "fixed") - return super().create( Box.create(*children, **props), # sidebar for content Box.create(width=props.get("width")), # spacer for layout diff --git a/reflex/style.py b/reflex/style.py index 642d126ca..a205cdc4a 100644 --- a/reflex/style.py +++ b/reflex/style.py @@ -138,9 +138,6 @@ def convert_item( if isinstance(style_item, Var): return style_item, style_item._get_all_var_data() - # if isinstance(style_item, str) and REFLEX_VAR_OPENING_TAG not in style_item: - # return style_item, None - # Otherwise, convert to Var to collapse VarData encoded in f-string. new_var = LiteralVar.create(style_item) var_data = new_var._get_all_var_data() if new_var is not None else None diff --git a/reflex/testing.py b/reflex/testing.py index 319be7cba..05b7d7c9d 100644 --- a/reflex/testing.py +++ b/reflex/testing.py @@ -206,7 +206,7 @@ class AppHarness: The full state name """ # NOTE: using State.get_name() somehow causes trouble here - # path = [State.get_name()] + [self.get_state_name(p) for p in path] + # path = [State.get_name()] + [self.get_state_name(p) for p in path] # noqa: ERA001 path = ["reflex___state____state"] + [self.get_state_name(p) for p in path] return ".".join(path) @@ -436,7 +436,6 @@ class AppHarness: Returns: The rendered app global code. - """ if not inspect.isclass(value) and not inspect.isfunction(value): return f"{key} = {value!r}" diff --git a/reflex/utils/format.py b/reflex/utils/format.py index 6236a883e..0159a17c3 100644 --- a/reflex/utils/format.py +++ b/reflex/utils/format.py @@ -712,7 +712,6 @@ def format_array_ref(refs: str, idx: Var | None) -> str: """ clean_ref = re.sub(r"[^\w]+", "_", refs) if idx is not None: - # idx._var_is_local = True return f"refs_{clean_ref}[{idx!s}]" return f"refs_{clean_ref}" diff --git a/reflex/utils/pyi_generator.py b/reflex/utils/pyi_generator.py index 5e73e4dce..2d3d2664e 100644 --- a/reflex/utils/pyi_generator.py +++ b/reflex/utils/pyi_generator.py @@ -196,12 +196,7 @@ def _get_type_hint(value, type_hint_globals, is_optional=True) -> str: elif isinstance(value, str): ev = eval(value, type_hint_globals) if rx_types.is_optional(ev): - # hints = { - # _get_type_hint(arg, type_hint_globals, is_optional=False) - # for arg in ev.__args__ - # } return _get_type_hint(ev, type_hint_globals, is_optional=False) - # return f"Optional[{', '.join(hints)}]" if rx_types.is_union(ev): res = [ @@ -260,8 +255,15 @@ def _generate_docstrings(clzs: list[Type[Component]], props: list[str]) -> str: # We've reached the functions, so stop. break + if line == "": + # We hit a blank line, so clear comments to avoid commented out prop appearing in next prop docs. + comments.clear() + continue + # Get comments for prop if line.strip().startswith("#"): + # Remove noqa from the comments. + line = line.partition(" # noqa")[0] comments.append(line) continue diff --git a/reflex/utils/types.py b/reflex/utils/types.py index fb26b14c9..b8bcbf2d6 100644 --- a/reflex/utils/types.py +++ b/reflex/utils/types.py @@ -97,7 +97,6 @@ StateIterVar = Union[list, set, tuple] if TYPE_CHECKING: from reflex.vars.base import Var - # ArgsSpec = Callable[[Var], list[Var]] ArgsSpec = ( Callable[[], Sequence[Var]] | Callable[[Var], Sequence[Var]] diff --git a/tests/integration/test_computed_vars.py b/tests/integration/test_computed_vars.py index a41458173..03aaf18b4 100644 --- a/tests/integration/test_computed_vars.py +++ b/tests/integration/test_computed_vars.py @@ -106,7 +106,6 @@ def ComputedVars(): ), ) - # raise Exception(State.count3._deps(objclass=State)) app = rx.App() app.add_page(index) diff --git a/tests/integration/test_input.py b/tests/integration/test_input.py index c718749aa..e9fec7dc1 100644 --- a/tests/integration/test_input.py +++ b/tests/integration/test_input.py @@ -183,6 +183,6 @@ async def test_fully_controlled_input(fully_controlled_input: AppHarness): clear_button.click() assert AppHarness._poll_for(lambda: on_change_input.get_attribute("value") == "") # potential bug: clearing the on_change field doesn't itself trigger on_change - # assert backend_state.text == "" - # assert debounce_input.get_attribute("value") == "" - # assert value_input.get_attribute("value") == "" + # assert backend_state.text == "" #noqa: ERA001 + # assert debounce_input.get_attribute("value") == "" #noqa: ERA001 + # assert value_input.get_attribute("value") == "" #noqa: ERA001 diff --git a/tests/units/components/base/test_bare.py b/tests/units/components/base/test_bare.py index c30ffaf15..178820cff 100644 --- a/tests/units/components/base/test_bare.py +++ b/tests/units/components/base/test_bare.py @@ -13,9 +13,6 @@ STATE_VAR = Var(_js_expr="default_state.name") ("{}", '{"{}"}'), (None, '{""}'), (STATE_VAR, "{default_state.name}"), - # This behavior is now unsupported. - # ("${default_state.name}", "${default_state.name}"), - # ("{state.name}", "{state.name}"), ], ) def test_fstrings(contents, expected): diff --git a/tests/units/components/media/test_image.py b/tests/units/components/media/test_image.py index f8618347c..742bd8c38 100644 --- a/tests/units/components/media/test_image.py +++ b/tests/units/components/media/test_image.py @@ -42,7 +42,7 @@ def test_set_src_str(): "`pic2.jpeg`", ) # For plain rx.el.img, an explicit var is not created, so the quoting happens later - # assert str(image.src) == "pic2.jpeg" # type: ignore + # assert str(image.src) == "pic2.jpeg" # type: ignore #noqa: ERA001 def test_set_src_img(pil_image: Img): diff --git a/tests/units/components/test_component.py b/tests/units/components/test_component.py index e2b035a8f..674873b69 100644 --- a/tests/units/components/test_component.py +++ b/tests/units/components/test_component.py @@ -918,17 +918,17 @@ def test_invalid_event_handler_args(component2, test_state): # # Event Handler types must match # with pytest.raises(EventHandlerArgTypeMismatch): # component2.create( - # on_user_visited_count_changed=test_state.do_something_with_bool - # ) + # on_user_visited_count_changed=test_state.do_something_with_bool # noqa: ERA001 RUF100 + # ) # noqa: ERA001 RUF100 # with pytest.raises(EventHandlerArgTypeMismatch): - # component2.create(on_user_list_changed=test_state.do_something_with_int) + # component2.create(on_user_list_changed=test_state.do_something_with_int) #noqa: ERA001 # with pytest.raises(EventHandlerArgTypeMismatch): - # component2.create(on_user_list_changed=test_state.do_something_with_list_int) + # component2.create(on_user_list_changed=test_state.do_something_with_list_int) #noqa: ERA001 - # component2.create(on_open=test_state.do_something_with_int) - # component2.create(on_open=test_state.do_something_with_bool) - # component2.create(on_user_visited_count_changed=test_state.do_something_with_int) - # component2.create(on_user_list_changed=test_state.do_something_with_list_str) + # component2.create(on_open=test_state.do_something_with_int) #noqa: ERA001 + # component2.create(on_open=test_state.do_something_with_bool) #noqa: ERA001 + # component2.create(on_user_visited_count_changed=test_state.do_something_with_int) #noqa: ERA001 + # component2.create(on_user_list_changed=test_state.do_something_with_list_str) #noqa: ERA001 # lambda cannot return weird values. with pytest.raises(ValueError): @@ -1437,8 +1437,6 @@ def test_get_vars(component, exp_vars): comp_vars, sorted(exp_vars, key=lambda v: v._js_expr), ): - # print(str(comp_var), str(exp_var)) - # print(comp_var._get_all_var_data(), exp_var._get_all_var_data()) assert comp_var.equals(exp_var) diff --git a/tests/units/test_app.py b/tests/units/test_app.py index 7c7455cba..48a4bdda1 100644 --- a/tests/units/test_app.py +++ b/tests/units/test_app.py @@ -899,8 +899,6 @@ class DynamicState(BaseState): loaded: int = 0 counter: int = 0 - # side_effect_counter: int = 0 - def on_load(self): """Event handler for page on_load, should trigger for all navigation events.""" self.loaded = self.loaded + 1 @@ -917,7 +915,6 @@ class DynamicState(BaseState): Returns: same as self.dynamic """ - # self.side_effect_counter = self.side_effect_counter + 1 return self.dynamic on_load_internal = OnLoadInternalState.on_load_internal.fn @@ -1059,7 +1056,6 @@ async def test_dynamic_route_var_route_change_completed_on_load( arg_name: exp_val, f"comp_{arg_name}": exp_val, constants.CompileVars.IS_HYDRATED: False, - # "side_effect_counter": exp_index, "router": exp_router, } }, @@ -1155,8 +1151,6 @@ async def test_dynamic_route_var_route_change_completed_on_load( state = await app.state_manager.get_state(substate_token) assert state.loaded == len(exp_vals) assert state.counter == len(exp_vals) - # print(f"Expected {exp_vals} rendering side effects, got {state.side_effect_counter}") - # assert state.side_effect_counter == len(exp_vals) if isinstance(app.state_manager, StateManagerRedis): await app.state_manager.close() diff --git a/tests/units/test_event.py b/tests/units/test_event.py index 4f7adfeb3..c5198a571 100644 --- a/tests/units/test_event.py +++ b/tests/units/test_event.py @@ -209,10 +209,6 @@ def test_event_redirect(input, output): assert isinstance(spec, EventSpec) assert spec.handler.fn.__qualname__ == "_redirect" - # this asserts need comment about what it's testing (they fail with Var as input) - # assert spec.args[0][0].equals(Var(_js_expr="path")) - # assert spec.args[0][1].equals(Var(_js_expr="/path")) - assert format.format_event(spec) == output diff --git a/tests/units/test_sqlalchemy.py b/tests/units/test_sqlalchemy.py index b18799e0c..23e315785 100644 --- a/tests/units/test_sqlalchemy.py +++ b/tests/units/test_sqlalchemy.py @@ -127,8 +127,8 @@ def test_automigration( assert result[0].b == 4.2 # No-op - # assert Model.migrate(autogenerate=True) - # assert len(list(versions.glob("*.py"))) == 4 + # assert Model.migrate(autogenerate=True) #noqa: ERA001 + # assert len(list(versions.glob("*.py"))) == 4 #noqa: ERA001 # drop table (AlembicSecond) model_registry.get_metadata().clear() diff --git a/tests/units/test_state.py b/tests/units/test_state.py index 790df1b7d..a580f9d74 100644 --- a/tests/units/test_state.py +++ b/tests/units/test_state.py @@ -791,7 +791,6 @@ async def test_process_event_simple(test_state): assert test_state.num1 == 69 # The delta should contain the changes, including computed vars. - # assert update.delta == {"test_state": {"num1": 69, "sum": 72.14}} assert update.delta == { TestState.get_full_name(): {"num1": 69, "sum": 72.14, "upper": ""}, GrandchildState3.get_full_name(): {"computed": ""}, @@ -3490,10 +3489,10 @@ def test_mutable_models(): state.dirty_vars.clear() # Not yet supported ENG-4083 - # assert isinstance(state.dc, MutableProxy) - # state.dc.foo = "baz" - # assert state.dirty_vars == {"dc"} - # state.dirty_vars.clear() + # assert isinstance(state.dc, MutableProxy) #noqa: ERA001 + # state.dc.foo = "baz" #noqa: ERA001 + # assert state.dirty_vars == {"dc"} #noqa: ERA001 + # state.dirty_vars.clear() #noqa: ERA001 def test_get_value(): diff --git a/tests/units/test_telemetry.py b/tests/units/test_telemetry.py index 25ad91323..d8a77dfd6 100644 --- a/tests/units/test_telemetry.py +++ b/tests/units/test_telemetry.py @@ -34,12 +34,6 @@ def test_disable(): @pytest.mark.parametrize("event", ["init", "reinit", "run-dev", "run-prod", "export"]) def test_send(mocker, event): httpx_post_mock = mocker.patch("httpx.post") - # mocker.patch( - # "builtins.open", - # mocker.mock_open( - # read_data='{"project_hash": "78285505863498957834586115958872998605"}' - # ), - # ) # Mock the read_text method of Path pathlib_path_read_text_mock = mocker.patch( diff --git a/tests/units/test_var.py b/tests/units/test_var.py index 3176443a6..048752d11 100644 --- a/tests/units/test_var.py +++ b/tests/units/test_var.py @@ -1495,8 +1495,6 @@ def test_valid_var_operations(operand1_var: Var, operand2_var, operators: List[s ) eval(f"operand1_var {operator} operand2_var") eval(f"operand2_var {operator} operand1_var") - # operand1_var.operation(op=operator, other=operand2_var) - # operand1_var.operation(op=operator, other=operand2_var, flip=True) @pytest.mark.parametrize( @@ -1773,11 +1771,9 @@ def test_invalid_var_operations(operand1_var: Var, operand2_var, operators: List print(f"testing {operator} on {operand1_var!s} and {operand2_var!s}") with pytest.raises(TypeError): print(eval(f"operand1_var {operator} operand2_var")) - # operand1_var.operation(op=operator, other=operand2_var) with pytest.raises(TypeError): print(eval(f"operand2_var {operator} operand1_var")) - # operand1_var.operation(op=operator, other=operand2_var, flip=True) @pytest.mark.parametrize( From a7151cd6c8ce9d036ff04770adf9efe6f6d2eec6 Mon Sep 17 00:00:00 2001 From: benedikt-bartscher <31854409+benedikt-bartscher@users.noreply.github.com> Date: Thu, 12 Dec 2024 03:29:01 +0100 Subject: [PATCH 70/71] disable polling (#4441) --- reflex/.templates/web/utils/state.js | 2 +- reflex/app.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/reflex/.templates/web/utils/state.js b/reflex/.templates/web/utils/state.js index 622f171ad..e135c7c0b 100644 --- a/reflex/.templates/web/utils/state.js +++ b/reflex/.templates/web/utils/state.js @@ -799,7 +799,7 @@ export const useEventLoop = ( connect( socket, dispatch, - ["websocket", "polling"], + ["websocket"], setConnectErrors, client_storage ); diff --git a/reflex/app.py b/reflex/app.py index 3f981a6c3..cf4eefa19 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -363,6 +363,7 @@ class App(MiddlewareMixin, LifespanMixin): max_http_buffer_size=constants.POLLING_MAX_HTTP_BUFFER_SIZE, ping_interval=constants.Ping.INTERVAL, ping_timeout=constants.Ping.TIMEOUT, + transports=["websocket"], ) elif getattr(self.sio, "async_mode", "") != "asgi": raise RuntimeError( From a86d2c612ac00598da2adb1eea33e5ce3f0579f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Brand=C3=A9ho?= Date: Wed, 11 Dec 2024 18:29:39 -0800 Subject: [PATCH 71/71] deprecate add_custom_404_page (#4505) * deprecate add_custom_404_page * show raw value in deprecate message * fix typo * Update reflex/app.py Co-authored-by: Masen Furer * change removal version to 0.8.0 --------- Co-authored-by: Masen Furer --- reflex/app.py | 36 ++++++++++++++----- reflex/components/core/client_side_routing.py | 4 +-- .../components/core/client_side_routing.pyi | 2 +- reflex/utils/exceptions.py | 4 +++ 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/reflex/app.py b/reflex/app.py index cf4eefa19..42808823a 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -468,7 +468,7 @@ class App(MiddlewareMixin, LifespanMixin): def add_page( self, - component: Component | ComponentCallable, + component: Component | ComponentCallable | None = None, route: str | None = None, title: str | Var | None = None, description: str | Var | None = None, @@ -491,17 +491,33 @@ class App(MiddlewareMixin, LifespanMixin): meta: The metadata of the page. Raises: - ValueError: When the specified route name already exists. + PageValueError: When the component is not set for a non-404 page. + RouteValueError: When the specified route name already exists. """ # If the route is not set, get it from the callable. if route is None: if not isinstance(component, Callable): - raise ValueError("Route must be set if component is not a callable.") + raise exceptions.RouteValueError( + "Route must be set if component is not a callable." + ) # Format the route. route = format.format_route(component.__name__) else: route = format.format_route(route, format_case=False) + if route == constants.Page404.SLUG: + if component is None: + component = Default404Page.create() + component = wait_for_client_redirect(self._generate_component(component)) + title = title or constants.Page404.TITLE + description = description or constants.Page404.DESCRIPTION + image = image or constants.Page404.IMAGE + else: + if component is None: + raise exceptions.PageValueError( + "Component must be set for a non-404 page." + ) + # Check if the route given is valid verify_route_validity(route) @@ -517,7 +533,7 @@ class App(MiddlewareMixin, LifespanMixin): if route == constants.PageNames.INDEX_ROUTE else f"`{route}`" ) - raise ValueError( + raise exceptions.RouteValueError( f"Duplicate page route {route_name} already exists. Make sure you do not have two" f" pages with the same route" ) @@ -634,10 +650,14 @@ class App(MiddlewareMixin, LifespanMixin): on_load: The event handler(s) that will be called each time the page load. meta: The metadata of the page. """ - if component is None: - component = Default404Page.create() + console.deprecate( + feature_name="App.add_custom_404_page", + reason=f"Use app.add_page(component, route='/{constants.Page404.SLUG}') instead.", + deprecation_version="0.6.7", + removal_version="0.8.0", + ) self.add_page( - component=wait_for_client_redirect(self._generate_component(component)), + component=component, route=constants.Page404.SLUG, title=title or constants.Page404.TITLE, image=image or constants.Page404.IMAGE, @@ -838,7 +858,7 @@ class App(MiddlewareMixin, LifespanMixin): # Render a default 404 page if the user didn't supply one if constants.Page404.SLUG not in self.unevaluated_pages: - self.add_custom_404_page() + self.add_page(route=constants.Page404.SLUG) # Fix up the style. self.style = evaluate_style_namespaces(self.style) diff --git a/reflex/components/core/client_side_routing.py b/reflex/components/core/client_side_routing.py index 342c69632..a10b90de8 100644 --- a/reflex/components/core/client_side_routing.py +++ b/reflex/components/core/client_side_routing.py @@ -24,7 +24,7 @@ class ClientSideRouting(Component): library = "$/utils/client_side_routing" tag = "useClientSideRouting" - def add_hooks(self) -> list[str]: + def add_hooks(self) -> list[str | Var]: """Get the hooks to render. Returns: @@ -66,4 +66,4 @@ class Default404Page(Component): tag = "Error" is_default = True - status_code: Var[int] = 404 # type: ignore + status_code: Var[int] = Var.create(404) diff --git a/reflex/components/core/client_side_routing.pyi b/reflex/components/core/client_side_routing.pyi index bb853e2c7..581b0e120 100644 --- a/reflex/components/core/client_side_routing.pyi +++ b/reflex/components/core/client_side_routing.pyi @@ -13,7 +13,7 @@ from reflex.vars.base import Var route_not_found: Var class ClientSideRouting(Component): - def add_hooks(self) -> list[str]: ... + def add_hooks(self) -> list[str | Var]: ... def render(self) -> str: ... @overload @classmethod diff --git a/reflex/utils/exceptions.py b/reflex/utils/exceptions.py index a89c4d4aa..6c378e159 100644 --- a/reflex/utils/exceptions.py +++ b/reflex/utils/exceptions.py @@ -63,6 +63,10 @@ class UploadValueError(ReflexError, ValueError): """Custom ValueError for upload related errors.""" +class PageValueError(ReflexError, ValueError): + """Custom ValueError for page related errors.""" + + class RouteValueError(ReflexError, ValueError): """Custom ValueError for route related errors."""