diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 0000000..b6b21f1 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,23 @@ +name: pre-commit + +on: + pull_request: + branches: ["main"] + push: + branches: ["main"] + +jobs: + pre-commit: + timeout-minutes: 30 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v2 + with: + python-version: "3.12" + - run: | + pip install pre-commit + pip install pyright + pre-commit run --all-files + env: + SKIP: update-pyi-files diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 810b770..7066642 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,3 +10,9 @@ repos: - id: ruff args: ["--fix", "--exit-non-zero-on-fix"] + - repo: https://github.com/codespell-project/codespell + rev: v2.3.0 + hooks: + - id: codespell + args: [custom_components, "*_demo"] + diff --git a/ag_grid_demo/ag_grid_demo/ag_grid_demo.py b/ag_grid_demo/ag_grid_demo/ag_grid_demo.py index 943f63f..1c9617e 100644 --- a/ag_grid_demo/ag_grid_demo/ag_grid_demo.py +++ b/ag_grid_demo/ag_grid_demo/ag_grid_demo.py @@ -1,9 +1,8 @@ """Welcome to Reflex! This file showcases the custom component in a basic app.""" +import pandas as pd import reflex as rx from reflex_ag_grid import ag_grid -import pandas as pd - df = pd.read_csv( "https://raw.githubusercontent.com/plotly/datasets/master/wind_dataset.csv" @@ -12,7 +11,7 @@ column_defs = [ ag_grid.column_def(field="direction"), ag_grid.column_def(field="strength"), - ag_grid.column_def(field="frequency"), + ag_grid.column_def(field="frequency", cell_renderer=ag_grid.renderers.link), ] @@ -42,8 +41,9 @@ def index(): row_data=df.to_dict("records"), column_defs=column_defs, row_selection="multiple", - on_selection_changed=lambda rows, _0, _1: BasicGridState.set_selection( - rows + on_selection_changed=lambda rows, _0, _1: BasicGridState.setvar( + "selection", + rows, ), width="50vw", ), diff --git a/ag_grid_demo/ag_grid_demo/model_dm.py b/ag_grid_demo/ag_grid_demo/model_dm.py index 5a19160..1fda59d 100644 --- a/ag_grid_demo/ag_grid_demo/model_dm.py +++ b/ag_grid_demo/ag_grid_demo/model_dm.py @@ -2,10 +2,9 @@ import faker import reflex as rx +from reflex_ag_grid.wrapper import ModelWrapper, model_wrapper from sqlmodel import Column, DateTime, Field, func -from reflex_ag_grid.wrapper import model_wrapper, ModelWrapper - class Friend(rx.Model, table=True): name: str diff --git a/custom_components/reflex_ag_grid/__init__.py b/custom_components/reflex_ag_grid/__init__.py index 4552b0c..67fab92 100644 --- a/custom_components/reflex_ag_grid/__init__.py +++ b/custom_components/reflex_ag_grid/__init__.py @@ -31,7 +31,7 @@ "handle_number_filter", "handle_text_filter", "model_wrapper", + "where_filter_def", "where_number_filter", "where_text_filter", - "where_filter_def", ] diff --git a/custom_components/reflex_ag_grid/ag_grid.py b/custom_components/reflex_ag_grid/ag_grid.py index 6d2007f..b08089c 100644 --- a/custom_components/reflex_ag_grid/ag_grid.py +++ b/custom_components/reflex_ag_grid/ag_grid.py @@ -2,15 +2,15 @@ # For wrapping react guide, visit https://reflex.dev/docs/wrapping-react/overview/ +import os from types import SimpleNamespace +from typing import Any, Callable, Literal, Union + import reflex as rx +from reflex.components.el import Div +from reflex.components.props import PropsBase -import os -from typing import Any, Callable, Union from .datasource import Datasource, SSRMDatasource -from reflex.components.props import PropsBase -from typing import Literal -from reflex.components.el import Div def callback_content(iterable: list[str]) -> str: @@ -152,7 +152,7 @@ class AGRenderers(SimpleNamespace): href=rx.Var("params.value", _var_type=str), target="_blank", ), - ).to(dict) # TODO: remove cast after reflex 0.6.6 + ) class ColumnDef(PropsBase): @@ -534,7 +534,7 @@ def select_rows_by_key(self, keys: list[str]) -> rx.event.EventHandler: api.forEachNode(function (node) {{ if (keys_set.has(node.key)) {{ selected_nodes.push(node); - }} + }} }}); api.deselectAll() api.setNodesSelected({{ nodes: selected_nodes, newValue: true }}); @@ -552,7 +552,7 @@ def log_nodes(self) -> rx.event.EventSpec: """ ) - def setGridOption(self, key: str, value: rx.Var) -> rx.event.EventSpec: + def setGridOption(self, key: str, value: rx.Var) -> rx.event.EventSpec: # noqa: N802 return self.api.set_grid_option(key, value) def set_datasource(self, datasource: Datasource): diff --git a/custom_components/reflex_ag_grid/datasource.py b/custom_components/reflex_ag_grid/datasource.py index 3434f49..376c048 100644 --- a/custom_components/reflex_ag_grid/datasource.py +++ b/custom_components/reflex_ag_grid/datasource.py @@ -1,5 +1,4 @@ import reflex as rx - from reflex.base import Base from reflex.config import get_config from reflex.utils import format @@ -10,8 +9,8 @@ class Datasource(Base): uri: str | None = None endpoint_uri: str | None = None - rowCount: rx.Var[int] | int | None = None - getRows: rx.Var | None = None + rowCount: rx.Var[int] | int | None = None # noqa: N815 + getRows: rx.Var | None = None # noqa: N815 def get_uri(self) -> str: return self.uri or ( @@ -86,7 +85,7 @@ def json(self) -> str: class SSRMDatasource(Base): uri: str | None = None endpoint_uri: str | None = None - getRows: rx.Var | None = None + getRows: rx.Var | None = None # noqa: N815 def get_uri(self) -> str: return self.uri or ( diff --git a/custom_components/reflex_ag_grid/handlers.py b/custom_components/reflex_ag_grid/handlers.py index b054f22..bcb9b20 100644 --- a/custom_components/reflex_ag_grid/handlers.py +++ b/custom_components/reflex_ag_grid/handlers.py @@ -3,12 +3,11 @@ import datetime from typing import Any, Type, TypeVar -from sqlmodel import not_, and_, or_ -from sqlmodel.sql.expression import SelectOfScalar +import reflex as rx from sqlalchemy.orm.attributes import InstrumentedAttribute from sqlalchemy.sql.roles import WhereHavingRole - -import reflex as rx +from sqlmodel import and_, not_, or_ +from sqlmodel.sql.expression import SelectOfScalar M = TypeVar("M", bound=rx.Model) @@ -32,7 +31,7 @@ def handle_text_filter(value, filter_def) -> bool: return not value if type == "notBlank": return bool(value) - assert False, f"type {type} does not exist" + raise TypeError(f"type {type} does not exist") def handle_number_filter(value, filter_def) -> bool: @@ -57,7 +56,7 @@ def handle_number_filter(value, filter_def) -> bool: if type == "notBlank": return bool(value) - assert False, f"type {type} does not exist" + raise TypeError(f"type {type} does not exist") def handle_filter_def(value, filter_def) -> bool: @@ -85,13 +84,14 @@ def handle_filter_def(value, filter_def) -> bool: def handle_filter_model(row, filter_model) -> bool: if not filter_model: return True - for field, filter_def in filter_model.items(): - try: + field, filter_def = None, None + try: + for field, filter_def in filter_model.items(): if not handle_filter_def(row[field], filter_def): return False - except Exception as e: - print(f"Error filtering {field} of {row}: {e}") - return False + except Exception as e: + print(f"Error filtering {field} of {row}: {e}") # noqa: T201 + return False return True @@ -122,7 +122,7 @@ def where_text_filter( return or_(value == None, value == "") # noqa: E711 if type == "notBlank": return and_(value != None, value != "") # noqa: E711 - assert False, f"type {type} does not exist" + raise TypeError(f"type {type} does not exist") def where_number_filter( @@ -160,7 +160,7 @@ def where_number_filter( if type == "notBlank": return value != None # noqa: E711 - assert False, f"type {type} does not exist" + raise TypeError(f"type {type} does not exist") def where_filter_def( diff --git a/custom_components/reflex_ag_grid/wrapper.py b/custom_components/reflex_ag_grid/wrapper.py index 7ec1f05..9ee6565 100644 --- a/custom_components/reflex_ag_grid/wrapper.py +++ b/custom_components/reflex_ag_grid/wrapper.py @@ -7,14 +7,13 @@ import json from typing import Any, ClassVar, Generic, Type +import reflex as rx from fastapi import Request from sqlmodel import col, func, select -import reflex as rx - -from reflex_ag_grid.ag_grid import ag_grid, ColumnDef +from reflex_ag_grid.ag_grid import ColumnDef, ag_grid from reflex_ag_grid.datasource import Datasource -from reflex_ag_grid.handlers import apply_filter_model, apply_sort_model, M +from reflex_ag_grid.handlers import M, apply_filter_model, apply_sort_model def _value_setter_signature( @@ -41,12 +40,12 @@ def get_default_column_def( Returns: The column definition. """ - _cdef_kwargs = dict( - sortable=True, - filter=True, - editable=True if value_setter is not None else False, - cell_editor=ag_grid.editors.text, - ) + _cdef_kwargs = { + "sortable": True, + "filter": True, + "editable": value_setter is not None, + "cell_editor": ag_grid.editors.text, + } _cdef_kwargs.update(cdef_kwargs) cdef = ag_grid.column_def( field=field, @@ -100,17 +99,17 @@ def _add_data_route(cls): The backend route will call the _get_data method to fetch the data. """ app = rx.utils.prerequisites.get_app().app - if cls.__data_route__ in app.api.routes: + if cls.__data_route__ in app._api.routes: return - @app.api.get(cls.__data_route__) + @app._api.get(cls.__data_route__) async def get_data( request: Request, state: str, start: int, end: int, - filter_model: str = None, - sort_model: str = None, + filter_model: str | None = None, + sort_model: str | None = None, ): try: token = request.headers["X-Reflex-Client-Token"] @@ -204,13 +203,13 @@ def get_component(cls, *children, **props) -> rx.Component: Returns: The Ag-Grid component. """ - _props = dict( - id=f"ag-grid-{cls.get_full_name()}", - default_col_def={"flex": 1}, - max_blocks_in_cache=4, - cache_block_size=50, - group_default_expanded=None, - ) + _props = { + "id": f"ag-grid-{cls.get_full_name()}", + "default_col_def": {"flex": 1}, + "max_blocks_in_cache": 4, + "cache_block_size": 50, + "group_default_expanded": None, + } _props.update(props) return ag_grid.root( *children, @@ -333,7 +332,7 @@ def _get_column_defs(self) -> list[ColumnDef]: field=field.name, ftype=field.type_, value_setter=type(self).on_value_setter, - editable=True if field.name != "id" else False, + editable=field.name != "id", ) for field in self._model_class.__fields__.values() ] diff --git a/pyproject.toml b/pyproject.toml index 7cc6347..98b43c6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,3 +27,17 @@ dev = ["build", "twine"] [tool.setuptools.packages.find] where = ["custom_components"] + +[tool.ruff] +target-version = "py310" +output-format = "concise" +lint.isort.split-on-trailing-comma = false +lint.select = ["B", "C4", "E", "ERA", "F", "FURB", "I", "N", "PERF", "PTH", "RUF", "SIM", "T", "TRY", "W"] +lint.ignore = ["B008", "D205", "E501", "F403", "SIM115", "RUF006", "RUF008", "RUF012", "TRY0"] +lint.pydocstyle.convention = "google" +include = ["custom_components/**/*.py", "ag_grid_demo/**/*.py"] + +[tool.ruff.lint.per-file-ignores] +"__init__.py" = ["F401"] +"env.py" = ["ALL"] +"*/alembic/*" = ["ALL"]