diff --git a/poetry.lock b/poetry.lock index 2012042a1..55cd70c49 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.4.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.4.0 and should not be changed by hand. [[package]] name = "anyio" @@ -37,25 +37,6 @@ files = [ [package.dependencies] typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""} -[[package]] -name = "attrs" -version = "22.2.0" -description = "Classes Without Boilerplate" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, - {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, -] - -[package.extras] -cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] -tests = ["attrs[tests-no-zope]", "zope.interface"] -tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] - [[package]] name = "bidict" version = "0.22.1" @@ -112,14 +93,14 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "certifi" -version = "2022.12.7" +version = "2023.5.7" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, - {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, + {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, + {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, ] [[package]] @@ -215,14 +196,14 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.1.0" +version = "1.1.1" description = "Backport of PEP 654 (exception groups)" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, - {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, + {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, + {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, ] [package.extras] @@ -252,19 +233,19 @@ test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.10.0)", "coverage[toml] (>= [[package]] name = "filelock" -version = "3.10.6" +version = "3.12.0" description = "A platform independent file lock." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "filelock-3.10.6-py3-none-any.whl", hash = "sha256:52f119747b2b9c4730dac715a7b1ab34b8ee70fd9259cba158ee53da566387ff"}, - {file = "filelock-3.10.6.tar.gz", hash = "sha256:409105becd604d6b176a483f855e7e8903c5cb2873e47f2c64f66a370c046aaf"}, + {file = "filelock-3.12.0-py3-none-any.whl", hash = "sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"}, + {file = "filelock-3.12.0.tar.gz", hash = "sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718"}, ] [package.extras] -docs = ["furo (>=2022.12.7)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.2)", "diff-cover (>=7.5)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] [[package]] name = "greenlet" @@ -424,14 +405,14 @@ socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "identify" -version = "2.5.22" +version = "2.5.24" description = "File identification library for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "identify-2.5.22-py2.py3-none-any.whl", hash = "sha256:f0faad595a4687053669c112004178149f6c326db71ee999ae4636685753ad2f"}, - {file = "identify-2.5.22.tar.gz", hash = "sha256:f7a93d6cf98e29bd07663c60728e7a4057615068d7a639d132dc883b2d54d31e"}, + {file = "identify-2.5.24-py2.py3-none-any.whl", hash = "sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d"}, + {file = "identify-2.5.24.tar.gz", hash = "sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4"}, ] [package.extras] @@ -451,14 +432,14 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.0.0" +version = "6.6.0" description = "Read metadata from Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"}, - {file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"}, + {file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"}, + {file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"}, ] [package.dependencies] @@ -552,52 +533,52 @@ files = [ [[package]] name = "numpy" -version = "1.24.2" +version = "1.24.3" description = "Fundamental package for array computing in Python" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "numpy-1.24.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eef70b4fc1e872ebddc38cddacc87c19a3709c0e3e5d20bf3954c147b1dd941d"}, - {file = "numpy-1.24.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d2859428712785e8a8b7d2b3ef0a1d1565892367b32f915c4a4df44d0e64f5"}, - {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6524630f71631be2dabe0c541e7675db82651eb998496bbe16bc4f77f0772253"}, - {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a51725a815a6188c662fb66fb32077709a9ca38053f0274640293a14fdd22978"}, - {file = "numpy-1.24.2-cp310-cp310-win32.whl", hash = "sha256:2620e8592136e073bd12ee4536149380695fbe9ebeae845b81237f986479ffc9"}, - {file = "numpy-1.24.2-cp310-cp310-win_amd64.whl", hash = "sha256:97cf27e51fa078078c649a51d7ade3c92d9e709ba2bfb97493007103c741f1d0"}, - {file = "numpy-1.24.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7de8fdde0003f4294655aa5d5f0a89c26b9f22c0a58790c38fae1ed392d44a5a"}, - {file = "numpy-1.24.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4173bde9fa2a005c2c6e2ea8ac1618e2ed2c1c6ec8a7657237854d42094123a0"}, - {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cecaed30dc14123020f77b03601559fff3e6cd0c048f8b5289f4eeabb0eb281"}, - {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a23f8440561a633204a67fb44617ce2a299beecf3295f0d13c495518908e910"}, - {file = "numpy-1.24.2-cp311-cp311-win32.whl", hash = "sha256:e428c4fbfa085f947b536706a2fc349245d7baa8334f0c5723c56a10595f9b95"}, - {file = "numpy-1.24.2-cp311-cp311-win_amd64.whl", hash = "sha256:557d42778a6869c2162deb40ad82612645e21d79e11c1dc62c6e82a2220ffb04"}, - {file = "numpy-1.24.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d0a2db9d20117bf523dde15858398e7c0858aadca7c0f088ac0d6edd360e9ad2"}, - {file = "numpy-1.24.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c72a6b2f4af1adfe193f7beb91ddf708ff867a3f977ef2ec53c0ffb8283ab9f5"}, - {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29e6bd0ec49a44d7690ecb623a8eac5ab8a923bce0bea6293953992edf3a76a"}, - {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eabd64ddb96a1239791da78fa5f4e1693ae2dadc82a76bc76a14cbb2b966e96"}, - {file = "numpy-1.24.2-cp38-cp38-win32.whl", hash = "sha256:e3ab5d32784e843fc0dd3ab6dcafc67ef806e6b6828dc6af2f689be0eb4d781d"}, - {file = "numpy-1.24.2-cp38-cp38-win_amd64.whl", hash = "sha256:76807b4063f0002c8532cfeac47a3068a69561e9c8715efdad3c642eb27c0756"}, - {file = "numpy-1.24.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4199e7cfc307a778f72d293372736223e39ec9ac096ff0a2e64853b866a8e18a"}, - {file = "numpy-1.24.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:adbdce121896fd3a17a77ab0b0b5eedf05a9834a18699db6829a64e1dfccca7f"}, - {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:889b2cc88b837d86eda1b17008ebeb679d82875022200c6e8e4ce6cf549b7acb"}, - {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780"}, - {file = "numpy-1.24.2-cp39-cp39-win32.whl", hash = "sha256:63e45511ee4d9d976637d11e6c9864eae50e12dc9598f531c035265991910468"}, - {file = "numpy-1.24.2-cp39-cp39-win_amd64.whl", hash = "sha256:a77d3e1163a7770164404607b7ba3967fb49b24782a6ef85d9b5f54126cc39e5"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:92011118955724465fb6853def593cf397b4a1367495e0b59a7e69d40c4eb71d"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9006288bcf4895917d02583cf3411f98631275bc67cce355a7f39f8c14338fa"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:150947adbdfeceec4e5926d956a06865c1c690f2fd902efede4ca6fe2e657c3f"}, - {file = "numpy-1.24.2.tar.gz", hash = "sha256:003a9f530e880cb2cd177cba1af7220b9aa42def9c4afc2a2fc3ee6be7eb2b22"}, + {file = "numpy-1.24.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c1104d3c036fb81ab923f507536daedc718d0ad5a8707c6061cdfd6d184e570"}, + {file = "numpy-1.24.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:202de8f38fc4a45a3eea4b63e2f376e5f2dc64ef0fa692838e31a808520efaf7"}, + {file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8535303847b89aa6b0f00aa1dc62867b5a32923e4d1681a35b5eef2d9591a463"}, + {file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d926b52ba1367f9acb76b0df6ed21f0b16a1ad87c6720a1121674e5cf63e2b6"}, + {file = "numpy-1.24.3-cp310-cp310-win32.whl", hash = "sha256:f21c442fdd2805e91799fbe044a7b999b8571bb0ab0f7850d0cb9641a687092b"}, + {file = "numpy-1.24.3-cp310-cp310-win_amd64.whl", hash = "sha256:ab5f23af8c16022663a652d3b25dcdc272ac3f83c3af4c02eb8b824e6b3ab9d7"}, + {file = "numpy-1.24.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9a7721ec204d3a237225db3e194c25268faf92e19338a35f3a224469cb6039a3"}, + {file = "numpy-1.24.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d6cc757de514c00b24ae8cf5c876af2a7c3df189028d68c0cb4eaa9cd5afc2bf"}, + {file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76e3f4e85fc5d4fd311f6e9b794d0c00e7002ec122be271f2019d63376f1d385"}, + {file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1d3c026f57ceaad42f8231305d4653d5f05dc6332a730ae5c0bea3513de0950"}, + {file = "numpy-1.24.3-cp311-cp311-win32.whl", hash = "sha256:c91c4afd8abc3908e00a44b2672718905b8611503f7ff87390cc0ac3423fb096"}, + {file = "numpy-1.24.3-cp311-cp311-win_amd64.whl", hash = "sha256:5342cf6aad47943286afa6f1609cad9b4266a05e7f2ec408e2cf7aea7ff69d80"}, + {file = "numpy-1.24.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7776ea65423ca6a15255ba1872d82d207bd1e09f6d0894ee4a64678dd2204078"}, + {file = "numpy-1.24.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ae8d0be48d1b6ed82588934aaaa179875e7dc4f3d84da18d7eae6eb3f06c242c"}, + {file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecde0f8adef7dfdec993fd54b0f78183051b6580f606111a6d789cd14c61ea0c"}, + {file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4749e053a29364d3452c034827102ee100986903263e89884922ef01a0a6fd2f"}, + {file = "numpy-1.24.3-cp38-cp38-win32.whl", hash = "sha256:d933fabd8f6a319e8530d0de4fcc2e6a61917e0b0c271fded460032db42a0fe4"}, + {file = "numpy-1.24.3-cp38-cp38-win_amd64.whl", hash = "sha256:56e48aec79ae238f6e4395886b5eaed058abb7231fb3361ddd7bfdf4eed54289"}, + {file = "numpy-1.24.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4719d5aefb5189f50887773699eaf94e7d1e02bf36c1a9d353d9f46703758ca4"}, + {file = "numpy-1.24.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ec87a7084caa559c36e0a2309e4ecb1baa03b687201d0a847c8b0ed476a7187"}, + {file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea8282b9bcfe2b5e7d491d0bf7f3e2da29700cec05b49e64d6246923329f2b02"}, + {file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210461d87fb02a84ef243cac5e814aad2b7f4be953b32cb53327bb49fd77fbb4"}, + {file = "numpy-1.24.3-cp39-cp39-win32.whl", hash = "sha256:784c6da1a07818491b0ffd63c6bbe5a33deaa0e25a20e1b3ea20cf0e43f8046c"}, + {file = "numpy-1.24.3-cp39-cp39-win_amd64.whl", hash = "sha256:d5036197ecae68d7f491fcdb4df90082b0d4960ca6599ba2659957aafced7c17"}, + {file = "numpy-1.24.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:352ee00c7f8387b44d19f4cada524586f07379c0d49270f87233983bc5087ca0"}, + {file = "numpy-1.24.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7d6acc2e7524c9955e5c903160aa4ea083736fde7e91276b0e5d98e6332812"}, + {file = "numpy-1.24.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:35400e6a8d102fd07c71ed7dcadd9eb62ee9a6e84ec159bd48c28235bbb0f8e4"}, + {file = "numpy-1.24.3.tar.gz", hash = "sha256:ab344f1bf21f140adab8e47fdbc7c35a477dc01408791f8ba00d018dd0bc5155"}, ] [[package]] name = "packaging" -version = "23.0" +version = "23.1" description = "Core utilities for Python packages" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, - {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, ] [[package]] @@ -693,48 +674,49 @@ test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] [[package]] name = "pathspec" -version = "0.11.0" +version = "0.11.1" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pathspec-0.11.0-py3-none-any.whl", hash = "sha256:3a66eb970cbac598f9e5ccb5b2cf58930cd8e3ed86d393d541eaf2d8b1705229"}, - {file = "pathspec-0.11.0.tar.gz", hash = "sha256:64d338d4e0914e91c1792321e6907b5a593f1ab1851de7fc269557a21b30ebbc"}, + {file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"}, + {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, ] [[package]] name = "platformdirs" -version = "3.1.0" +version = "3.5.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.1.0-py3-none-any.whl", hash = "sha256:13b08a53ed71021350c9e300d4ea8668438fb0046ab3937ac9a29913a1a1350a"}, - {file = "platformdirs-3.1.0.tar.gz", hash = "sha256:accc3665857288317f32c7bebb5a8e482ba717b474f3fc1d18ca7f9214be0cef"}, + {file = "platformdirs-3.5.0-py3-none-any.whl", hash = "sha256:47692bc24c1958e8b0f13dd727307cff1db103fca36399f457da8e05f222fdc4"}, + {file = "platformdirs-3.5.0.tar.gz", hash = "sha256:7954a68d0ba23558d753f73437c55f89027cf8f5108c19844d4b82e5af396335"}, ] [package.dependencies] -typing-extensions = {version = ">=4.4", markers = "python_version < \"3.8\""} +typing-extensions = {version = ">=4.5", markers = "python_version < \"3.8\""} [package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] name = "plotly" -version = "5.13.1" +version = "5.14.1" description = "An open-source, interactive data visualization library for Python" category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "plotly-5.13.1-py2.py3-none-any.whl", hash = "sha256:f776a5c664908450c6c1727f61e8e2e22798d9c6c69d37a9057735365084a2fa"}, - {file = "plotly-5.13.1.tar.gz", hash = "sha256:90ee9a1fee0dda30e2830e129855081ea17bd1b06a553a62b62de15caff1a219"}, + {file = "plotly-5.14.1-py2.py3-none-any.whl", hash = "sha256:a63f3ad9e4cc2e02902a738e5e3e7f3d1307f2732ac71a6c28f1238ed3052826"}, + {file = "plotly-5.14.1.tar.gz", hash = "sha256:bcac86d7fcba3eff7260c1eddc36ca34dae2aded10a0709808446565e0e53b93"}, ] [package.dependencies] +packaging = "*" tenacity = ">=6.2.0" [[package]] @@ -758,14 +740,14 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.2.1" +version = "3.3.1" description = "A framework for managing and maintaining multi-language pre-commit hooks." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "pre_commit-3.2.1-py2.py3-none-any.whl", hash = "sha256:a06a7fcce7f420047a71213c175714216498b49ebc81fe106f7716ca265f5bb6"}, - {file = "pre_commit-3.2.1.tar.gz", hash = "sha256:b5aee7d75dbba21ee161ba641b01e7ae10c5b91967ebf7b2ab0dfae12d07e1f1"}, + {file = "pre_commit-3.3.1-py2.py3-none-any.whl", hash = "sha256:218e9e3f7f7f3271ebc355a15598a4d3893ad9fc7b57fe446db75644543323b9"}, + {file = "pre_commit-3.3.1.tar.gz", hash = "sha256:733f78c9a056cdd169baa6cd4272d51ecfda95346ef8a89bf93712706021b907"}, ] [package.dependencies] @@ -777,26 +759,26 @@ virtualenv = ">=20.10.0" [[package]] name = "psutil" -version = "5.9.4" +version = "5.9.5" description = "Cross-platform lib for process and system monitoring in Python." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "psutil-5.9.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c1ca331af862803a42677c120aff8a814a804e09832f166f226bfd22b56feee8"}, - {file = "psutil-5.9.4-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:68908971daf802203f3d37e78d3f8831b6d1014864d7a85937941bb35f09aefe"}, - {file = "psutil-5.9.4-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:3ff89f9b835100a825b14c2808a106b6fdcc4b15483141482a12c725e7f78549"}, - {file = "psutil-5.9.4-cp27-cp27m-win32.whl", hash = "sha256:852dd5d9f8a47169fe62fd4a971aa07859476c2ba22c2254d4a1baa4e10b95ad"}, - {file = "psutil-5.9.4-cp27-cp27m-win_amd64.whl", hash = "sha256:9120cd39dca5c5e1c54b59a41d205023d436799b1c8c4d3ff71af18535728e94"}, - {file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6b92c532979bafc2df23ddc785ed116fced1f492ad90a6830cf24f4d1ea27d24"}, - {file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:efeae04f9516907be44904cc7ce08defb6b665128992a56957abc9b61dca94b7"}, - {file = "psutil-5.9.4-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:54d5b184728298f2ca8567bf83c422b706200bcbbfafdc06718264f9393cfeb7"}, - {file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16653106f3b59386ffe10e0bad3bb6299e169d5327d3f187614b1cb8f24cf2e1"}, - {file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54c0d3d8e0078b7666984e11b12b88af2db11d11249a8ac8920dd5ef68a66e08"}, - {file = "psutil-5.9.4-cp36-abi3-win32.whl", hash = "sha256:149555f59a69b33f056ba1c4eb22bb7bf24332ce631c44a319cec09f876aaeff"}, - {file = "psutil-5.9.4-cp36-abi3-win_amd64.whl", hash = "sha256:fd8522436a6ada7b4aad6638662966de0d61d241cb821239b2ae7013d41a43d4"}, - {file = "psutil-5.9.4-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:6001c809253a29599bc0dfd5179d9f8a5779f9dffea1da0f13c53ee568115e1e"}, - {file = "psutil-5.9.4.tar.gz", hash = "sha256:3d7f9739eb435d4b1338944abe23f49584bde5395f27487d2ee25ad9a8774a62"}, + {file = "psutil-5.9.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:be8929ce4313f9f8146caad4272f6abb8bf99fc6cf59344a3167ecd74f4f203f"}, + {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ab8ed1a1d77c95453db1ae00a3f9c50227ebd955437bcf2a574ba8adbf6a74d5"}, + {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4aef137f3345082a3d3232187aeb4ac4ef959ba3d7c10c33dd73763fbc063da4"}, + {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ea8518d152174e1249c4f2a1c89e3e6065941df2fa13a1ab45327716a23c2b48"}, + {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:acf2aef9391710afded549ff602b5887d7a2349831ae4c26be7c807c0a39fac4"}, + {file = "psutil-5.9.5-cp27-none-win32.whl", hash = "sha256:5b9b8cb93f507e8dbaf22af6a2fd0ccbe8244bf30b1baad6b3954e935157ae3f"}, + {file = "psutil-5.9.5-cp27-none-win_amd64.whl", hash = "sha256:8c5f7c5a052d1d567db4ddd231a9d27a74e8e4a9c3f44b1032762bd7b9fdcd42"}, + {file = "psutil-5.9.5-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3c6f686f4225553615612f6d9bc21f1c0e305f75d7d8454f9b46e901778e7217"}, + {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a7dd9997128a0d928ed4fb2c2d57e5102bb6089027939f3b722f3a210f9a8da"}, + {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89518112647f1276b03ca97b65cc7f64ca587b1eb0278383017c2a0dcc26cbe4"}, + {file = "psutil-5.9.5-cp36-abi3-win32.whl", hash = "sha256:104a5cc0e31baa2bcf67900be36acde157756b9c44017b86b2c049f11957887d"}, + {file = "psutil-5.9.5-cp36-abi3-win_amd64.whl", hash = "sha256:b258c0c1c9d145a1d5ceffab1134441c4c5113b2417fafff7315a917a026c3c9"}, + {file = "psutil-5.9.5-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c607bb3b57dc779d55e1554846352b4e358c10fff3abf3514a7a6601beebdb30"}, + {file = "psutil-5.9.5.tar.gz", hash = "sha256:5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c"}, ] [package.extras] @@ -857,14 +839,14 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pygments" -version = "2.14.0" +version = "2.15.1" description = "Pygments is a syntax highlighting package written in Python." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"}, - {file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"}, + {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, + {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, ] [package.extras] @@ -872,14 +854,14 @@ plugins = ["importlib-metadata"] [[package]] name = "pyright" -version = "1.1.297" +version = "1.1.306" description = "Command line wrapper for pyright" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pyright-1.1.297-py3-none-any.whl", hash = "sha256:3fd6528280eb649f8b64b7ece55299f01e340d29f4cf257da876957e3ee24062"}, - {file = "pyright-1.1.297.tar.gz", hash = "sha256:89082de2fbd240fa75767b57824f4d8516f2fb9005047265a67b895547c6272f"}, + {file = "pyright-1.1.306-py3-none-any.whl", hash = "sha256:008eb2a29584ae274a154d749cf81476a3073fb562a462eac8d43a753378b9db"}, + {file = "pyright-1.1.306.tar.gz", hash = "sha256:16d5d198be64de497d5f9002000a271176c381e21b977ca5566cf779b643c9ed"}, ] [package.dependencies] @@ -892,18 +874,17 @@ dev = ["twine (>=3.4.1)"] [[package]] name = "pytest" -version = "7.2.2" +version = "7.3.1" description = "pytest: simple powerful testing with Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.2.2-py3-none-any.whl", hash = "sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e"}, - {file = "pytest-7.2.2.tar.gz", hash = "sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4"}, + {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, + {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, ] [package.dependencies] -attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} @@ -913,7 +894,7 @@ pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] [[package]] name = "pytest-asyncio" @@ -970,14 +951,14 @@ six = ">=1.5" [[package]] name = "python-engineio" -version = "4.3.4" +version = "4.4.1" description = "Engine.IO server and client for Python" category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "python-engineio-4.3.4.tar.gz", hash = "sha256:d8d8b072799c36cadcdcc2b40d2a560ce09797ab3d2d596b2ad519a5e4df19ae"}, - {file = "python_engineio-4.3.4-py3-none-any.whl", hash = "sha256:7454314a529bba20e745928601ffeaf101c1b5aca9a6c4e48ad397803d10ea0c"}, + {file = "python-engineio-4.4.1.tar.gz", hash = "sha256:eb3663ecb300195926b526386f712dff84cd092c818fb7b62eeeda9160120c29"}, + {file = "python_engineio-4.4.1-py3-none-any.whl", hash = "sha256:28ab67f94cba2e5f598cbb04428138fd6bb8b06d3478c939412da445f24f0773"}, ] [package.extras] @@ -1000,14 +981,14 @@ six = ">=1.4.0" [[package]] name = "python-socketio" -version = "5.7.2" +version = "5.8.0" description = "Socket.IO server and client for Python" category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "python-socketio-5.7.2.tar.gz", hash = "sha256:92395062d9db3c13d30e7cdedaa0e1330bba78505645db695415f9a3c628d097"}, - {file = "python_socketio-5.7.2-py3-none-any.whl", hash = "sha256:d9a9f047e6fdd306c852fbac36516f4b495c2096f8ad9ceb8803b8e5ff5622e3"}, + {file = "python-socketio-5.8.0.tar.gz", hash = "sha256:e714f4dddfaaa0cb0e37a1e2deef2bb60590a5b9fea9c343dd8ca5e688416fd9"}, + {file = "python_socketio-5.8.0-py3-none-any.whl", hash = "sha256:7adb8867aac1c2929b9c1429f1c02e12ca4c36b67c807967393e367dfbb01441"}, ] [package.dependencies] @@ -1020,14 +1001,14 @@ client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] [[package]] name = "pytz" -version = "2022.7.1" +version = "2023.3" description = "World timezone definitions, modern and historical" category = "dev" optional = false python-versions = "*" files = [ - {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"}, - {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"}, + {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, + {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, ] [[package]] @@ -1082,18 +1063,18 @@ files = [ [[package]] name = "redis" -version = "4.5.1" +version = "4.5.4" description = "Python client for Redis database and key-value store" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "redis-4.5.1-py3-none-any.whl", hash = "sha256:5deb072d26e67d2be1712603bfb7947ec3431fb0eec9c578994052e33035af6d"}, - {file = "redis-4.5.1.tar.gz", hash = "sha256:1eec3741cda408d3a5f84b78d089c8b8d895f21b3b050988351e925faf202864"}, + {file = "redis-4.5.4-py3-none-any.whl", hash = "sha256:2c19e6767c474f2e85167909061d525ed65bea9301c0770bb151e041b7ac89a2"}, + {file = "redis-4.5.4.tar.gz", hash = "sha256:73ec35da4da267d6847e47f68730fdd5f62e2ca69e3ef5885c6a78a9374c3893"}, ] [package.dependencies] -async-timeout = ">=4.0.2" +async-timeout = {version = ">=4.0.2", markers = "python_version <= \"3.11.2\""} importlib-metadata = {version = ">=1.0", markers = "python_version < \"3.8\""} typing-extensions = {version = "*", markers = "python_version < \"3.8\""} @@ -1167,14 +1148,14 @@ files = [ [[package]] name = "setuptools" -version = "67.5.1" +version = "67.7.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.5.1-py3-none-any.whl", hash = "sha256:1c39d42bda4cb89f7fdcad52b6762e3c309ec8f8715b27c684176b7d71283242"}, - {file = "setuptools-67.5.1.tar.gz", hash = "sha256:15136a251127da2d2e77ac7a1bc231eb504654f7e3346d93613a13f2e2787535"}, + {file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"}, + {file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"}, ] [package.extras] @@ -1284,14 +1265,14 @@ sqlcipher = ["sqlcipher3-binary"] [[package]] name = "sqlalchemy2-stubs" -version = "0.0.2a32" +version = "0.0.2a34" description = "Typing Stubs for SQLAlchemy 1.4" category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "sqlalchemy2-stubs-0.0.2a32.tar.gz", hash = "sha256:2a2cfab71d35ac63bf21ad841d8610cd93a3bd4c6562848c538fa975585c2739"}, - {file = "sqlalchemy2_stubs-0.0.2a32-py3-none-any.whl", hash = "sha256:7f5fb30b0cf7c6b74c50c1d94df77ff32007afee8d80499752eb3fedffdbdfb8"}, + {file = "sqlalchemy2-stubs-0.0.2a34.tar.gz", hash = "sha256:2432137ab2fde1a608df4544f6712427b0b7ff25990cfbbc5a9d1db6c8c6f489"}, + {file = "sqlalchemy2_stubs-0.0.2a34-py3-none-any.whl", hash = "sha256:a313220ac793404349899faf1272e821a62dbe1d3a029bd444faa8d3e966cd07"}, ] [package.dependencies] @@ -1461,24 +1442,24 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", [[package]] name = "virtualenv" -version = "20.21.0" +version = "20.23.0" description = "Virtual Python Environment builder" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.21.0-py3-none-any.whl", hash = "sha256:31712f8f2a17bd06234fa97fdf19609e789dd4e3e4bf108c3da71d710651adbc"}, - {file = "virtualenv-20.21.0.tar.gz", hash = "sha256:f50e3e60f990a0757c9b68333c9fdaa72d7188caa417f96af9e52407831a3b68"}, + {file = "virtualenv-20.23.0-py3-none-any.whl", hash = "sha256:6abec7670e5802a528357fdc75b26b9f57d5d92f29c5462ba0fbe45feacc685e"}, + {file = "virtualenv-20.23.0.tar.gz", hash = "sha256:a85caa554ced0c0afbd0d638e7e2d7b5f92d23478d05d17a76daeac8f279f924"}, ] [package.dependencies] distlib = ">=0.3.6,<1" -filelock = ">=3.4.1,<4" -platformdirs = ">=2.4,<4" +filelock = ">=3.11,<4" +platformdirs = ">=3.2,<4" [package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] -test = ["covdefaults (>=2.2.2)", "coverage (>=7.1)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23)", "pytest (>=7.2.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.7.1)", "time-machine (>=2.9)"] [[package]] name = "watchdog" diff --git a/pynecone/app.py b/pynecone/app.py index b4c387b18..8c273981d 100644 --- a/pynecone/app.py +++ b/pynecone/app.py @@ -24,7 +24,7 @@ from pynecone.route import ( get_route_args, verify_route_validity, ) -from pynecone.state import DefaultState, Delta, State, StateManager, StateUpdate +from pynecone.state import DefaultState, State, StateManager, StateUpdate from pynecone.utils import format, types # Define custom types. @@ -62,8 +62,8 @@ class App(Base): # Middleware to add to the app. middleware: List[Middleware] = [] - # Event handlers to trigger when a page loads. - load_events: Dict[str, Union[EventHandler, List[EventHandler]]] = {} + # List of event handlers to trigger when a page loads. + load_events: Dict[str, List[EventHandler]] = {} def __init__(self, *args, **kwargs): """Initialize the app. @@ -149,16 +149,14 @@ class App(Base): allow_origins=["*"], ) - async def preprocess( - self, state: State, event: Event - ) -> Optional[Union[StateUpdate, List[StateUpdate]]]: + async def preprocess(self, state: State, event: Event) -> Optional[StateUpdate]: """Preprocess the event. This is where middleware can modify the event before it is processed. Each middleware is called in the order it was added to the app. - If a middleware returns a delta, the event is not processed and the - delta is returned. + If a middleware returns an update, the event is not processed and the + update is returned. Args: state: The state to preprocess. @@ -176,35 +174,33 @@ class App(Base): return out # type: ignore async def postprocess( - self, state: State, event: Event, delta: Delta - ) -> Optional[Delta]: + self, state: State, event: Event, update: StateUpdate + ) -> StateUpdate: """Postprocess the event. This is where middleware can modify the delta after it is processed. Each middleware is called in the order it was added to the app. - If a middleware returns a delta, the delta is not processed and the - delta is returned. - Args: state: The state to postprocess. event: The event to postprocess. - delta: The delta to postprocess. + update: The current state update. Returns: - An optional state to return. + The state update to return. """ for middleware in self.middleware: if asyncio.iscoroutinefunction(middleware.postprocess): out = await middleware.postprocess( - app=self, state=state, event=event, delta=delta + app=self, state=state, event=event, update=update ) else: out = middleware.postprocess( - app=self, state=state, event=event, delta=delta + app=self, state=state, event=event, update=update ) if out is not None: return out # type: ignore + return update def add_middleware(self, middleware: Middleware, index: Optional[int] = None): """Add middleware to the app. @@ -289,9 +285,26 @@ class App(Base): self._check_routes_conflict(route) self.pages[route] = component + # Add the load events. if on_load: + if not isinstance(on_load, list): + on_load = [on_load] self.load_events[route] = on_load + def get_load_events(self, route: str) -> List[EventHandler]: + """Get the load events for a route. + + Args: + route: The route to get the load events for. + + Returns: + The load events for the route. + """ + route = route.lstrip("/") + if route == "": + route = constants.INDEX_ROUTE + return self.load_events.get(route, []) + def _check_routes_conflict(self, new_route: str): """Verify if there is any conflict between the new route and any existing route. @@ -411,7 +424,7 @@ class App(Base): async def process( app: App, event: Event, sid: str, headers: Dict, client_ip: str -) -> List[StateUpdate]: +) -> StateUpdate: """Process an event. Args: @@ -444,27 +457,21 @@ async def process( substate.router_data = state.router_data # Preprocess the event. - pre = await app.preprocess(state, event) - if isinstance(pre, StateUpdate): - return [pre] - updates = pre + update = await app.preprocess(state, event) - # Apply the event to the state. - if updates is None: - updates = [await state._process(event)] - app.state_manager.set_state(event.token, state) + # Only process the event if there is no update. + if update is None: + # Apply the event to the state. + update = await state._process(event) - # Postprocess the event. - post_list = [] - for update in updates: - post = await app.postprocess(state, event, update.delta) # type: ignore - post_list.append(post) if post else None + # Postprocess the event. + update = await app.postprocess(state, event, update) - if len(post_list) > 0: - return [StateUpdate(delta=post) for post in post_list] + # Update the state. + app.state_manager.set_state(event.token, state) - # Return the updates. - return updates + # Return the update. + return update async def ping() -> str: @@ -598,11 +605,10 @@ class EventNamespace(AsyncNamespace): client_ip = environ["REMOTE_ADDR"] # Process the events. - updates = await process(self.app, event, sid, headers, client_ip) + update = await process(self.app, event, sid, headers, client_ip) # Emit the event. - for update in updates: - await self.emit(str(constants.SocketEvent.EVENT), update.json(), to=sid) # type: ignore + await self.emit(str(constants.SocketEvent.EVENT), update.json(), to=sid) # type: ignore async def on_ping(self, sid): """Event for testing the API endpoint. diff --git a/pynecone/constants.py b/pynecone/constants.py index 47ca09574..44ad25eea 100644 --- a/pynecone/constants.py +++ b/pynecone/constants.py @@ -106,6 +106,8 @@ STATE = "state" EVENTS = "events" # The name of the initial hydrate event. HYDRATE = "hydrate" +# The name of the is_hydrated variable. +IS_HYDRATED = "is_hydrated" # The name of the index page. INDEX_ROUTE = "index" # The name of the document root page. diff --git a/pynecone/event.py b/pynecone/event.py index 2ac73f9de..2ceac4c9c 100644 --- a/pynecone/event.py +++ b/pynecone/event.py @@ -23,7 +23,7 @@ class Event(Base): router_data: Dict[str, Any] = {} # The event payload. - payload: Dict[Any, Any] = {} + payload: Dict[str, Any] = {} class EventHandler(Base): @@ -90,7 +90,7 @@ class EventSpec(Base): local_args: Tuple[Var, ...] = () # The arguments to pass to the function. - args: Optional[Tuple[Tuple[Var, Var], ...]] = () + args: Tuple[Tuple[Var, Var], ...] = () # Whether to upload files. upload: bool = False @@ -318,9 +318,7 @@ def call_event_fn(fn: Callable, arg: Var) -> List[EventSpec]: return events -def get_handler_args( - event_spec: EventSpec, arg: Var -) -> Optional[Tuple[Tuple[Var, Var], ...]]: +def get_handler_args(event_spec: EventSpec, arg: Var) -> Tuple[Tuple[Var, Var], ...]: """Get the handler args for the given event spec. Args: @@ -335,7 +333,7 @@ def get_handler_args( return ( event_spec.args if len(args) > 2 - else (((Var.create_safe(args[1]), arg),) if len(args) == 2 else None) + else (((Var.create_safe(args[1]), arg),) if len(args) == 2 else tuple()) ) @@ -369,7 +367,7 @@ def fix_events( e = e() assert isinstance(e, EventSpec), f"Unexpected event type, {type(e)}." name = format.format_event_handler(e.handler) - payload = {k.name: v.name for k, v in e.args} if e.args else {} + payload = {k.name: v.name for k, v in e.args} # Create an event and append it to the list. out.append( diff --git a/pynecone/middleware/hydrate_middleware.py b/pynecone/middleware/hydrate_middleware.py index 0e7f091e8..779802a44 100644 --- a/pynecone/middleware/hydrate_middleware.py +++ b/pynecone/middleware/hydrate_middleware.py @@ -1,10 +1,10 @@ """Middleware to hydrate the state.""" from __future__ import annotations -from typing import TYPE_CHECKING, Dict, List, Optional, Union +from typing import TYPE_CHECKING, Optional from pynecone import constants -from pynecone.event import Event, EventHandler, get_hydrate_event +from pynecone.event import Event, fix_events, get_hydrate_event from pynecone.middleware.middleware import Middleware from pynecone.state import State, StateUpdate from pynecone.utils import format @@ -13,10 +13,7 @@ if TYPE_CHECKING: from pynecone.app import App -IS_HYDRATED = "is_hydrated" - - -State.add_var(IS_HYDRATED, type_=bool, default_value=False) +State.add_var(constants.IS_HYDRATED, type_=bool, default_value=False) class HydrateMiddleware(Middleware): @@ -24,7 +21,7 @@ class HydrateMiddleware(Middleware): async def preprocess( self, app: App, state: State, event: Event - ) -> Optional[Union[StateUpdate, List[StateUpdate]]]: + ) -> Optional[StateUpdate]: """Preprocess the event. Args: @@ -35,65 +32,19 @@ class HydrateMiddleware(Middleware): Returns: An optional delta or list of state updates to return. """ - if event.name == get_hydrate_event(state): - route = event.router_data.get(constants.RouteVar.PATH, "") - if route == "/": - load_event = app.load_events.get(constants.INDEX_ROUTE) - elif route: - load_event = app.load_events.get(route.lstrip("/")) - else: - load_event = None + # If this is not the hydrate event, return None + if event.name != get_hydrate_event(state): + return None - updates = [] + # Get the initial state. + delta = format.format_state({state.get_name(): state.dict()}) - # first get the initial state - delta = format.format_state({state.get_name(): state.dict()}) - if delta: - updates.append(StateUpdate(delta=delta)) + # Get the route for on_load events. + route = event.router_data.get(constants.RouteVar.PATH, "") - # then apply changes from on_load event handlers on top of that - if load_event: - if not isinstance(load_event, List): - load_event = [load_event] - for single_event in load_event: - updates.append( - await self.execute_load_event( - state, single_event, event.token, event.payload - ) - ) - # extra message telling the client state that hydration is complete - updates.append( - StateUpdate( - delta=format.format_state({state.get_name(): {IS_HYDRATED: True}}) - ) - ) + # Add the on_load events and set is_hydrated to True. + events = [*app.get_load_events(route), type(state).set_is_hydrated(True)] # type: ignore + events = fix_events(events, event.token) - return updates - - async def execute_load_event( - self, state: State, load_event: EventHandler, token: str, payload: Dict - ) -> StateUpdate: - """Execute single load event. - - Args: - state: The client state. - load_event: A single load event to execute. - token: Client token - payload: The event payload - - Returns: - A state Update. - - Raises: - ValueError: If the state value is None. - """ - substate_path = format.format_event_handler(load_event).split(".") - ex_state = state.get_substate(substate_path[:-1]) - if not ex_state: - raise ValueError( - "The value of state cannot be None when processing an on-load event." - ) - - return await state._process_event( - handler=load_event, state=ex_state, payload=payload, token=token - ) + # Return the state update. + return StateUpdate(delta=delta, events=events) diff --git a/pynecone/middleware/logging_middleware.py b/pynecone/middleware/logging_middleware.py index 351364686..32e6b56af 100644 --- a/pynecone/middleware/logging_middleware.py +++ b/pynecone/middleware/logging_middleware.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING from pynecone.event import Event from pynecone.middleware.middleware import Middleware -from pynecone.state import Delta, State +from pynecone.state import State, StateUpdate if TYPE_CHECKING: from pynecone.app import App @@ -24,13 +24,15 @@ class LoggingMiddleware(Middleware): """ print(f"Event {event}") - async def postprocess(self, app: App, state: State, event: Event, delta: Delta): + async def postprocess( + self, app: App, state: State, event: Event, update: StateUpdate + ): """Postprocess the event. Args: app: The app to apply the middleware to. state: The client state. event: The event to postprocess. - delta: The delta to postprocess. + update: The current state update. """ - print(f"Delta {delta}") + print(f"Update {update}") diff --git a/pynecone/middleware/middleware.py b/pynecone/middleware/middleware.py index b7f792053..179b8b6dc 100644 --- a/pynecone/middleware/middleware.py +++ b/pynecone/middleware/middleware.py @@ -2,11 +2,11 @@ from __future__ import annotations from abc import ABC -from typing import TYPE_CHECKING, List, Optional, Union +from typing import TYPE_CHECKING, Optional from pynecone.base import Base from pynecone.event import Event -from pynecone.state import Delta, State, StateUpdate +from pynecone.state import State, StateUpdate if TYPE_CHECKING: from pynecone.app import App @@ -17,7 +17,7 @@ class Middleware(Base, ABC): async def preprocess( self, app: App, state: State, event: Event - ) -> Optional[Union[StateUpdate, List[StateUpdate]]]: + ) -> Optional[StateUpdate]: """Preprocess the event. Args: @@ -26,22 +26,22 @@ class Middleware(Base, ABC): event: The event to preprocess. Returns: - An optional state to return. + An optional state update to return. """ return None async def postprocess( - self, app: App, state: State, event: Event, delta - ) -> Optional[Delta]: + self, app: App, state: State, event: Event, update: StateUpdate + ) -> StateUpdate: """Postprocess the event. Args: app: The app. state: The client state. event: The event to postprocess. - delta: The delta to postprocess. + update: The current state update. Returns: An optional state to return. """ - return None + return update diff --git a/pynecone/utils/format.py b/pynecone/utils/format.py index d3fdf3786..cdb2ea780 100644 --- a/pynecone/utils/format.py +++ b/pynecone/utils/format.py @@ -286,20 +286,13 @@ def format_event(event_spec: EventSpec) -> str: Returns: The compiled event. """ - args = ( - ",".join( - [ - ":".join( - ( - name.name, - json.dumps(val.name) if val.is_string else val.full_name, - ) - ) - for name, val in event_spec.args - ] - ) - if event_spec.args is not None - else "" + args = ",".join( + [ + ":".join( + (name.name, json.dumps(val.name) if val.is_string else val.full_name) + ) + for name, val in event_spec.args + ] ) return f"E(\"{format_event_handler(event_spec.handler)}\", {wrap(args, '{')})" diff --git a/pyproject.toml b/pyproject.toml index bc4703369..ac97d6b9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pynecone" -version = "0.1.28" +version = "0.1.29" description = "Web apps in pure Python." license = "Apache-2.0" authors = [ diff --git a/tests/middleware/test_hydrate_middleware.py b/tests/middleware/test_hydrate_middleware.py index 0bc13de8e..8a43cbec7 100644 --- a/tests/middleware/test_hydrate_middleware.py +++ b/tests/middleware/test_hydrate_middleware.py @@ -1,10 +1,11 @@ -from typing import Any, Dict, List +from typing import Any, Dict import pytest from pynecone.app import App -from pynecone.middleware.hydrate_middleware import IS_HYDRATED, HydrateMiddleware -from pynecone.state import State +from pynecone.constants import IS_HYDRATED +from pynecone.middleware.hydrate_middleware import HydrateMiddleware +from pynecone.state import State, StateUpdate def exp_is_hydrated(state: State) -> Dict[str, Any]: @@ -16,7 +17,7 @@ def exp_is_hydrated(state: State) -> Dict[str, Any]: Returns: dict similar to that returned by `State.get_delta` with IS_HYDRATED: True """ - return {state.get_name(): {IS_HYDRATED: True}} + return {state.get_name(): {IS_HYDRATED: "true"}} class TestState(State): @@ -77,33 +78,41 @@ def hydrate_middleware() -> HydrateMiddleware: @pytest.mark.asyncio @pytest.mark.parametrize( - "state, expected, event_fixture", + "State, expected, event_fixture", [ (TestState, {"test_state": {"num": 1}}, "event1"), (TestState2, {"test_state2": {"num": 1}}, "event2"), (TestState3, {"test_state3": {"num": 1}}, "event3"), ], ) -async def test_preprocess(state, hydrate_middleware, request, event_fixture, expected): +async def test_preprocess(State, hydrate_middleware, request, event_fixture, expected): """Test that a state hydrate event is processed correctly. Args: - state: state to process event + State: state to process event hydrate_middleware: instance of HydrateMiddleware request: pytest fixture request event_fixture: The event fixture(an Event) expected: expected delta """ - app = App(state=state, load_events={"index": state.test_handler}) + app = App(state=State, load_events={"index": [State.test_handler]}) + state = State() - result = await hydrate_middleware.preprocess( - app=app, event=request.getfixturevalue(event_fixture), state=state() + update = await hydrate_middleware.preprocess( + app=app, event=request.getfixturevalue(event_fixture), state=state ) - assert isinstance(result, List) - assert len(result) == 3 - assert result[0].delta == {state().get_name(): state().dict()} - assert result[1].delta == expected - assert result[2].delta == exp_is_hydrated(state()) + assert isinstance(update, StateUpdate) + assert update.delta == {state.get_name(): state.dict()} + events = update.events + assert len(events) == 2 + + # Apply the on_load event. + update = await state._process(events[0]) + assert update.delta == expected + + # Apply the hydrate event. + update = await state._process(events[1]) + assert update.delta == exp_is_hydrated(state) @pytest.mark.asyncio @@ -118,16 +127,23 @@ async def test_preprocess_multiple_load_events(hydrate_middleware, event1): state=TestState, load_events={"index": [TestState.test_handler, TestState.test_handler]}, ) + state = TestState() - result = await hydrate_middleware.preprocess( - app=app, event=event1, state=TestState() - ) - assert isinstance(result, List) - assert len(result) == 4 - assert result[0].delta == {"test_state": TestState().dict()} - assert result[1].delta == {"test_state": {"num": 1}} - assert result[2].delta == {"test_state": {"num": 2}} - assert result[3].delta == exp_is_hydrated(TestState()) + update = await hydrate_middleware.preprocess(app=app, event=event1, state=state) + assert isinstance(update, StateUpdate) + assert update.delta == {"test_state": state.dict()} + assert len(update.events) == 3 + + # Apply the events. + events = update.events + update = await state._process(events[0]) + assert update.delta == {"test_state": {"num": 1}} + + update = await state._process(events[1]) + assert update.delta == {"test_state": {"num": 2}} + + update = await state._process(events[2]) + assert update.delta == exp_is_hydrated(state) @pytest.mark.asyncio @@ -138,12 +154,16 @@ async def test_preprocess_no_events(hydrate_middleware, event1): hydrate_middleware: instance of HydrateMiddleware event1: an Event. """ - result = await hydrate_middleware.preprocess( + state = TestState() + update = await hydrate_middleware.preprocess( app=App(state=TestState), event=event1, - state=TestState(), + state=state, ) - assert isinstance(result, List) - assert len(result) == 2 - assert result[0].delta == {"test_state": TestState().dict()} - assert result[1].delta == exp_is_hydrated(TestState()) + assert isinstance(update, StateUpdate) + assert update.delta == {"test_state": state.dict()} + assert len(update.events) == 1 + assert isinstance(update, StateUpdate) + + update = await state._process(update.events[0]) + assert update.delta == exp_is_hydrated(state) diff --git a/tests/test_state.py b/tests/test_state.py index 9fcbd3884..7523130f1 100644 --- a/tests/test_state.py +++ b/tests/test_state.py @@ -4,9 +4,8 @@ import pytest from plotly.graph_objects import Figure from pynecone.base import Base -from pynecone.constants import RouteVar +from pynecone.constants import IS_HYDRATED, RouteVar from pynecone.event import Event, EventHandler -from pynecone.middleware.hydrate_middleware import IS_HYDRATED from pynecone.state import State from pynecone.utils import format from pynecone.var import BaseVar, ComputedVar