Add serializers for different var types (#1816)
This commit is contained in:
parent
74d227d2fd
commit
1938a6cc58
234
poetry.lock
generated
234
poetry.lock
generated
@ -1,14 +1,14 @@
|
||||
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "alembic"
|
||||
version = "1.11.1"
|
||||
version = "1.12.0"
|
||||
description = "A database migration tool for SQLAlchemy."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "alembic-1.11.1-py3-none-any.whl", hash = "sha256:dc871798a601fab38332e38d6ddb38d5e734f60034baeb8e2db5b642fccd8ab8"},
|
||||
{file = "alembic-1.11.1.tar.gz", hash = "sha256:6a810a6b012c88b33458fceb869aef09ac75d6ace5291915ba7fae44de372c01"},
|
||||
{file = "alembic-1.12.0-py3-none-any.whl", hash = "sha256:03226222f1cf943deee6c85d9464261a6c710cd19b4fe867a3ad1f25afda610f"},
|
||||
{file = "alembic-1.12.0.tar.gz", hash = "sha256:8e7645c32e4f200675e69f0745415335eb59a3663f5feb487abfa0b30c45888b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -45,13 +45,13 @@ trio = ["trio (<0.22)"]
|
||||
|
||||
[[package]]
|
||||
name = "async-timeout"
|
||||
version = "4.0.2"
|
||||
version = "4.0.3"
|
||||
description = "Timeout context manager for asyncio programs"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"},
|
||||
{file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"},
|
||||
{file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"},
|
||||
{file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -230,24 +230,24 @@ pycparser = "*"
|
||||
|
||||
[[package]]
|
||||
name = "cfgv"
|
||||
version = "3.3.1"
|
||||
version = "3.4.0"
|
||||
description = "Validate configuration and produce human readable error messages."
|
||||
optional = false
|
||||
python-versions = ">=3.6.1"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
|
||||
{file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
|
||||
{file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"},
|
||||
{file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.6"
|
||||
version = "8.1.7"
|
||||
description = "Composable command line interface toolkit"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "click-8.1.6-py3-none-any.whl", hash = "sha256:fa244bb30b3b5ee2cae3da8f55c9e5e0c0e86093306301fb418eb9dc40fbded5"},
|
||||
{file = "click-8.1.6.tar.gz", hash = "sha256:48ee849951919527a045bfe3bf7baa8a959c423134e1a5b98c05c20ba75a1cbd"},
|
||||
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
|
||||
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -386,13 +386,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
description = "Backport of PEP 654 (exception groups)"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"},
|
||||
{file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"},
|
||||
{file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"},
|
||||
{file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@ -421,18 +421,19 @@ test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6
|
||||
|
||||
[[package]]
|
||||
name = "filelock"
|
||||
version = "3.12.2"
|
||||
version = "3.12.4"
|
||||
description = "A platform independent file lock."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"},
|
||||
{file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"},
|
||||
{file = "filelock-3.12.4-py3-none-any.whl", hash = "sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4"},
|
||||
{file = "filelock-3.12.4.tar.gz", hash = "sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
|
||||
testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"]
|
||||
docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"]
|
||||
testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"]
|
||||
typing = ["typing-extensions (>=4.7.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "greenlet"
|
||||
@ -587,13 +588,13 @@ socks = ["socksio (==1.*)"]
|
||||
|
||||
[[package]]
|
||||
name = "identify"
|
||||
version = "2.5.26"
|
||||
version = "2.5.29"
|
||||
description = "File identification library for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "identify-2.5.26-py2.py3-none-any.whl", hash = "sha256:c22a8ead0d4ca11f1edd6c9418c3220669b3b7533ada0a0ffa6cc0ef85cf9b54"},
|
||||
{file = "identify-2.5.26.tar.gz", hash = "sha256:7243800bce2f58404ed41b7c002e53d4d22bcf3ae1b7900c2d7aefd95394bf7f"},
|
||||
{file = "identify-2.5.29-py2.py3-none-any.whl", hash = "sha256:24437fbf6f4d3fe6efd0eb9d67e24dd9106db99af5ceb27996a5f7895f24bf1b"},
|
||||
{file = "identify-2.5.29.tar.gz", hash = "sha256:d43d52b86b15918c137e3a74fff5224f60385cd0e9c38e99d07c257f02f151a5"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@ -1032,8 +1033,8 @@ files = [
|
||||
[package.dependencies]
|
||||
numpy = [
|
||||
{version = ">=1.20.3", markers = "python_version < \"3.10\""},
|
||||
{version = ">=1.21.0", markers = "python_version >= \"3.10\""},
|
||||
{version = ">=1.23.2", markers = "python_version >= \"3.11\""},
|
||||
{version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""},
|
||||
]
|
||||
python-dateutil = ">=2.8.1"
|
||||
pytz = ">=2020.1"
|
||||
@ -1052,6 +1053,73 @@ files = [
|
||||
{file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
version = "10.0.1"
|
||||
description = "Python Imaging Library (Fork)"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "Pillow-10.0.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:8f06be50669087250f319b706decf69ca71fdecd829091a37cc89398ca4dc17a"},
|
||||
{file = "Pillow-10.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50bd5f1ebafe9362ad622072a1d2f5850ecfa44303531ff14353a4059113b12d"},
|
||||
{file = "Pillow-10.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6a90167bcca1216606223a05e2cf991bb25b14695c518bc65639463d7db722d"},
|
||||
{file = "Pillow-10.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f11c9102c56ffb9ca87134bd025a43d2aba3f1155f508eff88f694b33a9c6d19"},
|
||||
{file = "Pillow-10.0.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:186f7e04248103482ea6354af6d5bcedb62941ee08f7f788a1c7707bc720c66f"},
|
||||
{file = "Pillow-10.0.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:0462b1496505a3462d0f35dc1c4d7b54069747d65d00ef48e736acda2c8cbdff"},
|
||||
{file = "Pillow-10.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d889b53ae2f030f756e61a7bff13684dcd77e9af8b10c6048fb2c559d6ed6eaf"},
|
||||
{file = "Pillow-10.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:552912dbca585b74d75279a7570dd29fa43b6d93594abb494ebb31ac19ace6bd"},
|
||||
{file = "Pillow-10.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:787bb0169d2385a798888e1122c980c6eff26bf941a8ea79747d35d8f9210ca0"},
|
||||
{file = "Pillow-10.0.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:fd2a5403a75b54661182b75ec6132437a181209b901446ee5724b589af8edef1"},
|
||||
{file = "Pillow-10.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2d7e91b4379f7a76b31c2dda84ab9e20c6220488e50f7822e59dac36b0cd92b1"},
|
||||
{file = "Pillow-10.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19e9adb3f22d4c416e7cd79b01375b17159d6990003633ff1d8377e21b7f1b21"},
|
||||
{file = "Pillow-10.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93139acd8109edcdeffd85e3af8ae7d88b258b3a1e13a038f542b79b6d255c54"},
|
||||
{file = "Pillow-10.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:92a23b0431941a33242b1f0ce6c88a952e09feeea9af4e8be48236a68ffe2205"},
|
||||
{file = "Pillow-10.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cbe68deb8580462ca0d9eb56a81912f59eb4542e1ef8f987405e35a0179f4ea2"},
|
||||
{file = "Pillow-10.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:522ff4ac3aaf839242c6f4e5b406634bfea002469656ae8358644fc6c4856a3b"},
|
||||
{file = "Pillow-10.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:84efb46e8d881bb06b35d1d541aa87f574b58e87f781cbba8d200daa835b42e1"},
|
||||
{file = "Pillow-10.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:898f1d306298ff40dc1b9ca24824f0488f6f039bc0e25cfb549d3195ffa17088"},
|
||||
{file = "Pillow-10.0.1-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:bcf1207e2f2385a576832af02702de104be71301c2696d0012b1b93fe34aaa5b"},
|
||||
{file = "Pillow-10.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d6c9049c6274c1bb565021367431ad04481ebb54872edecfcd6088d27edd6ed"},
|
||||
{file = "Pillow-10.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28444cb6ad49726127d6b340217f0627abc8732f1194fd5352dec5e6a0105635"},
|
||||
{file = "Pillow-10.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de596695a75496deb3b499c8c4f8e60376e0516e1a774e7bc046f0f48cd620ad"},
|
||||
{file = "Pillow-10.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:2872f2d7846cf39b3dbff64bc1104cc48c76145854256451d33c5faa55c04d1a"},
|
||||
{file = "Pillow-10.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4ce90f8a24e1c15465048959f1e94309dfef93af272633e8f37361b824532e91"},
|
||||
{file = "Pillow-10.0.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ee7810cf7c83fa227ba9125de6084e5e8b08c59038a7b2c9045ef4dde61663b4"},
|
||||
{file = "Pillow-10.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b1be1c872b9b5fcc229adeadbeb51422a9633abd847c0ff87dc4ef9bb184ae08"},
|
||||
{file = "Pillow-10.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:98533fd7fa764e5f85eebe56c8e4094db912ccbe6fbf3a58778d543cadd0db08"},
|
||||
{file = "Pillow-10.0.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:764d2c0daf9c4d40ad12fbc0abd5da3af7f8aa11daf87e4fa1b834000f4b6b0a"},
|
||||
{file = "Pillow-10.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fcb59711009b0168d6ee0bd8fb5eb259c4ab1717b2f538bbf36bacf207ef7a68"},
|
||||
{file = "Pillow-10.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:697a06bdcedd473b35e50a7e7506b1d8ceb832dc238a336bd6f4f5aa91a4b500"},
|
||||
{file = "Pillow-10.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f665d1e6474af9f9da5e86c2a3a2d2d6204e04d5af9c06b9d42afa6ebde3f21"},
|
||||
{file = "Pillow-10.0.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:2fa6dd2661838c66f1a5473f3b49ab610c98a128fc08afbe81b91a1f0bf8c51d"},
|
||||
{file = "Pillow-10.0.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:3a04359f308ebee571a3127fdb1bd01f88ba6f6fb6d087f8dd2e0d9bff43f2a7"},
|
||||
{file = "Pillow-10.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:723bd25051454cea9990203405fa6b74e043ea76d4968166dfd2569b0210886a"},
|
||||
{file = "Pillow-10.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:71671503e3015da1b50bd18951e2f9daf5b6ffe36d16f1eb2c45711a301521a7"},
|
||||
{file = "Pillow-10.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:44e7e4587392953e5e251190a964675f61e4dae88d1e6edbe9f36d6243547ff3"},
|
||||
{file = "Pillow-10.0.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:3855447d98cced8670aaa63683808df905e956f00348732448b5a6df67ee5849"},
|
||||
{file = "Pillow-10.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ed2d9c0704f2dc4fa980b99d565c0c9a543fe5101c25b3d60488b8ba80f0cce1"},
|
||||
{file = "Pillow-10.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5bb289bb835f9fe1a1e9300d011eef4d69661bb9b34d5e196e5e82c4cb09b37"},
|
||||
{file = "Pillow-10.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0d3e54ab1df9df51b914b2233cf779a5a10dfd1ce339d0421748232cea9876"},
|
||||
{file = "Pillow-10.0.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:2cc6b86ece42a11f16f55fe8903595eff2b25e0358dec635d0a701ac9586588f"},
|
||||
{file = "Pillow-10.0.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:ca26ba5767888c84bf5a0c1a32f069e8204ce8c21d00a49c90dabeba00ce0145"},
|
||||
{file = "Pillow-10.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f0b4b06da13275bc02adfeb82643c4a6385bd08d26f03068c2796f60d125f6f2"},
|
||||
{file = "Pillow-10.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bc2e3069569ea9dbe88d6b8ea38f439a6aad8f6e7a6283a38edf61ddefb3a9bf"},
|
||||
{file = "Pillow-10.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:8b451d6ead6e3500b6ce5c7916a43d8d8d25ad74b9102a629baccc0808c54971"},
|
||||
{file = "Pillow-10.0.1-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:32bec7423cdf25c9038fef614a853c9d25c07590e1a870ed471f47fb80b244db"},
|
||||
{file = "Pillow-10.0.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7cf63d2c6928b51d35dfdbda6f2c1fddbe51a6bc4a9d4ee6ea0e11670dd981e"},
|
||||
{file = "Pillow-10.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f6d3d4c905e26354e8f9d82548475c46d8e0889538cb0657aa9c6f0872a37aa4"},
|
||||
{file = "Pillow-10.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:847e8d1017c741c735d3cd1883fa7b03ded4f825a6e5fcb9378fd813edee995f"},
|
||||
{file = "Pillow-10.0.1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:7f771e7219ff04b79e231d099c0a28ed83aa82af91fd5fa9fdb28f5b8d5addaf"},
|
||||
{file = "Pillow-10.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459307cacdd4138edee3875bbe22a2492519e060660eaf378ba3b405d1c66317"},
|
||||
{file = "Pillow-10.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b059ac2c4c7a97daafa7dc850b43b2d3667def858a4f112d1aa082e5c3d6cf7d"},
|
||||
{file = "Pillow-10.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6caf3cd38449ec3cd8a68b375e0c6fe4b6fd04edb6c9766b55ef84a6e8ddf2d"},
|
||||
{file = "Pillow-10.0.1.tar.gz", hash = "sha256:d72967b06be9300fed5cfbc8b5bafceec48bf7cdc7dab66b1d2549035287191d"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"]
|
||||
tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "3.10.0"
|
||||
@ -1072,13 +1140,13 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co
|
||||
|
||||
[[package]]
|
||||
name = "plotly"
|
||||
version = "5.15.0"
|
||||
version = "5.17.0"
|
||||
description = "An open-source, interactive data visualization library for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "plotly-5.15.0-py2.py3-none-any.whl", hash = "sha256:3508876bbd6aefb8a692c21a7128ca87ce42498dd041efa5c933ee44b55aab24"},
|
||||
{file = "plotly-5.15.0.tar.gz", hash = "sha256:822eabe53997d5ebf23c77e1d1fcbf3bb6aa745eb05d532afd4b6f9a2e2ab02f"},
|
||||
{file = "plotly-5.17.0-py2.py3-none-any.whl", hash = "sha256:7c84cdf11da162423da957bb093287134f2d6f170eb9a74f1459f825892247c3"},
|
||||
{file = "plotly-5.17.0.tar.gz", hash = "sha256:290d796bf7bab87aad184fe24b86096234c4c95dcca6ecbca02d02bdf17d3d97"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1105,13 +1173,13 @@ testing = ["pytest", "pytest-benchmark"]
|
||||
|
||||
[[package]]
|
||||
name = "pre-commit"
|
||||
version = "3.3.3"
|
||||
version = "3.4.0"
|
||||
description = "A framework for managing and maintaining multi-language pre-commit hooks."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pre_commit-3.3.3-py2.py3-none-any.whl", hash = "sha256:10badb65d6a38caff29703362271d7dca483d01da88f9d7e05d0b97171c136cb"},
|
||||
{file = "pre_commit-3.3.3.tar.gz", hash = "sha256:a2256f489cd913d575c145132ae196fe335da32d91a8294b7afe6622335dd023"},
|
||||
{file = "pre_commit-3.4.0-py2.py3-none-any.whl", hash = "sha256:96d529a951f8b677f730a7212442027e8ba53f9b04d217c4c67dc56c393ad945"},
|
||||
{file = "pre_commit-3.4.0.tar.gz", hash = "sha256:6bbd5129a64cad4c0dfaeeb12cd8f7ea7e15b77028d985341478c8af3c759522"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1212,13 +1280,13 @@ email = ["email-validator (>=1.0.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.15.1"
|
||||
version = "2.16.1"
|
||||
description = "Pygments is a syntax highlighting package written in Python."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"},
|
||||
{file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"},
|
||||
{file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"},
|
||||
{file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@ -1226,13 +1294,13 @@ plugins = ["importlib-metadata"]
|
||||
|
||||
[[package]]
|
||||
name = "pyright"
|
||||
version = "1.1.318"
|
||||
version = "1.1.327"
|
||||
description = "Command line wrapper for pyright"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pyright-1.1.318-py3-none-any.whl", hash = "sha256:056c1b2e711c3526e32919de1684ae599d34b7ec27e94398858a43f56ac9ba9b"},
|
||||
{file = "pyright-1.1.318.tar.gz", hash = "sha256:69dcf9c32d5be27d531750de627e76a7cadc741d333b547c09044278b508db7b"},
|
||||
{file = "pyright-1.1.327-py3-none-any.whl", hash = "sha256:3462cda239e9140276238bbdbd0b59d77406f1c2e14d8cb8c20c8e25639c6b3c"},
|
||||
{file = "pyright-1.1.327.tar.gz", hash = "sha256:ba74148ad64f22020dbbed6781c4bdb38ecb8a7ca90dc3c87a4f08d1c0e11592"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1257,13 +1325,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "7.4.0"
|
||||
version = "7.4.2"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"},
|
||||
{file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"},
|
||||
{file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"},
|
||||
{file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1348,15 +1416,18 @@ six = ">=1.5"
|
||||
|
||||
[[package]]
|
||||
name = "python-engineio"
|
||||
version = "4.5.1"
|
||||
version = "4.7.1"
|
||||
description = "Engine.IO server and client for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "python-engineio-4.5.1.tar.gz", hash = "sha256:b167a1b208fcdce5dbe96a61a6ca22391cfa6715d796c22de93e3adf9c07ae0c"},
|
||||
{file = "python_engineio-4.5.1-py3-none-any.whl", hash = "sha256:67a675569f3e9bb274a8077f3c2068a8fe79cbfcb111cf31ca27b968484fe6c7"},
|
||||
{file = "python-engineio-4.7.1.tar.gz", hash = "sha256:a8422e345cd9a21451303380b160742ff02197975b1c3a02cef115febe2b1b20"},
|
||||
{file = "python_engineio-4.7.1-py3-none-any.whl", hash = "sha256:52499e8ab94fea1a6525ffe872fe7028d04b575799c5fa8e2cf7880e032de42e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
simple-websocket = ">=0.10.0"
|
||||
|
||||
[package.extras]
|
||||
asyncio-client = ["aiohttp (>=3.4)"]
|
||||
client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"]
|
||||
@ -1377,32 +1448,33 @@ six = ">=1.4.0"
|
||||
|
||||
[[package]]
|
||||
name = "python-socketio"
|
||||
version = "5.8.0"
|
||||
version = "5.9.0"
|
||||
description = "Socket.IO server and client for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "python-socketio-5.8.0.tar.gz", hash = "sha256:e714f4dddfaaa0cb0e37a1e2deef2bb60590a5b9fea9c343dd8ca5e688416fd9"},
|
||||
{file = "python_socketio-5.8.0-py3-none-any.whl", hash = "sha256:7adb8867aac1c2929b9c1429f1c02e12ca4c36b67c807967393e367dfbb01441"},
|
||||
{file = "python-socketio-5.9.0.tar.gz", hash = "sha256:dc42735f65534187f381fde291ebf620216a4960001370f32de940229b2e7f8f"},
|
||||
{file = "python_socketio-5.9.0-py3-none-any.whl", hash = "sha256:c20f12e4ed0cba57581af26bbeea9998bc2eeebb3b952fa92493a1e051cfe9dc"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
bidict = ">=0.21.0"
|
||||
python-engineio = ">=4.3.0"
|
||||
python-engineio = ">=4.7.0"
|
||||
|
||||
[package.extras]
|
||||
asyncio-client = ["aiohttp (>=3.4)"]
|
||||
client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"]
|
||||
docs = ["sphinx"]
|
||||
|
||||
[[package]]
|
||||
name = "pytz"
|
||||
version = "2023.3"
|
||||
version = "2023.3.post1"
|
||||
description = "World timezone definitions, modern and historical"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"},
|
||||
{file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"},
|
||||
{file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"},
|
||||
{file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1417,6 +1489,7 @@ files = [
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
|
||||
{file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
|
||||
@ -1424,8 +1497,15 @@ files = [
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
|
||||
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
||||
{file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
|
||||
{file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
|
||||
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
|
||||
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
|
||||
@ -1442,6 +1522,7 @@ files = [
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
|
||||
{file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
|
||||
@ -1449,6 +1530,7 @@ files = [
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
|
||||
{file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
|
||||
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
|
||||
@ -1476,13 +1558,13 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "13.5.1"
|
||||
version = "13.5.2"
|
||||
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "rich-13.5.1-py3-none-any.whl", hash = "sha256:b97381b204a206e1be618f5e1215a57174a1a7732490b3bf6668cf41d30bc72d"},
|
||||
{file = "rich-13.5.1.tar.gz", hash = "sha256:881653ee7037803559d8eae98f145e0a4c4b0ec3ff0300d2cc8d479c71fc6819"},
|
||||
{file = "rich-13.5.2-py3-none-any.whl", hash = "sha256:146a90b3b6b47cac4a73c12866a499e9817426423f57c5a66949c086191a8808"},
|
||||
{file = "rich-13.5.2.tar.gz", hash = "sha256:fb9d6c0a0f643c99eed3875b5377a184132ba9be4d61516a55273d3554d75a39"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1551,6 +1633,20 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-g
|
||||
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
|
||||
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
|
||||
|
||||
[[package]]
|
||||
name = "simple-websocket"
|
||||
version = "0.10.1"
|
||||
description = "Simple WebSocket server and client for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "simple-websocket-0.10.1.tar.gz", hash = "sha256:0ab46c8ffa51a46dc95eed94608b3b722841c0bf849def71d465c5c356679c82"},
|
||||
{file = "simple_websocket-0.10.1-py3-none-any.whl", hash = "sha256:62c36bacfd75cc867927bb39d91951342a7234bdfe20f41dd969a3b8bb1413b7"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
wsproto = "*"
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
@ -1635,7 +1731,7 @@ files = [
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\")"}
|
||||
greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"}
|
||||
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
|
||||
|
||||
[package.extras]
|
||||
@ -1731,13 +1827,13 @@ test = ["aiomysql (>=0.1.1,<0.2.0)", "aiosqlite (>=0.17.0,<0.20.0)", "arrow (>=1
|
||||
|
||||
[[package]]
|
||||
name = "tenacity"
|
||||
version = "8.2.2"
|
||||
version = "8.2.3"
|
||||
description = "Retry code until it succeeds"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "tenacity-8.2.2-py3-none-any.whl", hash = "sha256:2f277afb21b851637e8f52e6a613ff08734c347dc19ade928e519d7d2d8569b0"},
|
||||
{file = "tenacity-8.2.2.tar.gz", hash = "sha256:43af037822bd0029025877f3b2d97cc4d7bb0c2991000a3d59d71517c5c969e0"},
|
||||
{file = "tenacity-8.2.3-py3-none-any.whl", hash = "sha256:ce510e327a630c9e1beaf17d42e6ffacc88185044ad85cf74c0a8887c6a0f88c"},
|
||||
{file = "tenacity-8.2.3.tar.gz", hash = "sha256:5398ef0d78e63f40007c1fb4c0bff96e1911394d2fa8d194f77619c05ff6cc8a"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@ -1787,13 +1883,13 @@ sortedcontainers = "*"
|
||||
|
||||
[[package]]
|
||||
name = "trio-websocket"
|
||||
version = "0.10.3"
|
||||
version = "0.10.4"
|
||||
description = "WebSocket library for Trio"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "trio-websocket-0.10.3.tar.gz", hash = "sha256:1a748604ad906a7dcab9a43c6eb5681e37de4793ba0847ef0bc9486933ed027b"},
|
||||
{file = "trio_websocket-0.10.3-py3-none-any.whl", hash = "sha256:a9937d48e8132ebf833019efde2a52ca82d223a30a7ea3e8d60a7d28f75a4e3a"},
|
||||
{file = "trio-websocket-0.10.4.tar.gz", hash = "sha256:e66b3db3e2453017431dfbd352081006654e1241c2a6800dc2f43d7df54d55c5"},
|
||||
{file = "trio_websocket-0.10.4-py3-none-any.whl", hash = "sha256:c7a620c4013c34b7e4477d89fe76695da1e455e4510a8d7ae13f81c632bdce1d"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1923,13 +2019,13 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)",
|
||||
|
||||
[[package]]
|
||||
name = "virtualenv"
|
||||
version = "20.24.2"
|
||||
version = "20.24.5"
|
||||
description = "Virtual Python Environment builder"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "virtualenv-20.24.2-py3-none-any.whl", hash = "sha256:43a3052be36080548bdee0b42919c88072037d50d56c28bd3f853cbe92b953ff"},
|
||||
{file = "virtualenv-20.24.2.tar.gz", hash = "sha256:fd8a78f46f6b99a67b7ec5cf73f92357891a7b3a40fd97637c27f854aae3b9e0"},
|
||||
{file = "virtualenv-20.24.5-py3-none-any.whl", hash = "sha256:b80039f280f4919c77b30f1c23294ae357c4c8701042086e3fc005963e4e537b"},
|
||||
{file = "virtualenv-20.24.5.tar.gz", hash = "sha256:e8361967f6da6fbdf1426483bfe9fca8287c242ac0bc30429905721cefbff752"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -1938,7 +2034,7 @@ filelock = ">=3.12.2,<4"
|
||||
platformdirs = ">=3.9.1,<4"
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
|
||||
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
|
||||
test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
|
||||
|
||||
[[package]]
|
||||
@ -2125,4 +2221,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.7"
|
||||
content-hash = "44cce3d4423be203bf6b1ddc046cbdd9061924523b86baea8a42cd954dc86b36"
|
||||
content-hash = "0dd6230851cc4f43e192e45431d1c1dcb451b7946ae7cd169e220e7f7a072aa2"
|
||||
|
@ -29,7 +29,6 @@ fastapi = "^0.96.0"
|
||||
gunicorn = "^20.1.0"
|
||||
httpx = "^0.24.0"
|
||||
jinja2 = "^3.1.2"
|
||||
plotly = "^5.13.0"
|
||||
psutil = "^5.9.4"
|
||||
pydantic = "^1.10.2"
|
||||
python-multipart = "^0.0.5"
|
||||
@ -63,6 +62,10 @@ pandas = [
|
||||
{version = "^1.5.3", python = ">=3.8,<4.0"},
|
||||
{version = "^1.1", python = ">=3.7, <3.8"}
|
||||
]
|
||||
pillow = [
|
||||
{version = "^10.0.0", python = ">=3.8,<4.0"}
|
||||
]
|
||||
plotly = "^5.13.0"
|
||||
asynctest = "^0.13.0"
|
||||
pre-commit = {version = "^3.2.1", python = ">=3.8,<4.0"}
|
||||
selenium = "^4.11.0"
|
||||
|
@ -1,10 +1,13 @@
|
||||
"""Table components."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Dict, List, Union
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.tags import Tag
|
||||
from reflex.utils import format, imports, types
|
||||
from reflex.utils import imports, types
|
||||
from reflex.utils.serializers import serialize, serializer
|
||||
from reflex.vars import BaseVar, ComputedVar, ImportVar, Var
|
||||
|
||||
|
||||
@ -106,23 +109,59 @@ class DataTable(Gridjs):
|
||||
)
|
||||
|
||||
def _render(self) -> Tag:
|
||||
if isinstance(self.data, Var):
|
||||
if types.is_dataframe(self.data.type_):
|
||||
self.columns = BaseVar(
|
||||
name=f"{self.data.name}.columns",
|
||||
type_=List[Any],
|
||||
state=self.data.state,
|
||||
)
|
||||
self.data = BaseVar(
|
||||
name=f"{self.data.name}.data",
|
||||
type_=List[List[Any]],
|
||||
state=self.data.state,
|
||||
)
|
||||
else:
|
||||
if isinstance(self.data, Var) and types.is_dataframe(self.data.type_):
|
||||
self.columns = BaseVar(
|
||||
name=f"{self.data.name}.columns",
|
||||
type_=List[Any],
|
||||
state=self.data.state,
|
||||
)
|
||||
self.data = BaseVar(
|
||||
name=f"{self.data.name}.data",
|
||||
type_=List[List[Any]],
|
||||
state=self.data.state,
|
||||
)
|
||||
if types.is_dataframe(type(self.data)):
|
||||
# If given a pandas df break up the data and columns
|
||||
if types.is_dataframe(type(self.data)):
|
||||
self.columns = Var.create(list(self.data.columns.values.tolist())) # type: ignore
|
||||
self.data = Var.create(format.format_dataframe_values(self.data)) # type: ignore
|
||||
data = serialize(self.data)
|
||||
assert isinstance(data, dict), "Serialized dataframe should be a dict."
|
||||
self.columns = Var.create_safe(data["columns"])
|
||||
self.data = Var.create_safe(data["data"])
|
||||
|
||||
# Render the table.
|
||||
return super()._render()
|
||||
|
||||
|
||||
try:
|
||||
from pandas import DataFrame
|
||||
|
||||
def format_dataframe_values(df: DataFrame) -> List[List[Any]]:
|
||||
"""Format dataframe values to a list of lists.
|
||||
|
||||
Args:
|
||||
df: The dataframe to format.
|
||||
|
||||
Returns:
|
||||
The dataframe as a list of lists.
|
||||
"""
|
||||
return [
|
||||
[str(d) if isinstance(d, (list, tuple)) else d for d in data]
|
||||
for data in list(df.values.tolist())
|
||||
]
|
||||
|
||||
@serializer
|
||||
def serialize_dataframe(df: DataFrame) -> dict:
|
||||
"""Serialize a pandas dataframe.
|
||||
|
||||
Args:
|
||||
df: The dataframe to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized dataframe.
|
||||
"""
|
||||
return {
|
||||
"columns": df.columns.tolist(),
|
||||
"data": format_dataframe_values(df),
|
||||
}
|
||||
|
||||
except ImportError:
|
||||
pass
|
||||
|
@ -25,6 +25,7 @@ class Tabs(ChakraComponent):
|
||||
is_manual: If true, the tabs will be manually activated and display its panel by pressing Space or Enter. If false, the tabs will be automatically activated and their panel is displayed when they receive focus.
|
||||
orientation: The orientation of the tab list.
|
||||
variant: "line" | "enclosed" | "enclosed-colored" | "soft-rounded" | "solid-rounded" | "unstyled"
|
||||
color_scheme: The color scheme of the tabs.
|
||||
items: The items for the tabs component, a list of tuple (label, panel)
|
||||
**props: The properties of the component.
|
||||
|
||||
|
@ -13,7 +13,7 @@ from reflex.event import EventHandler, EventChain, EventSpec
|
||||
class Select(ChakraComponent):
|
||||
@overload
|
||||
@classmethod
|
||||
def create(cls, *children, value: Optional[Union[Var[str], str]] = None, default_value: Optional[Union[Var[str], str]] = None, placeholder: Optional[Union[Var[str], str]] = None, error_border_color: Optional[Union[Var[str], str]] = None, focus_border_color: Optional[Union[Var[str], str]] = None, is_disabled: Optional[Union[Var[bool], bool]] = None, is_invalid: Optional[Union[Var[bool], bool]] = None, is_read_only: Optional[Union[Var[bool], bool]] = None, is_required: Optional[Union[Var[bool], bool]] = None, variant: Optional[Union[Var[str], str]] = None, size: Optional[Union[Var[str], str]] = None, on_blur: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_change: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_context_menu: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_double_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_focus: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_down: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_enter: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_leave: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_move: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_out: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_over: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_up: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_scroll: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_unmount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, **props) -> "Select": # type: ignore
|
||||
def create(cls, *children, value: Optional[Union[Var[str], str]] = None, default_value: Optional[Union[Var[str], str]] = None, placeholder: Optional[Union[Var[str], str]] = None, error_border_color: Optional[Union[Var[str], str]] = None, focus_border_color: Optional[Union[Var[str], str]] = None, is_disabled: Optional[Union[Var[bool], bool]] = None, is_invalid: Optional[Union[Var[bool], bool]] = None, is_required: Optional[Union[Var[bool], bool]] = None, variant: Optional[Union[Var[str], str]] = None, size: Optional[Union[Var[str], str]] = None, on_blur: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_change: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_context_menu: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_double_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_focus: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_down: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_enter: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_leave: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_move: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_out: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_over: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_up: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_scroll: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_unmount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, **props) -> "Select": # type: ignore
|
||||
"""Create a select component.
|
||||
|
||||
If a list is provided as the first children, a default component
|
||||
@ -28,7 +28,6 @@ class Select(ChakraComponent):
|
||||
focus_border_color: The border color when the select is focused.
|
||||
is_disabled: If true, the select will be disabled.
|
||||
is_invalid: If true, the form control will be invalid. This has 2 side effects: - The FormLabel and FormErrorIcon will have `data-invalid` set to true - The form element (e.g, Input) will have `aria-invalid` set to true
|
||||
is_read_only: If true, the form control will be readonly
|
||||
is_required: If true, the form control will be required. This has 2 side effects: - The FormLabel will show a required indicator - The form element (e.g, Input) will have `aria-required` set to true
|
||||
variant: "outline" | "filled" | "flushed" | "unstyled"
|
||||
size: The size of the select.
|
||||
|
@ -1,13 +1,17 @@
|
||||
"""Component for displaying a plotly graph."""
|
||||
|
||||
from typing import Dict, List
|
||||
|
||||
from plotly.graph_objects import Figure
|
||||
import json
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from reflex.components.component import NoSSRComponent
|
||||
from reflex.components.tags import Tag
|
||||
from reflex.utils.serializers import serializer
|
||||
from reflex.vars import Var
|
||||
|
||||
try:
|
||||
from plotly.graph_objects import Figure
|
||||
except ImportError:
|
||||
Figure = Any
|
||||
|
||||
|
||||
class PlotlyLib(NoSSRComponent):
|
||||
"""A component that wraps a plotly lib."""
|
||||
@ -39,14 +43,22 @@ class Plotly(PlotlyLib):
|
||||
# If true, the graph will resize when the window is resized.
|
||||
use_resize_handler: Var[bool]
|
||||
|
||||
def _render(self) -> Tag:
|
||||
if (
|
||||
isinstance(self.data, Figure)
|
||||
and self.layout is None
|
||||
and self.width is not None
|
||||
):
|
||||
layout = Var.create({"width": self.width, "height": self.height})
|
||||
assert layout is not None
|
||||
self.layout = layout
|
||||
|
||||
return super()._render()
|
||||
try:
|
||||
from plotly.graph_objects import Figure
|
||||
from plotly.io import to_json
|
||||
|
||||
@serializer
|
||||
def serialize_figure(figure: Figure) -> list:
|
||||
"""Serialize a plotly figure.
|
||||
|
||||
Args:
|
||||
figure: The figure to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized figure.
|
||||
"""
|
||||
return json.loads(str(to_json(figure)))["data"]
|
||||
|
||||
except ImportError:
|
||||
pass
|
||||
|
@ -3,7 +3,7 @@
|
||||
# This file was generated by `scripts/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
|
||||
from typing import Dict, List, Optional, Union, overload
|
||||
from typing import Any, Dict, List, Optional, Union, overload
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.component import NoSSRComponent
|
||||
from reflex.vars import Var, BaseVar, ComputedVar
|
||||
@ -31,7 +31,7 @@ class PlotlyLib(NoSSRComponent):
|
||||
class Plotly(PlotlyLib):
|
||||
@overload
|
||||
@classmethod
|
||||
def create(cls, *children, data: Optional[Union[Var[Figure], Figure]] = None, layout: Optional[Union[Var[Dict], Dict]] = None, width: Optional[Union[Var[str], str]] = None, height: Optional[Union[Var[str], str]] = None, use_resize_handler: Optional[Union[Var[bool], bool]] = None, on_blur: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_context_menu: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_double_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_focus: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_down: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_enter: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_leave: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_move: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_out: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_over: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_up: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_scroll: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_unmount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, **props) -> "Plotly": # type: ignore
|
||||
def create(cls, *children, data: Optional[Union[Var[Any], Any]] = None, layout: Optional[Union[Var[Dict], Dict]] = None, width: Optional[Union[Var[str], str]] = None, height: Optional[Union[Var[str], str]] = None, use_resize_handler: Optional[Union[Var[bool], bool]] = None, on_blur: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_context_menu: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_double_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_focus: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_down: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_enter: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_leave: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_move: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_out: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_over: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_up: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_scroll: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_unmount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, **props) -> "Plotly": # type: ignore
|
||||
"""Create the component.
|
||||
|
||||
Args:
|
||||
|
@ -1,12 +1,14 @@
|
||||
"""An image component."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Optional, Set
|
||||
import base64
|
||||
import io
|
||||
from typing import Any, Optional
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.libs.chakra import ChakraComponent
|
||||
from reflex.components.tags import Tag
|
||||
from reflex.utils import format, types
|
||||
from reflex.utils.serializers import serializer
|
||||
from reflex.vars import Var
|
||||
|
||||
|
||||
@ -51,7 +53,7 @@ class Image(ChakraComponent):
|
||||
# Learn more _[here](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images)_
|
||||
src_set: Var[str]
|
||||
|
||||
def get_triggers(self) -> Set[str]:
|
||||
def get_triggers(self) -> set[str]:
|
||||
"""Get the event triggers for the component.
|
||||
|
||||
Returns:
|
||||
@ -60,9 +62,30 @@ class Image(ChakraComponent):
|
||||
return super().get_triggers() | {"on_error", "on_load"}
|
||||
|
||||
def _render(self) -> Tag:
|
||||
# If the src is an image, convert it to a base64 string.
|
||||
if types.is_image(type(self.src)):
|
||||
self.src = Var.create(format.format_image_data(self.src)) # type: ignore
|
||||
self.src.is_string = True
|
||||
|
||||
# Render the table.
|
||||
return super()._render()
|
||||
|
||||
|
||||
try:
|
||||
from PIL.Image import Image as Img
|
||||
|
||||
@serializer
|
||||
def serialize_image(image: Img) -> str:
|
||||
"""Serialize a plotly figure.
|
||||
|
||||
Args:
|
||||
image: The image to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized image.
|
||||
"""
|
||||
buff = io.BytesIO()
|
||||
image.save(buff, format="PNG")
|
||||
image_bytes = buff.getvalue()
|
||||
base64_image = base64.b64encode(image_bytes).decode("utf-8")
|
||||
return f"data:image/png;base64,{base64_image}"
|
||||
|
||||
except ImportError:
|
||||
pass
|
||||
|
@ -3,7 +3,7 @@
|
||||
# This file was generated by `scripts/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
|
||||
from typing import Any, Optional, Set, Union, overload
|
||||
from typing import Any, Optional, Union, overload
|
||||
from reflex.components.libs.chakra import ChakraComponent
|
||||
from reflex.components.component import Component
|
||||
from reflex.vars import Var, BaseVar, ComputedVar
|
||||
|
@ -197,6 +197,7 @@ class Model(Base, sqlmodel.SQLModel):
|
||||
target_metadata=sqlmodel.SQLModel.metadata,
|
||||
render_item=cls._alembic_render_item,
|
||||
process_revision_directives=writer, # type: ignore
|
||||
compare_type=False,
|
||||
)
|
||||
env.run_migrations()
|
||||
changes_detected = False
|
||||
|
@ -2,22 +2,16 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import os.path as op
|
||||
import re
|
||||
import sys
|
||||
import types as builtin_types
|
||||
from typing import TYPE_CHECKING, Any, Callable, Type, Union
|
||||
|
||||
import plotly.graph_objects as go
|
||||
from plotly.graph_objects import Figure
|
||||
from plotly.io import to_json
|
||||
from typing import TYPE_CHECKING, Any, Union
|
||||
|
||||
from reflex import constants
|
||||
from reflex.utils import exceptions, types
|
||||
from reflex.utils import exceptions, serializers, types
|
||||
from reflex.utils.serializers import serialize
|
||||
from reflex.vars import Var
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -316,12 +310,9 @@ def format_prop(
|
||||
return prop
|
||||
return json_dumps(prop)
|
||||
|
||||
elif isinstance(prop, Figure):
|
||||
prop = json.loads(to_json(prop))["data"] # type: ignore
|
||||
|
||||
# For dictionaries, convert any properties to strings.
|
||||
elif isinstance(prop, dict):
|
||||
prop = format_dict(prop)
|
||||
prop = serializers.serialize_dict(prop) # type: ignore
|
||||
|
||||
else:
|
||||
# Dump the prop as JSON.
|
||||
@ -461,44 +452,6 @@ def format_query_params(router_data: dict[str, Any]) -> dict[str, str]:
|
||||
return {k.replace("-", "_"): v for k, v in params.items()}
|
||||
|
||||
|
||||
def format_dataframe_values(value: Type) -> list[Any]:
|
||||
"""Format dataframe values.
|
||||
|
||||
Args:
|
||||
value: The value to format.
|
||||
|
||||
Returns:
|
||||
Format data
|
||||
"""
|
||||
if not types.is_dataframe(type(value)):
|
||||
return value
|
||||
|
||||
format_data = []
|
||||
for data in list(value.values.tolist()):
|
||||
element = []
|
||||
for d in data:
|
||||
element.append(str(d) if isinstance(d, (list, tuple)) else d)
|
||||
format_data.append(element)
|
||||
|
||||
return format_data
|
||||
|
||||
|
||||
def format_image_data(value: Type) -> str:
|
||||
"""Format image data.
|
||||
|
||||
Args:
|
||||
value: The value to format.
|
||||
|
||||
Returns:
|
||||
Format data
|
||||
"""
|
||||
buff = io.BytesIO()
|
||||
value.save(buff, format="PNG")
|
||||
image_bytes = buff.getvalue()
|
||||
base64_image = base64.b64encode(image_bytes).decode("utf-8")
|
||||
return f"data:image/png;base64,{base64_image}"
|
||||
|
||||
|
||||
def format_state(value: Any) -> Any:
|
||||
"""Recursively format values in the given state.
|
||||
|
||||
@ -523,30 +476,12 @@ def format_state(value: Any) -> Any:
|
||||
if isinstance(value, types.StateBases):
|
||||
return value
|
||||
|
||||
# Convert plotly figures to JSON.
|
||||
if isinstance(value, go.Figure):
|
||||
return json.loads(to_json(value))["data"] # type: ignore
|
||||
# Serialize the value.
|
||||
serialized = serialize(value)
|
||||
if serialized is not None:
|
||||
return serialized
|
||||
|
||||
# Convert pandas dataframes to JSON.
|
||||
if types.is_dataframe(type(value)):
|
||||
return {
|
||||
"columns": value.columns.tolist(),
|
||||
"data": format_dataframe_values(value),
|
||||
}
|
||||
|
||||
# Convert datetime objects to str.
|
||||
if types.is_datetime(type(value)):
|
||||
return str(value)
|
||||
|
||||
# Convert Image objects to base64.
|
||||
if types.is_image(type(value)):
|
||||
return format_image_data(value) # type: ignore
|
||||
|
||||
raise TypeError(
|
||||
"State vars must be primitive Python types, "
|
||||
"or subclasses of rx.Base. "
|
||||
f"Got var of type {type(value)}."
|
||||
)
|
||||
raise TypeError(f"No JSON serializer found for var {value} of type {type(value)}.")
|
||||
|
||||
|
||||
def format_ref(ref: str) -> str:
|
||||
@ -580,58 +515,6 @@ def format_array_ref(refs: str, idx: Var | None) -> str:
|
||||
return f"refs_{clean_ref}"
|
||||
|
||||
|
||||
def format_dict(prop: ComponentStyle) -> str:
|
||||
"""Format a dict with vars potentially as values.
|
||||
|
||||
Args:
|
||||
prop: The dict to format.
|
||||
|
||||
Returns:
|
||||
The formatted dict.
|
||||
|
||||
Raises:
|
||||
InvalidStylePropError: If a style prop has a callable value
|
||||
"""
|
||||
# Import here to avoid circular imports.
|
||||
from reflex.event import EventHandler
|
||||
from reflex.vars import Var
|
||||
|
||||
prop_dict = {}
|
||||
|
||||
# Convert any var keys to strings.
|
||||
for key, value in prop.items():
|
||||
if issubclass(type(value), Callable):
|
||||
raise exceptions.InvalidStylePropError(
|
||||
f"The style prop `{to_snake_case(key)}` cannot have " # type: ignore
|
||||
f"`{value.fn.__qualname__ if isinstance(value, EventHandler) else value.__qualname__ if isinstance(value, builtin_types.FunctionType) else value}`, "
|
||||
f"an event handler or callable as its value"
|
||||
)
|
||||
prop_dict[key] = str(value) if isinstance(value, Var) else value
|
||||
|
||||
# Dump the dict to a string.
|
||||
fprop = json_dumps(prop_dict)
|
||||
|
||||
def unescape_double_quotes_in_var(m: re.Match) -> str:
|
||||
# Since the outer quotes are removed, the inner escaped quotes must be unescaped.
|
||||
return re.sub('\\\\"', '"', m.group(1))
|
||||
|
||||
# This substitution is necessary to unwrap var values.
|
||||
fprop = re.sub(
|
||||
pattern=r"""
|
||||
(?<!\\) # must NOT start with a backslash
|
||||
" # match opening double quote of JSON value
|
||||
{(.*?)} # extract the value between curly braces (non-greedy)
|
||||
" # match must end with an unescaped double quote
|
||||
""",
|
||||
repl=unescape_double_quotes_in_var,
|
||||
string=fprop,
|
||||
flags=re.VERBOSE,
|
||||
)
|
||||
|
||||
# Return the formatted dict.
|
||||
return fprop
|
||||
|
||||
|
||||
def format_breadcrumbs(route: str) -> list[tuple[str, str]]:
|
||||
"""Take a route and return a list of tuple for use in breadcrumb.
|
||||
|
||||
|
193
reflex/utils/serializers.py
Normal file
193
reflex/utils/serializers.py
Normal file
@ -0,0 +1,193 @@
|
||||
"""Serializers used to convert Var types to JSON strings."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import types as builtin_types
|
||||
from datetime import date, datetime, time, timedelta
|
||||
from typing import Any, Callable, Dict, Type, Union, get_type_hints
|
||||
|
||||
from reflex.utils import exceptions, types
|
||||
|
||||
# Mapping from type to a serializer.
|
||||
# The serializer should convert the type to a JSON object.
|
||||
SerializedType = Union[str, bool, int, float, list, dict]
|
||||
Serializer = Callable[[Type], SerializedType]
|
||||
SERIALIZERS: dict[Type, Serializer] = {}
|
||||
|
||||
|
||||
def serializer(fn: Serializer) -> Serializer:
|
||||
"""Decorator to add a serializer for a given type.
|
||||
|
||||
Args:
|
||||
fn: The function to decorate.
|
||||
|
||||
Returns:
|
||||
The decorated function.
|
||||
|
||||
Raises:
|
||||
ValueError: If the function does not take a single argument.
|
||||
"""
|
||||
# Get the global serializers.
|
||||
global SERIALIZERS
|
||||
|
||||
# Check the type hints to get the type of the argument.
|
||||
type_hints = get_type_hints(fn)
|
||||
args = [arg for arg in type_hints if arg != "return"]
|
||||
|
||||
# Make sure the function takes a single argument.
|
||||
if len(args) != 1:
|
||||
raise ValueError("Serializer must take a single argument.")
|
||||
|
||||
# Get the type of the argument.
|
||||
type_ = type_hints[args[0]]
|
||||
|
||||
# Make sure the type is not already registered.
|
||||
registered_fn = SERIALIZERS.get(type_)
|
||||
if registered_fn is not None and registered_fn != fn:
|
||||
raise ValueError(
|
||||
f"Serializer for type {type_} is already registered as {registered_fn.__qualname__}."
|
||||
)
|
||||
|
||||
# Register the serializer.
|
||||
SERIALIZERS[type_] = fn
|
||||
|
||||
# Return the function.
|
||||
return fn
|
||||
|
||||
|
||||
def serialize(value: Any) -> SerializedType | None:
|
||||
"""Serialize the value to a JSON string.
|
||||
|
||||
Args:
|
||||
value: The value to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized value, or None if a serializer is not found.
|
||||
"""
|
||||
# Get the serializer for the type.
|
||||
serializer = get_serializer(type(value))
|
||||
|
||||
# If there is no serializer, return None.
|
||||
if serializer is None:
|
||||
return None
|
||||
|
||||
# Serialize the value.
|
||||
return serializer(value)
|
||||
|
||||
|
||||
def get_serializer(type_: Type) -> Serializer | None:
|
||||
"""Get the serializer for the type.
|
||||
|
||||
Args:
|
||||
type_: The type to get the serializer for.
|
||||
|
||||
Returns:
|
||||
The serializer for the type, or None if there is no serializer.
|
||||
"""
|
||||
global SERIALIZERS
|
||||
|
||||
# First, check if the type is registered.
|
||||
serializer = SERIALIZERS.get(type_)
|
||||
if serializer is not None:
|
||||
return serializer
|
||||
|
||||
# If the type is not registered, check if it is a subclass of a registered type.
|
||||
for registered_type, serializer in SERIALIZERS.items():
|
||||
if types._issubclass(type_, registered_type):
|
||||
return serializer
|
||||
|
||||
# If there is no serializer, return None.
|
||||
return None
|
||||
|
||||
|
||||
def has_serializer(type_: Type) -> bool:
|
||||
"""Check if there is a serializer for the type.
|
||||
|
||||
Args:
|
||||
type_: The type to check.
|
||||
|
||||
Returns:
|
||||
Whether there is a serializer for the type.
|
||||
"""
|
||||
return get_serializer(type_) is not None
|
||||
|
||||
|
||||
@serializer
|
||||
def serialize_str(value: str) -> str:
|
||||
"""Serialize a string.
|
||||
|
||||
Args:
|
||||
value: The string to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized string.
|
||||
"""
|
||||
return value
|
||||
|
||||
|
||||
@serializer
|
||||
def serialize_dict(prop: Dict[str, Any]) -> str:
|
||||
"""Serialize a dictionary to a JSON string.
|
||||
|
||||
Args:
|
||||
prop: The dictionary to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized dictionary.
|
||||
|
||||
Raises:
|
||||
InvalidStylePropError: If the style prop is invalid.
|
||||
"""
|
||||
# Import here to avoid circular imports.
|
||||
from reflex.event import EventHandler
|
||||
from reflex.utils.format import json_dumps, to_snake_case
|
||||
from reflex.vars import Var
|
||||
|
||||
prop_dict = {}
|
||||
|
||||
# Convert any var keys to strings.
|
||||
for key, value in prop.items():
|
||||
if types._issubclass(type(value), Callable):
|
||||
raise exceptions.InvalidStylePropError(
|
||||
f"The style prop `{to_snake_case(key)}` cannot have " # type: ignore
|
||||
f"`{value.fn.__qualname__ if isinstance(value, EventHandler) else value.__qualname__ if isinstance(value, builtin_types.FunctionType) else value}`, "
|
||||
f"an event handler or callable as its value"
|
||||
)
|
||||
prop_dict[key] = str(value) if isinstance(value, Var) else value
|
||||
|
||||
# Dump the dict to a string.
|
||||
fprop = json_dumps(prop_dict)
|
||||
|
||||
def unescape_double_quotes_in_var(m: re.Match) -> str:
|
||||
# Since the outer quotes are removed, the inner escaped quotes must be unescaped.
|
||||
return re.sub('\\\\"', '"', m.group(1))
|
||||
|
||||
# This substitution is necessary to unwrap var values.
|
||||
fprop = re.sub(
|
||||
pattern=r"""
|
||||
(?<!\\) # must NOT start with a backslash
|
||||
" # match opening double quote of JSON value
|
||||
{(.*?)} # extract the value between curly braces (non-greedy)
|
||||
" # match must end with an unescaped double quote
|
||||
""",
|
||||
repl=unescape_double_quotes_in_var,
|
||||
string=fprop,
|
||||
flags=re.VERBOSE,
|
||||
)
|
||||
|
||||
# Return the formatted dict.
|
||||
return fprop
|
||||
|
||||
|
||||
@serializer
|
||||
def serialize_datetime(dt: Union[date, datetime, time, timedelta]) -> str:
|
||||
"""Serialize a datetime to a JSON string.
|
||||
|
||||
Args:
|
||||
dt: The datetime to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized datetime.
|
||||
"""
|
||||
return str(dt)
|
@ -4,10 +4,10 @@ from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import typing
|
||||
from datetime import date, datetime, time, timedelta
|
||||
from typing import Any, Callable, Type, Union, _GenericAlias # type: ignore
|
||||
|
||||
from reflex.base import Base
|
||||
from reflex.utils import serializers
|
||||
|
||||
# Union of generic types.
|
||||
GenericType = Union[Type, _GenericAlias]
|
||||
@ -143,60 +143,16 @@ def is_dataframe(value: Type) -> bool:
|
||||
return value.__name__ == "DataFrame"
|
||||
|
||||
|
||||
def is_image(value: Type) -> bool:
|
||||
"""Check if the given value is a pillow image. By checking if the value subclasses PIL.
|
||||
def is_valid_var_type(type_: Type) -> bool:
|
||||
"""Check if the given type is a valid prop type.
|
||||
|
||||
Args:
|
||||
value: The value to check.
|
||||
type_: The type to check.
|
||||
|
||||
Returns:
|
||||
Whether the value is a pillow image.
|
||||
Whether the type is a valid prop type.
|
||||
"""
|
||||
if is_generic_alias(value) or value == typing.Any:
|
||||
return False
|
||||
return "PIL" in value.__module__
|
||||
|
||||
|
||||
def is_figure(value: Type) -> bool:
|
||||
"""Check if the given value is a figure.
|
||||
|
||||
Args:
|
||||
value: The value to check.
|
||||
|
||||
Returns:
|
||||
Whether the value is a figure.
|
||||
"""
|
||||
return value.__name__ == "Figure"
|
||||
|
||||
|
||||
def is_datetime(value: Type) -> bool:
|
||||
"""Check if the given value is a datetime object.
|
||||
|
||||
Args:
|
||||
value: The value to check.
|
||||
|
||||
Returns:
|
||||
Whether the value is a date, datetime, time, or timedelta.
|
||||
"""
|
||||
return issubclass(value, (date, datetime, time, timedelta))
|
||||
|
||||
|
||||
def is_valid_var_type(var: Type) -> bool:
|
||||
"""Check if the given value is a valid prop type.
|
||||
|
||||
Args:
|
||||
var: The value to check.
|
||||
|
||||
Returns:
|
||||
Whether the value is a valid prop type.
|
||||
"""
|
||||
return (
|
||||
_issubclass(var, StateVar)
|
||||
or is_dataframe(var)
|
||||
or is_figure(var)
|
||||
or is_image(var)
|
||||
or is_datetime(var)
|
||||
)
|
||||
return _issubclass(type_, StateVar) or serializers.has_serializer(type_)
|
||||
|
||||
|
||||
def is_backend_variable(name: str) -> bool:
|
||||
|
@ -24,13 +24,12 @@ from typing import (
|
||||
get_type_hints,
|
||||
)
|
||||
|
||||
from plotly.graph_objects import Figure
|
||||
from plotly.io import to_json
|
||||
from pydantic.fields import ModelField
|
||||
|
||||
from reflex import constants
|
||||
from reflex.base import Base
|
||||
from reflex.utils import console, format, types
|
||||
from reflex.utils.serializers import serialize
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from reflex.state import State
|
||||
@ -126,19 +125,16 @@ class Var(ABC):
|
||||
|
||||
type_ = type(value)
|
||||
|
||||
# Special case for plotly figures.
|
||||
if isinstance(value, Figure):
|
||||
value = json.loads(to_json(value))["data"] # type: ignore
|
||||
type_ = Figure
|
||||
|
||||
if isinstance(value, dict):
|
||||
value = format.format_dict(value)
|
||||
# Try to serialize the value.
|
||||
serialized = serialize(value)
|
||||
if serialized is not None:
|
||||
value = serialized
|
||||
|
||||
try:
|
||||
name = value if isinstance(value, str) else json.dumps(value)
|
||||
except TypeError as e:
|
||||
raise TypeError(
|
||||
f"To create a Var must be Var or JSON-serializable. Got {value} of type {type(value)}."
|
||||
f"No JSON serializer found for var {value} of type {type_}."
|
||||
) from e
|
||||
|
||||
return BaseVar(name=name, type_=type_, is_local=is_local, is_string=is_string)
|
||||
@ -184,7 +180,7 @@ class Var(ABC):
|
||||
"""
|
||||
if self.state:
|
||||
return self.full_name
|
||||
if self.is_string or self.type_ is Figure:
|
||||
if self.is_string:
|
||||
return self.name
|
||||
try:
|
||||
return json.loads(self.name)
|
||||
|
@ -7,7 +7,7 @@ import re
|
||||
import sys
|
||||
from inspect import getfullargspec
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional, get_args
|
||||
from typing import Any, Dict, List, Optional, Union, get_args # NOQA
|
||||
|
||||
import black
|
||||
|
||||
@ -181,7 +181,14 @@ class PyiGenerator:
|
||||
return _get_var_definition(self.current_module, _name)
|
||||
|
||||
def _generate_function(self, _name, _func):
|
||||
definition = "".join(inspect.getsource(_func).split(":\n")[0].split("\n"))
|
||||
import textwrap
|
||||
|
||||
# Don't generate indented functions.
|
||||
source = inspect.getsource(_func)
|
||||
if textwrap.dedent(source) != source:
|
||||
return []
|
||||
|
||||
definition = "".join([line for line in source.split(":\n")[0].split("\n")])
|
||||
return [f"{definition}:", " ..."]
|
||||
|
||||
def _write_pyi_file(self, variables, functions, classes):
|
||||
|
@ -2,8 +2,12 @@ import pandas as pd
|
||||
import pytest
|
||||
|
||||
import reflex as rx
|
||||
from reflex.components import data_table
|
||||
from reflex.components.datadisplay.datatable import (
|
||||
DataTable,
|
||||
serialize_dataframe, # type: ignore
|
||||
)
|
||||
from reflex.utils import types
|
||||
from reflex.utils.serializers import serialize
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@ -31,11 +35,11 @@ def test_validate_data_table(data_table_state: rx.Var, expected):
|
||||
|
||||
"""
|
||||
if not types.is_dataframe(data_table_state.data.type_):
|
||||
data_table_component = data_table(
|
||||
data_table_component = DataTable.create(
|
||||
data=data_table_state.data, columns=data_table_state.columns
|
||||
)
|
||||
else:
|
||||
data_table_component = data_table(data=data_table_state.data)
|
||||
data_table_component = DataTable.create(data=data_table_state.data)
|
||||
|
||||
data_table_dict = data_table_component.render()
|
||||
|
||||
@ -62,7 +66,7 @@ def test_invalid_props(props):
|
||||
props: props to pass in component.
|
||||
"""
|
||||
with pytest.raises(ValueError):
|
||||
data_table(**props)
|
||||
DataTable.create(**props)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@ -96,10 +100,21 @@ def test_computed_var_without_annotation(fixture, request, err_msg, is_data_fram
|
||||
"""
|
||||
with pytest.raises(ValueError) as err:
|
||||
if is_data_frame:
|
||||
data_table(data=request.getfixturevalue(fixture).data)
|
||||
DataTable.create(data=request.getfixturevalue(fixture).data)
|
||||
else:
|
||||
data_table(
|
||||
DataTable.create(
|
||||
data=request.getfixturevalue(fixture).data,
|
||||
columns=request.getfixturevalue(fixture).columns,
|
||||
)
|
||||
assert err.value.args[0] == err_msg
|
||||
|
||||
|
||||
def test_serialize_dataframe():
|
||||
"""Test if dataframe is serialized correctly."""
|
||||
df = pd.DataFrame(
|
||||
[["foo", "bar"], ["foo1", "bar1"]], columns=["column1", "column2"]
|
||||
)
|
||||
value = serialize(df)
|
||||
assert value == serialize_dataframe(df)
|
||||
assert isinstance(value, dict)
|
||||
assert list(value.keys()) == ["columns", "data"]
|
||||
|
34
tests/components/graphing/test_plotly.py
Normal file
34
tests/components/graphing/test_plotly.py
Normal file
@ -0,0 +1,34 @@
|
||||
import numpy as np
|
||||
import plotly.graph_objects as go
|
||||
import pytest
|
||||
|
||||
from reflex.components.graphing.plotly import serialize_figure # type: ignore
|
||||
from reflex.utils.serializers import serialize
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def plotly_fig() -> go.Figure:
|
||||
"""Get a plotly figure.
|
||||
|
||||
Returns:
|
||||
A random plotly figure.
|
||||
"""
|
||||
# Generate random data.
|
||||
data = np.random.randint(0, 10, size=(10, 4))
|
||||
trace = go.Scatter(
|
||||
x=list(range(len(data))), y=data[:, 0], mode="lines", name="Trace 1"
|
||||
)
|
||||
|
||||
# Create a graph.
|
||||
return go.Figure(data=[trace])
|
||||
|
||||
|
||||
def test_serialize_plotly(plotly_fig: go.Figure):
|
||||
"""Test that serializing a plotly figure works.
|
||||
|
||||
Args:
|
||||
plotly_fig: The figure to serialize.
|
||||
"""
|
||||
value = serialize(plotly_fig)
|
||||
assert isinstance(value, list)
|
||||
assert value == serialize_figure(plotly_fig)
|
65
tests/components/media/test_image.py
Normal file
65
tests/components/media/test_image.py
Normal file
@ -0,0 +1,65 @@
|
||||
import pytest
|
||||
|
||||
try:
|
||||
# PIL is only available in python 3.8+
|
||||
import numpy as np
|
||||
import PIL
|
||||
from PIL.Image import Image as Img
|
||||
|
||||
import reflex as rx
|
||||
from reflex.components.media.image import Image, serialize_image # type: ignore
|
||||
from reflex.utils.serializers import serialize
|
||||
|
||||
@pytest.fixture
|
||||
def pil_image() -> Img:
|
||||
"""Get an image.
|
||||
|
||||
Returns:
|
||||
A random PIL image.
|
||||
"""
|
||||
imarray = np.random.rand(100, 100, 3) * 255
|
||||
return PIL.Image.fromarray(imarray.astype("uint8")).convert("RGBA") # type: ignore
|
||||
|
||||
def test_serialize_image(pil_image: Img):
|
||||
"""Test that serializing an image works.
|
||||
|
||||
Args:
|
||||
pil_image: The image to serialize.
|
||||
"""
|
||||
data = serialize(pil_image)
|
||||
assert isinstance(data, str)
|
||||
assert data == serialize_image(pil_image)
|
||||
assert data.startswith("data:image/png;base64,")
|
||||
|
||||
def test_set_src_str():
|
||||
"""Test that setting the src works."""
|
||||
image = rx.image(src="pic2.jpeg")
|
||||
assert str(image.src) == "pic2.jpeg" # type: ignore
|
||||
|
||||
def test_set_src_img(pil_image: Img):
|
||||
"""Test that setting the src works.
|
||||
|
||||
Args:
|
||||
pil_image: The image to serialize.
|
||||
"""
|
||||
image = Image.create(src=pil_image)
|
||||
assert str(image.src) == serialize_image(pil_image) # type: ignore
|
||||
|
||||
def test_render(pil_image: Img):
|
||||
"""Test that rendering an image works.
|
||||
|
||||
Args:
|
||||
pil_image: The image to serialize.
|
||||
"""
|
||||
image = Image.create(src=pil_image)
|
||||
assert not image.src.is_string # type: ignore
|
||||
image._render()
|
||||
assert image.src.is_string # type: ignore
|
||||
|
||||
except ImportError:
|
||||
|
||||
def test_pillow_import():
|
||||
"""Make sure the Python version is less than 3.8."""
|
||||
import sys
|
||||
|
||||
assert sys.version_info < (3, 8)
|
@ -230,14 +230,9 @@ def test_create_type_error():
|
||||
|
||||
value = ErrorType()
|
||||
|
||||
with pytest.raises(TypeError) as exception:
|
||||
with pytest.raises(TypeError):
|
||||
Var.create(value)
|
||||
|
||||
assert (
|
||||
exception.value.args[0]
|
||||
== f"To create a Var must be Var or JSON-serializable. Got {value} of type {type(value)}."
|
||||
)
|
||||
|
||||
|
||||
def v(value) -> Var:
|
||||
val = (
|
||||
|
0
tests/utils/__init__.py
Normal file
0
tests/utils/__init__.py
Normal file
102
tests/utils/test_serializers.py
Normal file
102
tests/utils/test_serializers.py
Normal file
@ -0,0 +1,102 @@
|
||||
import datetime
|
||||
from typing import Any, Dict, Type
|
||||
|
||||
import pytest
|
||||
|
||||
from reflex.utils import serializers
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"type_,expected",
|
||||
[
|
||||
(str, True),
|
||||
(dict, True),
|
||||
(Dict[int, int], True),
|
||||
],
|
||||
)
|
||||
def test_has_serializer(type_: Type, expected: bool):
|
||||
"""Test that has_serializer returns the correct value.
|
||||
|
||||
|
||||
Args:
|
||||
type_: The type to check.
|
||||
expected: The expected result.
|
||||
"""
|
||||
assert serializers.has_serializer(type_) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"type_,expected",
|
||||
[
|
||||
(str, serializers.serialize_str),
|
||||
(dict, serializers.serialize_dict),
|
||||
(Dict[int, int], serializers.serialize_dict),
|
||||
(datetime.datetime, serializers.serialize_datetime),
|
||||
(datetime.date, serializers.serialize_datetime),
|
||||
(datetime.time, serializers.serialize_datetime),
|
||||
(datetime.timedelta, serializers.serialize_datetime),
|
||||
],
|
||||
)
|
||||
def test_get_serializer(type_: Type, expected: serializers.Serializer):
|
||||
"""Test that get_serializer returns the correct value.
|
||||
|
||||
|
||||
Args:
|
||||
type_: The type to check.
|
||||
expected: The expected result.
|
||||
"""
|
||||
assert serializers.get_serializer(type_) == expected
|
||||
|
||||
|
||||
def test_add_serializer():
|
||||
"""Test that adding a serializer works."""
|
||||
|
||||
def serialize_test(value: int) -> str:
|
||||
"""Serialize an int to a string.
|
||||
|
||||
Args:
|
||||
value: The value to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized value.
|
||||
"""
|
||||
return str(value)
|
||||
|
||||
# Initially there should be no serializer for int.
|
||||
assert not serializers.has_serializer(int)
|
||||
assert serializers.serialize(5) is None
|
||||
|
||||
# Register the serializer.
|
||||
assert serializers.serializer(serialize_test) == serialize_test
|
||||
|
||||
# There should now be a serializer for int.
|
||||
assert serializers.has_serializer(int)
|
||||
assert serializers.get_serializer(int) == serialize_test
|
||||
assert serializers.serialize(5) == "5"
|
||||
|
||||
# Remove the serializer.
|
||||
serializers.SERIALIZERS.pop(int)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"value,expected",
|
||||
[
|
||||
("test", "test"),
|
||||
(datetime.datetime(2021, 1, 1, 1, 1, 1, 1), "2021-01-01 01:01:01.000001"),
|
||||
(datetime.date(2021, 1, 1), "2021-01-01"),
|
||||
(datetime.time(1, 1, 1, 1), "01:01:01.000001"),
|
||||
(datetime.timedelta(1, 1, 1), "1 day, 0:00:01.000001"),
|
||||
(5, None),
|
||||
(None, None),
|
||||
([], None),
|
||||
],
|
||||
)
|
||||
def test_serialize(value: Any, expected: str):
|
||||
"""Test that serialize returns the correct value.
|
||||
|
||||
|
||||
Args:
|
||||
value: The value to serialize.
|
||||
expected: The expected result.
|
||||
"""
|
||||
assert serializers.serialize(value) == expected
|
@ -21,6 +21,7 @@ from reflex.utils import (
|
||||
types,
|
||||
)
|
||||
from reflex.utils import exec as utils_exec
|
||||
from reflex.utils.serializers import serialize
|
||||
from reflex.vars import BaseVar, Var
|
||||
|
||||
|
||||
@ -777,4 +778,4 @@ def test_style_prop_with_event_handler_value(callable):
|
||||
}
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
format.format_dict(style) # type: ignore
|
||||
serialize(style) # type: ignore
|
Loading…
Reference in New Issue
Block a user