Merge branch 'main' into lendemor/use_custom_bunfig_toml
This commit is contained in:
commit
41770043a1
@ -3,7 +3,7 @@ fail_fast: true
|
|||||||
repos:
|
repos:
|
||||||
|
|
||||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||||
rev: v0.7.1
|
rev: v0.7.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff-format
|
- id: ruff-format
|
||||||
args: [reflex, tests]
|
args: [reflex, tests]
|
||||||
|
246
poetry.lock
generated
246
poetry.lock
generated
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alembic"
|
name = "alembic"
|
||||||
version = "1.13.3"
|
version = "1.14.0"
|
||||||
description = "A database migration tool for SQLAlchemy."
|
description = "A database migration tool for SQLAlchemy."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "alembic-1.13.3-py3-none-any.whl", hash = "sha256:908e905976d15235fae59c9ac42c4c5b75cfcefe3d27c0fbf7ae15a37715d80e"},
|
{file = "alembic-1.14.0-py3-none-any.whl", hash = "sha256:99bd884ca390466db5e27ffccff1d179ec5c05c965cfefc0607e69f9e411cb25"},
|
||||||
{file = "alembic-1.13.3.tar.gz", hash = "sha256:203503117415561e203aa14541740643a611f641517f0209fcae63e9fa09f1a2"},
|
{file = "alembic-1.14.0.tar.gz", hash = "sha256:b00892b53b3642d0b8dbedba234dbf1924b69be83a9a769d5a624b01094e304b"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -54,13 +54,13 @@ trio = ["trio (>=0.26.1)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-timeout"
|
name = "async-timeout"
|
||||||
version = "4.0.3"
|
version = "5.0.0"
|
||||||
description = "Timeout context manager for asyncio programs"
|
description = "Timeout context manager for asyncio programs"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"},
|
{file = "async_timeout-5.0.0-py3-none-any.whl", hash = "sha256:904719a4bd6e0520047d0ddae220aabee67b877f7ca17bf8cea20f67f6247ae0"},
|
||||||
{file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
|
{file = "async_timeout-5.0.0.tar.gz", hash = "sha256:49675ec889daacfe65ff66d2dde7dd1447a6f4b2f23721022e4ba121f8772a85"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -585,13 +585,13 @@ test = ["pytest (>=6)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastapi"
|
name = "fastapi"
|
||||||
version = "0.115.3"
|
version = "0.115.4"
|
||||||
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
|
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "fastapi-0.115.3-py3-none-any.whl", hash = "sha256:8035e8f9a2b0aa89cea03b6c77721178ed5358e1aea4cd8570d9466895c0638c"},
|
{file = "fastapi-0.115.4-py3-none-any.whl", hash = "sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742"},
|
||||||
{file = "fastapi-0.115.3.tar.gz", hash = "sha256:c091c6a35599c036d676fa24bd4a6e19fa30058d93d950216cdc672881f6f7db"},
|
{file = "fastapi-0.115.4.tar.gz", hash = "sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -937,13 +937,13 @@ i18n = ["Babel (>=2.7)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "keyring"
|
name = "keyring"
|
||||||
version = "25.4.1"
|
version = "25.5.0"
|
||||||
description = "Store and access your passwords safely."
|
description = "Store and access your passwords safely."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "keyring-25.4.1-py3-none-any.whl", hash = "sha256:5426f817cf7f6f007ba5ec722b1bcad95a75b27d780343772ad76b17cb47b0bf"},
|
{file = "keyring-25.5.0-py3-none-any.whl", hash = "sha256:e67f8ac32b04be4714b42fe84ce7dad9c40985b9ca827c592cc303e7c26d9741"},
|
||||||
{file = "keyring-25.4.1.tar.gz", hash = "sha256:b07ebc55f3e8ed86ac81dd31ef14e81ace9dd9c3d4b5d77a6e9a2016d0d71a1b"},
|
{file = "keyring-25.5.0.tar.gz", hash = "sha256:4c753b3ec91717fe713c4edd522d625889d8973a349b0e582622f49766de58e6"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -1210,64 +1210,66 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "numpy"
|
name = "numpy"
|
||||||
version = "2.1.2"
|
version = "2.1.3"
|
||||||
description = "Fundamental package for array computing in Python"
|
description = "Fundamental package for array computing in Python"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.10"
|
python-versions = ">=3.10"
|
||||||
files = [
|
files = [
|
||||||
{file = "numpy-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:30d53720b726ec36a7f88dc873f0eec8447fbc93d93a8f079dfac2629598d6ee"},
|
{file = "numpy-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c894b4305373b9c5576d7a12b473702afdf48ce5369c074ba304cc5ad8730dff"},
|
||||||
{file = "numpy-2.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d3ca0a72dd8846eb6f7dfe8f19088060fcb76931ed592d29128e0219652884"},
|
{file = "numpy-2.1.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b47fbb433d3260adcd51eb54f92a2ffbc90a4595f8970ee00e064c644ac788f5"},
|
||||||
{file = "numpy-2.1.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:fc44e3c68ff00fd991b59092a54350e6e4911152682b4782f68070985aa9e648"},
|
{file = "numpy-2.1.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:825656d0743699c529c5943554d223c021ff0494ff1442152ce887ef4f7561a1"},
|
||||||
{file = "numpy-2.1.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:7c1c60328bd964b53f8b835df69ae8198659e2b9302ff9ebb7de4e5a5994db3d"},
|
{file = "numpy-2.1.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a4825252fcc430a182ac4dee5a505053d262c807f8a924603d411f6718b88fd"},
|
||||||
{file = "numpy-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6cdb606a7478f9ad91c6283e238544451e3a95f30fb5467fbf715964341a8a86"},
|
{file = "numpy-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e711e02f49e176a01d0349d82cb5f05ba4db7d5e7e0defd026328e5cfb3226d3"},
|
||||||
{file = "numpy-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d666cb72687559689e9906197e3bec7b736764df6a2e58ee265e360663e9baf7"},
|
{file = "numpy-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78574ac2d1a4a02421f25da9559850d59457bac82f2b8d7a44fe83a64f770098"},
|
||||||
{file = "numpy-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c6eef7a2dbd0abfb0d9eaf78b73017dbfd0b54051102ff4e6a7b2980d5ac1a03"},
|
{file = "numpy-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c7662f0e3673fe4e832fe07b65c50342ea27d989f92c80355658c7f888fcc83c"},
|
||||||
{file = "numpy-2.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:12edb90831ff481f7ef5f6bc6431a9d74dc0e5ff401559a71e5e4611d4f2d466"},
|
{file = "numpy-2.1.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fa2d1337dc61c8dc417fbccf20f6d1e139896a30721b7f1e832b2bb6ef4eb6c4"},
|
||||||
{file = "numpy-2.1.2-cp310-cp310-win32.whl", hash = "sha256:a65acfdb9c6ebb8368490dbafe83c03c7e277b37e6857f0caeadbbc56e12f4fb"},
|
{file = "numpy-2.1.3-cp310-cp310-win32.whl", hash = "sha256:72dcc4a35a8515d83e76b58fdf8113a5c969ccd505c8a946759b24e3182d1f23"},
|
||||||
{file = "numpy-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:860ec6e63e2c5c2ee5e9121808145c7bf86c96cca9ad396c0bd3e0f2798ccbe2"},
|
{file = "numpy-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:ecc76a9ba2911d8d37ac01de72834d8849e55473457558e12995f4cd53e778e0"},
|
||||||
{file = "numpy-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b42a1a511c81cc78cbc4539675713bbcf9d9c3913386243ceff0e9429ca892fe"},
|
{file = "numpy-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4d1167c53b93f1f5d8a139a742b3c6f4d429b54e74e6b57d0eff40045187b15d"},
|
||||||
{file = "numpy-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:faa88bc527d0f097abdc2c663cddf37c05a1c2f113716601555249805cf573f1"},
|
{file = "numpy-2.1.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c80e4a09b3d95b4e1cac08643f1152fa71a0a821a2d4277334c88d54b2219a41"},
|
||||||
{file = "numpy-2.1.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:c82af4b2ddd2ee72d1fc0c6695048d457e00b3582ccde72d8a1c991b808bb20f"},
|
{file = "numpy-2.1.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:576a1c1d25e9e02ed7fa5477f30a127fe56debd53b8d2c89d5578f9857d03ca9"},
|
||||||
{file = "numpy-2.1.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:13602b3174432a35b16c4cfb5de9a12d229727c3dd47a6ce35111f2ebdf66ff4"},
|
{file = "numpy-2.1.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:973faafebaae4c0aaa1a1ca1ce02434554d67e628b8d805e61f874b84e136b09"},
|
||||||
{file = "numpy-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ebec5fd716c5a5b3d8dfcc439be82a8407b7b24b230d0ad28a81b61c2f4659a"},
|
{file = "numpy-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:762479be47a4863e261a840e8e01608d124ee1361e48b96916f38b119cfda04a"},
|
||||||
{file = "numpy-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2b49c3c0804e8ecb05d59af8386ec2f74877f7ca8fd9c1e00be2672e4d399b1"},
|
{file = "numpy-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f24b3d1ecc1eebfbf5d6051faa49af40b03be1aaa781ebdadcbc090b4539b"},
|
||||||
{file = "numpy-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2cbba4b30bf31ddbe97f1c7205ef976909a93a66bb1583e983adbd155ba72ac2"},
|
{file = "numpy-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:17ee83a1f4fef3c94d16dc1802b998668b5419362c8a4f4e8a491de1b41cc3ee"},
|
||||||
{file = "numpy-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8e00ea6fc82e8a804433d3e9cedaa1051a1422cb6e443011590c14d2dea59146"},
|
{file = "numpy-2.1.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15cb89f39fa6d0bdfb600ea24b250e5f1a3df23f901f51c8debaa6a5d122b2f0"},
|
||||||
{file = "numpy-2.1.2-cp311-cp311-win32.whl", hash = "sha256:5006b13a06e0b38d561fab5ccc37581f23c9511879be7693bd33c7cd15ca227c"},
|
{file = "numpy-2.1.3-cp311-cp311-win32.whl", hash = "sha256:d9beb777a78c331580705326d2367488d5bc473b49a9bc3036c154832520aca9"},
|
||||||
{file = "numpy-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:f1eb068ead09f4994dec71c24b2844f1e4e4e013b9629f812f292f04bd1510d9"},
|
{file = "numpy-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:d89dd2b6da69c4fff5e39c28a382199ddedc3a5be5390115608345dec660b9e2"},
|
||||||
{file = "numpy-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7bf0a4f9f15b32b5ba53147369e94296f5fffb783db5aacc1be15b4bf72f43b"},
|
{file = "numpy-2.1.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f55ba01150f52b1027829b50d70ef1dafd9821ea82905b63936668403c3b471e"},
|
||||||
{file = "numpy-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b1d0fcae4f0949f215d4632be684a539859b295e2d0cb14f78ec231915d644db"},
|
{file = "numpy-2.1.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13138eadd4f4da03074851a698ffa7e405f41a0845a6b1ad135b81596e4e9958"},
|
||||||
{file = "numpy-2.1.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:f751ed0a2f250541e19dfca9f1eafa31a392c71c832b6bb9e113b10d050cb0f1"},
|
{file = "numpy-2.1.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:a6b46587b14b888e95e4a24d7b13ae91fa22386c199ee7b418f449032b2fa3b8"},
|
||||||
{file = "numpy-2.1.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:bd33f82e95ba7ad632bc57837ee99dba3d7e006536200c4e9124089e1bf42426"},
|
{file = "numpy-2.1.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:0fa14563cc46422e99daef53d725d0c326e99e468a9320a240affffe87852564"},
|
||||||
{file = "numpy-2.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b8cde4f11f0a975d1fd59373b32e2f5a562ade7cde4f85b7137f3de8fbb29a0"},
|
{file = "numpy-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8637dcd2caa676e475503d1f8fdb327bc495554e10838019651b76d17b98e512"},
|
||||||
{file = "numpy-2.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d95f286b8244b3649b477ac066c6906fbb2905f8ac19b170e2175d3d799f4df"},
|
{file = "numpy-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2312b2aa89e1f43ecea6da6ea9a810d06aae08321609d8dc0d0eda6d946a541b"},
|
||||||
{file = "numpy-2.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ab4754d432e3ac42d33a269c8567413bdb541689b02d93788af4131018cbf366"},
|
{file = "numpy-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a38c19106902bb19351b83802531fea19dee18e5b37b36454f27f11ff956f7fc"},
|
||||||
{file = "numpy-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e585c8ae871fd38ac50598f4763d73ec5497b0de9a0ab4ef5b69f01c6a046142"},
|
{file = "numpy-2.1.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02135ade8b8a84011cbb67dc44e07c58f28575cf9ecf8ab304e51c05528c19f0"},
|
||||||
{file = "numpy-2.1.2-cp312-cp312-win32.whl", hash = "sha256:9c6c754df29ce6a89ed23afb25550d1c2d5fdb9901d9c67a16e0b16eaf7e2550"},
|
{file = "numpy-2.1.3-cp312-cp312-win32.whl", hash = "sha256:e6988e90fcf617da2b5c78902fe8e668361b43b4fe26dbf2d7b0f8034d4cafb9"},
|
||||||
{file = "numpy-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:456e3b11cb79ac9946c822a56346ec80275eaf2950314b249b512896c0d2505e"},
|
{file = "numpy-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:0d30c543f02e84e92c4b1f415b7c6b5326cbe45ee7882b6b77db7195fb971e3a"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a84498e0d0a1174f2b3ed769b67b656aa5460c92c9554039e11f20a05650f00d"},
|
{file = "numpy-2.1.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96fe52fcdb9345b7cd82ecd34547fca4321f7656d500eca497eb7ea5a926692f"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4d6ec0d4222e8ffdab1744da2560f07856421b367928026fb540e1945f2eeeaf"},
|
{file = "numpy-2.1.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f653490b33e9c3a4c1c01d41bc2aef08f9475af51146e4a7710c450cf9761598"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:259ec80d54999cc34cd1eb8ded513cb053c3bf4829152a2e00de2371bd406f5e"},
|
{file = "numpy-2.1.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:dc258a761a16daa791081d026f0ed4399b582712e6fc887a95af09df10c5ca57"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:675c741d4739af2dc20cd6c6a5c4b7355c728167845e3c6b0e824e4e5d36a6c3"},
|
{file = "numpy-2.1.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:016d0f6f5e77b0f0d45d77387ffa4bb89816b57c835580c3ce8e099ef830befe"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b2d4e667895cc55e3ff2b56077e4c8a5604361fc21a042845ea3ad67465aa8"},
|
{file = "numpy-2.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c181ba05ce8299c7aa3125c27b9c2167bca4a4445b7ce73d5febc411ca692e43"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43cca367bf94a14aca50b89e9bc2061683116cfe864e56740e083392f533ce7a"},
|
{file = "numpy-2.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5641516794ca9e5f8a4d17bb45446998c6554704d888f86df9b200e66bdcce56"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:76322dcdb16fccf2ac56f99048af32259dcc488d9b7e25b51e5eca5147a3fb98"},
|
{file = "numpy-2.1.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ea4dedd6e394a9c180b33c2c872b92f7ce0f8e7ad93e9585312b0c5a04777a4a"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:32e16a03138cabe0cb28e1007ee82264296ac0983714094380b408097a418cfe"},
|
{file = "numpy-2.1.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0df3635b9c8ef48bd3be5f862cf71b0a4716fa0e702155c45067c6b711ddcef"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313-win32.whl", hash = "sha256:242b39d00e4944431a3cd2db2f5377e15b5785920421993770cddb89992c3f3a"},
|
{file = "numpy-2.1.3-cp313-cp313-win32.whl", hash = "sha256:50ca6aba6e163363f132b5c101ba078b8cbd3fa92c7865fd7d4d62d9779ac29f"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:f2ded8d9b6f68cc26f8425eda5d3877b47343e68ca23d0d0846f4d312ecaa445"},
|
{file = "numpy-2.1.3-cp313-cp313-win_amd64.whl", hash = "sha256:747641635d3d44bcb380d950679462fae44f54b131be347d5ec2bce47d3df9ed"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ffef621c14ebb0188a8633348504a35c13680d6da93ab5cb86f4e54b7e922b5"},
|
{file = "numpy-2.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:996bb9399059c5b82f76b53ff8bb686069c05acc94656bb259b1d63d04a9506f"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ad369ed238b1959dfbade9018a740fb9392c5ac4f9b5173f420bd4f37ba1f7a0"},
|
{file = "numpy-2.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:45966d859916ad02b779706bb43b954281db43e185015df6eb3323120188f9e4"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d82075752f40c0ddf57e6e02673a17f6cb0f8eb3f587f63ca1eaab5594da5b17"},
|
{file = "numpy-2.1.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:baed7e8d7481bfe0874b566850cb0b85243e982388b7b23348c6db2ee2b2ae8e"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:1600068c262af1ca9580a527d43dc9d959b0b1d8e56f8a05d830eea39b7c8af6"},
|
{file = "numpy-2.1.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a9f7f672a3388133335589cfca93ed468509cb7b93ba3105fce780d04a6576a0"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a26ae94658d3ba3781d5e103ac07a876b3e9b29db53f68ed7df432fd033358a8"},
|
{file = "numpy-2.1.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7aac50327da5d208db2eec22eb11e491e3fe13d22653dce51b0f4109101b408"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13311c2db4c5f7609b462bc0f43d3c465424d25c626d95040f073e30f7570e35"},
|
{file = "numpy-2.1.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4394bc0dbd074b7f9b52024832d16e019decebf86caf909d94f6b3f77a8ee3b6"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:2abbf905a0b568706391ec6fa15161fad0fb5d8b68d73c461b3c1bab6064dd62"},
|
{file = "numpy-2.1.3-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:50d18c4358a0a8a53f12a8ba9d772ab2d460321e6a93d6064fc22443d189853f"},
|
||||||
{file = "numpy-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ef444c57d664d35cac4e18c298c47d7b504c66b17c2ea91312e979fcfbdfb08a"},
|
{file = "numpy-2.1.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:14e253bd43fc6b37af4921b10f6add6925878a42a0c5fe83daee390bca80bc17"},
|
||||||
{file = "numpy-2.1.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bdd407c40483463898b84490770199d5714dcc9dd9b792f6c6caccc523c00952"},
|
{file = "numpy-2.1.3-cp313-cp313t-win32.whl", hash = "sha256:08788d27a5fd867a663f6fc753fd7c3ad7e92747efc73c53bca2f19f8bc06f48"},
|
||||||
{file = "numpy-2.1.2-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:da65fb46d4cbb75cb417cddf6ba5e7582eb7bb0b47db4b99c9fe5787ce5d91f5"},
|
{file = "numpy-2.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2564fbdf2b99b3f815f2107c1bbc93e2de8ee655a69c261363a1172a79a257d4"},
|
||||||
{file = "numpy-2.1.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c193d0b0238638e6fc5f10f1b074a6993cb13b0b431f64079a509d63d3aa8b7"},
|
{file = "numpy-2.1.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4f2015dfe437dfebbfce7c85c7b53d81ba49e71ba7eadbf1df40c915af75979f"},
|
||||||
{file = "numpy-2.1.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a7d80b2e904faa63068ead63107189164ca443b42dd1930299e0d1cb041cec2e"},
|
{file = "numpy-2.1.3-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:3522b0dfe983a575e6a9ab3a4a4dfe156c3e428468ff08ce582b9bb6bd1d71d4"},
|
||||||
{file = "numpy-2.1.2.tar.gz", hash = "sha256:13532a088217fa624c99b843eeb54640de23b3414b14aa66d023805eb731066c"},
|
{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"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1475,13 +1477,13 @@ xmp = ["defusedxml"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pip"
|
name = "pip"
|
||||||
version = "24.2"
|
version = "24.3.1"
|
||||||
description = "The PyPA recommended tool for installing Python packages."
|
description = "The PyPA recommended tool for installing Python packages."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "pip-24.2-py3-none-any.whl", hash = "sha256:2cd581cf58ab7fcfca4ce8efa6dcacd0de5bf8d0a3eb9ec927e07405f4d9e2a2"},
|
{file = "pip-24.3.1-py3-none-any.whl", hash = "sha256:3790624780082365f47549d032f3770eeb2b1e8bd1f7b2e02dace1afa361b4ed"},
|
||||||
{file = "pip-24.2.tar.gz", hash = "sha256:5b5e490b5e9cb275c879595064adce9ebd31b854e3e803740b72f9ccf34a45b8"},
|
{file = "pip-24.3.1.tar.gz", hash = "sha256:ebcb60557f2aefabc2e0f918751cd24ea0d56d8ec5445fe1807f1d2109660b99"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1908,37 +1910,37 @@ test = ["black (>=22.1.0)", "flake8 (>=4.0.1)", "pre-commit (>=2.17.0)", "pytest
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytest-benchmark"
|
name = "pytest-benchmark"
|
||||||
version = "4.0.0"
|
version = "5.1.0"
|
||||||
description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer."
|
description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "pytest-benchmark-4.0.0.tar.gz", hash = "sha256:fb0785b83efe599a6a956361c0691ae1dbb5318018561af10f3e915caa0048d1"},
|
{file = "pytest-benchmark-5.1.0.tar.gz", hash = "sha256:9ea661cdc292e8231f7cd4c10b0319e56a2118e2c09d9f50e1b3d150d2aca105"},
|
||||||
{file = "pytest_benchmark-4.0.0-py3-none-any.whl", hash = "sha256:fdb7db64e31c8b277dff9850d2a2556d8b60bcb0ea6524e36e28ffd7c87f71d6"},
|
{file = "pytest_benchmark-5.1.0-py3-none-any.whl", hash = "sha256:922de2dfa3033c227c96da942d1878191afa135a29485fb942e85dff1c592c89"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
py-cpuinfo = "*"
|
py-cpuinfo = "*"
|
||||||
pytest = ">=3.8"
|
pytest = ">=8.1"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
aspect = ["aspectlib"]
|
aspect = ["aspectlib"]
|
||||||
elasticsearch = ["elasticsearch"]
|
elasticsearch = ["elasticsearch"]
|
||||||
histogram = ["pygal", "pygaljs"]
|
histogram = ["pygal", "pygaljs", "setuptools"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytest-cov"
|
name = "pytest-cov"
|
||||||
version = "5.0.0"
|
version = "6.0.0"
|
||||||
description = "Pytest plugin for measuring coverage."
|
description = "Pytest plugin for measuring coverage."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"},
|
{file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"},
|
||||||
{file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"},
|
{file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
coverage = {version = ">=5.2.1", extras = ["toml"]}
|
coverage = {version = ">=7.5", extras = ["toml"]}
|
||||||
pytest = ">=4.6"
|
pytest = ">=4.6"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
@ -2013,13 +2015,13 @@ docs = ["sphinx"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-multipart"
|
name = "python-multipart"
|
||||||
version = "0.0.12"
|
version = "0.0.17"
|
||||||
description = "A streaming multipart parser for Python"
|
description = "A streaming multipart parser for Python"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "python_multipart-0.0.12-py3-none-any.whl", hash = "sha256:43dcf96cf65888a9cd3423544dd0d75ac10f7aa0c3c28a175bbcd00c9ce1aebf"},
|
{file = "python_multipart-0.0.17-py3-none-any.whl", hash = "sha256:15dc4f487e0a9476cc1201261188ee0940165cffc94429b6fc565c4d3045cb5d"},
|
||||||
{file = "python_multipart-0.0.12.tar.gz", hash = "sha256:045e1f98d719c1ce085ed7f7e1ef9d8ccc8c02ba02b5566d5f7521410ced58cb"},
|
{file = "python_multipart-0.0.17.tar.gz", hash = "sha256:41330d831cae6e2f22902704ead2826ea038d0419530eadff3ea80175aec5538"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2268,13 +2270,13 @@ idna2008 = ["idna"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rich"
|
name = "rich"
|
||||||
version = "13.9.3"
|
version = "13.9.4"
|
||||||
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8.0"
|
python-versions = ">=3.8.0"
|
||||||
files = [
|
files = [
|
||||||
{file = "rich-13.9.3-py3-none-any.whl", hash = "sha256:9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283"},
|
{file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"},
|
||||||
{file = "rich-13.9.3.tar.gz", hash = "sha256:bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e"},
|
{file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -2287,29 +2289,29 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.7.1"
|
version = "0.7.2"
|
||||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "ruff-0.7.1-py3-none-linux_armv6l.whl", hash = "sha256:cb1bc5ed9403daa7da05475d615739cc0212e861b7306f314379d958592aaa89"},
|
{file = "ruff-0.7.2-py3-none-linux_armv6l.whl", hash = "sha256:b73f873b5f52092e63ed540adefc3c36f1f803790ecf2590e1df8bf0a9f72cb8"},
|
||||||
{file = "ruff-0.7.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:27c1c52a8d199a257ff1e5582d078eab7145129aa02721815ca8fa4f9612dc35"},
|
{file = "ruff-0.7.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5b813ef26db1015953daf476202585512afd6a6862a02cde63f3bafb53d0b2d4"},
|
||||||
{file = "ruff-0.7.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:588a34e1ef2ea55b4ddfec26bbe76bc866e92523d8c6cdec5e8aceefeff02d99"},
|
{file = "ruff-0.7.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:853277dbd9675810c6826dad7a428d52a11760744508340e66bf46f8be9701d9"},
|
||||||
{file = "ruff-0.7.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94fc32f9cdf72dc75c451e5f072758b118ab8100727168a3df58502b43a599ca"},
|
{file = "ruff-0.7.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21aae53ab1490a52bf4e3bf520c10ce120987b047c494cacf4edad0ba0888da2"},
|
||||||
{file = "ruff-0.7.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:985818742b833bffa543a84d1cc11b5e6871de1b4e0ac3060a59a2bae3969250"},
|
{file = "ruff-0.7.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ccc7e0fc6e0cb3168443eeadb6445285abaae75142ee22b2b72c27d790ab60ba"},
|
||||||
{file = "ruff-0.7.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32f1e8a192e261366c702c5fb2ece9f68d26625f198a25c408861c16dc2dea9c"},
|
{file = "ruff-0.7.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd77877a4e43b3a98e5ef4715ba3862105e299af0c48942cc6d51ba3d97dc859"},
|
||||||
{file = "ruff-0.7.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:699085bf05819588551b11751eff33e9ca58b1b86a6843e1b082a7de40da1565"},
|
{file = "ruff-0.7.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e00163fb897d35523c70d71a46fbaa43bf7bf9af0f4534c53ea5b96b2e03397b"},
|
||||||
{file = "ruff-0.7.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:344cc2b0814047dc8c3a8ff2cd1f3d808bb23c6658db830d25147339d9bf9ea7"},
|
{file = "ruff-0.7.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3c54b538633482dc342e9b634d91168fe8cc56b30a4b4f99287f4e339103e88"},
|
||||||
{file = "ruff-0.7.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4316bbf69d5a859cc937890c7ac7a6551252b6a01b1d2c97e8fc96e45a7c8b4a"},
|
{file = "ruff-0.7.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b792468e9804a204be221b14257566669d1db5c00d6bb335996e5cd7004ba80"},
|
||||||
{file = "ruff-0.7.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79d3af9dca4c56043e738a4d6dd1e9444b6d6c10598ac52d146e331eb155a8ad"},
|
{file = "ruff-0.7.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dba53ed84ac19ae4bfb4ea4bf0172550a2285fa27fbb13e3746f04c80f7fa088"},
|
||||||
{file = "ruff-0.7.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c5c121b46abde94a505175524e51891f829414e093cd8326d6e741ecfc0a9112"},
|
{file = "ruff-0.7.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b19fafe261bf741bca2764c14cbb4ee1819b67adb63ebc2db6401dcd652e3748"},
|
||||||
{file = "ruff-0.7.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8422104078324ea250886954e48f1373a8fe7de59283d747c3a7eca050b4e378"},
|
{file = "ruff-0.7.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:28bd8220f4d8f79d590db9e2f6a0674f75ddbc3847277dd44ac1f8d30684b828"},
|
||||||
{file = "ruff-0.7.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:56aad830af8a9db644e80098fe4984a948e2b6fc2e73891538f43bbe478461b8"},
|
{file = "ruff-0.7.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9fd67094e77efbea932e62b5d2483006154794040abb3a5072e659096415ae1e"},
|
||||||
{file = "ruff-0.7.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:658304f02f68d3a83c998ad8bf91f9b4f53e93e5412b8f2388359d55869727fd"},
|
{file = "ruff-0.7.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:576305393998b7bd6c46018f8104ea3a9cb3fa7908c21d8580e3274a3b04b691"},
|
||||||
{file = "ruff-0.7.1-py3-none-win32.whl", hash = "sha256:b517a2011333eb7ce2d402652ecaa0ac1a30c114fbbd55c6b8ee466a7f600ee9"},
|
{file = "ruff-0.7.2-py3-none-win32.whl", hash = "sha256:fa993cfc9f0ff11187e82de874dfc3611df80852540331bc85c75809c93253a8"},
|
||||||
{file = "ruff-0.7.1-py3-none-win_amd64.whl", hash = "sha256:f38c41fcde1728736b4eb2b18850f6d1e3eedd9678c914dede554a70d5241307"},
|
{file = "ruff-0.7.2-py3-none-win_amd64.whl", hash = "sha256:dd8800cbe0254e06b8fec585e97554047fb82c894973f7ff18558eee33d1cb88"},
|
||||||
{file = "ruff-0.7.1-py3-none-win_arm64.whl", hash = "sha256:19aa200ec824c0f36d0c9114c8ec0087082021732979a359d6f3c390a6ff2a37"},
|
{file = "ruff-0.7.2-py3-none-win_arm64.whl", hash = "sha256:bb8368cd45bba3f57bb29cbb8d64b4a33f8415d0149d2655c5c8539452ce7760"},
|
||||||
{file = "ruff-0.7.1.tar.gz", hash = "sha256:9d8a41d4aa2dad1575adb98a82870cf5db5f76b2938cf2206c22c940034a36f4"},
|
{file = "ruff-0.7.2.tar.gz", hash = "sha256:2b14e77293380e475b4e3a7a368e14549288ed2931fce259a6f99978669e844f"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2329,13 +2331,13 @@ jeepney = ">=0.6"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "selenium"
|
name = "selenium"
|
||||||
version = "4.25.0"
|
version = "4.26.1"
|
||||||
description = "Official Python bindings for Selenium WebDriver"
|
description = "Official Python bindings for Selenium WebDriver"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "selenium-4.25.0-py3-none-any.whl", hash = "sha256:3798d2d12b4a570bc5790163ba57fef10b2afee958bf1d80f2a3cf07c4141f33"},
|
{file = "selenium-4.26.1-py3-none-any.whl", hash = "sha256:1db3f3a0cd5bb07624fa8a3905a6fdde1595a42185a0617077c361dc53d104fb"},
|
||||||
{file = "selenium-4.25.0.tar.gz", hash = "sha256:95d08d3b82fb353f3c474895154516604c7f0e6a9a565ae6498ef36c9bac6921"},
|
{file = "selenium-4.26.1.tar.gz", hash = "sha256:7640f3f08ae7f4e450f895678e8a10a55eb4e4ca18311ed675ecc4684b96b683"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -2348,23 +2350,23 @@ websocket-client = ">=1.8,<2.0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "setuptools"
|
name = "setuptools"
|
||||||
version = "75.2.0"
|
version = "75.3.0"
|
||||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "setuptools-75.2.0-py3-none-any.whl", hash = "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8"},
|
{file = "setuptools-75.3.0-py3-none-any.whl", hash = "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd"},
|
||||||
{file = "setuptools-75.2.0.tar.gz", hash = "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec"},
|
{file = "setuptools-75.3.0.tar.gz", hash = "sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"]
|
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 (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"]
|
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)"]
|
||||||
cover = ["pytest-cov"]
|
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)"]
|
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)"]
|
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", "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)"]
|
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.11.*)", "pytest-mypy"]
|
type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.12.*)", "pytest-mypy"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shellingham"
|
name = "shellingham"
|
||||||
@ -2540,13 +2542,13 @@ SQLAlchemy = ">=2.0.14,<2.1.0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "starlette"
|
name = "starlette"
|
||||||
version = "0.41.0"
|
version = "0.41.2"
|
||||||
description = "The little ASGI library that shines."
|
description = "The little ASGI library that shines."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "starlette-0.41.0-py3-none-any.whl", hash = "sha256:a0193a3c413ebc9c78bff1c3546a45bb8c8bcb4a84cae8747d650a65bd37210a"},
|
{file = "starlette-0.41.2-py3-none-any.whl", hash = "sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d"},
|
||||||
{file = "starlette-0.41.0.tar.gz", hash = "sha256:39cbd8768b107d68bfe1ff1672b38a2c38b49777de46d2a592841d58e3bf7c2a"},
|
{file = "starlette-0.41.2.tar.gz", hash = "sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -2790,13 +2792,13 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)",
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "virtualenv"
|
name = "virtualenv"
|
||||||
version = "20.27.0"
|
version = "20.27.1"
|
||||||
description = "Virtual Python Environment builder"
|
description = "Virtual Python Environment builder"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "virtualenv-20.27.0-py3-none-any.whl", hash = "sha256:44a72c29cceb0ee08f300b314848c86e57bf8d1f13107a5e671fb9274138d655"},
|
{file = "virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4"},
|
||||||
{file = "virtualenv-20.27.0.tar.gz", hash = "sha256:2ca56a68ed615b8fe4326d11a0dca5dfbe8fd68510fb6c6349163bed3c15f2b2"},
|
{file = "virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -3048,4 +3050,4 @@ type = ["pytest-mypy"]
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.9"
|
python-versions = "^3.9"
|
||||||
content-hash = "547fdabf7a030c2a7c8d63eb5b2a3c5e821afa86390f08b895db038d30013904"
|
content-hash = "664c8d3c78923d39d1d59227cb43416228ac396a7004344c058377886421c086"
|
||||||
|
@ -68,15 +68,15 @@ darglint = ">=1.8.1,<2.0"
|
|||||||
dill = ">=0.3.8"
|
dill = ">=0.3.8"
|
||||||
toml = ">=0.10.2,<1.0"
|
toml = ">=0.10.2,<1.0"
|
||||||
pytest-asyncio = ">=0.24.0"
|
pytest-asyncio = ">=0.24.0"
|
||||||
pytest-cov = ">=4.0.0,<6.0"
|
pytest-cov = ">=4.0.0,<7.0"
|
||||||
ruff = "0.7.1"
|
ruff = "0.7.2"
|
||||||
pandas = ">=2.1.1,<3.0"
|
pandas = ">=2.1.1,<3.0"
|
||||||
pillow = ">=10.0.0,<12.0"
|
pillow = ">=10.0.0,<12.0"
|
||||||
plotly = ">=5.13.0,<6.0"
|
plotly = ">=5.13.0,<6.0"
|
||||||
asynctest = ">=0.13.0,<1.0"
|
asynctest = ">=0.13.0,<1.0"
|
||||||
pre-commit = ">=3.2.1"
|
pre-commit = ">=3.2.1"
|
||||||
selenium = ">=4.11.0,<5.0"
|
selenium = ">=4.11.0,<5.0"
|
||||||
pytest-benchmark = ">=4.0.0,<5.0"
|
pytest-benchmark = ">=4.0.0,<6.0"
|
||||||
playwright = ">=1.46.0"
|
playwright = ">=1.46.0"
|
||||||
pytest-playwright = ">=0.5.1"
|
pytest-playwright = ">=0.5.1"
|
||||||
|
|
||||||
|
@ -336,6 +336,7 @@ _MAPPING: dict = {
|
|||||||
"State",
|
"State",
|
||||||
"dynamic",
|
"dynamic",
|
||||||
],
|
],
|
||||||
|
"istate.wrappers": ["get_state"],
|
||||||
"style": ["Style", "toggle_color_mode"],
|
"style": ["Style", "toggle_color_mode"],
|
||||||
"utils.imports": ["ImportVar"],
|
"utils.imports": ["ImportVar"],
|
||||||
"utils.serializers": ["serializer"],
|
"utils.serializers": ["serializer"],
|
||||||
|
@ -180,6 +180,7 @@ from .experimental import _x as _x
|
|||||||
from .istate.storage import Cookie as Cookie
|
from .istate.storage import Cookie as Cookie
|
||||||
from .istate.storage import LocalStorage as LocalStorage
|
from .istate.storage import LocalStorage as LocalStorage
|
||||||
from .istate.storage import SessionStorage as SessionStorage
|
from .istate.storage import SessionStorage as SessionStorage
|
||||||
|
from .istate.wrappers import get_state as get_state
|
||||||
from .middleware import Middleware as Middleware
|
from .middleware import Middleware as Middleware
|
||||||
from .middleware import middleware as middleware
|
from .middleware import middleware as middleware
|
||||||
from .model import Model as Model
|
from .model import Model as Model
|
||||||
|
@ -12,7 +12,6 @@ import inspect
|
|||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
@ -96,7 +95,7 @@ from reflex.state import (
|
|||||||
code_uses_state_contexts,
|
code_uses_state_contexts,
|
||||||
)
|
)
|
||||||
from reflex.utils import codespaces, console, exceptions, format, prerequisites, types
|
from reflex.utils import codespaces, console, exceptions, format, prerequisites, types
|
||||||
from reflex.utils.exec import is_prod_mode, is_testing_env, should_skip_compile
|
from reflex.utils.exec import is_prod_mode, is_testing_env
|
||||||
from reflex.utils.imports import ImportVar
|
from reflex.utils.imports import ImportVar
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -507,7 +506,7 @@ class App(MiddlewareMixin, LifespanMixin):
|
|||||||
# Check if the route given is valid
|
# Check if the route given is valid
|
||||||
verify_route_validity(route)
|
verify_route_validity(route)
|
||||||
|
|
||||||
if route in self.unevaluated_pages and os.getenv(constants.RELOAD_CONFIG):
|
if route in self.unevaluated_pages and environment.RELOAD_CONFIG.is_set():
|
||||||
# when the app is reloaded(typically for app harness tests), we should maintain
|
# when the app is reloaded(typically for app harness tests), we should maintain
|
||||||
# the latest render function of a route.This applies typically to decorated pages
|
# the latest render function of a route.This applies typically to decorated pages
|
||||||
# since they are only added when app._compile is called.
|
# since they are only added when app._compile is called.
|
||||||
@ -724,7 +723,7 @@ class App(MiddlewareMixin, LifespanMixin):
|
|||||||
Whether the app should be compiled.
|
Whether the app should be compiled.
|
||||||
"""
|
"""
|
||||||
# Check the environment variable.
|
# Check the environment variable.
|
||||||
if should_skip_compile():
|
if environment.REFLEX_SKIP_COMPILE.get():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
nocompile = prerequisites.get_web_dir() / constants.NOCOMPILE_FILE
|
nocompile = prerequisites.get_web_dir() / constants.NOCOMPILE_FILE
|
||||||
@ -947,7 +946,7 @@ class App(MiddlewareMixin, LifespanMixin):
|
|||||||
executor = None
|
executor = None
|
||||||
if (
|
if (
|
||||||
platform.system() in ("Linux", "Darwin")
|
platform.system() in ("Linux", "Darwin")
|
||||||
and (number_of_processes := environment.REFLEX_COMPILE_PROCESSES)
|
and (number_of_processes := environment.REFLEX_COMPILE_PROCESSES.get())
|
||||||
is not None
|
is not None
|
||||||
):
|
):
|
||||||
executor = concurrent.futures.ProcessPoolExecutor(
|
executor = concurrent.futures.ProcessPoolExecutor(
|
||||||
@ -956,7 +955,7 @@ class App(MiddlewareMixin, LifespanMixin):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
executor = concurrent.futures.ThreadPoolExecutor(
|
executor = concurrent.futures.ThreadPoolExecutor(
|
||||||
max_workers=environment.REFLEX_COMPILE_THREADS
|
max_workers=environment.REFLEX_COMPILE_THREADS.get()
|
||||||
)
|
)
|
||||||
|
|
||||||
for route, component in zip(self.pages, page_components):
|
for route, component in zip(self.pages, page_components):
|
||||||
|
@ -16,9 +16,6 @@ except ModuleNotFoundError:
|
|||||||
from pydantic.fields import ModelField # type: ignore
|
from pydantic.fields import ModelField # type: ignore
|
||||||
|
|
||||||
|
|
||||||
from reflex import constants
|
|
||||||
|
|
||||||
|
|
||||||
def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None:
|
def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None:
|
||||||
"""Ensure that the field's name does not shadow an existing attribute of the model.
|
"""Ensure that the field's name does not shadow an existing attribute of the model.
|
||||||
|
|
||||||
@ -31,7 +28,8 @@ def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None
|
|||||||
"""
|
"""
|
||||||
from reflex.utils.exceptions import VarNameError
|
from reflex.utils.exceptions import VarNameError
|
||||||
|
|
||||||
reload = os.getenv(constants.RELOAD_CONFIG) == "True"
|
# can't use reflex.config.environment here cause of circular import
|
||||||
|
reload = os.getenv("__RELOAD_CONFIG", "").lower() == "true"
|
||||||
for base in bases:
|
for base in bases:
|
||||||
try:
|
try:
|
||||||
if not reload and getattr(base, field_name, None):
|
if not reload and getattr(base, field_name, None):
|
||||||
|
@ -527,7 +527,7 @@ def remove_tailwind_from_postcss() -> tuple[str, str]:
|
|||||||
|
|
||||||
def purge_web_pages_dir():
|
def purge_web_pages_dir():
|
||||||
"""Empty out .web/pages directory."""
|
"""Empty out .web/pages directory."""
|
||||||
if not is_prod_mode() and environment.REFLEX_PERSIST_WEB_DIR:
|
if not is_prod_mode() and environment.REFLEX_PERSIST_WEB_DIR.get():
|
||||||
# Skip purging the web directory in dev mode if REFLEX_PERSIST_WEB_DIR is set.
|
# Skip purging the web directory in dev mode if REFLEX_PERSIST_WEB_DIR is set.
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ def get_upload_dir() -> Path:
|
|||||||
"""
|
"""
|
||||||
Upload.is_used = True
|
Upload.is_used = True
|
||||||
|
|
||||||
uploaded_files_dir = environment.REFLEX_UPLOADED_FILES_DIR
|
uploaded_files_dir = environment.REFLEX_UPLOADED_FILES_DIR.get()
|
||||||
uploaded_files_dir.mkdir(parents=True, exist_ok=True)
|
uploaded_files_dir.mkdir(parents=True, exist_ok=True)
|
||||||
return uploaded_files_dir
|
return uploaded_files_dir
|
||||||
|
|
||||||
|
@ -135,16 +135,16 @@ class GraphingTooltip(Recharts):
|
|||||||
|
|
||||||
alias = "RechartsTooltip"
|
alias = "RechartsTooltip"
|
||||||
|
|
||||||
# The separator between name and value.
|
# The separator between name and value. Default: ":"
|
||||||
separator: Var[str]
|
separator: Var[str]
|
||||||
|
|
||||||
# The offset size of tooltip. Number
|
# The offset size of tooltip. Number. Default: 10
|
||||||
offset: Var[int]
|
offset: Var[int]
|
||||||
|
|
||||||
# When an item of the payload has value null or undefined, this item won't be displayed.
|
# When an item of the payload has value null or undefined, this item won't be displayed. Default: True
|
||||||
filter_null: Var[bool]
|
filter_null: Var[bool]
|
||||||
|
|
||||||
# If set false, no cursor will be drawn when tooltip is active.
|
# If set false, no cursor will be drawn when tooltip is active. Default: {"strokeWidth": 1, "fill": rx.color("gray", 3)}
|
||||||
cursor: Var[Union[Dict[str, Any], bool]] = LiteralVar.create(
|
cursor: Var[Union[Dict[str, Any], bool]] = LiteralVar.create(
|
||||||
{
|
{
|
||||||
"strokeWidth": 1,
|
"strokeWidth": 1,
|
||||||
@ -155,16 +155,17 @@ class GraphingTooltip(Recharts):
|
|||||||
# The box of viewing area, which has the shape of {x: someVal, y: someVal, width: someVal, height: someVal}, usually calculated internally.
|
# The box of viewing area, which has the shape of {x: someVal, y: someVal, width: someVal, height: someVal}, usually calculated internally.
|
||||||
view_box: Var[Dict[str, Any]]
|
view_box: Var[Dict[str, Any]]
|
||||||
|
|
||||||
# The style of default tooltip content item which is a li element. DEFAULT: {}
|
# The style of default tooltip content item which is a li element. Default: {"color": rx.color("gray", 12)}
|
||||||
item_style: Var[Dict[str, Any]] = LiteralVar.create(
|
item_style: Var[Dict[str, Any]] = LiteralVar.create(
|
||||||
{
|
{
|
||||||
"color": Color("gray", 12),
|
"color": Color("gray", 12),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# The style of tooltip wrapper which is a dom element. DEFAULT: {}
|
# The style of tooltip wrapper which is a dom element. Default: {}
|
||||||
wrapper_style: Var[Dict[str, Any]]
|
wrapper_style: Var[Dict[str, Any]]
|
||||||
# The style of tooltip content which is a dom element. DEFAULT: {}
|
|
||||||
|
# The style of tooltip content which is a dom element. Default: {"background": rx.color("gray", 1), "borderColor": rx.color("gray", 4), "borderRadius": "8px"}
|
||||||
content_style: Var[Dict[str, Any]] = LiteralVar.create(
|
content_style: Var[Dict[str, Any]] = LiteralVar.create(
|
||||||
{
|
{
|
||||||
"background": Color("gray", 1),
|
"background": Color("gray", 1),
|
||||||
@ -173,30 +174,28 @@ class GraphingTooltip(Recharts):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# The style of default tooltip label which is a p element. DEFAULT: {}
|
# The style of default tooltip label which is a p element. Default: {"color": rx.color("gray", 11)}
|
||||||
label_style: Var[Dict[str, Any]] = LiteralVar.create({"color": Color("gray", 11)})
|
label_style: Var[Dict[str, Any]] = LiteralVar.create({"color": Color("gray", 11)})
|
||||||
|
|
||||||
# This option allows the tooltip to extend beyond the viewBox of the chart itself. DEFAULT: { x: false, y: false }
|
# This option allows the tooltip to extend beyond the viewBox of the chart itself. Default: {"x": False, "y": False}
|
||||||
allow_escape_view_box: Var[Dict[str, bool]] = LiteralVar.create(
|
allow_escape_view_box: Var[Dict[str, bool]]
|
||||||
{"x": False, "y": False}
|
|
||||||
)
|
|
||||||
|
|
||||||
# If set true, the tooltip is displayed. If set false, the tooltip is hidden, usually calculated internally.
|
# If set true, the tooltip is displayed. If set false, the tooltip is hidden, usually calculated internally. Default: False
|
||||||
active: Var[bool]
|
active: Var[bool]
|
||||||
|
|
||||||
# If this field is set, the tooltip position will be fixed and will not move anymore.
|
# If this field is set, the tooltip position will be fixed and will not move anymore.
|
||||||
position: Var[Dict[str, Any]]
|
position: Var[Dict[str, Any]]
|
||||||
|
|
||||||
# The coordinate of tooltip which is usually calculated internally.
|
# The coordinate of tooltip which is usually calculated internally. Default: {"x": 0, "y": 0}
|
||||||
coordinate: Var[Dict[str, Any]]
|
coordinate: Var[Dict[str, Any]]
|
||||||
|
|
||||||
# If set false, animation of tooltip will be disabled. DEFAULT: true in CSR, and false in SSR
|
# If set false, animation of tooltip will be disabled. Default: True
|
||||||
is_animation_active: Var[bool]
|
is_animation_active: Var[bool]
|
||||||
|
|
||||||
# Specifies the duration of animation, the unit of this option is ms. DEFAULT: 1500
|
# Specifies the duration of animation, the unit of this option is ms. Default: 1500
|
||||||
animation_duration: Var[int]
|
animation_duration: Var[int]
|
||||||
|
|
||||||
# The type of easing function. DEFAULT: 'ease'
|
# The type of easing function. Default: "ease"
|
||||||
animation_easing: Var[LiteralAnimationEasing]
|
animation_easing: Var[LiteralAnimationEasing]
|
||||||
|
|
||||||
|
|
||||||
|
@ -255,22 +255,22 @@ class GraphingTooltip(Recharts):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
*children: The children of the component.
|
*children: The children of the component.
|
||||||
separator: The separator between name and value.
|
separator: The separator between name and value. Default: ":"
|
||||||
offset: The offset size of tooltip. Number
|
offset: The offset size of tooltip. Number. Default: 10
|
||||||
filter_null: When an item of the payload has value null or undefined, this item won't be displayed.
|
filter_null: When an item of the payload has value null or undefined, this item won't be displayed. Default: True
|
||||||
cursor: If set false, no cursor will be drawn when tooltip is active.
|
cursor: If set false, no cursor will be drawn when tooltip is active. Default: {"strokeWidth": 1, "fill": rx.color("gray", 3)}
|
||||||
view_box: The box of viewing area, which has the shape of {x: someVal, y: someVal, width: someVal, height: someVal}, usually calculated internally.
|
view_box: The box of viewing area, which has the shape of {x: someVal, y: someVal, width: someVal, height: someVal}, usually calculated internally.
|
||||||
item_style: The style of default tooltip content item which is a li element. DEFAULT: {}
|
item_style: The style of default tooltip content item which is a li element. Default: {"color": rx.color("gray", 12)}
|
||||||
wrapper_style: The style of tooltip wrapper which is a dom element. DEFAULT: {}
|
wrapper_style: The style of tooltip wrapper which is a dom element. Default: {}
|
||||||
content_style: The style of tooltip content which is a dom element. DEFAULT: {}
|
content_style: The style of tooltip content which is a dom element. Default: {"background": rx.color("gray", 1), "borderColor": rx.color("gray", 4), "borderRadius": "8px"}
|
||||||
label_style: The style of default tooltip label which is a p element. DEFAULT: {}
|
label_style: The style of default tooltip label which is a p element. Default: {"color": rx.color("gray", 11)}
|
||||||
allow_escape_view_box: This option allows the tooltip to extend beyond the viewBox of the chart itself. DEFAULT: { x: false, y: false }
|
allow_escape_view_box: This option allows the tooltip to extend beyond the viewBox of the chart itself. Default: {"x": False, "y": False}
|
||||||
active: If set true, the tooltip is displayed. If set false, the tooltip is hidden, usually calculated internally.
|
active: If set true, the tooltip is displayed. If set false, the tooltip is hidden, usually calculated internally. Default: False
|
||||||
position: If this field is set, the tooltip position will be fixed and will not move anymore.
|
position: If this field is set, the tooltip position will be fixed and will not move anymore.
|
||||||
coordinate: The coordinate of tooltip which is usually calculated internally.
|
coordinate: The coordinate of tooltip which is usually calculated internally. Default: {"x": 0, "y": 0}
|
||||||
is_animation_active: If set false, animation of tooltip will be disabled. DEFAULT: true in CSR, and false in SSR
|
is_animation_active: If set false, animation of tooltip will be disabled. Default: True
|
||||||
animation_duration: Specifies the duration of animation, the unit of this option is ms. DEFAULT: 1500
|
animation_duration: Specifies the duration of animation, the unit of this option is ms. Default: 1500
|
||||||
animation_easing: The type of easing function. DEFAULT: 'ease'
|
animation_easing: The type of easing function. Default: "ease"
|
||||||
style: The style of the component.
|
style: The style of the component.
|
||||||
key: A unique key for the component.
|
key: A unique key for the component.
|
||||||
id: The id for the component.
|
id: The id for the component.
|
||||||
|
230
reflex/config.py
230
reflex/config.py
@ -10,7 +10,17 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Optional, Set
|
from typing import (
|
||||||
|
TYPE_CHECKING,
|
||||||
|
Any,
|
||||||
|
Dict,
|
||||||
|
Generic,
|
||||||
|
List,
|
||||||
|
Optional,
|
||||||
|
Set,
|
||||||
|
TypeVar,
|
||||||
|
get_args,
|
||||||
|
)
|
||||||
|
|
||||||
from typing_extensions import Annotated, get_type_hints
|
from typing_extensions import Annotated, get_type_hints
|
||||||
|
|
||||||
@ -300,6 +310,141 @@ def interpret_env_var_value(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
||||||
|
class EnvVar(Generic[T]):
|
||||||
|
"""Environment variable."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
default: Any
|
||||||
|
type_: T
|
||||||
|
|
||||||
|
def __init__(self, name: str, default: Any, type_: T) -> None:
|
||||||
|
"""Initialize the environment variable.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: The environment variable name.
|
||||||
|
default: The default value.
|
||||||
|
type_: The type of the value.
|
||||||
|
"""
|
||||||
|
self.name = name
|
||||||
|
self.default = default
|
||||||
|
self.type_ = type_
|
||||||
|
|
||||||
|
def interpret(self, value: str) -> T:
|
||||||
|
"""Interpret the environment variable value.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The environment variable value.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The interpreted value.
|
||||||
|
"""
|
||||||
|
return interpret_env_var_value(value, self.type_, self.name)
|
||||||
|
|
||||||
|
def getenv(self) -> Optional[T]:
|
||||||
|
"""Get the interpreted environment variable value.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The environment variable value.
|
||||||
|
"""
|
||||||
|
env_value = os.getenv(self.name, None)
|
||||||
|
if env_value is not None:
|
||||||
|
return self.interpret(env_value)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def is_set(self) -> bool:
|
||||||
|
"""Check if the environment variable is set.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if the environment variable is set.
|
||||||
|
"""
|
||||||
|
return self.name in os.environ
|
||||||
|
|
||||||
|
def get(self) -> T:
|
||||||
|
"""Get the interpreted environment variable value or the default value if not set.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The interpreted value.
|
||||||
|
"""
|
||||||
|
env_value = self.getenv()
|
||||||
|
if env_value is not None:
|
||||||
|
return env_value
|
||||||
|
return self.default
|
||||||
|
|
||||||
|
def set(self, value: T | None) -> None:
|
||||||
|
"""Set the environment variable. None unsets the variable.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The value to set.
|
||||||
|
"""
|
||||||
|
if value is None:
|
||||||
|
_ = os.environ.pop(self.name, None)
|
||||||
|
else:
|
||||||
|
if isinstance(value, enum.Enum):
|
||||||
|
value = value.value
|
||||||
|
os.environ[self.name] = str(value)
|
||||||
|
|
||||||
|
|
||||||
|
class env_var: # type: ignore
|
||||||
|
"""Descriptor for environment variables."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
default: Any
|
||||||
|
internal: bool = False
|
||||||
|
|
||||||
|
def __init__(self, default: Any, internal: bool = False) -> None:
|
||||||
|
"""Initialize the descriptor.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
default: The default value.
|
||||||
|
internal: Whether the environment variable is reflex internal.
|
||||||
|
"""
|
||||||
|
self.default = default
|
||||||
|
self.internal = internal
|
||||||
|
|
||||||
|
def __set_name__(self, owner, name):
|
||||||
|
"""Set the name of the descriptor.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
owner: The owner class.
|
||||||
|
name: The name of the descriptor.
|
||||||
|
"""
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def __get__(self, instance, owner):
|
||||||
|
"""Get the EnvVar instance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
instance: The instance.
|
||||||
|
owner: The owner class.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The EnvVar instance.
|
||||||
|
"""
|
||||||
|
type_ = get_args(get_type_hints(owner)[self.name])[0]
|
||||||
|
env_name = self.name
|
||||||
|
if self.internal:
|
||||||
|
env_name = f"__{env_name}"
|
||||||
|
return EnvVar(name=env_name, default=self.default, type_=type_)
|
||||||
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
|
||||||
|
def env_var(default, internal=False) -> EnvVar:
|
||||||
|
"""Typing helper for the env_var descriptor.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
default: The default value.
|
||||||
|
internal: Whether the environment variable is reflex internal.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The EnvVar instance.
|
||||||
|
"""
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
class PathExistsFlag:
|
class PathExistsFlag:
|
||||||
"""Flag to indicate that a path must exist."""
|
"""Flag to indicate that a path must exist."""
|
||||||
|
|
||||||
@ -307,83 +452,98 @@ class PathExistsFlag:
|
|||||||
ExistingPath = Annotated[Path, PathExistsFlag]
|
ExistingPath = Annotated[Path, PathExistsFlag]
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(init=False)
|
|
||||||
class EnvironmentVariables:
|
class EnvironmentVariables:
|
||||||
"""Environment variables class to instantiate environment variables."""
|
"""Environment variables class to instantiate environment variables."""
|
||||||
|
|
||||||
# Whether to use npm over bun to install frontend packages.
|
# Whether to use npm over bun to install frontend packages.
|
||||||
REFLEX_USE_NPM: bool = False
|
REFLEX_USE_NPM: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
# The npm registry to use.
|
# The npm registry to use.
|
||||||
NPM_CONFIG_REGISTRY: Optional[str] = None
|
NPM_CONFIG_REGISTRY: EnvVar[Optional[str]] = env_var(None)
|
||||||
|
|
||||||
# Whether to use Granian for the backend. Otherwise, use Uvicorn.
|
# Whether to use Granian for the backend. Otherwise, use Uvicorn.
|
||||||
REFLEX_USE_GRANIAN: bool = False
|
REFLEX_USE_GRANIAN: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
# The username to use for authentication on python package repository. Username and password must both be provided.
|
# The username to use for authentication on python package repository. Username and password must both be provided.
|
||||||
TWINE_USERNAME: Optional[str] = None
|
TWINE_USERNAME: EnvVar[Optional[str]] = env_var(None)
|
||||||
|
|
||||||
# The password to use for authentication on python package repository. Username and password must both be provided.
|
# The password to use for authentication on python package repository. Username and password must both be provided.
|
||||||
TWINE_PASSWORD: Optional[str] = None
|
TWINE_PASSWORD: EnvVar[Optional[str]] = env_var(None)
|
||||||
|
|
||||||
# Whether to use the system installed bun. If set to false, bun will be bundled with the app.
|
# Whether to use the system installed bun. If set to false, bun will be bundled with the app.
|
||||||
REFLEX_USE_SYSTEM_BUN: bool = False
|
REFLEX_USE_SYSTEM_BUN: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
# Whether to use the system installed node and npm. If set to false, node and npm will be bundled with the app.
|
# Whether to use the system installed node and npm. If set to false, node and npm will be bundled with the app.
|
||||||
REFLEX_USE_SYSTEM_NODE: bool = False
|
REFLEX_USE_SYSTEM_NODE: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
# The working directory for the next.js commands.
|
# The working directory for the next.js commands.
|
||||||
REFLEX_WEB_WORKDIR: Path = Path(constants.Dirs.WEB)
|
REFLEX_WEB_WORKDIR: EnvVar[Path] = env_var(Path(constants.Dirs.WEB))
|
||||||
|
|
||||||
# Path to the alembic config file
|
# Path to the alembic config file
|
||||||
ALEMBIC_CONFIG: ExistingPath = Path(constants.ALEMBIC_CONFIG)
|
ALEMBIC_CONFIG: EnvVar[ExistingPath] = env_var(Path(constants.ALEMBIC_CONFIG))
|
||||||
|
|
||||||
# Disable SSL verification for HTTPX requests.
|
# Disable SSL verification for HTTPX requests.
|
||||||
SSL_NO_VERIFY: bool = False
|
SSL_NO_VERIFY: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
# The directory to store uploaded files.
|
# The directory to store uploaded files.
|
||||||
REFLEX_UPLOADED_FILES_DIR: Path = Path(constants.Dirs.UPLOADED_FILES)
|
REFLEX_UPLOADED_FILES_DIR: EnvVar[Path] = env_var(
|
||||||
|
Path(constants.Dirs.UPLOADED_FILES)
|
||||||
|
)
|
||||||
|
|
||||||
# Whether to use seperate processes to compile the frontend and how many. If not set, defaults to thread executor.
|
# Whether to use separate processes to compile the frontend and how many. If not set, defaults to thread executor.
|
||||||
REFLEX_COMPILE_PROCESSES: Optional[int] = None
|
REFLEX_COMPILE_PROCESSES: EnvVar[Optional[int]] = env_var(None)
|
||||||
|
|
||||||
# Whether to use seperate threads to compile the frontend and how many. Defaults to `min(32, os.cpu_count() + 4)`.
|
# Whether to use separate threads to compile the frontend and how many. Defaults to `min(32, os.cpu_count() + 4)`.
|
||||||
REFLEX_COMPILE_THREADS: Optional[int] = None
|
REFLEX_COMPILE_THREADS: EnvVar[Optional[int]] = env_var(None)
|
||||||
|
|
||||||
# The directory to store reflex dependencies.
|
# The directory to store reflex dependencies.
|
||||||
REFLEX_DIR: Path = Path(constants.Reflex.DIR)
|
REFLEX_DIR: EnvVar[Path] = env_var(Path(constants.Reflex.DIR))
|
||||||
|
|
||||||
# Whether to print the SQL queries if the log level is INFO or lower.
|
# Whether to print the SQL queries if the log level is INFO or lower.
|
||||||
SQLALCHEMY_ECHO: bool = False
|
SQLALCHEMY_ECHO: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
# Whether to ignore the redis config error. Some redis servers only allow out-of-band configuration.
|
# Whether to ignore the redis config error. Some redis servers only allow out-of-band configuration.
|
||||||
REFLEX_IGNORE_REDIS_CONFIG_ERROR: bool = False
|
REFLEX_IGNORE_REDIS_CONFIG_ERROR: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
# Whether to skip purging the web directory in dev mode.
|
# Whether to skip purging the web directory in dev mode.
|
||||||
REFLEX_PERSIST_WEB_DIR: bool = False
|
REFLEX_PERSIST_WEB_DIR: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
# The reflex.build frontend host.
|
# The reflex.build frontend host.
|
||||||
REFLEX_BUILD_FRONTEND: str = constants.Templates.REFLEX_BUILD_FRONTEND
|
REFLEX_BUILD_FRONTEND: EnvVar[str] = env_var(
|
||||||
|
constants.Templates.REFLEX_BUILD_FRONTEND
|
||||||
|
)
|
||||||
|
|
||||||
# The reflex.build backend host.
|
# The reflex.build backend host.
|
||||||
REFLEX_BUILD_BACKEND: str = constants.Templates.REFLEX_BUILD_BACKEND
|
REFLEX_BUILD_BACKEND: EnvVar[str] = env_var(
|
||||||
|
constants.Templates.REFLEX_BUILD_BACKEND
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self):
|
# This env var stores the execution mode of the app
|
||||||
"""Initialize the environment variables."""
|
REFLEX_ENV_MODE: EnvVar[constants.Env] = env_var(constants.Env.DEV)
|
||||||
type_hints = get_type_hints(type(self))
|
|
||||||
|
|
||||||
for field in dataclasses.fields(self):
|
# Whether to run the backend only. Exclusive with REFLEX_FRONTEND_ONLY.
|
||||||
raw_value = os.getenv(field.name, None)
|
REFLEX_BACKEND_ONLY: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
field.type = type_hints.get(field.name) or field.type
|
# Whether to run the frontend only. Exclusive with REFLEX_BACKEND_ONLY.
|
||||||
|
REFLEX_FRONTEND_ONLY: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
value = (
|
# Reflex internal env to reload the config.
|
||||||
interpret_env_var_value(raw_value, field.type, field.name)
|
RELOAD_CONFIG: EnvVar[bool] = env_var(False, internal=True)
|
||||||
if raw_value is not None
|
|
||||||
else get_default_value_for_field(field)
|
|
||||||
)
|
|
||||||
|
|
||||||
setattr(self, field.name, value)
|
# If this env var is set to "yes", App.compile will be a no-op
|
||||||
|
REFLEX_SKIP_COMPILE: EnvVar[bool] = env_var(False, internal=True)
|
||||||
|
|
||||||
|
# Whether to run app harness tests in headless mode.
|
||||||
|
APP_HARNESS_HEADLESS: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
|
# Which app harness driver to use.
|
||||||
|
APP_HARNESS_DRIVER: EnvVar[str] = env_var("Chrome")
|
||||||
|
|
||||||
|
# Arguments to pass to the app harness driver.
|
||||||
|
APP_HARNESS_DRIVER_ARGS: EnvVar[str] = env_var("")
|
||||||
|
|
||||||
|
# Where to save screenshots when tests fail.
|
||||||
|
SCREENSHOT_DIR: EnvVar[Optional[Path]] = env_var(None)
|
||||||
|
|
||||||
|
|
||||||
environment = EnvironmentVariables()
|
environment = EnvironmentVariables()
|
||||||
|
@ -2,18 +2,13 @@
|
|||||||
|
|
||||||
from .base import (
|
from .base import (
|
||||||
COOKIES,
|
COOKIES,
|
||||||
ENV_BACKEND_ONLY_ENV_VAR,
|
|
||||||
ENV_FRONTEND_ONLY_ENV_VAR,
|
|
||||||
ENV_MODE_ENV_VAR,
|
|
||||||
IS_WINDOWS,
|
IS_WINDOWS,
|
||||||
LOCAL_STORAGE,
|
LOCAL_STORAGE,
|
||||||
POLLING_MAX_HTTP_BUFFER_SIZE,
|
POLLING_MAX_HTTP_BUFFER_SIZE,
|
||||||
PYTEST_CURRENT_TEST,
|
PYTEST_CURRENT_TEST,
|
||||||
REFLEX_VAR_CLOSING_TAG,
|
REFLEX_VAR_CLOSING_TAG,
|
||||||
REFLEX_VAR_OPENING_TAG,
|
REFLEX_VAR_OPENING_TAG,
|
||||||
RELOAD_CONFIG,
|
|
||||||
SESSION_STORAGE,
|
SESSION_STORAGE,
|
||||||
SKIP_COMPILE_ENV_VAR,
|
|
||||||
ColorMode,
|
ColorMode,
|
||||||
Dirs,
|
Dirs,
|
||||||
Env,
|
Env,
|
||||||
@ -106,7 +101,6 @@ __ALL__ = [
|
|||||||
POLLING_MAX_HTTP_BUFFER_SIZE,
|
POLLING_MAX_HTTP_BUFFER_SIZE,
|
||||||
PYTEST_CURRENT_TEST,
|
PYTEST_CURRENT_TEST,
|
||||||
Reflex,
|
Reflex,
|
||||||
RELOAD_CONFIG,
|
|
||||||
RequirementsTxt,
|
RequirementsTxt,
|
||||||
RouteArgType,
|
RouteArgType,
|
||||||
RouteRegex,
|
RouteRegex,
|
||||||
@ -116,7 +110,6 @@ __ALL__ = [
|
|||||||
ROUTER_DATA_INCLUDE,
|
ROUTER_DATA_INCLUDE,
|
||||||
ROUTE_NOT_FOUND,
|
ROUTE_NOT_FOUND,
|
||||||
SETTER_PREFIX,
|
SETTER_PREFIX,
|
||||||
SKIP_COMPILE_ENV_VAR,
|
|
||||||
SocketEvent,
|
SocketEvent,
|
||||||
StateManagerMode,
|
StateManagerMode,
|
||||||
Tailwind,
|
Tailwind,
|
||||||
|
@ -112,7 +112,7 @@ class Templates(SimpleNamespace):
|
|||||||
from reflex.config import environment
|
from reflex.config import environment
|
||||||
|
|
||||||
return (
|
return (
|
||||||
environment.REFLEX_BUILD_FRONTEND
|
environment.REFLEX_BUILD_FRONTEND.get()
|
||||||
+ "/gen?reflex_init_token={reflex_init_token}"
|
+ "/gen?reflex_init_token={reflex_init_token}"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ class Templates(SimpleNamespace):
|
|||||||
"""
|
"""
|
||||||
from reflex.config import environment
|
from reflex.config import environment
|
||||||
|
|
||||||
return environment.REFLEX_BUILD_BACKEND + "/api/init/{reflex_init_token}"
|
return environment.REFLEX_BUILD_BACKEND.get() + "/api/init/{reflex_init_token}"
|
||||||
|
|
||||||
@classproperty
|
@classproperty
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -139,7 +139,8 @@ class Templates(SimpleNamespace):
|
|||||||
from reflex.config import environment
|
from reflex.config import environment
|
||||||
|
|
||||||
return (
|
return (
|
||||||
environment.REFLEX_BUILD_BACKEND + "/api/gen/{generation_hash}/refactored"
|
environment.REFLEX_BUILD_BACKEND.get()
|
||||||
|
+ "/api/gen/{generation_hash}/refactored"
|
||||||
)
|
)
|
||||||
|
|
||||||
class Dirs(SimpleNamespace):
|
class Dirs(SimpleNamespace):
|
||||||
@ -239,19 +240,9 @@ COOKIES = "cookies"
|
|||||||
LOCAL_STORAGE = "local_storage"
|
LOCAL_STORAGE = "local_storage"
|
||||||
SESSION_STORAGE = "session_storage"
|
SESSION_STORAGE = "session_storage"
|
||||||
|
|
||||||
# If this env var is set to "yes", App.compile will be a no-op
|
|
||||||
SKIP_COMPILE_ENV_VAR = "__REFLEX_SKIP_COMPILE"
|
|
||||||
|
|
||||||
# This env var stores the execution mode of the app
|
|
||||||
ENV_MODE_ENV_VAR = "REFLEX_ENV_MODE"
|
|
||||||
|
|
||||||
ENV_BACKEND_ONLY_ENV_VAR = "REFLEX_BACKEND_ONLY"
|
|
||||||
ENV_FRONTEND_ONLY_ENV_VAR = "REFLEX_FRONTEND_ONLY"
|
|
||||||
|
|
||||||
# Testing variables.
|
# Testing variables.
|
||||||
# Testing os env set by pytest when running a test case.
|
# Testing os env set by pytest when running a test case.
|
||||||
PYTEST_CURRENT_TEST = "PYTEST_CURRENT_TEST"
|
PYTEST_CURRENT_TEST = "PYTEST_CURRENT_TEST"
|
||||||
RELOAD_CONFIG = "__REFLEX_RELOAD_CONFIG"
|
|
||||||
|
|
||||||
REFLEX_VAR_OPENING_TAG = "<reflex.Var>"
|
REFLEX_VAR_OPENING_TAG = "<reflex.Var>"
|
||||||
REFLEX_VAR_CLOSING_TAG = "</reflex.Var>"
|
REFLEX_VAR_CLOSING_TAG = "</reflex.Var>"
|
||||||
|
@ -63,7 +63,7 @@ class Bun(SimpleNamespace):
|
|||||||
"""
|
"""
|
||||||
from reflex.config import environment
|
from reflex.config import environment
|
||||||
|
|
||||||
return environment.REFLEX_DIR / "bun"
|
return environment.REFLEX_DIR.get() / "bun"
|
||||||
|
|
||||||
@classproperty
|
@classproperty
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -105,7 +105,7 @@ class Fnm(SimpleNamespace):
|
|||||||
"""
|
"""
|
||||||
from reflex.config import environment
|
from reflex.config import environment
|
||||||
|
|
||||||
return environment.REFLEX_DIR / "fnm"
|
return environment.REFLEX_DIR.get() / "fnm"
|
||||||
|
|
||||||
@classproperty
|
@classproperty
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -182,7 +182,7 @@ class PackageJson(SimpleNamespace):
|
|||||||
"@emotion/react": "11.13.3",
|
"@emotion/react": "11.13.3",
|
||||||
"axios": "1.7.7",
|
"axios": "1.7.7",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"next": "15.0.1",
|
"next": "14.2.16",
|
||||||
"next-sitemap": "4.2.3",
|
"next-sitemap": "4.2.3",
|
||||||
"next-themes": "0.3.0",
|
"next-themes": "0.3.0",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
|
@ -609,14 +609,14 @@ def publish(
|
|||||||
help="The API token to use for authentication on python package repository. If token is provided, no username/password should be provided at the same time",
|
help="The API token to use for authentication on python package repository. If token is provided, no username/password should be provided at the same time",
|
||||||
),
|
),
|
||||||
username: Optional[str] = typer.Option(
|
username: Optional[str] = typer.Option(
|
||||||
environment.TWINE_USERNAME,
|
environment.TWINE_USERNAME.get(),
|
||||||
"-u",
|
"-u",
|
||||||
"--username",
|
"--username",
|
||||||
show_default="TWINE_USERNAME environment variable value if set",
|
show_default="TWINE_USERNAME environment variable value if set",
|
||||||
help="The username to use for authentication on python package repository. Username and password must both be provided.",
|
help="The username to use for authentication on python package repository. Username and password must both be provided.",
|
||||||
),
|
),
|
||||||
password: Optional[str] = typer.Option(
|
password: Optional[str] = typer.Option(
|
||||||
environment.TWINE_PASSWORD,
|
environment.TWINE_PASSWORD.get(),
|
||||||
"-p",
|
"-p",
|
||||||
"--password",
|
"--password",
|
||||||
show_default="TWINE_PASSWORD environment variable value if set",
|
show_default="TWINE_PASSWORD environment variable value if set",
|
||||||
|
1
reflex/istate/__init__.py
Normal file
1
reflex/istate/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
"""This module will provide interfaces for the state."""
|
33
reflex/istate/proxy.py
Normal file
33
reflex/istate/proxy.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
"""A module to hold state proxy classes."""
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from reflex.state import StateProxy
|
||||||
|
|
||||||
|
|
||||||
|
class ReadOnlyStateProxy(StateProxy):
|
||||||
|
"""A read-only proxy for a state."""
|
||||||
|
|
||||||
|
def __setattr__(self, name: str, value: Any) -> None:
|
||||||
|
"""Prevent setting attributes on the state for read-only proxy.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: The attribute name.
|
||||||
|
value: The attribute value.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: Always raised when trying to set an attribute on proxied state.
|
||||||
|
"""
|
||||||
|
if name.startswith("_self_"):
|
||||||
|
# Special case attributes of the proxy itself, not applied to the wrapped object.
|
||||||
|
super().__setattr__(name, value)
|
||||||
|
return
|
||||||
|
raise NotImplementedError("This is a read-only state proxy.")
|
||||||
|
|
||||||
|
def mark_dirty(self):
|
||||||
|
"""Mark the state as dirty.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: Always raised when trying to mark the proxied state as dirty.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError("This is a read-only state proxy.")
|
31
reflex/istate/wrappers.py
Normal file
31
reflex/istate/wrappers.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
"""Wrappers for the state manager."""
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from reflex.istate.proxy import ReadOnlyStateProxy
|
||||||
|
from reflex.state import (
|
||||||
|
_split_substate_key,
|
||||||
|
_substate_key,
|
||||||
|
get_state_manager,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def get_state(token, state_cls: Any | None = None) -> ReadOnlyStateProxy:
|
||||||
|
"""Get the instance of a state for a token.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
token: The token for the state.
|
||||||
|
state_cls: The class of the state.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A read-only proxy of the state instance.
|
||||||
|
"""
|
||||||
|
mng = get_state_manager()
|
||||||
|
if state_cls is not None:
|
||||||
|
root_state = await mng.get_state(_substate_key(token, state_cls))
|
||||||
|
else:
|
||||||
|
root_state = await mng.get_state(token)
|
||||||
|
_, state_path = _split_substate_key(token)
|
||||||
|
state_cls = root_state.get_class_substate(tuple(state_path.split(".")))
|
||||||
|
instance = await root_state.get_state(state_cls)
|
||||||
|
return ReadOnlyStateProxy(instance)
|
@ -38,12 +38,12 @@ def get_engine(url: str | None = None) -> sqlalchemy.engine.Engine:
|
|||||||
url = url or conf.db_url
|
url = url or conf.db_url
|
||||||
if url is None:
|
if url is None:
|
||||||
raise ValueError("No database url configured")
|
raise ValueError("No database url configured")
|
||||||
if not environment.ALEMBIC_CONFIG.exists():
|
if not environment.ALEMBIC_CONFIG.get().exists():
|
||||||
console.warn(
|
console.warn(
|
||||||
"Database is not initialized, run [bold]reflex db init[/bold] first."
|
"Database is not initialized, run [bold]reflex db init[/bold] first."
|
||||||
)
|
)
|
||||||
# Print the SQL queries if the log level is INFO or lower.
|
# Print the SQL queries if the log level is INFO or lower.
|
||||||
echo_db_query = environment.SQLALCHEMY_ECHO
|
echo_db_query = environment.SQLALCHEMY_ECHO.get()
|
||||||
# Needed for the admin dash on sqlite.
|
# Needed for the admin dash on sqlite.
|
||||||
connect_args = {"check_same_thread": False} if url.startswith("sqlite") else {}
|
connect_args = {"check_same_thread": False} if url.startswith("sqlite") else {}
|
||||||
return sqlmodel.create_engine(url, echo=echo_db_query, connect_args=connect_args)
|
return sqlmodel.create_engine(url, echo=echo_db_query, connect_args=connect_args)
|
||||||
@ -231,7 +231,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
|
|||||||
Returns:
|
Returns:
|
||||||
tuple of (config, script_directory)
|
tuple of (config, script_directory)
|
||||||
"""
|
"""
|
||||||
config = alembic.config.Config(environment.ALEMBIC_CONFIG)
|
config = alembic.config.Config(environment.ALEMBIC_CONFIG.get())
|
||||||
return config, alembic.script.ScriptDirectory(
|
return config, alembic.script.ScriptDirectory(
|
||||||
config.get_main_option("script_location", default="version"),
|
config.get_main_option("script_location", default="version"),
|
||||||
)
|
)
|
||||||
@ -266,8 +266,8 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
|
|||||||
def alembic_init(cls):
|
def alembic_init(cls):
|
||||||
"""Initialize alembic for the project."""
|
"""Initialize alembic for the project."""
|
||||||
alembic.command.init(
|
alembic.command.init(
|
||||||
config=alembic.config.Config(environment.ALEMBIC_CONFIG),
|
config=alembic.config.Config(environment.ALEMBIC_CONFIG.get()),
|
||||||
directory=str(environment.ALEMBIC_CONFIG.parent / "alembic"),
|
directory=str(environment.ALEMBIC_CONFIG.get().parent / "alembic"),
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -287,7 +287,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
|
|||||||
Returns:
|
Returns:
|
||||||
True when changes have been detected.
|
True when changes have been detected.
|
||||||
"""
|
"""
|
||||||
if not environment.ALEMBIC_CONFIG.exists():
|
if not environment.ALEMBIC_CONFIG.get().exists():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
config, script_directory = cls._alembic_config()
|
config, script_directory = cls._alembic_config()
|
||||||
@ -388,7 +388,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
|
|||||||
True - indicating the process was successful.
|
True - indicating the process was successful.
|
||||||
None - indicating the process was skipped.
|
None - indicating the process was skipped.
|
||||||
"""
|
"""
|
||||||
if not environment.ALEMBIC_CONFIG.exists():
|
if not environment.ALEMBIC_CONFIG.get().exists():
|
||||||
return
|
return
|
||||||
|
|
||||||
with cls.get_db_engine().connect() as connection:
|
with cls.get_db_engine().connect() as connection:
|
||||||
|
@ -160,7 +160,7 @@ def _run(
|
|||||||
console.set_log_level(loglevel)
|
console.set_log_level(loglevel)
|
||||||
|
|
||||||
# Set env mode in the environment
|
# Set env mode in the environment
|
||||||
os.environ[constants.ENV_MODE_ENV_VAR] = env.value
|
environment.REFLEX_ENV_MODE.set(env)
|
||||||
|
|
||||||
# Show system info
|
# Show system info
|
||||||
exec.output_system_info()
|
exec.output_system_info()
|
||||||
@ -277,13 +277,13 @@ def run(
|
|||||||
False,
|
False,
|
||||||
"--frontend-only",
|
"--frontend-only",
|
||||||
help="Execute only frontend.",
|
help="Execute only frontend.",
|
||||||
envvar=constants.ENV_FRONTEND_ONLY_ENV_VAR,
|
envvar=environment.REFLEX_FRONTEND_ONLY.name,
|
||||||
),
|
),
|
||||||
backend: bool = typer.Option(
|
backend: bool = typer.Option(
|
||||||
False,
|
False,
|
||||||
"--backend-only",
|
"--backend-only",
|
||||||
help="Execute only backend.",
|
help="Execute only backend.",
|
||||||
envvar=constants.ENV_BACKEND_ONLY_ENV_VAR,
|
envvar=environment.REFLEX_BACKEND_ONLY.name,
|
||||||
),
|
),
|
||||||
frontend_port: str = typer.Option(
|
frontend_port: str = typer.Option(
|
||||||
config.frontend_port, help="Specify a different frontend port."
|
config.frontend_port, help="Specify a different frontend port."
|
||||||
@ -302,8 +302,8 @@ def run(
|
|||||||
if frontend and backend:
|
if frontend and backend:
|
||||||
console.error("Cannot use both --frontend-only and --backend-only options.")
|
console.error("Cannot use both --frontend-only and --backend-only options.")
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
os.environ[constants.ENV_BACKEND_ONLY_ENV_VAR] = str(backend).lower()
|
environment.REFLEX_BACKEND_ONLY.set(backend)
|
||||||
os.environ[constants.ENV_FRONTEND_ONLY_ENV_VAR] = str(frontend).lower()
|
environment.REFLEX_FRONTEND_ONLY.set(frontend)
|
||||||
|
|
||||||
_run(env, frontend, backend, frontend_port, backend_port, backend_host, loglevel)
|
_run(env, frontend, backend, frontend_port, backend_port, backend_host, loglevel)
|
||||||
|
|
||||||
@ -405,7 +405,7 @@ script_cli = typer.Typer()
|
|||||||
|
|
||||||
def _skip_compile():
|
def _skip_compile():
|
||||||
"""Skip the compile step."""
|
"""Skip the compile step."""
|
||||||
os.environ[constants.SKIP_COMPILE_ENV_VAR] = "yes"
|
environment.REFLEX_SKIP_COMPILE.set(True)
|
||||||
|
|
||||||
|
|
||||||
@db_cli.command(name="init")
|
@db_cli.command(name="init")
|
||||||
@ -420,7 +420,7 @@ def db_init():
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Check the alembic config.
|
# Check the alembic config.
|
||||||
if environment.ALEMBIC_CONFIG.exists():
|
if environment.ALEMBIC_CONFIG.get().exists():
|
||||||
console.error(
|
console.error(
|
||||||
"Database is already initialized. Use "
|
"Database is already initialized. Use "
|
||||||
"[bold]reflex db makemigrations[/bold] to create schema change "
|
"[bold]reflex db makemigrations[/bold] to create schema change "
|
||||||
|
@ -3377,7 +3377,7 @@ class StateManagerRedis(StateManager):
|
|||||||
)
|
)
|
||||||
except ResponseError:
|
except ResponseError:
|
||||||
# Some redis servers only allow out-of-band configuration, so ignore errors here.
|
# Some redis servers only allow out-of-band configuration, so ignore errors here.
|
||||||
if not environment.REFLEX_IGNORE_REDIS_CONFIG_ERROR:
|
if not environment.REFLEX_IGNORE_REDIS_CONFIG_ERROR.get():
|
||||||
raise
|
raise
|
||||||
async with self.redis.pubsub() as pubsub:
|
async with self.redis.pubsub() as pubsub:
|
||||||
await pubsub.psubscribe(lock_key_channel)
|
await pubsub.psubscribe(lock_key_channel)
|
||||||
|
@ -43,6 +43,7 @@ import reflex.utils.exec
|
|||||||
import reflex.utils.format
|
import reflex.utils.format
|
||||||
import reflex.utils.prerequisites
|
import reflex.utils.prerequisites
|
||||||
import reflex.utils.processes
|
import reflex.utils.processes
|
||||||
|
from reflex.config import environment
|
||||||
from reflex.state import (
|
from reflex.state import (
|
||||||
BaseState,
|
BaseState,
|
||||||
StateManager,
|
StateManager,
|
||||||
@ -250,6 +251,7 @@ class AppHarness:
|
|||||||
|
|
||||||
def _initialize_app(self):
|
def _initialize_app(self):
|
||||||
# disable telemetry reporting for tests
|
# disable telemetry reporting for tests
|
||||||
|
|
||||||
os.environ["TELEMETRY_ENABLED"] = "false"
|
os.environ["TELEMETRY_ENABLED"] = "false"
|
||||||
self.app_path.mkdir(parents=True, exist_ok=True)
|
self.app_path.mkdir(parents=True, exist_ok=True)
|
||||||
if self.app_source is not None:
|
if self.app_source is not None:
|
||||||
@ -615,10 +617,10 @@ class AppHarness:
|
|||||||
if self.frontend_url is None:
|
if self.frontend_url is None:
|
||||||
raise RuntimeError("Frontend is not running.")
|
raise RuntimeError("Frontend is not running.")
|
||||||
want_headless = False
|
want_headless = False
|
||||||
if os.environ.get("APP_HARNESS_HEADLESS"):
|
if environment.APP_HARNESS_HEADLESS.get():
|
||||||
want_headless = True
|
want_headless = True
|
||||||
if driver_clz is None:
|
if driver_clz is None:
|
||||||
requested_driver = os.environ.get("APP_HARNESS_DRIVER", "Chrome")
|
requested_driver = environment.APP_HARNESS_DRIVER.get()
|
||||||
driver_clz = getattr(webdriver, requested_driver)
|
driver_clz = getattr(webdriver, requested_driver)
|
||||||
if driver_options is None:
|
if driver_options is None:
|
||||||
driver_options = getattr(webdriver, f"{requested_driver}Options")()
|
driver_options = getattr(webdriver, f"{requested_driver}Options")()
|
||||||
@ -640,7 +642,7 @@ class AppHarness:
|
|||||||
driver_options.add_argument("headless")
|
driver_options.add_argument("headless")
|
||||||
if driver_options is None:
|
if driver_options is None:
|
||||||
raise RuntimeError(f"Could not determine options for {driver_clz}")
|
raise RuntimeError(f"Could not determine options for {driver_clz}")
|
||||||
if args := os.environ.get("APP_HARNESS_DRIVER_ARGS"):
|
if args := environment.APP_HARNESS_DRIVER_ARGS.get():
|
||||||
for arg in args.split(","):
|
for arg in args.split(","):
|
||||||
driver_options.add_argument(arg)
|
driver_options.add_argument(arg)
|
||||||
if driver_option_args is not None:
|
if driver_option_args is not None:
|
||||||
@ -944,7 +946,7 @@ class AppHarnessProd(AppHarness):
|
|||||||
def _start_backend(self):
|
def _start_backend(self):
|
||||||
if self.app_instance is None:
|
if self.app_instance is None:
|
||||||
raise RuntimeError("App was not initialized.")
|
raise RuntimeError("App was not initialized.")
|
||||||
os.environ[reflex.constants.SKIP_COMPILE_ENV_VAR] = "yes"
|
environment.REFLEX_SKIP_COMPILE.set(True)
|
||||||
self.backend = uvicorn.Server(
|
self.backend = uvicorn.Server(
|
||||||
uvicorn.Config(
|
uvicorn.Config(
|
||||||
app=self.app_instance,
|
app=self.app_instance,
|
||||||
@ -961,7 +963,7 @@ class AppHarnessProd(AppHarness):
|
|||||||
try:
|
try:
|
||||||
return super()._poll_for_servers(timeout)
|
return super()._poll_for_servers(timeout)
|
||||||
finally:
|
finally:
|
||||||
os.environ.pop(reflex.constants.SKIP_COMPILE_ENV_VAR, None)
|
environment.REFLEX_SKIP_COMPILE.set(None)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""Stop the frontend python webserver."""
|
"""Stop the frontend python webserver."""
|
||||||
|
@ -184,7 +184,7 @@ def should_use_granian():
|
|||||||
Returns:
|
Returns:
|
||||||
True if Granian should be used.
|
True if Granian should be used.
|
||||||
"""
|
"""
|
||||||
return environment.REFLEX_USE_GRANIAN
|
return environment.REFLEX_USE_GRANIAN.get()
|
||||||
|
|
||||||
|
|
||||||
def get_app_module():
|
def get_app_module():
|
||||||
@ -369,7 +369,9 @@ def run_uvicorn_backend_prod(host, port, loglevel):
|
|||||||
command,
|
command,
|
||||||
run=True,
|
run=True,
|
||||||
show_logs=True,
|
show_logs=True,
|
||||||
env={constants.SKIP_COMPILE_ENV_VAR: "yes"}, # skip compile for prod backend
|
env={
|
||||||
|
environment.REFLEX_SKIP_COMPILE.name: "true"
|
||||||
|
}, # skip compile for prod backend
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -405,7 +407,7 @@ def run_granian_backend_prod(host, port, loglevel):
|
|||||||
run=True,
|
run=True,
|
||||||
show_logs=True,
|
show_logs=True,
|
||||||
env={
|
env={
|
||||||
constants.SKIP_COMPILE_ENV_VAR: "yes"
|
environment.REFLEX_SKIP_COMPILE.name: "true"
|
||||||
}, # skip compile for prod backend
|
}, # skip compile for prod backend
|
||||||
)
|
)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -491,11 +493,8 @@ def is_prod_mode() -> bool:
|
|||||||
Returns:
|
Returns:
|
||||||
True if the app is running in production mode or False if running in dev mode.
|
True if the app is running in production mode or False if running in dev mode.
|
||||||
"""
|
"""
|
||||||
current_mode = os.environ.get(
|
current_mode = environment.REFLEX_ENV_MODE.get()
|
||||||
constants.ENV_MODE_ENV_VAR,
|
return current_mode == constants.Env.PROD
|
||||||
constants.Env.DEV.value,
|
|
||||||
)
|
|
||||||
return current_mode == constants.Env.PROD.value
|
|
||||||
|
|
||||||
|
|
||||||
def is_frontend_only() -> bool:
|
def is_frontend_only() -> bool:
|
||||||
@ -504,7 +503,13 @@ def is_frontend_only() -> bool:
|
|||||||
Returns:
|
Returns:
|
||||||
True if the app is running in frontend-only mode.
|
True if the app is running in frontend-only mode.
|
||||||
"""
|
"""
|
||||||
return os.environ.get(constants.ENV_FRONTEND_ONLY_ENV_VAR, "").lower() == "true"
|
console.deprecate(
|
||||||
|
"is_frontend_only() is deprecated and will be removed in a future release.",
|
||||||
|
reason="Use `environment.REFLEX_FRONTEND_ONLY.get()` instead.",
|
||||||
|
deprecation_version="0.6.5",
|
||||||
|
removal_version="0.7.0",
|
||||||
|
)
|
||||||
|
return environment.REFLEX_FRONTEND_ONLY.get()
|
||||||
|
|
||||||
|
|
||||||
def is_backend_only() -> bool:
|
def is_backend_only() -> bool:
|
||||||
@ -513,7 +518,13 @@ def is_backend_only() -> bool:
|
|||||||
Returns:
|
Returns:
|
||||||
True if the app is running in backend-only mode.
|
True if the app is running in backend-only mode.
|
||||||
"""
|
"""
|
||||||
return os.environ.get(constants.ENV_BACKEND_ONLY_ENV_VAR, "").lower() == "true"
|
console.deprecate(
|
||||||
|
"is_backend_only() is deprecated and will be removed in a future release.",
|
||||||
|
reason="Use `environment.REFLEX_BACKEND_ONLY.get()` instead.",
|
||||||
|
deprecation_version="0.6.5",
|
||||||
|
removal_version="0.7.0",
|
||||||
|
)
|
||||||
|
return environment.REFLEX_BACKEND_ONLY.get()
|
||||||
|
|
||||||
|
|
||||||
def should_skip_compile() -> bool:
|
def should_skip_compile() -> bool:
|
||||||
@ -522,4 +533,10 @@ def should_skip_compile() -> bool:
|
|||||||
Returns:
|
Returns:
|
||||||
True if the app should skip compile.
|
True if the app should skip compile.
|
||||||
"""
|
"""
|
||||||
return os.environ.get(constants.SKIP_COMPILE_ENV_VAR) == "yes"
|
console.deprecate(
|
||||||
|
"should_skip_compile() is deprecated and will be removed in a future release.",
|
||||||
|
reason="Use `environment.REFLEX_SKIP_COMPILE.get()` instead.",
|
||||||
|
deprecation_version="0.6.5",
|
||||||
|
removal_version="0.7.0",
|
||||||
|
)
|
||||||
|
return environment.REFLEX_SKIP_COMPILE.get()
|
||||||
|
@ -12,7 +12,7 @@ def _httpx_verify_kwarg() -> bool:
|
|||||||
Returns:
|
Returns:
|
||||||
True if SSL verification is enabled, False otherwise
|
True if SSL verification is enabled, False otherwise
|
||||||
"""
|
"""
|
||||||
return not environment.SSL_NO_VERIFY
|
return not environment.SSL_NO_VERIFY.get()
|
||||||
|
|
||||||
|
|
||||||
def get(url: str, **kwargs) -> httpx.Response:
|
def get(url: str, **kwargs) -> httpx.Response:
|
||||||
|
@ -136,7 +136,7 @@ def use_system_node() -> bool:
|
|||||||
Returns:
|
Returns:
|
||||||
Whether the system node should be used.
|
Whether the system node should be used.
|
||||||
"""
|
"""
|
||||||
return environment.REFLEX_USE_SYSTEM_NODE
|
return environment.REFLEX_USE_SYSTEM_NODE.get()
|
||||||
|
|
||||||
|
|
||||||
def use_system_bun() -> bool:
|
def use_system_bun() -> bool:
|
||||||
@ -145,7 +145,7 @@ def use_system_bun() -> bool:
|
|||||||
Returns:
|
Returns:
|
||||||
Whether the system bun should be used.
|
Whether the system bun should be used.
|
||||||
"""
|
"""
|
||||||
return environment.REFLEX_USE_SYSTEM_BUN
|
return environment.REFLEX_USE_SYSTEM_BUN.get()
|
||||||
|
|
||||||
|
|
||||||
def get_node_bin_path() -> Path | None:
|
def get_node_bin_path() -> Path | None:
|
||||||
|
@ -69,7 +69,7 @@ def get_web_dir() -> Path:
|
|||||||
Returns:
|
Returns:
|
||||||
The working directory.
|
The working directory.
|
||||||
"""
|
"""
|
||||||
return environment.REFLEX_WEB_WORKDIR
|
return environment.REFLEX_WEB_WORKDIR.get()
|
||||||
|
|
||||||
|
|
||||||
def _python_version_check():
|
def _python_version_check():
|
||||||
@ -260,7 +260,7 @@ def windows_npm_escape_hatch() -> bool:
|
|||||||
Returns:
|
Returns:
|
||||||
If the user has set REFLEX_USE_NPM.
|
If the user has set REFLEX_USE_NPM.
|
||||||
"""
|
"""
|
||||||
return environment.REFLEX_USE_NPM
|
return environment.REFLEX_USE_NPM.get()
|
||||||
|
|
||||||
|
|
||||||
def get_app(reload: bool = False) -> ModuleType:
|
def get_app(reload: bool = False) -> ModuleType:
|
||||||
@ -278,7 +278,7 @@ def get_app(reload: bool = False) -> ModuleType:
|
|||||||
from reflex.utils import telemetry
|
from reflex.utils import telemetry
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.environ[constants.RELOAD_CONFIG] = str(reload)
|
environment.RELOAD_CONFIG.set(reload)
|
||||||
config = get_config()
|
config = get_config()
|
||||||
if not config.app_name:
|
if not config.app_name:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
@ -1025,7 +1025,7 @@ def needs_reinit(frontend: bool = True) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# Make sure the .reflex directory exists.
|
# Make sure the .reflex directory exists.
|
||||||
if not environment.REFLEX_DIR.exists():
|
if not environment.REFLEX_DIR.get().exists():
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Make sure the .web directory exists in frontend mode.
|
# Make sure the .web directory exists in frontend mode.
|
||||||
@ -1130,7 +1130,7 @@ def ensure_reflex_installation_id() -> Optional[int]:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
initialize_reflex_user_directory()
|
initialize_reflex_user_directory()
|
||||||
installation_id_file = environment.REFLEX_DIR / "installation_id"
|
installation_id_file = environment.REFLEX_DIR.get() / "installation_id"
|
||||||
|
|
||||||
installation_id = None
|
installation_id = None
|
||||||
if installation_id_file.exists():
|
if installation_id_file.exists():
|
||||||
@ -1155,7 +1155,7 @@ def ensure_reflex_installation_id() -> Optional[int]:
|
|||||||
def initialize_reflex_user_directory():
|
def initialize_reflex_user_directory():
|
||||||
"""Initialize the reflex user directory."""
|
"""Initialize the reflex user directory."""
|
||||||
# Create the reflex directory.
|
# Create the reflex directory.
|
||||||
path_ops.mkdir(environment.REFLEX_DIR)
|
path_ops.mkdir(environment.REFLEX_DIR.get())
|
||||||
|
|
||||||
|
|
||||||
def initialize_frontend_dependencies():
|
def initialize_frontend_dependencies():
|
||||||
@ -1178,7 +1178,10 @@ def check_db_initialized() -> bool:
|
|||||||
Returns:
|
Returns:
|
||||||
True if alembic is initialized (or if database is not used).
|
True if alembic is initialized (or if database is not used).
|
||||||
"""
|
"""
|
||||||
if get_config().db_url is not None and not environment.ALEMBIC_CONFIG.exists():
|
if (
|
||||||
|
get_config().db_url is not None
|
||||||
|
and not environment.ALEMBIC_CONFIG.get().exists()
|
||||||
|
):
|
||||||
console.error(
|
console.error(
|
||||||
"Database is not initialized. Run [bold]reflex db init[/bold] first."
|
"Database is not initialized. Run [bold]reflex db init[/bold] first."
|
||||||
)
|
)
|
||||||
@ -1188,7 +1191,7 @@ def check_db_initialized() -> bool:
|
|||||||
|
|
||||||
def check_schema_up_to_date():
|
def check_schema_up_to_date():
|
||||||
"""Check if the sqlmodel metadata matches the current database schema."""
|
"""Check if the sqlmodel metadata matches the current database schema."""
|
||||||
if get_config().db_url is None or not environment.ALEMBIC_CONFIG.exists():
|
if get_config().db_url is None or not environment.ALEMBIC_CONFIG.get().exists():
|
||||||
return
|
return
|
||||||
with model.Model.get_db_engine().connect() as connection:
|
with model.Model.get_db_engine().connect() as connection:
|
||||||
try:
|
try:
|
||||||
|
@ -55,4 +55,4 @@ def _get_npm_registry() -> str:
|
|||||||
Returns:
|
Returns:
|
||||||
str:
|
str:
|
||||||
"""
|
"""
|
||||||
return environment.NPM_CONFIG_REGISTRY or get_best_registry()
|
return environment.NPM_CONFIG_REGISTRY.get() or get_best_registry()
|
||||||
|
@ -78,7 +78,7 @@ def serializer(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Apply type transformation if requested
|
# Apply type transformation if requested
|
||||||
if to is not None:
|
if to is not None or ((to := type_hints.get("return")) is not None):
|
||||||
SERIALIZER_TYPES[type_] = to
|
SERIALIZER_TYPES[type_] = to
|
||||||
get_serializer_type.cache_clear()
|
get_serializer_type.cache_clear()
|
||||||
|
|
||||||
@ -189,16 +189,37 @@ def get_serializer_type(type_: Type) -> Optional[Type]:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def has_serializer(type_: Type) -> bool:
|
def has_serializer(type_: Type, into_type: Type | None = None) -> bool:
|
||||||
"""Check if there is a serializer for the type.
|
"""Check if there is a serializer for the type.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
type_: The type to check.
|
type_: The type to check.
|
||||||
|
into_type: The type to serialize into.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Whether there is a serializer for the type.
|
Whether there is a serializer for the type.
|
||||||
"""
|
"""
|
||||||
return get_serializer(type_) is not None
|
serializer_for_type = get_serializer(type_)
|
||||||
|
return serializer_for_type is not None and (
|
||||||
|
into_type is None or get_serializer_type(type_) == into_type
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def can_serialize(type_: Type, into_type: Type | None = None) -> bool:
|
||||||
|
"""Check if there is a serializer for the type.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
type_: The type to check.
|
||||||
|
into_type: The type to serialize into.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Whether there is a serializer for the type.
|
||||||
|
"""
|
||||||
|
return has_serializer(type_, into_type) or (
|
||||||
|
isinstance(type_, type)
|
||||||
|
and dataclasses.is_dataclass(type_)
|
||||||
|
and (into_type is None or into_type is dict)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@serializer(to=str)
|
@serializer(to=str)
|
||||||
@ -214,7 +235,7 @@ def serialize_type(value: type) -> str:
|
|||||||
return value.__name__
|
return value.__name__
|
||||||
|
|
||||||
|
|
||||||
@serializer
|
@serializer(to=dict)
|
||||||
def serialize_base(value: Base) -> dict:
|
def serialize_base(value: Base) -> dict:
|
||||||
"""Serialize a Base instance.
|
"""Serialize a Base instance.
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@ import multiprocessing
|
|||||||
import platform
|
import platform
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
from reflex.config import environment
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from datetime import UTC, datetime
|
from datetime import UTC, datetime
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -20,7 +22,6 @@ import psutil
|
|||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.utils import console
|
from reflex.utils import console
|
||||||
from reflex.utils.exec import should_skip_compile
|
|
||||||
from reflex.utils.prerequisites import ensure_reflex_installation_id, get_project_hash
|
from reflex.utils.prerequisites import ensure_reflex_installation_id, get_project_hash
|
||||||
|
|
||||||
POSTHOG_API_URL: str = "https://app.posthog.com/capture/"
|
POSTHOG_API_URL: str = "https://app.posthog.com/capture/"
|
||||||
@ -94,7 +95,7 @@ def _raise_on_missing_project_hash() -> bool:
|
|||||||
False when compilation should be skipped (i.e. no .web directory is required).
|
False when compilation should be skipped (i.e. no .web directory is required).
|
||||||
Otherwise return True.
|
Otherwise return True.
|
||||||
"""
|
"""
|
||||||
return not should_skip_compile()
|
return not environment.REFLEX_SKIP_COMPILE.get()
|
||||||
|
|
||||||
|
|
||||||
def _prepare_event(event: str, **kwargs) -> dict:
|
def _prepare_event(event: str, **kwargs) -> dict:
|
||||||
|
@ -75,7 +75,6 @@ from reflex.utils.types import (
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from reflex.state import BaseState
|
from reflex.state import BaseState
|
||||||
|
|
||||||
from .function import FunctionVar
|
|
||||||
from .number import (
|
from .number import (
|
||||||
BooleanVar,
|
BooleanVar,
|
||||||
NumberVar,
|
NumberVar,
|
||||||
@ -279,6 +278,24 @@ def _decode_var_immutable(value: str) -> tuple[VarData | None, str]:
|
|||||||
return VarData.merge(*var_datas) if var_datas else None, value
|
return VarData.merge(*var_datas) if var_datas else None, value
|
||||||
|
|
||||||
|
|
||||||
|
def can_use_in_object_var(cls: GenericType) -> bool:
|
||||||
|
"""Check if the class can be used in an ObjectVar.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
cls: The class to check.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Whether the class can be used in an ObjectVar.
|
||||||
|
"""
|
||||||
|
if types.is_union(cls):
|
||||||
|
return all(can_use_in_object_var(t) for t in types.get_args(cls))
|
||||||
|
return (
|
||||||
|
inspect.isclass(cls)
|
||||||
|
and not issubclass(cls, Var)
|
||||||
|
and serializers.can_serialize(cls, dict)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(
|
@dataclasses.dataclass(
|
||||||
eq=False,
|
eq=False,
|
||||||
frozen=True,
|
frozen=True,
|
||||||
@ -565,36 +582,33 @@ class Var(Generic[VAR_TYPE]):
|
|||||||
# Encode the _var_data into the formatted output for tracking purposes.
|
# Encode the _var_data into the formatted output for tracking purposes.
|
||||||
return f"{constants.REFLEX_VAR_OPENING_TAG}{hashed_var}{constants.REFLEX_VAR_CLOSING_TAG}{self._js_expr}"
|
return f"{constants.REFLEX_VAR_OPENING_TAG}{hashed_var}{constants.REFLEX_VAR_CLOSING_TAG}{self._js_expr}"
|
||||||
|
|
||||||
@overload
|
|
||||||
def to(self, output: Type[StringVar]) -> StringVar: ...
|
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def to(self, output: Type[str]) -> StringVar: ...
|
def to(self, output: Type[str]) -> StringVar: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def to(self, output: Type[BooleanVar]) -> BooleanVar: ...
|
def to(self, output: Type[bool]) -> BooleanVar: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def to(
|
def to(self, output: type[int] | type[float]) -> NumberVar: ...
|
||||||
self, output: Type[NumberVar], var_type: type[int] | type[float] = float
|
|
||||||
) -> NumberVar: ...
|
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def to(
|
def to(
|
||||||
self,
|
self,
|
||||||
output: Type[ArrayVar],
|
output: type[list] | type[tuple] | type[set],
|
||||||
var_type: type[list] | type[tuple] | type[set] = list,
|
|
||||||
) -> ArrayVar: ...
|
) -> ArrayVar: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def to(
|
def to(
|
||||||
self, output: Type[ObjectVar], var_type: types.GenericType = dict
|
self, output: Type[ObjectVar], var_type: Type[VAR_INSIDE]
|
||||||
) -> ObjectVar: ...
|
) -> ObjectVar[VAR_INSIDE]: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def to(
|
def to(
|
||||||
self, output: Type[FunctionVar], var_type: Type[Callable] = Callable
|
self, output: Type[ObjectVar], var_type: None = None
|
||||||
) -> FunctionVar: ...
|
) -> ObjectVar[VAR_TYPE]: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def to(self, output: VAR_SUBCLASS, var_type: None = None) -> VAR_SUBCLASS: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def to(
|
def to(
|
||||||
@ -630,21 +644,19 @@ class Var(Generic[VAR_TYPE]):
|
|||||||
return get_to_operation(NoneVar).create(self) # type: ignore
|
return get_to_operation(NoneVar).create(self) # type: ignore
|
||||||
|
|
||||||
# Handle fixed_output_type being Base or a dataclass.
|
# Handle fixed_output_type being Base or a dataclass.
|
||||||
try:
|
if can_use_in_object_var(fixed_output_type):
|
||||||
if issubclass(fixed_output_type, Base):
|
|
||||||
return self.to(ObjectVar, output)
|
|
||||||
except TypeError:
|
|
||||||
pass
|
|
||||||
if dataclasses.is_dataclass(fixed_output_type) and not issubclass(
|
|
||||||
fixed_output_type, Var
|
|
||||||
):
|
|
||||||
return self.to(ObjectVar, output)
|
return self.to(ObjectVar, output)
|
||||||
|
|
||||||
if inspect.isclass(output):
|
if inspect.isclass(output):
|
||||||
for var_subclass in _var_subclasses[::-1]:
|
for var_subclass in _var_subclasses[::-1]:
|
||||||
if issubclass(output, var_subclass.var_subclass):
|
if issubclass(output, var_subclass.var_subclass):
|
||||||
|
current_var_type = self._var_type
|
||||||
|
if current_var_type is Any:
|
||||||
|
new_var_type = var_type
|
||||||
|
else:
|
||||||
|
new_var_type = var_type or current_var_type
|
||||||
to_operation_return = var_subclass.to_var_subclass.create(
|
to_operation_return = var_subclass.to_var_subclass.create(
|
||||||
value=self, _var_type=var_type
|
value=self, _var_type=new_var_type
|
||||||
)
|
)
|
||||||
return to_operation_return # type: ignore
|
return to_operation_return # type: ignore
|
||||||
|
|
||||||
@ -707,11 +719,7 @@ class Var(Generic[VAR_TYPE]):
|
|||||||
):
|
):
|
||||||
return self.to(NumberVar, self._var_type)
|
return self.to(NumberVar, self._var_type)
|
||||||
|
|
||||||
if all(
|
if can_use_in_object_var(var_type):
|
||||||
inspect.isclass(t)
|
|
||||||
and (issubclass(t, Base) or dataclasses.is_dataclass(t))
|
|
||||||
for t in inner_types
|
|
||||||
):
|
|
||||||
return self.to(ObjectVar, self._var_type)
|
return self.to(ObjectVar, self._var_type)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@ -730,13 +738,9 @@ class Var(Generic[VAR_TYPE]):
|
|||||||
if issubclass(fixed_type, var_subclass.python_types):
|
if issubclass(fixed_type, var_subclass.python_types):
|
||||||
return self.to(var_subclass.var_subclass, self._var_type)
|
return self.to(var_subclass.var_subclass, self._var_type)
|
||||||
|
|
||||||
try:
|
if can_use_in_object_var(fixed_type):
|
||||||
if issubclass(fixed_type, Base):
|
|
||||||
return self.to(ObjectVar, self._var_type)
|
|
||||||
except TypeError:
|
|
||||||
pass
|
|
||||||
if dataclasses.is_dataclass(fixed_type):
|
|
||||||
return self.to(ObjectVar, self._var_type)
|
return self.to(ObjectVar, self._var_type)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def get_default_value(self) -> Any:
|
def get_default_value(self) -> Any:
|
||||||
@ -1181,6 +1185,9 @@ class Var(Generic[VAR_TYPE]):
|
|||||||
|
|
||||||
OUTPUT = TypeVar("OUTPUT", bound=Var)
|
OUTPUT = TypeVar("OUTPUT", bound=Var)
|
||||||
|
|
||||||
|
VAR_SUBCLASS = TypeVar("VAR_SUBCLASS", bound=Var)
|
||||||
|
VAR_INSIDE = TypeVar("VAR_INSIDE")
|
||||||
|
|
||||||
|
|
||||||
class ToOperation:
|
class ToOperation:
|
||||||
"""A var operation that converts a var to another type."""
|
"""A var operation that converts a var to another type."""
|
||||||
@ -2888,6 +2895,8 @@ def dispatch(
|
|||||||
|
|
||||||
V = TypeVar("V")
|
V = TypeVar("V")
|
||||||
|
|
||||||
|
BASE_TYPE = TypeVar("BASE_TYPE", bound=Base)
|
||||||
|
|
||||||
|
|
||||||
class Field(Generic[T]):
|
class Field(Generic[T]):
|
||||||
"""Shadow class for Var to allow for type hinting in the IDE."""
|
"""Shadow class for Var to allow for type hinting in the IDE."""
|
||||||
@ -2924,6 +2933,11 @@ class Field(Generic[T]):
|
|||||||
self: Field[Dict[str, V]], instance: None, owner
|
self: Field[Dict[str, V]], instance: None, owner
|
||||||
) -> ObjectVar[Dict[str, V]]: ...
|
) -> ObjectVar[Dict[str, V]]: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def __get__(
|
||||||
|
self: Field[BASE_TYPE], instance: None, owner
|
||||||
|
) -> ObjectVar[BASE_TYPE]: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __get__(self, instance: None, owner) -> Var[T]: ...
|
def __get__(self, instance: None, owner) -> Var[T]: ...
|
||||||
|
|
||||||
|
@ -1116,7 +1116,9 @@ U = TypeVar("U")
|
|||||||
|
|
||||||
|
|
||||||
@var_operation
|
@var_operation
|
||||||
def ternary_operation(condition: BooleanVar, if_true: Var[T], if_false: Var[U]):
|
def ternary_operation(
|
||||||
|
condition: BooleanVar, if_true: Var[T], if_false: Var[U]
|
||||||
|
) -> CustomVarOperationReturn[Union[T, U]]:
|
||||||
"""Create a ternary operation.
|
"""Create a ternary operation.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -36,7 +36,7 @@ from .base import (
|
|||||||
from .number import BooleanVar, NumberVar, raise_unsupported_operand_types
|
from .number import BooleanVar, NumberVar, raise_unsupported_operand_types
|
||||||
from .sequence import ArrayVar, StringVar
|
from .sequence import ArrayVar, StringVar
|
||||||
|
|
||||||
OBJECT_TYPE = TypeVar("OBJECT_TYPE", bound=Dict)
|
OBJECT_TYPE = TypeVar("OBJECT_TYPE")
|
||||||
|
|
||||||
KEY_TYPE = TypeVar("KEY_TYPE")
|
KEY_TYPE = TypeVar("KEY_TYPE")
|
||||||
VALUE_TYPE = TypeVar("VALUE_TYPE")
|
VALUE_TYPE = TypeVar("VALUE_TYPE")
|
||||||
@ -59,7 +59,7 @@ class ObjectVar(Var[OBJECT_TYPE], python_types=dict):
|
|||||||
|
|
||||||
@overload
|
@overload
|
||||||
def _value_type(
|
def _value_type(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, VALUE_TYPE]],
|
self: ObjectVar[Dict[Any, VALUE_TYPE]],
|
||||||
) -> Type[VALUE_TYPE]: ...
|
) -> Type[VALUE_TYPE]: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
@ -87,7 +87,7 @@ class ObjectVar(Var[OBJECT_TYPE], python_types=dict):
|
|||||||
|
|
||||||
@overload
|
@overload
|
||||||
def values(
|
def values(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, VALUE_TYPE]],
|
self: ObjectVar[Dict[Any, VALUE_TYPE]],
|
||||||
) -> ArrayVar[List[VALUE_TYPE]]: ...
|
) -> ArrayVar[List[VALUE_TYPE]]: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
@ -103,7 +103,7 @@ class ObjectVar(Var[OBJECT_TYPE], python_types=dict):
|
|||||||
|
|
||||||
@overload
|
@overload
|
||||||
def entries(
|
def entries(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, VALUE_TYPE]],
|
self: ObjectVar[Dict[Any, VALUE_TYPE]],
|
||||||
) -> ArrayVar[List[Tuple[str, VALUE_TYPE]]]: ...
|
) -> ArrayVar[List[Tuple[str, VALUE_TYPE]]]: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
@ -133,47 +133,47 @@ class ObjectVar(Var[OBJECT_TYPE], python_types=dict):
|
|||||||
# NoReturn is used here to catch when key value is Any
|
# NoReturn is used here to catch when key value is Any
|
||||||
@overload
|
@overload
|
||||||
def __getitem__(
|
def __getitem__(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, NoReturn]],
|
self: ObjectVar[Dict[Any, NoReturn]],
|
||||||
key: Var | Any,
|
key: Var | Any,
|
||||||
) -> Var: ...
|
) -> Var: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getitem__(
|
def __getitem__(
|
||||||
self: (
|
self: (
|
||||||
ObjectVar[Dict[KEY_TYPE, int]]
|
ObjectVar[Dict[Any, int]]
|
||||||
| ObjectVar[Dict[KEY_TYPE, float]]
|
| ObjectVar[Dict[Any, float]]
|
||||||
| ObjectVar[Dict[KEY_TYPE, int | float]]
|
| ObjectVar[Dict[Any, int | float]]
|
||||||
),
|
),
|
||||||
key: Var | Any,
|
key: Var | Any,
|
||||||
) -> NumberVar: ...
|
) -> NumberVar: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getitem__(
|
def __getitem__(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, str]],
|
self: ObjectVar[Dict[Any, str]],
|
||||||
key: Var | Any,
|
key: Var | Any,
|
||||||
) -> StringVar: ...
|
) -> StringVar: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getitem__(
|
def __getitem__(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, list[ARRAY_INNER_TYPE]]],
|
self: ObjectVar[Dict[Any, list[ARRAY_INNER_TYPE]]],
|
||||||
key: Var | Any,
|
key: Var | Any,
|
||||||
) -> ArrayVar[list[ARRAY_INNER_TYPE]]: ...
|
) -> ArrayVar[list[ARRAY_INNER_TYPE]]: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getitem__(
|
def __getitem__(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, set[ARRAY_INNER_TYPE]]],
|
self: ObjectVar[Dict[Any, set[ARRAY_INNER_TYPE]]],
|
||||||
key: Var | Any,
|
key: Var | Any,
|
||||||
) -> ArrayVar[set[ARRAY_INNER_TYPE]]: ...
|
) -> ArrayVar[set[ARRAY_INNER_TYPE]]: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getitem__(
|
def __getitem__(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, tuple[ARRAY_INNER_TYPE, ...]]],
|
self: ObjectVar[Dict[Any, tuple[ARRAY_INNER_TYPE, ...]]],
|
||||||
key: Var | Any,
|
key: Var | Any,
|
||||||
) -> ArrayVar[tuple[ARRAY_INNER_TYPE, ...]]: ...
|
) -> ArrayVar[tuple[ARRAY_INNER_TYPE, ...]]: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getitem__(
|
def __getitem__(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, dict[OTHER_KEY_TYPE, VALUE_TYPE]]],
|
self: ObjectVar[Dict[Any, dict[OTHER_KEY_TYPE, VALUE_TYPE]]],
|
||||||
key: Var | Any,
|
key: Var | Any,
|
||||||
) -> ObjectVar[dict[OTHER_KEY_TYPE, VALUE_TYPE]]: ...
|
) -> ObjectVar[dict[OTHER_KEY_TYPE, VALUE_TYPE]]: ...
|
||||||
|
|
||||||
@ -195,50 +195,56 @@ class ObjectVar(Var[OBJECT_TYPE], python_types=dict):
|
|||||||
# NoReturn is used here to catch when key value is Any
|
# NoReturn is used here to catch when key value is Any
|
||||||
@overload
|
@overload
|
||||||
def __getattr__(
|
def __getattr__(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, NoReturn]],
|
self: ObjectVar[Dict[Any, NoReturn]],
|
||||||
name: str,
|
name: str,
|
||||||
) -> Var: ...
|
) -> Var: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getattr__(
|
def __getattr__(
|
||||||
self: (
|
self: (
|
||||||
ObjectVar[Dict[KEY_TYPE, int]]
|
ObjectVar[Dict[Any, int]]
|
||||||
| ObjectVar[Dict[KEY_TYPE, float]]
|
| ObjectVar[Dict[Any, float]]
|
||||||
| ObjectVar[Dict[KEY_TYPE, int | float]]
|
| ObjectVar[Dict[Any, int | float]]
|
||||||
),
|
),
|
||||||
name: str,
|
name: str,
|
||||||
) -> NumberVar: ...
|
) -> NumberVar: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getattr__(
|
def __getattr__(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, str]],
|
self: ObjectVar[Dict[Any, str]],
|
||||||
name: str,
|
name: str,
|
||||||
) -> StringVar: ...
|
) -> StringVar: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getattr__(
|
def __getattr__(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, list[ARRAY_INNER_TYPE]]],
|
self: ObjectVar[Dict[Any, list[ARRAY_INNER_TYPE]]],
|
||||||
name: str,
|
name: str,
|
||||||
) -> ArrayVar[list[ARRAY_INNER_TYPE]]: ...
|
) -> ArrayVar[list[ARRAY_INNER_TYPE]]: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getattr__(
|
def __getattr__(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, set[ARRAY_INNER_TYPE]]],
|
self: ObjectVar[Dict[Any, set[ARRAY_INNER_TYPE]]],
|
||||||
name: str,
|
name: str,
|
||||||
) -> ArrayVar[set[ARRAY_INNER_TYPE]]: ...
|
) -> ArrayVar[set[ARRAY_INNER_TYPE]]: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getattr__(
|
def __getattr__(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, tuple[ARRAY_INNER_TYPE, ...]]],
|
self: ObjectVar[Dict[Any, tuple[ARRAY_INNER_TYPE, ...]]],
|
||||||
name: str,
|
name: str,
|
||||||
) -> ArrayVar[tuple[ARRAY_INNER_TYPE, ...]]: ...
|
) -> ArrayVar[tuple[ARRAY_INNER_TYPE, ...]]: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getattr__(
|
def __getattr__(
|
||||||
self: ObjectVar[Dict[KEY_TYPE, dict[OTHER_KEY_TYPE, VALUE_TYPE]]],
|
self: ObjectVar[Dict[Any, dict[OTHER_KEY_TYPE, VALUE_TYPE]]],
|
||||||
name: str,
|
name: str,
|
||||||
) -> ObjectVar[dict[OTHER_KEY_TYPE, VALUE_TYPE]]: ...
|
) -> ObjectVar[dict[OTHER_KEY_TYPE, VALUE_TYPE]]: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def __getattr__(
|
||||||
|
self: ObjectVar,
|
||||||
|
name: str,
|
||||||
|
) -> ObjectItemOperation: ...
|
||||||
|
|
||||||
def __getattr__(self, name) -> Var:
|
def __getattr__(self, name) -> Var:
|
||||||
"""Get an attribute of the var.
|
"""Get an attribute of the var.
|
||||||
|
|
||||||
@ -377,8 +383,8 @@ class LiteralObjectVar(CachedVarOperation, ObjectVar[OBJECT_TYPE], LiteralVar):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def create(
|
def create(
|
||||||
cls,
|
cls,
|
||||||
_var_value: OBJECT_TYPE,
|
_var_value: dict,
|
||||||
_var_type: GenericType | None = None,
|
_var_type: Type[OBJECT_TYPE] | None = None,
|
||||||
_var_data: VarData | None = None,
|
_var_data: VarData | None = None,
|
||||||
) -> LiteralObjectVar[OBJECT_TYPE]:
|
) -> LiteralObjectVar[OBJECT_TYPE]:
|
||||||
"""Create the literal object var.
|
"""Create the literal object var.
|
||||||
|
@ -853,31 +853,31 @@ class ArrayVar(Var[ARRAY_VAR_TYPE], python_types=(list, tuple, set)):
|
|||||||
@overload
|
@overload
|
||||||
def __getitem__(
|
def __getitem__(
|
||||||
self: (
|
self: (
|
||||||
ArrayVar[Tuple[OTHER_TUPLE, int]]
|
ArrayVar[Tuple[Any, int]]
|
||||||
| ArrayVar[Tuple[OTHER_TUPLE, float]]
|
| ArrayVar[Tuple[Any, float]]
|
||||||
| ArrayVar[Tuple[OTHER_TUPLE, int | float]]
|
| ArrayVar[Tuple[Any, int | float]]
|
||||||
),
|
),
|
||||||
i: Literal[1, -1],
|
i: Literal[1, -1],
|
||||||
) -> NumberVar: ...
|
) -> NumberVar: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getitem__(
|
def __getitem__(
|
||||||
self: ArrayVar[Tuple[str, OTHER_TUPLE]], i: Literal[0, -2]
|
self: ArrayVar[Tuple[str, Any]], i: Literal[0, -2]
|
||||||
) -> StringVar: ...
|
) -> StringVar: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getitem__(
|
def __getitem__(
|
||||||
self: ArrayVar[Tuple[OTHER_TUPLE, str]], i: Literal[1, -1]
|
self: ArrayVar[Tuple[Any, str]], i: Literal[1, -1]
|
||||||
) -> StringVar: ...
|
) -> StringVar: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getitem__(
|
def __getitem__(
|
||||||
self: ArrayVar[Tuple[bool, OTHER_TUPLE]], i: Literal[0, -2]
|
self: ArrayVar[Tuple[bool, Any]], i: Literal[0, -2]
|
||||||
) -> BooleanVar: ...
|
) -> BooleanVar: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __getitem__(
|
def __getitem__(
|
||||||
self: ArrayVar[Tuple[OTHER_TUPLE, bool]], i: Literal[1, -1]
|
self: ArrayVar[Tuple[Any, bool]], i: Literal[1, -1]
|
||||||
) -> BooleanVar: ...
|
) -> BooleanVar: ...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
|
@ -6,6 +6,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from reflex.config import environment
|
||||||
from reflex.testing import AppHarness, AppHarnessProd
|
from reflex.testing import AppHarness, AppHarnessProd
|
||||||
|
|
||||||
DISPLAY = None
|
DISPLAY = None
|
||||||
@ -21,7 +22,7 @@ def xvfb():
|
|||||||
Yields:
|
Yields:
|
||||||
the pyvirtualdisplay object that the browser will be open on
|
the pyvirtualdisplay object that the browser will be open on
|
||||||
"""
|
"""
|
||||||
if os.environ.get("GITHUB_ACTIONS") and not os.environ.get("APP_HARNESS_HEADLESS"):
|
if os.environ.get("GITHUB_ACTIONS") and not environment.APP_HARNESS_HEADLESS.get():
|
||||||
from pyvirtualdisplay.smartdisplay import ( # pyright: ignore [reportMissingImports]
|
from pyvirtualdisplay.smartdisplay import ( # pyright: ignore [reportMissingImports]
|
||||||
SmartDisplay,
|
SmartDisplay,
|
||||||
)
|
)
|
||||||
@ -42,7 +43,7 @@ def pytest_exception_interact(node, call, report):
|
|||||||
call: The pytest call describing when/where the test was invoked.
|
call: The pytest call describing when/where the test was invoked.
|
||||||
report: The pytest log report object.
|
report: The pytest log report object.
|
||||||
"""
|
"""
|
||||||
screenshot_dir = os.environ.get("SCREENSHOT_DIR")
|
screenshot_dir = environment.SCREENSHOT_DIR.get()
|
||||||
if DISPLAY is None or screenshot_dir is None:
|
if DISPLAY is None or screenshot_dir is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@ import pytest
|
|||||||
import reflex as rx
|
import reflex as rx
|
||||||
import reflex.config
|
import reflex.config
|
||||||
from reflex.config import (
|
from reflex.config import (
|
||||||
|
EnvVar,
|
||||||
|
env_var,
|
||||||
environment,
|
environment,
|
||||||
interpret_boolean_env,
|
interpret_boolean_env,
|
||||||
interpret_enum_env,
|
interpret_enum_env,
|
||||||
@ -214,7 +216,7 @@ def test_replace_defaults(
|
|||||||
|
|
||||||
|
|
||||||
def reflex_dir_constant() -> Path:
|
def reflex_dir_constant() -> Path:
|
||||||
return environment.REFLEX_DIR
|
return environment.REFLEX_DIR.get()
|
||||||
|
|
||||||
|
|
||||||
def test_reflex_dir_env_var(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
def test_reflex_dir_env_var(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
|
||||||
@ -227,6 +229,7 @@ def test_reflex_dir_env_var(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) ->
|
|||||||
monkeypatch.setenv("REFLEX_DIR", str(tmp_path))
|
monkeypatch.setenv("REFLEX_DIR", str(tmp_path))
|
||||||
|
|
||||||
mp_ctx = multiprocessing.get_context(method="spawn")
|
mp_ctx = multiprocessing.get_context(method="spawn")
|
||||||
|
assert reflex_dir_constant() == tmp_path
|
||||||
with mp_ctx.Pool(processes=1) as pool:
|
with mp_ctx.Pool(processes=1) as pool:
|
||||||
assert pool.apply(reflex_dir_constant) == tmp_path
|
assert pool.apply(reflex_dir_constant) == tmp_path
|
||||||
|
|
||||||
@ -242,3 +245,38 @@ def test_interpret_int_env() -> None:
|
|||||||
@pytest.mark.parametrize("value, expected", [("true", True), ("false", False)])
|
@pytest.mark.parametrize("value, expected", [("true", True), ("false", False)])
|
||||||
def test_interpret_bool_env(value: str, expected: bool) -> None:
|
def test_interpret_bool_env(value: str, expected: bool) -> None:
|
||||||
assert interpret_boolean_env(value, "TELEMETRY_ENABLED") == expected
|
assert interpret_boolean_env(value, "TELEMETRY_ENABLED") == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_env_var():
|
||||||
|
class TestEnv:
|
||||||
|
BLUBB: EnvVar[str] = env_var("default")
|
||||||
|
INTERNAL: EnvVar[str] = env_var("default", internal=True)
|
||||||
|
BOOLEAN: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
|
assert TestEnv.BLUBB.get() == "default"
|
||||||
|
assert TestEnv.BLUBB.name == "BLUBB"
|
||||||
|
TestEnv.BLUBB.set("new")
|
||||||
|
assert os.environ.get("BLUBB") == "new"
|
||||||
|
assert TestEnv.BLUBB.get() == "new"
|
||||||
|
TestEnv.BLUBB.set(None)
|
||||||
|
assert "BLUBB" not in os.environ
|
||||||
|
|
||||||
|
assert TestEnv.INTERNAL.get() == "default"
|
||||||
|
assert TestEnv.INTERNAL.name == "__INTERNAL"
|
||||||
|
TestEnv.INTERNAL.set("new")
|
||||||
|
assert os.environ.get("__INTERNAL") == "new"
|
||||||
|
assert TestEnv.INTERNAL.get() == "new"
|
||||||
|
assert TestEnv.INTERNAL.getenv() == "new"
|
||||||
|
TestEnv.INTERNAL.set(None)
|
||||||
|
assert "__INTERNAL" not in os.environ
|
||||||
|
|
||||||
|
assert TestEnv.BOOLEAN.get() is False
|
||||||
|
assert TestEnv.BOOLEAN.name == "BOOLEAN"
|
||||||
|
TestEnv.BOOLEAN.set(True)
|
||||||
|
assert os.environ.get("BOOLEAN") == "True"
|
||||||
|
assert TestEnv.BOOLEAN.get() is True
|
||||||
|
TestEnv.BOOLEAN.set(False)
|
||||||
|
assert os.environ.get("BOOLEAN") == "False"
|
||||||
|
assert TestEnv.BOOLEAN.get() is False
|
||||||
|
TestEnv.BOOLEAN.set(None)
|
||||||
|
assert "BOOLEAN" not in os.environ
|
||||||
|
@ -45,7 +45,7 @@ from reflex.testing import chdir
|
|||||||
from reflex.utils import format, prerequisites, types
|
from reflex.utils import format, prerequisites, types
|
||||||
from reflex.utils.exceptions import SetUndefinedStateVarError
|
from reflex.utils.exceptions import SetUndefinedStateVarError
|
||||||
from reflex.utils.format import json_dumps
|
from reflex.utils.format import json_dumps
|
||||||
from reflex.vars.base import ComputedVar, Var
|
from reflex.vars.base import Var, computed_var
|
||||||
from tests.units.states.mutation import MutableSQLAModel, MutableTestState
|
from tests.units.states.mutation import MutableSQLAModel, MutableTestState
|
||||||
|
|
||||||
from .states import GenState
|
from .states import GenState
|
||||||
@ -109,7 +109,7 @@ class TestState(BaseState):
|
|||||||
_backend: int = 0
|
_backend: int = 0
|
||||||
asynctest: int = 0
|
asynctest: int = 0
|
||||||
|
|
||||||
@ComputedVar
|
@computed_var
|
||||||
def sum(self) -> float:
|
def sum(self) -> float:
|
||||||
"""Dynamically sum the numbers.
|
"""Dynamically sum the numbers.
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ class TestState(BaseState):
|
|||||||
"""
|
"""
|
||||||
return self.num1 + self.num2
|
return self.num1 + self.num2
|
||||||
|
|
||||||
@ComputedVar
|
@computed_var
|
||||||
def upper(self) -> str:
|
def upper(self) -> str:
|
||||||
"""Uppercase the key.
|
"""Uppercase the key.
|
||||||
|
|
||||||
@ -1124,7 +1124,7 @@ def test_child_state():
|
|||||||
v: int = 2
|
v: int = 2
|
||||||
|
|
||||||
class ChildState(MainState):
|
class ChildState(MainState):
|
||||||
@ComputedVar
|
@computed_var
|
||||||
def rendered_var(self):
|
def rendered_var(self):
|
||||||
return self.v
|
return self.v
|
||||||
|
|
||||||
@ -1143,7 +1143,7 @@ def test_conditional_computed_vars():
|
|||||||
t1: str = "a"
|
t1: str = "a"
|
||||||
t2: str = "b"
|
t2: str = "b"
|
||||||
|
|
||||||
@ComputedVar
|
@computed_var
|
||||||
def rendered_var(self) -> str:
|
def rendered_var(self) -> str:
|
||||||
if self.flag:
|
if self.flag:
|
||||||
return self.t1
|
return self.t1
|
||||||
@ -3095,12 +3095,12 @@ def test_potentially_dirty_substates():
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
class State(RxState):
|
class State(RxState):
|
||||||
@ComputedVar
|
@computed_var
|
||||||
def foo(self) -> str:
|
def foo(self) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
class C1(State):
|
class C1(State):
|
||||||
@ComputedVar
|
@computed_var
|
||||||
def bar(self) -> str:
|
def bar(self) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ from packaging import version
|
|||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.base import Base
|
from reflex.base import Base
|
||||||
|
from reflex.config import environment
|
||||||
from reflex.event import EventHandler
|
from reflex.event import EventHandler
|
||||||
from reflex.state import BaseState
|
from reflex.state import BaseState
|
||||||
from reflex.utils import (
|
from reflex.utils import (
|
||||||
@ -593,3 +594,11 @@ def test_style_prop_with_event_handler_value(callable):
|
|||||||
rx.box(
|
rx.box(
|
||||||
style=style, # type: ignore
|
style=style, # type: ignore
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_prod_mode() -> None:
|
||||||
|
"""Test that the prod mode is correctly determined."""
|
||||||
|
environment.REFLEX_ENV_MODE.set(constants.Env.PROD)
|
||||||
|
assert utils_exec.is_prod_mode()
|
||||||
|
environment.REFLEX_ENV_MODE.set(None)
|
||||||
|
assert not utils_exec.is_prod_mode()
|
||||||
|
102
tests/units/vars/test_object.py
Normal file
102
tests/units/vars/test_object.py
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import pytest
|
||||||
|
from typing_extensions import assert_type
|
||||||
|
|
||||||
|
import reflex as rx
|
||||||
|
from reflex.utils.types import GenericType
|
||||||
|
from reflex.vars.base import Var
|
||||||
|
from reflex.vars.object import LiteralObjectVar, ObjectVar
|
||||||
|
|
||||||
|
|
||||||
|
class Bare:
|
||||||
|
"""A bare class with a single attribute."""
|
||||||
|
|
||||||
|
quantity: int = 0
|
||||||
|
|
||||||
|
|
||||||
|
@rx.serializer
|
||||||
|
def serialize_bare(obj: Bare) -> dict:
|
||||||
|
"""A serializer for the bare class.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
obj: The object to serialize.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A dictionary with the quantity attribute.
|
||||||
|
"""
|
||||||
|
return {"quantity": obj.quantity}
|
||||||
|
|
||||||
|
|
||||||
|
class Base(rx.Base):
|
||||||
|
"""A reflex base class with a single attribute."""
|
||||||
|
|
||||||
|
quantity: int = 0
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectState(rx.State):
|
||||||
|
"""A reflex state with bare and base objects."""
|
||||||
|
|
||||||
|
bare: rx.Field[Bare] = rx.field(Bare())
|
||||||
|
base: rx.Field[Base] = rx.field(Base())
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("type_", [Base, Bare])
|
||||||
|
def test_var_create(type_: GenericType) -> None:
|
||||||
|
my_object = type_()
|
||||||
|
var = Var.create(my_object)
|
||||||
|
assert var._var_type is type_
|
||||||
|
|
||||||
|
quantity = var.quantity
|
||||||
|
assert quantity._var_type is int
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("type_", [Base, Bare])
|
||||||
|
def test_literal_create(type_: GenericType) -> None:
|
||||||
|
my_object = type_()
|
||||||
|
var = LiteralObjectVar.create(my_object)
|
||||||
|
assert var._var_type is type_
|
||||||
|
|
||||||
|
quantity = var.quantity
|
||||||
|
assert quantity._var_type is int
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("type_", [Base, Bare])
|
||||||
|
def test_guess(type_: GenericType) -> None:
|
||||||
|
my_object = type_()
|
||||||
|
var = Var.create(my_object)
|
||||||
|
var = var.guess_type()
|
||||||
|
assert var._var_type is type_
|
||||||
|
|
||||||
|
quantity = var.quantity
|
||||||
|
assert quantity._var_type is int
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("type_", [Base, Bare])
|
||||||
|
def test_state(type_: GenericType) -> None:
|
||||||
|
attr_name = type_.__name__.lower()
|
||||||
|
var = getattr(ObjectState, attr_name)
|
||||||
|
assert var._var_type is type_
|
||||||
|
|
||||||
|
quantity = var.quantity
|
||||||
|
assert quantity._var_type is int
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("type_", [Base, Bare])
|
||||||
|
def test_state_to_operation(type_: GenericType) -> None:
|
||||||
|
attr_name = type_.__name__.lower()
|
||||||
|
original_var = getattr(ObjectState, attr_name)
|
||||||
|
|
||||||
|
var = original_var.to(ObjectVar, type_)
|
||||||
|
assert var._var_type is type_
|
||||||
|
|
||||||
|
var = original_var.to(ObjectVar)
|
||||||
|
assert var._var_type is type_
|
||||||
|
|
||||||
|
|
||||||
|
def test_typing() -> None:
|
||||||
|
# Bare
|
||||||
|
var = ObjectState.bare.to(ObjectVar)
|
||||||
|
_ = assert_type(var, ObjectVar[Bare])
|
||||||
|
|
||||||
|
# Base
|
||||||
|
var = ObjectState.base
|
||||||
|
_ = assert_type(var, ObjectVar[Base])
|
Loading…
Reference in New Issue
Block a user