diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b8871cccd..7e7643c92 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,6 +49,6 @@ jobs: - run: poetry install --no-interaction - run: poetry run pytest tests - run: poetry run pyright pynecone tests - - run: poetry run pydocstyle pynecone tests + - run: poetry run ruff check . --format github - run: find pynecone tests -name "*.py" -not -path pynecone/pc.py | xargs poetry run darglint - run: poetry run black --check pynecone tests diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3c28d0d50..d3e588ed4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -87,8 +87,8 @@ poetry run pytest tests ``` Next make sure all the following tests pass. This ensures that every new change has proper documentation and type checking. ``` bash +poetry run ruff check . poetry run pyright pynecone tests -poetry run pydocstyle pynecone tests find pynecone tests -name "*.py" -not -path pynecone/pc.py | xargs poetry run darglint ``` Finally run `black` to format your code. diff --git a/poetry.lock b/poetry.lock index c02c484f1..a14165335 100644 --- a/poetry.lock +++ b/poetry.lock @@ -384,14 +384,14 @@ files = [ [[package]] name = "importlib-metadata" -version = "4.13.0" +version = "6.0.0" description = "Read metadata from Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "importlib_metadata-4.13.0-py3-none-any.whl", hash = "sha256:8a8a81bcf996e74fee46f0d16bd3eaa382a7eb20fd82445c3ad11f4090334116"}, - {file = "importlib_metadata-4.13.0.tar.gz", hash = "sha256:dd0173e8f150d6815e098fd354f6414b0f079af4644ddfe90c71e2fc6174346d"}, + {file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"}, + {file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"}, ] [package.dependencies] @@ -399,7 +399,7 @@ typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] @@ -415,24 +415,6 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] -[[package]] -name = "isort" -version = "5.11.5" -description = "A Python utility / library to sort Python imports." -category = "dev" -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "isort-5.11.5-py3-none-any.whl", hash = "sha256:ba1d72fb2595a01c7895a5128f9585a5cc4b6d395f1c8d514989b9a7eb2a8746"}, - {file = "isort-5.11.5.tar.gz", hash = "sha256:6be1f76a507cb2ecf16c7cf14a37e41609ca082330be4e3436a18ef74add55db"}, -] - -[package.extras] -colors = ["colorama (>=0.4.3,<0.5.0)"] -pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] - [[package]] name = "mypy-extensions" version = "1.0.0" @@ -486,22 +468,22 @@ files = [ [[package]] name = "platformdirs" -version = "2.6.2" +version = "3.0.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-2.6.2-py3-none-any.whl", hash = "sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490"}, - {file = "platformdirs-2.6.2.tar.gz", hash = "sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2"}, + {file = "platformdirs-3.0.0-py3-none-any.whl", hash = "sha256:b1d5eb14f221506f50d6604a561f4c5786d9e80355219694a1b244bcd96f4567"}, + {file = "platformdirs-3.0.0.tar.gz", hash = "sha256:8a1228abb1ef82d788f74139988b137e78692984ec7b08eaa6c65f1723af28f9"}, ] [package.dependencies] typing-extensions = {version = ">=4.4", markers = "python_version < \"3.8\""} [package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] +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)"] [[package]] name = "plotly" @@ -617,25 +599,6 @@ typing-extensions = ">=4.1.0" dotenv = ["python-dotenv (>=0.10.4)"] email = ["email-validator (>=1.0.3)"] -[[package]] -name = "pydocstyle" -version = "6.3.0" -description = "Python docstring style checker" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"}, - {file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"}, -] - -[package.dependencies] -importlib-metadata = {version = ">=2.0.0,<5.0.0", markers = "python_version < \"3.8\""} -snowballstemmer = ">=2.2.0" - -[package.extras] -toml = ["tomli (>=1.2.3)"] - [[package]] name = "pygments" version = "2.14.0" @@ -653,14 +616,14 @@ plugins = ["importlib-metadata"] [[package]] name = "pyright" -version = "1.1.292" +version = "1.1.293" description = "Command line wrapper for pyright" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pyright-1.1.292-py3-none-any.whl", hash = "sha256:23d1f14b15afe38bb7a7117b9861ad0546aff078da312d294e60a727445c23ff"}, - {file = "pyright-1.1.292.tar.gz", hash = "sha256:035ea1af6fabfdcc80c0afb545f677bd377114157d69779cce2a642ff894e51c"}, + {file = "pyright-1.1.293-py3-none-any.whl", hash = "sha256:afc05309e775a9869c864da4e8c0c7a3e3be9d8fe202e780c3bae981bbb13936"}, + {file = "pyright-1.1.293.tar.gz", hash = "sha256:9397fdfcbc684fe5b87abbf9c27f540fe3b8d75999a5f187519cae1d065be38c"}, ] [package.dependencies] @@ -772,14 +735,14 @@ client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] [[package]] name = "redis" -version = "4.4.2" +version = "4.5.1" description = "Python client for Redis database and key-value store" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "redis-4.4.2-py3-none-any.whl", hash = "sha256:e6206448e2f8a432871d07d432c13ed6c2abcf6b74edb436c99752b1371be387"}, - {file = "redis-4.4.2.tar.gz", hash = "sha256:a010f6cb7378065040a02839c3f75c7e0fb37a87116fb4a95be82a95552776c7"}, + {file = "redis-4.5.1-py3-none-any.whl", hash = "sha256:5deb072d26e67d2be1712603bfb7947ec3431fb0eec9c578994052e33035af6d"}, + {file = "redis-4.5.1.tar.gz", hash = "sha256:1eec3741cda408d3a5f84b78d089c8b8d895f21b3b050988351e925faf202864"}, ] [package.dependencies] @@ -829,16 +792,42 @@ typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9 [package.extras] jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] +[[package]] +name = "ruff" +version = "0.0.244" +description = "An extremely fast Python linter, written in Rust." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.0.244-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:5d65a0adffa51314cf9f1036c51dbcde0462b23b49a3d8e3a696a221f9f46f54"}, + {file = "ruff-0.0.244-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:3d6bf5094f2c447f5ff8d10c670dc1bc8b7f70cb5f4e43afe1d0624b934c1284"}, + {file = "ruff-0.0.244-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0f54790b297d5df8120a348c91426a0375c40f62880d30438e46922399b29bf"}, + {file = "ruff-0.0.244-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:88e263e3d7267b4b10f5c1fc1446c5d6b47824c6d78e5c3a97ef79c83d9cb837"}, + {file = "ruff-0.0.244-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8044c79098e3f2deaf970ab468bf5661b193163369bfe5bbda636e6363aa7932"}, + {file = "ruff-0.0.244-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:258e5e3386a8efdff9f253395cc03a3a88204442ac8db50aeb0a529e2862d57b"}, + {file = "ruff-0.0.244-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd09c523aeed4d81f358093dc4df384a4db42ff5f9627c9506c26c2becbe19a7"}, + {file = "ruff-0.0.244-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c98f0d4a4e052e8b0e27b47e83563026d749b07a21a097780cd283c2f885ad3c"}, + {file = "ruff-0.0.244-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2359f840c95364d779b86a822fe025fa416eb14adc661c1263bc39e90065f0bd"}, + {file = "ruff-0.0.244-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8b85ced1e75b7cf1dd90d0708f8e46e2d58fc124334492cc5103f24d832a3922"}, + {file = "ruff-0.0.244-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9c2d49c2021bf80f3e66968c1a41f89061911ffb7ed1f0d39a3204a45fc97ba7"}, + {file = "ruff-0.0.244-py3-none-musllinux_1_2_i686.whl", hash = "sha256:da77d573c7a5b27bad43468fb7e47e78e22715426beb4e673106d24a9a584838"}, + {file = "ruff-0.0.244-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:9f16fc3380753310af2a10e2867dfc133849e51c545561ec0a389aa93b3058b0"}, + {file = "ruff-0.0.244-py3-none-win32.whl", hash = "sha256:b3fc70a4c5d5a0ab8e5b3c3e818ca224913eee84f65bf63ee212af2bbd5f1792"}, + {file = "ruff-0.0.244-py3-none-win_amd64.whl", hash = "sha256:78bbc5d1cca0a8752f6e4b3f4485f4c4f2428543a0777d1bde865aa43bdab190"}, + {file = "ruff-0.0.244.tar.gz", hash = "sha256:7c05773e990348a6d7628b9b7294fe76303bc870dd94d9c34154bc1560053050"}, +] + [[package]] name = "setuptools" -version = "67.1.0" +version = "67.2.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.1.0-py3-none-any.whl", hash = "sha256:a7687c12b444eaac951ea87a9627c4f904ac757e7abdc5aac32833234af90378"}, - {file = "setuptools-67.1.0.tar.gz", hash = "sha256:e261cdf010c11a41cb5cb5f1bf3338a7433832029f559a6a7614bd42a967c300"}, + {file = "setuptools-67.2.0-py3-none-any.whl", hash = "sha256:16ccf598aab3b506593c17378473978908a2734d7336755a8769b480906bec1c"}, + {file = "setuptools-67.2.0.tar.gz", hash = "sha256:b440ee5f7e607bb8c9de15259dba2583dd41a38879a7abc1d43a71c59524da48"}, ] [package.extras] @@ -858,18 +847,6 @@ files = [ {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, ] -[[package]] -name = "snowballstemmer" -version = "2.2.0" -description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, - {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, -] - [[package]] name = "sqlalchemy" version = "1.4.41" @@ -999,14 +976,14 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyam [[package]] name = "tenacity" -version = "8.1.0" +version = "8.2.0" description = "Retry code until it succeeds" category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "tenacity-8.1.0-py3-none-any.whl", hash = "sha256:35525cd47f82830069f0d6b73f7eb83bc5b73ee2fff0437952cedf98b27653ac"}, - {file = "tenacity-8.1.0.tar.gz", hash = "sha256:e48c437fdf9340f5666b92cd7990e96bc5fc955e1298baf4a907e3972067a445"}, + {file = "tenacity-8.2.0-py3-none-any.whl", hash = "sha256:b723061a78ed0f4524190eae321d3d84100227d51c5677035b6615d91895e0d6"}, + {file = "tenacity-8.2.0.tar.gz", hash = "sha256:a43bcd8910406e0884ca0db3db7bed581f389c1d05165e992a1ddabfc81df05e"}, ] [package.extras] @@ -1125,14 +1102,14 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", [[package]] name = "zipp" -version = "3.12.0" +version = "3.12.1" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "zipp-3.12.0-py3-none-any.whl", hash = "sha256:9eb0a4c5feab9b08871db0d672745b53450d7f26992fd1e4653aa43345e97b86"}, - {file = "zipp-3.12.0.tar.gz", hash = "sha256:73efd63936398aac78fd92b6f4865190119d6c91b531532e798977ea8dd402eb"}, + {file = "zipp-3.12.1-py3-none-any.whl", hash = "sha256:6c4fe274b8f85ec73c37a8e4e3fa00df9fb9335da96fb789e3b96b318e5097b3"}, + {file = "zipp-3.12.1.tar.gz", hash = "sha256:a3cac813d40993596b39ea9e93a18e8a2076d5c378b8bc88ec32ab264e04ad02"}, ] [package.extras] @@ -1142,4 +1119,4 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "2.0" python-versions = "^3.7" -content-hash = "dbef0407da32ffd7878a44913923144d62359cfa057c3942f421d7bdae84c4bf" +content-hash = "29af23359858d18a743ff85426e7496fb7e47bdda6d746294aea4a360df6e617" diff --git a/pynecone/app.py b/pynecone/app.py index f5ac0263b..c2a65b34c 100644 --- a/pynecone/app.py +++ b/pynecone/app.py @@ -33,7 +33,7 @@ class App(Base): api: FastAPI = None # type: ignore # The Socket.IO AsyncServer. - sio: AsyncServer = None + sio: Optional[AsyncServer] = None # The state class to use for the app. state: Type[State] = DefaultState diff --git a/pynecone/compiler/compiler.py b/pynecone/compiler/compiler.py index 3c10c9b95..297fbfc27 100644 --- a/pynecone/compiler/compiler.py +++ b/pynecone/compiler/compiler.py @@ -3,7 +3,7 @@ from __future__ import annotations import json from functools import wraps -from typing import TYPE_CHECKING, Callable, List, Set, Tuple, Type +from typing import Callable, List, Set, Tuple, Type from pynecone import constants from pynecone.compiler import templates, utils diff --git a/pynecone/compiler/utils.py b/pynecone/compiler/utils.py index bce94d58f..40a072bb3 100644 --- a/pynecone/compiler/utils.py +++ b/pynecone/compiler/utils.py @@ -8,6 +8,7 @@ from pynecone import constants, utils from pynecone.compiler import templates from pynecone.components.base import ( Body, + ColorModeScript, Description, DocumentHead, Head, @@ -17,7 +18,6 @@ from pynecone.components.base import ( Main, Script, Title, - ColorModeScript, ) from pynecone.components.component import Component, CustomComponent, ImportDict from pynecone.state import State diff --git a/pynecone/components/__init__.py b/pynecone/components/__init__.py index b3c0f15d0..3a6fac1e8 100644 --- a/pynecone/components/__init__.py +++ b/pynecone/components/__init__.py @@ -19,7 +19,6 @@ from .typography import * if TYPE_CHECKING: from typing import Any - from pynecone.var import Var # Add the convenience methods for all the components. locals().update( @@ -109,9 +108,10 @@ def cond(condition: Any, c1: Any, c2: Any = None): The conditional component. """ # Import here to avoid circular imports. - from .tags.tag import PropCond from pynecone.var import Var + from .tags.tag import PropCond + # Convert the condition to a Var. cond_var = Var.create(condition) assert cond_var is not None, "The condition must be set." diff --git a/pynecone/components/base/__init__.py b/pynecone/components/base/__init__.py index e4fedf206..8c83f8fbf 100644 --- a/pynecone/components/base/__init__.py +++ b/pynecone/components/base/__init__.py @@ -1,7 +1,7 @@ """Base components.""" from .body import Body -from .document import DocumentHead, Html, Main, Script, ColorModeScript +from .document import ColorModeScript, DocumentHead, Html, Main, Script from .head import Head from .link import Link from .meta import Description, Image, Title diff --git a/pynecone/components/base/body.py b/pynecone/components/base/body.py index 55c76eda7..7626a94c4 100644 --- a/pynecone/components/base/body.py +++ b/pynecone/components/base/body.py @@ -2,7 +2,6 @@ from pynecone.components.component import Component from pynecone.components.tags import Tag -from pynecone.var import Var class Body(Component): diff --git a/pynecone/components/base/meta.py b/pynecone/components/base/meta.py index f01612408..a7fd114c2 100644 --- a/pynecone/components/base/meta.py +++ b/pynecone/components/base/meta.py @@ -4,7 +4,6 @@ from typing import Optional from pynecone.components.base.bare import Bare from pynecone.components.component import Component -from pynecone.components.tags import Tag class Title(Component): diff --git a/pynecone/components/component.py b/pynecone/components/component.py index 3ad2b3bde..a3aaf8ee8 100644 --- a/pynecone/components/component.py +++ b/pynecone/components/component.py @@ -5,7 +5,7 @@ from __future__ import annotations import typing from abc import ABC from functools import wraps -from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type, Union +from typing import Any, Callable, Dict, List, Optional, Set, Type, Union from pynecone import constants, utils from pynecone.base import Base @@ -292,7 +292,7 @@ class Component(Base, ABC): # Special case for props named `type_`. if hasattr(self, "type_"): - props["type"] = getattr(self, "type_") + props["type"] = self.type_ # type: ignore return tag.add_props(**props) diff --git a/pynecone/components/datadisplay/list.py b/pynecone/components/datadisplay/list.py index 85e33fdc2..2fb4eb5bb 100644 --- a/pynecone/components/datadisplay/list.py +++ b/pynecone/components/datadisplay/list.py @@ -1,6 +1,6 @@ """List components.""" -from pynecone.components.component import Component +from pynecone.components import Component from pynecone.components.libs.chakra import ChakraComponent from pynecone.var import Var diff --git a/pynecone/components/datadisplay/table.py b/pynecone/components/datadisplay/table.py index 5153f52e9..94ffe794a 100644 --- a/pynecone/components/datadisplay/table.py +++ b/pynecone/components/datadisplay/table.py @@ -1,8 +1,6 @@ """Table components.""" -from typing import List from pynecone.components.component import Component - from pynecone.components.libs.chakra import ChakraComponent from pynecone.var import Var diff --git a/pynecone/components/disclosure/accordion.py b/pynecone/components/disclosure/accordion.py index 58f13b66d..3afb75fca 100644 --- a/pynecone/components/disclosure/accordion.py +++ b/pynecone/components/disclosure/accordion.py @@ -1,8 +1,8 @@ """Container to stack elements with spacing.""" from typing import List, Optional, Union -from pynecone.components.component import Component +from pynecone.components.component import Component from pynecone.components.libs.chakra import ChakraComponent from pynecone.var import Var diff --git a/pynecone/components/disclosure/tabs.py b/pynecone/components/disclosure/tabs.py index 17ce2334d..fedef2932 100644 --- a/pynecone/components/disclosure/tabs.py +++ b/pynecone/components/disclosure/tabs.py @@ -54,7 +54,7 @@ class Tabs(ChakraComponent): for label, panel in items: tabs.append(Tab.create(label)) panels.append(TabPanel.create(panel)) - children = [TabList.create(*tabs), TabPanels.create(*panels)] + children = [TabList.create(*tabs), TabPanels.create(*panels)] # type: ignore return super().create(*children, **props) diff --git a/pynecone/components/forms/editable.py b/pynecone/components/forms/editable.py index 350802896..44fe273ab 100644 --- a/pynecone/components/forms/editable.py +++ b/pynecone/components/forms/editable.py @@ -3,7 +3,6 @@ from typing import Set from pynecone.components.libs.chakra import ChakraComponent -from pynecone.components.tags import Tag from pynecone.var import Var diff --git a/pynecone/components/graphing/plotly.py b/pynecone/components/graphing/plotly.py index 2423777aa..850bd0688 100644 --- a/pynecone/components/graphing/plotly.py +++ b/pynecone/components/graphing/plotly.py @@ -1,9 +1,8 @@ """Component for displaying a plotly graph.""" -from typing import Dict, Union +from typing import Dict from plotly.graph_objects import Figure -from plotly.io import to_json from pynecone.components.component import Component from pynecone.components.tags import Tag diff --git a/pynecone/components/graphing/victory.py b/pynecone/components/graphing/victory.py index 2ccfd3d88..f857184e4 100644 --- a/pynecone/components/graphing/victory.py +++ b/pynecone/components/graphing/victory.py @@ -1,9 +1,8 @@ """Victory graphing components.""" -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional from pynecone.components.component import Component -from pynecone.components.tags import Tag from pynecone.style import Style from pynecone.var import Var diff --git a/pynecone/components/overlay/alertdialog.py b/pynecone/components/overlay/alertdialog.py index 100e5be91..f299d6e05 100644 --- a/pynecone/components/overlay/alertdialog.py +++ b/pynecone/components/overlay/alertdialog.py @@ -3,8 +3,8 @@ from typing import Set from pynecone.components.component import Component -from pynecone.components.media.icon import Icon from pynecone.components.libs.chakra import ChakraComponent +from pynecone.components.media.icon import Icon from pynecone.var import Var diff --git a/pynecone/components/overlay/drawer.py b/pynecone/components/overlay/drawer.py index 9598ebdd8..a01621c38 100644 --- a/pynecone/components/overlay/drawer.py +++ b/pynecone/components/overlay/drawer.py @@ -1,8 +1,8 @@ """Container to stack elements with spacing.""" from typing import Set -from pynecone.components.component import Component +from pynecone.components.component import Component from pynecone.components.libs.chakra import ChakraComponent from pynecone.components.media.icon import Icon from pynecone.var import Var diff --git a/pynecone/components/overlay/menu.py b/pynecone/components/overlay/menu.py index 6d0cfb570..5ef5bde22 100644 --- a/pynecone/components/overlay/menu.py +++ b/pynecone/components/overlay/menu.py @@ -1,8 +1,8 @@ """Menu components.""" from typing import Set -from pynecone.components.component import Component +from pynecone.components.component import Component from pynecone.components.libs.chakra import ChakraComponent from pynecone.var import Var diff --git a/pynecone/components/overlay/modal.py b/pynecone/components/overlay/modal.py index c0843d7f0..2ec3b3d4d 100644 --- a/pynecone/components/overlay/modal.py +++ b/pynecone/components/overlay/modal.py @@ -1,8 +1,8 @@ """Modal components.""" from typing import Set -from pynecone.components.component import Component +from pynecone.components.component import Component from pynecone.components.libs.chakra import ChakraComponent from pynecone.components.media import Icon from pynecone.var import Var diff --git a/pynecone/components/overlay/popover.py b/pynecone/components/overlay/popover.py index abc84641e..6d6583611 100644 --- a/pynecone/components/overlay/popover.py +++ b/pynecone/components/overlay/popover.py @@ -1,9 +1,8 @@ """Popover components.""" from typing import Set -from pynecone.components.component import Component -from pynecone.components.forms.button import Button +from pynecone.components.component import Component from pynecone.components.libs.chakra import ChakraComponent from pynecone.var import Var diff --git a/pynecone/components/tags/tag.py b/pynecone/components/tags/tag.py index e20a62b49..c9f807e64 100644 --- a/pynecone/components/tags/tag.py +++ b/pynecone/components/tags/tag.py @@ -82,16 +82,14 @@ class Tag(Base): return json.dumps(prop) elif isinstance(prop, Figure): - prop = json.loads(to_json(prop))["data"] + prop = json.loads(to_json(prop))["data"] # type: ignore # For dictionaries, convert any properties to strings. else: if isinstance(prop, dict): # Convert any var keys to strings. prop = { - key: str(val) - if isinstance(val, Var) or isinstance(val, PropCond) - else val + key: str(val) if isinstance(val, (Var, PropCond)) else val for key, val in prop.items() } diff --git a/pynecone/components/typography/highlight.py b/pynecone/components/typography/highlight.py index 30ecb1d79..77a700bf6 100644 --- a/pynecone/components/typography/highlight.py +++ b/pynecone/components/typography/highlight.py @@ -1,6 +1,6 @@ """A heading component.""" -from typing import List, Union +from typing import List from pynecone.components.libs.chakra import ChakraComponent from pynecone.var import Var diff --git a/pynecone/pc.py b/pynecone/pc.py index 6189b3f8d..6ac0a81da 100644 --- a/pynecone/pc.py +++ b/pynecone/pc.py @@ -8,8 +8,6 @@ import typer from pynecone import constants, utils -from rich.prompt import Prompt - # Create the app. cli = typer.Typer() diff --git a/pynecone/state.py b/pynecone/state.py index 8c3174880..a499a9342 100644 --- a/pynecone/state.py +++ b/pynecone/state.py @@ -13,7 +13,7 @@ from redis import Redis from pynecone import constants, utils from pynecone.base import Base from pynecone.event import Event, EventHandler, window_alert -from pynecone.var import BaseVar, ComputedVar, PCList, Var +from pynecone.var import BaseVar, ComputedVar, Var Delta = Dict[str, Any] diff --git a/pynecone/style.py b/pynecone/style.py index cfbcf0162..b7caefea8 100644 --- a/pynecone/style.py +++ b/pynecone/style.py @@ -6,7 +6,6 @@ from pynecone import constants, utils from pynecone.event import EventChain from pynecone.var import BaseVar, Var - toggle_color_mode = BaseVar(name=constants.TOGGLE_COLOR_MODE, type_=EventChain) diff --git a/pynecone/telemetry.py b/pynecone/telemetry.py index f32aebd0c..28c62367d 100644 --- a/pynecone/telemetry.py +++ b/pynecone/telemetry.py @@ -1,8 +1,9 @@ """Anonymous telemetry for Pynecone.""" -import platform -import psutil import multiprocessing +import platform + +import psutil from pynecone import constants from pynecone.base import Base diff --git a/pynecone/utils.py b/pynecone/utils.py index 3bd3ee062..ed160e924 100644 --- a/pynecone/utils.py +++ b/pynecone/utils.py @@ -18,7 +18,6 @@ from collections import defaultdict from pathlib import Path from subprocess import DEVNULL, PIPE, STDOUT from types import ModuleType -from typing import _GenericAlias # type: ignore from typing import ( TYPE_CHECKING, Any, @@ -29,11 +28,12 @@ from typing import ( Tuple, Type, Union, + _GenericAlias, # type: ignore # type: ignore ) -from typing import _GenericAlias # type: ignore from urllib.parse import urlparse -import psutil + import plotly.graph_objects as go +import psutil import typer import uvicorn from plotly.io import to_json @@ -298,7 +298,7 @@ def get_config() -> Config: try: return __import__(constants.CONFIG_MODULE).config except ImportError: - return Config(app_name="") + return Config(app_name="") # type: ignore def check_node_version(min_version): @@ -319,7 +319,7 @@ def check_node_version(min_version): version = result.stdout.decode().strip().split("v")[1] # Compare the version numbers return version.split(".") >= min_version.split(".") - except Exception as e: + except Exception: return False @@ -475,10 +475,12 @@ def is_latest_template() -> bool: Returns: Whether the app is using the latest template. """ - template_version = open(constants.PCVERSION_TEMPLATE_FILE).read() + with open(constants.PCVERSION_TEMPLATE_FILE) as f: # type: ignore + template_version = f.read() if not os.path.exists(constants.PCVERSION_APP_FILE): return False - app_version = open(constants.PCVERSION_APP_FILE).read() + with open(constants.PCVERSION_APP_FILE) as f: # type: ignore + app_version = f.read() return app_version >= template_version @@ -1149,7 +1151,7 @@ def format_state(value: Any) -> Dict: # Convert plotly figures to JSON. if isinstance(value, go.Figure): - return json.loads(to_json(value))["data"] + return json.loads(to_json(value))["data"] # type: ignore # Convert pandas dataframes to JSON. if is_dataframe(type(value)): diff --git a/pynecone/var.py b/pynecone/var.py index ce86ceaf3..754e77908 100644 --- a/pynecone/var.py +++ b/pynecone/var.py @@ -3,8 +3,17 @@ from __future__ import annotations import json from abc import ABC -from typing import _GenericAlias # type: ignore -from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Type, Union +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Dict, + List, + Optional, + Type, + Union, + _GenericAlias, # type: ignore +) from plotly.graph_objects import Figure from plotly.io import to_json @@ -61,7 +70,7 @@ class Var(ABC): # Special case for plotly figures. if isinstance(value, Figure): - value = json.loads(to_json(value))["data"] + value = json.loads(to_json(value))["data"] # type: ignore type_ = Figure name = value if isinstance(value, str) else json.dumps(value) diff --git a/pyproject.toml b/pyproject.toml index 3315a91ca..2f86b5f9d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,11 +42,10 @@ pytest = "^7.1.2" pytest-mock = "^3.10.0" pyright = "^1.1.229" darglint = "^1.8.1" -pydocstyle = "^6.1.1" toml = "^0.10.2" -isort = "^5.10.1" pytest-asyncio = "^0.20.1" black = "^22.10.0" +ruff = "^0.0.244" [tool.poetry.scripts] pc = "pynecone.pc:main" @@ -55,4 +54,18 @@ pc = "pynecone.pc:main" requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" -[tool.pyright] \ No newline at end of file +[tool.pyright] + +[tool.ruff] + +select = ["B", "D", "E", "F", "I", "SIM", "W"] + +ignore = ["B008", "D203", "D205", "D213", "D401", "D406", "D407", "E501", "F403", "F405", "F541"] + +target-version = "py37" + +[tool.ruff.per-file-ignores] + +"__init__.py" = ["F401"] +"tests/*.py" = ["D100", "D103", "D104"] +"pynecone/.templates/*.py" = ["D100", "D103", "D104"] \ No newline at end of file diff --git a/tests/components/graphing/test_victory_data.py b/tests/components/graphing/test_victory_data.py index e50db1cb6..8bfa58581 100644 --- a/tests/components/graphing/test_victory_data.py +++ b/tests/components/graphing/test_victory_data.py @@ -1,5 +1,3 @@ -import pytest - from pynecone import data # Test data. diff --git a/tests/components/layout/test_cond.py b/tests/components/layout/test_cond.py index 4a9e5b280..6e76a81c8 100644 --- a/tests/components/layout/test_cond.py +++ b/tests/components/layout/test_cond.py @@ -13,7 +13,7 @@ from pynecone.components.typography.text import Text @pytest.fixture def cond_state(request): class CondState(pc.State): - value: request.param["value_type"] = request.param["value"] + value: request.param["value_type"] = request.param["value"] # noqa return CondState @@ -28,7 +28,7 @@ def cond_state(request): indirect=True, ) def test_validate_cond(cond_state: pc.Var): - """Test if cond can be a pc.Val with any values + """Test if cond can be a pc.Val with any values. Args: cond_state: A fixture. @@ -71,18 +71,18 @@ def test_prop_cond(c1: Any, c2: Any): assert isinstance(prop_cond, PropCond) assert prop_cond.prop1 == c1 assert prop_cond.prop2 == c2 - assert prop_cond.cond == True + assert prop_cond.cond == True # noqa def test_cond_no_else(): - """Test if cond can be used without else""" + """Test if cond can be used without else.""" # Components should support the use of cond without else comp = cond(True, Text.create("hello")) assert isinstance(comp, Cond) - assert comp.cond == True + assert comp.cond == True # noqa assert comp.comp1 == Text.create("hello") assert comp.comp2 == Fragment.create() # Props do not support the use of cond without else with pytest.raises(ValueError): - prop_cond = cond(True, "hello") + cond(True, "hello") diff --git a/tests/components/test_tag.py b/tests/components/test_tag.py index 8593025ee..a350938ce 100644 --- a/tests/components/test_tag.py +++ b/tests/components/test_tag.py @@ -1,10 +1,8 @@ -import platform from typing import Dict import pytest -from pynecone.components import Box -from pynecone.components.tags import CondTag, IterTag, Tag +from pynecone.components.tags import CondTag, Tag from pynecone.components.tags.tag import PropCond from pynecone.event import EventChain, EventHandler, EventSpec from pynecone.var import BaseVar, Var @@ -144,7 +142,6 @@ def test_format_tag(tag: Tag, expected: str, windows_platform: bool): expected: The expected formatted tag. windows_platform: Whether the system is windows. """ - expected = expected.replace("\n", "\r\n") if windows_platform else expected assert str(tag) == expected diff --git a/tests/test_app.py b/tests/test_app.py index ff02c239f..3c50e35cc 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -1,11 +1,10 @@ import os.path -from typing import List, Tuple, Type +from typing import Type import pytest from pynecone.app import App, DefaultState from pynecone.components import Box -from pynecone.event import Event from pynecone.middleware import HydrateMiddleware from pynecone.state import State from pynecone.style import Style diff --git a/tests/test_event.py b/tests/test_event.py index 0f56382b6..c4f648ea3 100644 --- a/tests/test_event.py +++ b/tests/test_event.py @@ -1,6 +1,4 @@ -import pytest - -from pynecone.event import Event, EventHandler, EventSpec +from pynecone.event import Event, EventHandler from pynecone.var import Var diff --git a/tests/test_propcond.py b/tests/test_propcond.py index 2019870bf..326ec5223 100644 --- a/tests/test_propcond.py +++ b/tests/test_propcond.py @@ -3,8 +3,8 @@ from typing import Any import pytest from pynecone.components.tags.tag import PropCond -from pynecone.var import BaseVar, Var from pynecone.utils import wrap +from pynecone.var import BaseVar @pytest.mark.parametrize( @@ -16,7 +16,7 @@ from pynecone.utils import wrap ], ) def test_validate_propcond(prop1: Any, prop2: Any): - """Test the creation of conditional props + """Test the creation of conditional props. Args: prop1: truth condition value diff --git a/tests/test_state.py b/tests/test_state.py index 3a1e3bbf5..fc505cb68 100644 --- a/tests/test_state.py +++ b/tests/test_state.py @@ -1,6 +1,7 @@ from typing import Dict, List import pytest +from plotly.graph_objects import Figure from pynecone import utils from pynecone.base import Base @@ -8,7 +9,6 @@ from pynecone.constants import RouteVar from pynecone.event import Event from pynecone.state import State from pynecone.var import BaseVar, ComputedVar -from plotly.graph_objects import Figure class Object(Base): @@ -651,7 +651,7 @@ def test_add_var(test_state): test_state.add_var("dynamic_list", List[int], [5, 10]) assert test_state.dynamic_list == [5, 10] - assert getattr(test_state, "dynamic_list") == [5, 10] + assert test_state.dynamic_list == [5, 10] # how to test that one? # test_state.dynamic_list.append(15) @@ -659,4 +659,4 @@ def test_add_var(test_state): test_state.add_var("dynamic_dict", Dict[str, int], {"k1": 5, "k2": 10}) assert test_state.dynamic_dict == {"k1": 5, "k2": 10} - assert getattr(test_state, "dynamic_dict") == {"k1": 5, "k2": 10} + assert test_state.dynamic_dict == {"k1": 5, "k2": 10} diff --git a/tests/test_telemetry.py b/tests/test_telemetry.py index 54c1431de..4ed83ac2d 100644 --- a/tests/test_telemetry.py +++ b/tests/test_telemetry.py @@ -1,7 +1,6 @@ -import pytest +import json from pynecone import telemetry -import json def versiontuple(v): @@ -15,7 +14,7 @@ def test_telemetry(): # Check that the user OS is one of the supported operating systems. tel.get_os() - assert tel.user_os != None + assert tel.user_os is not None assert tel.user_os in ["Linux", "Darwin", "Java", "Windows"] # Check that the CPU count and memory are greater than 0. @@ -30,12 +29,12 @@ def test_telemetry(): # Check that the Pynecone version is not None. tel.get_python_version() - assert tel.pynecone_version != None + assert tel.pynecone_version is not None # Check that the Python version is greater than 3.7. tel.get_pynecone_version() - assert tel.python_version != None + assert tel.python_version is not None assert versiontuple(tel.python_version) >= versiontuple("3.7") # Check the json method. diff --git a/tests/test_utils.py b/tests/test_utils.py index 743f6c489..878df7322 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -231,7 +231,7 @@ def test_format_route(route: str, expected: bool): def test_setup_frontend(tmp_path, mocker): """Test checking if assets content have been - copied into the .web/public folder + copied into the .web/public folder. Args: tmp_path: root path of test case data directory