diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2141bdada67..a61118d5f19 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -54,20 +54,21 @@ repos: require_serial: true - repo: local hooks: - - id: pyright - name: pyright - entry: uv run --no-sync pyright + - id: ty + name: ty + entry: uv run --no-sync ty check language: system types: [python] + pass_filenames: false require_serial: true - repo: local hooks: - # The second opinion the assert_type examples exist for. Always runs: what - # these examples catch is a source change altering an inferred type, so - # scoping the hook to the examples themselves would never fire on the edit - # that broke them. - - id: ty - name: ty + # The assert_type examples, re-checked against the newest Python the project + # supports. Always runs: what these examples catch is a source change altering + # an inferred type, so scoping the hook to the examples themselves would never + # fire on the edit that broke them. + - id: ty-type-checking + name: ty-type-checking entry: uv run --no-sync ty check --python-version 3.14 tests/type_checking language: system always_run: true diff --git a/AGENTS.md b/AGENTS.md index 7a472e5f7f9..8bae4e479e6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -18,8 +18,8 @@ uv run pytest tests/units --cov --no-cov-on-fail --cov-report= # unit tests (> uv run pytest tests/integration # integration tests (slow) uv run ruff check . # lint uv run ruff format . # format -uv run pyright reflex tests # type check -uv run python scripts/check_min_deps.py # validate each package's declared minimum dep versions (pyright in isolated min-version envs; workspace siblings resolve from locally built wheels, all other deps from PyPI). CI passes --wheelhouse instead, reusing the build jobs' artifacts +uv run ty check # type check +uv run python scripts/check_min_deps.py # validate each package's declared minimum dep versions (ty in isolated min-version envs; workspace siblings resolve from locally built wheels, all other deps from PyPI). CI passes --wheelhouse instead, reusing the build jobs' artifacts uv run python scripts/check_min_deps.py --check-dev-pins [pkg] # fail if pkg (default: all) declares an unpublishable *.dev dependency pin (the publish workflow runs the same gate via `reflex-release check-dev-pins`) uv run reflex-release sync # regenerate the release workflows after editing [tool.reflex-release] or the reflex-release templates uv run python scripts/make_pyi.py # regenerate .pyi stubs @@ -210,7 +210,7 @@ if TYPE_CHECKING: Before submitting: 1. Tests pass with adequate coverage 2. `uv run ruff check .` and `uv run ruff format .` clean -3. `uv run pyright reflex tests` passes +3. `uv run ty check` passes 4. `pyi_hashes.json` updated if components changed 5. Documentation updated if user-facing behavior changed 6. News fragment added for user-facing changes diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 477ebcdaef3..f75b1280c00 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -175,7 +175,7 @@ Next make sure all the following tests pass. This ensures that every new change ```bash uv run ruff check . -uv run pyright reflex tests +uv run ty check ``` Finally, run `ruff` to format your code. @@ -184,7 +184,7 @@ Finally, run `ruff` to format your code. uv run ruff format . ``` -Consider installing git pre-commit hooks so Ruff, Pyright, and `make_pyi` will run automatically before each commit. +Consider installing git pre-commit hooks so Ruff, ty, and `make_pyi` will run automatically before each commit. ```bash uv run pre-commit install diff --git a/docs/app/reflex_docs/pages/docs/__init__.py b/docs/app/reflex_docs/pages/docs/__init__.py index a1e2f8bd999..ed75737fc1a 100644 --- a/docs/app/reflex_docs/pages/docs/__init__.py +++ b/docs/app/reflex_docs/pages/docs/__init__.py @@ -582,7 +582,7 @@ def register_doc(virtual_doc: str, comp): # Alias needed by sidebar — the library page route object. -library_: Route = library # type: ignore[assignment] +library_: Route = library # Process all docs via reflex_docgen pipeline. diff --git a/docs/app/reflex_docs/pages/docs/cloud_cliref.py b/docs/app/reflex_docs/pages/docs/cloud_cliref.py index f91a41cb0d3..1a536bdf66a 100644 --- a/docs/app/reflex_docs/pages/docs/cloud_cliref.py +++ b/docs/app/reflex_docs/pages/docs/cloud_cliref.py @@ -261,7 +261,7 @@ def process_command(command: click.Command, name: str) -> str: if find_spec("typer") is not None and find_spec("typer.main") is not None: - import typer # pyright: ignore[reportMissingImports] + import typer if isinstance(cli, typer.Typer): cli = typer.main.get_command(cli) diff --git a/docs/app/reflex_docs/templates/docpage/sidebar/sidebar.py b/docs/app/reflex_docs/templates/docpage/sidebar/sidebar.py index 3615664c0b1..ad917d2dc8c 100644 --- a/docs/app/reflex_docs/templates/docpage/sidebar/sidebar.py +++ b/docs/app/reflex_docs/templates/docpage/sidebar/sidebar.py @@ -559,7 +559,7 @@ def sidebar_comp( rx.cond(is_docs_ai_builder, ai_builder_content, docs_content), ) - return rx.box( # pyright: ignore [reportCallIssue] + return rx.box( categories, content, style={ diff --git a/docs/app/reflex_docs/utils/http.py b/docs/app/reflex_docs/utils/http.py index 5ee033d5a82..1cef1fb4a03 100644 --- a/docs/app/reflex_docs/utils/http.py +++ b/docs/app/reflex_docs/utils/http.py @@ -26,7 +26,7 @@ def once(f: Callable[[], T]) -> Callable[[], T]: def wrapper() -> T: nonlocal value value = f() if value is unset else value - return value # pyright: ignore[reportReturnType] + return value return wrapper diff --git a/examples/playground/.content-hash b/examples/playground/.content-hash index baa0334b36f..f1d72ed8042 100644 --- a/examples/playground/.content-hash +++ b/examples/playground/.content-hash @@ -1 +1 @@ -sha256:4e394b7fae5105fdd5820509cefc0ee7bd5d4e05714a89cfb8d1478568123ef5 +sha256:651c89480e23f669f2388196cf4bac2397fff2e8363a1cd1544e25e07a53a030 diff --git a/examples/playground/playground/models.py b/examples/playground/playground/models.py index ffc732ef005..5906059eaf0 100644 --- a/examples/playground/playground/models.py +++ b/examples/playground/playground/models.py @@ -31,7 +31,7 @@ def seed_database(): """ with rx.session() as session: connection = session.connection() - product_table = Product.__table__ # pyright: ignore[reportAttributeAccessIssue] + product_table = Product.__table__ # ty:ignore[unresolved-attribute] connection.execute(CreateTable(product_table, if_not_exists=True)) table = Product.__tablename__ if connection.exec_driver_sql(f"SELECT 1 FROM {table} LIMIT 1").first(): diff --git a/examples/playground/playground/pages/charts.py b/examples/playground/playground/pages/charts.py index c08e2d6ab87..ae3fa209139 100644 --- a/examples/playground/playground/pages/charts.py +++ b/examples/playground/playground/pages/charts.py @@ -7,7 +7,7 @@ from playground.layout import layout from playground.states.charts import KINDS, MAX_POINTS, MIN_POINTS, ChartsState -CHART_SIZE = {"width": "100%", "height": 280} +CHART_SIZE: dict[str, Any] = {"width": "100%", "height": 280} def waves_chart() -> rx.Component | rx.Var: diff --git a/examples/playground/playground/pages/grids.py b/examples/playground/playground/pages/grids.py index fcf341a96af..1bb50f01074 100644 --- a/examples/playground/playground/pages/grids.py +++ b/examples/playground/playground/pages/grids.py @@ -31,7 +31,7 @@ def grids() -> rx.Component: rx.data_editor( columns=EDITOR_COLUMNS, data=GridState.rows, - on_cell_edited=GridState.edit_cell, # pyright: ignore[reportArgumentType] + on_cell_edited=GridState.edit_cell, # ty:ignore[invalid-argument-type] height="20rem", ), id="grids-editor", diff --git a/examples/playground/playground/pages/item.py b/examples/playground/playground/pages/item.py index 7651b1acbfa..5ad74e8689c 100644 --- a/examples/playground/playground/pages/item.py +++ b/examples/playground/playground/pages/item.py @@ -15,6 +15,6 @@ def item() -> rx.Component: rx.vstack( rx.heading("Item"), # Dynamic route arguments are vars of the root state. - rx.text("item_id: ", rx.code(rx.State.item_id, id="item-id")), # pyright: ignore[reportAttributeAccessIssue] + rx.text("item_id: ", rx.code(rx.State.item_id, id="item-id")), # ty:ignore[unresolved-attribute] ) ) diff --git a/examples/playground/playground/pages/settings.py b/examples/playground/playground/pages/settings.py index 769c211954d..157889737f5 100644 --- a/examples/playground/playground/pages/settings.py +++ b/examples/playground/playground/pages/settings.py @@ -75,7 +75,7 @@ def settings() -> rx.Component: name.capitalize(), rx.switch( checked=SettingsState.switches[name], - on_change=lambda _, name=name: SettingsState.flip( + on_change=lambda _, name=name: SettingsState.flip( # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 name ), id=f"settings-switch-{name}", @@ -123,7 +123,7 @@ def settings() -> rx.Component: rx.callout( "The accent previews here; the app theme stays violet.", icon="info", - color_scheme=SettingsState.accent, # pyright: ignore[reportArgumentType] + color_scheme=SettingsState.accent, # ty:ignore[invalid-argument-type] size=rx.cond(SettingsState.compact, "1", "2"), id="settings-preview", ), diff --git a/examples/playground/playground/pages/tasks.py b/examples/playground/playground/pages/tasks.py index d21811610fd..eba1b90cdfe 100644 --- a/examples/playground/playground/pages/tasks.py +++ b/examples/playground/playground/pages/tasks.py @@ -32,7 +32,7 @@ def task_row(task: rx.vars.ObjectVar[Task]) -> rx.Component: return rx.hstack( rx.checkbox( checked=task.done, - on_change=lambda _: TasksState.toggle(task.id), + on_change=lambda _: TasksState.toggle(task.id), # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 ), rx.text( task.title, @@ -123,7 +123,7 @@ def tasks() -> rx.Component: *[ rx.input( placeholder=f"note on {tag}", - on_blur=lambda value, tag=tag: TasksState.set_note(tag, value), + on_blur=lambda value, tag=tag: TasksState.set_note(tag, value), # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 id=f"tasks-note-{tag}", ) for tag in TAG_CHOICES diff --git a/examples/playground/playground/states/data.py b/examples/playground/playground/states/data.py index 247f056d02f..086baee56ec 100644 --- a/examples/playground/playground/states/data.py +++ b/examples/playground/playground/states/data.py @@ -60,7 +60,7 @@ def _query(self): """Query the current page of the filtered, sorted products.""" statement = Product.select() if self.query: - statement = statement.where(Product.name.contains(self.query)) # pyright: ignore[reportAttributeAccessIssue] + statement = statement.where(Product.name.contains(self.query)) # ty:ignore[unresolved-attribute] if self.category != "all": statement = statement.where(Product.category == self.category) column = getattr(Product, self.sort_by) diff --git a/examples/playground/playground/states/editor.py b/examples/playground/playground/states/editor.py index 40992ec0faf..321b485db8d 100644 --- a/examples/playground/playground/states/editor.py +++ b/examples/playground/playground/states/editor.py @@ -117,7 +117,7 @@ def save(self, form_data: dict[str, Any]): return rx.toast.error("Fix the highlighted fields.") with rx.session() as session: if self.product is None: - product = Product(listed_day=0, **values) # pyright: ignore[reportArgumentType] + product = Product(listed_day=0, **values) # ty:ignore[invalid-argument-type] else: product = session.get(Product, self.product.id) if product is None: diff --git a/examples/playground/playground/states/tasks.py b/examples/playground/playground/states/tasks.py index 5a595f0eb81..39480b00214 100644 --- a/examples/playground/playground/states/tasks.py +++ b/examples/playground/playground/states/tasks.py @@ -167,7 +167,7 @@ def set_filter(self, value: str | list[str]): Args: value: One of ``all``, ``open`` and ``done``. """ - if value in FILTERS: + if isinstance(value, str) and value in FILTERS: self.filter = value @rx.event diff --git a/examples/playground/playground/states/widgets.py b/examples/playground/playground/states/widgets.py index b3d1c90f237..1cacf7ef4fc 100644 --- a/examples/playground/playground/states/widgets.py +++ b/examples/playground/playground/states/widgets.py @@ -23,7 +23,7 @@ def set_layout(self, value: str | list[str]): Args: value: One of ``cards``, ``list`` and ``table``. """ - if value in LAYOUTS: + if isinstance(value, str) and value in LAYOUTS: self.layout = value @rx.event diff --git a/packages/reflex-base/src/reflex_base/components/component.py b/packages/reflex-base/src/reflex_base/components/component.py index c9097c51a4d..5396388d9ae 100644 --- a/packages/reflex-base/src/reflex_base/components/component.py +++ b/packages/reflex-base/src/reflex_base/components/component.py @@ -134,7 +134,7 @@ def field( default_factory: Callable[[], FIELD_TYPE] | None = None, is_javascript_property: bool | None = None, doc: str | None = None, -) -> FIELD_TYPE: +) -> Any: """Create a field for a component. Args: @@ -152,7 +152,7 @@ def field( if default is not MISSING and default_factory is not None: msg = "cannot specify both default and default_factory" raise ValueError(msg) - return ComponentField( # pyright: ignore [reportReturnType] + return ComponentField( default=default, default_factory=default_factory, is_javascript=is_javascript_property, @@ -428,7 +428,7 @@ def __deepcopy__(self, memo: dict[int, Any]) -> BaseComponent: def _clear_compile_caches(self) -> None: """Clear cached render/compiler artifacts after compile-time mutation.""" - attrs = cast("dict[str, Any]", vars(self)) + attrs = vars(self) for attr in _COMPILE_CACHE_ATTRS: attrs.pop(attr, None) @@ -528,7 +528,7 @@ class ComponentNamespace(SimpleNamespace): # expressions can reach its attributes (e.g. ``rx.form.FormData``). _stub_as_class: ClassVar[bool] = False - def __hash__(self) -> int: # pyright: ignore [reportIncompatibleVariableOverride] + def __hash__(self) -> int: """Get the hash of the namespace. Returns: @@ -668,15 +668,15 @@ class TriggerDefinition: description="Fired when focus has left the element (or left some element inside of it). For example, it is called when the user clicks outside of a focused text input.", ), EventTriggers.ON_CLICK: TriggerDefinition( - spec=pointer_event_spec, # pyright: ignore [reportArgumentType] + spec=pointer_event_spec, description="Fired when the user clicks on an element. For example, it's called when the user clicks on a button.", ), EventTriggers.ON_CONTEXT_MENU: TriggerDefinition( - spec=pointer_event_spec, # pyright: ignore [reportArgumentType] + spec=pointer_event_spec, description="Fired when the user right-clicks on an element.", ), EventTriggers.ON_DOUBLE_CLICK: TriggerDefinition( - spec=pointer_event_spec, # pyright: ignore [reportArgumentType] + spec=pointer_event_spec, description="Fired when the user double-clicks on an element.", ), EventTriggers.ON_MOUSE_DOWN: TriggerDefinition( @@ -1116,7 +1116,7 @@ def get_event_triggers(cls) -> dict[str, types.ArgsSpec | Sequence[types.ArgsSpe cached = cls.__dict__.get("_event_triggers_cache") if cached is not None: return cached - result = DEFAULT_TRIGGERS | args_specs_from_fields(cls.get_fields()) # pyright: ignore [reportOperatorIssue] + result = DEFAULT_TRIGGERS | args_specs_from_fields(cls.get_fields()) cls._event_triggers_cache = result return result @@ -1401,9 +1401,11 @@ def _get_component_style(self, styles: ComponentStyle | Style) -> Style | None: The style of the component. """ component_style = None - if (style := styles.get(type(self))) is not None: # pyright: ignore [reportArgumentType] + if isinstance(styles, Style): + return component_style + if (style := styles.get(type(self))) is not None: component_style = Style(style) - if (style := styles.get(self.create)) is not None: # pyright: ignore [reportArgumentType] + if (style := styles.get(self.create)) is not None: component_style = Style(style) return component_style @@ -1591,12 +1593,14 @@ def _get_vars_from_event_triggers( if isinstance(event, Var): yield event_trigger, [event] elif isinstance(event, EventChain): - event_args = [] + event_args: list[Var] = [] for spec in event.events: if isinstance(spec, EventSpec): for args in spec.args: event_args.extend(args) - else: + elif isinstance(spec, Var): + # EventCallback is only in the declared type of + # EventChain.events; calling one yields an EventSpec. event_args.append(spec) yield event_trigger, event_args @@ -2331,7 +2335,7 @@ def _format_patterns_into_condition(patterns: list, element: Var) -> Var: ) -def render_dict_to_var(tag: dict | Component | str) -> Var: +def render_dict_to_var(tag: dict[str, Any] | Component | str) -> Var: """Convert a render dict to a Var. Args: @@ -2340,37 +2344,38 @@ def render_dict_to_var(tag: dict | Component | str) -> Var: Returns: The Var. """ + if isinstance(tag, Component): + return render_dict_to_var(tag.render()) if not isinstance(tag, dict): - if isinstance(tag, Component): - return render_dict_to_var(tag.render()) return Var.create(tag) + render_dict: dict[str, Any] = tag - if "contents" in tag: - return Var(tag["contents"]) + if "contents" in render_dict: + return Var(render_dict["contents"]) - if "iterable" in tag: + if "iterable" in render_dict: function_return = LiteralArrayVar.create([ - render_dict_to_var(child.render()) for child in tag["children"] + render_dict_to_var(child.render()) for child in render_dict["children"] ]) func = ArgsFunctionOperation.create( - (tag["arg_var_name"], tag["index_var_name"]), + (render_dict["arg_var_name"], render_dict["index_var_name"]), function_return, ) return FunctionStringVar.create("Array.prototype.map.call").call( - tag["iterable"] - if not isinstance(tag["iterable"], ObjectVar) - else tag["iterable"].items(), + render_dict["iterable"] + if not isinstance(render_dict["iterable"], ObjectVar) + else render_dict["iterable"].items(), func, ) - if "match_cases" in tag: - element = Var(tag["cond"]) + if "match_cases" in render_dict: + element = Var(render_dict["cond"]) - conditionals = render_dict_to_var(tag["default"]) + conditionals = render_dict_to_var(render_dict["default"]) - for case in tag["match_cases"][::-1]: + for case in render_dict["match_cases"][::-1]: patterns, return_value = case condition = _format_patterns_into_condition(patterns, element) @@ -2382,18 +2387,18 @@ def render_dict_to_var(tag: dict | Component | str) -> Var: return conditionals - if "cond_state" in tag: + if "cond_state" in render_dict: return ternary_operation( - Var(tag["cond_state"]), - render_dict_to_var(tag["true_value"]), - render_dict_to_var(tag["false_value"]) - if tag["false_value"] is not None + Var(render_dict["cond_state"]), + render_dict_to_var(render_dict["true_value"]), + render_dict_to_var(render_dict["false_value"]) + if render_dict["false_value"] is not None else LiteralNoneVar.create(), ) - props = Var("({" + ",".join(tag["props"]) + "})") + props = Var("({" + ",".join(render_dict["props"]) + "})") - raw_tag_name = tag.get("name") + raw_tag_name = render_dict.get("name") tag_name = Var(raw_tag_name or "Fragment") return FunctionStringVar.create( @@ -2401,7 +2406,7 @@ def render_dict_to_var(tag: dict | Component | str) -> Var: ).call( tag_name, props, - *[render_dict_to_var(child) for child in tag["children"]], + *[render_dict_to_var(child) for child in render_dict["children"]], ) diff --git a/packages/reflex-base/src/reflex_base/components/field.py b/packages/reflex-base/src/reflex_base/components/field.py index bcf054c6a32..7069c4db8f3 100644 --- a/packages/reflex-base/src/reflex_base/components/field.py +++ b/packages/reflex-base/src/reflex_base/components/field.py @@ -38,7 +38,7 @@ def __init__( # Process type annotation type_origin = get_origin(annotated_type) or annotated_type if type_origin is Annotated: - type_origin = annotated_type.__origin__ # pyright: ignore [reportAttributeAccessIssue] + type_origin = annotated_type.__origin__ # ty:ignore[unresolved-attribute] # For Annotated types, use the actual type inside the annotation self.type_ = annotated_type else: @@ -110,11 +110,11 @@ def _collect_inherited_fields(cls, bases: tuple[type, ...]) -> dict[str, Any]: # Collect inherited fields from base classes for base in bases[::-1]: - if hasattr(base, "_inherited_fields"): - inherited_fields.update(base._inherited_fields) + if (fields := getattr(base, "_inherited_fields", None)) is not None: + inherited_fields.update(fields) for base in bases[::-1]: - if hasattr(base, "_own_fields"): - inherited_fields.update(base._own_fields) + if (fields := getattr(base, "_own_fields", None)) is not None: + inherited_fields.update(fields) return inherited_fields diff --git a/packages/reflex-base/src/reflex_base/components/memo.py b/packages/reflex-base/src/reflex_base/components/memo.py index e447bb6e400..54d22fcae49 100644 --- a/packages/reflex-base/src/reflex_base/components/memo.py +++ b/packages/reflex-base/src/reflex_base/components/memo.py @@ -8,7 +8,7 @@ from copy import copy from enum import Enum from functools import cache, partial, update_wrapper -from types import UnionType +from types import FunctionType, UnionType from typing import ( Annotated, Any, @@ -49,7 +49,7 @@ from reflex_base.utils import console, format, memo_paths from reflex_base.utils.deterministic_hash import deterministic_hash from reflex_base.utils.imports import ImportVar, ParsedImportDict -from reflex_base.utils.types import safe_issubclass, typehint_issubclass +from reflex_base.utils.types import safe_issubclass, set_signature, typehint_issubclass from reflex_base.vars import VarData from reflex_base.vars.base import LiteralVar, Var from reflex_base.vars.function import ( @@ -280,7 +280,7 @@ def get(self, thunk: Callable[[], _BodyT] | None = None) -> _BodyT: class MemoDefinition: """Base metadata for a memo.""" - fn: Callable[..., Any] + fn: FunctionType python_name: str params: tuple[MemoParam, ...] # The Python module that defined this memo. When set, the memo's compiled @@ -954,7 +954,7 @@ def _event_handler_placeholder(placeholder_name: str, args_spec: Any) -> Callabl def _placeholder(*args: Any) -> Any: return run_script(prop_callback.call(*args)) - _placeholder.__signature__ = inspect.signature(primary_spec) # pyright: ignore[reportFunctionMemberAccess] + set_signature(_placeholder, inspect.signature(primary_spec)) return _placeholder @@ -1203,7 +1203,7 @@ def finalize( def _evaluate_memo_function( - fn: Callable[..., Any], + fn: FunctionType, params: tuple[MemoParam, ...], runtime_values: Mapping[str, Any] | None = None, ) -> Any: @@ -1294,7 +1294,7 @@ def _lift_rest_props(component: Component, rest_target_fields: set[str]) -> Comp def _analyze_params( - fn: Callable[..., Any], + fn: FunctionType, *, for_component: bool, hints: dict[str, Any] | None = None, @@ -1488,7 +1488,7 @@ def _build_args_function( def _evaluate_component_body( - fn: Callable[..., Any], + fn: FunctionType, params: tuple[MemoParam, ...], rest_target_fields: set[str], runtime_values: Mapping[str, Any] | None = None, @@ -1521,7 +1521,7 @@ def _evaluate_component_body( def _evaluate_function_body( - fn: Callable[..., Any], params: tuple[MemoParam, ...] + fn: FunctionType, params: tuple[MemoParam, ...] ) -> ArgsFunctionOperation: """Run a var memo's body and build its compiled function. @@ -1538,7 +1538,7 @@ def _evaluate_function_body( def _create_component_definition( - fn: Callable[..., Any], + fn: FunctionType, return_annotation: Any, source_module: str | None = None, ) -> MemoComponentDefinition: @@ -2282,7 +2282,7 @@ def _warn_legacy_base_props(fn_name: str, prop_names: Sequence[str]) -> None: def _memo_impl( - fn: Callable[..., Any], + fn: FunctionType, wrapper: Var | None, ) -> _MemoComponentWrapper | _MemoFunctionWrapper: """Analyze and register a memo definition for a decorated function. @@ -2399,7 +2399,7 @@ def memo( *, wrapper: Var | None ) -> Callable[[Callable[..., Component]], _MemoComponentWrapper]: ... def memo( - fn: Callable[..., Any] | None = None, + fn: FunctionType | None = None, *, wrapper: Var | None = DEFAULT_MEMO_WRAPPER, ) -> ( diff --git a/packages/reflex-base/src/reflex_base/components/props.py b/packages/reflex-base/src/reflex_base/components/props.py index 1d69df4aee7..13b33bc84e9 100644 --- a/packages/reflex-base/src/reflex_base/components/props.py +++ b/packages/reflex-base/src/reflex_base/components/props.py @@ -160,11 +160,11 @@ def props_field( if default is not MISSING and default_factory is not None: msg = "cannot specify both default and default_factory" raise ValueError(msg) - return PropsField( # pyright: ignore [reportReturnType] + return PropsField( default=default, default_factory=default_factory, annotated_type=MISSING, - ) + ) # ty:ignore[invalid-return-type] @dataclass_transform(field_specifiers=(props_field,)) diff --git a/packages/reflex-base/src/reflex_base/environment.py b/packages/reflex-base/src/reflex_base/environment.py index 00e38b9e882..04f4320e5d7 100644 --- a/packages/reflex-base/src/reflex_base/environment.py +++ b/packages/reflex-base/src/reflex_base/environment.py @@ -580,7 +580,7 @@ def get_type_hints_environment(cls: type) -> dict[str, Any]: return get_type_hints(cls) -class env_var: # noqa: N801 # pyright: ignore [reportRedeclaration] +class env_var: # noqa: N801 """Descriptor for environment variables.""" name: str diff --git a/packages/reflex-base/src/reflex_base/event/__init__.py b/packages/reflex-base/src/reflex_base/event/__init__.py index 7f6c6ffe43e..1f6d0ca73e8 100644 --- a/packages/reflex-base/src/reflex_base/event/__init__.py +++ b/packages/reflex-base/src/reflex_base/event/__init__.py @@ -14,6 +14,7 @@ TYPE_CHECKING, Annotated, Any, + ClassVar, Generic, Literal, NoReturn, @@ -53,6 +54,7 @@ is_non_string_sequence, is_optional, safe_issubclass, + set_signature, typehint_issubclass, value_inside_optional, ) @@ -487,7 +489,7 @@ def _no_chain_background_task(state: "BaseState", fn: Callable) -> Callable: Raises: TypeError: If the background task is not async. """ - name = fn.__name__ + name = format.callable_name(fn) call = f"{type(state).__name__}.{name}" message = ( f"Cannot directly call background task {name!r}, use " @@ -601,16 +603,17 @@ def _parameters(self) -> Mapping[str, inspect.Parameter]: return parameters @classmethod - def __class_getitem__(cls, args_spec: str) -> Annotated: + def __class_getitem__(cls, args_spec: Callable | Sequence[Callable]) -> Annotated: # ty:ignore[invalid-type-form] """Get a typed EventHandler. Args: - args_spec: The args_spec of the EventHandler. + args_spec: The args spec of the EventHandler: a single spec callable + or a sequence of them, attached to the resulting ``Annotated``. Returns: The EventHandler class item. """ - return Annotated[cls, args_spec] + return Annotated[cls, args_spec] # ty:ignore[invalid-type-form] @cached_property def is_background(self) -> bool: @@ -803,7 +806,7 @@ class EventSpec(EventActionsMixin): args: The arguments to pass to the function. """ - handler: EventHandler = dataclasses.field(default=None) # pyright: ignore [reportAssignmentType] + handler: EventHandler = dataclasses.field(default=None) # ty:ignore[invalid-assignment] client_handler_name: str = dataclasses.field(default="") @@ -946,7 +949,7 @@ class EventChain(EventActionsMixin): args_spec: Callable | Sequence[Callable] | None = dataclasses.field(default=None) - invocation: Var | None = dataclasses.field(default=None) + invocation: FunctionVar | None = dataclasses.field(default=None) @classmethod def create( @@ -1301,7 +1304,7 @@ def __call__(self, *values: Var[T]) -> tuple[Var[T], ...]: @overload -def passthrough_event_spec( # pyright: ignore [reportOverlappingOverload] +def passthrough_event_spec( event_type: type[T], / ) -> Callable[[Var[T]], tuple[Var[T]]]: ... @@ -1312,11 +1315,25 @@ def passthrough_event_spec( ) -> Callable[[Var[T], Var[U]], tuple[Var[T], Var[U]]]: ... +@overload +def passthrough_event_spec( + event_type: types.UnionType, / +) -> Callable[[Var[Any]], tuple[Var[Any]]]: ... + + +@overload +def passthrough_event_spec( + event_type_1: types.UnionType | type[T], + event_type2: types.UnionType | type[U], + /, +) -> Callable[[Var[Any], Var[Any]], tuple[Var[Any], Var[Any]]]: ... + + @overload def passthrough_event_spec(*event_types: type[T]) -> IdentityEventReturn[T]: ... -def passthrough_event_spec(*event_types: type[T]) -> IdentityEventReturn[T]: # pyright: ignore [reportInconsistentOverload] +def passthrough_event_spec(*event_types: type[T]) -> IdentityEventReturn[T]: """A helper function that returns the input event as output. Args: @@ -1329,22 +1346,23 @@ def passthrough_event_spec(*event_types: type[T]) -> IdentityEventReturn[T]: # def inner(*values: Var[T]) -> tuple[Var[T], ...]: return values - inner_type = tuple(Var[event_type] for event_type in event_types) - return_annotation = tuple[inner_type] + inner_type = tuple(Var[event_type] for event_type in event_types) # ty:ignore[invalid-type-form] + return_annotation = tuple[inner_type] # ty:ignore[invalid-type-form] - inner.__signature__ = inspect.signature(inner).replace( # pyright: ignore [reportFunctionMemberAccess] + new_signature = inspect.signature(inner).replace( parameters=[ inspect.Parameter( f"ev_{i}", kind=inspect.Parameter.POSITIONAL_OR_KEYWORD, - annotation=Var[event_type], + annotation=Var[event_type], # ty:ignore[invalid-type-form] ) for i, event_type in enumerate(event_types) ], return_annotation=return_annotation, ) + set_signature(inner, new_signature) for i, event_type in enumerate(event_types): - inner.__annotations__[f"ev_{i}"] = Var[event_type] + inner.__annotations__[f"ev_{i}"] = Var[event_type] # ty:ignore[invalid-type-form] inner.__annotations__["return"] = return_annotation return inner @@ -1540,7 +1558,7 @@ def fn(): return None fn.__qualname__ = name - fn.__signature__ = sig # pyright: ignore [reportFunctionMemberAccess] + set_signature(fn, sig) return EventSpec( handler=EventHandler(fn=fn), args=tuple( @@ -2660,7 +2678,7 @@ def bool(self) -> NoReturn: class LiteralEventVar(VarOperationCall, LiteralVar, EventVar): """A literal event var.""" - _var_value: EventSpec = dataclasses.field(default=None) # pyright: ignore [reportAssignmentType] + _var_value: EventSpec = dataclasses.field(default=None) # ty:ignore[invalid-assignment] def __hash__(self) -> int: """Get the hash of the var. @@ -2689,6 +2707,7 @@ def create( EventFnArgMismatchError: If the event handler takes arguments. """ if isinstance(value, EventHandler): + handler = value def no_args(): return () @@ -2696,7 +2715,7 @@ def no_args(): try: value = call_event_handler(value, no_args) except EventFnArgMismatchError: - msg = f"Event handler {value.fn.__qualname__} used inside of a rx.cond() must not take any arguments." + msg = f"Event handler {format.callable_qualname(handler.fn)} used inside of a rx.cond() must not take any arguments." raise EventFnArgMismatchError(msg) from None return cls( @@ -2747,7 +2766,7 @@ def bool(self) -> NoReturn: class LiteralEventChainVar(ArgsFunctionOperationBuilder, LiteralVar, EventChainVar): """A literal event chain var.""" - _var_value: EventChain = dataclasses.field(default=None) # pyright: ignore [reportAssignmentType] + _var_value: EventChain = dataclasses.field(default=None) # ty:ignore[invalid-assignment] def __hash__(self) -> int: """Get the hash of the var. @@ -2780,7 +2799,7 @@ def create( if isinstance(value.args_spec, Sequence) else value.args_spec ) - sig = inspect.signature(arg_spec) # pyright: ignore [reportArgumentType] + sig = inspect.signature(arg_spec) # ty:ignore[invalid-argument-type] arg_vars = () if sig.parameters: arg_def = tuple(f"_{p}" for p in sig.parameters) @@ -2894,7 +2913,7 @@ def __init__(self, func: Callable[[Any, Unpack[P]], Any]): Args: func: The function to be wrapped. """ - self.func = func + self.func = func # ty:ignore[invalid-assignment] @overload def __call__( @@ -3007,7 +3026,7 @@ def __call__( value4: V4 | Var[V4], ) -> "EventCallback[V5, *Q]": ... - def __call__(self, *values) -> "EventCallback": # pyright: ignore [reportInconsistentOverload] + def __call__(self, *values) -> "EventCallback": """Call the function with the values. Args: @@ -3016,7 +3035,7 @@ def __call__(self, *values) -> "EventCallback": # pyright: ignore [reportIncons Returns: The function with the values. """ - return self.func(*values) # pyright: ignore [reportArgumentType] + return self.func(*values) @overload def __get__( @@ -3122,6 +3141,12 @@ def __call__(self, *args: Var) -> Any: class EventNamespace: """A namespace for event related classes.""" + if TYPE_CHECKING: + event: ClassVar["type[EventNamespace]"] + __path__: ClassVar[Any] + __spec__: ClassVar[Any] + __package__: ClassVar[str | None] + # Core Event Classes Event = Event EventActionsMixin = EventActionsMixin @@ -3299,7 +3324,7 @@ def wrapper( types = get_type_hints(func) state_arg_name = next(iter(inspect.signature(func).parameters), None) state_cls = state_arg_name and types.get(state_arg_name) - if state_cls and issubclass(state_cls, BaseState): + if state_cls and issubclass(state_cls, BaseState): # ty:ignore[invalid-argument-type] name = ( (func.__module__ + "." + qualname) .replace(".", "_") @@ -3325,7 +3350,9 @@ def wrapper( event_actions = _build_event_actions() if event_actions: setattr(func, EVENT_ACTIONS_MARKER, event_actions) - return func # pyright: ignore [reportReturnType] + # Handlers defined in a state class body stay plain functions here; + # BaseStateMeta turns them into EventCallback descriptors. + return func # ty:ignore[invalid-return-type] if func is not None: return wrapper(func) @@ -3379,7 +3406,7 @@ def wrapper( __file__ = __file__ @property - def BaseState(self) -> "type[BaseState]": # noqa: N802 + def BaseState(self) -> "type[BaseState]": # noqa: N802 # ty:ignore[invalid-type-form] """The BaseState class. A reference to BaseState is needed for doc generation when resolving @@ -3395,9 +3422,9 @@ def BaseState(self) -> "type[BaseState]": # noqa: N802 event = EventNamespace -event.event = event # pyright: ignore[reportAttributeAccessIssue] +event.event = event _this = sys.modules[__name__] -event.__path__ = _this.__path__ # pyright: ignore[reportAttributeAccessIssue] -event.__spec__ = _this.__spec__ # pyright: ignore[reportAttributeAccessIssue] -event.__package__ = _this.__package__ # pyright: ignore[reportAttributeAccessIssue] -sys.modules[__name__] = event # pyright: ignore[reportArgumentType] +event.__path__ = _this.__path__ +event.__spec__ = _this.__spec__ +event.__package__ = _this.__package__ +sys.modules[__name__] = event # ty:ignore[invalid-assignment] diff --git a/packages/reflex-base/src/reflex_base/event/context.py b/packages/reflex-base/src/reflex_base/event/context.py index 66a88ac3e27..47d3ff8c505 100644 --- a/packages/reflex-base/src/reflex_base/event/context.py +++ b/packages/reflex-base/src/reflex_base/event/context.py @@ -10,7 +10,7 @@ from reflex_base import otel from reflex_base.context.base import BaseContext -from reflex_base.utils.format import to_snake_case +from reflex_base.utils.format import callable_qualname, to_snake_case if TYPE_CHECKING: from opentelemetry.context import Context @@ -27,7 +27,7 @@ def get_name(cls: type | Callable) -> str: The name of the state/func. """ module = cls.__module__.replace(".", "___") - qualname = getattr(cls, "__qualname__", cls.__name__).replace(".", "___") + qualname = callable_qualname(cls).replace(".", "___") return to_snake_case(f"{module}___{qualname}") diff --git a/packages/reflex-base/src/reflex_base/event/processor/base_state_processor.py b/packages/reflex-base/src/reflex_base/event/processor/base_state_processor.py index 7d13b83e437..6d55abf8e87 100644 --- a/packages/reflex-base/src/reflex_base/event/processor/base_state_processor.py +++ b/packages/reflex-base/src/reflex_base/event/processor/base_state_processor.py @@ -24,7 +24,7 @@ from reflex_base.event.processor.future import EventFuture from reflex_base.registry import RegisteredEventHandler from reflex_base.utils.form import form_data_as_dict, transform_form_data -from reflex_base.utils.format import format_event_handler +from reflex_base.utils.format import callable_qualname, format_event_handler from reflex_base.utils.serializers import deserializers from reflex_base.utils.types import is_non_string_sequence @@ -679,7 +679,7 @@ async def _handle_backend_exception( if events := self.backend_exception_handler(ex): await chain_updates( events=events, - handler_name=self.backend_exception_handler.__qualname__, + handler_name=callable_qualname(self.backend_exception_handler), ) diff --git a/packages/reflex-base/src/reflex_base/event/processor/event_processor.py b/packages/reflex-base/src/reflex_base/event/processor/event_processor.py index 51f7e1231be..5abcacfae00 100644 --- a/packages/reflex-base/src/reflex_base/event/processor/event_processor.py +++ b/packages/reflex-base/src/reflex_base/event/processor/event_processor.py @@ -31,7 +31,7 @@ if hasattr(asyncio, "QueueShutDown"): - class QueueShutDown(asyncio.QueueShutDown): # pyright: ignore[reportRedeclaration] + class QueueShutDown(asyncio.QueueShutDown): """Exception raised when trying to put an item into a shut down queue.""" _QUEUE_SHUTDOWN_ERRORS: tuple[type[BaseException], ...] = (asyncio.QueueShutDown,) @@ -566,7 +566,7 @@ async def _wait_for_chain() -> None: # Raise any exceptions for the caller, waiting for all chained events. await task_future.wait_all() - def _try_clean_future(self, future: EventFuture) -> None: # type: ignore[override] + def _try_clean_future(self, future: EventFuture) -> None: """Pop a future from _futures when it and all immediate children are done. After popping, cascade the check upward: if the parent future is also @@ -681,7 +681,7 @@ def _cancel_older_chains(self, key: tuple[str, str], root_gen: int) -> None: previous.cancel() slot.clear() - def _on_future_done(self, future: EventFuture) -> None: # type: ignore[override] + def _on_future_done(self, future: EventFuture) -> None: """Callback invoked when an enqueued future completes. If the future was cancelled externally, cancel the running task @@ -789,7 +789,7 @@ def _create_event_task( else: task = asyncio.create_task(coro, name=name) if sys.version_info < (3, 12): - task._event_ctx = entry.ctx # pyright: ignore[reportAttributeAccessIssue] + task._event_ctx = entry.ctx # ty:ignore[unresolved-attribute] self._tasks[entry.ctx.txid] = task task.add_done_callback(self._finish_task) return task @@ -911,7 +911,7 @@ def _finish_task(self, task: asyncio.Task): """ if sys.version_info < (3, 12): # py3.11 compat - task_ctx = task._event_ctx # type: ignore[attr-defined] + task_ctx = task._event_ctx # ty:ignore[unresolved-attribute] else: task_ctx = task.get_context().run(EventContext.get) self._tasks.pop(task_ctx.txid, None) @@ -969,7 +969,7 @@ def _resolve_future( name=f"reflex_backend_exception_handler|task=[{task.get_name()}]|{time.time()}", ) if sys.version_info < (3, 12): - t._event_ctx = task_ctx # pyright: ignore[reportAttributeAccessIssue] + t._event_ctx = task_ctx # ty:ignore[unresolved-attribute] t.add_done_callback(self._finish_task) return True logger.exception(f"Error in {task.get_name()} [txid={task_ctx.txid}]:") diff --git a/packages/reflex-base/src/reflex_base/plugins/base.py b/packages/reflex-base/src/reflex_base/plugins/base.py index 3f52afe48ee..c52d7f00e67 100644 --- a/packages/reflex-base/src/reflex_base/plugins/base.py +++ b/packages/reflex-base/src/reflex_base/plugins/base.py @@ -1,5 +1,7 @@ """Base class for all plugins.""" +from __future__ import annotations + from collections.abc import Callable, Mapping, Sequence from enum import Enum from pathlib import Path @@ -22,7 +24,12 @@ class HookOrder(str, Enum): from reflex.app import App, UnevaluatedPage from reflex_base.components.component import BaseComponent, Component from reflex_base.event import EventType - from reflex_base.plugins.compiler import ComponentAndChildren, PageContext + from reflex_base.plugins.compiler import ( + CompileContext, + ComponentAndChildren, + PageComponent, + PageContext, + ) from reflex_base.vars.base import Var @@ -58,7 +65,7 @@ class PreCompileContext(CommonContext): add_save_task: AddTaskProtocol add_modify_task: Callable[[str, Callable[[str], str]], None] radix_themes_plugin: Any - unevaluated_pages: Sequence["UnevaluatedPage"] + unevaluated_pages: Sequence[UnevaluatedPage] class AddPageProtocol(Protocol): @@ -71,14 +78,14 @@ class AddPageProtocol(Protocol): def __call__( self, - component: "Component | Callable[[], Any] | None" = None, + component: Component | Callable[[], Any] | None = None, route: str | None = None, *, - title: "str | Var | None" = None, - description: "str | Var | None" = None, + title: str | Var | None = None, + description: str | Var | None = None, image: str = ..., - on_load: "EventType[()] | None" = None, - meta: Sequence["Mapping[str, Any] | Component"] = ..., + on_load: EventType[()] | None = None, + meta: Sequence[Mapping[str, Any] | Component] = ..., context: dict[str, Any] | None = None, **extra_page_args: Any, ) -> None: @@ -101,7 +108,7 @@ def __call__( class RegisterRouteContext(CommonContext): """Context for the ``register_route`` hook.""" - app_type: type["App"] + app_type: type[App] add_page: AddPageProtocol has_app_page: Callable[[str], bool] @@ -109,7 +116,7 @@ class RegisterRouteContext(CommonContext): class PostCompileContext(CommonContext): """Context for post-compile hooks.""" - app: "App" + app: App class PostBuildContext(CommonContext): @@ -251,10 +258,10 @@ def update_env_json( def eval_page( self, - page_fn: Any, + page_fn: PageComponent, /, **kwargs: Any, - ) -> "PageContext | None": + ) -> PageContext | None: """Evaluate a page-like object into a page context. Args: @@ -268,7 +275,7 @@ def eval_page( def compile_page( self, - page_ctx: "PageContext", + page_ctx: PageContext, /, **kwargs: Any, ) -> None: @@ -277,13 +284,13 @@ def compile_page( def enter_component( self, - comp: "BaseComponent", + comp: BaseComponent, /, *, - page_context: "PageContext", - compile_context: Any, + page_context: PageContext, + compile_context: CompileContext, in_prop_tree: bool = False, - ) -> "BaseComponent | ComponentAndChildren | None": + ) -> BaseComponent | ComponentAndChildren | None: """Inspect or transform a component before visiting its descendants. Args: @@ -299,14 +306,14 @@ def enter_component( def leave_component( self, - comp: "BaseComponent", - children: tuple["BaseComponent", ...], + comp: BaseComponent, + children: tuple[BaseComponent, ...], /, *, - page_context: "PageContext", - compile_context: Any, + page_context: PageContext, + compile_context: CompileContext, in_prop_tree: bool = False, - ) -> "BaseComponent | ComponentAndChildren | None": + ) -> BaseComponent | ComponentAndChildren | None: """Inspect or transform a component after visiting its descendants. Args: diff --git a/packages/reflex-base/src/reflex_base/plugins/compiler.py b/packages/reflex-base/src/reflex_base/plugins/compiler.py index aef1cb7dd66..154ab0a421e 100644 --- a/packages/reflex-base/src/reflex_base/plugins/compiler.py +++ b/packages/reflex-base/src/reflex_base/plugins/compiler.py @@ -10,6 +10,7 @@ from reflex_base.components.component import BaseComponent, Component from reflex_base.context.base import BaseContext +from reflex_base.utils.format import callable_name from reflex_base.utils.imports import ParsedImportDict, collapse_imports, merge_imports from reflex_base.vars import VarData @@ -724,7 +725,7 @@ def compile( **kwargs, ) if page_ctx is None: - page_name = getattr(page_fn, "__name__", repr(page_fn)) + page_name = callable_name(page_fn) msg = ( f"No compiler plugin was able to evaluate page {page.route!r} " f"({page_name})." diff --git a/packages/reflex-base/src/reflex_base/plugins/shared_tailwind.py b/packages/reflex-base/src/reflex_base/plugins/shared_tailwind.py index 3908d56fc19..530ba92432b 100644 --- a/packages/reflex-base/src/reflex_base/plugins/shared_tailwind.py +++ b/packages/reflex-base/src/reflex_base/plugins/shared_tailwind.py @@ -2,7 +2,6 @@ import dataclasses import logging -from collections.abc import Mapping from copy import deepcopy from typing import Any, Literal, NotRequired, TypedDict @@ -111,7 +110,7 @@ def tailwind_config_js_template( imports = [ plugin["import"] for plugin in plugins - if isinstance(plugin, Mapping) and "import" in plugin + if not isinstance(plugin, str) and "import" in plugin ] # Generate import statements for destructured imports @@ -122,12 +121,12 @@ def tailwind_config_js_template( # Generate plugin imports plugin_imports = [] for i, plugin in enumerate(plugins, 1): - if isinstance(plugin, Mapping) and "call" not in plugin: + if isinstance(plugin, str): + plugin_imports.append(f"import plugin{i} from {json.dumps(plugin)};") + elif "call" not in plugin: plugin_imports.append( f"import plugin{i} from {json.dumps(plugin['name'])};" ) - elif not isinstance(plugin, Mapping): - plugin_imports.append(f"import plugin{i} from {json.dumps(plugin)};") plugin_imports_lines = "\n".join(plugin_imports) @@ -139,7 +138,7 @@ def tailwind_config_js_template( # Generate plugin array plugin_list = [] for i, plugin in enumerate(plugins, 1): - if isinstance(plugin, Mapping) and "call" in plugin: + if not isinstance(plugin, str) and "call" in plugin: args_part = "" if "args" in plugin: args_part = json.dumps(plugin["args"]) diff --git a/packages/reflex-base/src/reflex_base/style.py b/packages/reflex-base/src/reflex_base/style.py index 78eb046e7f3..11582386e5a 100644 --- a/packages/reflex-base/src/reflex_base/style.py +++ b/packages/reflex-base/src/reflex_base/style.py @@ -139,7 +139,7 @@ def convert_item( def convert_list( responsive_list: list[str | dict | Var], -) -> tuple[list[str | dict[str, Var | list | dict]], VarData | None]: +) -> tuple[list[Var | str | dict[str, Var | str | list | dict]], VarData | None]: """Format a responsive value list. Args: @@ -148,10 +148,10 @@ def convert_list( Returns: The recursively converted responsive value list and any associated VarData. """ - converted_value = [] + converted_value: list[Var | str | dict[str, Var | str | list | dict]] = [] item_var_datas = [] for responsive_item in responsive_list: - if isinstance(responsive_item, dict): + if not isinstance(responsive_item, Var) and isinstance(responsive_item, dict): # Recursively format nested style dictionaries. item, item_var_data = convert(responsive_item) else: @@ -162,8 +162,8 @@ def convert_list( def convert( - style_dict: dict[str, Var | dict | list | str], -) -> tuple[dict[str, str | list | dict], VarData | None]: + style_dict: Mapping[str, Any], +) -> tuple[dict[str, Var | str | list | dict], VarData | None]: """Format a style dictionary. Args: @@ -173,7 +173,7 @@ def convert( The formatted style dictionary. """ var_data = None # Track import/hook data from any Vars in the style dict. - out = {} + out: dict[str, Var | str | list | dict] = {} def update_out_dict( return_value: Var | dict | list | str, keys_to_update: tuple[str, ...] @@ -364,7 +364,7 @@ def format_as_emotion(style_dict: dict[str, Any]) -> Style | None: else: # Apply media queries from responsive value list. mbps = { - media_query([0, *breakpoints_values][bp]): ( + media_query([0, *breakpoints_values][bp]): ( # ty:ignore[invalid-argument-type] bp_value if isinstance(bp_value, dict) else {key: bp_value} ) for bp, bp_value in enumerate(value) diff --git a/packages/reflex-base/src/reflex_base/telemetry_context.py b/packages/reflex-base/src/reflex_base/telemetry_context.py index 6219a767f6c..72488951b6b 100644 --- a/packages/reflex-base/src/reflex_base/telemetry_context.py +++ b/packages/reflex-base/src/reflex_base/telemetry_context.py @@ -55,7 +55,7 @@ def set_exception(self, exc: BaseException | None) -> None: object.__setattr__(self, "exception", exc) @classmethod - def get(cls) -> TelemetryContext | None: # pyright: ignore[reportIncompatibleMethodOverride] + def get(cls) -> TelemetryContext | None: """Return the active telemetry context, or None if none is attached. Returns: diff --git a/packages/reflex-base/src/reflex_base/utils/decorator.py b/packages/reflex-base/src/reflex_base/utils/decorator.py index e2b27ee1f01..043f0e63a88 100644 --- a/packages/reflex-base/src/reflex_base/utils/decorator.py +++ b/packages/reflex-base/src/reflex_base/utils/decorator.py @@ -27,7 +27,7 @@ def once(f: Callable[[], T]) -> Callable[[], T]: def wrapper() -> T: nonlocal value value = f() if value is unset else value - return value # pyright: ignore[reportReturnType] + return value # ty:ignore[invalid-return-type] return wrapper @@ -64,12 +64,16 @@ def debug(f: Callable[P, T]) -> Callable[P, T]: Returns: A function that prints the function name, arguments, and result. """ + # Import here to avoid circular imports. + from reflex_base.utils.format import callable_name + + fn_name = callable_name(f) @functools.wraps(f) def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: result = f(*args, **kwargs) print( # noqa: T201 - f"Calling {f.__name__} with args: {args} and kwargs: {kwargs}, result: {result}" + f"Calling {fn_name} with args: {args} and kwargs: {kwargs}, result: {result}" ) return result @@ -111,7 +115,12 @@ def cached_procedure( The decorated function. """ - def _inner_decorator(func: Callable[P, Picklable]) -> Callable[P, Picklable]: + def _inner_decorator(func: Callable[P, Picklable]) -> Callable[P, Picklable]: # ty:ignore[invalid-type-form] + # Import here to avoid circular imports. + from reflex_base.utils.format import callable_name + + fn_name = callable_name(func) + def _inner(*args: P.args, **kwargs: P.kwargs) -> Picklable: cache_file = cache_file_path() @@ -124,7 +133,7 @@ def _inner(*args: P.args, **kwargs: P.kwargs) -> Picklable: return new_value logger.debug( - f"Using cached value for {func.__name__} with payload: {new_payload}" + f"Using cached value for {fn_name} with payload: {new_payload}" ) return cast("Picklable", value) diff --git a/packages/reflex-base/src/reflex_base/utils/deterministic_hash.py b/packages/reflex-base/src/reflex_base/utils/deterministic_hash.py index 39611c0de8d..0f08a70cfe2 100644 --- a/packages/reflex-base/src/reflex_base/utils/deterministic_hash.py +++ b/packages/reflex-base/src/reflex_base/utils/deterministic_hash.py @@ -65,7 +65,7 @@ def _hash_dataclass_layout(cls: type) -> tuple[bytes, tuple[tuple[bytes, str], . """ layout = _hash_dataclass_layouts.get(cls) if layout is None: - fields = dataclasses.fields(cls) # pyright: ignore [reportArgumentType] + fields = dataclasses.fields(cls) # ty:ignore[invalid-argument-type] # The defining class is part of the header: two dataclasses with the # same field names and values are different values. layout = ( diff --git a/packages/reflex-base/src/reflex_base/utils/format.py b/packages/reflex-base/src/reflex_base/utils/format.py index a06ba99c48d..3af16a9cef6 100644 --- a/packages/reflex-base/src/reflex_base/utils/format.py +++ b/packages/reflex-base/src/reflex_base/utils/format.py @@ -35,6 +35,40 @@ } +def callable_name(fn: object) -> str: + """Return ``fn.__name__`` when available, otherwise ``repr(fn)``. + + Args: + fn: The object whose display name is wanted. + + Returns: + The display name. + """ + name = getattr(fn, "__name__", None) + if isinstance(name, str): + return name + return repr(fn) + + +def callable_qualname(fn: object) -> str: + """Return ``fn.__qualname__`` when available, otherwise the display name. + + Like :func:`callable_name` but keeps the qualifying path (e.g. + ``MyState.handler``) for callables that expose ``__qualname__``, falling + back to :func:`callable_name` for those that don't (e.g. ``partial``). + + Args: + fn: The object whose qualified name is wanted. + + Returns: + The qualified display name. + """ + qualname = getattr(fn, "__qualname__", None) + if isinstance(qualname, str): + return qualname + return callable_name(fn) + + def length_of_largest_common_substring(str1: str, str2: str) -> int: """Find the length of the largest common substring between two strings. @@ -562,15 +596,15 @@ def _default_args_spec(): payloads = [] if not is_non_string_sequence(events): - events = [events] + events = [events] # ty:ignore[invalid-assignment] https://github.com/astral-sh/ty/issues/4394 # Process each event/spec/lambda (similar to Component._create_event_chain). - for spec in events: + for spec in events: # ty:ignore[not-iterable] https://github.com/astral-sh/ty/issues/4394 specs: list[EventSpec] = [] if isinstance(spec, (EventHandler, EventSpec)): specs = [call_event_handler(spec, args_spec or _default_args_spec)] elif isinstance(spec, type(lambda: None)): - specs = call_event_fn(spec, args_spec or _default_args_spec) # pyright: ignore [reportAssignmentType, reportArgumentType] + specs = call_event_fn(spec, args_spec or _default_args_spec) # ty:ignore[invalid-assignment] if isinstance(specs, Var): msg = f"Invalid event spec: {specs}. Expected a list of EventSpecs." raise ValueError(msg) diff --git a/packages/reflex-base/src/reflex_base/utils/imports.py b/packages/reflex-base/src/reflex_base/utils/imports.py index f82fd8d0090..f774c837e07 100644 --- a/packages/reflex-base/src/reflex_base/utils/imports.py +++ b/packages/reflex-base/src/reflex_base/utils/imports.py @@ -5,6 +5,7 @@ import dataclasses from collections import defaultdict from collections.abc import Iterable, Mapping, Sequence +from typing import final # Absolute import paths beginning with one of these reserved ``.web`` # subdirectories are rewritten to ``$``-prefixed module specifiers. @@ -204,6 +205,7 @@ def collapse_imports( } +@final @dataclasses.dataclass(frozen=True) class ImportVar: """An import var.""" diff --git a/packages/reflex-base/src/reflex_base/utils/log.py b/packages/reflex-base/src/reflex_base/utils/log.py index 725313fe889..6ac71a2444d 100644 --- a/packages/reflex-base/src/reflex_base/utils/log.py +++ b/packages/reflex-base/src/reflex_base/utils/log.py @@ -227,7 +227,7 @@ def emit(self, record: logging.LogRecord): "markup": markup, **getattr(record, _RICH_KWARGS_FIELD, {}), } - console.print(f"{prefix}{record.getMessage()}", **print_kwargs) + console.print(f"{prefix}{record.getMessage()}", **print_kwargs) # ty:ignore[invalid-argument-type] if record.exc_info and record.exc_info[0] is not None: # Tracebacks may contain user data; never parse them as markup. # Never word-wrap them either: wrapping breaks file paths. @@ -249,7 +249,7 @@ def format_exception(self, record: logging.LogRecord) -> str: Returns: The formatted traceback. """ - return _EXC_FORMATTER.formatException(record.exc_info) # pyright: ignore[reportArgumentType] + return _EXC_FORMATTER.formatException(record.exc_info) # ty:ignore[invalid-argument-type] def _write_json(payload: dict, *, stderr: bool): diff --git a/packages/reflex-base/src/reflex_base/utils/pyi_generator.py b/packages/reflex-base/src/reflex_base/utils/pyi_generator.py index 894aff53bdb..bdd46b08442 100644 --- a/packages/reflex-base/src/reflex_base/utils/pyi_generator.py +++ b/packages/reflex-base/src/reflex_base/utils/pyi_generator.py @@ -488,7 +488,7 @@ def _get_class_annotation_globals(target_class: type) -> Mapping[str, Any]: @cache -def _get_class_event_triggers(target_class: type) -> frozenset[str]: +def _get_class_event_triggers(target_class: type[Component]) -> frozenset[str]: """Get and cache event trigger names for a class. Args: @@ -513,7 +513,7 @@ def _generate_imports( """ return [ *[ - ast.ImportFrom(module=name, names=[ast.alias(name=val) for val in values]) # pyright: ignore [reportCallIssue] + ast.ImportFrom(module=name, names=[ast.alias(name=val) for val in values]) # ty:ignore[no-matching-overload] for name, values in DEFAULT_IMPORTS.items() ], ast.Import([ast.alias("reflex")]), @@ -600,7 +600,7 @@ def _extract_func_kwargs_as_ast_nodes( def _extract_class_props_as_ast_nodes( func: Callable, - clzs: list[type], + clzs: list[type[Component]], type_hint_globals: dict[str, Any], extract_real_default: bool = False, ) -> Sequence[tuple[ast.arg, ast.Constant | None]]: @@ -649,7 +649,7 @@ def _extract_class_props_as_ast_nodes( # with the annotation in some cases. with contextlib.suppress(AttributeError, KeyError): # Try to get default from pydantic field definition. - default = target_class.__fields__[name].default + default = target_class.__fields__[name].default # ty:ignore[unresolved-attribute] if isinstance(default, Var): default = default._decode() @@ -666,7 +666,7 @@ def _extract_class_props_as_ast_nodes( ) ), ), - ast.Constant(value=default), # pyright: ignore [reportArgumentType] + ast.Constant(value=default), )) return kwargs @@ -690,7 +690,8 @@ def _get_visible_type_name( type_name = getattr(typ, "__name__", None) if type_name is not None and ( - type_hint_globals.get(type_name) is typ + type_module in ("builtins", "__builtins__") + or type_hint_globals.get(type_name) is typ or type_name in DEFAULT_IMPORTS.get(str(type_module), set()) or type_name in EXCLUDED_IMPORTS.get(str(type_module), set()) ): @@ -754,7 +755,9 @@ def type_to_ast( return ast.Name(id=str(typ)) # Get the base type name (List, Dict, Optional, etc.) - base_name = getattr(origin, "_name", origin.__name__) + base_name = getattr(origin, "_name", None) or getattr( + origin, "__name__", repr(origin) + ) # Get type arguments args = get_args(typ) @@ -845,7 +848,9 @@ def _generate_component_create_functiondef( # kwargs associated with props defined in the class and its parents all_classes = [c for c in clz.__mro__ if issubclass(c, Component)] prop_kwargs = _extract_class_props_as_ast_nodes( - clz.create, all_classes, type_hint_globals + clz.create, + all_classes, + type_hint_globals, ) all_props = [arg[0].arg for arg in prop_kwargs] kwargs.extend(prop_kwargs) @@ -972,7 +977,7 @@ def figure_out_return_type(annotation: Any): defaults=[], ) - return ast.FunctionDef( # pyright: ignore [reportCallIssue] + return ast.FunctionDef( name="create", args=create_args, body=[ @@ -1024,7 +1029,7 @@ def _generate_staticmethod_call_functiondef( else [] ), ) - return ast.FunctionDef( # pyright: ignore [reportCallIssue] + return ast.FunctionDef( name="__call__", args=call_args, body=[ @@ -1082,7 +1087,7 @@ def _generate_namespace_call_functiondef( # Determine which class is wrapped by the namespace __call__ method component_clz = clz.__call__.__self__ - if clz.__call__.__func__.__name__ != "create": # pyright: ignore [reportFunctionMemberAccess] + if clz.__call__.__func__.__name__ != "create": return None if not issubclass(component_clz, Component): @@ -1190,7 +1195,7 @@ def visit_Module(self, node: ast.Module) -> ast.Module: The modified Module node. """ self.generic_visit(node) - return self._remove_docstring(node) # pyright: ignore [reportReturnType] + return self._remove_docstring(node) # ty:ignore[invalid-return-type] def visit_Import( self, node: ast.Import | ast.ImportFrom @@ -1420,8 +1425,13 @@ def visit_AnnAssign(self, node: ast.AnnAssign) -> ast.AnnAssign | None: if self._current_class_is_component(): # Remove annotated assignments in Component classes (props) return None - # Blank out assignments in type stubs. - node.value = None + # Blank out assignments in type stubs. In a class body keep `...` when there + # was one: for dataclass-like classes (e.g. PropsBase) a default is what + # makes the field optional in the synthesized __init__. + if self.current_class is not None and node.value is not None: + node.value = ast.Constant(value=...) + else: + node.value = None return node diff --git a/packages/reflex-base/src/reflex_base/utils/serializers.py b/packages/reflex-base/src/reflex_base/utils/serializers.py index 29ac48cf60f..d393c1d4e5b 100644 --- a/packages/reflex-base/src/reflex_base/utils/serializers.py +++ b/packages/reflex-base/src/reflex_base/utils/serializers.py @@ -124,7 +124,7 @@ def wrapper(fn: SERIALIZED_FUNCTION) -> SERIALIZED_FUNCTION: if registered_fn is None and (name := _get_optional_type_name(type_)): registered_fn = _OPTIONAL_SERIALIZERS[name] if registered_fn is not None and registered_fn != fn and overwrite is not True: - message = f"Overwriting serializer for type {type_} from {registered_fn.__module__}:{registered_fn.__qualname__} to {fn.__module__}:{fn.__qualname__}." + message = f"Overwriting serializer for type {type_} from {registered_fn.__module__}:{registered_fn.__qualname__} to {fn.__module__}:{fn.__qualname__}." # ty:ignore[unresolved-attribute] if overwrite is False: raise ValueError(message) caller_frame = next( @@ -594,7 +594,7 @@ def serialize_image(image: _serializer_types.Image) -> str: base64_image = base64.b64encode(image_bytes).decode("utf-8") try: # Newer method to get the mime type, but does not always work. - mime_type = image.get_format_mimetype() # pyright: ignore [reportAttributeAccessIssue] + mime_type = image.get_format_mimetype() # ty:ignore[unresolved-attribute] except AttributeError: try: # Fallback method diff --git a/packages/reflex-base/src/reflex_base/utils/types.py b/packages/reflex-base/src/reflex_base/utils/types.py index eead8d73f30..b567f1e37c2 100644 --- a/packages/reflex-base/src/reflex_base/utils/types.py +++ b/packages/reflex-base/src/reflex_base/utils/types.py @@ -5,11 +5,12 @@ import ast import builtins import dataclasses +import inspect import logging import sys import types import typing -from collections.abc import Callable, Iterable, Mapping, Sequence +from collections.abc import Callable, Hashable, Iterable, Mapping, Sequence from enum import Enum from functools import lru_cache from importlib.util import find_spec @@ -29,9 +30,9 @@ Tuple, TypeVar, Union, - _eval_type, # pyright: ignore [reportAttributeAccessIssue] - _GenericAlias, # pyright: ignore [reportAttributeAccessIssue] - _SpecialGenericAlias, # pyright: ignore [reportAttributeAccessIssue] + _eval_type, # ty:ignore[unresolved-import] + _GenericAlias, # ty:ignore[unresolved-import] + _SpecialGenericAlias, # ty:ignore[unresolved-import] get_args, is_typeddict, ) @@ -51,6 +52,21 @@ if TYPE_CHECKING: PROPERTY_CLASSES: tuple[type, ...] + +def set_signature(fn: Any, signature: inspect.Signature) -> None: + """Attach an explicit ``__signature__`` to a callable. + + ``__signature__`` is an optional attribute that ``inspect.signature`` reads + when present, but it is not part of a function's static type, so it is set + here through an ``Any``-typed handle rather than direct attribute access. + + Args: + fn: The callable to annotate. + signature: The signature to expose for ``fn``. + """ + fn.__signature__ = signature + + # Potential GenericAlias types for isinstance checks. GenericAliasTypes = (_GenericAlias, GenericAlias, _SpecialGenericAlias) @@ -95,68 +111,68 @@ VAR7 = TypeVar("VAR7", bound="Var") -class _ArgsSpec0(Protocol): +class _ArgsSpec0(Hashable, Protocol): def __call__(self) -> Sequence[Var]: ... -class _ArgsSpec1(Protocol): - def __call__(self, var1: VAR1, /) -> Sequence[Var]: ... # pyright: ignore [reportInvalidTypeVarUse] +class _ArgsSpec1(Hashable, Protocol): + def __call__(self, var1: VAR1, /) -> Sequence[Var]: ... -class _ArgsSpec2(Protocol): - def __call__(self, var1: VAR1, var2: VAR2, /) -> Sequence[Var]: ... # pyright: ignore [reportInvalidTypeVarUse] +class _ArgsSpec2(Hashable, Protocol): + def __call__(self, var1: VAR1, var2: VAR2, /) -> Sequence[Var]: ... -class _ArgsSpec3(Protocol): - def __call__(self, var1: VAR1, var2: VAR2, var3: VAR3, /) -> Sequence[Var]: ... # pyright: ignore [reportInvalidTypeVarUse] +class _ArgsSpec3(Hashable, Protocol): + def __call__(self, var1: VAR1, var2: VAR2, var3: VAR3, /) -> Sequence[Var]: ... -class _ArgsSpec4(Protocol): +class _ArgsSpec4(Hashable, Protocol): def __call__( self, - var1: VAR1, # pyright: ignore [reportInvalidTypeVarUse] - var2: VAR2, # pyright: ignore [reportInvalidTypeVarUse] - var3: VAR3, # pyright: ignore [reportInvalidTypeVarUse] - var4: VAR4, # pyright: ignore [reportInvalidTypeVarUse] + var1: VAR1, + var2: VAR2, + var3: VAR3, + var4: VAR4, /, ) -> Sequence[Var]: ... -class _ArgsSpec5(Protocol): +class _ArgsSpec5(Hashable, Protocol): def __call__( self, - var1: VAR1, # pyright: ignore [reportInvalidTypeVarUse] - var2: VAR2, # pyright: ignore [reportInvalidTypeVarUse] - var3: VAR3, # pyright: ignore [reportInvalidTypeVarUse] - var4: VAR4, # pyright: ignore [reportInvalidTypeVarUse] - var5: VAR5, # pyright: ignore [reportInvalidTypeVarUse] + var1: VAR1, + var2: VAR2, + var3: VAR3, + var4: VAR4, + var5: VAR5, /, ) -> Sequence[Var]: ... -class _ArgsSpec6(Protocol): +class _ArgsSpec6(Hashable, Protocol): def __call__( self, - var1: VAR1, # pyright: ignore [reportInvalidTypeVarUse] - var2: VAR2, # pyright: ignore [reportInvalidTypeVarUse] - var3: VAR3, # pyright: ignore [reportInvalidTypeVarUse] - var4: VAR4, # pyright: ignore [reportInvalidTypeVarUse] - var5: VAR5, # pyright: ignore [reportInvalidTypeVarUse] - var6: VAR6, # pyright: ignore [reportInvalidTypeVarUse] + var1: VAR1, + var2: VAR2, + var3: VAR3, + var4: VAR4, + var5: VAR5, + var6: VAR6, /, ) -> Sequence[Var]: ... -class _ArgsSpec7(Protocol): +class _ArgsSpec7(Hashable, Protocol): def __call__( self, - var1: VAR1, # pyright: ignore [reportInvalidTypeVarUse] - var2: VAR2, # pyright: ignore [reportInvalidTypeVarUse] - var3: VAR3, # pyright: ignore [reportInvalidTypeVarUse] - var4: VAR4, # pyright: ignore [reportInvalidTypeVarUse] - var5: VAR5, # pyright: ignore [reportInvalidTypeVarUse] - var6: VAR6, # pyright: ignore [reportInvalidTypeVarUse] - var7: VAR7, # pyright: ignore [reportInvalidTypeVarUse] + var1: VAR1, + var2: VAR2, + var3: VAR3, + var4: VAR4, + var5: VAR5, + var6: VAR6, + var7: VAR7, /, ) -> Sequence[Var]: ... @@ -542,7 +558,7 @@ def get_typed_dict_field_types(typed_dict: Any) -> dict[str, Any]: def _unionize(args: list[GenericType]) -> GenericType: if not args: - return Any # pyright: ignore [reportReturnType] + return Any if len(args) == 1: return args[0] return Union[tuple(args)] # noqa: UP007 @@ -632,8 +648,9 @@ def has_args(cls: type) -> bool: return True # Check if the class inherits from a generic class (using __orig_bases__) - if hasattr(cls, "__orig_bases__"): - for base in cls.__orig_bases__: + orig_bases = getattr(cls, "__orig_bases__", None) + if orig_bases is not None: + for base in orig_bases: if get_args(base): return True @@ -1023,15 +1040,15 @@ def get_attribute_access_type( except NotImplementedError: type_ = None if type_ is not None: - if hasattr(column_type, "item_type"): + if isinstance(column_type, sqlalchemy.ARRAY): try: - item_type = column_type.item_type.python_type # pyright: ignore [reportAttributeAccessIssue] + item_type = column_type.item_type.python_type except NotImplementedError: item_type = None if item_type is not None: if type_ in PrimitiveToAnnotation: type_ = PrimitiveToAnnotation[type_] - type_ = type_[item_type] # pyright: ignore [reportIndexIssue] + type_ = type_[item_type] if hasattr(column, "nullable") and column.nullable: type_ = type_ | None return type_ @@ -1049,8 +1066,8 @@ def get_attribute_access_type( return list[ get_attribute_access_type( attr.target_class, - attr.remote_attr.key, # pyright: ignore [reportAttributeAccessIssue] - ) + attr.remote_attr.key, + ) # ty:ignore[invalid-type-form] ] elif ( sqlmodel_type is not None @@ -1061,7 +1078,7 @@ def get_attribute_access_type( and declares_annotation(cls, name) ): # Check in the annotations directly (for sqlmodel.Relationship) - hints = get_type_hints(cls) # pyright: ignore [reportArgumentType] + hints = get_type_hints(cls) if name in hints: type_ = hints[name] type_origin = get_origin(type_) @@ -1080,7 +1097,7 @@ def get_attribute_access_type( # ForwardRef resolution of unrelated annotations. try: if declares_annotation(cls, name): - hints = get_type_hints(cls) # pyright: ignore [reportArgumentType] + hints = get_type_hints(cls) if name in hints: return hints[name] except NameError as e: @@ -1110,7 +1127,7 @@ def get_base_class(cls: GenericType) -> type: return type(get_args(cls)[0]) if is_union(cls): - return tuple(get_base_class(arg) for arg in get_args(cls)) # pyright: ignore [reportReturnType] + return tuple(get_base_class(arg) for arg in get_args(cls)) # ty:ignore[invalid-return-type] return get_base_class(cls.__origin__) if is_generic_alias(cls) else cls @@ -1536,13 +1553,14 @@ def validate_literal(key: str, value: Any, expected_type: type, comp_name: str): """ from reflex_base.vars import Var + expected_args = get_args(expected_type) if ( is_literal(expected_type) and not isinstance(value, Var) # validating vars is not supported yet. and not is_encoded_fstring(value) # f-strings are not supported. - and value not in expected_type.__args__ + and value not in expected_args ): - allowed_values = expected_type.__args__ + allowed_values = expected_args if value not in allowed_values: allowed_value_str = ",".join([ str(v) if not isinstance(v, str) else f"'{v}'" for v in allowed_values @@ -1805,7 +1823,7 @@ def _resolve_annotation( def resolve_annotations( raw_annotations: Mapping[str, type[Any]], module_name: str | None -) -> dict[str, type[Any]]: +) -> dict[str, type[Any] | ForwardRef]: """Partially taken from typing.get_type_hints. Resolve string or ForwardRef annotations into type objects if possible. @@ -1815,7 +1833,9 @@ def resolve_annotations( module_name: The name of the module. Returns: - The resolved annotations. + The resolved annotations. Entries that could not be resolved remain + as ``ForwardRef`` instances (callers can re-resolve them later via + ``update_forward_refs``). """ module = sys.modules.get(module_name, None) if module_name is not None else None diff --git a/packages/reflex-base/src/reflex_base/vars/base.py b/packages/reflex-base/src/reflex_base/vars/base.py index 500579629ce..78cebf6031b 100644 --- a/packages/reflex-base/src/reflex_base/vars/base.py +++ b/packages/reflex-base/src/reflex_base/vars/base.py @@ -63,7 +63,7 @@ VarDependencyError, VarTypeError, ) -from reflex_base.utils.format import format_state_name, json_dumps +from reflex_base.utils.format import callable_name, format_state_name, json_dumps from reflex_base.utils.imports import ( ImmutableImportDict, ImmutableParsedImportDict, @@ -785,7 +785,7 @@ def __init_subclass__( frozen=True, slots=True, ) - class ToVarOperation(ToOperation, cls): + class ToVarOperation(ToOperation, cls): # ty:ignore[shadowed-type-variable] """Base class of converting a var to another var type.""" _original: Var = dataclasses.field( @@ -960,7 +960,7 @@ def _replace( @overload @classmethod - def create( # pyright: ignore[reportOverlappingOverload] + def create( cls, value: NoReturn, _var_data: VarData | None = None, @@ -968,7 +968,7 @@ def create( # pyright: ignore[reportOverlappingOverload] @overload @classmethod - def create( # pyright: ignore[reportOverlappingOverload] + def create( cls, value: builtins.bool, _var_data: VarData | None = None, @@ -1000,7 +1000,7 @@ def create( @overload @classmethod - def create( # pyright: ignore [reportOverlappingOverload] + def create( cls, value: Color, _var_data: VarData | None = None, @@ -1008,7 +1008,7 @@ def create( # pyright: ignore [reportOverlappingOverload] @overload @classmethod - def create( # pyright: ignore [reportOverlappingOverload] + def create( cls, value: LITERAL_STRING_T, _var_data: VarData | None = None, @@ -1016,7 +1016,7 @@ def create( # pyright: ignore [reportOverlappingOverload] @overload @classmethod - def create( # pyright: ignore [reportOverlappingOverload] + def create( cls, value: STRING_T, _var_data: VarData | None = None, @@ -1024,7 +1024,7 @@ def create( # pyright: ignore [reportOverlappingOverload] @overload @classmethod - def create( # pyright: ignore[reportOverlappingOverload] + def create( cls, value: None, _var_data: VarData | None = None, @@ -1092,7 +1092,7 @@ def __format__(self, format_spec: str) -> str: return f"{constants.REFLEX_VAR_OPENING_TAG}{hashed_var}{constants.REFLEX_VAR_CLOSING_TAG}{self._js_expr}" @overload - def to(self, output: type[str]) -> StringVar: ... # pyright: ignore[reportOverlappingOverload] + def to(self, output: type[str]) -> StringVar: ... @overload def to(self, output: type[builtins.bool]) -> BooleanVar: ... @@ -1160,7 +1160,7 @@ def to( return self.to(conversion_entry.var_subclass, output) if fixed_output_type is None: - return get_to_operation(NoneVar).create(self) # pyright: ignore [reportReturnType] + return get_to_operation(NoneVar).create(self) is_class = isinstance(output, type) if ( @@ -1172,7 +1172,7 @@ def to( new_var_type = var_type else: new_var_type = var_type or current_var_type - return output_entry.to_var_subclass.create( # pyright: ignore [reportReturnType] + return output_entry.to_var_subclass.create( value=self, _var_type=new_var_type ) @@ -1199,7 +1199,7 @@ def to( return self @overload - def guess_type(self: Var[NoReturn]) -> Var[Any]: ... # pyright: ignore [reportOverlappingOverload] + def guess_type(self: Var[NoReturn]) -> Var[Any]: ... @overload def guess_type(self: Var[str]) -> StringVar: ... @@ -1371,13 +1371,13 @@ def _var_set_state(self, state: type[BaseState] | str) -> Self: else format_state_name(state.get_full_name()) ) - return StateOperation.create( # pyright: ignore [reportReturnType] + return StateOperation.create( formatted_state_name, self, _var_data=VarData.merge( VarData.from_state(state, self._js_expr), self._var_data ), - ).guess_type() + ).guess_type() # ty:ignore[invalid-return-type] def __eq__(self, other: Var | Any) -> BooleanVar: """Check if the current variable is equal to the given variable. @@ -1726,9 +1726,18 @@ def __contains__(self, _: Any) -> Var: VAR_INSIDE = TypeVar("VAR_INSIDE") +@dataclasses.dataclass(eq=False, frozen=True) class ToOperation: """A var operation that converts a var to another type.""" + _js_expr: str = "" + _var_type: GenericType = Any + _var_data: VarData | None = None + _original: Var = dataclasses.field( + default_factory=lambda: Var(_js_expr="null", _var_type=None) + ) + _default_var_type: ClassVar[GenericType] = Any + def __getattr__(self, name: str) -> Any: """Get an attribute of the var. @@ -1792,10 +1801,10 @@ def create( The ToOperation. """ return cls( - _js_expr="", # pyright: ignore [reportCallIssue] - _var_data=_var_data, # pyright: ignore [reportCallIssue] - _var_type=_var_type or cls._default_var_type, # pyright: ignore [reportCallIssue, reportAttributeAccessIssue] - _original=value, # pyright: ignore [reportCallIssue] + _js_expr="", + _var_data=_var_data, + _var_type=_var_type or cls._default_var_type, + _original=value, ) @@ -2060,7 +2069,7 @@ def get_python_literal(value: LiteralVar | Any) -> Any | None: # NoReturn is used to match CustomVarOperationReturn with no type hint. @overload -def var_operation( # pyright: ignore [reportOverlappingOverload] +def var_operation( func: Callable[P, CustomVarOperationReturn[NoReturn]], ) -> Callable[P, Var]: ... @@ -2072,7 +2081,7 @@ def var_operation( @overload -def var_operation( # pyright: ignore [reportOverlappingOverload] +def var_operation( func: Callable[P, CustomVarOperationReturn[bool]] | Callable[P, CustomVarOperationReturn[bool | None]], ) -> Callable[P, BooleanVar]: ... @@ -2122,7 +2131,7 @@ def var_operation( ) -> Callable[P, Var[T]]: ... -def var_operation( # pyright: ignore [reportInconsistentOverload] +def var_operation( func: Callable[P, CustomVarOperationReturn[T]], ) -> Callable[P, Var[T]]: """Decorator for creating a var operation. @@ -2157,9 +2166,9 @@ def wrapper(*args: P.args, **kwargs: P.kwargs) -> Var[T]: op_args += tuple(kwargs_vars.items()) return CustomVarOperation.create( - name=func.__name__, + name=callable_name(func), args=op_args, - return_var=func(*args_vars, **kwargs_vars), # pyright: ignore [reportCallIssue, reportReturnType] + return_var=func(*args_vars, **kwargs_vars), # ty:ignore[invalid-argument-type] ).guess_type() return wrapper @@ -2182,21 +2191,21 @@ def figure_out_type(value: Any) -> types.GenericType: if isinstance(value, list): if not value: return Sequence[NoReturn] - return Sequence[unionize(*{figure_out_type(v) for v in value[:100]})] + return Sequence[unionize(*{figure_out_type(v) for v in value[:100]})] # ty:ignore[invalid-type-form] if isinstance(value, set): - return set[unionize(*{figure_out_type(v) for v in value})] + return set[unionize(*{figure_out_type(v) for v in value})] # ty:ignore[invalid-type-form] if isinstance(value, tuple): if not value: return tuple[NoReturn, ...] if len(value) <= 5: - return tuple[tuple(figure_out_type(v) for v in value)] - return tuple[unionize(*{figure_out_type(v) for v in value[:100]}), ...] + return tuple[tuple(figure_out_type(v) for v in value)] # ty:ignore[invalid-type-form] + return tuple[unionize(*{figure_out_type(v) for v in value[:100]}), ...] # ty:ignore[invalid-type-form] if isinstance(value, Mapping): if not value: return Mapping[NoReturn, NoReturn] return Mapping[ - unionize(*{figure_out_type(k) for k in list(value.keys())[:100]}), - unionize(*{figure_out_type(v) for v in list(value.values())[:100]}), + unionize(*{figure_out_type(k) for k in list(value.keys())[:100]}), # ty:ignore[invalid-type-form] + unionize(*{figure_out_type(v) for v in list(value.values())[:100]}), # ty:ignore[invalid-type-form] ] return type(value) @@ -2253,8 +2262,8 @@ def delete_properties(this: Any): if original_del is not None: original_del(this) - delete_properties.cached_field_names = cached_field_names # pyright: ignore [reportFunctionMemberAccess] - delete_properties.original_del = original_del # pyright: ignore [reportFunctionMemberAccess] + delete_properties.cached_field_names = cached_field_names # ty:ignore[unresolved-attribute] + delete_properties.original_del = original_del # ty:ignore[unresolved-attribute] owner.__del__ = delete_properties elif name != self._attrname: @@ -2341,7 +2350,7 @@ def __getattr__(self, name: str) -> Any: next_class = parent_classes[parent_classes.index(CachedVarOperation) + 1] - return next_class.__getattr__(self, name) + return next_class.__getattr__(self, name) # ty:ignore[unresolved-attribute] def _get_all_var_data(self) -> VarData | None: """Get all VarData associated with the Var. @@ -2584,7 +2593,7 @@ class ComputedVar(Var[RETURN_TYPE]): _fget: Callable[[BaseState], RETURN_TYPE] = dataclasses.field( default_factory=lambda: lambda _: None - ) # pyright: ignore [reportAssignmentType] + ) # ty:ignore[invalid-assignment] _name: str = dataclasses.field(default="") @@ -2622,10 +2631,11 @@ def __init__( "return", Any ) + fget_name = callable_name(fget) if hint is Any: - raise UntypedComputedVarError(var_name=fget.__name__) + raise UntypedComputedVarError(var_name=fget_name) is_using_fget_name = "_js_expr" not in kwargs - js_expr = kwargs.pop("_js_expr", fget.__name__ + FIELD_MARKER) + js_expr = kwargs.pop("_js_expr", fget_name + FIELD_MARKER) kwargs.setdefault("_var_type", hint) Var.__init__( @@ -2634,7 +2644,7 @@ def __init__( _var_type=kwargs.pop("_var_type"), _var_data=kwargs.pop( "_var_data", - VarData(field_name=fget.__name__) if is_using_fget_name else None, + VarData(field_name=fget_name) if is_using_fget_name else None, ), ) @@ -2643,12 +2653,12 @@ def __init__( raise TypeError(msg) if backend is None: - backend = fget.__name__.startswith("_") + backend = fget_name.startswith("_") object.__setattr__(self, "_backend", backend) object.__setattr__(self, "_initial_value", initial_value) object.__setattr__(self, "_cache", cache) - object.__setattr__(self, "_name", fget.__name__) + object.__setattr__(self, "_name", fget_name) if isinstance(interval, int): interval = datetime.timedelta(seconds=interval) @@ -2896,6 +2906,13 @@ def __get__( owner: type, ) -> ObjectVar[SQLA_TYPE]: ... + @overload + def __get__( + self: ComputedVar[BASE_MODEL_TYPE], + instance: None, + owner: type, + ) -> ObjectVar[BASE_MODEL_TYPE]: ... + if TYPE_CHECKING: @overload @@ -2909,7 +2926,7 @@ def __get__(self, instance: None, owner: type) -> ComputedVar[RETURN_TYPE]: ... @overload def __get__(self, instance: BaseState, owner: type) -> RETURN_TYPE: ... - def __get__(self, instance: Any, owner: type): + def __get__(self, instance: Any, owner: type[BaseState]): """Get the ComputedVar value. If the value is already cached on the instance, return the cached value. @@ -3031,12 +3048,14 @@ def _deps( """ from .dep_tracking import DependencyTracker - d = {} + d: dict[str, set[str]] = {} if self._static_deps: - d.update(self._static_deps) - # None is a placeholder for the current state class. - if None in d: - d[objclass.get_full_name()] = d.pop(None) + # None is a placeholder for the current state class, which may + # also be named explicitly; merge both into one entry. + for k, v in self._static_deps.items(): + d.setdefault( + k if k is not None else objclass.get_full_name(), set() + ).update(v) if not self._auto_deps: return d @@ -3122,7 +3141,7 @@ def _determine_var_type(self) -> type: hints = get_type_hints(self._fget) if "return" in hints: return hints["return"] - return Any # pyright: ignore [reportReturnType] + return Any @property def __class__(self) -> type: @@ -3213,6 +3232,13 @@ def __get__( owner: type, ) -> ObjectVar[SQLA_TYPE]: ... + @overload + def __get__( + self: AsyncComputedVar[BASE_MODEL_TYPE], + instance: None, + owner: type, + ) -> ObjectVar[BASE_MODEL_TYPE]: ... + if TYPE_CHECKING: @overload @@ -3390,7 +3416,7 @@ def computed_var( if fget is not None: sign = inspect.signature(fget) if len(sign.parameters) != 1: - raise ComputedVarSignatureError(fget.__name__, signature=str(sign)) + raise ComputedVarSignatureError(callable_name(fget), signature=str(sign)) if inspect.iscoroutinefunction(fget): computed_var_cls = AsyncComputedVar @@ -3942,15 +3968,16 @@ def transform(fn: Callable[[Var], Var]) -> Callable[[Var], Var]: return_type = types["return"] origin = get_origin(return_type) + fn_name = callable_name(fn) if origin is not Var: - msg = f"Expected return type of {fn.__name__} to be a Var, got {origin}." + msg = f"Expected return type of {fn_name} to be a Var, got {origin}." raise TypeError(msg) generic_args = get_args(return_type) if not generic_args: - msg = f"Expected Var return type of {fn.__name__} to have a generic type." + msg = f"Expected Var return type of {fn_name} to have a generic type." raise TypeError(msg) generic_type = get_origin(generic_args[0]) or generic_args[0] @@ -3991,6 +4018,7 @@ def dispatch( if result_origin_var_type in dispatchers: fn = dispatchers[result_origin_var_type] + fn_name = callable_name(fn) fn_types = get_type_hints(fn) fn_first_arg_type = fn_types.get( next(iter(inspect.signature(fn).parameters.values())).name, Any @@ -4001,7 +4029,7 @@ def dispatch( fn_return_origin = get_origin(fn_return) or fn_return if fn_return_origin is not Var: - msg = f"Expected return type of {fn.__name__} to be a Var, got {fn_return}." + msg = f"Expected return type of {fn_name} to be a Var, got {fn_return}." raise TypeError(msg) fn_return_generic_args = get_args(fn_return) @@ -4013,7 +4041,7 @@ def dispatch( arg_origin = get_origin(fn_first_arg_type) or fn_first_arg_type if arg_origin is not Var: - msg = f"Expected first argument of {fn.__name__} to be a Var, got {fn_first_arg_type}." + msg = f"Expected first argument of {fn_name} to be a Var, got {fn_first_arg_type}." raise TypeError(msg) arg_generic_args = get_args(fn_first_arg_type) @@ -4055,10 +4083,14 @@ def dispatch( if TYPE_CHECKING: from _typeshed import DataclassInstance + from pydantic import BaseModel from sqlalchemy.orm import DeclarativeBase SQLA_TYPE = TypeVar("SQLA_TYPE", bound=DeclarativeBase | None) DATACLASS_TYPE = TypeVar("DATACLASS_TYPE", bound=DataclassInstance | None) + # Pydantic models are not dataclasses (no `__dataclass_fields__` at runtime), so + # they need their own overloads to resolve to ObjectVar. + BASE_MODEL_TYPE = TypeVar("BASE_MODEL_TYPE", bound=BaseModel | None) MAPPING_TYPE = TypeVar("MAPPING_TYPE", bound=Mapping | None) V = TypeVar("V") @@ -4155,8 +4187,7 @@ def __init__( default: FIELD_TYPE | MISSING_TYPE = MISSING, default_factory: Callable[[], FIELD_TYPE] | None = None, is_var: bool = True, - annotated_type: GenericType # pyright: ignore [reportRedeclaration] - | MISSING_TYPE = MISSING, + annotated_type: GenericType | MISSING_TYPE = MISSING, source_field: Field | None = None, ) -> None: """Initialize the field. @@ -4180,7 +4211,7 @@ def __init__( and issubclass(type_origin, Field) and (args := getattr(annotated_type, "__args__", None)) ): - annotated_type: GenericType = args[0] + annotated_type = args[0] type_origin = get_origin(annotated_type) or annotated_type if self.default is MISSING and self.default_factory is None: @@ -4200,7 +4231,7 @@ def __init__( self.outer_type_ = self.annotated_type = annotated_type if type_origin is Annotated: - type_origin = annotated_type.__origin__ # pyright: ignore [reportAttributeAccessIssue] + type_origin = annotated_type.__origin__ self.type_ = self.type_origin = type_origin else: @@ -4240,14 +4271,15 @@ def _replace(self, **kwargs: Any) -> Self: Returns: The new field. """ - return type(self)(**{ + arguments: dict[str, Any] = { "default": self.default, "default_factory": self.default_factory, "is_var": self.is_var, "annotated_type": self.annotated_type, "source_field": self, **kwargs, - }) + } + return type(self)(**arguments) @classmethod def _with_default(cls, value: Any, annotated_type: Any = MISSING) -> Self: @@ -4372,7 +4404,7 @@ def _get_raw(self, instance: Any) -> FIELD_TYPE | None: state = ( instance if type(instance) is self._owner - else _owner_state(instance, self._owner) # pyright: ignore[reportArgumentType] + else _owner_state(instance, self._owner) # ty:ignore[invalid-argument-type] ) try: return state.__dict__[self._name] @@ -4390,7 +4422,7 @@ def __set__(self, instance: Any, value: FIELD_TYPE): state = ( instance if type(instance) is self._owner - else _owner_state(instance, self._owner) # pyright: ignore[reportArgumentType] + else _owner_state(instance, self._owner) # ty:ignore[invalid-argument-type] ) if isinstance(value, self._proxy): value = value.__wrapped__ # pyright: ignore[reportAttributeAccessIssue] @@ -4457,12 +4489,22 @@ def __get__( @overload def __get__( - self: Field[list[V]] - | Field[set[V]] - | Field[list[V] | None] - | Field[set[V] | None], - instance: None, - owner: Any, + self: Field[list[V]], instance: None, owner: Any + ) -> ArrayVar[Sequence[V]]: ... + + @overload + def __get__( + self: Field[set[V]], instance: None, owner: Any + ) -> ArrayVar[Sequence[V]]: ... + + @overload + def __get__( + self: Field[list[V] | None], instance: None, owner: Any + ) -> ArrayVar[Sequence[V]]: ... + + @overload + def __get__( + self: Field[set[V] | None], instance: None, owner: Any ) -> ArrayVar[Sequence[V]]: ... @overload @@ -4496,6 +4538,16 @@ def __get__( self: Field[SQLA_TYPE], instance: None, owner: Any ) -> ObjectVar[SQLA_TYPE]: ... + @overload + def __get__( + self: Field[BASE_MODEL_TYPE | None], instance: None, owner: Any + ) -> ObjectVar[BASE_MODEL_TYPE]: ... + + @overload + def __get__( + self: Field[BASE_MODEL_TYPE], instance: None, owner: Any + ) -> ObjectVar[BASE_MODEL_TYPE]: ... + if TYPE_CHECKING: @overload @@ -4514,7 +4566,7 @@ def __get__(self, instance: None, owner: Any) -> Var[FIELD_TYPE]: ... @overload def __get__(self, instance: Any, owner: Any) -> FIELD_TYPE: ... - def __get__(self, instance: Any, owner: Any): # pyright: ignore [reportInconsistentOverload] + def __get__(self, instance: Any, owner: Any): """Get the Var on class access, or the value on instance access. Args: @@ -4531,7 +4583,7 @@ def __get__(self, instance: Any, owner: Any): # pyright: ignore [reportInconsis state = ( instance if type(instance) is self._owner - else _owner_state(instance, self._owner) # pyright: ignore[reportArgumentType] + else _owner_state(instance, self._owner) # ty:ignore[invalid-argument-type] ) try: value = state.__dict__[self._name] @@ -5137,6 +5189,11 @@ def __new__( class EvenMoreBasicBaseState(metaclass=BaseStateMeta): """A simplified base state class that provides basic functionality.""" + if TYPE_CHECKING: + # Whether this state class is a mixin and should not be instantiated. + # Set by ``BaseStateMeta.__new__`` as a class attribute. + _mixin: ClassVar[bool] = False + def __init__( self, **kwargs, diff --git a/packages/reflex-base/src/reflex_base/vars/dep_tracking.py b/packages/reflex-base/src/reflex_base/vars/dep_tracking.py index 733b5274820..3d57ac410fc 100644 --- a/packages/reflex-base/src/reflex_base/vars/dep_tracking.py +++ b/packages/reflex-base/src/reflex_base/vars/dep_tracking.py @@ -124,10 +124,10 @@ def __post_init__(self): """After initializing, populate the dependencies dict.""" with contextlib.suppress(AttributeError): # unbox functools.partial - self.func = cast(FunctionType, self.func.func) # pyright: ignore[reportAttributeAccessIssue] + self.func = cast(FunctionType, self.func.func) # ty:ignore[unresolved-attribute] with contextlib.suppress(AttributeError): # unbox EventHandler - self.func = cast(FunctionType, self.func.fn) # pyright: ignore[reportAttributeAccessIssue,reportFunctionMemberAccess] + self.func = cast(FunctionType, self.func.fn) # ty:ignore[unresolved-attribute] if isinstance(self.func, FunctionType): with contextlib.suppress(AttributeError, IndexError): @@ -238,7 +238,7 @@ def _get_globals(self) -> dict[str, Any]: """ if isinstance(self.func, CodeType): return {} - return self.func.__globals__ # pyright: ignore[reportAttributeAccessIssue] + return self.func.__globals__ def _get_closure(self) -> dict[str, Any]: """Get the closure of the function, with unbound values omitted. @@ -251,7 +251,7 @@ def _get_closure(self) -> dict[str, Any]: return { var_name: get_cell_value(cell) for var_name, cell in zip( - self.func.__code__.co_freevars, # pyright: ignore[reportAttributeAccessIssue] + self.func.__code__.co_freevars, self.func.__closure__ or (), strict=False, ) diff --git a/packages/reflex-base/src/reflex_base/vars/function.py b/packages/reflex-base/src/reflex_base/vars/function.py index 5f6520972da..72eb5257e77 100644 --- a/packages/reflex-base/src/reflex_base/vars/function.py +++ b/packages/reflex-base/src/reflex_base/vars/function.py @@ -176,7 +176,7 @@ def partial( @overload def partial(self, *args: Var | Any) -> FunctionVar: ... - def partial(self, *args: Var | Any) -> FunctionVar: # pyright: ignore [reportInconsistentOverload] + def partial(self, *args: Var | Any) -> FunctionVar: """Partially apply the function with the given arguments. Args: @@ -250,7 +250,7 @@ def call( @overload def call(self, *args: Var | Any) -> Var: ... - def call(self, *args: Var | Any) -> Var: # pyright: ignore [reportInconsistentOverload] + def call(self, *args: Var | Any) -> Var: """Call the function with the given arguments. Args: @@ -279,7 +279,7 @@ class FunctionStringVar(FunctionVar[CALLABLE_TYPE]): def create( cls, func: str, - _var_type: type[OTHER_CALLABLE_TYPE] = ReflexCallable[Any, Any], + _var_type: type[OTHER_CALLABLE_TYPE] = ReflexCallable[Any, Any], # ty:ignore[invalid-parameter-default] _var_data: VarData | None = None, ) -> FunctionStringVar[OTHER_CALLABLE_TYPE]: """Create a new function var from a string. diff --git a/packages/reflex-base/src/reflex_base/vars/number.py b/packages/reflex-base/src/reflex_base/vars/number.py index cacb83577d1..5176d763085 100644 --- a/packages/reflex-base/src/reflex_base/vars/number.py +++ b/packages/reflex-base/src/reflex_base/vars/number.py @@ -300,7 +300,7 @@ def __neg__(self) -> NumberVar: Returns: The number negation operation. """ - return number_negate_operation(self) # pyright: ignore [reportReturnType] + return number_negate_operation(self) def __invert__(self): """Boolean NOT the number. @@ -529,7 +529,7 @@ def wrapper(lhs: number_types, rhs: number_types) -> NumberVar: Returns: The binary number operation. """ - return operation(lhs, rhs) # pyright: ignore [reportReturnType, reportArgumentType] + return operation(lhs, rhs) return wrapper @@ -1137,7 +1137,7 @@ def ternary_operation( Returns: The ternary operation. """ - type_value: type[T] | type[U] = unionize(if_true._var_type, if_false._var_type) + type_value: type[T] | type[U] = unionize(if_true._var_type, if_false._var_type) # ty:ignore[invalid-assignment] value: CustomVarOperationReturn[T | U] = var_operation_return( js_expression=f"({condition!s} ? {if_true!s} : {if_false!s})", var_type=type_value, diff --git a/packages/reflex-base/src/reflex_base/vars/object.py b/packages/reflex-base/src/reflex_base/vars/object.py index 8b8504944df..1ae7ef230a0 100644 --- a/packages/reflex-base/src/reflex_base/vars/object.py +++ b/packages/reflex-base/src/reflex_base/vars/object.py @@ -169,7 +169,7 @@ def merge(self, other: ObjectVar): # NoReturn is used here to catch when key value is Any @overload - def __getitem__( # pyright: ignore [reportOverlappingOverload] + def __getitem__( self: ObjectVar[Mapping[Any, NoReturn]], key: Var | Any, ) -> Var: ... @@ -254,9 +254,9 @@ def get(self, key: Var | Any, default: Var | Any | None = None) -> Var: if default is None: default = Var.create(None) - value = self.__getitem__(key) # pyright: ignore[reportUnknownVariableType,reportAttributeAccessIssue,reportUnknownMemberType] + value = self.__getitem__(key) # ty:ignore[no-matching-overload] - return cond( # pyright: ignore[reportUnknownVariableType] + return cond( value, value, default, @@ -264,7 +264,7 @@ def get(self, key: Var | Any, default: Var | Any | None = None) -> Var: # NoReturn is used here to catch when key value is Any @overload - def __getattr__( # pyright: ignore [reportOverlappingOverload] + def __getattr__( self: ObjectVar[Mapping[Any, NoReturn]], name: str, ) -> Var: ... @@ -417,7 +417,7 @@ def _key_type(self) -> type: The type of the keys of the object. """ args_list = typing.get_args(self._var_type) - return args_list[0] if args_list else Any # pyright: ignore [reportReturnType] + return args_list[0] if args_list else Any def _value_type(self) -> type: """Get the type of the values of the object. @@ -426,7 +426,7 @@ def _value_type(self) -> type: The type of the values of the object. """ args_list = typing.get_args(self._var_type) - return args_list[1] if args_list else Any # pyright: ignore [reportReturnType] + return args_list[1] if args_list else Any @cached_property_no_lock def _cached_var_name(self) -> str: @@ -568,7 +568,7 @@ def object_values_operation(value: ObjectVar): """ return var_operation_return( js_expression=f"Object.values({value!s} ?? {{}})", - var_type=list[value._value_type()], + var_type=list[value._value_type()], # ty:ignore[invalid-type-form] ) @@ -584,7 +584,7 @@ def object_entries_operation(value: ObjectVar): """ return var_operation_return( js_expression=f"Object.entries({value!s} ?? {{}})", - var_type=list[tuple[str, value._value_type()]], + var_type=list[tuple[str, value._value_type()]], # ty:ignore[invalid-type-form] ) @@ -602,8 +602,8 @@ def object_merge_operation(lhs: ObjectVar, rhs: ObjectVar): return var_operation_return( js_expression=f"({{...{lhs!s}, ...{rhs!s}}})", var_type=Mapping[ - lhs._key_type() | rhs._key_type(), - lhs._value_type() | rhs._value_type(), + lhs._key_type() | rhs._key_type(), # ty:ignore[invalid-type-form] + lhs._value_type() | rhs._value_type(), # ty:ignore[invalid-type-form] ], ) diff --git a/packages/reflex-base/src/reflex_base/vars/sequence.py b/packages/reflex-base/src/reflex_base/vars/sequence.py index 1ded6c57ab1..5f2b6bd5f2e 100644 --- a/packages/reflex-base/src/reflex_base/vars/sequence.py +++ b/packages/reflex-base/src/reflex_base/vars/sequence.py @@ -46,7 +46,7 @@ if TYPE_CHECKING: from typing_extensions import deprecated - from .base import DATACLASS_TYPE, SQLA_TYPE + from .base import BASE_MODEL_TYPE, DATACLASS_TYPE, SQLA_TYPE from .function import FunctionVar from .object import ObjectVar @@ -105,7 +105,7 @@ def reverse(self) -> ArrayVar[ARRAY_VAR_TYPE]: Returns: The reversed array. """ - return array_reverse_operation(self) + return array_reverse_operation(self) # ty:ignore[invalid-return-type] def __add__(self, other: ArrayVar[ARRAY_VAR_TYPE]) -> ArrayVar[ARRAY_VAR_TYPE]: """Concatenate two arrays. @@ -119,7 +119,7 @@ def __add__(self, other: ArrayVar[ARRAY_VAR_TYPE]) -> ArrayVar[ARRAY_VAR_TYPE]: if not isinstance(other, ArrayVar): raise_unsupported_operand_types("+", (type(self), type(other))) - return array_concat_operation(self, other) + return array_concat_operation(self, other) # ty:ignore[invalid-return-type] @overload def __getitem__(self, i: slice) -> ArrayVar[ARRAY_VAR_TYPE]: ... @@ -150,7 +150,7 @@ def __getitem__( ) -> NumberVar: ... @overload - def __getitem__( # pyright: ignore [reportOverlappingOverload] + def __getitem__( self: ArrayVar[tuple[str, Any]], i: Literal[0, -2] ) -> StringVar: ... @@ -206,6 +206,12 @@ def __getitem__( i: int | NumberVar, ) -> ObjectVar[DATACLASS_TYPE]: ... + @overload + def __getitem__( + self: ArrayVar[Sequence[BASE_MODEL_TYPE]], + i: int | NumberVar, + ) -> ObjectVar[BASE_MODEL_TYPE]: ... + @overload def __getitem__(self, i: int | NumberVar) -> Var: ... @@ -322,7 +328,7 @@ def pluck(self, field: StringVar | str) -> ArrayVar: Returns: The array pluck operation. """ - return array_pluck_operation(self, field) + return array_pluck_operation(self, field) # ty:ignore[invalid-return-type] def __mul__(self, other: NumberVar | int) -> ArrayVar[ARRAY_VAR_TYPE]: """Multiply the sequence by a number or integer. @@ -338,7 +344,7 @@ def __mul__(self, other: NumberVar | int) -> ArrayVar[ARRAY_VAR_TYPE]: ): raise_unsupported_operand_types("*", (type(self), type(other))) - return repeat_array_operation(self, other) + return repeat_array_operation(self, other) # ty:ignore[invalid-return-type] __rmul__ = __mul__ @@ -997,7 +1003,7 @@ def __ge__(self, other: StringVar | str) -> BooleanVar: return string_ge_operation(self, other) @overload - def replace( # pyright: ignore [reportOverlappingOverload] + def replace( self, search_value: StringVar | str, new_value: StringVar | str ) -> StringVar: ... @@ -1006,7 +1012,7 @@ def replace( self, search_value: Any, new_value: Any ) -> CustomVarOperationReturn[StringVar]: ... - def replace(self, search_value: Any, new_value: Any) -> StringVar: # pyright: ignore [reportInconsistentOverload] + def replace(self, search_value: Any, new_value: Any) -> StringVar: """Replace a string with a value. Args: diff --git a/packages/reflex-bench/src/reflex_bench/drivers/browser.py b/packages/reflex-bench/src/reflex_bench/drivers/browser.py index 877b691416d..da6e3eab2e5 100644 --- a/packages/reflex-bench/src/reflex_bench/drivers/browser.py +++ b/packages/reflex-bench/src/reflex_bench/drivers/browser.py @@ -507,7 +507,7 @@ def start(self) -> None: # The driver is the node process behind Playwright's pipe transport, a # child of the harness; Chromium's root is the driver's child. driver = psutil.Process( - playwright._impl_obj._connection._transport._proc.pid # pyright: ignore[reportAttributeAccessIssue] + playwright._impl_obj._connection._transport._proc.pid # ty:ignore[unresolved-attribute] ) self._processes = (*driver.children(), driver) self.anchor = Anchor.take() diff --git a/packages/reflex-bench/src/reflex_bench/suites/events.py b/packages/reflex-bench/src/reflex_bench/suites/events.py index bcb6de15e0b..169c95334f9 100644 --- a/packages/reflex-bench/src/reflex_bench/suites/events.py +++ b/packages/reflex-bench/src/reflex_bench/suites/events.py @@ -322,7 +322,7 @@ def server_env( with redis), and ``REFLEX_REDIS_URL`` only for redis, since reflex uses redis whenever a URL is configured. """ - result = { + result: dict[str, str] = { **env, **cache_env(states_dir=states_dir), "REFLEX_STATE_MANAGER_MODE": manager, diff --git a/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/apps.py b/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/apps.py index 2abb0ce768e..f78f06f8f01 100644 --- a/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/apps.py +++ b/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/apps.py @@ -235,7 +235,7 @@ async def get(self, app_id: uuid.UUID | str) -> CustomDomain | None: """ # An app without a custom domain answers with an empty object, the only # value a dict that can hold no values matches. - domain = await self._client._request( + domain = await self._client._request( # ty:ignore[no-matching-overload] "GET", f"apps/{path_segment(app_id)}/custom_domain", CustomDomain | dict[str, NoReturn], @@ -581,7 +581,7 @@ async def current_deployment( The running deployment, or None if the app is not running, e.g. while it is stopped, paused or deploying. """ - deployment = await self._client._request( + deployment = await self._client._request( # ty:ignore[no-matching-overload] "GET", f"apps/{path_segment(app_id)}/deployment", RunningDeployment | _NoRunningDeployment, diff --git a/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/databases.py b/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/databases.py index a5432209817..92a0c2d8944 100644 --- a/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/databases.py +++ b/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/databases.py @@ -52,7 +52,7 @@ async def get(self, app_id: uuid.UUID | str) -> ManagedDatabase | None: Returns: The database, or None if the app has none. """ - database = await self._client._request( + database = await self._client._request( # ty:ignore[no-matching-overload] "GET", f"apps/{path_segment(app_id)}/database", ManagedDatabase | _NoDatabase, diff --git a/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/environments.py b/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/environments.py index a41a4976e13..16f6b1d65a4 100644 --- a/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/environments.py +++ b/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/environments.py @@ -237,7 +237,7 @@ async def copy_missing_secrets( Returns: The secrets copied. """ - body = await self._client._request( + body = await self._client._request( # ty:ignore[no-matching-overload] "POST", f"apps/{path_segment(app_id)}/environments/{path_segment(environment_id)}/copy-missing-secrets", _NamedCopiedSecrets | _CountedCopiedSecrets, diff --git a/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/projects.py b/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/projects.py index d57d8aa6bfc..5237d51eb69 100644 --- a/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/projects.py +++ b/packages/reflex-build-sdk/src/reflex_build_sdk/_async/resources/projects.py @@ -119,7 +119,7 @@ async def permissions( Returns: The permission names, sorted. """ - permissions = await self._client._request( + permissions = await self._client._request( # ty:ignore[no-matching-overload] "GET", f"project/{path_segment(project_id)}/role/{path_segment(role_id)}", builtins.list[dict[str, Any]] | None, @@ -251,7 +251,7 @@ async def list(self, project_id: uuid.UUID | str) -> builtins.list[ProjectMember Returns: The members. """ - members = await self._client._request( + members = await self._client._request( # ty:ignore[no-matching-overload] "GET", f"project/{path_segment(project_id)}/users", builtins.list[ProjectMember] | None, @@ -271,7 +271,7 @@ async def set_role( ``"applied"``, or ``"pending_approval"`` when the project requires an admin to approve the change first. """ - result = await self._client._request( + result = await self._client._request( # ty:ignore[no-matching-overload] "POST", "project/users/invite", dict[str, Any] | None, @@ -431,7 +431,7 @@ async def list(self) -> builtins.list[ProjectSummary]: Returns: The projects. """ - projects = await self._client._request( + projects = await self._client._request( # ty:ignore[no-matching-overload] "GET", "project", builtins.list[ProjectSummary] | None ) return projects or [] diff --git a/packages/reflex-build-sdk/src/reflex_build_sdk/_decode.py b/packages/reflex-build-sdk/src/reflex_build_sdk/_decode.py index 8192e5079d1..c8353bfa631 100644 --- a/packages/reflex-build-sdk/src/reflex_build_sdk/_decode.py +++ b/packages/reflex-build-sdk/src/reflex_build_sdk/_decode.py @@ -366,7 +366,7 @@ def resolve_fields() -> list[tuple[str, str, Decoder, bool]]: field.default is dataclasses.MISSING and field.default_factory is dataclasses.MISSING, ) - for field in dataclasses.fields(tp) + for field in dataclasses.fields(tp) # ty:ignore[invalid-argument-type] if field.init ] diff --git a/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/apps.py b/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/apps.py index bdbe98a1c5f..783ec8e8e1b 100644 --- a/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/apps.py +++ b/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/apps.py @@ -236,7 +236,7 @@ def get(self, app_id: uuid.UUID | str) -> CustomDomain | None: """ # An app without a custom domain answers with an empty object, the only # value a dict that can hold no values matches. - domain = self._client._request( + domain = self._client._request( # ty:ignore[no-matching-overload] "GET", f"apps/{path_segment(app_id)}/custom_domain", CustomDomain | dict[str, NoReturn], @@ -578,7 +578,7 @@ def current_deployment( The running deployment, or None if the app is not running, e.g. while it is stopped, paused or deploying. """ - deployment = self._client._request( + deployment = self._client._request( # ty:ignore[no-matching-overload] "GET", f"apps/{path_segment(app_id)}/deployment", RunningDeployment | _NoRunningDeployment, diff --git a/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/databases.py b/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/databases.py index 0476ae86582..afcf40d67c3 100644 --- a/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/databases.py +++ b/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/databases.py @@ -53,7 +53,7 @@ def get(self, app_id: uuid.UUID | str) -> ManagedDatabase | None: Returns: The database, or None if the app has none. """ - database = self._client._request( + database = self._client._request( # ty:ignore[no-matching-overload] "GET", f"apps/{path_segment(app_id)}/database", ManagedDatabase | _NoDatabase, diff --git a/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/environments.py b/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/environments.py index 0de78144a52..d07c7c257c1 100644 --- a/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/environments.py +++ b/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/environments.py @@ -238,7 +238,7 @@ def copy_missing_secrets( Returns: The secrets copied. """ - body = self._client._request( + body = self._client._request( # ty:ignore[no-matching-overload] "POST", f"apps/{path_segment(app_id)}/environments/{path_segment(environment_id)}/copy-missing-secrets", _NamedCopiedSecrets | _CountedCopiedSecrets, diff --git a/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/projects.py b/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/projects.py index 2d1c0acb5e7..40e52141db1 100644 --- a/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/projects.py +++ b/packages/reflex-build-sdk/src/reflex_build_sdk/_sync/resources/projects.py @@ -120,7 +120,7 @@ def permissions( Returns: The permission names, sorted. """ - permissions = self._client._request( + permissions = self._client._request( # ty:ignore[no-matching-overload] "GET", f"project/{path_segment(project_id)}/role/{path_segment(role_id)}", builtins.list[dict[str, Any]] | None, @@ -250,7 +250,7 @@ def list(self, project_id: uuid.UUID | str) -> builtins.list[ProjectMember]: Returns: The members. """ - members = self._client._request( + members = self._client._request( # ty:ignore[no-matching-overload] "GET", f"project/{path_segment(project_id)}/users", builtins.list[ProjectMember] | None, @@ -270,7 +270,7 @@ def set_role( ``"applied"``, or ``"pending_approval"`` when the project requires an admin to approve the change first. """ - result = self._client._request( + result = self._client._request( # ty:ignore[no-matching-overload] "POST", "project/users/invite", dict[str, Any] | None, @@ -426,7 +426,7 @@ def list(self) -> builtins.list[ProjectSummary]: Returns: The projects. """ - projects = self._client._request( + projects = self._client._request( # ty:ignore[no-matching-overload] "GET", "project", builtins.list[ProjectSummary] | None ) return projects or [] diff --git a/packages/reflex-components-code/src/reflex_components_code/shiki_code_block.py b/packages/reflex-components-code/src/reflex_components_code/shiki_code_block.py index 0bb18b22b07..7cd579db6b9 100644 --- a/packages/reflex-components-code/src/reflex_components_code/shiki_code_block.py +++ b/packages/reflex-components-code/src/reflex_components_code/shiki_code_block.py @@ -590,7 +590,7 @@ def create( transformer_styles = {} # Collect styles from transformers and wrapper - for transformer in code_block.transformers._var_value: # pyright: ignore [reportAttributeAccessIssue] + for transformer in code_block.transformers._var_value: # ty:ignore[unresolved-attribute] if isinstance(transformer, ShikiBaseTransformers) and transformer.style: transformer_styles.update(transformer.style) transformer_styles.update(code_wrapper_props.pop("style", {})) @@ -645,7 +645,7 @@ def create_transformer(cls, library: str, fns: list[str]) -> ShikiBaseTransforme raise ValueError(msg) return ShikiBaseTransformers( library=library, - fns=[FunctionStringVar.create(fn) for fn in fns], # pyright: ignore [reportCallIssue] + fns=[FunctionStringVar.create(fn) for fn in fns], ) def _render(self, props: dict[str, Any] | None = None): diff --git a/packages/reflex-components-core/pyproject.toml b/packages/reflex-components-core/pyproject.toml index e2564258405..df934c0ffed 100644 --- a/packages/reflex-components-core/pyproject.toml +++ b/packages/reflex-components-core/pyproject.toml @@ -18,7 +18,7 @@ classifiers = [ dependencies = [ "reflex-base >= 0.10.1.dev0", "reflex-components-lucide >= 1.1.0", - "reflex-components-sonner >= 0.10.0", + "reflex-components-sonner >= 0.10.1.dev0", "python_multipart >= 0.0.21", "starlette >= 0.47.0", "typing_extensions >= 4.0.0", diff --git a/packages/reflex-components-core/src/reflex_components_core/core/banner.py b/packages/reflex-components-core/src/reflex_components_core/core/banner.py index 6cf4e97a58b..0be1d86208a 100644 --- a/packages/reflex-components-core/src/reflex_components_core/core/banner.py +++ b/packages/reflex-components-core/src/reflex_components_core/core/banner.py @@ -111,7 +111,7 @@ def add_hooks(self) -> list[str | Var]: close_button=True, duration=120000, id=toast_id, - ) # pyright: ignore [reportCallIssue] + ) if environment.REFLEX_DOES_BACKEND_COLD_START.get(): loading_message = Var.create("Backend is starting.") diff --git a/packages/reflex-components-core/src/reflex_components_core/core/breakpoints.py b/packages/reflex-components-core/src/reflex_components_core/core/breakpoints.py index e6277d6327d..1d406a2f916 100644 --- a/packages/reflex-components-core/src/reflex_components_core/core/breakpoints.py +++ b/packages/reflex-components-core/src/reflex_components_core/core/breakpoints.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.breakpoints import * # pragma: no cover diff --git a/packages/reflex-components-core/src/reflex_components_core/core/cond.py b/packages/reflex-components-core/src/reflex_components_core/core/cond.py index 9b8540e2556..2474d334605 100644 --- a/packages/reflex-components-core/src/reflex_components_core/core/cond.py +++ b/packages/reflex-components-core/src/reflex_components_core/core/cond.py @@ -118,7 +118,7 @@ def add_imports(self) -> ImportDict: @overload -def cond(condition: Any, c1: Component, c2: Any, /) -> Component: ... # pyright: ignore [reportOverlappingOverload] +def cond(condition: Any, c1: Component, c2: Any, /) -> Component: ... @overload @@ -126,7 +126,7 @@ def cond(condition: Any, c1: Component, /) -> Component: ... @overload -def cond(condition: Any, c1: Any, c2: Component, /) -> Component: ... # pyright: ignore [reportOverlappingOverload] +def cond(condition: Any, c1: Any, c2: Component, /) -> Component: ... T = TypeVar("T", covariant=True) @@ -137,31 +137,31 @@ def cond(condition: Any, c1: Any, c2: Component, /) -> Component: ... # pyright @overload def cond( condition: Any, c1: LITERAL_STRING_S, c2: LITERAL_STRING_S, / -) -> Var[LITERAL_STRING_S]: ... # pyright: ignore [reportOverlappingOverload] +) -> Var[LITERAL_STRING_S]: ... @overload def cond( condition: Any, c1: LITERAL_STRING_S, c2: Var[U], / -) -> Var[LITERAL_STRING_S | U]: ... # pyright: ignore [reportOverlappingOverload] +) -> Var[LITERAL_STRING_S | U]: ... @overload def cond( condition: Any, c1: Var[T], c2: LITERAL_STRING_S, / -) -> Var[T | LITERAL_STRING_S]: ... # pyright: ignore [reportOverlappingOverload] +) -> Var[T | LITERAL_STRING_S]: ... @overload -def cond(condition: Any, c1: Var[T], c2: Var[U], /) -> Var[T | U]: ... # pyright: ignore [reportOverlappingOverload] +def cond(condition: Any, c1: Var[T], c2: Var[U], /) -> Var[T | U]: ... @overload -def cond(condition: Any, c1: T, c2: Var[U], /) -> Var[T | U]: ... # pyright: ignore [reportOverlappingOverload] +def cond(condition: Any, c1: T, c2: Var[U], /) -> Var[T | U]: ... @overload -def cond(condition: Any, c1: Var[T], c2: U, /) -> Var[T | U]: ... # pyright: ignore [reportOverlappingOverload] +def cond(condition: Any, c1: Var[T], c2: U, /) -> Var[T | U]: ... @overload @@ -218,7 +218,7 @@ def cond(condition: Any, c1: Any, c2: Any = types.Unset(), /) -> Component | Var @overload -def color_mode_cond(light: Component, dark: Component | None = None) -> Component: ... # pyright: ignore [reportOverlappingOverload] +def color_mode_cond(light: Component, dark: Component | None = None) -> Component: ... @overload diff --git a/packages/reflex-components-core/src/reflex_components_core/core/debounce.py b/packages/reflex-components-core/src/reflex_components_core/core/debounce.py index c53bf956668..c812b14c930 100644 --- a/packages/reflex-components-core/src/reflex_components_core/core/debounce.py +++ b/packages/reflex-components-core/src/reflex_components_core/core/debounce.py @@ -148,12 +148,12 @@ def create(cls, *children: Component, **props: Any) -> Component: ) component = super().create(**props) - component._get_style = child._get_style + component._get_style = child._get_style # ty:ignore[invalid-assignment] component.event_triggers.update(child.event_triggers) component.children = child.children - component._rename_props = child._rename_props # pyright: ignore[reportAttributeAccessIssue] + component._rename_props = child._rename_props # ty:ignore[invalid-attribute-access] outer_get_all_custom_code = component._get_all_custom_code - component._get_all_custom_code = lambda: ( + component._get_all_custom_code = lambda: ( # ty:ignore[invalid-assignment] outer_get_all_custom_code() | (child._get_all_custom_code()) ) return component diff --git a/packages/reflex-components-core/src/reflex_components_core/core/foreach.py b/packages/reflex-components-core/src/reflex_components_core/core/foreach.py index 1df59feda9d..7eee3be664c 100644 --- a/packages/reflex-components-core/src/reflex_components_core/core/foreach.py +++ b/packages/reflex-components-core/src/reflex_components_core/core/foreach.py @@ -122,7 +122,7 @@ def create( return component def _render(self) -> IterTag: - props = {} + props: dict[str, Any] = {} render_sig = inspect.signature(self.render_fn) params = list(render_sig.parameters.values()) @@ -149,7 +149,7 @@ def _render(self) -> IterTag: if (render_fn_code := getattr(render_fn, "__code__", None)) is not None: code_hash = md5(render_fn_code.co_code).hexdigest() elif isinstance(render_fn, functools.partial): - code_hash = md5(render_fn.func.__code__.co_code).hexdigest() + code_hash = md5(render_fn.func.__code__.co_code).hexdigest() # ty:ignore[unresolved-attribute] else: code_hash = md5(repr(render_fn).encode()).hexdigest() props["index_var_name"] = f"index_{code_hash}" diff --git a/packages/reflex-components-core/src/reflex_components_core/core/match.py b/packages/reflex-components-core/src/reflex_components_core/core/match.py index fe1c31d020e..094ccb8cbaf 100644 --- a/packages/reflex-components-core/src/reflex_components_core/core/match.py +++ b/packages/reflex-components-core/src/reflex_components_core/core/match.py @@ -198,16 +198,17 @@ def _validate_return_types( MatchTypeError: If the return types of cases are different. """ first_case_return = match_cases[0][-1] - return_type = type(first_case_return) - + return_type: type[Var] | type[BaseComponent] if isinstance(first_case_return, BaseComponent): return_type = BaseComponent elif isinstance(first_case_return, Var): return_type = Var + else: + msg = "Return value must be a var or component" + raise MatchTypeError(msg) - cases = [] for index, case in enumerate(match_cases): - conditions, return_value = case + return_value = case[-1] if not isinstance(return_value, return_type): msg = ( f"Match cases should have the same return types. Case {index} with return " @@ -215,8 +216,7 @@ def _validate_return_types( f" of type {type(return_value)!r} is not {return_type}" ) raise MatchTypeError(msg) - cases.append((conditions, return_value)) - return cases + return match_cases # ty:ignore[invalid-return-type] @classmethod def _create_match_cond_var_or_component( @@ -245,7 +245,7 @@ def _create_match_cond_var_or_component( cond=match_cond_var, match_cases=match_cases, default=default, - children=[case[1] for case in match_cases] + [default], # pyright: ignore [reportArgumentType] + children=[case[1] for case in match_cases] + [default], # ty:ignore[invalid-argument-type] ) ) diff --git a/packages/reflex-components-core/src/reflex_components_core/el/elements/forms.py b/packages/reflex-components-core/src/reflex_components_core/el/elements/forms.py index 6fd8855a222..14579d52502 100644 --- a/packages/reflex-components-core/src/reflex_components_core/el/elements/forms.py +++ b/packages/reflex-components-core/src/reflex_components_core/el/elements/forms.py @@ -390,9 +390,9 @@ def create(cls, *children, **props): # Render the form hooks and use the hash of the resulting code to create a unique name. props["handle_submit_unique_name"] = "" form = super().create(*children, **props) - form._validate_on_submit_typed_dict_fields() # pyright: ignore[reportAttributeAccessIssue] - form._deprecate_id_only_form_controls() # pyright: ignore[reportAttributeAccessIssue] - form.handle_submit_unique_name = md5( # pyright: ignore[reportAttributeAccessIssue] + form._validate_on_submit_typed_dict_fields() # ty:ignore[unresolved-attribute] + form._deprecate_id_only_form_controls() # ty:ignore[unresolved-attribute] + form.handle_submit_unique_name = md5( # ty:ignore[unresolved-attribute] str(form._get_all_hooks()).encode("utf-8") ).hexdigest() return form diff --git a/packages/reflex-components-internal/pyproject.toml b/packages/reflex-components-internal/pyproject.toml index 900e055e89c..4b32d32632c 100644 --- a/packages/reflex-components-internal/pyproject.toml +++ b/packages/reflex-components-internal/pyproject.toml @@ -17,6 +17,7 @@ classifiers = [ ] dependencies = [ "reflex >= 0.10.1.dev0", + "reflex-base >= 0.10.1.dev0", ] [tool.hatch.version] diff --git a/packages/reflex-components-internal/src/reflex_components_internal/blocks/demo_form.py b/packages/reflex-components-internal/src/reflex_components_internal/blocks/demo_form.py index 809ca911cc0..ae94bc8e8cc 100644 --- a/packages/reflex-components-internal/src/reflex_components_internal/blocks/demo_form.py +++ b/packages/reflex-components-internal/src/reflex_components_internal/blocks/demo_form.py @@ -470,7 +470,7 @@ def demo_form_dialog( ), ), open=demo_form_open_cs.value, - on_open_change=demo_form_open_cs.set_value, + on_open_change=demo_form_open_cs.set_value, # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 on_open_change_complete=[ rx.call_function(demo_form_error_message.set_value("")) ], diff --git a/packages/reflex-components-internal/src/reflex_components_internal/components/base/checkbox.py b/packages/reflex-components-internal/src/reflex_components_internal/components/base/checkbox.py index a3f955bffd2..98396362202 100644 --- a/packages/reflex-components-internal/src/reflex_components_internal/components/base/checkbox.py +++ b/packages/reflex-components-internal/src/reflex_components_internal/components/base/checkbox.py @@ -123,7 +123,7 @@ def create(cls, *children, **props) -> BaseUIComponent: """ class_name = props.pop("class_name", "") if label := props.pop("label", None): - return Label.create( # pyright: ignore[reportReturnType] + return Label.create( CheckboxRoot.create( CheckboxIndicator.create(), *children, @@ -131,7 +131,7 @@ def create(cls, *children, **props) -> BaseUIComponent: ), label, class_name=cn(ClassNames.LABEL, class_name), - ) + ) # ty:ignore[invalid-return-type] return CheckboxRoot.create( CheckboxIndicator.create(), *children, diff --git a/packages/reflex-components-internal/src/reflex_components_internal/components/base/input.py b/packages/reflex-components-internal/src/reflex_components_internal/components/base/input.py index 941915709d0..cb9e125d843 100644 --- a/packages/reflex-components-internal/src/reflex_components_internal/components/base/input.py +++ b/packages/reflex-components-internal/src/reflex_components_internal/components/base/input.py @@ -59,7 +59,7 @@ class InputRoot(InputBaseComponent, ReflexInput): render_: Var[Component] @classmethod - def create(cls, *children, **props) -> "InputRoot": # pyright: ignore[reportIncompatibleMethodOverride] + def create(cls, *children, **props) -> "InputRoot": """Create a high level input component with simplified API. Returns: @@ -67,7 +67,7 @@ def create(cls, *children, **props) -> "InputRoot": # pyright: ignore[reportInc """ props["data-slot"] = "input" cls.set_class_name(ClassNames.INPUT, props) - return super().create(*children, **props) # pyright: ignore[reportReturnType] + return super().create(*children, **props) # ty:ignore[invalid-return-type] class HighLevelInput(InputBaseComponent): @@ -151,7 +151,7 @@ def create(cls, *children, **props) -> BaseUIComponent: }, }) - return Div.create( # pyright: ignore[reportReturnType] + return Div.create( ( Span.create( hi(icon, class_name="text-secondary-12 size-4 pointer-events-none"), @@ -166,7 +166,7 @@ def create(cls, *children, **props) -> BaseUIComponent: on_click=set_focus(id), class_name=cn(f"{ClassNames.DIV} {INPUT_SIZE_VARIANTS[size]}", class_name), **props, - ) + ) # ty:ignore[invalid-return-type] @staticmethod def _create_clear_button(id: str, clear_events: list[EventHandler]) -> Button: diff --git a/packages/reflex-components-radix/src/reflex_components_radix/themes/components/icon_button.py b/packages/reflex-components-radix/src/reflex_components_radix/themes/components/icon_button.py index d0e089e9041..508d67380e4 100644 --- a/packages/reflex-components-radix/src/reflex_components_radix/themes/components/icon_button.py +++ b/packages/reflex-components-radix/src/reflex_components_radix/themes/components/icon_button.py @@ -76,7 +76,7 @@ def create(cls, *children, **props) -> Component: raise ValueError(msg) if "size" in props: if isinstance(props["size"], str): - children[0].size = RADIX_TO_LUCIDE_SIZE[props["size"]] # pyright: ignore[reportAttributeAccessIssue] + children[0].size = RADIX_TO_LUCIDE_SIZE[props["size"]] # ty:ignore[invalid-assignment] else: size_map_var = Match.create( props["size"], @@ -86,7 +86,7 @@ def create(cls, *children, **props) -> Component: if not isinstance(size_map_var, Var): msg = f"Match did not return a Var: {size_map_var}" raise ValueError(msg) - children[0].size = size_map_var # pyright: ignore[reportAttributeAccessIssue] + children[0].size = size_map_var # ty:ignore[invalid-assignment] return super().create(*children, **props) def add_style(self): diff --git a/packages/reflex-components-radix/src/reflex_components_radix/themes/layout/list.py b/packages/reflex-components-radix/src/reflex_components_radix/themes/layout/list.py index 9ba8e1e747c..d0e3925912e 100644 --- a/packages/reflex-components-radix/src/reflex_components_radix/themes/layout/list.py +++ b/packages/reflex-components-radix/src/reflex_components_radix/themes/layout/list.py @@ -174,7 +174,7 @@ def create(cls, *children, **props): for child in children: if isinstance(child, Text): - child.as_ = "span" # pyright: ignore[reportAttributeAccessIssue] + child.as_ = "span" elif isinstance(child, Icon) and "display" not in child.style: child.style["display"] = "inline" return super().create(*children, **props) diff --git a/packages/reflex-components-react-player/src/reflex_components_react_player/react_player.py b/packages/reflex-components-react-player/src/reflex_components_react_player/react_player.py index 8e213787651..8344d23b986 100644 --- a/packages/reflex-components-react-player/src/reflex_components_react_player/react_player.py +++ b/packages/reflex-components-react-player/src/reflex_components_react_player/react_player.py @@ -258,7 +258,7 @@ def create(cls, *children, **props) -> ReactPlayer: f"The prop {prop!r} has been replaced by {new_prop!r}, please update your code.", ) props[new_prop] = props.pop(prop) - return super().create(*children, **props) # type: ignore[return-value] + return super().create(*children, **props) def _render(self, props: dict[str, Any] | None = None): """Render the component. Adds width and height set to None because diff --git a/packages/reflex-components-recharts/pyproject.toml b/packages/reflex-components-recharts/pyproject.toml index 7facf482f6c..ec7af560a71 100644 --- a/packages/reflex-components-recharts/pyproject.toml +++ b/packages/reflex-components-recharts/pyproject.toml @@ -16,7 +16,7 @@ classifiers = [ "Programming Language :: Python :: 3.15", ] dependencies = [ - "reflex-base >= 0.10.0", + "reflex-base >= 0.10.1.dev0", "reflex-components-core >= 0.10.0", ] diff --git a/packages/reflex-components-recharts/src/reflex_components_recharts/charts.py b/packages/reflex-components-recharts/src/reflex_components_recharts/charts.py index f05aa827fe3..3cc6189dd01 100644 --- a/packages/reflex-components-recharts/src/reflex_components_recharts/charts.py +++ b/packages/reflex-components-recharts/src/reflex_components_recharts/charts.py @@ -19,6 +19,7 @@ from reflex_base.constants import EventTriggers from reflex_base.constants.colors import Color from reflex_base.event import EventHandler, no_args_event_spec +from reflex_base.utils.format import callable_name from reflex_base.vars.base import Var from reflex_base.vars.object import RestProp @@ -678,7 +679,7 @@ def _sankey_renderer( def _wrapper(rest: RestProp) -> Component: return fn(**{first_param.name: rest.to(props_type)}) - _wrapper.__name__ = fn.__name__ + _wrapper.__name__ = callable_name(fn) _wrapper.__module__ = fn.__module__ return memo(wrapper=None)(_wrapper) diff --git a/packages/reflex-components-sonner/src/reflex_components_sonner/toast.py b/packages/reflex-components-sonner/src/reflex_components_sonner/toast.py index 43994d16f35..2c087cb1225 100644 --- a/packages/reflex-components-sonner/src/reflex_components_sonner/toast.py +++ b/packages/reflex-components-sonner/src/reflex_components_sonner/toast.py @@ -4,7 +4,7 @@ import builtins import dataclasses -from typing import Any, Literal +from typing import Any, Literal, final from reflex_base.components.component import Component, ComponentNamespace, field from reflex_base.components.props import NoExtrasAllowedProps @@ -36,6 +36,7 @@ ) +@final @dataclasses.dataclass class ToastAction: """A toast action that render a button in the toast.""" @@ -80,62 +81,62 @@ class ToastProps(NoExtrasAllowedProps): """Props for the toast component.""" # Toast's title, renders above the description. - title: str | Var | None + title: str | Var | None = None # Toast's description, renders underneath the title. - description: str | Var | None + description: str | Var | None = None # Whether to show the close button. - close_button: bool | None + close_button: bool | None = None # Dark toast in light mode and vice versa. - invert: bool | None + invert: bool | None = None # Control the sensitivity of the toast for screen readers - important: bool | None + important: bool | None = None # Time in milliseconds that should elapse before automatically closing the toast. - duration: int | None + duration: int | None = None # Position of the toast. - position: LiteralPosition | None + position: LiteralPosition | None = None # If false, it'll prevent the user from dismissing the toast. - dismissible: bool | None + dismissible: bool | None = None # TODO: fix serialization of icons for toast? (might not be possible yet) # Icon displayed in front of toast's text, aligned vertically. # icon: Icon | None = None # noqa: ERA001 # Renders a primary button, clicking it will close the toast. - action: ToastAction | None + action: ToastAction | None = None # Renders a secondary button, clicking it will close the toast. - cancel: ToastAction | None + cancel: ToastAction | None = None # Custom id for the toast. - id: str | Var | None + id: str | Var | None = None # Removes the default styling, which allows for easier customization. - unstyled: bool | None + unstyled: bool | None = None # Custom style for the toast. - style: Style | None + style: Style | None = None # Class name for the toast. - class_name: str | None + class_name: str | None = None # XXX: These still do not seem to work Custom style for the toast primary button. - action_button_styles: Style | None + action_button_styles: Style | None = None # Custom style for the toast secondary button. - cancel_button_styles: Style | None + cancel_button_styles: Style | None = None # The function gets called when either the close button is clicked, or the toast is swiped. - on_dismiss: Any | None + on_dismiss: Any | None = None # Function that gets called when the toast disappears automatically after it's timeout (duration` prop). - on_auto_close: Any | None + on_auto_close: Any | None = None def dict(self, *args: Any, **kwargs: Any) -> builtins.dict[str, Any]: """Convert the object to a dictionary. @@ -271,7 +272,7 @@ def send_toast( raise ValueError(msg) if props: - args = LiteralVar.create(ToastProps(component_name="rx.toast", **props)) # pyright: ignore [reportCallIssue] + args = LiteralVar.create(ToastProps(component_name="rx.toast", **props)) # ty:ignore[unknown-argument] toast = toast_command.call(message, args) else: toast = toast_command.call(message) diff --git a/packages/reflex-docgen/src/reflex_docgen/_class.py b/packages/reflex-docgen/src/reflex_docgen/_class.py index 0c8b7d1a406..4f9eaec6287 100644 --- a/packages/reflex-docgen/src/reflex_docgen/_class.py +++ b/packages/reflex-docgen/src/reflex_docgen/_class.py @@ -1,17 +1,22 @@ """Generate documentation for arbitrary Python classes.""" +from __future__ import annotations + import collections.abc import dataclasses import inspect import re from dataclasses import dataclass -from typing import Any, Literal, get_args, get_origin, get_type_hints +from typing import TYPE_CHECKING, Any, Literal, get_args, get_origin, get_type_hints from reflex_base.utils.types import is_union from reflex_base.vars.base import BaseStateMeta from typing_extensions import TypeAliasType from typing_inspection.introspection import AnnotationSource, inspect_annotation +if TYPE_CHECKING: + from _typeshed import DataclassInstance + @dataclass(frozen=True, slots=True, kw_only=True) class FieldDocumentation: @@ -298,7 +303,7 @@ def _build_field_documentation( def _get_dataclass_fields( - cls: type, docstring_attrs: dict[str, str] + cls: type[DataclassInstance], docstring_attrs: dict[str, str] ) -> tuple[FieldDocumentation, ...]: """Extract fields from a dataclass. diff --git a/packages/reflex-docgen/src/reflex_docgen/markdown/_parser.py b/packages/reflex-docgen/src/reflex_docgen/markdown/_parser.py index f89d02aeae0..aef303337ce 100644 --- a/packages/reflex-docgen/src/reflex_docgen/markdown/_parser.py +++ b/packages/reflex-docgen/src/reflex_docgen/markdown/_parser.py @@ -292,9 +292,9 @@ def _convert_block(token: BlockToken) -> Block | None: raise TypeError(msg) item_blocks = _convert_block_children(item_token) items.append(ListItem(children=item_blocks)) - # List.start is an instance attribute (int | None) but pyright sees + # List.start is an instance attribute (int | None) but the type checker sees # the classmethod start(cls, line) instead. - list_start = cast("int | None", token.start) # pyright: ignore[reportAttributeAccessIssue] + list_start = cast("int | None", token.start) return ListBlock( ordered=list_start is not None, start=list_start, diff --git a/packages/reflex-hosting-cli/src/reflex_cli/deployments.py b/packages/reflex-hosting-cli/src/reflex_cli/deployments.py index 665d417592e..4b29b96bb38 100644 --- a/packages/reflex-hosting-cli/src/reflex_cli/deployments.py +++ b/packages/reflex-hosting-cli/src/reflex_cli/deployments.py @@ -229,7 +229,7 @@ def get_group_from_info(group_info: TyperInfo, *args, **kwargs): original_get_group_from_info, ) - typer.main.get_group_from_info = get_group_from_info + typer.main.get_group_from_info = get_group_from_info # ty:ignore[invalid-assignment] return fake_typer_app @@ -239,4 +239,4 @@ def get_group_from_info(group_info: TyperInfo, *args, **kwargs): and find_spec("typer.core") is not None and find_spec("typer.models") is not None ): - deployments_cli = _patch_typer(deployments_cli) # pyright: ignore[reportAssignmentType] + deployments_cli = _patch_typer(deployments_cli) # ty:ignore[invalid-assignment] diff --git a/packages/reflex-hosting-cli/src/reflex_cli/utils/hosting.py b/packages/reflex-hosting-cli/src/reflex_cli/utils/hosting.py index 9225aacc5b1..a4369419517 100644 --- a/packages/reflex-hosting-cli/src/reflex_cli/utils/hosting.py +++ b/packages/reflex-hosting-cli/src/reflex_cli/utils/hosting.py @@ -428,7 +428,7 @@ def open(self, url: str, new: int = 0, autoraise: bool = True): return False -webbrowser.BackgroundBrowser = SilentBackgroundBrowser +webbrowser.BackgroundBrowser = SilentBackgroundBrowser # ty:ignore[invalid-assignment] class TokenSource(str, Enum): diff --git a/packages/reflex-hosting-cli/src/reflex_cli/v2/cli.py b/packages/reflex-hosting-cli/src/reflex_cli/v2/cli.py index ab71083cf5c..e425cf3819c 100644 --- a/packages/reflex-hosting-cli/src/reflex_cli/v2/cli.py +++ b/packages/reflex-hosting-cli/src/reflex_cli/v2/cli.py @@ -1010,9 +1010,7 @@ def deploy( if envfile: try: - from dotenv import ( - dotenv_values, # pyright: ignore[reportMissingImports] - ) + from dotenv import dotenv_values # A bare `KEY` line with no `=` parses to None, which names # no value to set; only assignments become secrets. @@ -1049,7 +1047,7 @@ def deploy( False, True, True, - ) # pyright: ignore[reportCallIssue] + ) # ty:ignore[missing-argument] else: export_fn( str(temporary_dir_path), @@ -1058,7 +1056,7 @@ def deploy( False, True, include_db, - True, # pyright: ignore[reportCallIssue] + True, # ty:ignore[too-many-positional-arguments] ) except Exception as ex: logger.error(f"Unable to export due to: {ex}") @@ -1072,7 +1070,7 @@ def deploy( if rx_version.release < breaking_release: export_fn( str(temporary_dir_path), server_url, host_url, True, False, True - ) # pyright: ignore[reportCallIssue] + ) # ty:ignore[missing-argument] else: export_fn( str(temporary_dir_path), @@ -1081,7 +1079,7 @@ def deploy( True, False, include_db, - True, # pyright: ignore[reportCallIssue] + True, # ty:ignore[too-many-positional-arguments] ) except ImportError as ie: logger.error( @@ -1136,7 +1134,7 @@ def deploy( hostname=extract_domain(host_url) if hostname else None, secrets=processed_envs, packages=packages, - strategy=strategy, # pyright: ignore[reportArgumentType] + strategy=strategy, # ty:ignore[invalid-argument-type] description=deployment_description, on_upload_progress=lambda sent, total: progress.update( upload, completed=sent, total=total diff --git a/packages/reflex-hosting-cli/src/reflex_cli/v2/deployments.py b/packages/reflex-hosting-cli/src/reflex_cli/v2/deployments.py index 502f138f156..d95fa831ebb 100644 --- a/packages/reflex-hosting-cli/src/reflex_cli/v2/deployments.py +++ b/packages/reflex-hosting-cli/src/reflex_cli/v2/deployments.py @@ -137,7 +137,7 @@ def get_group_from_info(group_info: TyperInfo, *args, **kwargs): original_get_group_from_info, ) - typer.main.get_group_from_info = get_group_from_info + typer.main.get_group_from_info = get_group_from_info # ty:ignore[invalid-assignment] return fake_typer_app @@ -147,7 +147,7 @@ def get_group_from_info(group_info: TyperInfo, *args, **kwargs): and find_spec("typer.core") is not None and find_spec("typer.models") is not None ): - hosting_cli = _patch_typer(hosting_cli) # pyright: ignore[reportAssignmentType] + hosting_cli = _patch_typer(hosting_cli) # ty:ignore[invalid-assignment] TIME_FORMAT_HELP = "Accepts ISO 8601 format, unix epoch or time relative to now. For time relative to now, use the format: . Valid units are d (day), h (hour), m (minute), s (second). For example, 1d for 1 day ago from now." MIN_LOGS_LIMIT = 50 diff --git a/packages/reflex-hosting-cli/src/reflex_cli/v2/gcp.py b/packages/reflex-hosting-cli/src/reflex_cli/v2/gcp.py index 27cdf9406d3..55f6b1a4cfb 100644 --- a/packages/reflex-hosting-cli/src/reflex_cli/v2/gcp.py +++ b/packages/reflex-hosting-cli/src/reflex_cli/v2/gcp.py @@ -718,7 +718,7 @@ def _parse_envs(envfile: str | None, envs: tuple[str, ...]) -> dict[str, str]: if envfile: try: - from dotenv import dotenv_values # pyright: ignore[reportMissingImports] + from dotenv import dotenv_values except ImportError: logger.error( 'The `python-dotenv` package is required for --envfile. Run `pip install "python-dotenv>=1.0.1"`.' diff --git a/packages/reflex-hosting-cli/src/reflex_cli/v2/secrets.py b/packages/reflex-hosting-cli/src/reflex_cli/v2/secrets.py index e3c8c7b761e..66b152a2842 100644 --- a/packages/reflex-hosting-cli/src/reflex_cli/v2/secrets.py +++ b/packages/reflex-hosting-cli/src/reflex_cli/v2/secrets.py @@ -141,9 +141,7 @@ def update_secrets( if envfile: try: - from dotenv import ( # pyright: ignore[reportMissingImports] - dotenv_values, - ) + from dotenv import dotenv_values except ImportError: logger.error( """The `python-dotenv` package is required to load environment variables from a file. Run `pip install "python-dotenv>=1.0.1"`.""" diff --git a/packages/reflex-site-shared/src/reflex_site_shared/components/blocks/flexdown.py b/packages/reflex-site-shared/src/reflex_site_shared/components/blocks/flexdown.py index b44cda41713..30a8ea92f84 100644 --- a/packages/reflex-site-shared/src/reflex_site_shared/components/blocks/flexdown.py +++ b/packages/reflex-site-shared/src/reflex_site_shared/components/blocks/flexdown.py @@ -1,6 +1,5 @@ """Flexdown module — component maps and markdown helpers.""" -# pyright: reportAttributeAccessIssue=false from reflex_base.constants.colors import ColorType from reflex_components_code.shiki_code_block import code_block as shiki_code_block diff --git a/packages/reflex-site-shared/src/reflex_site_shared/components/blocks/headings.py b/packages/reflex-site-shared/src/reflex_site_shared/components/blocks/headings.py index ba52291b83d..14ee2eacd74 100644 --- a/packages/reflex-site-shared/src/reflex_site_shared/components/blocks/headings.py +++ b/packages/reflex-site-shared/src/reflex_site_shared/components/blocks/headings.py @@ -1,4 +1,3 @@ -# pyright: reportArgumentType=false, reportReturnType=false, reportOperatorIssue=false """Template for documentation pages.""" from typing import ClassVar diff --git a/packages/reflex-site-shared/src/reflex_site_shared/components/patterns.py b/packages/reflex-site-shared/src/reflex_site_shared/components/patterns.py index 97964efd8fe..bd451ebf6b0 100644 --- a/packages/reflex-site-shared/src/reflex_site_shared/components/patterns.py +++ b/packages/reflex-site-shared/src/reflex_site_shared/components/patterns.py @@ -107,7 +107,7 @@ def hosting_patterns() -> list[rx.Component]: rx.image( src=f"{REFLEX_ASSETS_CDN}hosting/light/hosting_patterns.svg", alt="Reflex Hosting Patterns", - class_name=rx.cond( # type: ignore[arg-type] + class_name=rx.cond( HostingBannerState.is_banner_visible, "dark:hidden lg:flex hidden absolute top-0 z-[-1] w-[1028px] h-[478px] pointer-events-none shrink-0 left-1/2 transform -translate-x-1/2 -translate-y-1/2 lg:mt-[24rem] mt-[3.5rem]", "dark:hidden lg:flex hidden absolute top-0 z-[-1] w-[1028px] h-[478px] pointer-events-none shrink-0 left-1/2 transform -translate-x-1/2 -translate-y-1/2 lg:mt-[19rem] mt-[8.5rem]", @@ -116,7 +116,7 @@ def hosting_patterns() -> list[rx.Component]: rx.image( src=f"{REFLEX_ASSETS_CDN}hosting/dark/hosting_patterns.svg", alt="Reflex Hosting Patterns", - class_name=rx.cond( # type: ignore[arg-type] + class_name=rx.cond( HostingBannerState.is_banner_visible, "hidden dark:flex lg:dark:flex absolute top-0 z-[-1] w-[1028px] h-[478px] pointer-events-none shrink-0 left-1/2 transform -translate-x-1/2 -translate-y-1/2 lg:mt-[24rem] mt-[3.5rem]", "hidden dark:flex lg:dark:flex absolute top-0 z-[-1] w-[1028px] h-[478px] pointer-events-none shrink-0 left-1/2 transform -translate-x-1/2 -translate-y-1/2 lg:mt-[19rem] mt-[8.5rem]", diff --git a/packages/reflex-site-shared/src/reflex_site_shared/styles/styles.py b/packages/reflex-site-shared/src/reflex_site_shared/styles/styles.py index a0786e0c5b9..f9711f6d14f 100644 --- a/packages/reflex-site-shared/src/reflex_site_shared/styles/styles.py +++ b/packages/reflex-site-shared/src/reflex_site_shared/styles/styles.py @@ -19,26 +19,26 @@ def get_code_style(color: str): The component. """ return { - "color": c_color(color, 9), # type: ignore[arg-type] + "color": c_color(color, 9), "border_radius": "4px", - "border": f"1px solid {c_color(color, 4)}", # type: ignore[arg-type] - "background": c_color(color, 3), # type: ignore[arg-type] + "border": f"1px solid {c_color(color, 4)}", + "background": c_color(color, 3), **fonts.code, "line_height": "1.5", } -def get_code_style_rdx(color: str): # type: ignore[reportArgumentType] +def get_code_style_rdx(color: str): """Get code style rdx. Returns: The component. """ return { - "color": rx.color(color, 11), # type: ignore[reportArgumentType] + "color": rx.color(color, 11), "border_radius": "0.25rem", - "border": f"1px solid {rx.color(color, 5)}", # type: ignore[reportArgumentType] - "background": rx.color(color, 3), # type: ignore[reportArgumentType] + "border": f"1px solid {rx.color(color, 5)}", + "background": rx.color(color, 3), } diff --git a/packages/reflex-site-shared/src/reflex_site_shared/views/footer.py b/packages/reflex-site-shared/src/reflex_site_shared/views/footer.py index da84842d801..5f530d77f5c 100644 --- a/packages/reflex-site-shared/src/reflex_site_shared/views/footer.py +++ b/packages/reflex-site-shared/src/reflex_site_shared/views/footer.py @@ -57,7 +57,7 @@ def tab_item(mode: str, icon: str) -> rx.Component: ) return rx.el.button( get_icon(icon, class_name="shrink-0"), - on_click=set_color_mode(mode), # type: ignore[reportArgumentType] + on_click=set_color_mode(mode), class_name=ui.cn( "flex items-center cursor-pointer justify-center rounded-full border shadow-none transition-colors size-7 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring ", rx.cond(mode == color_mode, active_cn, unactive_cn), diff --git a/packages/reflex-workflow/benchmarks/bench.py b/packages/reflex-workflow/benchmarks/bench.py index 9adc231488e..573e75969b5 100644 --- a/packages/reflex-workflow/benchmarks/bench.py +++ b/packages/reflex-workflow/benchmarks/bench.py @@ -690,7 +690,7 @@ async def main() -> None: trials: dict[str, list[dict[str, Any]]] = collections.defaultdict(list) for trial in range(args.repeat): for name, scenario in scenarios: - trials[name].append(await measure(layout, **scenario)) + trials[name].append(await measure(layout, **scenario)) # ty:ignore[invalid-argument-type] print(f"trial {trial + 1}: {name}: {json.dumps(trials[name][-1])}") results = [ summarize( diff --git a/packages/reflex-workflow/examples/ex08_sweep.py b/packages/reflex-workflow/examples/ex08_sweep.py index 024ec3a5bc5..4ee23200ec9 100644 --- a/packages/reflex-workflow/examples/ex08_sweep.py +++ b/packages/reflex-workflow/examples/ex08_sweep.py @@ -115,7 +115,7 @@ async def run_pass(self) -> Every[Sweep]: .with_for_update(skip_locked=True) ) ).scalars() - taken = [ + taken: list[dict[str, Any]] = [ { "item": watch.item, "due_at": watch.due_at, diff --git a/packages/reflex-workflow/src/reflex_workflow/engine/execute.py b/packages/reflex-workflow/src/reflex_workflow/engine/execute.py index de1c6e3716b..b84ccdec03a 100644 --- a/packages/reflex-workflow/src/reflex_workflow/engine/execute.py +++ b/packages/reflex-workflow/src/reflex_workflow/engine/execute.py @@ -771,7 +771,7 @@ async def execute( # against the database clock, so every time the engine writes # comes from one. if callable(repeat): - refused = await wake_on_schedule(session, repeat, values) + refused = await wake_on_schedule(session, repeat, values) # ty:ignore[invalid-argument-type] if refused is not None: outcome, recorded = "failed", refused # The children go in first so the row can record how many of them diff --git a/packages/reflex-workflow/src/reflex_workflow/model.py b/packages/reflex-workflow/src/reflex_workflow/model.py index 11f60cad96b..6fb1b6c7de2 100644 --- a/packages/reflex-workflow/src/reflex_workflow/model.py +++ b/packages/reflex-workflow/src/reflex_workflow/model.py @@ -260,7 +260,7 @@ def __init__( max_backoff: The longest a retry is put off. """ self.fn = fn - self.name = fn.__name__ + self.name = fn.__name__ # ty:ignore[unresolved-attribute] self.retries = retries self.backoff = backoff self.lane = lane diff --git a/pyi_hashes.json b/pyi_hashes.json index 9df583b7fa1..1f8ee302d65 100644 --- a/pyi_hashes.json +++ b/pyi_hashes.json @@ -1,6 +1,6 @@ { "packages/reflex-components-code/src/reflex_components_code/code.pyi": "3b89c09ccc89eeeafe3e38ca539607a0", - "packages/reflex-components-code/src/reflex_components_code/shiki_code_block.pyi": "53c8f35514ebcf40ac5cf70c2342ac1c", + "packages/reflex-components-code/src/reflex_components_code/shiki_code_block.pyi": "1f23b551c57a3e840caf98c316dcb1d8", "packages/reflex-components-core/src/reflex_components_core/__init__.pyi": "d89c7cfa0920f664bc41d292ef882a64", "packages/reflex-components-core/src/reflex_components_core/base/__init__.pyi": "d46e910c03263a8d3456d473de9e76c7", "packages/reflex-components-core/src/reflex_components_core/base/app_wrap.pyi": "4a701f7eaf84ec041c8fd5c8af4e48ff", @@ -37,11 +37,11 @@ "packages/reflex-components-core/src/reflex_components_core/el/elements/tables.pyi": "7b4c2eaff78f6a412f804457570014c4", "packages/reflex-components-core/src/reflex_components_core/el/elements/typography.pyi": "a3d0d5b0ad9d896261091603df6d2c03", "packages/reflex-components-core/src/reflex_components_core/react_router/dom.pyi": "7617635157b816f70354e2db98b38642", - "packages/reflex-components-dataeditor/src/reflex_components_dataeditor/dataeditor.pyi": "1faf9b4e77e589f4d071483c14fe16f7", + "packages/reflex-components-dataeditor/src/reflex_components_dataeditor/dataeditor.pyi": "25347a60721c7d6f63c0b3fc8864519b", "packages/reflex-components-gridjs/src/reflex_components_gridjs/datatable.pyi": "2ce1c076ecf5c2fa4945b4abdbf2f91d", "packages/reflex-components-lucide/src/reflex_components_lucide/icon.pyi": "0bbc5e33f2c2175c3ddcbf1b08dc8923", "packages/reflex-components-markdown/src/reflex_components_markdown/markdown.pyi": "6759daf6e242e209d9298045c7b4456a", - "packages/reflex-components-moment/src/reflex_components_moment/moment.pyi": "21c3396cb28b1ef6442c5a9588dc708b", + "packages/reflex-components-moment/src/reflex_components_moment/moment.pyi": "998dd16202e4e1035d9842a93a284438", "packages/reflex-components-plotly/src/reflex_components_plotly/plotly.pyi": "f411341e59a3065fee964747584f9fcf", "packages/reflex-components-radix/src/reflex_components_radix/__init__.pyi": "a77352f60fb6f4135b5d08a6e56efa6d", "packages/reflex-components-radix/src/reflex_components_radix/primitives/__init__.pyi": "bbd4d1a4fa73275a882c33ba485d0165", @@ -117,8 +117,8 @@ "packages/reflex-components-recharts/src/reflex_components_recharts/general.pyi": "fe22b3cf69e9ae3d425cc88c3511525b", "packages/reflex-components-recharts/src/reflex_components_recharts/polar.pyi": "99ebcfc07868061bdc3c2010d85a153f", "packages/reflex-components-recharts/src/reflex_components_recharts/recharts.pyi": "f2a9cf6db58d169289fbc76de6813300", - "packages/reflex-components-sonner/src/reflex_components_sonner/toast.pyi": "f170ac685b6ba5892370166c80684db3", + "packages/reflex-components-sonner/src/reflex_components_sonner/toast.pyi": "829911e2f365d91727d967c0f353762a", "reflex/__init__.pyi": "23c090b0294d3a91e59f447f36a7a37f", "reflex/components/__init__.pyi": "9facd05a776d0641432696bbf8e34388", - "reflex/experimental/memo.pyi": "87e485038dc79f66b2ab15144845ef1e" + "reflex/experimental/memo.pyi": "7a0856a828747dbbf85aefe048d8136c" } diff --git a/pyproject.toml b/pyproject.toml index 0934af7a6e8..7c169c8c21b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -110,7 +110,6 @@ dev = [ "psycopg[binary]; python_version < '3.15'", "psycopg; python_version >= '3.15'", "pydantic", - "pyright", "pytest-asyncio", "pytest-benchmark", "pytest-codspeed", @@ -172,32 +171,11 @@ path = "scripts/hatch_build.py" dependencies = ["plotly", "ruff"] require-runtime-dependencies = true -[tool.pyright] -extraPaths = [ - "packages/reflex-bench/src", - "packages/reflex-code/src", - "packages/reflex-components/src", - "packages/reflex-dataeditor/src", - "packages/reflex-gridjs/src", - "packages/reflex-lucide/src", - "packages/reflex-markdown/src", - "packages/reflex-moment/src", - "packages/reflex-plotly/src", - "packages/reflex-radix/src", - "packages/reflex-release/src", - "packages/reflex-react-player/src", - "packages/reflex-react-router/src", - "packages/reflex-recharts/src", - "packages/reflex-sonner/src", - "packages/reflex-components-internal/src", - "packages/reflex-otel/src", - "packages/reflex-build-sdk/src", - "packages/reflex-site-shared/src", - "packages/reflex-workflow/src", - # The workflow examples are read from the repository rather than installed. - "packages/reflex-workflow", - "packages/integrations-docs/src", -] +[tool.ty.environment] +# The workflow examples are read from the repository rather than installed. +extra-paths = ["packages/reflex-workflow"] + +[tool.ty.src] exclude = [ ".venv", "**/__pycache__", @@ -209,7 +187,17 @@ exclude = [ "packages/integrations-docs", "packages/reflex-ui-shared", ] -reportIncompatibleMethodOverride = false + +[tool.ty.rules] +invalid-method-override = "ignore" +unsupported-base = "ignore" +# `EventHandler[some_arg_spec]` is the public spelling for declaring an event +# trigger; `EventHandler.__class_getitem__` turns it into `Annotated[EventHandler, +# some_arg_spec]`. The subscript argument is a function, not a type, so ty rejects +# it in a type expression (intentionally, see astral-sh/ty#3388). Component authors +# outside this repo hit the same thing, so ignore the rule rather than rewriting +# every annotation to the `Annotated[...]` form. +not-subscriptable = "ignore" [tool.ruff] target-version = "py311" @@ -493,7 +481,7 @@ backend_held = [ ] backend_pinned = [ # Linters are pinned deliberately and bumped on their own cadence. - "pyright", + "ty", "ruff", ] frontend_held = [ @@ -561,6 +549,9 @@ reflex-hosting-cli = false pillow = "2026-10-21T00:00:00Z" certifi = "2026-10-21T00:00:00Z" virtualenv = "2026-10-22T00:00:00Z" +# Keep the type checker itself resolvable at its latest release; ty ships frequent +# fixes the migration depends on. +ty = false [tool.uv.sources] hatch-reflex-pyi.workspace = true diff --git a/reflex/_upload.py b/reflex/_upload.py index b8b2dcfe48f..96c43b34020 100644 --- a/reflex/_upload.py +++ b/reflex/_upload.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_components_core.core._upload.""" from reflex_components_core.core._upload import * # pragma: no cover diff --git a/reflex/app.py b/reflex/app.py index 97d7d7472e5..a542ade4c3d 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -980,7 +980,9 @@ def _page_route_key( if route is not None: return format.format_route(route) if isinstance(component, Callable): - return format.format_route(format.to_kebab_case(component.__name__)) + return format.format_route( + format.to_kebab_case(format.callable_name(component)) + ) return None def add_page( @@ -1166,7 +1168,7 @@ def _commit_page( state = self._state or State state.setup_dynamic_args(prepared.route_args) - self._load_events[page.route] = ( + self._load_events[page.route] = ( # ty:ignore[invalid-assignment] https://github.com/astral-sh/ty/issues/4394 ( list(page.on_load) if is_non_string_sequence(page.on_load) @@ -1829,7 +1831,7 @@ def all_routes(_request: Request) -> Response: @overload @deprecated("pass token as rx.BaseStateToken instead of str") - def modify_state( + def modify_state( # ty:ignore[invalid-overload] https://github.com/astral-sh/ty/issues/2057 self, token: str, background: bool = False, @@ -1837,7 +1839,7 @@ def modify_state( ) -> contextlib.AbstractAsyncContextManager[BaseState]: ... @overload - def modify_state( + def modify_state( # ty:ignore[invalid-overload] https://github.com/astral-sh/ty/issues/2057 self, token: BaseStateToken, background: bool = False, @@ -2024,7 +2026,7 @@ async def health(_request: Request) -> JSONResponse: - "db" (bool or str): Database status - True, False, or "NA". - "redis" (bool or str): Redis status - True, False, or "NA". """ - health_status = {"status": True} + health_status: dict[str, bool | None] = {"status": True} status_code = 200 tasks = [] diff --git a/reflex/app_mixins/lifespan.py b/reflex/app_mixins/lifespan.py index 4dd9964cc1a..d7bbbec9a8a 100644 --- a/reflex/app_mixins/lifespan.py +++ b/reflex/app_mixins/lifespan.py @@ -14,6 +14,7 @@ from reflex_base.utils import console from reflex_base.utils.exceptions import InvalidLifespanTaskTypeError +from reflex_base.utils.format import callable_name from starlette.applications import Starlette from reflex.utils import prerequisites @@ -42,7 +43,7 @@ def _get_task_name(task: asyncio.Task | Callable) -> str: """ if isinstance(task, asyncio.Task): return task.get_name() - return task.__name__ # pyright: ignore[reportAttributeAccessIssue] + return callable_name(task) def _report_task_result(task: asyncio.Task) -> None: @@ -167,25 +168,21 @@ async def _run_lifespan_tasks(self, starlette_app: Starlette): f"{_LIFESPAN_TASK_CANCEL_TIMEOUT} seconds of cancellation." ) # Disassociate sid / token pairings so they can be reconnected properly. - try: - event_namespace = self.event_namespace # pyright: ignore[reportAttributeAccessIssue] - except AttributeError: - pass - else: + event_namespace = getattr(self, "event_namespace", None) + if event_namespace: try: - if event_namespace: - try: - await event_namespace._token_manager.disconnect_all() - finally: - await event_namespace._token_manager.close() + try: + await event_namespace._token_manager.disconnect_all() + finally: + await event_namespace._token_manager.close() except Exception as e: logger.error(f"Error during lifespan cleanup: {e}") # Flush any pending writes from the state manager. try: - state_manager = self.state_manager # pyright: ignore[reportAttributeAccessIssue] - except (AttributeError, ValueError): - pass - else: + state_manager = getattr(self, "state_manager", None) + except ValueError: + state_manager = None + if state_manager is not None: await state_manager.close() await prerequisites.close_health_redis() @@ -233,7 +230,7 @@ def register_lifespan_task( ) raise RuntimeError(msg) if inspect.isgeneratorfunction(task) or inspect.isasyncgenfunction(task): - msg = f"Task {task.__name__} of type generator must be decorated with contextlib.asynccontextmanager." + msg = f"Task {_get_task_name(task)} of type generator must be decorated with contextlib.asynccontextmanager." raise InvalidLifespanTaskTypeError(msg) task_name = _get_task_name(task) diff --git a/reflex/app_mixins/middleware.py b/reflex/app_mixins/middleware.py index c9bea19e922..f9c5f4fe451 100644 --- a/reflex/app_mixins/middleware.py +++ b/reflex/app_mixins/middleware.py @@ -49,7 +49,7 @@ async def _preprocess(self, state: BaseState, event: Event) -> StateUpdate | Non An optional state to return. """ for middleware in self._middlewares: - out = middleware.preprocess(app=self, state=state, event=event) # pyright: ignore [reportArgumentType] + out = middleware.preprocess(app=self, state=state, event=event) # ty:ignore[invalid-argument-type] if inspect.isawaitable(out): out = await out if out is not None: @@ -75,11 +75,11 @@ async def _postprocess( out = update for middleware in self._middlewares: out = middleware.postprocess( - app=self, # pyright: ignore [reportArgumentType] + app=self, # ty:ignore[invalid-argument-type] state=state, event=event, update=update, ) if inspect.isawaitable(out): out = await out - return out # pyright: ignore[reportReturnType] + return out diff --git a/reflex/assets.py b/reflex/assets.py index 83b3d033477..c70f9878a69 100644 --- a/reflex/assets.py +++ b/reflex/assets.py @@ -87,7 +87,7 @@ def __new__( else: relative_path = str.__new__( str, - object, # pyright: ignore[reportArgumentType] + object, # ty:ignore[invalid-argument-type] "utf-8" if encoding is None else encoding, "strict" if errors is None else errors, ) diff --git a/reflex/compiler/compiler.py b/reflex/compiler/compiler.py index dab3bfb578f..421c8ea2718 100644 --- a/reflex/compiler/compiler.py +++ b/reflex/compiler/compiler.py @@ -35,7 +35,7 @@ from reflex_base.registry import RegistrationContext, _default_bundled_libraries from reflex_base.utils import log, memo_paths from reflex_base.utils.exceptions import ReflexError -from reflex_base.utils.format import to_title_case +from reflex_base.utils.format import callable_name, to_title_case from reflex_base.utils.imports import ( ABSOLUTE_IMPORT_PREFIXES, ImportVar, @@ -864,6 +864,24 @@ def purge_web_pages_dir(): from reflex.app import App, ComponentCallable, UnevaluatedPage +def _wrap_in_fragment( + component: ComponentCallable | tuple[Component, ...] | str | Var | int | float, +) -> Component | None: + """Wrap a Var, primitive or sequence of components in a Fragment. + + Args: + component: The value to wrap. + + Returns: + The Fragment, or None if the value cannot be wrapped. + """ + if isinstance(component, (Var, int, float, str)): + return Fragment.create(component) + if isinstance(component, Sequence): + return Fragment.create(*component) + return None + + def _into_component_once( component: Component | ComponentCallable @@ -883,11 +901,7 @@ def _into_component_once( """ if isinstance(component, Component): return component - if isinstance(component, (Var, int, float, str)): - return Fragment.create(component) - if isinstance(component, Sequence): - return Fragment.create(*component) - return None + return _wrap_in_fragment(component) def readable_name_from_component( @@ -913,9 +927,10 @@ def readable_name_from_component( module = getmodule(component) if module is not None: module_name = module.__name__ + name = callable_name(component) if module_name is not None: - return f"{module_name}.{component.__name__}" - return component.__name__ + return f"{module_name}.{name}" + return name return None @@ -959,7 +974,9 @@ def into_component(component: Component | ComponentCallable) -> Component: # noqa: DAR401 """ - if (converted := _into_component_once(component)) is not None: + if isinstance(component, Component): + return component + if (converted := _wrap_in_fragment(component)) is not None: return converted if not callable(component): msg = f"Expected a Component or callable, got {component!r} of type {type(component)}" @@ -1044,23 +1061,17 @@ def compile_unevaluated_page( component = Fragment.create(component) - meta_args = { - "title": ( + # Add meta information to the component. + utils.add_meta( + component, + title=( page.title if page.title is not None else make_default_page_title(get_config().app_name, route) ), - "image": page.image, - "meta": page.meta, - } - - if page.description is not None: - meta_args["description"] = page.description - - # Add meta information to the component. - utils.add_meta( - component, - **meta_args, + image=page.image, + meta=page.meta, + description=page.description, ) except Exception as e: diff --git a/reflex/compiler/plugins/builtin.py b/reflex/compiler/plugins/builtin.py index f8855b8a7b1..4d0ecf75846 100644 --- a/reflex/compiler/plugins/builtin.py +++ b/reflex/compiler/plugins/builtin.py @@ -4,7 +4,7 @@ import dataclasses from collections.abc import Callable, Sequence -from typing import Any +from typing import TYPE_CHECKING, Any from reflex_base.components.app_wraps import _ingest_component_var_app_wraps from reflex_base.components.component import BaseComponent, Component, ComponentStyle @@ -18,6 +18,9 @@ from reflex.compiler import utils +if TYPE_CHECKING: + from reflex_base.plugins.compiler import PageComponent + @dataclasses.dataclass(frozen=True, slots=True) class DefaultPagePlugin(Plugin): @@ -25,7 +28,7 @@ class DefaultPagePlugin(Plugin): def eval_page( self, - page_fn: Any, + page_fn: PageComponent, /, *, page: PageDefinition, @@ -55,7 +58,7 @@ def eval_page( if (description := getattr(page, "description", None)) is not None: meta_args["description"] = description - utils.add_meta(component, **meta_args) + utils.add_meta(component, **meta_args) # ty:ignore[invalid-argument-type] except Exception as err: if hasattr(err, "add_note"): err.add_note(f"Happened while evaluating page {page.route!r}") @@ -118,7 +121,7 @@ def enter_component( /, *, page_context: PageContext, - compile_context: Any, + compile_context: CompileContext, in_prop_tree: bool = False, ) -> BaseComponent | None: """Apply the non-recursive portion of ``_add_style_recursive``. @@ -181,7 +184,7 @@ def leave_component( /, *, page_context: PageContext, - compile_context: Any, + compile_context: CompileContext, in_prop_tree: bool = False, ) -> None: """Collect imports and page artifacts for the active component node.""" diff --git a/reflex/compiler/plugins/memoize.py b/reflex/compiler/plugins/memoize.py index 86b6b53a3e4..36170bc047c 100644 --- a/reflex/compiler/plugins/memoize.py +++ b/reflex/compiler/plugins/memoize.py @@ -21,7 +21,6 @@ from __future__ import annotations import dataclasses -from typing import Any from reflex_base.components.app_wraps import ( collect_var_app_wraps_for_component, @@ -37,7 +36,7 @@ is_snapshot_boundary, ) from reflex_base.constants.compiler import MemoizationDisposition -from reflex_base.plugins import ComponentAndChildren, PageContext +from reflex_base.plugins import CompileContext, ComponentAndChildren, PageContext from reflex_base.plugins.base import Plugin from reflex_components_core.base.bare import Bare from reflex_components_core.core.cond import Cond @@ -232,7 +231,7 @@ def enter_component( /, *, page_context: PageContext, - compile_context: Any, + compile_context: CompileContext, in_prop_tree: bool = False, ) -> BaseComponent | ComponentAndChildren | None: """Memoize snapshot-boundary subtrees before descent. @@ -300,7 +299,7 @@ def leave_component( /, *, page_context: PageContext, - compile_context: Any, + compile_context: CompileContext, in_prop_tree: bool = False, ) -> BaseComponent | ComponentAndChildren | None: """Wrap non-boundary memoizables and pop any suppression this component pushed. @@ -360,7 +359,7 @@ def leave_component( def _build_wrapper( comp: Component, page_context: PageContext, - compile_context: Any, + compile_context: CompileContext, ) -> BaseComponent | None: """Return the memo wrapper component for ``comp``, or ``None`` if untagged. diff --git a/reflex/compiler/templates.py b/reflex/compiler/templates.py index 7ac0223331d..486858ed475 100644 --- a/reflex/compiler/templates.py +++ b/reflex/compiler/templates.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.compiler.templates import * # pragma: no cover diff --git a/reflex/compiler/utils.py b/reflex/compiler/utils.py index 8168fed9668..91fb7a86958 100644 --- a/reflex/compiler/utils.py +++ b/reflex/compiler/utils.py @@ -238,8 +238,8 @@ def compile_state(state: type[BaseState]) -> dict: asyncio.run, _resolve_delta(initial_state) ).result() # A backend in this process diffs first hydrates against these exact values. - cache_initial_snapshot(state, resolved_initial_state) - return _sorted_keys(resolved_initial_state) + cache_initial_snapshot(state, resolved_initial_state) # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/3186 + return _sorted_keys(resolved_initial_state) # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/3186 def _compile_initial_state( @@ -783,11 +783,10 @@ def create_document_root( for component in head_components or []: if isinstance(component, Meta): - if component.char_set is not None: # pyright: ignore[reportAttributeAccessIssue] + if component.char_set is not None: # ty:ignore[unresolved-attribute] existing_meta_types.add("char_set") - if ( - (name := component.name) is not None # pyright: ignore[reportAttributeAccessIssue] - and name.equals(Var.create("viewport")) + if (name := component.name) is not None and name.equals( # ty:ignore[unresolved-attribute] + Var.create("viewport") ): existing_meta_types.add("viewport") @@ -1000,7 +999,7 @@ def get_memo_module_path(segments: tuple[str, ...]) -> str: def add_meta( page: Component, title: str | Var, - image: str, + image: str | Var, meta: Sequence[Mapping[str, Any] | Component], description: str | Var | None = None, ) -> Component: diff --git a/reflex/components/component.py b/reflex/components/component.py index 4affaccc7fe..fddd1f07bee 100644 --- a/reflex/components/component.py +++ b/reflex/components/component.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.components.component import * # pragma: no cover diff --git a/reflex/components/dynamic.py b/reflex/components/dynamic.py index 0f3a260e86b..127532530bd 100644 --- a/reflex/components/dynamic.py +++ b/reflex/components/dynamic.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from typing import Any diff --git a/reflex/components/field.py b/reflex/components/field.py index 6fe5b1dd916..5c41215c895 100644 --- a/reflex/components/field.py +++ b/reflex/components/field.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.components.field import * # pragma: no cover diff --git a/reflex/components/literals.py b/reflex/components/literals.py index 0738bda1331..d6a5ee042d5 100644 --- a/reflex/components/literals.py +++ b/reflex/components/literals.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.components.literals.""" from reflex_base.components.literals import * # pragma: no cover diff --git a/reflex/components/memo.py b/reflex/components/memo.py index 4de9661b2e8..e2907a0ce6a 100644 --- a/reflex/components/memo.py +++ b/reflex/components/memo.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.components.memo import * # pragma: no cover diff --git a/reflex/components/props.py b/reflex/components/props.py index 8ea89b2ab1b..b8cdfe7ffc0 100644 --- a/reflex/components/props.py +++ b/reflex/components/props.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.components.props.""" from reflex_base.components.props import * # pragma: no cover diff --git a/reflex/components/tags/__init__.py b/reflex/components/tags/__init__.py index 855786c12bf..e3e1c3fa6c2 100644 --- a/reflex/components/tags/__init__.py +++ b/reflex/components/tags/__init__.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.components.tags import * # pragma: no cover diff --git a/reflex/components/tags/cond_tag.py b/reflex/components/tags/cond_tag.py index 5d9a8b0a226..677ddc5d630 100644 --- a/reflex/components/tags/cond_tag.py +++ b/reflex/components/tags/cond_tag.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.components.tags.cond_tag import * # pragma: no cover diff --git a/reflex/components/tags/iter_tag.py b/reflex/components/tags/iter_tag.py index 9bb13e2ba03..414d830dd1e 100644 --- a/reflex/components/tags/iter_tag.py +++ b/reflex/components/tags/iter_tag.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.components.tags.iter_tag import * # pragma: no cover diff --git a/reflex/components/tags/match_tag.py b/reflex/components/tags/match_tag.py index b3f09d058a3..5995bcd4f84 100644 --- a/reflex/components/tags/match_tag.py +++ b/reflex/components/tags/match_tag.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.components.tags.match_tag import * # pragma: no cover diff --git a/reflex/components/tags/tag.py b/reflex/components/tags/tag.py index 95365b678a8..2ae9df9c94b 100644 --- a/reflex/components/tags/tag.py +++ b/reflex/components/tags/tag.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.components.tags.tag import * # pragma: no cover diff --git a/reflex/components/tags/tagless.py b/reflex/components/tags/tagless.py index cf0d12ee2ff..3ae0c1c7351 100644 --- a/reflex/components/tags/tagless.py +++ b/reflex/components/tags/tagless.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.components.tags.tagless import * # pragma: no cover diff --git a/reflex/config.py b/reflex/config.py index 1d015fcf056..1054947ad34 100644 --- a/reflex/config.py +++ b/reflex/config.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.config.""" from reflex_base.config import * # pragma: no cover diff --git a/reflex/constants/base.py b/reflex/constants/base.py index b500c7e5f0c..f42e8240952 100644 --- a/reflex/constants/base.py +++ b/reflex/constants/base.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.constants.base import * # pragma: no cover diff --git a/reflex/constants/colors.py b/reflex/constants/colors.py index c1f1bf610fe..1b7d9cca3e5 100644 --- a/reflex/constants/colors.py +++ b/reflex/constants/colors.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.constants.colors import * # pragma: no cover diff --git a/reflex/constants/compiler.py b/reflex/constants/compiler.py index e8a4e38a6eb..c99bef62b4a 100644 --- a/reflex/constants/compiler.py +++ b/reflex/constants/compiler.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.constants.compiler import * # pragma: no cover diff --git a/reflex/constants/config.py b/reflex/constants/config.py index 1263c236c93..fca2cac594f 100644 --- a/reflex/constants/config.py +++ b/reflex/constants/config.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.constants.config.""" from reflex_base.constants.config import * # pragma: no cover diff --git a/reflex/constants/event.py b/reflex/constants/event.py index 823ac585643..886ea8ef1bc 100644 --- a/reflex/constants/event.py +++ b/reflex/constants/event.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.constants.event import * # pragma: no cover diff --git a/reflex/constants/installer.py b/reflex/constants/installer.py index 54bf46fb30e..e2560af2a80 100644 --- a/reflex/constants/installer.py +++ b/reflex/constants/installer.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.constants.installer.""" from reflex_base.constants.installer import * # pragma: no cover diff --git a/reflex/constants/route.py b/reflex/constants/route.py index aa301e230de..9b0455f728a 100644 --- a/reflex/constants/route.py +++ b/reflex/constants/route.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.constants.route.""" from reflex_base.constants.route import * # pragma: no cover diff --git a/reflex/constants/state.py b/reflex/constants/state.py index 3782112b6fa..9f953ccf490 100644 --- a/reflex/constants/state.py +++ b/reflex/constants/state.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.constants.state import * # pragma: no cover diff --git a/reflex/constants/utils.py b/reflex/constants/utils.py index 0c983c73dfd..dd6aaae4c32 100644 --- a/reflex/constants/utils.py +++ b/reflex/constants/utils.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.constants.utils.""" from reflex_base.constants.utils import * # pragma: no cover diff --git a/reflex/environment.py b/reflex/environment.py index e0dbb564d1e..cf8e3bf0fde 100644 --- a/reflex/environment.py +++ b/reflex/environment.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.environment.""" from reflex_base.environment import * # pragma: no cover diff --git a/reflex/event.py b/reflex/event.py index a086ce57581..622e3fc9b3c 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -2,7 +2,7 @@ import sys -from reflex_base.event import * # pyright: ignore[reportWildcardImportFromLibrary] +from reflex_base.event import * from reflex_base.event import event as event -sys.modules[__name__] = event # pyright: ignore[reportArgumentType] +sys.modules[__name__] = event # ty:ignore[invalid-assignment] diff --git a/reflex/experimental/client_state.py b/reflex/experimental/client_state.py index 1d0b69c1bc1..0435701cc74 100644 --- a/reflex/experimental/client_state.py +++ b/reflex/experimental/client_state.py @@ -4,11 +4,10 @@ import dataclasses import re -from collections.abc import Callable from typing import Any from reflex_base import constants -from reflex_base.event import EventChain, EventHandler, EventSpec, run_script +from reflex_base.event import EventChain, EventSpec, EventType, run_script from reflex_base.utils.imports import ImportVar from reflex_base.vars import VarData, get_unique_variable_name from reflex_base.vars.base import LiteralVar, Var @@ -284,7 +283,7 @@ def set(self) -> Var: """ return self.set_value() - def retrieve(self, callback: EventHandler | Callable | None = None) -> EventSpec: + def retrieve(self, callback: EventType[Any] | None = None) -> EventSpec: """Pass the value of the client state variable to a backend EventHandler. The event handler must `yield` or `return` the EventSpec to trigger the event. diff --git a/reflex/experimental/memo.py b/reflex/experimental/memo.py index ea01542314d..90ae66bde3e 100644 --- a/reflex/experimental/memo.py +++ b/reflex/experimental/memo.py @@ -8,4 +8,4 @@ ExperimentalNamespace.register_component_warning("memo") -sys.modules[__name__] = memo # pyright: ignore[reportArgumentType] +sys.modules[__name__] = memo diff --git a/reflex/istate/data.py b/reflex/istate/data.py index 06a438ddf6a..6cad032a29d 100644 --- a/reflex/istate/data.py +++ b/reflex/istate/data.py @@ -442,7 +442,7 @@ def create( # entry still accepts it because .to()/guess_type() only call .create(...), # which has a compatible signature. _register_var_subclass_entry( - VarSubclassEntry(ReflexURLVar, ReflexURLCastedVar, (ReflexURL,)) # pyright: ignore[reportArgumentType] + VarSubclassEntry(ReflexURLVar, ReflexURLCastedVar, (ReflexURL,)) # ty:ignore[invalid-argument-type] ) diff --git a/reflex/istate/manager/__init__.py b/reflex/istate/manager/__init__.py index 156c5af687e..723f54bf8ef 100644 --- a/reflex/istate/manager/__init__.py +++ b/reflex/istate/manager/__init__.py @@ -110,7 +110,7 @@ def _coerce_token(token: StateToken[TOKEN_TYPE] | str) -> StateToken[TOKEN_TYPE] from reflex.istate.manager.token import BaseStateToken from reflex.state import State - return BaseStateToken.from_legacy_token(token, root_state=State) # type: ignore[return-value] + return BaseStateToken.from_legacy_token(token, root_state=State) # ty:ignore[invalid-return-type] return token @overload @@ -209,7 +209,7 @@ async def modify_state( Yields: The state for the token. """ - yield # pyright: ignore[reportReturnType] + yield # ty:ignore[invalid-yield] def modify_state_with_links( self, diff --git a/reflex/istate/manager/disk.py b/reflex/istate/manager/disk.py index 920e19867fb..7541a444dbe 100644 --- a/reflex/istate/manager/disk.py +++ b/reflex/istate/manager/disk.py @@ -211,7 +211,7 @@ async def get_state( if isinstance(token, BaseStateToken): # Find the root state root_state_cls = token.cls.get_root_state() - root_state = await self.load_state(token.with_cls(root_state_cls)) + root_state = await self.load_state(token.with_cls(root_state_cls)) # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/1824 # Create a new root state tree with all substates instantiated. fresh_root_state = root_state_cls(_reflex_internal_init=True) if root_state is None: @@ -230,7 +230,7 @@ async def get_state( if state is None: state = token.cls() self.states[token.cache_key] = state - return cast(TOKEN_TYPE, state) + return state async def set_state_for_substate( self, token: StateToken[TOKEN_TYPE], substate: TOKEN_TYPE @@ -253,7 +253,7 @@ async def set_state_for_substate( if isinstance(token, BaseStateToken) and isinstance(substate, BaseState): for substate_substate in substate.substates.values(): - await self.set_state_for_substate(token, substate_substate) + await self.set_state_for_substate(token, substate_substate) # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/1824 def _is_locked(self, token: StateToken) -> bool: """Check whether a token's lock is currently held. diff --git a/reflex/istate/manager/redis.py b/reflex/istate/manager/redis.py index 2d7d25ad244..f6e03b1fa6b 100644 --- a/reflex/istate/manager/redis.py +++ b/reflex/istate/manager/redis.py @@ -658,7 +658,8 @@ async def _get_state_cached( raise ValueError # noqa: TRY301 except ValueError: await self.get_state( - token, for_state_instance=cached_state + token, # ty:ignore[invalid-argument-type] + for_state_instance=cached_state, ) yield cast(TOKEN_TYPE, cached_state) return @@ -897,7 +898,7 @@ async def _subscribe_lock_updates(self): lock_waiter_key_pattern: self._handle_lock_contention, } async with self.redis.pubsub() as pubsub: - await pubsub.psubscribe(**handlers) # pyright: ignore[reportArgumentType] + await pubsub.psubscribe(**handlers) try: # Notifications are only delivered once redis confirms the subscription. async for message in pubsub.listen(): @@ -1011,7 +1012,7 @@ async def _n_lock_contenders(self, lock_key: bytes) -> int: res = self.redis.scard(lock_key + b"_waiters") if inspect.isawaitable(res): res = await res - return res + return res # ty:ignore[invalid-return-type] @contextlib.asynccontextmanager async def _request_lock_release( diff --git a/reflex/istate/manager/token.py b/reflex/istate/manager/token.py index 8b8e626ebc2..ac7b5d4d84e 100644 --- a/reflex/istate/manager/token.py +++ b/reflex/istate/manager/token.py @@ -252,7 +252,7 @@ def from_legacy_token( client_token, state_path = _split_substate_key(legacy_token) try: - state_cls = root_state.get_class_substate(tuple(state_path.split("."))) # type: ignore[union-attr] + state_cls = root_state.get_class_substate(tuple(state_path.split("."))) except ValueError as err: msg = ( "Invalid legacy state token: no state found for the state path. Expected " diff --git a/reflex/istate/proxy.py b/reflex/istate/proxy.py index a4df7c2401c..d81bd4d6ad3 100644 --- a/reflex/istate/proxy.py +++ b/reflex/istate/proxy.py @@ -93,8 +93,8 @@ # which the proxy's instance-level forwarding cannot answer for; the methods # `@dataclass` writes need no copy, resolving through the wrapped object. _DATACLASS_CLASS_ATTRS = ( - dataclasses._FIELDS, # pyright: ignore [reportAttributeAccessIssue] - dataclasses._PARAMS, # pyright: ignore [reportAttributeAccessIssue] + dataclasses._FIELDS, # ty:ignore[unresolved-attribute] + dataclasses._PARAMS, # ty:ignore[unresolved-attribute] "__match_args__", ) @@ -112,7 +112,7 @@ def _dataclass_proxy_namespace(wrapped_cls: type) -> dict[str, Any]: # dataclass declares as an instance field must not be copied. `fields()` # lists exactly those, excluding the ClassVar and InitVar entries that # `__dataclass_fields__` also carries, which stay class-level regardless. - instance_fields = {field.name for field in dataclasses.fields(wrapped_cls)} # pyright: ignore [reportArgumentType] + instance_fields = {field.name for field in dataclasses.fields(wrapped_cls)} # ty:ignore[invalid-argument-type] return { attr: getattr(wrapped_cls, attr) for attr in _DATACLASS_CLASS_ATTRS @@ -383,7 +383,7 @@ def __getattr__(self, name: str) -> Any: ) raise ImmutableStateError(msg) - value = super().__getattr__(name) # pyright: ignore[reportAttributeAccessIssue] + value = super().__getattr__(name) if not name.startswith("_self_") and isinstance(value, MutableProxy): # Ensure mutations to these containers are blocked unless proxy is # mutable. An inherited field lives on an ancestor state: proxy @@ -480,7 +480,7 @@ async def get_state(self, state_cls: type[T_STATE]) -> T_STATE: await self.__wrapped__.get_state(state_cls), event=self._self_event, parent_state_proxy=self, - ) # pyright: ignore [reportReturnType] + ) # ty:ignore[invalid-return-type] async def _as_state_update(self, *args, **kwargs) -> StateUpdate: """Temporarily allow mutability to access parent_state. @@ -1007,7 +1007,7 @@ def _wrap_mutable(self, value: Any, path: tuple[_AccessSpec, ...]) -> Any: ) def _wrap_recursive_decorator( - self, wrapped: Callable, instance: BaseState, args: list, kwargs: dict + self, wrapped: Callable, instance: BaseState, args: tuple, kwargs: dict ) -> Any: """Wrap a function that returns a possibly mutable value. @@ -1045,7 +1045,7 @@ def __getattr__(self, __name: str) -> Any: Returns: The attribute value. """ - value = super().__getattr__(__name) # pyright: ignore[reportAttributeAccessIssue] + value = super().__getattr__(__name) if type(value) in _SCALAR_TYPES: # Skip the checks below entirely on the scalar hot path. return value @@ -1077,7 +1077,7 @@ def __getattr__(self, __name: str) -> Any: # Wrap special methods that may return mutable objects tied to the state. value = wrapt.FunctionWrapper( value, - self._wrap_recursive_decorator, # pyright: ignore[reportArgumentType] + self._wrap_recursive_decorator, ) if is_mutable_type(type(value)) and __name not in ( @@ -1176,7 +1176,7 @@ def __delitem__(self, key: str): Args: key: The key of the item. """ - self._mark_dirty(super().__delitem__, args=(key,)) # pyright: ignore[reportAttributeAccessIssue] + self._mark_dirty(super().__delitem__, args=(key,)) def __setitem__(self, key: str, value: Any): """Set the item on the proxied object and mark state dirty. @@ -1185,7 +1185,7 @@ def __setitem__(self, key: str, value: Any): key: The key of the item. value: The value of the item. """ - self._mark_dirty(super().__setitem__, args=(key, value)) # pyright: ignore[reportAttributeAccessIssue] + self._mark_dirty(super().__setitem__, args=(key, value)) def __setattr__(self, name: str, value: Any): """Set the attribute on the proxied object and mark state dirty. @@ -1294,6 +1294,8 @@ class ImmutableMutableProxy(MutableProxy): to modify the wrapped object when the StateProxy is immutable. """ + _self_state: StateProxy + # Ensure that recursively wrapped proxies use ImmutableMutableProxy as base. __base_proxy__ = "ImmutableMutableProxy" @@ -1306,7 +1308,7 @@ def _dirty_state(self) -> BaseState: Raises: ImmutableStateError: if the StateProxy is not mutable. """ - state = cast("StateProxy", self._self_state) + state = self._self_state if not state._is_mutable(): msg = ( "Background task StateProxy is immutable outside of a context " diff --git a/reflex/istate/shared.py b/reflex/istate/shared.py index a4d24de0657..ff3ccbda697 100644 --- a/reflex/istate/shared.py +++ b/reflex/istate/shared.py @@ -426,10 +426,8 @@ async def _modify_linked_states( # Go through all linked states and patch them in if they are present in the tree for linked_state_name, linked_token in self._reflex_internal_links.items(): linked_state_cls: type[SharedState] = ( - self.get_root_state().get_class_substate( # pyright: ignore[reportAssignmentType] - linked_state_name - ) - ) + self.get_root_state().get_class_substate(linked_state_name) + ) # ty:ignore[invalid-assignment] try: original_state = self._get_state_from_cache(linked_state_cls) except ValueError: diff --git a/reflex/istate/wrappers.py b/reflex/istate/wrappers.py index 09e0a4fa3a7..6601171b8eb 100644 --- a/reflex/istate/wrappers.py +++ b/reflex/istate/wrappers.py @@ -1,14 +1,14 @@ """Wrappers for the state manager.""" -from typing import Any - from reflex.istate.manager import get_state_manager from reflex.istate.manager.token import BaseStateToken from reflex.istate.proxy import ReadOnlyStateProxy -from reflex.state import State, _split_substate_key +from reflex.state import BaseState, State, _split_substate_key -async def get_state(token: str, state_cls: Any | None = None) -> ReadOnlyStateProxy: +async def get_state( + token: str, state_cls: type[BaseState] | None = None +) -> ReadOnlyStateProxy: """Get the instance of a state for a token. Args: diff --git a/reflex/model.py b/reflex/model.py index c84a56c9dde..d94a12635c3 100644 --- a/reflex/model.py +++ b/reflex/model.py @@ -273,12 +273,12 @@ def get_metadata(cls) -> sqlalchemy.MetaData: return metadata -else: +elif not TYPE_CHECKING: get_engine_args = _print_db_not_available get_engine = _print_db_not_available get_async_engine = _print_db_not_available sqla_session = _print_db_not_available - ModelRegistry = _ClassThatErrorsOnInit # pyright: ignore [reportAssignmentType] + ModelRegistry = _ClassThatErrorsOnInit if TYPE_CHECKING or (find_spec("sqlalchemy") and find_spec("alembic")): import alembic.autogenerate @@ -531,6 +531,7 @@ def migrate(autogenerate: bool = False) -> bool | None: ): import sqlmodel from reflex_base.utils.serializers import serialize_sqlmodel as serialize_sqlmodel + from sqlmodel.main import SQLModelConfig _AsyncSessionLocal: dict[str | None, sqlalchemy.ext.asyncio.async_sessionmaker] = {} @@ -573,7 +574,7 @@ class Model(sqlmodel.SQLModel): id: int | None = sqlmodel.Field(default=None, primary_key=True) - model_config = { # pyright: ignore [reportAssignmentType] + model_config: ClassVar[SQLModelConfig] = { "arbitrary_types_allowed": True, "use_enum_values": True, "extra": "allow", @@ -715,8 +716,8 @@ def asession(url: str | None = None) -> AsyncSession: ) return _AsyncSessionLocal[url]() -else: +elif not TYPE_CHECKING: get_db_status = _print_db_not_available session = _print_db_not_available asession = _print_db_not_available - Model = _ClassThatErrorsOnInit # pyright: ignore [reportAssignmentType] + Model = _ClassThatErrorsOnInit diff --git a/reflex/page.py b/reflex/page.py index 8cadbafc384..450ecd26896 100644 --- a/reflex/page.py +++ b/reflex/page.py @@ -167,4 +167,4 @@ def __new__( page_namespace = PageNamespace -sys.modules[__name__] = page_namespace # pyright: ignore[reportArgumentType] +sys.modules[__name__] = page_namespace # ty:ignore[invalid-assignment] diff --git a/reflex/plugins/_screenshot.py b/reflex/plugins/_screenshot.py index bd0bbb878bd..a73a2b2dd60 100644 --- a/reflex/plugins/_screenshot.py +++ b/reflex/plugins/_screenshot.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.plugins._screenshot.""" from reflex_base.plugins._screenshot import * # pragma: no cover diff --git a/reflex/plugins/base.py b/reflex/plugins/base.py index c7f85b406cc..535102b293b 100644 --- a/reflex/plugins/base.py +++ b/reflex/plugins/base.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.plugins.base.""" from reflex_base.plugins.base import * # pragma: no cover diff --git a/reflex/plugins/shared_tailwind.py b/reflex/plugins/shared_tailwind.py index ae1d730334d..16bb2425e85 100644 --- a/reflex/plugins/shared_tailwind.py +++ b/reflex/plugins/shared_tailwind.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.plugins.shared_tailwind.""" from reflex_base.plugins.shared_tailwind import * # pragma: no cover diff --git a/reflex/plugins/sitemap.py b/reflex/plugins/sitemap.py index de79b9c18ed..02ddf01b9cb 100644 --- a/reflex/plugins/sitemap.py +++ b/reflex/plugins/sitemap.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.plugins.sitemap.""" from reflex_base.plugins.sitemap import * # pragma: no cover diff --git a/reflex/plugins/tailwind_v3.py b/reflex/plugins/tailwind_v3.py index a5baf1b5c70..95c1f702260 100644 --- a/reflex/plugins/tailwind_v3.py +++ b/reflex/plugins/tailwind_v3.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.plugins.tailwind_v3.""" from reflex_base.plugins.tailwind_v3 import * # pragma: no cover diff --git a/reflex/plugins/tailwind_v4.py b/reflex/plugins/tailwind_v4.py index 177e12c219f..2102166f8de 100644 --- a/reflex/plugins/tailwind_v4.py +++ b/reflex/plugins/tailwind_v4.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.plugins.tailwind_v4.""" from reflex_base.plugins.tailwind_v4 import * # pragma: no cover diff --git a/reflex/state.py b/reflex/state.py index 9859e0d3c2a..d9bbf110e5d 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -14,7 +14,7 @@ import pickle import re import sys -from collections.abc import Callable, Iterable, Iterator, Sequence +from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence from datetime import timedelta from hashlib import md5 from types import FunctionType @@ -61,6 +61,7 @@ ComputedVar, DynamicRouteVar, EvenMoreBasicBaseState, + LiteralVar, ToOperation, Var, _inherited_value, @@ -294,7 +295,7 @@ def _override_base_method(fn: Callable[PARAMS, RETURN]) -> Callable[PARAMS, RETU Returns: The marked function. """ - fn.__override_base_method__ = True # pyright: ignore[reportFunctionMemberAccess] + fn.__override_base_method__ = True # ty:ignore[unresolved-attribute] return fn @@ -314,7 +315,7 @@ def _cache_per_class( Returns: A method that computes its value once per class. """ - cache_key = fn.__name__ + cache_key = format.callable_name(fn) @functools.wraps(fn) def wrapped(cls: type[BaseState]) -> RETURN: @@ -856,11 +857,14 @@ def _bind_mixin_members(cls) -> None: if _inherited_value(cls.__mro__, name) is not value: continue if is_computed_var(value): + fget = value.fget + if not isinstance(fget, FunctionType): + continue _bind_attr( cls, name, value._replace( - fget=cls._copy_fn(value.fget), + fget=cls._copy_fn(fget), _var_data=VarData.from_state(cls), ), ) @@ -887,7 +891,7 @@ def _add_event_handler( setattr(cls, name, handler) @staticmethod - def _copy_fn(fn: Callable) -> Callable: + def _copy_fn(fn: FunctionType) -> FunctionType: """Copy a function. Used to copy ComputedVars and EventHandlers from mixins. Args: @@ -928,7 +932,7 @@ def _item_is_event_handler(name: str, value: Any) -> bool: ) @classmethod - def _evaluate(cls, f: Callable[[Self], Any], of_type: type | None = None) -> Var: + def _evaluate(cls, f: FunctionType, of_type: type | None = None) -> Var: """Evaluate a function to a ComputedVar. Experimental. Args: @@ -1426,7 +1430,7 @@ def _set_default_value(cls, name: str, prop: Var): object.__setattr__(prop, "_var_type", prop._var_type | None) @classmethod - def _update_substate_vars(cls, vars_to_add: builtins.dict[str, Var]): + def _update_substate_vars(cls, vars_to_add: Mapping[str, Var]): """Update the inherited vars of substates recursively when new vars are added. Also updates the var dependency tracking dicts after adding vars. @@ -1830,14 +1834,6 @@ async def get_var_value(self, var: Var[VAR_TYPE]) -> VAR_TYPE: if not isinstance(var, Var): return var - unset = object() - - # Fast case: this is a literal var and the value is known. - if ( - var_value := getattr(var, "_var_value", unset) - ) is not unset and not isinstance(var_value, Var): - return var_value # pyright: ignore [reportReturnType] - # Unwrap any cast wrappers and resolve via the underlying var's *own* # var data, not the recursive _get_all_var_data(). For an operation or # derived var (e.g. State.a + State.b or State.items[0]), the recursive @@ -1848,6 +1844,13 @@ async def get_var_value(self, var: Var[VAR_TYPE]) -> VAR_TYPE: inner_var = var while isinstance(inner_var, ToOperation): inner_var = inner_var._original + + # Fast case: this is a literal var and the value is known. + if isinstance(inner_var, LiteralVar) and not isinstance( + inner_var._var_value, Var + ): + return inner_var._var_value + var_data = inner_var._var_data if var_data is None or not var_data.state or not var_data.field_name: msg = f"Unable to retrieve value for {var._js_expr}: not associated with any state." @@ -2413,7 +2416,7 @@ async def _get_state_from_redis(self, state_cls: type[T_STATE]) -> T_STATE: from reflex.istate.shared import SharedStateBaseInternal shared_base = await self.get_state(SharedStateBaseInternal) - return await shared_base._resolve_linked_state(state_cls, linked_token) # type: ignore[return-value] + return await shared_base._resolve_linked_state(state_cls, linked_token) # ty:ignore[invalid-return-type] return await super()._get_state_from_redis(state_cls) @event diff --git a/reflex/style.py b/reflex/style.py index 7bea29b6a8e..86dd70eb1c4 100644 --- a/reflex/style.py +++ b/reflex/style.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.style import * # pragma: no cover diff --git a/reflex/testing.py b/reflex/testing.py index c80133231c5..8de199539a0 100644 --- a/reflex/testing.py +++ b/reflex/testing.py @@ -29,6 +29,7 @@ from reflex_base.config import get_config, reload_config from reflex_base.environment import environment from reflex_base.registry import RegistrationContext +from reflex_base.utils.format import callable_name from reflex_base.utils.types import ASGIApp import reflex @@ -65,7 +66,7 @@ # The timeout (minutes) to check for the port. DEFAULT_TIMEOUT = 15 POLL_INTERVAL = 0.25 -FRONTEND_POPEN_ARGS = {} +FRONTEND_POPEN_ARGS: dict[str, Any] = {} T = TypeVar("T") TimeoutType = int | float | None @@ -88,7 +89,7 @@ def _get_uvicorn(): if platform.system() == "Windows": - FRONTEND_POPEN_ARGS["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # pyright: ignore [reportAttributeAccessIssue] + FRONTEND_POPEN_ARGS["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # ty:ignore[unresolved-attribute] FRONTEND_POPEN_ARGS["shell"] = True else: FRONTEND_POPEN_ARGS["start_new_session"] = True @@ -141,7 +142,7 @@ class AppHarness: backend: uvicorn.Server | None = None _frontends: list[WebDriver] = dataclasses.field(default_factory=list) _registry_token: contextvars.Token[RegistrationContext] | None = None - _base_registration_context: ClassVar[RegistrationContext] | None = None + _base_registration_context: ClassVar[RegistrationContext | None] = None @classmethod def create( @@ -173,14 +174,14 @@ def create( elif isinstance(app_source, functools.partial): keywords = app_source.keywords slug_suffix = "_".join([str(v) for v in keywords.values()]) - func_name = app_source.func.__name__ + func_name = callable_name(app_source.func) app_name = f"{func_name}_{slug_suffix}" app_name = re.sub(r"[^a-zA-Z0-9_]", "_", app_name) elif isinstance(app_source, str): msg = "app_name must be provided when app_source is a string." raise ValueError(msg) else: - app_name = app_source.__name__ + app_name = callable_name(app_source) app_name = app_name.lower() while "__" in app_name: @@ -442,12 +443,12 @@ def _wait_frontend(self): msg = "Frontend did not start" raise RuntimeError(msg) + stdout = self.frontend_process.stdout + def consume_frontend_output(): while True: try: - line = ( - self.frontend_process.stdout.readline() # pyright: ignore [reportOptionalMemberAccess] - ) + line = stdout.readline() # catch I/O operation on closed file. except ValueError as e: logger.debug(str(e)) @@ -681,29 +682,29 @@ def frontend( want_headless = True if driver_clz is None: requested_driver = environment.APP_HARNESS_DRIVER.get() - driver_clz = getattr(webdriver, requested_driver) # pyright: ignore [reportPossiblyUnboundVariable] + driver_clz = getattr(webdriver, requested_driver) if driver_options is None: - driver_options = getattr(webdriver, f"{requested_driver}Options")() # pyright: ignore [reportPossiblyUnboundVariable] - if driver_clz is webdriver.Chrome: # pyright: ignore [reportPossiblyUnboundVariable] + driver_options = getattr(webdriver, f"{requested_driver}Options")() + if driver_clz is webdriver.Chrome: if driver_options is None: from selenium.webdriver.chrome.options import Options - driver_options = Options() # pyright: ignore [reportPossiblyUnboundVariable] + driver_options = Options() driver_options.add_argument("--class=AppHarness") if want_headless: driver_options.add_argument("--headless=new") - elif driver_clz is webdriver.Firefox: # pyright: ignore [reportPossiblyUnboundVariable] + elif driver_clz is webdriver.Firefox: if driver_options is None: from selenium.webdriver.firefox.options import Options - driver_options = Options() # pyright: ignore [reportPossiblyUnboundVariable] + driver_options = Options() if want_headless: driver_options.add_argument("-headless") - elif driver_clz is webdriver.Edge: # pyright: ignore [reportPossiblyUnboundVariable] + elif driver_clz is webdriver.Edge: if driver_options is None: from selenium.webdriver.edge.options import Options - driver_options = Options() # pyright: ignore [reportPossiblyUnboundVariable] + driver_options = Options() if want_headless: driver_options.add_argument("headless") if driver_options is None: @@ -720,7 +721,7 @@ def frontend( driver_options.set_capability(key, value) if driver_kwargs is None: driver_kwargs = {} - driver = driver_clz(options=driver_options, **driver_kwargs) # pyright: ignore [reportOptionalCall, reportArgumentType] + driver = driver_clz(options=driver_options, **driver_kwargs) driver.get(self.frontend_url) self._frontends.append(driver) return driver diff --git a/reflex/utils/compat.py b/reflex/utils/compat.py index fa8ecc8f9a4..c58106c8654 100644 --- a/reflex/utils/compat.py +++ b/reflex/utils/compat.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.utils.compat import * # pragma: no cover diff --git a/reflex/utils/console.py b/reflex/utils/console.py index 6c884425034..2ebeeac662b 100644 --- a/reflex/utils/console.py +++ b/reflex/utils/console.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.utils.console import * # pragma: no cover diff --git a/reflex/utils/decorator.py b/reflex/utils/decorator.py index 6846799fcd9..2bb924b5228 100644 --- a/reflex/utils/decorator.py +++ b/reflex/utils/decorator.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.utils.decorator import * # pragma: no cover diff --git a/reflex/utils/exceptions.py b/reflex/utils/exceptions.py index c08487e6e96..ee4c8a37ec4 100644 --- a/reflex/utils/exceptions.py +++ b/reflex/utils/exceptions.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.utils.exceptions import * # pragma: no cover diff --git a/reflex/utils/exec.py b/reflex/utils/exec.py index 5c4a8fb9726..40176d6dbfd 100644 --- a/reflex/utils/exec.py +++ b/reflex/utils/exec.py @@ -36,7 +36,7 @@ # For uvicorn windows bug fix (#2335) frontend_process = None _frontend_process_lock = threading.Lock() -_frontend_shutting_down = False +_frontend_shutting_down: bool = False DEV_BACKEND_RELOAD_MARKER = ".reflex_dev_backend_started" @@ -290,7 +290,7 @@ def run_process_and_launch_url( "env": _with_development_condition(frontend_env(os.environ)) } if constants.IS_WINDOWS and backend_present: - kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # pyright: ignore [reportAttributeAccessIssue] + kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # ty:ignore[unresolved-attribute] process = processes.new_process( run_command, cwd=get_web_dir(), diff --git a/reflex/utils/format.py b/reflex/utils/format.py index 1a168466b76..8ed7a0b63be 100644 --- a/reflex/utils/format.py +++ b/reflex/utils/format.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.utils.format import * # pragma: no cover diff --git a/reflex/utils/imports.py b/reflex/utils/imports.py index 3b93770f60e..be6a1f4e811 100644 --- a/reflex/utils/imports.py +++ b/reflex/utils/imports.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.utils.imports import * # pragma: no cover diff --git a/reflex/utils/lazy_loader.py b/reflex/utils/lazy_loader.py index 7c1a5ca3a59..b895936b937 100644 --- a/reflex/utils/lazy_loader.py +++ b/reflex/utils/lazy_loader.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.utils.lazy_loader.""" from reflex_base.utils.lazy_loader import * # pragma: no cover diff --git a/reflex/utils/path_ops.py b/reflex/utils/path_ops.py index 0fa4a744316..a71aca23903 100644 --- a/reflex/utils/path_ops.py +++ b/reflex/utils/path_ops.py @@ -15,7 +15,7 @@ import sys import threading import unicodedata -from collections.abc import Iterator +from collections.abc import Iterator, Mapping from pathlib import Path from reflex_base.config import get_config @@ -395,7 +395,7 @@ def _write_json_file(file_path: Path, value: dict[str, object]) -> None: raise -def update_json_file(file_path: str | Path, update_dict: dict[str, object]) -> None: +def update_json_file(file_path: str | Path, update_dict: Mapping[str, object]) -> None: """Update the contents of a json file. Args: diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index acfa8ac6062..99899980c55 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -394,7 +394,7 @@ def _safe_getenv(k: str, fallback: str | None = None) -> str | None: try: import nt - if not nt._supports_virtual_terminal(): # pyright: ignore[reportAttributeAccessIssue] + if not nt._supports_virtual_terminal(): return False except (ImportError, AttributeError): return False @@ -436,7 +436,7 @@ def compile_or_validate_app( try: colorize = _can_colorize() - traceback.print_exception(e, colorize=colorize) # pyright: ignore[reportCallIssue] + traceback.print_exception(e, colorize=colorize) # ty:ignore[no-matching-overload] except Exception: traceback.print_exception(e) return False diff --git a/reflex/utils/processes.py b/reflex/utils/processes.py index 2e5d449c582..221a68dad4b 100644 --- a/reflex/utils/processes.py +++ b/reflex/utils/processes.py @@ -263,7 +263,7 @@ def subprocess_p_open(args: subprocess._CMD, **kwargs): fn: Callable[..., subprocess.CompletedProcess[str] | subprocess.Popen[str]] = ( subprocess.run if run else subprocess_p_open ) - return fn(non_empty_args, **kwargs) + return fn(non_empty_args, **kwargs) # ty:ignore[no-matching-overload] def _interrupt_main_thread(): @@ -284,7 +284,7 @@ def _interrupt_main_thread(): @contextlib.contextmanager def run_concurrently_context( - *fns: Callable[..., Any] | tuple[Callable[..., Any], ...], + *fns: Callable[..., Any] | tuple[Any, ...], interrupt_on_failure: bool = True, ) -> Generator[list[futures.Future], None, None]: """Run functions concurrently in a thread pool. diff --git a/reflex/utils/pyi_generator.py b/reflex/utils/pyi_generator.py index 02c8dbd99cd..8e3e1a96a25 100644 --- a/reflex/utils/pyi_generator.py +++ b/reflex/utils/pyi_generator.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.utils.pyi_generator import * # pragma: no cover diff --git a/reflex/utils/serializers.py b/reflex/utils/serializers.py index 53bdb151e7b..60d36df58c3 100644 --- a/reflex/utils/serializers.py +++ b/reflex/utils/serializers.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.utils.serializers import * # pragma: no cover diff --git a/reflex/utils/tasks.py b/reflex/utils/tasks.py index 282cadb7325..9ae6be47564 100644 --- a/reflex/utils/tasks.py +++ b/reflex/utils/tasks.py @@ -7,6 +7,8 @@ from contextvars import Context from typing import Any +from reflex_base.utils.format import callable_name + logger = logging.getLogger(__name__) @@ -32,6 +34,7 @@ async def _run_forever( """ last_regular_loop_start = 0 exception_count = 0 + fn_name = callable_name(coro_function) while True: # Reset the exception count when the limit window has elapsed since the last non-exception loop started. @@ -48,10 +51,10 @@ async def _run_forever( exception_count += 1 if exception_count >= exception_limit: logger.error( - f"{coro_function.__name__}: task exceeded exception limit {exception_limit} within {exception_limit_window}s: {e}" + f"{fn_name}: task exceeded exception limit {exception_limit} within {exception_limit_window}s: {e}" ) raise - logger.error(f"{coro_function.__name__}: task error suppressed: {e}") + logger.error(f"{fn_name}: task error suppressed: {e}") await asyncio.sleep(exception_delay) continue raise @@ -106,7 +109,8 @@ def ensure_task( exception_limit_window=exception_limit_window, **kwargs, ) - task_name = f"reflex_ensure_task|{type(owner).__name__}.{task_attribute}={coro_function.__name__}|{time.time()}" + fn_name = callable_name(coro_function) + task_name = f"reflex_ensure_task|{type(owner).__name__}.{task_attribute}={fn_name}|{time.time()}" if task_context is not None: # Run the task in the given context (not needed after Python 3.11+ which supports passing context to create_task directly). task = task_context.run(asyncio.create_task, rf_coro, name=task_name) diff --git a/reflex/utils/telemetry.py b/reflex/utils/telemetry.py index e669935681c..b1c7fa5bf7b 100644 --- a/reflex/utils/telemetry.py +++ b/reflex/utils/telemetry.py @@ -70,7 +70,7 @@ def _retrieve_cpu_info() -> CpuInfo | None: The CPU info. """ platform_os = platform.system() - cpuinfo = {} + cpuinfo: dict[str, Any] = {} try: if platform_os == "Windows": cmd = 'powershell -Command "Get-CimInstance Win32_Processor | Select-Object -First 1 | Select-Object AddressWidth,Manufacturer,Name | ConvertTo-Json"' diff --git a/reflex/utils/telemetry_accounting.py b/reflex/utils/telemetry_accounting.py index 45d067183c7..617d5ecdcab 100644 --- a/reflex/utils/telemetry_accounting.py +++ b/reflex/utils/telemetry_accounting.py @@ -255,7 +255,7 @@ def _get_db_model_count() -> int: "redis": "state_manager_redis", } -_STORAGE_FEATURE: dict[type[ClientStorageBase], FeatureName] = { +_STORAGE_FEATURE: dict[type, FeatureName] = { Cookie: "cookie_count", LocalStorage: "local_storage_count", SessionStorage: "session_storage_count", diff --git a/reflex/utils/types.py b/reflex/utils/types.py index b68ba5cf1fe..bc797c63465 100644 --- a/reflex/utils/types.py +++ b/reflex/utils/types.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from typing import TYPE_CHECKING diff --git a/reflex/vars/__init__.py b/reflex/vars/__init__.py index 11d95952307..8854e8b66ad 100644 --- a/reflex/vars/__init__.py +++ b/reflex/vars/__init__.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Immutable-Based Var System.""" from reflex_base.vars import * # pragma: no cover diff --git a/reflex/vars/base.py b/reflex/vars/base.py index ebb21f5cb18..19323076605 100644 --- a/reflex/vars/base.py +++ b/reflex/vars/base.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.vars.base import * # pragma: no cover diff --git a/reflex/vars/color.py b/reflex/vars/color.py index 2b53da8dced..bd6da9bd19d 100644 --- a/reflex/vars/color.py +++ b/reflex/vars/color.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.vars.color import * # pragma: no cover diff --git a/reflex/vars/datetime.py b/reflex/vars/datetime.py index 8a1beb83e60..479450b042f 100644 --- a/reflex/vars/datetime.py +++ b/reflex/vars/datetime.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.vars.datetime import * # pragma: no cover diff --git a/reflex/vars/dep_tracking.py b/reflex/vars/dep_tracking.py index d2bdb2a3144..c4cee730dc6 100644 --- a/reflex/vars/dep_tracking.py +++ b/reflex/vars/dep_tracking.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.vars.dep_tracking import * # pragma: no cover diff --git a/reflex/vars/function.py b/reflex/vars/function.py index 126f11e7ffc..9b7a62a3906 100644 --- a/reflex/vars/function.py +++ b/reflex/vars/function.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.vars.function import * # pragma: no cover diff --git a/reflex/vars/number.py b/reflex/vars/number.py index b76889a407e..fabf4a62194 100644 --- a/reflex/vars/number.py +++ b/reflex/vars/number.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.vars.number import * # pragma: no cover diff --git a/reflex/vars/object.py b/reflex/vars/object.py index 898093c6666..71fb0fc21b9 100644 --- a/reflex/vars/object.py +++ b/reflex/vars/object.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.vars.object import * # pragma: no cover diff --git a/reflex/vars/sequence.py b/reflex/vars/sequence.py index 7bfdd606ede..2afa4af0d66 100644 --- a/reflex/vars/sequence.py +++ b/reflex/vars/sequence.py @@ -1,4 +1,3 @@ -# pyright: reportWildcardImportFromLibrary=false """Re-export from reflex_base.""" from reflex_base.vars.sequence import * # pragma: no cover diff --git a/scripts/check_min_deps.py b/scripts/check_min_deps.py index a8596e99657..a4cc365f0ca 100644 --- a/scripts/check_min_deps.py +++ b/scripts/check_min_deps.py @@ -4,7 +4,7 @@ ``packages/*``), this installs the package editable into two isolated virtualenvs (deps from PyPI, never the local workspace, via ``--no-sources``): one with dependencies resolved to their *declared minimums* (``--resolution lowest-direct``) and one with the latest -compatible versions. Pyright runs against the package's own source in each, and the check +compatible versions. ty runs against the package's own source in each, and the check fails only on errors that are *new* at the minimum versions. The delta is what matters, not the absolute error count: a package's source legitimately @@ -78,6 +78,7 @@ import argparse import json import os +import re import shutil import subprocess import sys @@ -101,7 +102,7 @@ # Packages that are intentionally not validated: # hatch-reflex-pyi - build-backend plugin, only depends on hatchling # integrations-docs - has no declared dependencies -# reflex-site-shared - excluded from the root pyright config +# reflex-site-shared - excluded from the root ty config SKIP_PACKAGES = frozenset({ "hatch-reflex-pyi", "integrations-docs", @@ -160,7 +161,7 @@ class Package: """Directory containing the package's ``pyproject.toml`` (the editable install target).""" source_dir: Path - """Directory of importable source that pyright should type-check.""" + """Directory of importable source that ty should type-check.""" extras: tuple[str, ...] """Names of optional-dependency groups to install alongside the package.""" @@ -385,32 +386,46 @@ def _run(cmd: list[str], **kwargs) -> subprocess.CompletedProcess[str]: ) -def _pyright_errors(report: dict) -> dict[tuple[str, int, int, str], str]: - """Extract error diagnostics from a pyright JSON report. +def _ty_config() -> str: + """Build the ``ty.toml`` the isolated checks run under. + + ``--config-file`` replaces every discovered config, so the root project's rule + severities are copied over to keep the isolated runs comparable to the repo-wide + check. The interpreter comes from ``--python``, so no environment is declared. + + Returns: + The ``ty.toml`` contents. + """ + rules = _load_pyproject(REPO_ROOT / "pyproject.toml")["tool"]["ty"]["rules"] + body = "".join(f'{rule} = "{level}"\n' for rule, level in rules.items()) + return f"[rules]\n{body}" + + +_TY_DIAGNOSTIC = re.compile( + r"^(?P.+?):(?P\d+):(?P\d+): " + r"(?P\w+)\[(?P[\w-]+)\] (?P.*)$" +) + + +def _ty_errors(output: str) -> dict[tuple[str, int, int, str], str]: + """Extract error diagnostics from ty's concise output. Args: - report: The parsed ``--outputjson`` document. + output: The captured ``--output-format concise`` text. Returns: - A mapping from a stable diagnostic key (file, line, character, message) to a + A mapping from a stable diagnostic key (file, line, column, message) to a formatted, human-readable display line. """ errors: dict[tuple[str, int, int, str], str] = {} - for diagnostic in report.get("generalDiagnostics", []): - if diagnostic.get("severity") != "error": - continue - start = diagnostic.get("range", {}).get("start", {}) - if "line" not in start or "character" not in start: + for line in output.splitlines(): + match = _TY_DIAGNOSTIC.match(line) + if match is None or match["severity"] != "error": continue - key = ( - diagnostic["file"], - start["line"], - start["character"], - diagnostic["message"], - ) + message = f"[{match['rule']}] {match['message']}" + key = (match["file"], int(match["line"]), int(match["column"]), message) errors[key] = ( - f"{diagnostic['file']}:{start['line'] + 1}:{start['character'] + 1}" - f" - error: {diagnostic['message']}" + f"{match['file']}:{match['line']}:{match['column']} - error: {message}" ) return errors @@ -558,7 +573,7 @@ def build_wheelhouse( This runs to completion before any package is checked, and never alongside one. The pyi build hook deletes the stubs in a sibling's *own* source tree and regenerates them, so a - build overlapping a pyright run over that same tree is read mid-rewrite: an import + build overlapping a ty run over that same tree is read mid-rewrite: an import resolves into a stub that has just been removed, or is not yet written, and the delta reports errors that belong to neither resolution. Building everything up front also builds each sibling once per run rather than once per package that declares it. @@ -713,13 +728,13 @@ def _resolve_and_check( pins: Sequence[str], lowest: bool, ) -> tuple[dict[tuple[str, int, int, str], str] | None, str]: - """Install a package into an isolated venv and run pyright against its source. + """Install a package into an isolated venv and run ty against its source. Args: package: The package to install and check. python_version: The interpreter version for the venv. venv: Directory in which to create the virtualenv. - config: Path to the pyright options config. + config: Path to the ty options config. wheelhouse: Local index holding wheels built from the package's workspace siblings, or ``None`` when the package declares none. pins: Extra ``name==version`` requirements to install alongside the package (see @@ -729,9 +744,9 @@ def _resolve_and_check( lowest: Whether to pin direct dependencies to their declared minimums. Returns: - A ``(errors, detail)`` tuple. ``errors`` is the pyright error map, or ``None`` if - the environment could not be built or pyright produced no parseable output, in - which case ``detail`` carries the captured output. + A ``(errors, detail)`` tuple. ``errors`` is the ty error map, or ``None`` if the + environment could not be built or ty failed outright, in which case ``detail`` + carries the captured output. """ venv_proc = _run(["uv", "venv", "--python", python_version, str(venv)]) if venv_proc.returncode != 0: @@ -771,23 +786,24 @@ def _resolve_and_check( # workspace rather than this isolated environment, so checking them reports imports that # were never this package's to resolve. Naming the ``.py`` files leaves the diagnostics # byte-identical whether or not stubs happen to be present. - pyright = _run( + ty = _run( [ - "pyright", - "--outputjson", - "--pythonpath", + "ty", + "check", + "--python", venv_python, - "--project", + "--config-file", str(config), + "--output-format", + "concise", + "--exit-zero", *sorted(str(module) for module in package.source_dir.rglob("*.py")), ], cwd=REPO_ROOT, ) - try: - report = json.loads(pyright.stdout) - except json.JSONDecodeError: - return None, pyright.stdout or "(pyright produced no output)" - return _pyright_errors(report), "" + if ty.returncode != 0: + return None, ty.stdout or "(ty produced no output)" + return _ty_errors(ty.stdout), "" def check_package( @@ -799,9 +815,9 @@ def check_package( """Check that a package type-checks no worse at its declared minimums than at latest. Installs the package twice in isolated environments — once with dependencies at their - latest compatible versions, once pinned to their declared minimums — and compares - pyright errors. Errors present only at the minimum versions indicate the code depends - on a newer dependency than its declared lower bound allows. + latest compatible versions, once pinned to their declared minimums — and compares ty + errors. Errors present only at the minimum versions indicate the code depends on a + newer dependency than its declared lower bound allows. Args: package: The package to validate. @@ -815,8 +831,8 @@ def check_package( """ with tempfile.TemporaryDirectory(prefix=f"min-deps-{package.name}-") as tmp: tmp_path = Path(tmp) - config = tmp_path / "pyrightconfig.json" - config.write_text(json.dumps({"reportIncompatibleMethodOverride": False})) + config = tmp_path / "ty.toml" + config.write_text(_ty_config()) latest_pins, minimum_pins = ( _workspace_pins(package, versions) if package.local_sources else ([], []) diff --git a/tests/benchmarks/support/redis.py b/tests/benchmarks/support/redis.py index 3d0b0f93947..1775edc04e8 100644 --- a/tests/benchmarks/support/redis.py +++ b/tests/benchmarks/support/redis.py @@ -53,7 +53,7 @@ async def real_redis_state_manager() -> AsyncIterator[StateManagerRedis]: url = performance_redis_url() redis = Redis.from_url(url) try: - await redis.ping() # pyright: ignore [reportGeneralTypeIssues] + await redis.ping() # ty:ignore[invalid-await] if await redis.dbsize(): msg = ( f"Redis database at {url!r} is not empty; performance tests " diff --git a/tests/benchmarks/support/states.py b/tests/benchmarks/support/states.py index 1e637b971b7..fea1dfa8a09 100644 --- a/tests/benchmarks/support/states.py +++ b/tests/benchmarks/support/states.py @@ -82,7 +82,7 @@ def initialized_state(size: int) -> PerformanceState: Initialized performance state. """ state = PerformanceState( - _reflex_internal_init=True # pyright: ignore [reportCallIssue] + _reflex_internal_init=True # ty:ignore[unknown-argument] ) state.numbers = list(range(size)) state.mapping = {f"key_{index}": index for index in range(size)} diff --git a/tests/benchmarks/test_event_processing.py b/tests/benchmarks/test_event_processing.py index 46ec2c943a2..c3631d130e2 100644 --- a/tests/benchmarks/test_event_processing.py +++ b/tests/benchmarks/test_event_processing.py @@ -93,7 +93,7 @@ async def run_events(tokens: Sequence[str]) -> None: emitted_deltas.clear() async with processor as p: - async for _ in asyncio.as_completed([ + async for _ in asyncio.as_completed([ # ty:ignore[not-iterable] await p.enqueue(token, event) for token in tokens ]): pass @@ -344,7 +344,7 @@ async def run_events() -> None: async with processor as p: async for _ in asyncio.as_completed([ await p.enqueue("benchmark-token", event) for event in events - ]): + ]): # ty:ignore[not-iterable] pass assert emitted == len(events) @@ -418,7 +418,7 @@ async def test_table_event_deltas(): assert delta["status" + FIELD_MARKER] == status assert delta["sort_reverse" + FIELD_MARKER] == reverse assert delta["filtered_orders" + FIELD_MARKER] == expected - assert delta["total_amount" + FIELD_MARKER] == sum( + assert delta["total_amount" + FIELD_MARKER] == sum( # ty:ignore[no-matching-overload] row["amount"] for row in expected ) diff --git a/tests/benchmarks/test_routes.py b/tests/benchmarks/test_routes.py index 15d0fa2e07e..5f175864967 100644 --- a/tests/benchmarks/test_routes.py +++ b/tests/benchmarks/test_routes.py @@ -29,7 +29,7 @@ def cached_rxconfig() -> Iterator[None]: module_name = constants.Config.MODULE saved = sys.modules.get(module_name) stub = types.ModuleType(module_name) - stub.config = get_config() # pyright: ignore [reportAttributeAccessIssue] + stub.config = get_config() # ty:ignore[unresolved-attribute] sys.modules[module_name] = stub try: yield diff --git a/tests/benchmarks/test_state_manager.py b/tests/benchmarks/test_state_manager.py index d58f6c73f84..ca121f738dc 100644 --- a/tests/benchmarks/test_state_manager.py +++ b/tests/benchmarks/test_state_manager.py @@ -298,8 +298,8 @@ def _touch(state: BaseState) -> None: Args: state: The root state to dirty. """ - state.counter += 1 # pyright: ignore[reportAttributeAccessIssue] - state.substates[DATA_SUBSTATE_NAME].revision += 1 # pyright: ignore[reportAttributeAccessIssue] + state.counter += 1 # ty:ignore[unresolved-attribute] + state.substates[DATA_SUBSTATE_NAME].revision += 1 # ty:ignore[unresolved-attribute] async def _get_state(manager: StateManager) -> None: diff --git a/tests/benchmarks/test_state_proxy.py b/tests/benchmarks/test_state_proxy.py index 00c7482bd88..c1b401890dd 100644 --- a/tests/benchmarks/test_state_proxy.py +++ b/tests/benchmarks/test_state_proxy.py @@ -91,7 +91,7 @@ def test_var_access(access_fn, benchmark: BenchmarkFixture): access_fn: The parametrized var-access routine. benchmark: The codspeed benchmark fixture. """ - state = ProxyBenchmarkState() # pyright: ignore [reportCallIssue] + state = ProxyBenchmarkState() benchmark(lambda: access_fn(state)) diff --git a/tests/integration/test_background_task.py b/tests/integration/test_background_task.py index 283dbe4cd12..792e6892e46 100644 --- a/tests/integration/test_background_task.py +++ b/tests/integration/test_background_task.py @@ -334,9 +334,7 @@ def test_background_task( AppHarness.expect(lambda: counter.text == "620", timeout=40) AppHarness.expect(lambda: counter_async_cv.text == "620", timeout=40) # all tasks should have exited and cleaned up - AppHarness.expect( - lambda: not background_task.app_instance.event_processor._tasks # pyright: ignore [reportOptionalMemberAccess] - ) + AppHarness.expect(lambda: not background_task.app_instance.event_processor._tasks) # ty:ignore[unresolved-attribute] def test_nested_async_with_self( diff --git a/tests/integration/test_call_script.py b/tests/integration/test_call_script.py index f7643202f35..4681b00356c 100644 --- a/tests/integration/test_call_script.py +++ b/tests/integration/test_call_script.py @@ -92,7 +92,7 @@ def call_script_inline_return_callback(self): def call_script_inline_return_lambda(self): return rx.call_script( "inline2()", - callback=lambda result: CallScriptState.call_script_callback_other_arg( + callback=lambda result: CallScriptState.call_script_callback_other_arg( # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 result, "lambda" ), ) @@ -140,7 +140,7 @@ def call_script_external_return_callback(self): def call_script_external_return_lambda(self): return rx.call_script( "external2()", - callback=lambda result: CallScriptState.call_script_callback_other_arg( + callback=lambda result: CallScriptState.call_script_callback_other_arg( # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 result, "lambda" ), ) diff --git a/tests/integration/test_component_state.py b/tests/integration/test_component_state.py index 1190b47a15a..36eaa466547 100644 --- a/tests/integration/test_component_state.py +++ b/tests/integration/test_component_state.py @@ -32,7 +32,7 @@ def increment(self): """Increment this component's counter and update its label.""" self.count += 1 self.label = f"Count {self.count}" - self._be = self.count # pyright: ignore [reportAttributeAccessIssue] + self._be = self.count # ty:ignore[invalid-assignment] @rx.event def reset_counter(self): @@ -41,19 +41,19 @@ def reset_counter(self): @rx.event def assert_be(self, value: E): - assert self._be == int(value) # pyright: ignore [reportAttributeAccessIssue, reportArgumentType] + assert self._be == int(value) # ty:ignore[invalid-argument-type] @rx.event def assert_be_none(self): - assert self._be is None # pyright: ignore [reportAttributeAccessIssue] + assert self._be is None @rx.event def assert_be_int(self, value: int): - assert self._be_int == value # pyright: ignore [reportAttributeAccessIssue] + assert self._be_int == value @rx.event def assert_be_str(self, value: str): - assert self._be_str == value # pyright: ignore [reportAttributeAccessIssue] + assert self._be_str == value @classmethod def get_component(cls, *children, **props): @@ -85,7 +85,7 @@ def get_component(cls, *children, **props): "Assert _be", id=f"{eid}-assert-be", ), - on_submit=lambda fd: cls.assert_be(fd.to(dict)["be_value"]), # pyright: ignore [reportAttributeAccessIssue] + on_submit=lambda fd: cls.assert_be(fd.to(dict)["be_value"]), # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 reset_on_submit=True, ), rx.button( @@ -159,7 +159,7 @@ def index(): configured, rx.button( "Inc A", - on_click=mc_a.State.increment, # pyright: ignore [reportAttributeAccessIssue, reportOptionalMemberAccess] + on_click=mc_a.State.increment, # ty:ignore[unresolved-attribute] id="inc-a", ), rx.text( diff --git a/tests/integration/test_dynamic_components.py b/tests/integration/test_dynamic_components.py index acbee4cc3d5..05e80f1905c 100644 --- a/tests/integration/test_dynamic_components.py +++ b/tests/integration/test_dynamic_components.py @@ -10,8 +10,6 @@ from reflex.testing import AppHarness -# pyright: reportOptionalMemberAccess=false, reportGeneralTypeIssues=false, reportUnknownMemberType=false - def DynamicComponents(): """App with var operations.""" diff --git a/tests/integration/test_dynamic_routes.py b/tests/integration/test_dynamic_routes.py index e2630345bb3..3429fc65f07 100644 --- a/tests/integration/test_dynamic_routes.py +++ b/tests/integration/test_dynamic_routes.py @@ -24,7 +24,7 @@ class DynamicState(rx.State): @rx.event def on_load(self): - page_data = f"{self.router.page.path}-{self.page_id or 'no page id'}" # pyright: ignore[reportAttributeAccessIssue] + page_data = f"{self.router.page.path}-{self.page_id or 'no page id'}" # ty:ignore[unresolved-attribute] print(f"on_load: {page_data}") self.order.append(page_data) @@ -44,7 +44,7 @@ def on_load_static(self): @rx.var def next_page(self) -> str: try: - return str(int(self.page_id) + 1) # pyright: ignore[reportAttributeAccessIssue] + return str(int(self.page_id) + 1) # ty:ignore[unresolved-attribute] except ValueError: return "0" @@ -59,7 +59,7 @@ def index(): read_only=True, id="token", ), - rx.input(value=rx.State.page_id, read_only=True, id="page_id"), # pyright: ignore [reportAttributeAccessIssue] + rx.input(value=rx.State.page_id, read_only=True, id="page_id"), # ty:ignore[unresolved-attribute] rx.input( value=DynamicState.router.page.raw_path, read_only=True, @@ -75,7 +75,7 @@ def index(): rx.link("missing", href="/missing", id="link_missing"), rx.vstack( rx.foreach( - DynamicState.order, # pyright: ignore [reportAttributeAccessIssue] + DynamicState.order, rx.text, ), id="event_order", @@ -88,7 +88,7 @@ class ArgState(rx.State): @rx.var(cache=False) def arg(self) -> int: - return int(self.arg_str or 0) # pyright: ignore[reportAttributeAccessIssue] + return int(self.arg_str or 0) # ty:ignore[unresolved-attribute] class ArgSubState(ArgState): @rx.var @@ -97,7 +97,7 @@ def cached_arg(self) -> int: @rx.var def cached_arg_str(self) -> str: - return self.arg_str # pyright: ignore[reportAttributeAccessIssue] + return self.arg_str # ty:ignore[unresolved-attribute] @rx.page(route="/arg/[arg_str]") def arg() -> rx.Component: @@ -110,11 +110,11 @@ def arg() -> rx.Component: rx.data_list.root( rx.data_list.item( rx.data_list.label("rx.State.arg_str (dynamic)"), - rx.data_list.value(rx.State.arg_str, id="state-arg_str"), # pyright: ignore [reportAttributeAccessIssue] + rx.data_list.value(rx.State.arg_str, id="state-arg_str"), # ty:ignore[unresolved-attribute] ), rx.data_list.item( rx.data_list.label("ArgState.arg_str (dynamic) (inherited)"), - rx.data_list.value(ArgState.arg_str, id="argstate-arg_str"), # pyright: ignore [reportAttributeAccessIssue] + rx.data_list.value(ArgState.arg_str, id="argstate-arg_str"), # ty:ignore[unresolved-attribute] ), rx.data_list.item( rx.data_list.label("ArgState.arg"), @@ -122,7 +122,7 @@ def arg() -> rx.Component: ), rx.data_list.item( rx.data_list.label("ArgSubState.arg_str (dynamic) (inherited)"), - rx.data_list.value(ArgSubState.arg_str, id="argsubstate-arg_str"), # pyright: ignore [reportAttributeAccessIssue] + rx.data_list.value(ArgSubState.arg_str, id="argsubstate-arg_str"), # ty:ignore[unresolved-attribute] ), rx.data_list.item( rx.data_list.label("ArgSubState.arg (inherited)"), diff --git a/tests/integration/test_event_actions.py b/tests/integration/test_event_actions.py index f253c306fd1..d219ea9e832 100644 --- a/tests/integration/test_event_actions.py +++ b/tests/integration/test_event_actions.py @@ -25,16 +25,19 @@ def TestEventAction(): class EventActionState(rx.State): order: list[str] - def on_click(self, ev): + @rx.event + def on_click(self, ev: str): self.order.append(f"on_click:{ev}") @rx.event def on_click2(self): self.order.append("on_click2") + @rx.event def on_click_throttle(self): self.order.append("on_click_throttle") + @rx.event def on_click_debounce(self): self.order.append("on_click_debounce") @@ -76,12 +79,12 @@ def index(): ), rx.button( "Click event", - on_click=EventActionState.on_click("no_event_actions"), # pyright: ignore [reportCallIssue] + on_click=EventActionState.on_click("no_event_actions"), id="btn-click-event", ), rx.button( "Click stop propagation", - on_click=EventActionState.on_click("stop_propagation").stop_propagation, # pyright: ignore [reportCallIssue] + on_click=EventActionState.on_click("stop_propagation").stop_propagation, id="btn-click-stop-propagation", ), rx.button( @@ -97,13 +100,13 @@ def index(): rx.link( "Link", href="?link", - on_click=EventActionState.on_click("link_no_event_actions"), # pyright: ignore [reportCallIssue] + on_click=EventActionState.on_click("link_no_event_actions"), id="link", ), rx.link( "Link Stop Propagation", href="?link-stop-propagation", - on_click=EventActionState.on_click( # pyright: ignore [reportCallIssue] + on_click=EventActionState.on_click( "link_stop_propagation" ).stop_propagation, id="link-stop-propagation", @@ -117,7 +120,7 @@ def index(): rx.link( "Link Prevent Default", href="/invalid", - on_click=EventActionState.on_click( # pyright: ignore [reportCallIssue] + on_click=EventActionState.on_click( "link_prevent_default" ).prevent_default, id="link-prevent-default", @@ -125,36 +128,34 @@ def index(): rx.link( "Link Both", href="/invalid", - on_click=EventActionState.on_click( # pyright: ignore [reportCallIssue] + on_click=EventActionState.on_click( "link_both" ).stop_propagation.prevent_default, id="link-stop-propagation-prevent-default", ), EventFiringComponent.create( id="custom-stop-propagation", - on_click=EventActionState.on_click( # pyright: ignore [reportCallIssue] + on_click=EventActionState.on_click( "custom-stop-propagation" ).stop_propagation, ), EventFiringComponent.create( id="custom-prevent-default", - on_click=EventActionState.on_click( # pyright: ignore [reportCallIssue] + on_click=EventActionState.on_click( "custom-prevent-default" ).prevent_default, ), rx.button( "Throttle", id="btn-throttle", - on_click=lambda: ( - EventActionState.on_click_throttle.throttle( # pyright: ignore [reportFunctionMemberAccess] - 200 - ).stop_propagation + on_click=lambda: ( # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 + EventActionState.on_click_throttle.throttle(200).stop_propagation ), ), rx.button( "Debounce", id="btn-debounce", - on_click=EventActionState.on_click_debounce.debounce( # pyright: ignore [reportFunctionMemberAccess] + on_click=EventActionState.on_click_debounce.debounce( 200 ).stop_propagation, ), @@ -165,7 +166,7 @@ def index(): ), id="event_order", ), - on_click=EventActionState.on_click("outer"), # pyright: ignore [reportCallIssue] + on_click=EventActionState.on_click("outer"), ), rx.form( rx.dialog.root( rx.dialog.trigger( @@ -176,12 +177,12 @@ def index(): rx.dialog.close( rx.form( rx.button("Submit", id="btn-submit"), - on_submit=EventActionState.on_submit.stop_propagation, # pyright: ignore [reportCallIssue] + on_submit=EventActionState.on_submit.stop_propagation, ), ), ), ), - on_submit=EventActionState.on_submit, # pyright: ignore [reportCallIssue] + on_submit=EventActionState.on_submit, ) app = rx.App() @@ -361,8 +362,8 @@ def test_event_actions_dialog_form_in_form( driver.find_element(By.ID, open_dialog_id).click() el = wait.until(EC.element_to_be_clickable((By.ID, submit_button_id))) - el.click() # pyright: ignore[reportAttributeAccessIssue] - el.send_keys(Keys.ESCAPE) # pyright: ignore[reportAttributeAccessIssue] + el.click() + el.send_keys(Keys.ESCAPE) btn_no_events = wait.until(EC.element_to_be_clickable((By.ID, "btn-no-events"))) btn_no_events.location_once_scrolled_into_view diff --git a/tests/integration/test_event_chain.py b/tests/integration/test_event_chain.py index 2059095bf6d..0faf40d6f00 100644 --- a/tests/integration/test_event_chain.py +++ b/tests/integration/test_event_chain.py @@ -217,12 +217,12 @@ def index(): rx.button( "Click Int Type", id="click_int_type", - on_click=lambda: State.event_arg_repr_type(1), + on_click=lambda: State.event_arg_repr_type(1), # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 ), rx.button( "Click Dict Type", id="click_dict_type", - on_click=lambda: State.event_arg_repr_type({"a": 1}), + on_click=lambda: State.event_arg_repr_type({"a": 1}), # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 ), rx.button( "Return Chain Int Type", @@ -257,7 +257,7 @@ def index(): rx.button( "Mixed Cond", id="mixed_cond_btn", - on_click=lambda: rx.cond( + on_click=lambda: rx.cond( # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 State.cond_input == "fn", mark_dom_fn.partial("fn_branch"), State.event_arg("ev_branch"), @@ -282,7 +282,7 @@ def on_mount_return_chain(): rx.text( "return", on_mount=State.on_load_return_chain, - on_unmount=lambda: State.event_arg("unmount"), + on_unmount=lambda: State.event_arg("unmount"), # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 ), common_elements, rx.button("Unmount", on_click=rx.redirect("/"), id="unmount"), @@ -292,7 +292,7 @@ def on_mount_yield_chain(): return rx.fragment( rx.text( "yield", - on_mount=[ + on_mount=[ # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 State.on_load_yield_chain, lambda: State.event_arg("mount"), ], diff --git a/tests/integration/test_exception_handlers.py b/tests/integration/test_exception_handlers.py index cfc586a445f..06b2ce9d4bc 100644 --- a/tests/integration/test_exception_handlers.py +++ b/tests/integration/test_exception_handlers.py @@ -32,6 +32,7 @@ class TestAppState(rx.State): def set_react_error(self, value: bool): self.react_error = value + @rx.event def divide_by_number(self, number: int): """Divide by number and print the result. @@ -53,7 +54,7 @@ def index(): ), rx.button( "induce_backend_error", - on_click=lambda: TestAppState.divide_by_number(0), # pyright: ignore [reportCallIssue] + on_click=lambda: TestAppState.divide_by_number(0), # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 id="induce-backend-error-btn", ), rx.button( diff --git a/tests/integration/test_form_submit.py b/tests/integration/test_form_submit.py index 261cfbb7389..40369844943 100644 --- a/tests/integration/test_form_submit.py +++ b/tests/integration/test_form_submit.py @@ -78,7 +78,7 @@ def index(): rx.input( id="debounce_input", debounce_timeout=0, - on_change=rx.console_log, + on_change=rx.console_log, # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 ), rx.button("Submit", type_="submit"), id=form_content_wrapper_id, @@ -159,7 +159,7 @@ def index(): rx.input( name="debounce_input", debounce_timeout=0, - on_change=rx.console_log, + on_change=rx.console_log, # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 ), rx.button("Submit", type_="submit"), rx.icon_button(rx.icon(tag="plus")), diff --git a/tests/integration/test_lifespan.py b/tests/integration/test_lifespan.py index 6adac44175c..6fefced8047 100644 --- a/tests/integration/test_lifespan.py +++ b/tests/integration/test_lifespan.py @@ -37,9 +37,9 @@ def LifespanApp( @asynccontextmanager async def lifespan_context(app, inc: int = 1): - global lifespan_context_global + global lifespan_context_global # ty:ignore[unresolved-global] print(f"Lifespan context entered: {app}.") - lifespan_context_global += inc # pyright: ignore[reportUnboundVariable] + lifespan_context_global += inc try: yield finally: @@ -47,22 +47,22 @@ async def lifespan_context(app, inc: int = 1): lifespan_context_global += inc async def lifespan_task(inc: int = 1): - global lifespan_task_global + global lifespan_task_global # ty:ignore[unresolved-global] print("Lifespan global started.") try: while True: - lifespan_task_global += inc # pyright: ignore[reportUnboundVariable, reportPossiblyUnboundVariable] + lifespan_task_global += inc await asyncio.sleep(0.1) except asyncio.CancelledError as ce: print(f"Lifespan global cancelled: {ce}.") lifespan_task_global = 0 async def raw_asyncio_task_coro(): - global raw_asyncio_task_global + global raw_asyncio_task_global # ty:ignore[unresolved-global] print("Raw asyncio task started.") try: while True: - raw_asyncio_task_global += 1 # pyright: ignore[reportUnboundVariable, reportPossiblyUnboundVariable] + raw_asyncio_task_global += 1 await asyncio.sleep(0.1) except asyncio.CancelledError as ce: print(f"Raw asyncio task cancelled: {ce}.") diff --git a/tests/integration/test_linked_state.py b/tests/integration/test_linked_state.py index 6670b18df16..0520cab5db0 100644 --- a/tests/integration/test_linked_state.py +++ b/tests/integration/test_linked_state.py @@ -62,9 +62,9 @@ def clear_event_link_status(self): @rx.event async def on_load_link_default(self): - linked_state = await self._link_to(self.room or "default") # pyright: ignore[reportAttributeAccessIssue] - if self.room: # pyright: ignore[reportAttributeAccessIssue] - assert linked_state._linked_to == self.room # pyright: ignore[reportAttributeAccessIssue] + linked_state = await self._link_to(self.room or "default") # ty:ignore[unresolved-attribute] + if self.room: # ty:ignore[unresolved-attribute] + assert linked_state._linked_to == self.room # ty:ignore[unresolved-attribute] else: assert linked_state._linked_to == "default" @@ -82,7 +82,7 @@ class SharedNotes(rx.SharedState): @rx.event async def on_load_link_default(self): - linked_state = await self._link_to(self.room or "default") # pyright: ignore[reportAttributeAccessIssue] + linked_state = await self._link_to(self.room or "default") # ty:ignore[unresolved-attribute] initial_note = self.router.page.params.get("initial_note", "") if initial_note: linked_state.note = initial_note diff --git a/tests/integration/test_login_flow.py b/tests/integration/test_login_flow.py index 306ba0b28b2..d510dfd1611 100644 --- a/tests/integration/test_login_flow.py +++ b/tests/integration/test_login_flow.py @@ -36,8 +36,8 @@ def login(self): yield rx.redirect("/") def index(): - return rx.cond( # pyright: ignore [reportCallIssue] - State.is_hydrated & State.auth_token, # pyright: ignore [reportOperatorIssue] + return rx.cond( + State.is_hydrated & State.auth_token, # ty:ignore[unsupported-operator] rx.vstack( rx.heading(State.auth_token, id="auth-token"), rx.button("Logout", on_click=State.logout, id="logout"), diff --git a/tests/integration/test_telemetry_compile.py b/tests/integration/test_telemetry_compile.py index fd4069f9572..a669eb304aa 100644 --- a/tests/integration/test_telemetry_compile.py +++ b/tests/integration/test_telemetry_compile.py @@ -35,6 +35,7 @@ def TelemetryCompileApp(events_log_path: str = ""): import json import os from pathlib import Path + from typing import Any import reflex as rx from reflex.istate.storage import Cookie, LocalStorage, SessionStorage @@ -49,14 +50,20 @@ def TelemetryCompileApp(events_log_path: str = ""): sink = Path(events_log_path) sink.parent.mkdir(parents=True, exist_ok=True) - def _capture(event, properties=None, **_kwargs): + def _capture( + event: str, + telemetry_enabled: bool | None = None, + *, + properties: dict[str, Any] | None = None, + **_kwargs: Any, + ) -> bool: with sink.open("a") as fh: fh.write( json.dumps({"event": event, "properties": properties or {}}) + "\n" ) return True - telemetry.send = _capture + telemetry.send = _capture # ty:ignore[invalid-assignment] class StorageRoot(rx.State): token: str = Cookie() diff --git a/tests/integration/test_upload.py b/tests/integration/test_upload.py index 4c64761e82e..e0795b7685a 100644 --- a/tests/integration/test_upload.py +++ b/tests/integration/test_upload.py @@ -175,7 +175,7 @@ def index(): ), rx.button( "Upload", - on_click=lambda: UploadState.handle_upload(rx.upload_files()), # pyright: ignore [reportArgumentType] + on_click=lambda: UploadState.handle_upload(rx.upload_files()), # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/2870 https://github.com/astral-sh/ty/issues/4098 id="upload_button", ), rx.box( @@ -201,7 +201,7 @@ def index(): rx.button( "Upload", on_click=UploadState.handle_upload_secondary( - rx.upload_files( # pyright: ignore [reportArgumentType] + rx.upload_files( upload_id="secondary", on_upload_progress=UploadState.upload_progress, ), @@ -243,7 +243,7 @@ def index(): rx.button( "Upload", on_click=UploadState.handle_upload_tertiary( - rx.upload_files( # pyright: ignore [reportArgumentType] + rx.upload_files( upload_id="tertiary", ), ), @@ -264,8 +264,8 @@ def index(): rx.button("Select File"), rx.text("Drag and drop files here or click to select files"), ), - on_drop=UploadState.handle_upload_quaternary( - rx.upload_files( # pyright: ignore [reportArgumentType] + on_drop=UploadState.handle_upload_quaternary( # ty:ignore[no-matching-overload] + rx.upload_files( upload_id="quaternary", ), "resume-field", @@ -291,8 +291,8 @@ def index(): ), rx.button( "Upload", - on_click=UploadState.handle_upload_stream( - rx.upload_files_chunk( # pyright: ignore [reportArgumentType] + on_click=UploadState.handle_upload_stream( # ty:ignore[no-matching-overload] + rx.upload_files_chunk( upload_id="streaming", on_upload_progress=UploadState.stream_upload_progress, ), diff --git a/tests/integration/test_var_operations.py b/tests/integration/test_var_operations.py index 987b0902c1d..c8cd538838c 100644 --- a/tests/integration/test_var_operations.py +++ b/tests/integration/test_var_operations.py @@ -607,7 +607,7 @@ def index(): id="list_map", ), rx.text( - ArrayVar.range(1, 5).foreach(lambda x: x * 2).to_string(), + ArrayVar.range(1, 5).foreach(lambda x: x * 2).to_string(), # ty:ignore[deprecated] id="list_foreach_alias", ), rx.text( diff --git a/tests/integration/tests_playwright/test_appearance.py b/tests/integration/tests_playwright/test_appearance.py index 2e92b1ba69a..6ef38ca7f57 100644 --- a/tests/integration/tests_playwright/test_appearance.py +++ b/tests/integration/tests_playwright/test_appearance.py @@ -65,7 +65,7 @@ def index(): rx.icon(tag="moon", size=20), value="dark", ), - on_change=set_color_mode, # pyright: ignore[reportArgumentType] + on_change=set_color_mode, # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 variant="classic", radius="large", value=color_mode, diff --git a/tests/integration/tests_playwright/test_datetime_operations.py b/tests/integration/tests_playwright/test_datetime_operations.py index 4f79ed8698a..3c2d413d0fb 100644 --- a/tests/integration/tests_playwright/test_datetime_operations.py +++ b/tests/integration/tests_playwright/test_datetime_operations.py @@ -91,19 +91,19 @@ def index(): rx.text(DtOperationsState.unset1 == DtOperationsState.date1, id="u1_eq_1"), rx.text(DtOperationsState.unset1 != DtOperationsState.date1, id="u1_neq_1"), rx.text( - DtOperationsState.unset1 < DtOperationsState.date1, # pyright: ignore[reportOptionalOperand] + DtOperationsState.unset1 < DtOperationsState.date1, # ty:ignore[unsupported-operator] id="u1_lt_1", ), rx.text( - DtOperationsState.unset1 <= DtOperationsState.date1, # pyright: ignore[reportOptionalOperand] + DtOperationsState.unset1 <= DtOperationsState.date1, # ty:ignore[unsupported-operator] id="u1_le_1", ), rx.text( - DtOperationsState.unset1 > DtOperationsState.date1, # pyright: ignore[reportOptionalOperand] + DtOperationsState.unset1 > DtOperationsState.date1, # ty:ignore[unsupported-operator] id="u1_gt_1", ), rx.text( - DtOperationsState.unset1 >= DtOperationsState.date1, # pyright: ignore[reportOptionalOperand] + DtOperationsState.unset1 >= DtOperationsState.date1, # ty:ignore[unsupported-operator] id="u1_ge_1", ), rx.text( diff --git a/tests/integration/tests_playwright/test_frontend_path.py b/tests/integration/tests_playwright/test_frontend_path.py index d9709d84653..2b477361125 100644 --- a/tests/integration/tests_playwright/test_frontend_path.py +++ b/tests/integration/tests_playwright/test_frontend_path.py @@ -42,7 +42,7 @@ def on_load_static(self): @rx.event def on_load_dynamic(self): - page_id = self.page_id # pyright: ignore[reportAttributeAccessIssue] + page_id = self.page_id # ty:ignore[unresolved-attribute] self.on_load_events.append(f"dynamic-{page_id}") @rx.event @@ -121,7 +121,7 @@ def _router_info(): id="router-url-path", ), rx.input( - value=FPState.router.page.raw_path, # pyright: ignore[reportDeprecated] + value=FPState.router.page.raw_path, read_only=True, id="router-page-raw-path", ), @@ -202,7 +202,7 @@ def static_page(): @rx.page("/dynamic/[page_id]", on_load=FPState.on_load_dynamic) def dynamic_page(): return rx.box( - rx.text(f"dynamic page {rx.State.page_id}", id="page-id"), # pyright: ignore[reportAttributeAccessIssue] + rx.text(f"dynamic page {rx.State.page_id}", id="page-id"), # ty:ignore[unresolved-attribute] rx.input( value=FPState.router.session.client_token, read_only=True, diff --git a/tests/integration/tests_playwright/test_unicode_string_operations.py b/tests/integration/tests_playwright/test_unicode_string_operations.py index d48d651d336..ca43ce4e23b 100644 --- a/tests/integration/tests_playwright/test_unicode_string_operations.py +++ b/tests/integration/tests_playwright/test_unicode_string_operations.py @@ -23,20 +23,20 @@ class UnicodeState(rx.State): def index(): return rx.vstack( rx.text( - UnicodeState.value.length(), # pyright: ignore[reportAttributeAccessIssue] + UnicodeState.value.length(), # ty:ignore[unresolved-attribute] id="length", ), rx.text(UnicodeState.value[::-1], id="reverse"), rx.text(UnicodeState.value[1], id="character"), rx.text(UnicodeState.value[1:], id="slice"), rx.text( - UnicodeState.plain.length(), # pyright: ignore[reportAttributeAccessIssue] + UnicodeState.plain.length(), # ty:ignore[unresolved-attribute] id="plain-length", ), rx.text(UnicodeState.plain[1:3], id="plain-slice"), rx.text(UnicodeState.plain[-1], id="plain-character"), rx.text( - UnicodeState.missing.length(), # pyright: ignore[reportAttributeAccessIssue, reportOptionalMemberAccess] + UnicodeState.missing.length(), # ty:ignore[unresolved-attribute] id="missing-length", ), ) diff --git a/tests/performance/test_event_loop.py b/tests/performance/test_event_loop.py index fe121a88203..62e417fe926 100644 --- a/tests/performance/test_event_loop.py +++ b/tests/performance/test_event_loop.py @@ -142,7 +142,7 @@ def blocking(self): async def thread_offload(self): """Move CPU work off the event-loop thread.""" _record_state_stage("handler_started") - self.value += await asyncio.to_thread(sum, range(100_000)) + self.value += await asyncio.to_thread(sum, range(100_000)) # ty:ignore[unsupported-operator] _record_state_stage("handler_finished") _record_state_stage("delta_started") diff --git a/tests/type_checking/fields.py b/tests/type_checking/fields.py index c9869a05a7b..9005e0ee91f 100644 --- a/tests/type_checking/fields.py +++ b/tests/type_checking/fields.py @@ -4,6 +4,7 @@ from dataclasses import MISSING from typing import assert_type +import pydantic from reflex_base.components.field import BaseField from reflex_base.utils.compat import MISSING_TYPE from reflex_base.vars.base import Field, field @@ -41,11 +42,17 @@ class _Data: value: int +class _Pydantic(pydantic.BaseModel): + value: int = 0 + + class _ObjectFieldState(State): model: Field[_Model] = field(default_factory=lambda: _Model(id=0)) optional_model: Field[_Model | None] = field(default=None) data: Field[_Data] = field(default_factory=lambda: _Data(value=0)) optional_data: Field[_Data | None] = field(default=None) + pydantic_model: Field[_Pydantic] = field(default_factory=_Pydantic) + optional_pydantic_model: Field[_Pydantic | None] = field(default=None) mapping: Field[dict[str, int]] = field(default_factory=dict) optional_mapping: Field[dict[str, int] | None] = field(default=None) @@ -57,5 +64,7 @@ class _ObjectFieldState(State): assert_type(_ObjectFieldState.optional_model, ObjectVar[_Model]) assert_type(_ObjectFieldState.data, ObjectVar[_Data]) assert_type(_ObjectFieldState.optional_data, ObjectVar[_Data]) +assert_type(_ObjectFieldState.pydantic_model, ObjectVar[_Pydantic]) +assert_type(_ObjectFieldState.optional_pydantic_model, ObjectVar[_Pydantic]) assert_type(_ObjectFieldState.mapping, ObjectVar[dict[str, int]]) assert_type(_ObjectFieldState.optional_mapping, ObjectVar[dict[str, int]]) diff --git a/tests/units/compiler/test_compiler.py b/tests/units/compiler/test_compiler.py index dc80f257cb8..1fbd1cdad50 100644 --- a/tests/units/compiler/test_compiler.py +++ b/tests/units/compiler/test_compiler.py @@ -23,6 +23,7 @@ from reflex_base.vars.sequence import LiteralStringVar from reflex_components_core.base import Description, document from reflex_components_core.base.document import Links, Scripts +from reflex_components_core.base.fragment import Fragment from reflex_components_core.el.elements.metadata import Head, Link, Meta from reflex_components_core.el.elements.other import Html @@ -818,17 +819,17 @@ def test_create_document_root(): assert isinstance(root, Html) assert isinstance(root.children[0], Head) # Default language. - lang = root.lang # pyright: ignore [reportAttributeAccessIssue] + lang = root.lang # ty:ignore[unresolved-attribute] assert isinstance(lang, LiteralStringVar) assert lang.equals(Var.create("en")) # No children in head. assert len(root.children[0].children) == 6 assert isinstance(root.children[0].children[1], Meta) - char_set = root.children[0].children[1].char_set # pyright: ignore [reportAttributeAccessIssue] + char_set = root.children[0].children[1].char_set # ty:ignore[unresolved-attribute] assert isinstance(char_set, LiteralStringVar) assert char_set.equals(Var.create("utf-8")) assert isinstance(root.children[0].children[2], Meta) - name = root.children[0].children[2].name # pyright: ignore [reportAttributeAccessIssue] + name = root.children[0].children[2].name # ty:ignore[unresolved-attribute] assert isinstance(name, LiteralStringVar) assert name.equals(Var.create("viewport")) assert isinstance(root.children[0].children[3], document.Meta) @@ -853,7 +854,7 @@ class PageState(rx.State): description = page.children[1] assert isinstance(description, Description) - assert description.content is PageState.description # pyright: ignore [reportAttributeAccessIssue] + assert description.content is PageState.description # ty:ignore[unresolved-attribute] def test_add_meta_drops_empty_description(): @@ -895,7 +896,7 @@ def test_create_document_root_with_scripts(): "link", "Links", ] - lang = root.lang # pyright: ignore [reportAttributeAccessIssue] + lang = root.lang # ty:ignore[unresolved-attribute] assert isinstance(lang, LiteralStringVar) assert lang.equals(Var.create("rx")) assert isinstance(root.custom_attrs, dict) @@ -915,7 +916,7 @@ def test_create_document_root_with_meta_char_set(): assert len(root.children[0].children) == 6 names = [c.tag for c in root.children[0].children] assert names == ["script", "meta", "meta", "Meta", "link", "Links"] - assert str(root.children[0].children[1].char_set) == '"cp1252"' # pyright: ignore [reportAttributeAccessIssue] + assert str(root.children[0].children[1].char_set) == '"cp1252"' # ty:ignore[unresolved-attribute] @pytest.mark.usefixtures("dev_mode") @@ -932,10 +933,10 @@ def test_create_document_root_with_meta_viewport(): assert len(root.children[0].children) == 7 names = [c.tag for c in root.children[0].children] assert names == ["script", "meta", "meta", "meta", "Meta", "link", "Links"] - assert str(root.children[0].children[1].http_equiv) == '"refresh"' # pyright: ignore [reportAttributeAccessIssue] - assert str(root.children[0].children[2].name) == '"viewport"' # pyright: ignore [reportAttributeAccessIssue] - assert str(root.children[0].children[2].content) == '"foo"' # pyright: ignore [reportAttributeAccessIssue] - assert str(root.children[0].children[3].char_set) == '"utf-8"' # pyright: ignore [reportAttributeAccessIssue] + assert str(root.children[0].children[1].http_equiv) == '"refresh"' # ty:ignore[unresolved-attribute] + assert str(root.children[0].children[2].name) == '"viewport"' # ty:ignore[unresolved-attribute] + assert str(root.children[0].children[2].content) == '"foo"' # ty:ignore[unresolved-attribute] + assert str(root.children[0].children[3].char_set) == '"utf-8"' # ty:ignore[unresolved-attribute] class _RoutePlugin(rx.plugins.Plugin): @@ -1886,8 +1887,8 @@ def test_compile_app_drops_event_caches_from_earlier_compiles( app = rx.App() app.add_page(lambda: rx.el.div("hello"), route="/") stale = object() - context._bound_event_chains[0, 0, None] = stale # pyright: ignore[reportArgumentType] - context._memoized_event_triggers["on_click", 0] = stale # pyright: ignore[reportArgumentType] + context._bound_event_chains[0, 0, None] = stale # ty:ignore[invalid-assignment] + context._memoized_event_triggers["on_click", 0] = stale # ty:ignore[invalid-assignment] compiler.compile_app(app, dry_run=True, use_rich=False) @@ -1954,3 +1955,50 @@ def test_compile_app_resolves_show_built_with_reflex( assert get_user_tier.called is ( compile_context == constants.CompileContext.DEPLOY and configured is None ) + + +@pytest.mark.parametrize( + ("component", "children"), + [ + ("text", 1), + (Var.create("var"), 1), + ((rx.el.div(), rx.el.span()), 2), + (lambda: "text", 1), + (lambda: (rx.el.div(), rx.el.span()), 2), + ], +) +def test_into_component_wraps_renderables_in_a_fragment(component, children: int): + """Strings, Vars and sequences, returned directly or by a callable, become a Fragment. + + Args: + component: The value to convert. + children: The number of children the Fragment should have. + """ + converted = compiler.into_component(component) + assert isinstance(converted, Fragment) + assert len(converted.children) == children + + +def test_into_component_returns_components_as_is(): + """A Component, or the one a callable returns, is used unchanged.""" + div = rx.el.div() + assert compiler.into_component(div) is div + assert compiler.into_component(lambda: div) is div + + +@pytest.mark.parametrize( + ("component", "message"), + [ + (None, "Expected a Component or callable"), + (lambda: None, "Expected a Component, got None"), + ], +) +def test_into_component_rejects_non_renderables(component, message: str): + """A value that is neither renderable nor callable, or a callable returning one, raises. + + Args: + component: The value to convert. + message: The expected start of the error message. + """ + with pytest.raises(TypeError, match=message): + compiler.into_component(component) diff --git a/tests/units/compiler/test_dynamic_components_codegen.py b/tests/units/compiler/test_dynamic_components_codegen.py index b209f5b8744..ddbad049d62 100644 --- a/tests/units/compiler/test_dynamic_components_codegen.py +++ b/tests/units/compiler/test_dynamic_components_codegen.py @@ -429,7 +429,7 @@ def add_imports(self) -> ParsedImportDict: def test_dynamic_component_codegen_wires_event_handlers() -> None: """Dynamic component codegen should preserve backend event handlers.""" - state = State(_reflex_internal_init=True) # pyright: ignore[reportCallIssue] + state = State(_reflex_internal_init=True) # ty:ignore[unknown-argument] component = rx.el.div( rx.el.button("hydrate", on_click=State.set_is_hydrated(True)), rx.el.span(state.is_hydrated), @@ -497,7 +497,7 @@ def counter_ui(self) -> rx.Component: justify="center", ) - state = DynamicCounterCodegenState(_reflex_internal_init=True) # pyright: ignore[reportCallIssue] + state = DynamicCounterCodegenState(_reflex_internal_init=True) # ty:ignore[unknown-argument] code = serializers.serialize(state.counter_ui) assert isinstance(code, str) diff --git a/tests/units/compiler/test_memoize_plugin.py b/tests/units/compiler/test_memoize_plugin.py index ffea8c7ca2d..ce2d485e868 100644 --- a/tests/units/compiler/test_memoize_plugin.py +++ b/tests/units/compiler/test_memoize_plugin.py @@ -365,13 +365,10 @@ def special_child() -> Component: lambda item: rx.text(item), ) if special_form == "cond": - return cast( - Component, - rx.cond( - SpecialFormMemoState.flag, - rx.text("yes"), - rx.text("no"), - ), + return rx.cond( + SpecialFormMemoState.flag, + rx.text("yes"), + rx.text("no"), ) return cast( Component, @@ -501,13 +498,10 @@ def test_common_memoization_snapshot_helper_classifies_snapshot_cases() -> None: lambda item: rx.text(item), ) ) - cond_fragment = cast( - Component, - rx.cond( - SpecialFormMemoState.flag, - rx.text("yes"), - rx.text("no"), - ), + cond_fragment = rx.cond( + SpecialFormMemoState.flag, + rx.text("yes"), + rx.text("no"), ) match_fragment = cast( Component, @@ -855,8 +849,12 @@ def fake_create_passthrough_component_memo( fake_create_passthrough_component_memo, ) - first_compile = SimpleNamespace(memoize_wrappers={}, auto_memo_components={}) - second_compile = SimpleNamespace(memoize_wrappers={}, auto_memo_components={}) + first_compile = cast( + CompileContext, SimpleNamespace(memoize_wrappers={}, auto_memo_components={}) + ) + second_compile = cast( + CompileContext, SimpleNamespace(memoize_wrappers={}, auto_memo_components={}) + ) page_context = cast(PageContext, SimpleNamespace(source_module=None)) MemoizeStatefulPlugin._build_wrapper( @@ -2162,7 +2160,7 @@ def test_form_memo_preserves_control_refs(form_factory) -> None: lambda: form_factory( rx.box( rx.input(id="plain_field"), - rx.input(id="debounced_field", on_change=rx.console_log), + rx.input(id="debounced_field", on_change=rx.console_log), # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 rx.radio_group(["a", "b"], id="unset_field"), rx.text("Label", id="label"), id="wrapper", diff --git a/tests/units/components/core/test_colors.py b/tests/units/components/core/test_colors.py index 3ef74e2582b..d384360f634 100644 --- a/tests/units/components/core/test_colors.py +++ b/tests/units/components/core/test_colors.py @@ -24,7 +24,7 @@ def create_color_var(color): color_with_fstring = rx.color( - f"{ColorState.color}", # pyright: ignore [reportArgumentType] + f"{ColorState.color}", # ty:ignore[invalid-argument-type] ColorState.shade, ) @@ -55,7 +55,7 @@ def create_color_var(color): ( create_color_var( rx.color( - f"{ColorState.color_part}ato", # pyright: ignore [reportArgumentType] + f"{ColorState.color_part}ato", # ty:ignore[invalid-argument-type] ColorState.shade, ) ), @@ -143,4 +143,4 @@ def test_radix_color(color, expected): expected (str): The expected custom_style string, radix or literal """ code_block = CodeBlock.create("Hello World", background_color=color) - assert str(code_block.custom_style["backgroundColor"]) == expected # pyright: ignore [reportAttributeAccessIssue] + assert str(code_block.custom_style["backgroundColor"]) == expected # ty:ignore[unresolved-attribute] diff --git a/tests/units/components/core/test_cond.py b/tests/units/components/core/test_cond.py index b5d78d09b22..40df1bb89a9 100644 --- a/tests/units/components/core/test_cond.py +++ b/tests/units/components/core/test_cond.py @@ -16,7 +16,7 @@ @pytest.fixture def cond_state(request): class CondState(BaseState): - value: request.param["value_type"] = request.param["value"] # pyright: ignore [reportInvalidTypeForm, reportUndefinedVariable] # noqa: F821 + value: request.param["value_type"] = request.param["value"] # noqa: F821 return CondState @@ -43,7 +43,7 @@ def test_validate_cond(cond_state: BaseState): cond_state: A fixture. """ cond_component = cond( - cond_state.value, # pyright: ignore[reportAttributeAccessIssue] + cond_state.value, # ty:ignore[unresolved-attribute] Text.create("cond is True"), Text.create("cond is False"), ) @@ -51,7 +51,7 @@ def test_validate_cond(cond_state: BaseState): assert cond_dict["name"] == "Fragment" [condition] = cond_dict["children"] - assert condition["cond_state"] == str(cond_state.value.bool()) # pyright: ignore[reportAttributeAccessIssue] + assert condition["cond_state"] == str(cond_state.value.bool()) # ty:ignore[unresolved-attribute] # true value true_value = condition["true_value"] @@ -114,12 +114,12 @@ def test_cond_no_else(): comp = comp.children[0] assert isinstance(comp, Cond) assert comp.cond._decode() is True - assert comp.children[0].render() == Fragment.create(Text.create("hello")).render() # pyright: ignore [reportOptionalMemberAccess] + assert comp.children[0].render() == Fragment.create(Text.create("hello")).render() assert comp.children[1] == Fragment.create() # Props do not support the use of cond without else with pytest.raises(ValueError): - cond(True, "hello") # pyright: ignore [reportArgumentType] + cond(True, "hello") # ty:ignore[invalid-argument-type] def test_cond_render_missing_false_child_defaults_to_fragment() -> None: @@ -162,7 +162,7 @@ def computed_str(self) -> str: def test_cond_assert_types() -> None: - """Test that pyright infers the correct return types for cond overloads.""" + """Test that the type checker infers the correct return types for cond overloads.""" text_comp = Text.create("hello") text_comp2 = Text.create("world") var_int: Var[int] = LiteralVar.create(1) @@ -185,10 +185,10 @@ def test_cond_assert_types() -> None: _ = assert_type(cond(True, "hello", "world"), Var[Literal["hello", "world"]]) # non-string T, T -> Var[T] (only literal strings get the narrowing overloads) - _ = assert_type(cond(True, 1, 2), Var[int]) + _ = assert_type(cond(True, 1, 2), Var[int]) # ty:ignore[type-assertion-failure] # T, U -> Var[T | U] - _ = assert_type(cond(True, "hello", 3), Var[str | int]) + _ = assert_type(cond(True, "hello", 3), Var[str | int]) # ty:ignore[type-assertion-failure] # literal str, Var[Literal[...]] -> Var[Literal[...]] _ = assert_type(cond(True, "hello", literal_var_str), Var[Literal["hello", "a"]]) @@ -206,7 +206,7 @@ def test_cond_assert_types() -> None: _ = assert_type(cond(True, "hello", widened_var_str), Var[str]) # Var[T], U -> Var[T | U] - _ = assert_type(cond(True, widened_var_str, 3), Var[str | int]) + _ = assert_type(cond(True, widened_var_str, 3), Var[str | int]) # ty:ignore[type-assertion-failure] # Var[T], Var[U] -> Var[T | U] _ = assert_type(cond(True, var_int, widened_var_str), Var[int | str]) diff --git a/tests/units/components/core/test_html.py b/tests/units/components/core/test_html.py index 4241c9344ab..fd53a50485c 100644 --- a/tests/units/components/core/test_html.py +++ b/tests/units/components/core/test_html.py @@ -16,7 +16,7 @@ def test_html_many_children(): def test_html_create(): html = Html.create("

Hello !

") - assert str(html.dangerouslySetInnerHTML) == '({ ["__html"] : "

Hello !

" })' # pyright: ignore [reportAttributeAccessIssue] + assert str(html.dangerouslySetInnerHTML) == '({ ["__html"] : "

Hello !

" })' # ty:ignore[unresolved-attribute] assert ( str(html) == 'jsx("div",{className:"rx-Html",dangerouslySetInnerHTML:({ ["__html"] : "

Hello !

" })},)' @@ -31,7 +31,7 @@ class TestState(State): html = Html.create(f"

Hello {TestState.myvar}!

") - html_dangerouslySetInnerHTML = html.dangerouslySetInnerHTML # pyright: ignore [reportAttributeAccessIssue] + html_dangerouslySetInnerHTML = html.dangerouslySetInnerHTML # ty:ignore[unresolved-attribute] assert ( str(html_dangerouslySetInnerHTML) diff --git a/tests/units/components/core/test_upload.py b/tests/units/components/core/test_upload.py index 1fd26e09135..76215e6db84 100644 --- a/tests/units/components/core/test_upload.py +++ b/tests/units/components/core/test_upload.py @@ -22,7 +22,7 @@ StyledUpload, Upload, UploadNamespace, - _on_drop_spec, # pyright: ignore [reportAttributeAccessIssue] + _on_drop_spec, cancel_upload, get_upload_url, ) @@ -185,7 +185,7 @@ def test_upload_create(): up_comp_5 = Upload.create( id="foo_id", on_drop=StreamingUploadStateTest.chunk_drop_handler( - rx.upload_files_chunk(upload_id="foo_id") # pyright: ignore[reportArgumentType] + rx.upload_files_chunk(upload_id="foo_id") ), ) assert isinstance(up_comp_5, Upload) @@ -194,7 +194,7 @@ def test_upload_create(): up_comp_6 = Upload.create( id="foo_id", on_drop=StreamingUploadStateTest.chunk_upload_alias_handler( - rx.upload_files_chunk(upload_id="foo_id") # pyright: ignore[reportArgumentType] + rx.upload_files_chunk(upload_id="foo_id") ), ) assert isinstance(up_comp_6, Upload) @@ -217,7 +217,7 @@ def test_upload_button_handlers_allow_custom_param_names(): chunk_button = rx.button( "Upload", on_click=StreamingUploadStateTest.chunk_upload_alias_handler( - rx.upload_files_chunk(upload_id="foo_id") # pyright: ignore[reportArgumentType] + rx.upload_files_chunk(upload_id="foo_id") ), ) chunk_chain = cast(EventChain, chunk_button.event_triggers["on_click"]) diff --git a/tests/units/components/datadisplay/test_code.py b/tests/units/components/datadisplay/test_code.py index cd9e451ac97..c1cc94ffa03 100644 --- a/tests/units/components/datadisplay/test_code.py +++ b/tests/units/components/datadisplay/test_code.py @@ -18,12 +18,12 @@ def test_default_code_copy_button_has_an_accessible_name(): def test_code_light_dark_theme(theme, expected): code_block = CodeBlock.create(theme=theme) - assert code_block.theme._js_expr == expected # pyright: ignore [reportAttributeAccessIssue] + assert code_block.theme._js_expr == expected # ty:ignore[unresolved-attribute] def test_code_block_rejects_string_theme(): with pytest.raises(TypeError, match=r"CodeBlock\.theme"): - CodeBlock.create("print('Hello')", theme="one_dark") # pyright: ignore[reportArgumentType] + CodeBlock.create("print('Hello')", theme="one_dark") # ty:ignore[invalid-argument-type] def test_code_block_collects_custom_style_state_vars(): @@ -35,9 +35,9 @@ class CustomStyleState(rx.State): ) rendered = str(code_block.render()) - assert CustomStyleState.color._js_expr in rendered # pyright: ignore [reportAttributeAccessIssue] + assert CustomStyleState.color._js_expr in rendered # ty:ignore[unresolved-attribute] - var_data = CustomStyleState.color._get_all_var_data() # pyright: ignore [reportAttributeAccessIssue] + var_data = CustomStyleState.color._get_all_var_data() # ty:ignore[unresolved-attribute] assert var_data is not None assert var_data.hooks collected_hooks = code_block._get_all_hooks() diff --git a/tests/units/components/datadisplay/test_datatable.py b/tests/units/components/datadisplay/test_datatable.py index 684248e875c..54d3ece0672 100644 --- a/tests/units/components/datadisplay/test_datatable.py +++ b/tests/units/components/datadisplay/test_datatable.py @@ -16,7 +16,7 @@ { "data": pd.DataFrame( [["foo", "bar"], ["foo1", "bar1"]], - columns=["column1", "column2"], # pyright: ignore [reportArgumentType] + columns=["column1", "column2"], ) }, "data", @@ -34,13 +34,13 @@ def test_validate_data_table(data_table_state: rx.State, expected): expected: expected var name. """ - if not types.is_dataframe(data_table_state.data._var_type): # pyright: ignore[reportAttributeAccessIssue] + if not types.is_dataframe(data_table_state.data._var_type): # ty:ignore[unresolved-attribute] data_table_component = DataTable.create( - data=data_table_state.data, # pyright: ignore[reportAttributeAccessIssue] - columns=data_table_state.columns, # pyright: ignore[reportAttributeAccessIssue] + data=data_table_state.data, # ty:ignore[unresolved-attribute] + columns=data_table_state.columns, # ty:ignore[unresolved-attribute] ) else: - data_table_component = DataTable.create(data=data_table_state.data) # pyright: ignore[reportAttributeAccessIssue] + data_table_component = DataTable.create(data=data_table_state.data) # ty:ignore[unresolved-attribute] data_table_dict = data_table_component.render() @@ -127,7 +127,7 @@ def test_serialize_dataframe(): """Test if dataframe is serialized correctly.""" simple_dataframe = pd.DataFrame( [["foo", "bar"], ["foo1", "bar1"]], - columns=["column1", "column2"], # pyright: ignore [reportArgumentType] + columns=["column1", "column2"], ) value = serialize(simple_dataframe) assert value == serialize_dataframe(simple_dataframe) diff --git a/tests/units/components/datadisplay/test_shiki_code.py b/tests/units/components/datadisplay/test_shiki_code.py index 2f79fafea45..ed85d76ae1b 100644 --- a/tests/units/components/datadisplay/test_shiki_code.py +++ b/tests/units/components/datadisplay/test_shiki_code.py @@ -103,7 +103,7 @@ def test_create_shiki_code_block( # Test that the first child is the code code_block_component = component.children[0] - assert code_block_component.code._var_value == expected_first_child # pyright: ignore [reportAttributeAccessIssue] + assert code_block_component.code._var_value == expected_first_child # ty:ignore[unresolved-attribute] applied_styles = component.style for key, value in expected_styles.items(): @@ -138,12 +138,12 @@ def test_create_shiki_high_level_code_block( # Test that the first child is the code block component code_block_component = component.children[0] - assert code_block_component.code._var_value == children[0] # pyright: ignore [reportAttributeAccessIssue] + assert code_block_component.code._var_value == children[0] # ty:ignore[unresolved-attribute] # Check if the transformer is set correctly if expected if expected_transformers: exp_trans_names = [t.__name__ for t in expected_transformers] - for transformer in code_block_component.transformers._var_value: # pyright: ignore [reportAttributeAccessIssue] + for transformer in code_block_component.transformers._var_value: # ty:ignore[unresolved-attribute] assert type(transformer).__name__ in exp_trans_names # Check if the second child is the copy button if can_copy is True @@ -193,12 +193,12 @@ def test_shiki_high_level_code_block_theme_language_mapping(children, props): if "theme" in props: assert component.children[ 0 - ].theme._var_value == ShikiHighLevelCodeBlock._map_themes(props["theme"]) # pyright: ignore [reportAttributeAccessIssue] + ].theme._var_value == ShikiHighLevelCodeBlock._map_themes(props["theme"]) # ty:ignore[unresolved-attribute] # Test that the language is mapped correctly if "language" in props: assert component.children[ 0 - ].language._var_value == ShikiHighLevelCodeBlock._map_languages( # pyright: ignore [reportAttributeAccessIssue] + ].language._var_value == ShikiHighLevelCodeBlock._map_languages( # ty:ignore[unresolved-attribute] props["language"] ) diff --git a/tests/units/components/forms/test_form.py b/tests/units/components/forms/test_form.py index e1b8bd79dae..2cae3afde92 100644 --- a/tests/units/components/forms/test_form.py +++ b/tests/units/components/forms/test_form.py @@ -42,7 +42,7 @@ def test_render_on_submit(): _var_type=EventChain, ) f = Form.create(on_submit=submit_it) - exp_submit_name = f"handleSubmit_{f.handle_submit_unique_name}" # pyright: ignore [reportAttributeAccessIssue] + exp_submit_name = f"handleSubmit_{f.handle_submit_unique_name}" # ty:ignore[unresolved-attribute] assert f"onSubmit:{exp_submit_name}" in f.render()["props"] @@ -121,7 +121,7 @@ def test_form_refs_include_debounced_controls(): """ID-only debounced inputs remain available to submit handlers.""" form = HTMLForm.create( DebounceInput.create( - Input.create(id=DEBOUNCED_INPUT_ID, on_change=rx.console_log) + Input.create(id=DEBOUNCED_INPUT_ID, on_change=rx.console_log) # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 ) ) @@ -185,7 +185,7 @@ def test_on_submit_rejects_typed_dict_with_unresolved_field_types(): """A TypedDict whose field types cannot be resolved fails at compile time.""" class LooseData(TypedDict): - tags: _T # pyright: ignore[reportGeneralTypeIssues] + tags: _T # ty:ignore[unbound-type-variable] class LooseState(rx.State): @rx.event @@ -277,7 +277,7 @@ class MemoizedInput(Input): (_memoized_control, "memoized_input"), ( lambda: DebounceInput.create( - Input.create(id="debounced_input", on_change=rx.console_log) + Input.create(id="debounced_input", on_change=rx.console_log) # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 ), "debounced_input", ), @@ -304,12 +304,16 @@ def test_on_submit_warns_for_custom_controls_with_only_an_id( lambda: Input.create(id="disabled_input", disabled=True), lambda: DebounceInput.create( Input.create( - id="debounced_named", name="debounced_named", on_change=rx.console_log + id="debounced_named", + name="debounced_named", + on_change=rx.console_log, # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 ) ), lambda: DebounceInput.create( Input.create( - id="debounced_disabled", disabled=True, on_change=rx.console_log + id="debounced_disabled", + disabled=True, + on_change=rx.console_log, # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 ) ), ], @@ -333,10 +337,10 @@ def test_on_submit_accepts_typed_dict_with_unresolvable_field_types(): class OrderData(TypedDict): name: str - amount: "Decimal" # noqa: F821 # pyright: ignore[reportUndefinedVariable] - tip: "NotRequired[Decimal]" # noqa: F821 # pyright: ignore[reportUndefinedVariable] - fee: "NotRequired[billing.Money]" # noqa: F821 # pyright: ignore[reportUndefinedVariable] - tags: "Seq[str]" # noqa: F821 # pyright: ignore[reportUndefinedVariable] + amount: "Decimal" # noqa: F821 # ty:ignore[unresolved-reference] + tip: "NotRequired[Decimal]" # noqa: F821 # ty:ignore[unresolved-reference] + fee: "NotRequired[billing.Money]" # noqa: F821 # ty:ignore[unresolved-reference] + tags: "Seq[str]" # noqa: F821 # ty:ignore[unresolved-reference] class OrderState(rx.State): @rx.event @@ -416,7 +420,7 @@ def on_submit(self, form_data: EmailData): pass HTMLForm.create( - DebounceInput.create(Input.create(name="email", on_change=rx.console_log)), + DebounceInput.create(Input.create(name="email", on_change=rx.console_log)), # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 on_submit=EmailState.on_submit, ) @@ -480,7 +484,7 @@ def on_submit(self, source: str, form_data: SignupData): form = HTMLForm.create( Input.create(name="email"), - on_submit=SignupState.on_submit("marketing"), # pyright: ignore [reportCallIssue] + on_submit=SignupState.on_submit("marketing"), ) assert isinstance(form.event_triggers["on_submit"], EventChain) diff --git a/tests/units/components/graphing/test_recharts.py b/tests/units/components/graphing/test_recharts.py index c6a9875c82f..bff8abd7d82 100644 --- a/tests/units/components/graphing/test_recharts.py +++ b/tests/units/components/graphing/test_recharts.py @@ -130,8 +130,8 @@ def custom_link(link: rx.Var[SankeyLinkProps]) -> rx.Component: namespace, ) - assert callable(sankey_chart.node(namespace["custom_node"])) - assert callable(sankey_chart.link(namespace["custom_link"])) + assert callable(sankey_chart.node(namespace["custom_node"])) # ty:ignore[invalid-argument-type] + assert callable(sankey_chart.link(namespace["custom_link"])) # ty:ignore[invalid-argument-type] def test_sankey_renderer_decorator_rejects_positional_only_parameter(): diff --git a/tests/units/components/media/test_image.py b/tests/units/components/media/test_image.py index 9692c3b99f8..2585ee8eb11 100644 --- a/tests/units/components/media/test_image.py +++ b/tests/units/components/media/test_image.py @@ -16,7 +16,7 @@ def pil_image() -> Img: """ rng = np.random.default_rng() imarray = rng.random((100, 100, 3)) * 255 - return PIL.Image.fromarray(imarray.astype("uint8")).convert("RGBA") # pyright: ignore [reportAttributeAccessIssue] + return PIL.Image.fromarray(imarray.astype("uint8")).convert("RGBA") # ty:ignore[possibly-missing-submodule] def test_serialize_image(pil_image: Img): @@ -34,4 +34,4 @@ def test_serialize_image(pil_image: Img): def test_set_src_str(): """Test that setting the src works.""" image = rx.image(src="pic2.jpeg") - assert str(image.src) == '"pic2.jpeg"' # pyright: ignore [reportAttributeAccessIssue] + assert str(image.src) == '"pic2.jpeg"' # ty:ignore[unresolved-attribute] diff --git a/tests/units/components/recharts/test_cartesian.py b/tests/units/components/recharts/test_cartesian.py index 565a7d740c3..f6f6427b1b2 100644 --- a/tests/units/components/recharts/test_cartesian.py +++ b/tests/units/components/recharts/test_cartesian.py @@ -76,13 +76,13 @@ def test_yaxis_tick_formatter(): def test_xaxis_tick_formatter_rejects_non_callable(): with pytest.raises(TypeError): - XAxis.create(tick_formatter=123) # pyright: ignore [reportArgumentType] + XAxis.create(tick_formatter=123) # ty:ignore[invalid-argument-type] def test_xaxis_tick_formatter_rejects_python_callable(): with pytest.raises(TypeError): XAxis.create( - tick_formatter=lambda value: value # pyright: ignore [reportArgumentType] + tick_formatter=lambda value: value # ty:ignore[invalid-argument-type] ) diff --git a/tests/units/components/test_component.py b/tests/units/components/test_component.py index c141365e6ed..aa630a4b7cc 100644 --- a/tests/units/components/test_component.py +++ b/tests/units/components/test_component.py @@ -42,8 +42,8 @@ import reflex as rx from reflex import ( - _COMPONENTS_BASE_MAPPING, # pyright: ignore[reportAttributeAccessIssue] - _COMPONENTS_CORE_MAPPING, # pyright: ignore[reportAttributeAccessIssue] + _COMPONENTS_BASE_MAPPING, # ty:ignore[unresolved-import] + _COMPONENTS_CORE_MAPPING, # ty:ignore[unresolved-import] ) from reflex.state import BaseState from reflex.utils import imports @@ -803,7 +803,7 @@ class BackendPropState(BaseState): _size: str = "3" with pytest.raises(TypeError, match=r"got value Field\(default='3'"): - rx.heading("x", size=BackendPropState._size) # pyright: ignore[reportArgumentType] + rx.heading("x", size=BackendPropState._size) # ty:ignore[invalid-argument-type] def test_component_create_backend_var_class_name(): @@ -1325,7 +1325,8 @@ class EventState(rx.State): def handler(self): """A handler that does nothing.""" - def handler2(self, arg): + @rx.event + def handler2(self, arg: int): """A handler that takes an arg. Args: @@ -1448,17 +1449,17 @@ def handler2(self, arg): id="direct-event-handler", ), pytest.param( - rx.fragment(on_blur=EventState.handler2(TEST_VAR)), # pyright: ignore [reportCallIssue] + rx.fragment(on_blur=EventState.handler2(TEST_VAR)), # ty:ignore[no-matching-overload] [ARG_VAR, TEST_VAR], id="direct-event-handler-arg", ), pytest.param( - rx.fragment(on_blur=EventState.handler2(EventState.v)), # pyright: ignore [reportCallIssue] + rx.fragment(on_blur=EventState.handler2(EventState.v)), [ARG_VAR, EventState.v], id="direct-event-handler-arg2", ), pytest.param( - rx.fragment(on_blur=lambda: EventState.handler2(TEST_VAR)), # pyright: ignore [reportCallIssue] + rx.fragment(on_blur=lambda: EventState.handler2(TEST_VAR)), # ty:ignore[invalid-argument-type, no-matching-overload] https://github.com/astral-sh/ty/issues/4098 [ARG_VAR, TEST_VAR], id="direct-event-handler-lambda", ), @@ -1764,7 +1765,8 @@ def test_validate_invalid_children(): rx.fragment(invalid_component()), rx.fragment( rx.foreach( - LiteralVar.create([1, 2, 3]), lambda x: invalid_component(x) + LiteralVar.create([1, 2, 3]), + lambda x: invalid_component(x), ) ), ) @@ -1911,7 +1913,7 @@ def get_event_triggers(cls) -> dict[str, Any]: ) def test_component_add_imports(tags): class BaseComponent(Component): - def _get_imports(self) -> ImportDict: # pyright: ignore [reportIncompatibleMethodOverride] + def _get_imports(self) -> ImportDict: return {} class Reference(Component): @@ -1923,7 +1925,7 @@ def _get_imports(self) -> ParsedImportDict: ) class TestBase(Component): - def add_imports( # pyright: ignore [reportIncompatibleMethodOverride] + def add_imports( self, ) -> dict[str, str | ImportVar | list[str] | list[ImportVar]]: return {"foo": "bar"} @@ -1953,7 +1955,7 @@ class ChildComponent1(BaseComponent): pass class GrandchildComponent1(ChildComponent1): - def add_hooks(self): # pyright: ignore [reportIncompatibleMethodOverride] + def add_hooks(self): return [ "const hook2 = 43", "const hook3 = 44", @@ -1966,11 +1968,11 @@ def add_hooks(self): ] class GrandchildComponent2(ChildComponent1): - def _get_hooks(self): # pyright: ignore [reportIncompatibleMethodOverride] + def _get_hooks(self): return "const hook5 = 46" class GreatGrandchildComponent2(GrandchildComponent2): - def add_hooks(self): # pyright: ignore [reportIncompatibleMethodOverride] + def add_hooks(self): return [ "const hook2 = 43", "const hook6 = 47", @@ -2045,7 +2047,7 @@ def add_custom_code(self): ] class GrandchildComponent2(ChildComponent1): - def _get_custom_code(self): # pyright: ignore [reportIncompatibleMethodOverride] + def _get_custom_code(self): return "const custom_code5 = 46" class GreatGrandchildComponent2(GrandchildComponent2): @@ -2244,7 +2246,7 @@ def add_style(self): class StyledComponent(ParentComponent): tag = "StyledComponent" - def add_style(self): # pyright: ignore [reportIncompatibleMethodOverride] + def add_style(self): return { "color": v1, "fake": v2, @@ -2355,7 +2357,7 @@ def do_something(self): rx.box( rx.text( "random text", - on_blur=lambda: TriggerState.do_something, + on_blur=lambda: TriggerState.do_something, # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 ), ), True, diff --git a/tests/units/components/test_memo.py b/tests/units/components/test_memo.py index 6f52239fbc1..1586137de61 100644 --- a/tests/units/components/test_memo.py +++ b/tests/units/components/test_memo.py @@ -1350,7 +1350,7 @@ def test_var_returning_memo_rejects_wrapper(): """``wrapper=`` is only supported on component-returning memos.""" with pytest.raises(TypeError, match="only supports `wrapper=`"): - @rx.memo(wrapper=None) # pyright: ignore[reportArgumentType] + @rx.memo(wrapper=None) # ty:ignore[invalid-argument-type] def format_id(value: rx.Var[int]) -> rx.Var[str]: return value.to(str) @@ -1541,7 +1541,7 @@ class RestrictedChild(Component): @rx.memo def transparent(children: rx.Var[rx.Component]) -> rx.Component: - return children # type: ignore[return-value] + return children # ty:ignore[invalid-return-type] wrapped_child = transparent(RestrictedChild.create()) parent = ValidParent.create(wrapped_child) @@ -1633,7 +1633,7 @@ def eh_compile_memo( def test_component_memo_event_handler_wires_event_chain_at_call_site(): """Instantiating an EH memo should wrap the handler in an EventChain trigger.""" - def _handler_fn(value: str): # pyright: ignore[reportUnusedFunction] + def _handler_fn(value: str): pass raw_handler = EventHandler(fn=_handler_fn) @@ -1670,7 +1670,7 @@ def test_component_memo_rejects_event_handler_with_default(): @rx.memo def bad_eh_default( - event: rx.EventHandler[rx.event.passthrough_event_spec(str)] = None, # pyright: ignore[reportArgumentType] + event: rx.EventHandler[rx.event.passthrough_event_spec(str)] = None, ) -> rx.Component: return rx.button("hi") @@ -2265,7 +2265,7 @@ def test_memo_tag_separates_same_named_classes_from_different_modules(): "class Probe(Component):\n tag = 'Probe'\n library = 'probe-lib'\n", namespace, ) - probes.append(namespace["Probe"].create()) + probes.append(namespace["Probe"].create()) # ty:ignore[unresolved-attribute] a, b = probes assert type(a) is not type(b) diff --git a/tests/units/components/test_props.py b/tests/units/components/test_props.py index e14f1e05158..772dbf863bd 100644 --- a/tests/units/components/test_props.py +++ b/tests/units/components/test_props.py @@ -206,8 +206,8 @@ def handle_input(self, value: str): pass props = EventProps( - on_click=FooState.handle_click, # pyright: ignore[reportArgumentType] - not_start_with_on=FooState.handle_input, # pyright: ignore[reportArgumentType] + on_click=FooState.handle_click, + not_start_with_on=FooState.handle_input, ) props_dict = props.dict() assert isinstance(props_dict["onClick"], EventChain) diff --git a/tests/units/components/typography/test_markdown.py b/tests/units/components/typography/test_markdown.py index 2ddc591252b..780713121f1 100644 --- a/tests/units/components/typography/test_markdown.py +++ b/tests/units/components/typography/test_markdown.py @@ -29,7 +29,7 @@ def test_get_component(tag, expected): expected: The expected component. """ md = Markdown.create("# Hello") - assert tag in md.component_map # pyright: ignore [reportAttributeAccessIssue] + assert tag in md.component_map # ty:ignore[unresolved-attribute] assert md.get_component(tag).tag == expected diff --git a/tests/units/conftest.py b/tests/units/conftest.py index e4e83140c64..37b20fc2872 100644 --- a/tests/units/conftest.py +++ b/tests/units/conftest.py @@ -119,7 +119,7 @@ def upload_sub_state_event_spec(): Returns: Event Spec. """ - return EventSpec(handler=SubUploadState.handle_upload, upload=True) # pyright: ignore [reportCallIssue] + return EventSpec(handler=SubUploadState.handle_upload, upload=True) # ty:ignore[invalid-argument-type, unknown-argument] @pytest.fixture @@ -129,7 +129,7 @@ def upload_event_spec(): Returns: Event Spec. """ - return EventSpec(handler=UploadState.handle_upload1, upload=True) # pyright: ignore [reportCallIssue] + return EventSpec(handler=UploadState.handle_upload1, upload=True) # ty:ignore[invalid-argument-type, unknown-argument] @pytest.fixture @@ -263,11 +263,11 @@ class Entry: Entry.__module__ = module.__name__ Entry.__qualname__ = "Entry" - module.Entry = Entry # pyright: ignore[reportAttributeAccessIssue] - module.Color = enum.Enum( # pyright: ignore[reportAttributeAccessIssue] + module.Entry = Entry # ty:ignore[unresolved-attribute] + module.Color = enum.Enum( # ty:ignore[unresolved-attribute] "Color", {"RED": "red", "BLUE": "blue"}, module=module.__name__ ) - module.Point = collections.namedtuple("Point", "x y", module=module.__name__) # pyright: ignore[reportAttributeAccessIssue] + module.Point = collections.namedtuple("Point", "x y", module=module.__name__) # ty:ignore[unresolved-attribute] return module diff --git a/tests/units/docgen/test_class_and_component.py b/tests/units/docgen/test_class_and_component.py index 691a9cb64e8..4526d8a8f34 100644 --- a/tests/units/docgen/test_class_and_component.py +++ b/tests/units/docgen/test_class_and_component.py @@ -394,7 +394,7 @@ class _DataclassWithFieldDoc: name: From docstring. """ - name: str = dataclasses.field(default="x", doc="From field.doc") + name: str = dataclasses.field(default="x", doc="From field.doc") # ty:ignore[no-matching-overload] doc = generate_class_documentation(_DataclassWithFieldDoc) fields_by_name = {f.name: f for f in doc.fields} diff --git a/tests/units/istate/manager/test_disk.py b/tests/units/istate/manager/test_disk.py index 402a14cb31e..48924e84e82 100644 --- a/tests/units/istate/manager/test_disk.py +++ b/tests/units/istate/manager/test_disk.py @@ -111,7 +111,7 @@ async def test_set_state_persists_untouched_base_state( monkeypatch.setattr(prerequisites, "get_states_dir", lambda: tmp_path) state_manager = StateManagerDisk(_write_debounce_seconds=write_debounce_seconds) token = BaseStateToken(ident="client", cls=DiskPersistState) - state = DiskPersistState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + state = DiskPersistState(_reflex_internal_init=True) # ty:ignore[unknown-argument] object.__setattr__(state, "num", 9.5) state.dirty_vars.clear() state._was_touched = False diff --git a/tests/units/istate/manager/test_expiration.py b/tests/units/istate/manager/test_expiration.py index 93907e03569..48ec4f1a98f 100644 --- a/tests/units/istate/manager/test_expiration.py +++ b/tests/units/istate/manager/test_expiration.py @@ -222,7 +222,7 @@ async def test_memory_state_manager_get_state_refreshes_expiration( same_state = await state_manager_memory.get_state(state_token) assert same_state is state - assert state_manager_memory._token_expires_at[token] > expires_at + assert state_manager_memory._token_expires_at[token][0] > expires_at[0] await asyncio.sleep(0.6) @@ -247,7 +247,7 @@ async def test_memory_state_manager_set_state_refreshes_expiration( await state_manager_memory.set_state(state_token, state) - assert state_manager_memory._token_expires_at[token] > expires_at + assert state_manager_memory._token_expires_at[token][0] > expires_at[0] await asyncio.sleep(0.6) @@ -270,7 +270,7 @@ async def test_memory_state_manager_multiple_accesses_extend_expiration( for _ in range(3): await asyncio.sleep(0.25) assert await state_manager_memory.get_state(state_token) is state - assert state_manager_memory._token_expires_at[token] > expires_at + assert state_manager_memory._token_expires_at[token][0] > expires_at[0] expires_at = state_manager_memory._token_expires_at[token] await asyncio.sleep(0.6) @@ -333,7 +333,7 @@ async def test_memory_state_manager_refreshes_expiration_after_locked_access( await asyncio.sleep(1.2) assert token in state_manager_memory.states - assert state_manager_memory._token_expires_at[token] > expires_at + assert state_manager_memory._token_expires_at[token][0] > expires_at[0] await asyncio.sleep(0.6) diff --git a/tests/units/istate/manager/test_redis.py b/tests/units/istate/manager/test_redis.py index 5ed218e1ef4..42ef87e97cf 100644 --- a/tests/units/istate/manager/test_redis.py +++ b/tests/units/istate/manager/test_redis.py @@ -170,7 +170,7 @@ def event_log(state_manager_redis: StateManagerRedis) -> list[dict[str, Any]]: Returns: The redis event log. """ - return state_manager_redis.redis._internals["event_log"] # pyright: ignore[reportAttributeAccessIssue] + return state_manager_redis.redis._internals["event_log"] # ty:ignore[unresolved-attribute] @pytest.fixture @@ -186,7 +186,7 @@ def event_log_on_update(state_manager_redis: StateManagerRedis) -> asyncio.Event Returns: The event that is set when new events are added to the redis event log. """ - return state_manager_redis.redis._internals["event_log_on_update"] # pyright: ignore[reportAttributeAccessIssue] + return state_manager_redis.redis._internals["event_log_on_update"] # ty:ignore[unresolved-attribute] @pytest.mark.asyncio @@ -973,7 +973,7 @@ def counting_eval(script, numkeys, *keys_and_args): async with state_manager_redis.modify_state(token) as state: assert len(state.substates) == 2 state.count = 1 - redis.eval = counting_eval # pyright: ignore[reportAttributeAccessIssue] + redis.eval = counting_eval # ty:ignore[invalid-assignment] try: await state_manager_redis.set_state( token, @@ -981,7 +981,7 @@ def counting_eval(script, numkeys, *keys_and_args): lock_id=await redis.get(state_manager_redis._lock_key(token)), ) finally: - redis.eval = real_eval # pyright: ignore[reportAttributeAccessIssue] + redis.eval = real_eval # ty:ignore[invalid-assignment] # One command for a tree of three states, all of them touched by the load. assert len(evals) == 1 diff --git a/tests/units/istate/test_data.py b/tests/units/istate/test_data.py index 5dcf2089086..3f329102136 100644 --- a/tests/units/istate/test_data.py +++ b/tests/units/istate/test_data.py @@ -341,11 +341,11 @@ def test_shared_empty_url_default_cannot_be_mutated_through_a_state(): class _URLIsolationState(BaseState): pass - one = _URLIsolationState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] - two = _URLIsolationState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + one = _URLIsolationState(_reflex_internal_init=True) # ty:ignore[unknown-argument] + two = _URLIsolationState(_reflex_internal_init=True) # ty:ignore[unknown-argument] with pytest.raises(AttributeError, match="immutable"): - one.router.url.path = "/mutated" + one.router.url.path = "/mutated" # ty:ignore[invalid-assignment] one.rx_router_url = URLData.from_url(ReflexURL("https://example.com/real")) diff --git a/tests/units/istate/test_proxy.py b/tests/units/istate/test_proxy.py index 9aa5404bf5a..27a507cf583 100644 --- a/tests/units/istate/test_proxy.py +++ b/tests/units/istate/test_proxy.py @@ -420,7 +420,7 @@ async def test_inherited_mutable_var_marks_its_owner( (token, {InheritedListState.get_full_name(): {"items" + FIELD_MARKER: [1]}}), ] async with state_manager.modify_state(state_token) as root: - assert root.items == [1] # pyright: ignore [reportAttributeAccessIssue] + assert root.items == [1] # ty:ignore[unresolved-attribute] @pytest.mark.asyncio @@ -447,7 +447,7 @@ async def test_inherited_handler_is_guarded_by_the_proxy( async with proxy: proxy.add_item(1) async with state_manager.modify_state(state_token) as root: - assert root.items == [1] # pyright: ignore [reportAttributeAccessIssue] + assert root.items == [1] # ty:ignore[unresolved-attribute] @pytest.mark.asyncio @@ -476,9 +476,9 @@ async def test_inherited_handler_runs_on_its_state( async with proxy: bump() async with state_manager.modify_state(state_token) as root: - assert root.count == 2 # pyright: ignore [reportAttributeAccessIssue] + assert root.count == 2 # ty:ignore[unresolved-attribute] substate = root.get_substate(RedeclaringSubState.get_full_name().split(".")) - assert substate.count == 10 # pyright: ignore [reportAttributeAccessIssue] + assert substate.count == 10 # ty:ignore[unresolved-attribute] @pytest.mark.asyncio @@ -1333,7 +1333,7 @@ class IntervalState(State): def timed(self) -> int: return self.base - state = IntervalState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + state = IntervalState(_reflex_internal_init=True) # ty:ignore[unknown-argument] proxy = StateProxy(state) assert proxy._expired_computed_vars() == {"timed"} assert IntervalState._interval_computed_var_names == frozenset({"timed"}) @@ -1351,7 +1351,7 @@ def test_subclass_overrides_a_framework_method(): def get_value(self, key: str): return f"shadow:{key}" - get_value.__override_base_method__ = True # pyright: ignore [reportFunctionMemberAccess] + get_value.__override_base_method__ = True # ty:ignore[unresolved-attribute] ShadowState = type( "ShadowState", diff --git a/tests/units/istate/test_shared.py b/tests/units/istate/test_shared.py index e7cb2e73010..29468c7329a 100644 --- a/tests/units/istate/test_shared.py +++ b/tests/units/istate/test_shared.py @@ -162,14 +162,14 @@ async def greeting(self) -> str: @pytest.mark.asyncio async def test_patch_state_recomputes_readers_after_restoring(): """Computed vars read from a patched state are recomputed once it is swapped back.""" - root = PatchRoot(_reflex_internal_init=True) # pyright: ignore[reportCallIssue] + root = PatchRoot(_reflex_internal_init=True) # ty:ignore[unknown-argument] original = root.get_substate([PatchSource.get_name()]) reader = root.get_substate([PatchReader.get_name()]) # The state of another client, in a tree of its own. - linked_root = PatchRoot(_reflex_internal_init=True) # pyright: ignore[reportCallIssue] + linked_root = PatchRoot(_reflex_internal_init=True) # ty:ignore[unknown-argument] linked = linked_root.get_substate([PatchSource.get_name()]) linked.who = "linked" # pyright: ignore[reportAttributeAccessIssue] async with _patch_state(original_state=original, linked_state=linked): - assert await reader.greeting == "linked" # pyright: ignore[reportAttributeAccessIssue] - assert await reader.greeting == "private" # pyright: ignore[reportAttributeAccessIssue] + assert await reader.greeting == "linked" # ty:ignore[unresolved-attribute] + assert await reader.greeting == "private" # ty:ignore[unresolved-attribute] diff --git a/tests/units/reflex_base/event/processor/test_base_state_processor.py b/tests/units/reflex_base/event/processor/test_base_state_processor.py index ebbbc91f23d..ef1d261f5f1 100644 --- a/tests/units/reflex_base/event/processor/test_base_state_processor.py +++ b/tests/units/reflex_base/event/processor/test_base_state_processor.py @@ -505,7 +505,7 @@ def _expire_token(state_manager: StateManager, token: str) -> None: state_manager._purge_token(BaseStateToken(ident=token, cls=State)) return assert isinstance(state_manager, StateManagerRedis) - keys = state_manager.redis._internals["keys"] # pyright: ignore[reportAttributeAccessIssue] + keys = state_manager.redis._internals["keys"] # ty:ignore[unresolved-attribute] for key in [key for key in keys if key.startswith(token.encode())]: del keys[key] @@ -1053,7 +1053,7 @@ class RetainingBgState(State): @event(background=True) async def bg(self): dispatch_root.append( - weakref.ref(self.__wrapped__._get_root_state()) # pyright: ignore [reportAttributeAccessIssue] + weakref.ref(self.__wrapped__._get_root_state()) # ty:ignore[unresolved-attribute] ) async with self: pass @@ -1511,7 +1511,7 @@ class DynamicLoadState(State): @event def load_item(self): - item_id = self.item_id # pyright: ignore[reportAttributeAccessIssue] + item_id = self.item_id # ty:ignore[unresolved-attribute] self.seen = [*self.seen, f"{self.router.url.path}|{item_id}"] @event @@ -2042,7 +2042,7 @@ def handler(self, form_data: _TagsRecord, count: int): def test_prepare_event_payload_falls_back_when_hints_do_not_resolve(): """Unresolvable annotations still never expose the wrapped form entries.""" - def handler(self, form_data: "_UndefinedFormData"): # noqa: F821 # pyright: ignore[reportUndefinedVariable] + def handler(self, form_data: "_UndefinedFormData"): # noqa: F821 # ty:ignore[unresolved-reference] pass payload = _prepare_event_payload( @@ -3141,7 +3141,7 @@ async def sibling(self) -> str: DependentState.computed_vars["sibling"].add_dependency( DependentState, - StorageState.value, # pyright: ignore[reportArgumentType] + StorageState.value, # ty:ignore[invalid-argument-type] ) wired_app.add_page( lambda: rx.text( diff --git a/tests/units/reflex_base/event/processor/test_event_processor.py b/tests/units/reflex_base/event/processor/test_event_processor.py index e7a389b4392..eeab88145e9 100644 --- a/tests/units/reflex_base/event/processor/test_event_processor.py +++ b/tests/units/reflex_base/event/processor/test_event_processor.py @@ -155,7 +155,7 @@ async def _background_slow_logging_handler(value: str = "default"): _CALL_LOG.append({"value": value}) -_background_slow_logging_handler._reflex_background_task = True # type: ignore[attr-defined] +_background_slow_logging_handler._reflex_background_task = True # ty:ignore[unresolved-attribute] # Gates for coordinating supersede tests; tests create loop-local events here. _GATES: dict[str, asyncio.Event] = {} @@ -233,7 +233,7 @@ async def _superseding_root_handler(value: str = "default", child: str = "load") await ctx.enqueue(Event.from_event_type(child_event(value))[0]) -_superseding_root_handler._reflex_supersedes = True # type: ignore[attr-defined] +_superseding_root_handler._reflex_supersedes = True # ty:ignore[unresolved-attribute] async def _polling_handler(tick: int = 0, ticks: int = 0): @@ -264,7 +264,7 @@ async def _superseding_poll_root_handler(ticks: int = 0): await ctx.enqueue(Event.from_event_type(polling_event(0, ticks))[0]) -_superseding_poll_root_handler._reflex_supersedes = True # type: ignore[attr-defined] +_superseding_poll_root_handler._reflex_supersedes = True # ty:ignore[unresolved-attribute] async def _shared_refresh_handler(value: str = "default"): @@ -289,8 +289,8 @@ async def _shared_refresh_handler(value: str = "default"): _CALL_LOG.append({"value": value}) -_shared_refresh_handler._reflex_background_task = True # type: ignore[attr-defined] -_shared_refresh_handler._reflex_supersedes = True # type: ignore[attr-defined] +_shared_refresh_handler._reflex_background_task = True # ty:ignore[unresolved-attribute] +_shared_refresh_handler._reflex_supersedes = True # ty:ignore[unresolved-attribute] async def _refresh_spawner_handler(value: str = "default", gated: bool = False): @@ -306,7 +306,7 @@ async def _refresh_spawner_handler(value: str = "default", gated: bool = False): await ctx.enqueue(Event.from_event_type(shared_refresh_event(value))[0]) -_refresh_spawner_handler._reflex_background_task = True # type: ignore[attr-defined] +_refresh_spawner_handler._reflex_background_task = True # ty:ignore[unresolved-attribute] async def _refresh_fanout_handler(): @@ -339,8 +339,8 @@ async def _lingering_refresh_handler(value: str = "default", chain: bool = False _CALL_LOG.append({"value": value}) -_lingering_refresh_handler._reflex_background_task = True # type: ignore[attr-defined] -_lingering_refresh_handler._reflex_supersedes = True # type: ignore[attr-defined] +_lingering_refresh_handler._reflex_background_task = True # ty:ignore[unresolved-attribute] +_lingering_refresh_handler._reflex_supersedes = True # ty:ignore[unresolved-attribute] async def _counting_superseding_handler(tick: int = 0, limit: int = 3): @@ -359,7 +359,7 @@ async def _counting_superseding_handler(tick: int = 0, limit: int = 3): _CALL_LOG.append({"value": f"tick_{tick}"}) -_counting_superseding_handler._reflex_supersedes = True # type: ignore[attr-defined] +_counting_superseding_handler._reflex_supersedes = True # ty:ignore[unresolved-attribute] noop_event = EventHandler(fn=_noop_handler) @@ -545,7 +545,7 @@ async def test_native_queue_shutdown_is_suppressed( send_error = mocker.patch("reflex.utils.telemetry.send_error") console_error = mocker.patch("reflex.utils.console.error") queue: asyncio.Queue = asyncio.Queue() - queue.shutdown() + queue.shutdown() # ty:ignore[unresolved-attribute] processor._queue = queue await processor._process_queue() @@ -1562,7 +1562,7 @@ async def test_late_chained_invocation_stays_cancellable( assert first.txid in ep._futures late_ctx = dataclasses.replace( - ep._root_context.fork(token=token), # pyright: ignore[reportOptionalMemberAccess] + ep._root_context.fork(token=token), # ty:ignore[unresolved-attribute] parent_txid=first.txid, ) late = await ep.enqueue( diff --git a/tests/units/reflex_base/plugins/test_base.py b/tests/units/reflex_base/plugins/test_base.py index 7f4e9aa466b..397cffddca2 100644 --- a/tests/units/reflex_base/plugins/test_base.py +++ b/tests/units/reflex_base/plugins/test_base.py @@ -64,7 +64,7 @@ def test_register_route_default_is_noop(): """The base route hook accepts the staged context and contributes nothing.""" assert ( Plugin().register_route( - app_type=object, # pyright: ignore[reportArgumentType] + app_type=object, # ty:ignore[invalid-argument-type] add_page=lambda *args, **kwargs: None, has_app_page=lambda route: False, ) diff --git a/tests/units/reflex_base/test_otel.py b/tests/units/reflex_base/test_otel.py index 944e82c2a0c..95afc3a53fd 100644 --- a/tests/units/reflex_base/test_otel.py +++ b/tests/units/reflex_base/test_otel.py @@ -25,8 +25,8 @@ def _ctx(token: str = "tok", parent_txid: str | None = None) -> EventContext: return EventContext( token=token, - state_manager=None, # type: ignore[arg-type] - enqueue_impl=None, # type: ignore[arg-type] + state_manager=None, # ty:ignore[invalid-argument-type] + enqueue_impl=None, # ty:ignore[invalid-argument-type] parent_txid=parent_txid, ) diff --git a/tests/units/reflex_base/utils/pyi_generator/dataset/classvar_and_private.py b/tests/units/reflex_base/utils/pyi_generator/dataset/classvar_and_private.py index e9aa27b9243..b7ee8e9f0dc 100644 --- a/tests/units/reflex_base/utils/pyi_generator/dataset/classvar_and_private.py +++ b/tests/units/reflex_base/utils/pyi_generator/dataset/classvar_and_private.py @@ -30,7 +30,7 @@ class StrictComponent(Component): _valid_children: ClassVar[list[str]] = ["ChildA", "ChildB"] # The memoization mode. - _memoization_mode: ClassVar[Any] = None + _memoization_mode: ClassVar[Any] = None # ty:ignore[invalid-attribute-override] # A public prop that should appear in create(). visible_prop: Var[str] = field(doc="A prop visible in the stub.") diff --git a/tests/units/reflex_base/utils/pyi_generator/dataset/staticmethod_namespace.py b/tests/units/reflex_base/utils/pyi_generator/dataset/staticmethod_namespace.py index 3f5fc00f725..12a9e0b8dc7 100644 --- a/tests/units/reflex_base/utils/pyi_generator/dataset/staticmethod_namespace.py +++ b/tests/units/reflex_base/utils/pyi_generator/dataset/staticmethod_namespace.py @@ -29,7 +29,7 @@ def send_notification(message: str, level: str = "info") -> EventSpec: Returns: The event spec. """ - return EventSpec() # type: ignore[call-arg] + return EventSpec() # ty:ignore[missing-argument] class Notify(ComponentNamespace): diff --git a/tests/units/reflex_base/utils/pyi_generator/test_unit.py b/tests/units/reflex_base/utils/pyi_generator/test_unit.py index b862f15a5c9..770aa439d91 100644 --- a/tests/units/reflex_base/utils/pyi_generator/test_unit.py +++ b/tests/units/reflex_base/utils/pyi_generator/test_unit.py @@ -451,6 +451,21 @@ class ModeComp(Component): assert "mode: str =" not in result +def test_stub_class_field_default_kept_as_ellipsis(): + source = """ +from reflex_base.components.props import NoExtrasAllowedProps + +class SomeProps(NoExtrasAllowedProps): + required: str + optional: str | None = None +""" + result = _generate_stub_from_source(source) + # A class field's default decides whether it is required in the synthesized + # __init__, so its presence has to survive into the stub as `...`. + assert "required: str\n" in result + assert "optional: str | None = ..." in result + + def test_stub_classvar_preserved(): source = """ from typing import ClassVar diff --git a/tests/units/reflex_base/utils/test_deterministic_hash.py b/tests/units/reflex_base/utils/test_deterministic_hash.py index 44f9d5defca..b6e208072bb 100644 --- a/tests/units/reflex_base/utils/test_deterministic_hash.py +++ b/tests/units/reflex_base/utils/test_deterministic_hash.py @@ -317,13 +317,13 @@ def test_deterministic_hash_dataclass_field_contradicting_its_annotation( The value-keyed cache is gated on declared field types, so an instance that contradicts them reaches the cache lookup and is not hashable as a key. """ - probe = _KeyedProbe(name=["not", "a", "str"]) # pyright: ignore [reportArgumentType] + probe = _KeyedProbe(name=["not", "a", "str"]) # ty:ignore[invalid-argument-type] assert deterministic_hash(probe) == deterministic_hash( - _KeyedProbe(name=["not", "a", "str"]) # pyright: ignore [reportArgumentType] + _KeyedProbe(name=["not", "a", "str"]) # ty:ignore[invalid-argument-type] ) assert deterministic_hash(probe) != deterministic_hash( - _KeyedProbe(name=["other"]) # pyright: ignore [reportArgumentType] + _KeyedProbe(name=["other"]) # ty:ignore[invalid-argument-type] ) # The well-typed instances alongside it still take the cached path. assert deterministic_hash(_KeyedProbe(name="probe")) == deterministic_hash( diff --git a/tests/units/reflex_base/utils/test_form.py b/tests/units/reflex_base/utils/test_form.py index b87cd0c8216..e7389abd996 100644 --- a/tests/units/reflex_base/utils/test_form.py +++ b/tests/units/reflex_base/utils/test_form.py @@ -76,7 +76,7 @@ def test_form_data_is_immutable(): """A FormData cannot be changed after it is built.""" form_data = FormData(ITEMS) with pytest.raises(TypeError): - form_data["tag"] = "c" # pyright: ignore[reportIndexIssue] + form_data["tag"] = "c" # ty:ignore[invalid-assignment] with pytest.raises(AttributeError): form_data.other = 1 # pyright: ignore[reportAttributeAccessIssue] @@ -502,7 +502,7 @@ def test_transform_form_data_bracketed_names_to_form_data(hint: Any): class _UnresolvableData(TypedDict): tag: list[str] - amount: "Decimal" # noqa: F821 # pyright: ignore[reportUndefinedVariable] + amount: "Decimal" # noqa: F821 # ty:ignore[unresolved-reference] def test_transform_form_data_coerces_around_unresolvable_fields(): diff --git a/tests/units/reflex_base/utils/test_format.py b/tests/units/reflex_base/utils/test_format.py index c97d38cb25a..a0b9ca481cd 100644 --- a/tests/units/reflex_base/utils/test_format.py +++ b/tests/units/reflex_base/utils/test_format.py @@ -53,7 +53,7 @@ def test_format_data_editor_column_deprecated(mocker: MockerFixture): """ deprecate = mocker.patch("reflex_base.utils.console.deprecate") - assert format.format_data_editor_column("Name") == { + assert format.format_data_editor_column("Name") == { # ty:ignore[deprecated] "title": "Name", "id": "name", "type": "str", diff --git a/tests/units/reflex_base/utils/test_log.py b/tests/units/reflex_base/utils/test_log.py index dfdf620957e..348250f8cfd 100644 --- a/tests/units/reflex_base/utils/test_log.py +++ b/tests/units/reflex_base/utils/test_log.py @@ -236,7 +236,7 @@ def test_set_log_level_env_propagation(monkeypatch): def test_set_log_level_rejects_strings(): """Passing a raw string raises a TypeError.""" with pytest.raises(TypeError): - log.set_log_level("debug") # pyright: ignore[reportArgumentType] + log.set_log_level("debug") # ty:ignore[invalid-argument-type] def test_set_log_level_none_is_noop(): @@ -344,7 +344,7 @@ def test_deprecate_skips_frames_compiled_from_strings(capsys): {"log": log}, namespace, ) - namespace["emit"]() # pyright: ignore[reportCallIssue] + namespace["emit"]() # ty:ignore[call-non-callable] out, _ = capsys.readouterr() assert "" not in out assert "test_log.py" in out @@ -594,7 +594,7 @@ def test_console_and_pipeline_share_one_log_file(monkeypatch, tmp_path): monkeypatch.setattr( console, "log_file_console", - console.log_file_console.__wrapped__, # pyright: ignore[reportFunctionMemberAccess] + console.log_file_console.__wrapped__, # ty:ignore[unresolved-attribute] ) reflex_logger = logging.getLogger("reflex") reflex_logger.addHandler(handler) @@ -624,7 +624,7 @@ def _fresh_file_handler( """ log_file = tmp_path / "full.log" monkeypatch.setenv("REFLEX_LOG_FILE", str(log_file)) - handler = log._file_handler.__wrapped__() # pyright: ignore[reportFunctionMemberAccess] + handler = log._file_handler.__wrapped__() # ty:ignore[unresolved-attribute] monkeypatch.setattr(log, "_file_handler", lambda: handler) return handler, log_file @@ -667,7 +667,7 @@ def test_log_file_console_targets_file_after_external_close( monkeypatch.setattr( console, "log_file_console", - console.log_file_console.__wrapped__, # pyright: ignore[reportFunctionMemberAccess] + console.log_file_console.__wrapped__, # ty:ignore[unresolved-attribute] ) try: # What granian's post-fork dictConfig does to every existing handler. @@ -683,7 +683,7 @@ def test_log_file_console_targets_file_after_external_close( def test_cached_log_file_console_survives_external_close(monkeypatch, tmp_path, capsys): """A file console created before the close keeps writing to the file.""" handler, log_file = _fresh_file_handler(monkeypatch, tmp_path) - file_console = console.log_file_console.__wrapped__() # pyright: ignore[reportFunctionMemberAccess] + file_console = console.log_file_console.__wrapped__() # ty:ignore[unresolved-attribute] monkeypatch.setattr(console, "log_file_console", lambda: file_console) try: console.print_to_log_file("record before close") @@ -703,7 +703,7 @@ def test_file_handler_truncates_previous_run(monkeypatch, tmp_path): log_file = tmp_path / "full.log" log_file.write_text("records from a previous run\n", encoding="utf-8") monkeypatch.setenv("REFLEX_LOG_FILE", str(log_file)) - handler = log._file_handler.__wrapped__() # pyright: ignore[reportFunctionMemberAccess] + handler = log._file_handler.__wrapped__() # ty:ignore[unresolved-attribute] handler.close() assert log_file.read_text(encoding="utf-8") == "" diff --git a/tests/units/reflex_base/utils/test_types.py b/tests/units/reflex_base/utils/test_types.py index 4227b0edd9a..595119b9523 100644 --- a/tests/units/reflex_base/utils/test_types.py +++ b/tests/units/reflex_base/utils/test_types.py @@ -285,7 +285,7 @@ def test_isinstance_checks_type_parameter_bounds() -> None: t = TypeVar("t") bounded = TypeVar("bounded", bound=str) constrained = TypeVar("constrained", int, str) - forward = TypeVar("forward", bound="Unresolvable") # noqa: F821 # pyright: ignore[reportUndefinedVariable] + forward = TypeVar("forward", bound="Unresolvable") # noqa: F821 # ty:ignore[unresolved-reference] assert _isinstance(1, t, nested=1, treat_var_as_type=False) assert _isinstance("x", t | None, nested=1, treat_var_as_type=False) assert not _isinstance("x", list[t], nested=1, treat_var_as_type=False) # pyright: ignore[reportGeneralTypeIssues] @@ -360,7 +360,7 @@ def test_resolve_type_alias_unwraps_annotated(alias_cls: type) -> None: assert resolve_type_alias(Annotated[Annotated[int, "a"], "b"]) is int assert resolve_type_alias(Annotated[int | str, "meta"]) == int | str # An alias on either side of the annotation resolves through it. - assert resolve_type_alias(Annotated[alias_cls("Name", str), "meta"]) is str + assert resolve_type_alias(Annotated[alias_cls("Name", str), "meta"]) is str # ty:ignore[invalid-type-form] assert resolve_type_alias(alias_cls("Meta", Annotated[str, "meta"])) is str # A union member keeps resolving. assert resolve_type_alias(Annotated[int, "meta"] | str) == int | str @@ -615,7 +615,7 @@ class Plain(Concrete): class _Unresolved(TypedDict): - value: _FieldT # pyright: ignore[reportGeneralTypeIssues] + value: _FieldT # ty:ignore[unbound-type-variable] def test_get_typed_dict_field_types_rejects_unresolved_type_variables(): diff --git a/tests/units/reflex_base/vars/test_base.py b/tests/units/reflex_base/vars/test_base.py index 242cf2e85a9..d2b81451b99 100644 --- a/tests/units/reflex_base/vars/test_base.py +++ b/tests/units/reflex_base/vars/test_base.py @@ -96,7 +96,7 @@ def test_custom_field_attr_survives_annotated_rebuild(): setattr(f, _MARKER_ATTR, "tag") class MyState(EvenMoreBasicBaseState): - name: str = f # pyright: ignore[reportAssignmentType] + name: str = f # ty:ignore[invalid-assignment] rebuilt = MyState.get_fields()["name"] assert getattr(rebuilt, _MARKER_ATTR, None) == "tag" @@ -136,10 +136,10 @@ def test_reserved_annotation_attr_not_copied(): it would shadow the real class annotation. """ f = field("x") - f.annotation = int # pyright: ignore[reportAttributeAccessIssue] + f.annotation = int # ty:ignore[unresolved-attribute] class MyState(EvenMoreBasicBaseState): - name: str = f # pyright: ignore[reportAssignmentType] + name: str = f # ty:ignore[invalid-assignment] rebuilt = MyState.get_fields()["name"] assert "annotation" not in rebuilt.__dict__ @@ -161,13 +161,13 @@ def __init__(self) -> None: check = Check() f = field("x") - f._check = check # pyright: ignore[reportAttributeAccessIssue] + f._check = check # ty:ignore[unresolved-attribute] class MyState(EvenMoreBasicBaseState): - name: str = f # pyright: ignore[reportAssignmentType] + name: str = f # ty:ignore[invalid-assignment] rebuilt = MyState.get_fields()["name"] - assert rebuilt._check is check # pyright: ignore[reportAttributeAccessIssue] + assert rebuilt._check is check # ty:ignore[unresolved-attribute] def _type_alias_types() -> list[type]: @@ -402,7 +402,7 @@ class Point: pass def serialize_point(value: Point) -> str: - return value.label # pyright: ignore[reportAttributeAccessIssue] + return value.label # ty:ignore[unresolved-attribute] serializers.serializer(serialize_point) try: @@ -1294,7 +1294,7 @@ def test_field_subclass_is_kept(): """A field declared with a Field subclass stays one wherever it is copied.""" class Parent(State): - annotated: int = TaggedField(default=1, tag="a") # pyright: ignore[reportAssignmentType] + annotated: int = TaggedField(default=1, tag="a") # ty:ignore[invalid-assignment] generic: TaggedField[int] = TaggedField(default=2, tag="g") unannotated = TaggedField(default="x", tag="u") @@ -1305,7 +1305,7 @@ class AnnotatedChild(Parent): annotated: int = 5 class Mixin(State, mixin=True): - mixed: int = TaggedField(default=4, tag="m") # pyright: ignore[reportAssignmentType] + mixed: int = TaggedField(default=4, tag="m") # ty:ignore[invalid-assignment] class UsesMixin(Mixin, State): pass @@ -1377,9 +1377,9 @@ def test_backend_field_is_not_type_checked(): T = TypeVar("T") class Model(EvenMoreBasicBaseState): - _value: T # pyright: ignore[reportGeneralTypeIssues] + _value: T # ty:ignore[unbound-type-variable] - model = Model() # pyright: ignore[reportCallIssue] + model = Model() # ty:ignore[missing-argument] model._value = 1 assert model._value == 1 @@ -1497,7 +1497,7 @@ class Parent(State): count: int = 0 class Child(Parent): - count: ClassVar[int] = 5 # pyright: ignore[reportIncompatibleVariableOverride] + count: ClassVar[int] = 5 # ty:ignore[invalid-attribute-override] assert Child.get_fields()["count"] is Parent.get_fields()["count"] assert "count" not in Child.base_vars @@ -1594,7 +1594,7 @@ class S(BaseState): for value in (["a"], ("a",)): with pytest.raises(TypeError) as exc_info: - S.items = value # pyright: ignore[reportAttributeAccessIssue] + S.items = value # ty:ignore[invalid-assignment] assert f"{S.__name__}.__fields__['items'].set_default(...)" in str( exc_info.value ) @@ -1679,12 +1679,12 @@ class Parent(BaseState): _config: ClassVar[str] = "old" class Child(Parent): - _value: ClassVar[str] = "child" # pyright: ignore[reportIncompatibleVariableOverride] + _value: ClassVar[str] = "child" # ty:ignore[invalid-attribute-override] Child._value = "new" Parent._config = "new" Parent.extra = 1 # pyright: ignore[reportAttributeAccessIssue] - assert (Child._value, Parent._config, Parent.extra) == ("new", "new", 1) # pyright: ignore[reportAttributeAccessIssue] + assert (Child._value, Parent._config, Parent.extra) == ("new", "new", 1) # ty:ignore[unresolved-attribute] assert Parent.get_fields()["_value"].default == "old" @@ -1757,11 +1757,11 @@ class MismatchState(BaseState): @computed_var def cached(self) -> int: - return str(self.count) # pyright: ignore [reportReturnType] + return str(self.count) # ty:ignore[invalid-return-type] @computed_var(cache=False) def uncached(self) -> int: - return str(self.count) # pyright: ignore [reportReturnType] + return str(self.count) # ty:ignore[invalid-return-type] state = MismatchState() with caplog.at_level(logging.ERROR, logger="reflex_base.vars.base"): @@ -1790,11 +1790,11 @@ class AsyncMismatchState(BaseState): @computed_var async def cached(self) -> int: - return str(self.count) # pyright: ignore [reportReturnType] + return str(self.count) # ty:ignore[invalid-return-type] @computed_var(cache=False) async def uncached(self) -> int: - return str(self.count) # pyright: ignore [reportReturnType] + return str(self.count) # ty:ignore[invalid-return-type] state = AsyncMismatchState() with caplog.at_level(logging.ERROR, logger="reflex_base.vars.base"): @@ -2029,8 +2029,8 @@ def test_field_read_wraps_mutable_values(annotation: Any, value: Any): ) state = state_cls() state.item = value # pyright: ignore [reportAttributeAccessIssue] - assert isinstance(state.item, MutableProxy) # pyright: ignore [reportAttributeAccessIssue] - assert state.item.__wrapped__ is value # pyright: ignore [reportAttributeAccessIssue] + assert isinstance(state.item, MutableProxy) # ty:ignore[unresolved-attribute] + assert state.item.__wrapped__ is value # ty:ignore[unresolved-attribute] def test_cached_computed_var_checks_return_type_on_recompute_only( @@ -2133,13 +2133,13 @@ class DepthState(BaseState): @computed_var def as_ints(self) -> list[int]: - return self.wrong_elements # pyright: ignore[reportReturnType] + return self.wrong_elements # ty:ignore[invalid-return-type] environment.REFLEX_ENV_MODE.set(env_mode) state = DepthState() with caplog.at_level(logging.ERROR, logger="reflex_base.vars.base"): - state.items = ["a"] # pyright: ignore[reportAttributeAccessIssue] + state.items = ["a"] # ty:ignore[invalid-assignment] state.wrong_elements = ["b"] _ = state.as_ints name = type(state).__name__ @@ -2149,7 +2149,7 @@ def as_ints(self) -> list[int]: caplog.clear() with caplog.at_level(logging.ERROR, logger="reflex_base.vars.base"): - state.items = "not a list" # pyright: ignore[reportAttributeAccessIssue] + state.items = "not a list" # ty:ignore[invalid-assignment] assert any(f"{name}.items" in r.getMessage() for r in caplog.records) diff --git a/tests/units/reflex_bench/drivers/test_app_process.py b/tests/units/reflex_bench/drivers/test_app_process.py index ce309048614..2e75d55e5ad 100644 --- a/tests/units/reflex_bench/drivers/test_app_process.py +++ b/tests/units/reflex_bench/drivers/test_app_process.py @@ -151,7 +151,7 @@ def configure(**spec: Any) -> dict[str, str]: path.write_text(json.dumps(spec), encoding="utf-8") env = {**subject_env(Path(sys.executable)), "FAKE_REFLEX": str(path)} env.pop("PYTHONSAFEPATH", None) - return env + return env # ty:ignore[invalid-return-type] return configure diff --git a/tests/units/reflex_bench/drivers/test_editor.py b/tests/units/reflex_bench/drivers/test_editor.py index 53e915c34e3..6a128f50efe 100644 --- a/tests/units/reflex_bench/drivers/test_editor.py +++ b/tests/units/reflex_bench/drivers/test_editor.py @@ -125,7 +125,7 @@ def time_ns() -> int: t0 = edit.write() assert [name for name, _ in events] == ["fsync", "t0", "replace"] assert events[1] == ("t0", t0) - src, dst = events[2][1] # pyright: ignore[reportGeneralTypeIssues] + src, dst = events[2][1] # ty:ignore[not-iterable] # A sibling on the same file system, named so file watchers ignore it # (watchfiles' default filter skips names ending in "~"). assert src.parent == dst.parent == target.path.parent diff --git a/tests/units/reflex_bench/factories.py b/tests/units/reflex_bench/factories.py index 3a3e4c029cf..69673bccd51 100644 --- a/tests/units/reflex_bench/factories.py +++ b/tests/units/reflex_bench/factories.py @@ -95,7 +95,7 @@ def make_machine(profile_id: str = "test-profile", **changes: Any) -> MachineDoc "virtualized": False, "tools": {"bun": True, "node": True, "chromium": False}, } - machine.update(changes) # pyright: ignore[reportCallIssue, reportArgumentType] + machine.update(changes) # ty:ignore[invalid-argument-type] return machine @@ -131,7 +131,7 @@ def make_entry( "params": dict(params or {}), "kind": "time", "version": version, - "status": status, # pyright: ignore[reportAssignmentType] + "status": status, # ty:ignore[invalid-argument-type] "error": error, "traceback_tail": None, "dims": {}, diff --git a/tests/units/reflex_bench/fixtures/test_generate.py b/tests/units/reflex_bench/fixtures/test_generate.py index 7e33e7b1ce6..a71e678ec91 100644 --- a/tests/units/reflex_bench/fixtures/test_generate.py +++ b/tests/units/reflex_bench/fixtures/test_generate.py @@ -89,7 +89,7 @@ def test_pages_and_routes(tmp_path: Path, pages: int): assert files == sorted(f"page_{index}.py" for index in range(pages)) module = ast.parse((tmp_path / "genapp" / "genapp.py").read_text(encoding="utf-8")) routes = { - call.args[0].id: next(k.value.value for k in call.keywords if k.arg == "route") # pyright: ignore[reportAttributeAccessIssue] + call.args[0].id: next(k.value.value for k in call.keywords if k.arg == "route") # ty:ignore[unresolved-attribute] for call in ast.walk(module) if isinstance(call, ast.Call) and isinstance(call.func, ast.Attribute) @@ -185,7 +185,7 @@ def test_the_output_imports_only_reflex(tmp_path: Path): imported.add(node.module) assert "reflex" in imported # Besides reflex, only the app's own modules. - assert {name for name in imported if name.split(".")[0] != "genapp"} == {"reflex"} + assert {name for name in imported if name.split(".")[0] != "genapp"} == {"reflex"} # ty:ignore[unresolved-attribute] def test_rxconfig_has_only_the_radix_guard(tmp_path: Path): @@ -213,7 +213,7 @@ def test_the_state_tree(tmp_path: Path): def members(name: str) -> tuple[list[str], list[str], list[str]]: body = classes[name].body - fields = [node.target.id for node in body if isinstance(node, ast.AnnAssign)] # pyright: ignore[reportAttributeAccessIssue] + fields = [node.target.id for node in body if isinstance(node, ast.AnnAssign)] # ty:ignore[unresolved-attribute] functions = [node for node in body if isinstance(node, ast.FunctionDef)] by_decorator = { decorator: [ diff --git a/tests/units/reflex_bench/report/test_format.py b/tests/units/reflex_bench/report/test_format.py index 2da25708c78..6e66fd12871 100644 --- a/tests/units/reflex_bench/report/test_format.py +++ b/tests/units/reflex_bench/report/test_format.py @@ -90,7 +90,7 @@ def _comparison(**changes) -> ComparisonDoc: "verdict": "regressed", "runs_needed": None, } - comparison.update(changes) # pyright: ignore[reportCallIssue, reportArgumentType] + comparison.update(changes) # ty:ignore[invalid-argument-type] return comparison diff --git a/tests/units/reflex_bench/suites/fakes.py b/tests/units/reflex_bench/suites/fakes.py index 4c6b055ba14..a3313d44a0e 100644 --- a/tests/units/reflex_bench/suites/fakes.py +++ b/tests/units/reflex_bench/suites/fakes.py @@ -353,7 +353,7 @@ def interactive(self, app: FakeApp, path: str = "/") -> Interactive: FakeBrowser.configure(tab) self.tabs.append(tab) return Interactive( - tab=tab, # pyright: ignore[reportArgumentType] + tab=tab, # ty:ignore[invalid-argument-type] interactive_ready=3.0, nav_to_interactive_s=0.8, fcp_s=2.5, diff --git a/tests/units/reflex_bench/suites/test_hmr.py b/tests/units/reflex_bench/suites/test_hmr.py index d5187628bd4..415d28ddfd7 100644 --- a/tests/units/reflex_bench/suites/test_hmr.py +++ b/tests/units/reflex_bench/suites/test_hmr.py @@ -672,7 +672,7 @@ def test_granian_worker_is_the_other_listener_of_the_backend_port(): worker_pid = int(root.stdout.readline()) app = FakeApp(Path(), Path(), mode="dev", reflex_version=None, env={}) app.pid, app.backend_url = root.pid, f"http://localhost:{port}" - supervisor, worker = hmr.granian_processes(app) # pyright: ignore[reportArgumentType] + supervisor, worker = hmr.granian_processes(app) # ty:ignore[invalid-argument-type] assert (supervisor.pid, worker.pid) == (root.pid, worker_pid) finally: for proc in [*tree.children(recursive=True), tree]: @@ -688,4 +688,4 @@ def test_granian_processes_need_a_listening_worker(): probe.bind(("127.0.0.1", 0)) app.backend_url = f"http://localhost:{probe.getsockname()[1]}" with pytest.raises(LookupError, match="no process of the app listens"): - hmr.granian_processes(app) # pyright: ignore[reportArgumentType] + hmr.granian_processes(app) # ty:ignore[invalid-argument-type] diff --git a/tests/units/reflex_bench/test_ab.py b/tests/units/reflex_bench/test_ab.py index 15317eb55f7..f089b2af5c9 100644 --- a/tests/units/reflex_bench/test_ab.py +++ b/tests/units/reflex_bench/test_ab.py @@ -51,7 +51,8 @@ def cleanup(self, ctx: Context) -> None: record.append(f"cleanup {ctx.arm}") bench = Benchmark.define( - Recorder, **{"id": "t.ab", "metrics": {"wall": WALL}, **define} + Recorder, + **{"id": "t.ab", "metrics": {"wall": WALL}, **define}, # ty:ignore[invalid-argument-type] ) return Planned(bench, bench.expand()[0]) @@ -62,7 +63,7 @@ def _schedulers( head: Subject | None = None, **policy: Any, ) -> tuple[Scheduler, Scheduler]: - shared = Policy(**{"runs": 3, **policy}) + shared = Policy(**{"runs": 3, **policy}) # ty:ignore[invalid-argument-type] return ( Scheduler(base or make_subject(), shared, home=tmp_path, seed=1), Scheduler(head or make_subject(), shared, home=tmp_path, seed=1), diff --git a/tests/units/reflex_bench/test_registry.py b/tests/units/reflex_bench/test_registry.py index fc313dd45c0..852f3bb6fbe 100644 --- a/tests/units/reflex_bench/test_registry.py +++ b/tests/units/reflex_bench/test_registry.py @@ -143,7 +143,7 @@ class Other(_Sampler): def test_invalid_declarations(kwargs, message): arguments = {"id": "t.x", "metrics": {"wall": WALL}, **kwargs} with pytest.raises(ValueError, match=message): - Benchmark.define(_Sampler, **arguments) + Benchmark.define(_Sampler, **arguments) # ty:ignore[invalid-argument-type] def test_class_without_sample_is_rejected(): @@ -156,9 +156,9 @@ class NoSample: def test_metric_validation(): with pytest.raises(ValueError, match="direction"): - Metric(unit="s", direction="up") # pyright: ignore[reportArgumentType] + Metric(unit="s", direction="up") # ty:ignore[invalid-argument-type] with pytest.raises(ValueError, match="assume"): - Metric(unit="s", direction="lower", assume="maybe") # pyright: ignore[reportArgumentType] + Metric(unit="s", direction="lower", assume="maybe") # ty:ignore[invalid-argument-type] with pytest.raises(ValueError, match="unit"): Metric(unit="", direction="lower") assert Metric(unit="ev/s", direction="higher").family == "rate" @@ -288,7 +288,7 @@ def test_normalize_rejects_bad_return_types_and_extra(two_metrics): with pytest.raises(TypeError, match="must return None, a dict"): two_metrics.normalize([1, 2], 0.1) with pytest.raises(TypeError, match="extra must be a dict"): - two_metrics.normalize(SampleResult({"bytes": 1}, [1]), 0.1) # pyright: ignore[reportArgumentType] + two_metrics.normalize(SampleResult({"bytes": 1}, [1]), 0.1) # ty:ignore[invalid-argument-type] with pytest.raises(ValueError, match="JSON-serializable"): two_metrics.normalize(SampleResult({"bytes": 1}, {"x": object()}), 0.1) diff --git a/tests/units/reflex_bench/test_scheduler.py b/tests/units/reflex_bench/test_scheduler.py index c2b6ca792f7..49c8cc504d9 100644 --- a/tests/units/reflex_bench/test_scheduler.py +++ b/tests/units/reflex_bench/test_scheduler.py @@ -55,7 +55,7 @@ def run(self: Any, ctx: Context) -> Any: hooks = ("setup_cache", "setup", "prepare", "sample", "conclude", "cleanup") recorder = type("Recorder", (), {name: hook(name) for name in hooks}) arguments = {"id": "t.rec", "metrics": {"wall": WALL}, **define} - bench = Benchmark.define(recorder, **arguments) + bench = Benchmark.define(recorder, **arguments) # ty:ignore[invalid-argument-type] return Planned(bench, bench.expand()[0]) diff --git a/tests/units/reflex_bench/test_schema.py b/tests/units/reflex_bench/test_schema.py index 505999b8870..9f9bb1c5b05 100644 --- a/tests/units/reflex_bench/test_schema.py +++ b/tests/units/reflex_bench/test_schema.py @@ -36,7 +36,7 @@ def test_valid_document_round_trips(tmp_path: Path, doc: schema.ResultDoc): def test_missing_profile_id_fails_validation_and_dump_refuses( tmp_path: Path, doc: schema.ResultDoc ): - del doc["machine"]["profile_id"] # pyright: ignore[reportGeneralTypeIssues] + del doc["machine"]["profile_id"] # ty:ignore[invalid-argument-type] assert "machine.profile_id: missing" in schema.validate(doc) path = tmp_path / "result.json" with pytest.raises(schema.SchemaError, match=r"machine\.profile_id: missing"): @@ -74,14 +74,14 @@ def test_fixture_is_optional_and_nullable(doc: schema.ResultDoc): def test_interrupted_is_an_optional_boolean(doc: schema.ResultDoc): doc["interrupted"] = True assert schema.validate(doc) == [] - doc["interrupted"] = "yes" # pyright: ignore[reportGeneralTypeIssues] + doc["interrupted"] = "yes" # ty:ignore[invalid-assignment] assert schema.validate(doc) == ["interrupted: expected a boolean"] def test_unknown_keys_are_allowed_for_forward_compatibility(doc: schema.ResultDoc): extended = copy.deepcopy(doc) - extended["future"] = {"anything": 1} # pyright: ignore[reportGeneralTypeIssues] - extended["benchmarks"][0]["future_field"] = [1, 2] # pyright: ignore[reportGeneralTypeIssues] + extended["future"] = {"anything": 1} # ty:ignore[invalid-key] + extended["benchmarks"][0]["future_field"] = [1, 2] # ty:ignore[invalid-key] assert schema.validate(extended) == [] @@ -93,8 +93,8 @@ def test_wrong_schema_id_is_rejected(doc: schema.ResultDoc): def test_enums_are_checked(doc: schema.ResultDoc): - doc["benchmarks"][0]["status"] = "crashed" # pyright: ignore[reportGeneralTypeIssues] - doc["benchmarks"][0]["metrics"]["wall"]["direction"] = "up" # pyright: ignore[reportGeneralTypeIssues] + doc["benchmarks"][0]["status"] = "crashed" # ty:ignore[invalid-assignment] + doc["benchmarks"][0]["metrics"]["wall"]["direction"] = "up" # ty:ignore[invalid-assignment] errors = schema.validate(doc) assert any( e.startswith("benchmarks[0].status: expected one of ok,") for e in errors @@ -118,9 +118,9 @@ def test_empty_subjects_are_rejected(doc: schema.ResultDoc): def test_nested_required_keys_are_checked(doc: schema.ResultDoc): - del doc["benchmarks"][0]["metrics"]["wall"]["unit"] # pyright: ignore[reportGeneralTypeIssues] - del doc["benchmarks"][0]["sample_meta"][0]["warmup"] # pyright: ignore[reportGeneralTypeIssues] - doc["invocation"] = [] # pyright: ignore[reportGeneralTypeIssues] + del doc["benchmarks"][0]["metrics"]["wall"]["unit"] # ty:ignore[invalid-argument-type] + del doc["benchmarks"][0]["sample_meta"][0]["warmup"] # ty:ignore[invalid-argument-type] + doc["invocation"] = [] # ty:ignore[invalid-assignment] assert schema.validate(doc) == [ "invocation: expected an object, got list", "benchmarks[0].sample_meta[0].warmup: missing", @@ -162,7 +162,7 @@ def test_wrong_container_types_are_rejected( @pytest.mark.parametrize(("key", "value"), [("warmup", "false"), ("arm", ["A"])]) def test_sample_meta_types_are_checked(doc: schema.ResultDoc, key: str, value: Any): - doc["benchmarks"][0]["sample_meta"][1][key] = value + doc["benchmarks"][0]["sample_meta"][1][key] = value # ty:ignore[invalid-key] assert schema.validate(doc) == [ "benchmarks[0].sample_meta[1]: arm must be a string, warmup a boolean" ] diff --git a/tests/units/reflex_bench/test_stats.py b/tests/units/reflex_bench/test_stats.py index eea4061f08e..fe96d537845 100644 --- a/tests/units/reflex_bench/test_stats.py +++ b/tests/units/reflex_bench/test_stats.py @@ -372,11 +372,11 @@ def test_verdict_too_few_samples_is_inconclusive_never_unchanged(): def test_verdict_requires_significance_and_the_whole_ci_past_the_threshold(): kwargs = {"direction": "lower", "threshold": 0.03, "alpha": 0.01} - assert stats.verdict(0.1, (0.05, 0.15), 0.001, **kwargs) == "regressed" - assert stats.verdict(0.1, (0.05, 0.15), 0.02, **kwargs) == "inconclusive" - assert stats.verdict(0.05, (0.01, 0.09), 0.001, **kwargs) == "inconclusive" - assert stats.verdict(-0.1, (-0.15, -0.05), 0.001, **kwargs) == "improved" - assert stats.verdict(0.0, (-0.02, 0.02), 0.9, **kwargs) == "unchanged" + assert stats.verdict(0.1, (0.05, 0.15), 0.001, **kwargs) == "regressed" # ty:ignore[invalid-argument-type] + assert stats.verdict(0.1, (0.05, 0.15), 0.02, **kwargs) == "inconclusive" # ty:ignore[invalid-argument-type] + assert stats.verdict(0.05, (0.01, 0.09), 0.001, **kwargs) == "inconclusive" # ty:ignore[invalid-argument-type] + assert stats.verdict(-0.1, (-0.15, -0.05), 0.001, **kwargs) == "improved" # ty:ignore[invalid-argument-type] + assert stats.verdict(0.0, (-0.02, 0.02), 0.9, **kwargs) == "unchanged" # ty:ignore[invalid-argument-type] def test_exact_metrics_skip_the_tests(): @@ -418,10 +418,10 @@ def test_compare_samples_with_a_zero_base_median_compares_absolutely(): assert comparison.p < 0.01 # No relative threshold applies to an absolute difference. kwargs = {"direction": "lower", "threshold": 0.0, "alpha": 0.01} - assert stats.verdict(5.0, comparison.ci, comparison.p, **kwargs) == "regressed" - assert stats.verdict(-5.0, (-5.0, -5.0), comparison.p, **kwargs) == "improved" - assert stats.verdict(0.0, (0.0, 0.0), 1.0, **kwargs) == "unchanged" - assert stats.verdict(0.5, (-0.5, 1.0), 0.2, **kwargs) == "inconclusive" + assert stats.verdict(5.0, comparison.ci, comparison.p, **kwargs) == "regressed" # ty:ignore[invalid-argument-type] + assert stats.verdict(-5.0, (-5.0, -5.0), comparison.p, **kwargs) == "improved" # ty:ignore[invalid-argument-type] + assert stats.verdict(0.0, (0.0, 0.0), 1.0, **kwargs) == "unchanged" # ty:ignore[invalid-argument-type] + assert stats.verdict(0.5, (-0.5, 1.0), 0.2, **kwargs) == "inconclusive" # ty:ignore[invalid-argument-type] # Too few samples for a CI still give the absolute effect. few = stats.compare_samples([0.0] * 3, [5.0] * 3) assert (few.mode, few.effect, few.ci) == ("absolute", 5.0, None) @@ -555,7 +555,7 @@ def _series(name: str) -> tuple[list[float], list[float]]: Returns: The x and y values. """ - return { + return { # ty:ignore[invalid-return-type] "N4": ([1, 2, 3, 4], [2.1, 3.9, 6.2, 7.8]), "N5": ( [0, 1000, 2000, 3000, 4000], diff --git a/tests/units/reflex_build_sdk/_async/resources/test_projects.py b/tests/units/reflex_build_sdk/_async/resources/test_projects.py index 07f4cb43ffd..6f8f04794b3 100644 --- a/tests/units/reflex_build_sdk/_async/resources/test_projects.py +++ b/tests/units/reflex_build_sdk/_async/resources/test_projects.py @@ -441,7 +441,9 @@ async def test_roles_preview_update(client: AsyncReflexBuild, mock_api: MockAPI) ), ) assert await client.projects.roles.preview_update( - PROJECT_ID, ROLE_ID, **ROLE_BODY + PROJECT_ID, + ROLE_ID, + **ROLE_BODY, # ty:ignore[invalid-argument-type] ) == RoleUpdatePreview( gained=["can_view_audit_logs"], lost=[], diff --git a/tests/units/reflex_build_sdk/_async/resources/test_security_reviews.py b/tests/units/reflex_build_sdk/_async/resources/test_security_reviews.py index c3af3b20a1c..c38d3c45c33 100644 --- a/tests/units/reflex_build_sdk/_async/resources/test_security_reviews.py +++ b/tests/units/reflex_build_sdk/_async/resources/test_security_reviews.py @@ -110,7 +110,8 @@ async def test_get(client: AsyncReflexBuild, mock_api: MockAPI): job_id=JOB_ID, status="complete", result=SecurityReviewResult( - summary="One issue.", violations=[SecurityViolation(**VIOLATION)] + summary="One issue.", + violations=[SecurityViolation(**VIOLATION)], # ty:ignore[invalid-argument-type] ), ) diff --git a/tests/units/reflex_build_sdk/_sync/resources/test_projects.py b/tests/units/reflex_build_sdk/_sync/resources/test_projects.py index 9f31bf2614b..aa5048294bb 100644 --- a/tests/units/reflex_build_sdk/_sync/resources/test_projects.py +++ b/tests/units/reflex_build_sdk/_sync/resources/test_projects.py @@ -434,7 +434,9 @@ def test_roles_preview_update(client: ReflexBuild, mock_api: MockAPI): ), ) assert client.projects.roles.preview_update( - PROJECT_ID, ROLE_ID, **ROLE_BODY + PROJECT_ID, + ROLE_ID, + **ROLE_BODY, # ty:ignore[invalid-argument-type] ) == RoleUpdatePreview( gained=["can_view_audit_logs"], lost=[], diff --git a/tests/units/reflex_build_sdk/_sync/resources/test_security_reviews.py b/tests/units/reflex_build_sdk/_sync/resources/test_security_reviews.py index 938dcbb827b..8393d3d6a24 100644 --- a/tests/units/reflex_build_sdk/_sync/resources/test_security_reviews.py +++ b/tests/units/reflex_build_sdk/_sync/resources/test_security_reviews.py @@ -109,7 +109,8 @@ def test_get(client: ReflexBuild, mock_api: MockAPI): job_id=JOB_ID, status="complete", result=SecurityReviewResult( - summary="One issue.", violations=[SecurityViolation(**VIOLATION)] + summary="One issue.", + violations=[SecurityViolation(**VIOLATION)], # ty:ignore[invalid-argument-type] ), ) diff --git a/tests/units/reflex_build_sdk/schema_check.py b/tests/units/reflex_build_sdk/schema_check.py index 35a5a5e8a36..dc3340a56fa 100644 --- a/tests/units/reflex_build_sdk/schema_check.py +++ b/tests/units/reflex_build_sdk/schema_check.py @@ -175,7 +175,7 @@ def model_problems( hints = typing.get_type_hints(model) properties = component.get("properties", {}) required = set(component.get("required", [])) - fields = dataclasses.fields(model) + fields = dataclasses.fields(model) # ty:ignore[invalid-argument-type] mapped = {json_key(field) for field in fields} problems = [ f"{model.__name__}: no field for {key!r}" diff --git a/tests/units/reflex_build_sdk/test_base.py b/tests/units/reflex_build_sdk/test_base.py index 74361cdfcd3..d3d60f0a072 100644 --- a/tests/units/reflex_build_sdk/test_base.py +++ b/tests/units/reflex_build_sdk/test_base.py @@ -33,7 +33,7 @@ def _client(**kwargs: Any) -> BaseClient: "timeout": None, "max_retries": DEFAULT_MAX_RETRIES, } - return BaseClient(**(settings | kwargs)) + return BaseClient(**(settings | kwargs)) # ty:ignore[invalid-argument-type] def _request(method: str = "GET") -> Request: diff --git a/tests/units/reflex_build_sdk/test_deploy.py b/tests/units/reflex_build_sdk/test_deploy.py index fb9f6692d40..021b04b7662 100644 --- a/tests/units/reflex_build_sdk/test_deploy.py +++ b/tests/units/reflex_build_sdk/test_deploy.py @@ -84,7 +84,7 @@ def send(self, request: Request) -> Response: if request.url.endswith("frontend.zip"): return reply(403)(request) assert not isinstance(request.content, bytes | None) - for _ in request.content: # pyright: ignore[reportGeneralTypeIssues] + for _ in request.content: # ty:ignore[not-iterable] pass return reply(200)(request) @@ -126,7 +126,7 @@ def test_upload_reports_progress(tmp_path: Path): class Storage: def send(self, request: Request) -> Response: assert not isinstance(request.content, bytes | None) - b"".join(request.content) # pyright: ignore[reportArgumentType] + b"".join(request.content) # ty:ignore[invalid-argument-type] return reply(200)(request) def close(self) -> None: @@ -148,7 +148,7 @@ class Storage: def send(self, request: Request) -> Response: requests.append(request) assert not isinstance(request.content, bytes | None) - b"".join(request.content) # pyright: ignore[reportArgumentType] + b"".join(request.content) # ty:ignore[invalid-argument-type] return reply(200)(request) def close(self) -> None: diff --git a/tests/units/reflex_build_sdk/test_types.py b/tests/units/reflex_build_sdk/test_types.py index d31949cd954..065012c2689 100644 --- a/tests/units/reflex_build_sdk/test_types.py +++ b/tests/units/reflex_build_sdk/test_types.py @@ -177,7 +177,7 @@ def test_unmapped_properties_are_in_the_schema_and_unmapped(model: type): for component in SCHEMA_MODELS[model] for key in components[component].get("properties", {}) } - mapped = {json_key(field) for field in dataclasses.fields(model)} + mapped = {json_key(field) for field in dataclasses.fields(model)} # ty:ignore[invalid-argument-type] assert set(UNMAPPED_PROPERTIES[model]) <= properties - mapped @@ -218,7 +218,7 @@ class _Model: def _problems(**overrides: Any) -> list[str]: component = { **_COMPONENT, - "properties": {**_COMPONENT["properties"], **overrides}, + "properties": {**_COMPONENT["properties"], **overrides}, # ty:ignore[invalid-argument-type] } return model_problems(_Model, component, {_Nested: ("Nested",)}) @@ -293,7 +293,7 @@ def test_checker_reports_missing_and_optional_fields(): component = { "properties": { key: value - for key, value in _COMPONENT["properties"].items() + for key, value in _COMPONENT["properties"].items() # ty:ignore[unresolved-attribute] if key != "tags" }, "required": ["id", "nested"], @@ -308,7 +308,7 @@ def test_checker_reports_unmapped_properties(): component = { **_COMPONENT, "properties": { - **_COMPONENT["properties"], + **_COMPONENT["properties"], # ty:ignore[invalid-argument-type] "added": {"type": "string"}, "skipped": {"type": "string"}, }, diff --git a/tests/units/reflex_build_sdk/transports/test_aiohttp.py b/tests/units/reflex_build_sdk/transports/test_aiohttp.py index c00af1de7ff..cea04220eff 100644 --- a/tests/units/reflex_build_sdk/transports/test_aiohttp.py +++ b/tests/units/reflex_build_sdk/transports/test_aiohttp.py @@ -189,7 +189,7 @@ def request(self, *args: Any, **kwargs: Any) -> Any: raise aiohttp.ClientPayloadError(msg) session = RecordingSession() - transport = AiohttpTransport(session) # pyright: ignore[reportArgumentType] + transport = AiohttpTransport(session) # ty:ignore[invalid-argument-type] with pytest.raises(TransportError): await transport.send(_request("http://127.0.0.1/echo/x", timeout=7.0)) (timeout,) = session.timeouts @@ -285,7 +285,7 @@ async def test_errors(error: BaseException, sent: bool, timed_out: bool): sent: Whether the request could have reached the server. timed_out: Whether the failure was a timeout. """ - transport = AiohttpTransport(_FailingSession(error)) # pyright: ignore[reportArgumentType] + transport = AiohttpTransport(_FailingSession(error)) # ty:ignore[invalid-argument-type] request = _request("http://127.0.0.1/echo/x") with pytest.raises(TransportError) as exc_info: await transport.send(request) diff --git a/tests/units/reflex_build_sdk/transports/test_httpx.py b/tests/units/reflex_build_sdk/transports/test_httpx.py index aa40ffe4f78..ec3df772f90 100644 --- a/tests/units/reflex_build_sdk/transports/test_httpx.py +++ b/tests/units/reflex_build_sdk/transports/test_httpx.py @@ -71,7 +71,7 @@ def _upload(content: object) -> Request: method="PUT", url="https://storage.example.com/bucket/backend.zip?signature=x", headers={"Content-Length": "6"}, - content=content, # pyright: ignore[reportArgumentType] + content=content, # ty:ignore[invalid-argument-type] ) diff --git a/tests/units/reflex_build_sdk/transports/test_httpx2.py b/tests/units/reflex_build_sdk/transports/test_httpx2.py index d23846ec77d..1db4234775d 100644 --- a/tests/units/reflex_build_sdk/transports/test_httpx2.py +++ b/tests/units/reflex_build_sdk/transports/test_httpx2.py @@ -72,7 +72,7 @@ def _upload(content: object) -> Request: method="PUT", url="https://storage.example.com/bucket/backend.zip?signature=x", headers={"Content-Length": "6"}, - content=content, # pyright: ignore[reportArgumentType] + content=content, # ty:ignore[invalid-argument-type] ) diff --git a/tests/units/reflex_cli/sdk.py b/tests/units/reflex_cli/sdk.py index 51a51f308dd..1075343b9ca 100644 --- a/tests/units/reflex_cli/sdk.py +++ b/tests/units/reflex_cli/sdk.py @@ -113,7 +113,7 @@ def gcp_connection(name: str, **fields: Any) -> GcpConnection: Returns: The connection. """ - return GcpConnection(**{ + return GcpConnection(**{ # ty:ignore[invalid-argument-type] "id": uuid.uuid5(uuid.NAMESPACE_OID, name), "name": name, "is_default": False, @@ -134,7 +134,7 @@ def provider_account(name: str, **fields: Any) -> ProviderAccount: The provider account. """ created = datetime.datetime(2026, 7, 1, tzinfo=datetime.UTC) - return ProviderAccount(**{ + return ProviderAccount(**{ # ty:ignore[invalid-argument-type] "id": uuid.uuid5(uuid.NAMESPACE_OID, name), "provider": "gcp", "name": name, diff --git a/tests/units/reflex_cli/utils/test_hosting.py b/tests/units/reflex_cli/utils/test_hosting.py index 5e909d942a5..541a130c208 100644 --- a/tests/units/reflex_cli/utils/test_hosting.py +++ b/tests/units/reflex_cli/utils/test_hosting.py @@ -1354,7 +1354,7 @@ def _report(**fields: object) -> DeploymentReport: "build_log_excerpt": None, } report.update(fields) - return DeploymentReport(**report) # pyright: ignore[reportArgumentType] + return DeploymentReport(**report) # ty:ignore[invalid-argument-type] def test_failure_report_prints_reason_and_build_log( diff --git a/tests/units/reflex_cli/utils/test_log.py b/tests/units/reflex_cli/utils/test_log.py index c7c9a0f608c..f38b208b8e6 100644 --- a/tests/units/reflex_cli/utils/test_log.py +++ b/tests/units/reflex_cli/utils/test_log.py @@ -512,7 +512,7 @@ def _with_old_reflex_base() -> Iterator[tuple[ModuleType, ModuleType, ModuleType blocker = _ReflexBaseLogBlocker() sys.meta_path.insert(0, blocker) old_constants_base = ModuleType("reflex_base.constants.base") - old_constants_base.LogLevel = _OldBaseLogLevel # pyright: ignore[reportAttributeAccessIssue] + old_constants_base.LogLevel = _OldBaseLogLevel # ty:ignore[unresolved-attribute] sys.modules["reflex_base.constants.base"] = old_constants_base try: yield ( @@ -579,7 +579,7 @@ def test_loglevel_option_still_offers_every_choice_on_old_reflex_base(): """ with _with_old_reflex_base() as (_, _fallback_log, _console): cli_options = importlib.import_module("reflex_cli.utils.cli_options") - (option,) = cli_options.loglevel_option(lambda: None).__click_params__ + (option,) = cli_options.loglevel_option(lambda: None).__click_params__ # ty:ignore[unresolved-attribute] assert list(option.type.choices) == [level.value for level in _OldBaseLogLevel] diff --git a/tests/units/reflex_cli/v2/test_apps.py b/tests/units/reflex_cli/v2/test_apps.py index 0a2cdbe4bd5..581e4b4287e 100644 --- a/tests/units/reflex_cli/v2/test_apps.py +++ b/tests/units/reflex_cli/v2/test_apps.py @@ -19,7 +19,7 @@ from .utils import api_error, as_click_command, fake_client -hosting_cli = as_click_command(hosting_cli) +hosting_cli = as_click_command(hosting_cli) # ty:ignore[invalid-assignment] runner = CliRunner() @@ -54,7 +54,7 @@ def app_summary(name: str = "test-app", **fields) -> AppSummary: Returns: The app. """ - return AppSummary(**{ + return AppSummary(**{ # ty:ignore[invalid-argument-type] "id": _APP_ID, "name": name, "description": "", @@ -75,7 +75,7 @@ def app(name: str = "test-app", **fields) -> App: Returns: The app. """ - return App(**{ + return App(**{ # ty:ignore[invalid-argument-type] "id": _APP_ID, "name": name, "description": "", @@ -109,7 +109,7 @@ def deployment_record(**fields) -> DeploymentRecord: Returns: The deployment. """ - return DeploymentRecord(**{ + return DeploymentRecord(**{ # ty:ignore[invalid-argument-type] "id": _DEPLOYMENT_ID, "url": "https://example.com", "backend_url": "https://api.example.com", diff --git a/tests/units/reflex_cli/v2/test_auth.py b/tests/units/reflex_cli/v2/test_auth.py index ce4f7e56ee9..66fe9a334ea 100644 --- a/tests/units/reflex_cli/v2/test_auth.py +++ b/tests/units/reflex_cli/v2/test_auth.py @@ -15,7 +15,7 @@ from .utils import api_error, as_click_command, fake_client -hosting_cli = as_click_command(hosting_cli) +hosting_cli = as_click_command(hosting_cli) # ty:ignore[invalid-assignment] runner = CliRunner() diff --git a/tests/units/reflex_cli/v2/test_cli.py b/tests/units/reflex_cli/v2/test_cli.py index bd2bbd3413b..c0938606fa2 100644 --- a/tests/units/reflex_cli/v2/test_cli.py +++ b/tests/units/reflex_cli/v2/test_cli.py @@ -79,7 +79,7 @@ def app_summary(name: str = "fake-app", **fields) -> AppSummary: Returns: The app. """ - return AppSummary(**{ + return AppSummary(**{ # ty:ignore[invalid-argument-type] "id": _APP_ID, "name": name, "description": "", @@ -100,7 +100,7 @@ def app(name: str = "fake-app", **fields) -> App: Returns: The app. """ - return App(**{ + return App(**{ # ty:ignore[invalid-argument-type] "id": _APP_ID, "name": name, "description": "", @@ -135,7 +135,7 @@ def project(name: str = "fake-project", **fields) -> Project: Returns: The project. """ - return Project(**{ + return Project(**{ # ty:ignore[invalid-argument-type] "id": _PROJECT_ID, "name": name, "tier": ProjectTier(name="Pro", cpu_quota=4, ram_quota=8, deployment_quota=10), diff --git a/tests/units/reflex_cli/v2/test_gcp.py b/tests/units/reflex_cli/v2/test_gcp.py index a324848f653..04dc154cdba 100644 --- a/tests/units/reflex_cli/v2/test_gcp.py +++ b/tests/units/reflex_cli/v2/test_gcp.py @@ -13,7 +13,7 @@ from .utils import api_error, as_click_command, fake_client -hosting_cli = as_click_command(hosting_cli) +hosting_cli = as_click_command(hosting_cli) # ty:ignore[invalid-assignment] runner = CliRunner() diff --git a/tests/units/reflex_cli/v2/test_project.py b/tests/units/reflex_cli/v2/test_project.py index 030f06ce13d..e7dccaa493c 100644 --- a/tests/units/reflex_cli/v2/test_project.py +++ b/tests/units/reflex_cli/v2/test_project.py @@ -20,7 +20,7 @@ from .utils import api_error, as_click_command, fake_client -hosting_cli = as_click_command(hosting_cli) +hosting_cli = as_click_command(hosting_cli) # ty:ignore[invalid-assignment] runner = CliRunner() diff --git a/tests/units/reflex_cli/v2/test_providers.py b/tests/units/reflex_cli/v2/test_providers.py index 0d268b6a412..01284e154b6 100644 --- a/tests/units/reflex_cli/v2/test_providers.py +++ b/tests/units/reflex_cli/v2/test_providers.py @@ -40,7 +40,7 @@ def _status(**fields) -> GcpStatus: Returns: The status. """ - return GcpStatus(**{ + return GcpStatus(**{ # ty:ignore[invalid-argument-type] "configured": True, "allowed": True, "project_id": None, diff --git a/tests/units/reflex_cli/v2/test_scan.py b/tests/units/reflex_cli/v2/test_scan.py index fabcc36654c..2776eca88ab 100644 --- a/tests/units/reflex_cli/v2/test_scan.py +++ b/tests/units/reflex_cli/v2/test_scan.py @@ -21,7 +21,7 @@ from .utils import api_error, as_click_command, fake_client -hosting_cli = as_click_command(hosting_cli) +hosting_cli = as_click_command(hosting_cli) # ty:ignore[invalid-assignment] runner = CliRunner() diff --git a/tests/units/reflex_cli/v2/test_secrets.py b/tests/units/reflex_cli/v2/test_secrets.py index f0e2bc05e6e..bc8d64020ef 100644 --- a/tests/units/reflex_cli/v2/test_secrets.py +++ b/tests/units/reflex_cli/v2/test_secrets.py @@ -11,7 +11,7 @@ from .utils import FakeClient, api_error, as_click_command, fake_client -hosting_cli = as_click_command(hosting_cli) +hosting_cli = as_click_command(hosting_cli) # ty:ignore[invalid-assignment] runner = CliRunner() diff --git a/tests/units/reflex_cli/v2/test_vmtypes_regions.py b/tests/units/reflex_cli/v2/test_vmtypes_regions.py index 926c7f1a66a..9ad03ae476d 100644 --- a/tests/units/reflex_cli/v2/test_vmtypes_regions.py +++ b/tests/units/reflex_cli/v2/test_vmtypes_regions.py @@ -11,7 +11,7 @@ from .utils import api_error, as_click_command, fake_client -hosting_cli = as_click_command(hosting_cli) +hosting_cli = as_click_command(hosting_cli) # ty:ignore[invalid-assignment] runner = CliRunner() diff --git a/tests/units/reflex_site_shared/backend/test_demo_requests.py b/tests/units/reflex_site_shared/backend/test_demo_requests.py index f1eed45fd04..9d12c245c4a 100644 --- a/tests/units/reflex_site_shared/backend/test_demo_requests.py +++ b/tests/units/reflex_site_shared/backend/test_demo_requests.py @@ -65,7 +65,7 @@ def _state() -> DemoRequestState: Returns: The state. """ - root = rx.State(_reflex_internal_init=True) # pyright: ignore[reportCallIssue] + root = rx.State(_reflex_internal_init=True) # ty:ignore[unknown-argument] state = cast(DemoRequestState, root.get_substate([DemoRequestState.get_name()])) state.router = RouterData(url=ReflexURL(PAGE)) return state diff --git a/tests/units/reflex_site_shared/docs/test_site.py b/tests/units/reflex_site_shared/docs/test_site.py index 42e9b130602..1daedaedb3b 100644 --- a/tests/units/reflex_site_shared/docs/test_site.py +++ b/tests/units/reflex_site_shared/docs/test_site.py @@ -69,7 +69,7 @@ def add_page(self, **kwargs: object) -> None: app = AppRecorder() routes = register_docs( - app, # type: ignore[arg-type] + app, # ty:ignore[invalid-argument-type] DocsSiteConfig( content_dir=tmp_path, sitemap_base_url="https://example.com/docs/product/", diff --git a/tests/units/reflex_site_shared/test_docs_shell.py b/tests/units/reflex_site_shared/test_docs_shell.py index 3ba1e500528..7d28187275d 100644 --- a/tests/units/reflex_site_shared/test_docs_shell.py +++ b/tests/units/reflex_site_shared/test_docs_shell.py @@ -377,7 +377,7 @@ def _feedback_state() -> DocsFeedbackState: Returns: The feedback state. """ - root = rx.State(_reflex_internal_init=True) # pyright: ignore[reportCallIssue] + root = rx.State(_reflex_internal_init=True) # ty:ignore[unknown-argument] return cast(DocsFeedbackState, root.get_substate([DocsFeedbackState.get_name()])) diff --git a/tests/units/reflex_workflow/engine/test_runner.py b/tests/units/reflex_workflow/engine/test_runner.py index 3e05137c15f..b246602c2c8 100644 --- a/tests/units/reflex_workflow/engine/test_runner.py +++ b/tests/units/reflex_workflow/engine/test_runner.py @@ -2892,7 +2892,7 @@ async def test_run_workflows_refuses_settings_that_cannot_work( session_factory, settings: dict[str, object] ): with pytest.raises(ValueError, match="must be"): - async with run_workflows(session_factory, workflows=[Parting], **settings): # pyright: ignore[reportArgumentType] + async with run_workflows(session_factory, workflows=[Parting], **settings): # ty:ignore[invalid-argument-type] pass diff --git a/tests/units/reflex_workflow/examples/test_ex07_long_wait_approval.py b/tests/units/reflex_workflow/examples/test_ex07_long_wait_approval.py index 964da18cdb2..8a8574956e7 100644 --- a/tests/units/reflex_workflow/examples/test_ex07_long_wait_approval.py +++ b/tests/units/reflex_workflow/examples/test_ex07_long_wait_approval.py @@ -91,7 +91,7 @@ async def read_directly( async def test_a_complete_request_waits_for_a_decision_and_is_filed(database): async with worker(database): - request_id = await submitted(COMPLETE) + request_id = await submitted(COMPLETE) # ty:ignore[invalid-argument-type] await eventually(reaches(request_id, "awaiting-decision")) assert ( @@ -109,7 +109,7 @@ async def test_a_complete_request_waits_for_a_decision_and_is_filed(database): async def test_a_rejected_request_is_never_filed(database): async with worker(database): - request_id = await submitted(COMPLETE) + request_id = await submitted(COMPLETE) # ty:ignore[invalid-argument-type] await eventually(reaches(request_id, "awaiting-decision")) assert ( diff --git a/tests/units/reflex_workflow/examples/test_ex11_background_job.py b/tests/units/reflex_workflow/examples/test_ex11_background_job.py index b0192efa300..802cb7999d7 100644 --- a/tests/units/reflex_workflow/examples/test_ex11_background_job.py +++ b/tests/units/reflex_workflow/examples/test_ex11_background_job.py @@ -82,8 +82,9 @@ async def test_progress_is_the_same_whether_or_not_anyone_was_watching(running): order = ["queued", "planning", "rendering", "uploading", "done"] # Nothing the watching client saw went backwards. - assert [order.index(stage) for stage in seen] == sorted( - order.index(stage) for stage in seen + assert [order.index(stage) for stage in seen] == sorted( # ty:ignore[invalid-argument-type] + order.index(stage) # ty:ignore[invalid-argument-type] + for stage in seen ) for run_id in (watched, unwatched): row = await Job.by(Job.run_id == run_id).get() diff --git a/tests/units/reflex_workflow/test_model.py b/tests/units/reflex_workflow/test_model.py index 2814aa849aa..7de0c25e07b 100644 --- a/tests/units/reflex_workflow/test_model.py +++ b/tests/units/reflex_workflow/test_model.py @@ -160,7 +160,7 @@ class Second(Base, Shared): def test_step_calls_are_typed_by_their_workflow(): assert_type(Expense.decide("approve"), Call[Expense]) - assert_type( + assert_type( # ty:ignore[type-assertion-failure] wake_in(Expense.escalate(), datetime.timedelta(hours=1)), WakeIn[Expense] ) assert_type(Expense.by(Expense.id == 1), RunHandle[Expense]) @@ -192,18 +192,18 @@ def test_steps_defined_on_a_shared_base_belong_to_each_table(): def test_step_arguments_are_checked(): - Expense.decide("maybe") # pyright: ignore[reportArgumentType] - Expense.decide("approve", by=1) # pyright: ignore[reportArgumentType] - Expense.decide() # pyright: ignore[reportCallIssue] - Expense.escalate("now") # pyright: ignore[reportCallIssue] + Expense.decide("maybe") # ty:ignore[invalid-argument-type] + Expense.decide("approve", by=1) # ty:ignore[invalid-argument-type] + Expense.decide() # ty:ignore[missing-argument] + Expense.escalate("now") # ty:ignore[too-many-positional-arguments] async def _never_called() -> None: """Hold calls that must not type-check; never run.""" - await Expense().start(Other.go()) # pyright: ignore[reportArgumentType] - await Expense().start(Expense.decide) # pyright: ignore[reportArgumentType] - await Expense.by(Expense.id == 1).run(Other.go()) # pyright: ignore[reportArgumentType] - await Expense.by(Expense.id == 1).deliver(Other.go()) # pyright: ignore[reportArgumentType] + await Expense().start(Other.go()) # ty:ignore[invalid-argument-type] + await Expense().start(Expense.decide) # ty:ignore[invalid-argument-type] + await Expense.by(Expense.id == 1).run(Other.go()) # ty:ignore[invalid-argument-type] + await Expense.by(Expense.id == 1).deliver(Other.go()) # ty:ignore[invalid-argument-type] # A step of a shared base is a step of every table that inherits it. await First().start(Shared.begin) await Second.by(Second.id == 1).run(Shared.begin()) @@ -221,7 +221,7 @@ def test_a_call_keeps_its_arguments_as_json(): def test_arguments_that_are_not_json_are_rejected(): - call = Expense.decide(datetime.date(2026, 1, 1)) # pyright: ignore[reportArgumentType] + call = Expense.decide(datetime.date(2026, 1, 1)) # ty:ignore[invalid-argument-type] with pytest.raises(TypeError, match="JSON-serializable"): call.encode() @@ -231,7 +231,7 @@ def test_arguments_json_cannot_hold_are_rejected(value: object): if value == "circular": value = [] value.append(value) - call = Expense.decide(value) # pyright: ignore[reportArgumentType] + call = Expense.decide(value) # ty:ignore[invalid-argument-type] with pytest.raises(TypeError, match="JSON-serializable"): call.encode() @@ -248,7 +248,7 @@ def test_a_bare_step_is_a_call_without_arguments(): def test_a_bare_step_that_needs_arguments_is_rejected(): with pytest.raises(TypeError, match="takes arguments"): - wake_in(Expense.decide, datetime.timedelta(days=1)) # pyright: ignore[reportArgumentType] + wake_in(Expense.decide, datetime.timedelta(days=1)) # ty:ignore[invalid-argument-type] def test_another_workflows_step_is_rejected_at_runtime(): @@ -303,7 +303,7 @@ def test_a_limit_has_to_cap_something(): ) def test_a_limit_has_to_be_positive(caps: dict[str, object]): with pytest.raises(ValueError, match="must be positive"): - Limit(by="customer", **caps) # pyright: ignore[reportArgumentType] + Limit(by="customer", **caps) # ty:ignore[invalid-argument-type] def test_a_rate_needs_the_period_it_is_counted_over(): @@ -319,7 +319,7 @@ async def test_a_rate_without_a_bucket_table_says_so(monkeypatch): spec = Metered.__workflow_limit__ assert spec is not None with pytest.raises(TypeError, match="rate bucket table must be mapped"): - await claim.take_tokens(None, Metered, spec, "stripe", 1) # pyright: ignore[reportArgumentType] + await claim.take_tokens(None, Metered, spec, "stripe", 1) # ty:ignore[invalid-argument-type] def test_only_one_bucket_table_may_be_mapped(monkeypatch): @@ -340,9 +340,9 @@ def test_arguments_a_step_cannot_take_are_rejected_where_the_call_is_made(): # A webhook body that does not fit the step it addresses is refused while # there is still a caller to tell. with pytest.raises(TypeError, match="cannot take those arguments"): - check_call(Expense, Expense.decide(verdikt="approve")) # pyright: ignore[reportCallIssue] + check_call(Expense, Expense.decide(verdikt="approve")) # ty:ignore[missing-argument, unknown-argument] with pytest.raises(TypeError, match="cannot take those arguments"): - check_call(Expense, Expense.decide("approve", "again")) # pyright: ignore[reportCallIssue] + check_call(Expense, Expense.decide("approve", "again")) # ty:ignore[too-many-positional-arguments] check_call(Expense, Expense.decide("approve")) @@ -357,7 +357,7 @@ def engine_index(cls: type[Workflow], suffix: str) -> Index | None: The index, or None. """ name = f"ix_{cls.__tablename__}_{suffix}" - table = cls.__table__ # pyright: ignore[reportAttributeAccessIssue] + table = cls.__table__ # ty:ignore[unresolved-attribute] return next((index for index in table.indexes if index.name == name), None) diff --git a/tests/units/test_app.py b/tests/units/test_app.py index ae575628094..3a4e5f8e4e7 100644 --- a/tests/units/test_app.py +++ b/tests/units/test_app.py @@ -235,16 +235,16 @@ class TestAuthProvider(AuthProvider): login_path: str = "/login" logout_path: str = "/logout" - def login(self): # pyright: ignore [reportIncompatibleMethodOverride] + def login(self): """Login.""" - def is_authenticated(self): # pyright: ignore [reportIncompatibleMethodOverride] + def is_authenticated(self): """Is authenticated.""" - def get_admin_user(self): # pyright: ignore [reportIncompatibleMethodOverride] + def get_admin_user(self): """Get admin user.""" - def logout(self): # pyright: ignore [reportIncompatibleMethodOverride] + def logout(self): """Logout.""" return TestAuthProvider @@ -735,7 +735,7 @@ async def test_dynamic_var_event( clean_registration_context: The registration context fixture, which is cleared before each test. """ clean_registration_context.register_base_state(test_state) - state = test_state() # pyright: ignore [reportCallIssue] + state = test_state() # ty:ignore[missing-argument] state.add_var("int_val", int, 0) def set_int_val(self, value: int): @@ -971,7 +971,7 @@ class DictMutationTestState(BaseState): def add_age(self): """Add an age to the dict.""" - self.details.update({"age": 20}) # pyright: ignore [reportCallIssue, reportArgumentType] + self.details.update({"age": 20}) # ty:ignore[no-matching-overload] def change_name(self): """Change the name in the dict.""" @@ -1009,7 +1009,7 @@ def add_street_to_home_address(self): def change_friend_name(self): """Change the friend's name in the nested dict.""" - self.friend_in_nested_dict["friend"]["name"] = "Tommy" + self.friend_in_nested_dict["friend"]["name"] = "Tommy" # ty:ignore[invalid-assignment] def remove_friend(self): """Remove the friend from the nested dict.""" @@ -1017,7 +1017,7 @@ def remove_friend(self): def add_friend_age(self): """Add an age to the friend in the nested dict.""" - self.friend_in_nested_dict["friend"]["age"] = 30 + self.friend_in_nested_dict["friend"]["age"] = 30 # ty:ignore[invalid-assignment] return DictMutationTestState() @@ -1985,7 +1985,7 @@ def comp_dynamic(self) -> str: Returns: same as self.dynamic """ - return self.dynamic # pyright: ignore[reportAttributeAccessIssue] + return self.dynamic # ty:ignore[unresolved-attribute] def test_dynamic_arg_shadow( @@ -2037,7 +2037,7 @@ def cleanup_dynamic_arg(): """Fixture to reset DynamicState class vars after each test.""" yield with contextlib.suppress(AttributeError): - del State.dynamic # pyright: ignore[reportAttributeAccessIssue] + del State.dynamic # ty:ignore[unresolved-attribute] State.computed_vars.pop("dynamic", None) State.vars.pop("dynamic", None) @@ -2170,14 +2170,14 @@ def _dynamic_state_event(name, val, **kwargs): if isinstance(app.state_manager, StateManagerRedis): # When redis is used, the state is not updated until the processing is complete state = await app.state_manager.get_state(substate_token) - assert state.dynamic == prev_exp_val # pyright: ignore[reportAttributeAccessIssue] + assert state.dynamic == prev_exp_val # ty:ignore[unresolved-attribute] if environment.REFLEX_OPLOCK_ENABLED.get(): await app.state_manager.close() # check that router data was written to the state_manager store state = await app.state_manager.get_state(substate_token) - assert state.dynamic == exp_val # pyright: ignore[reportAttributeAccessIssue] + assert state.dynamic == exp_val # ty:ignore[unresolved-attribute] # a simple state update event should NOT trigger on_load or route var side effects emitted_deltas.clear() @@ -3305,19 +3305,19 @@ def test_app_wrap_priority( class Fragment1(Component): tag = "Fragment1" - def _get_app_wrap_components(self) -> dict[tuple[int, str], Component]: # pyright: ignore [reportIncompatibleMethodOverride] + def _get_app_wrap_components(self) -> dict[tuple[int, str], Component]: return {(99, "Box"): rx.box()} class Fragment2(Component): tag = "Fragment2" - def _get_app_wrap_components(self) -> dict[tuple[int, str], Component]: # pyright: ignore [reportIncompatibleMethodOverride] + def _get_app_wrap_components(self) -> dict[tuple[int, str], Component]: return {(50, "Text"): rx.text()} class Fragment3(Component): tag = "Fragment3" - def _get_app_wrap_components(self) -> dict[tuple[int, str], Component]: # pyright: ignore [reportIncompatibleMethodOverride] + def _get_app_wrap_components(self) -> dict[tuple[int, str], Component]: return {(10, "Fragment2"): Fragment2.create()} def page(): @@ -4184,7 +4184,7 @@ def test_context_middleware_is_registered_as_a_class( ) # Mimic the instrumentation's patch on every middleware in the stack. for cls in registered: - cls.__call__ = cls.__call__ + cls.__call__ = cls.__call__ # ty:ignore[invalid-assignment] async def test_context_middleware_sets_contexts(app_with_processor: App): diff --git a/tests/units/test_attribute_access_type.py b/tests/units/test_attribute_access_type.py index d26ab141b06..50f9050a89f 100644 --- a/tests/units/test_attribute_access_type.py +++ b/tests/units/test_attribute_access_type.py @@ -426,7 +426,7 @@ def test_get_attribute_access_type_no_default(cls: type) -> None: class UnresolvableRefClass: """Class with an unresolvable forward-ref annotation.""" - broken: UndefinedElsewhere # noqa: F821 # pyright: ignore[reportUndefinedVariable] + broken: UndefinedElsewhere # noqa: F821 # ty:ignore[unresolved-reference] count: int = 0 diff --git a/tests/units/test_check_min_deps.py b/tests/units/test_check_min_deps.py index e6d17412b7a..ffc2a698957 100644 --- a/tests/units/test_check_min_deps.py +++ b/tests/units/test_check_min_deps.py @@ -59,53 +59,43 @@ def test_discover_packages_records_optional_extras(): assert set(by_name["reflex-build-sdk"].extras) == {"aiohttp", "httpx", "httpx2"} -def test_pyright_errors_keys_and_filters_severity(): - report = { - "generalDiagnostics": [ - { - "file": "/abs/foo.py", - "severity": "error", - "message": "boom", - "range": {"start": {"line": 9, "character": 4}}, - }, - { - "file": "/abs/foo.py", - "severity": "warning", - "message": "ignore me", - "range": {"start": {"line": 1, "character": 0}}, - }, - ] - } - errors = check_min_deps._pyright_errors(report) - - assert list(errors) == [("/abs/foo.py", 9, 4, "boom")] - # Line/character are converted to 1-based in the display string. - assert errors["/abs/foo.py", 9, 4, "boom"] == "/abs/foo.py:10:5 - error: boom" - - -def test_pyright_errors_delta_cancels_shared_noise(): - def report(messages: list[tuple[str, int]]) -> dict: - return { - "generalDiagnostics": [ - { - "file": "/abs/foo.py", - "severity": "error", - "message": msg, - "range": {"start": {"line": line, "character": 0}}, - } - for msg, line in messages - ] - } +def test_ty_errors_keys_and_filters_severity(): + output = ( + "/abs/foo.py:10:5: error[unresolved-attribute] boom\n" + "/abs/foo.py:2:1: warning[unused-ignore-comment] ignore me\n" + "Found 2 diagnostics\n" + ) + errors = check_min_deps._ty_errors(output) + + assert list(errors) == [("/abs/foo.py", 10, 5, "[unresolved-attribute] boom")] + assert errors["/abs/foo.py", 10, 5, "[unresolved-attribute] boom"] == ( + "/abs/foo.py:10:5 - error: [unresolved-attribute] boom" + ) + + +def test_ty_errors_delta_cancels_shared_noise(): + def output(messages: list[tuple[str, int]]) -> str: + return "".join( + f"/abs/foo.py:{line}:1: error[unresolved-import] {msg}\n" + for msg, line in messages + ) # A shared, undeclared-import error appears in both resolutions; only the # minimum-version-specific error should remain in the delta. - baseline = check_min_deps._pyright_errors(report([("missing optional import", 1)])) - minimum = check_min_deps._pyright_errors( - report([("missing optional import", 1), ("model_dump is unknown", 50)]) + baseline = check_min_deps._ty_errors(output([("missing optional import", 1)])) + minimum = check_min_deps._ty_errors( + output([("missing optional import", 1), ("model_dump is unknown", 50)]) ) new = minimum.keys() - baseline.keys() - assert new == {("/abs/foo.py", 50, 0, "model_dump is unknown")} + assert new == {("/abs/foo.py", 50, 1, "[unresolved-import] model_dump is unknown")} + + +def test_ty_config_mirrors_root_rule_severities(): + config = check_min_deps._ty_config() + + assert config.startswith("[rules]\n") + assert 'invalid-method-override = "ignore"' in config @pytest.mark.parametrize( @@ -352,9 +342,9 @@ def test_resolve_and_check_checks_modules_not_the_source_directory( lowest=False, ) - pyright = fake_run.command_starting_with(["pyright"]) - checked = pyright[pyright.index("--project") + 2 :] - assert str(check_min_deps.REPO_ROOT / "reflex") not in pyright + ty = fake_run.command_starting_with(["ty", "check"]) + checked = ty[ty.index("--exit-zero") + 1 :] + assert str(check_min_deps.REPO_ROOT / "reflex") not in ty assert checked, "the package's modules are passed individually" assert all(module.endswith(".py") for module in checked) assert str(check_min_deps.REPO_ROOT / "reflex" / "app.py") in checked diff --git a/tests/units/test_config.py b/tests/units/test_config.py index 4ec4bc3d68c..d55ac8d9ac4 100644 --- a/tests/units/test_config.py +++ b/tests/units/test_config.py @@ -34,7 +34,7 @@ def test_requires_app_name(): """Test that a config requires an app_name.""" with pytest.raises(TypeError): - rx.Config() # pyright: ignore[reportCallIssue] + rx.Config() # ty:ignore[missing-argument] def test_set_app_name(base_config_values): @@ -490,7 +490,7 @@ def test_replace_defaults( exp_config_values: The expected config values. """ mock_os_env = os.environ.copy() - monkeypatch.setattr(reflex_base.config.os, "environ", mock_os_env) # pyright: ignore[reportPrivateImportUsage] + monkeypatch.setattr(reflex_base.config.os, "environ", mock_os_env) mock_os_env.update({k: str(v) for k, v in env_vars.items()}) c = rx.Config(app_name="a", **config_kwargs) c._set_persistent(**set_persistent_vars) @@ -660,14 +660,14 @@ def test_disable_with_plugin_class(self): def test_disable_with_plugin_instance_backward_compat(self): """Test disabling a plugin by passing an instance (deprecated).""" - config = rx.Config(app_name="test", disable_plugins=[SitemapPlugin()]) # pyright: ignore[reportArgumentType] + config = rx.Config(app_name="test", disable_plugins=[SitemapPlugin()]) # ty:ignore[invalid-argument-type] assert not any(isinstance(p, SitemapPlugin) for p in config.plugins) def test_disable_with_string_backward_compat(self): """Test disabling a plugin by passing a string (deprecated).""" config = rx.Config( app_name="test", - disable_plugins=["reflex.plugins.sitemap.SitemapPlugin"], # pyright: ignore[reportArgumentType] + disable_plugins=["reflex.plugins.sitemap.SitemapPlugin"], # ty:ignore[invalid-argument-type] ) assert not any(isinstance(p, SitemapPlugin) for p in config.plugins) @@ -681,14 +681,14 @@ def test_disable_plugins_normalized_to_classes(self): def test_disable_instance_normalized_to_class(self): """Test that a Plugin instance in disable_plugins is normalized to its class.""" - config = rx.Config(app_name="test", disable_plugins=[SitemapPlugin()]) # pyright: ignore[reportArgumentType] + config = rx.Config(app_name="test", disable_plugins=[SitemapPlugin()]) # ty:ignore[invalid-argument-type] assert config.disable_plugins == [SitemapPlugin] def test_disable_string_normalized_to_class(self): """Test that a string in disable_plugins is normalized to the class.""" config = rx.Config( app_name="test", - disable_plugins=["reflex.plugins.sitemap.SitemapPlugin"], # pyright: ignore[reportArgumentType] + disable_plugins=["reflex.plugins.sitemap.SitemapPlugin"], # ty:ignore[invalid-argument-type] ) assert config.disable_plugins == [SitemapPlugin] @@ -734,7 +734,7 @@ def test_plugins_instance_passthrough(): def test_plugins_class_auto_instantiated(): """A Plugin subclass is auto-instantiated rather than raising deep in the compiler (issue #6440).""" - config = rx.Config(app_name="test", plugins=[SitemapPlugin]) # pyright: ignore[reportArgumentType] + config = rx.Config(app_name="test", plugins=[SitemapPlugin]) # ty:ignore[invalid-argument-type] instances = [p for p in config.plugins if isinstance(p, SitemapPlugin)] assert len(instances) == 1 # And it must be an instance, not the class itself. @@ -744,7 +744,7 @@ def test_plugins_class_auto_instantiated(): def test_plugins_invalid_value_raises_config_error(): """A non-Plugin value raises ConfigError naming the entry, not a deep TypeError (issue #6440).""" with pytest.raises(ConfigError, match=r"reflex\.Config\.plugins"): - rx.Config(app_name="test", plugins=["not-a-plugin"]) # pyright: ignore[reportArgumentType] + rx.Config(app_name="test", plugins=["not-a-plugin"]) # ty:ignore[invalid-argument-type] def test_plugins_class_requiring_args_raises_config_error(): @@ -755,7 +755,7 @@ def __init__(self, required): self.required = required with pytest.raises(ConfigError, match="NeedsArgs"): - rx.Config(app_name="test", plugins=[NeedsArgs]) # pyright: ignore[reportArgumentType] + rx.Config(app_name="test", plugins=[NeedsArgs]) # ty:ignore[invalid-argument-type] # Module-level plugins so REFLEX_EXTRA_PLUGINS can resolve them by import path. @@ -1286,7 +1286,7 @@ def test_concurrent_import_not_recorded_as_rxconfig_dep( try: assert race_gate.in_load.wait(timeout=5) # Import a project-local module from this thread while rxconfig loads. - import side_module # noqa: F401 # pyright: ignore[reportMissingImports] + import side_module # noqa: F401 # ty:ignore[unresolved-import] finally: race_gate.release.set() loader.join(timeout=5) @@ -1672,7 +1672,7 @@ def test_load_config_deprecated(mocker: MockerFixture): ) deprecate = mocker.patch("reflex_base.utils.console.deprecate") - assert reflex_base.config._load_config() is conf + assert reflex_base.config._load_config() is conf # ty:ignore[deprecated] get_config.assert_called_once_with() deprecate.assert_called_once() diff --git a/tests/units/test_environment.py b/tests/units/test_environment.py index 4829dbd088a..e24462f1ef0 100644 --- a/tests/units/test_environment.py +++ b/tests/units/test_environment.py @@ -410,7 +410,7 @@ def test_get_with_default(self): def test_set_string_value(self): """Test setting a string value.""" env_var_instance = EnvVar("TEST_VAR", "default", str) - env_var_instance.set("new_value") # type: ignore[arg-type] + env_var_instance.set("new_value") # ty:ignore[invalid-argument-type] assert os.environ.get("TEST_VAR") == "new_value" # Clean up del os.environ["TEST_VAR"] @@ -429,7 +429,7 @@ def test_set_none_value(self, monkeypatch): def test_set_enum_value(self): """Test setting an enum value.""" env_var_instance = EnvVar("TEST_VAR", _TestEnum.VALUE1, _TestEnum) - env_var_instance.set(_TestEnum.VALUE2) # type: ignore[arg-type] + env_var_instance.set(_TestEnum.VALUE2) # ty:ignore[invalid-argument-type] assert os.environ.get("TEST_VAR") == "value2" # Clean up del os.environ["TEST_VAR"] @@ -437,7 +437,7 @@ def test_set_enum_value(self): def test_set_list_value(self): """Test setting a list value.""" env_var_instance = EnvVar("TEST_VAR", [], list[int]) - env_var_instance.set([1, 2, 3]) # type: ignore[arg-type] + env_var_instance.set([1, 2, 3]) # ty:ignore[invalid-argument-type] assert os.environ.get("TEST_VAR") == "1:2:3" # Clean up del os.environ["TEST_VAR"] @@ -792,7 +792,7 @@ def test_timedelta_env_var_round_trips_through_set( ): # `EnvVar` binds its type var to the class object, so a value argument # never matches - the same quirk the other `set` tests here work around. - env_var_instance.set(value) # type: ignore[arg-type] + env_var_instance.set(value) # ty:ignore[invalid-argument-type] assert env_var_instance.get() == value @@ -999,6 +999,6 @@ def test_env_var_set_runs_callbacks_for_its_name(monkeypatch: pytest.MonkeyPatch assert calls == [] env_var_instance = EnvVar(name, None, str) - env_var_instance.set("value") # type: ignore[arg-type] + env_var_instance.set("value") # ty:ignore[invalid-argument-type] env_var_instance.set(None) assert calls == ["value", None] diff --git a/tests/units/test_event.py b/tests/units/test_event.py index abc07d9a963..9f175050fce 100644 --- a/tests/units/test_event.py +++ b/tests/units/test_event.py @@ -276,7 +276,7 @@ def on_event(self, value: int): with pytest.raises(EventHandlerTypeError, match=r"Got Field\(default=42"): S.on_event(S._secret) with pytest.raises(EventHandlerTypeError, match=r"Got Field\(default=42"): - cast(EventSpec, S.on_event()).add_args(S._secret) # pyright: ignore[reportArgumentType] + cast(EventSpec, S.on_event()).add_args(S._secret) # ty:ignore[invalid-argument-type] class BackendTriggerState(BaseState): @@ -316,7 +316,7 @@ def test_backend_var_upload_progress_reports_repr(): """A backend var passed as on_upload_progress reports its repr.""" upload = rx.upload_files( upload_id="u", - on_upload_progress=BackendTriggerState._secret, # pyright: ignore[reportArgumentType] + on_upload_progress=BackendTriggerState._secret, # ty:ignore[invalid-argument-type] ) with pytest.raises(ValueError, match=r"^Field\(default=42.* is not a valid"): upload.as_event_spec(handler=cast(EventHandler, BackendTriggerState.on_upload)) @@ -329,7 +329,7 @@ class S(BaseState): @event def on_event( self, - event: "_LateBoundEventType", # pyright: ignore[reportUndefinedVariable] # noqa: F821 + event: "_LateBoundEventType", # ty:ignore[unresolved-reference] # noqa: F821 ): pass @@ -821,7 +821,7 @@ def handler(self): assert isinstance(handler, EventHandler) assert not handler.event_actions - sp_handler = EventActionState.handler.stop_propagation # pyright: ignore [reportFunctionMemberAccess] + sp_handler = EventActionState.handler.stop_propagation # ty:ignore[unresolved-attribute] assert sp_handler.event_actions == {"stopPropagation": True} # should NOT affect other references to the handler assert not handler.event_actions @@ -927,7 +927,7 @@ def get_handler(self, arg: Var[str]): return S.e(arg) w = Wrapper() - _ = rx.input(on_change=w.get_handler) + _ = rx.input(on_change=w.get_handler) # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 def test_event_decorator_with_event_actions(): diff --git a/tests/units/test_health_endpoint.py b/tests/units/test_health_endpoint.py index 6f5766bc306..81344389326 100644 --- a/tests/units/test_health_endpoint.py +++ b/tests/units/test_health_endpoint.py @@ -108,7 +108,7 @@ async def test_close_health_redis(mocker: MockerFixture): # Case 2: Database connection error (OperationalError) ( MagicMock(), - sqlalchemy.exc.OperationalError("error", "error", "error"), # pyright: ignore[reportArgumentType] + sqlalchemy.exc.OperationalError("error", "error", "error"), # ty:ignore[invalid-argument-type] {"db": False}, ), ], diff --git a/tests/units/test_mock_redis.py b/tests/units/test_mock_redis.py index d0c81ea908e..4529f5d6484 100644 --- a/tests/units/test_mock_redis.py +++ b/tests/units/test_mock_redis.py @@ -24,7 +24,7 @@ async def test_pubsub_listen_yields_pmessage_for_pattern_without_handler(): "data": b"set", } # The internal event log keeps its raw entries. - assert redis._internals["event_log"][-1] == { # pyright: ignore[reportAttributeAccessIssue] + assert redis._internals["event_log"][-1] == { # ty:ignore[unresolved-attribute] "channel": b"__keyspace@1__:foo1", "data": b"set", } diff --git a/tests/units/test_model.py b/tests/units/test_model.py index 696d27fa618..ad76b381b63 100644 --- a/tests/units/test_model.py +++ b/tests/units/test_model.py @@ -177,7 +177,7 @@ def test_automigration( assert versions.exists() # initial table - class AlembicThing(Model, table=True): # pyright: ignore [reportRedeclaration] + class AlembicThing(Model, table=True): t1: str with get_engine().connect() as connection: @@ -198,7 +198,7 @@ class AlembicThing(Model, table=True): # pyright: ignore [reportRedeclaration] model_registry.get_metadata().clear() # Create column t2, mark t1 as optional with default - class AlembicThing(Model, table=True): # pyright: ignore [reportRedeclaration] + class AlembicThing(Model, table=True): t1: str | None = "default" t2: str = "bar" @@ -218,7 +218,7 @@ class AlembicThing(Model, table=True): # pyright: ignore [reportRedeclaration] model_registry.get_metadata().clear() # Drop column t1 - class AlembicThing(Model, table=True): # pyright: ignore [reportRedeclaration] + class AlembicThing(Model, table=True): t2: str = "bar" assert migrate(autogenerate=True) @@ -253,7 +253,7 @@ class AlembicSecond(Model, table=True): # drop table (AlembicSecond) model_registry.get_metadata().clear() - class AlembicThing(Model, table=True): # pyright: ignore [reportRedeclaration] + class AlembicThing(Model, table=True): t2: str = "bar" assert migrate(autogenerate=True) diff --git a/tests/units/test_page.py b/tests/units/test_page.py index ba571cc1691..81b882fc860 100644 --- a/tests/units/test_page.py +++ b/tests/units/test_page.py @@ -86,7 +86,7 @@ def load_foo(): description="Foo description", meta=[{"name": "keywords", "content": "foo, test"}], script_tags=["foo-script"], - on_load=load_foo, + on_load=load_foo, # ty:ignore[invalid-argument-type] https://github.com/astral-sh/ty/issues/4098 )(foo_) assert decorated_foo_ == foo_ assert len(clean_registration_context.decorated_pages) == 1 @@ -150,4 +150,4 @@ def test_page_namespace_unknown_attribute_raises(): """Unknown attributes on the page namespace raise AttributeError.""" page_module = importlib.import_module("reflex.page") with pytest.raises(AttributeError, match=r"reflex\.page"): - _ = page_module.definitely_not_an_attribute + _ = page_module.definitely_not_an_attribute # ty:ignore[unresolved-attribute] diff --git a/tests/units/test_prerequisites.py b/tests/units/test_prerequisites.py index 09b49edefac..7c575d11ec8 100644 --- a/tests/units/test_prerequisites.py +++ b/tests/units/test_prerequisites.py @@ -2295,14 +2295,12 @@ def test_extract_package_name(): assert js_runtimes._extract_package_name("@scope/pkg@1.2.3") == "@scope/pkg" -def test_cached_procedure(): +def test_cached_procedure(tmp_path: Path): call_count = 0 - temp_file = tempfile.mktemp() + temp_file = tmp_path / "no_args_cache" - @cached_procedure( - cache_file_path=lambda: Path(temp_file), payload_fn=lambda: "constant" - ) + @cached_procedure(cache_file_path=lambda: temp_file, payload_fn=lambda: "constant") def _function_with_no_args(): nonlocal call_count call_count += 1 @@ -2314,10 +2312,10 @@ def _function_with_no_args(): call_count = 0 - another_temp_file = tempfile.mktemp() + another_temp_file = tmp_path / "some_args_cache" @cached_procedure( - cache_file_path=lambda: Path(another_temp_file), + cache_file_path=lambda: another_temp_file, payload_fn=lambda *args, **kwargs: f"{repr(args), repr(kwargs)}", ) def _function_with_some_args(*args, **kwargs): @@ -2336,7 +2334,8 @@ def _function_with_some_args(*args, **kwargs): call_count = 0 @cached_procedure( - cache_file_path=lambda: Path(tempfile.mktemp()), payload_fn=lambda: "constant" + cache_file_path=lambda: tmp_path / f"fresh_{uuid.uuid4().hex}", + payload_fn=lambda: "constant", ) def _function_with_no_args_fn(): nonlocal call_count diff --git a/tests/units/test_route.py b/tests/units/test_route.py index 3e51a5b1bbe..0c2a1db0aba 100644 --- a/tests/units/test_route.py +++ b/tests/units/test_route.py @@ -170,8 +170,8 @@ def test_get_load_events_strips_frontend_path( conf = rx.Config(app_name="testing", frontend_path="/app") mocker.patch("reflex_base.config._get_config", return_value=conf) app = App() - app._unevaluated_pages = dict.fromkeys(["index", "app", "apple"]) # pyright: ignore[reportAttributeAccessIssue] - app._load_events = { # pyright: ignore[reportAttributeAccessIssue] + app._unevaluated_pages = dict.fromkeys(["index", "app", "apple"]) # ty:ignore[invalid-assignment] + app._load_events = { # ty:ignore[invalid-assignment] "index": ["index"], "app": ["app"], "apple": ["apple"], diff --git a/tests/units/test_sqlalchemy.py b/tests/units/test_sqlalchemy.py index 476fd9a2fe1..27aad820491 100644 --- a/tests/units/test_sqlalchemy.py +++ b/tests/units/test_sqlalchemy.py @@ -191,7 +191,7 @@ class ModelBase(Base, MappedAsDataclass): id: Mapped[int | None] = mapped_column(primary_key=True, default=None) # initial table - class AlembicThing(ModelBase): # pyright: ignore[reportRedeclaration] + class AlembicThing(ModelBase): t1: Mapped[str] = mapped_column(default="") with get_engine().connect() as connection: @@ -208,7 +208,7 @@ class AlembicThing(ModelBase): # pyright: ignore[reportRedeclaration] model_registry.get_metadata().clear() # Create column t2, mark t1 as optional with default - class AlembicThing(ModelBase): # pyright: ignore[reportRedeclaration] + class AlembicThing(ModelBase): t1: Mapped[str | None] = mapped_column(default="default") t2: Mapped[str] = mapped_column(default="bar") @@ -228,7 +228,7 @@ class AlembicThing(ModelBase): # pyright: ignore[reportRedeclaration] model_registry.get_metadata().clear() # Drop column t1 - class AlembicThing(ModelBase): # pyright: ignore[reportRedeclaration] + class AlembicThing(ModelBase): t2: Mapped[str] = mapped_column(default="bar") assert migrate(autogenerate=True) @@ -263,7 +263,7 @@ class AlembicSecond(ModelBase): # drop table (AlembicSecond) model_registry.get_metadata().clear() - class AlembicThing(ModelBase): # pyright: ignore[reportRedeclaration] + class AlembicThing(ModelBase): t2: Mapped[str] = mapped_column(default="bar") assert migrate(autogenerate=True) diff --git a/tests/units/test_state.py b/tests/units/test_state.py index cc61b0de658..fe4ca48f6fb 100644 --- a/tests/units/test_state.py +++ b/tests/units/test_state.py @@ -19,7 +19,7 @@ import sys import threading from collections import namedtuple -from collections.abc import AsyncGenerator, Callable, Mapping +from collections.abc import AsyncGenerator, Callable, Mapping, Sequence from hashlib import md5 from pathlib import Path from textwrap import dedent @@ -166,7 +166,7 @@ class TestMixin(BaseState, mixin=True): _mixin_backend: rx.Field[int] = rx.field(default_factory=lambda: 10) -class TestState(TestMixin, BaseState): # pyright: ignore[reportUnsafeMultipleInheritance] +class TestState(TestMixin, BaseState): """A test state.""" # Set this class as not test one @@ -331,7 +331,7 @@ def test_state() -> TestState: Returns: A test state. """ - return TestState() # pyright: ignore [reportCallIssue] + return TestState() # ty:ignore[missing-argument] @pytest.mark.parametrize("method", ["dict", "get_delta"]) @@ -374,7 +374,7 @@ def test_load_events_do_not_copy_router_data(app_module_mock): RouteVar.QUERY: {"name": "test"}, RouteVar.HEADERS: {"cookie": "session=secret", "user-agent": "browser"}, } - state = State(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + state = State(_reflex_internal_init=True) # ty:ignore[unknown-argument] state.router_data = router_data state.router = RouterData.from_router_data(router_data) load_events = _load_events_for_page(state) @@ -573,13 +573,13 @@ def test_dict(test_state: TestState): def test_class_indexing_with_vars(): """Test that we can index into a state var with another var.""" - prop = TestState.array[TestState.num1] # pyright: ignore [reportCallIssue, reportArgumentType] + prop = TestState.array[TestState.num1] # ty:ignore[invalid-argument-type] assert ( str(prop) == f"{TestState.get_name()}.array{FIELD_MARKER}?.at?.({TestState.get_name()}.num1{FIELD_MARKER})" ) - prop = TestState.mapping["a"][TestState.num1] # pyright: ignore [reportCallIssue, reportArgumentType] + prop = TestState.mapping["a"][TestState.num1] assert ( str(prop) == f'{TestState.get_name()}.mapping{FIELD_MARKER}?.["a"]?.at?.({TestState.get_name()}.num1{FIELD_MARKER})' @@ -1225,22 +1225,22 @@ class DynamicState(BaseState): assert not hasattr(ds1, "dynamic_int") ds1.add_var("dynamic_int", int, 42) # Existing and new instances get the default - assert ds1.dynamic_int == 42 # pyright: ignore [reportAttributeAccessIssue] - assert DynamicState().dynamic_int == 42 # pyright: ignore[reportAttributeAccessIssue] - assert isinstance(DynamicState.dynamic_int, Var) # pyright: ignore [reportAttributeAccessIssue] + assert ds1.dynamic_int == 42 # ty:ignore[unresolved-attribute] + assert DynamicState().dynamic_int == 42 # ty:ignore[unresolved-attribute] + assert isinstance(DynamicState.dynamic_int, Var) # ty:ignore[unresolved-attribute] ds1.add_var("dynamic_list", list[int], [5, 10]) - assert ds1.dynamic_list == [5, 10] # pyright: ignore [reportAttributeAccessIssue] + assert ds1.dynamic_list == [5, 10] # ty:ignore[unresolved-attribute] ds2 = DynamicState() - assert ds2.dynamic_list == [5, 10] # pyright: ignore[reportAttributeAccessIssue] - ds2.dynamic_list.append(15) # pyright: ignore[reportAttributeAccessIssue] - assert ds2.dynamic_list == [5, 10, 15] # pyright: ignore[reportAttributeAccessIssue] - assert DynamicState().dynamic_list == [5, 10] # pyright: ignore[reportAttributeAccessIssue] + assert ds2.dynamic_list == [5, 10] # ty:ignore[unresolved-attribute] + ds2.dynamic_list.append(15) # ty:ignore[unresolved-attribute] + assert ds2.dynamic_list == [5, 10, 15] # ty:ignore[unresolved-attribute] + assert DynamicState().dynamic_list == [5, 10] # ty:ignore[unresolved-attribute] ds1.add_var("dynamic_dict", dict[str, int], {"k1": 5, "k2": 10}) - assert ds1.dynamic_dict == {"k1": 5, "k2": 10} # pyright: ignore [reportAttributeAccessIssue] - assert ds2.dynamic_dict == {"k1": 5, "k2": 10} # pyright: ignore [reportAttributeAccessIssue] - assert DynamicState().dynamic_dict == {"k1": 5, "k2": 10} # pyright: ignore[reportAttributeAccessIssue] + assert ds1.dynamic_dict == {"k1": 5, "k2": 10} # ty:ignore[unresolved-attribute] + assert ds2.dynamic_dict == {"k1": 5, "k2": 10} # ty:ignore[unresolved-attribute] + assert DynamicState().dynamic_dict == {"k1": 5, "k2": 10} # ty:ignore[unresolved-attribute] class InterdependentState(BaseState): @@ -2152,11 +2152,14 @@ def dep_v(self) -> int: @pytest.mark.parametrize("use_partial", [True, False]) -def test_cached_var_depends_on_event_handler(use_partial: bool): +def test_cached_var_depends_on_event_handler( + use_partial: bool, monkeypatch: pytest.MonkeyPatch +): """A cached var that calls an event handler calculates deps correctly. Args: use_partial: if true, replace the EventHandler with functools.partial + monkeypatch: The pytest monkeypatch fixture. """ counter = 0 @@ -2181,7 +2184,7 @@ class MethodPartial(functools.partial): def __get__(self, instance: Any, owner: Any = None) -> Any: return self if instance is None else MethodType(self, instance) - HandlerState.handler = MethodPartial(HandlerState.handler.fn) # pyright: ignore [reportFunctionMemberAccess] + HandlerState.handler = MethodPartial(HandlerState.handler.fn) # ty:ignore[invalid-assignment, unresolved-attribute] assert isinstance(HandlerState.handler, functools.partial) else: assert isinstance(HandlerState.handler, EventHandler) @@ -2848,7 +2851,7 @@ def mock_app_simple(monkeypatch) -> rx.App: setattr(app_module, CompileVars.APP, app) app._state = TestState - app.event_namespace.emit = CopyingAsyncMock() # pyright: ignore [reportOptionalMemberAccess] + app.event_namespace.emit = CopyingAsyncMock() # ty:ignore[invalid-assignment] def _mock_get_app(*args, **kwargs): return app_module @@ -3473,7 +3476,7 @@ def assert_array_dirty(): assert_array_dirty() mutable_state.array.reverse() assert_array_dirty() - mutable_state.array.sort() # pyright: ignore[reportCallIssue] + mutable_state.array.sort() # ty:ignore[invalid-argument-type] assert_array_dirty() mutable_state.array[0] = 666 assert_array_dirty() @@ -3493,7 +3496,7 @@ def assert_array_dirty(): assert isinstance(mutable_state.array[0], MutableProxy) for item in mutable_state.array: assert isinstance(item, MutableProxy) - item["foo"] = "bar" # pyright: ignore[reportArgumentType, reportCallIssue] + item["foo"] = "bar" assert_array_dirty() @@ -3565,10 +3568,10 @@ def assert_hashmap_dirty(): mutable_value_third_ref = mutable_state.hashmap.pop("setdefault_mutable_key") assert not isinstance(mutable_value_third_ref, MutableProxy) assert_hashmap_dirty() - mutable_value_third_ref.append("baz") # pyright: ignore[reportAttributeAccessIssue] + mutable_value_third_ref.append("baz") # ty:ignore[unresolved-attribute] assert not mutable_state.dirty_vars # Unfortunately previous refs still will mark the state dirty... nothing doing about that - assert mutable_value.pop() # pyright: ignore[reportCallIssue] + assert mutable_value.pop() assert_hashmap_dirty() @@ -3723,7 +3726,7 @@ def test_duplicate_substate_class(mocker: MockerFixture): class TestState(BaseState): pass - class ChildTestState(TestState): # pyright: ignore [reportRedeclaration] + class ChildTestState(TestState): pass class ChildTestState(TestState): # noqa: F811 @@ -3766,21 +3769,21 @@ class MutableResetState(BaseState): items: list[list[int]] = default instance = MutableResetState() - assert instance.items.__wrapped__ is not default # pyright: ignore [reportAttributeAccessIssue] + assert instance.items.__wrapped__ is not default # ty:ignore[unresolved-attribute] assert instance.items == default == copied_default instance.items.append([3, 3]) assert instance.items != default assert instance.items != copied_default instance.reset() - assert instance.items.__wrapped__ is not default # pyright: ignore [reportAttributeAccessIssue] + assert instance.items.__wrapped__ is not default # ty:ignore[unresolved-attribute] assert instance.items == default == copied_default instance.items.append([3, 3]) assert instance.items != default assert instance.items != copied_default instance.reset() - assert instance.items.__wrapped__ is not default # pyright: ignore [reportAttributeAccessIssue] + assert instance.items.__wrapped__ is not default # ty:ignore[unresolved-attribute] assert instance.items == default == copied_default instance.items.append([3, 3]) assert instance.items != default @@ -3842,31 +3845,29 @@ class UnionState(BaseState): c3r: Custom3 = Custom3(c2r=Custom2(c1r=Custom1(foo=""))) custom_union: Custom1 | Custom2 | Custom3 = Custom1(foo="") - assert str(UnionState.c3.c2) == f'{UnionState.c3!s}?.["c2"]' # pyright: ignore [reportOptionalMemberAccess] - assert str(UnionState.c3.c2.c1) == f'{UnionState.c3!s}?.["c2"]?.["c1"]' # pyright: ignore [reportOptionalMemberAccess] - assert ( - str(UnionState.c3.c2.c1.foo) == f'{UnionState.c3!s}?.["c2"]?.["c1"]?.["foo"]' # pyright: ignore [reportOptionalMemberAccess] - ) + assert str(UnionState.c3.c2) == f'{UnionState.c3!s}?.["c2"]' # ty:ignore[unresolved-attribute] + assert str(UnionState.c3.c2.c1) == f'{UnionState.c3!s}?.["c2"]?.["c1"]' # ty:ignore[unresolved-attribute] + assert str(UnionState.c3.c2.c1.foo) == f'{UnionState.c3!s}?.["c2"]?.["c1"]?.["foo"]' # ty:ignore[unresolved-attribute] assert ( - str(UnionState.c3.c2.c1r.foo) == f'{UnionState.c3!s}?.["c2"]?.["c1r"]?.["foo"]' # pyright: ignore [reportOptionalMemberAccess] + str(UnionState.c3.c2.c1r.foo) == f'{UnionState.c3!s}?.["c2"]?.["c1r"]?.["foo"]' # ty:ignore[unresolved-attribute] ) - assert str(UnionState.c3.c2r.c1) == f'{UnionState.c3!s}?.["c2r"]?.["c1"]' # pyright: ignore [reportOptionalMemberAccess] + assert str(UnionState.c3.c2r.c1) == f'{UnionState.c3!s}?.["c2r"]?.["c1"]' # ty:ignore[unresolved-attribute] assert ( - str(UnionState.c3.c2r.c1.foo) == f'{UnionState.c3!s}?.["c2r"]?.["c1"]?.["foo"]' # pyright: ignore [reportOptionalMemberAccess] + str(UnionState.c3.c2r.c1.foo) == f'{UnionState.c3!s}?.["c2r"]?.["c1"]?.["foo"]' # ty:ignore[unresolved-attribute] ) assert ( - str(UnionState.c3.c2r.c1r.foo) # pyright: ignore [reportOptionalMemberAccess] + str(UnionState.c3.c2r.c1r.foo) # ty:ignore[unresolved-attribute] == f'{UnionState.c3!s}?.["c2r"]?.["c1r"]?.["foo"]' ) assert str(UnionState.c3i.c2) == f'{UnionState.c3i!s}?.["c2"]' assert str(UnionState.c3r.c2) == f'{UnionState.c3r!s}?.["c2"]' - assert UnionState.custom_union.foo is not None # pyright: ignore [reportAttributeAccessIssue] - assert UnionState.custom_union.c1 is not None # pyright: ignore [reportAttributeAccessIssue] - assert UnionState.custom_union.c1r is not None # pyright: ignore [reportAttributeAccessIssue] - assert UnionState.custom_union.c2 is not None # pyright: ignore [reportAttributeAccessIssue] - assert UnionState.custom_union.c2r is not None # pyright: ignore [reportAttributeAccessIssue] - assert types.is_optional(UnionState.opt_int._var_type) # pyright: ignore [reportAttributeAccessIssue, reportOptionalMemberAccess] - assert types.is_union(UnionState.int_float._var_type) # pyright: ignore [reportAttributeAccessIssue] + assert UnionState.custom_union.foo is not None # ty:ignore[unresolved-attribute] + assert UnionState.custom_union.c1 is not None # ty:ignore[unresolved-attribute] + assert UnionState.custom_union.c1r is not None # ty:ignore[unresolved-attribute] + assert UnionState.custom_union.c2 is not None # ty:ignore[unresolved-attribute] + assert UnionState.custom_union.c2r is not None # ty:ignore[unresolved-attribute] + assert types.is_optional(UnionState.opt_int._var_type) # ty:ignore[unresolved-attribute] + assert types.is_union(UnionState.int_float._var_type) # ty:ignore[unresolved-attribute] def test_set_base_field_via_setter(): @@ -4028,7 +4029,7 @@ def index(): app._compile_page("index") on_load_internal_name = format.format_event_handler( - OnLoadInternalState.on_load_internal # pyright: ignore[reportArgumentType] + OnLoadInternalState.on_load_internal # ty:ignore[invalid-argument-type] ) async with mock_base_state_event_processor as processor: @@ -4094,7 +4095,7 @@ def index(): app._compile_page("index") on_load_internal_name = format.format_event_handler( - OnLoadInternalState.on_load_internal # pyright: ignore[reportArgumentType] + OnLoadInternalState.on_load_internal # ty:ignore[invalid-argument-type] ) async with mock_base_state_event_processor as processor: @@ -4506,7 +4507,7 @@ async def test_get_var_value_of_the_whole_router() -> None: attribute it stands for, this raised UnretrievableVarValueError, while a state with a single `router` base var resolved it. """ - state = State(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + state = State(_reflex_internal_init=True) # ty:ignore[unknown-argument] router = await state.get_var_value(State.router) @@ -4900,9 +4901,9 @@ def test_redis_state_manager_config_knobs(tmp_path, expiration_kwargs, expected_ reflex_base.config.reload_config() state_manager = StateManagerRedis(redis=mock_redis()) - assert state_manager.lock_expiration == expected_values[0] # pyright: ignore [reportAttributeAccessIssue] - assert state_manager.token_expiration == expected_values[1] # pyright: ignore [reportAttributeAccessIssue] - assert state_manager.lock_warning_threshold == expected_values[2] # pyright: ignore [reportAttributeAccessIssue] + assert state_manager.lock_expiration == expected_values[0] + assert state_manager.token_expiration == expected_values[1] + assert state_manager.lock_warning_threshold == expected_values[2] @pytest.mark.parametrize( @@ -5206,10 +5207,10 @@ def test_mixin_state() -> None: assert "computed" in UsesMixinState.computed_vars assert "computed" in UsesMixinState.vars - state = UsesMixinState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + state = UsesMixinState(_reflex_internal_init=True) # ty:ignore[missing-argument, unknown-argument] assert state._backend == 0 assert state._backend_no_default == {} - other = UsesMixinState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + other = UsesMixinState(_reflex_internal_init=True) # ty:ignore[missing-argument, unknown-argument] assert state.get_value("_backend_no_default") is not other.get_value( "_backend_no_default" ) @@ -5273,12 +5274,12 @@ def marked_computed(self) -> str: """ return "marked" - marked_computed.fget._custom_marker = object() # pyright: ignore [reportFunctionMemberAccess] + marked_computed.fget._custom_marker = object() # ty:ignore[unresolved-attribute] def marked_handler(self): """An event handler tagged with a custom attribute.""" - marked_handler._custom_marker = object() # pyright: ignore [reportFunctionMemberAccess] + marked_handler._custom_marker = object() # ty:ignore[unresolved-attribute] def kwonly_default_handler(self, *, count: int = 1) -> int: """An event handler with a keyword-only default argument. @@ -5302,8 +5303,8 @@ def test_copy_fn_preserves_custom_function_attributes() -> None: copied_computed_fget = UsesMarkerMixin.computed_vars["marked_computed"].fget assert copied_computed_fget is not orig_computed_fget assert ( - copied_computed_fget._custom_marker # pyright: ignore [reportFunctionMemberAccess] - is orig_computed_fget._custom_marker # pyright: ignore [reportFunctionMemberAccess] + copied_computed_fget._custom_marker # ty:ignore[unresolved-attribute] + is orig_computed_fget._custom_marker ) orig_handler_fn = MarkerMixin.__dict__["marked_handler"] @@ -5355,7 +5356,7 @@ class UsesBackgroundTaskMixin(BackgroundTaskMixin, State): pass handler = UsesBackgroundTaskMixin.handle_in_background - assert handler.is_background # pyright: ignore [reportAttributeAccessIssue] + assert handler.is_background # pyright: ignore [reportAttributeAccessIssue] # ty:ignore[unresolved-attribute] def test_assignment_to_undeclared_vars(): @@ -5364,7 +5365,7 @@ def test_assignment_to_undeclared_vars(): class State(BaseState): val: str _val: str - __val: str # pyright: ignore [reportGeneralTypeIssues] + __val: str def handle_supported_regular_vars(self): self.val = "no underscore" @@ -5384,8 +5385,8 @@ class Substate(State): def handle_var(self): self.value = 20 - state = State() # pyright: ignore [reportCallIssue] - sub_state = Substate() # pyright: ignore [reportCallIssue] + state = State() # ty:ignore[missing-argument] + sub_state = Substate() # ty:ignore[missing-argument] with pytest.raises(SetUndefinedStateVarError): state.handle_regular_var() @@ -5427,7 +5428,7 @@ class WithDefault: class InheritsDefault(WithDefault, BaseState): _n: int - assert InheritsDefault()._n == 3 # pyright: ignore [reportCallIssue] + assert InheritsDefault()._n == 3 # ty:ignore[missing-argument] def _boom() -> int: msg = "factory blew up" @@ -5440,7 +5441,7 @@ class FactoryState(WithFailingFactory, BaseState): _n: int with pytest.raises(ValueError, match="factory blew up"): - _ = FactoryState()._n # pyright: ignore [reportCallIssue] + _ = FactoryState()._n # ty:ignore[missing-argument] def test_assignment_through_property_setter(): @@ -5475,7 +5476,7 @@ def derived(self) -> str: return "" with pytest.raises(AttributeError) as exc_info: - ReadOnlyState().derived = "x" # pyright: ignore [reportCallIssue, reportAttributeAccessIssue] + ReadOnlyState().derived = "x" # ty:ignore[invalid-assignment] # SetUndefinedStateVarError is itself an AttributeError, so exclude it by type assert not isinstance(exc_info.value, SetUndefinedStateVarError) @@ -5551,7 +5552,7 @@ class DillState(BaseState): _f: Callable | None = None _g: Any = None - state = DillState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + state = DillState(_reflex_internal_init=True) # ty:ignore[unknown-argument] state._o = Obj(f=lambda: 42) state._f = lambda: 420 @@ -5565,7 +5566,7 @@ class DillState(BaseState): assert unpickled_state._o.f() == 42 # Threading locks are unpicklable normally, and raise TypeError instead of PicklingError. - state2 = DillState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + state2 = DillState(_reflex_internal_init=True) # ty:ignore[unknown-argument] state2._g = threading.Lock() pk2 = state2._serialize() unpickled_state2 = BaseState._deserialize(pk2) @@ -5573,7 +5574,7 @@ class DillState(BaseState): assert isinstance(unpickled_state2._g, type(threading.Lock())) # Some object, like generator, are still unpicklable with dill. - state3 = DillState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + state3 = DillState(_reflex_internal_init=True) # ty:ignore[unknown-argument] state3._g = (i for i in range(10)) with pytest.raises(StateSerializationError): @@ -5821,7 +5822,7 @@ def renamed(mapping: Mapping[str, Any], old: str, new: str): values = {k: v for k, v in mapping.items() if k != old} return patch.dict(mapping, {**values, new: mapping[old]}, clear=True) - patches: list[contextlib.AbstractContextManager] = { + patches: Sequence[contextlib.AbstractContextManager] = { "state_renamed": [ patch.object(child, "get_full_name", classmethod(lambda cls: "renamed")) ], @@ -6051,7 +6052,7 @@ def test_deserialize_unreadable_state_raises_schema_mismatch( monkeypatch: The pytest monkeypatch fixture. """ module = app_classes_module - state = AppObjectState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + state = AppObjectState(_reflex_internal_init=True) # ty:ignore[unknown-argument] state._value = [module.Entry("a"), module.Color.BLUE, module.Point(1, 2)] data = state._serialize() assert isinstance(BaseState._deserialize(data=data), AppObjectState) @@ -6341,7 +6342,7 @@ def py_Any(self, a: Any): # noqa: D102 assert isinstance(a, list) self.passed = True - def py_unresolvable(self, u: Unresolvable): # noqa: D102, F821 # pyright: ignore [reportUndefinedVariable] + def py_unresolvable(self, u: Unresolvable): # noqa: D102, F821 # ty:ignore[unresolved-reference] assert isinstance(u, list) self.passed = True @@ -6419,6 +6420,9 @@ async def test_get_var_value( # LiteralVar with known value assert await state.get_var_value(rx.Var.create([1, 2, 3])) == [1, 2, 3] + # Cast LiteralVar resolves to the original literal value + assert await state.get_var_value(rx.Var.create(1).to(int)) == 1 + # Generic Var with no state with pytest.raises(UnretrievableVarValueError): await state.get_var_value(rx.Var("undefined")) @@ -6437,7 +6441,7 @@ async def test_get_var_value( await state.get_var_value(TestState.num1 + TestState.num2) with pytest.raises(UnretrievableVarValueError): # array[0] is a Var operation at runtime, though statically typed as the element. - await state.get_var_value(TestState.array[0]) # pyright: ignore[reportArgumentType] + await state.get_var_value(TestState.array[0]) # ty:ignore[invalid-argument-type] with pytest.raises(UnretrievableVarValueError): await state.get_var_value(TestState.mapping["a"]) @@ -6679,6 +6683,35 @@ async def fetch_data_state(self) -> None: await other_state.fetch_data_state() # Should not raise exception. +def test_add_dependency_on_own_state_keeps_declared_deps() -> None: + """A dependency added on the var's own state joins its declared deps.""" + + class OwnStateDepState(BaseState): + a: Field[int] = field(0) + b: Field[int] = field(0) + + @rx.var(deps=["a"], auto_deps=False) + def total(self) -> int: + return self.a + self.b + + cvar = OwnStateDepState.computed_vars["total"] + cvar.add_dependency(OwnStateDepState, OwnStateDepState.b) + assert cvar._deps(objclass=OwnStateDepState) == { + OwnStateDepState.get_full_name(): {"a", "b"} + } + + # A reload rebuilds the dependency map from _deps. + OwnStateDepState._var_dependencies = {} + OwnStateDepState._init_var_dependency_dicts() + state = OwnStateDepState() + assert state.total == 0 + state.dirty_vars.clear() + state.a = 1 + state._mark_dirty_computed_vars() + assert "total" in state.dirty_vars + assert state.total == 1 + + def test_override_base_method_skips_event_handler_wrapping(): """A method marked with __override_base_method__ should not be wrapped as an EventHandler.""" from reflex.state import _override_base_method @@ -6713,7 +6746,7 @@ def __set__(self, instance, value): self._values[id(instance)] = value class DescriptorState(rx.State): - _desc_value: int = _IntDescriptor() # pyright: ignore[reportAssignmentType] + _desc_value: int = _IntDescriptor() # ty:ignore[invalid-assignment] @rx.var def doubled(self) -> int: @@ -6723,7 +6756,7 @@ def doubled(self) -> int: assert "_desc_value" not in DescriptorState.base_vars # Descriptor remains the class-level attribute (not overwritten by a field). assert isinstance(DescriptorState.__dict__["_desc_value"], _IntDescriptor) - state = DescriptorState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + state = DescriptorState(_reflex_internal_init=True) # ty:ignore[unknown-argument] state._desc_value = 3 assert state.doubled == 6 @@ -6752,14 +6785,14 @@ def __set__(self, instance, value): child_descriptor = _Sentinel("child") class ParentDescState(rx.State): - _shared: int = parent_descriptor # pyright: ignore[reportAssignmentType] + _shared: int = parent_descriptor # ty:ignore[invalid-assignment] @rx.var def parent_view(self) -> int: return self._shared class ChildDescState(ParentDescState): - _shared: int = child_descriptor # pyright: ignore[reportAssignmentType] + _shared: int = child_descriptor # ty:ignore[invalid-assignment] @rx.var def child_view(self) -> int: @@ -6824,7 +6857,7 @@ def index(): "cancelled": asyncio.Event(), } on_load_internal_name = format.format_event_handler( - OnLoadInternalState.on_load_internal # pyright: ignore[reportArgumentType] + OnLoadInternalState.on_load_internal # ty:ignore[invalid-argument-type] ) async with mock_base_state_event_processor as processor: @@ -6905,7 +6938,7 @@ def test_setattr_alias_annotated_var(mocker: MockerFixture): mocker: Pytest mock fixture. """ error_mock = mocker.patch("reflex_base.vars.base.logger.error") - state = AliasAnnotatedState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + state = AliasAnnotatedState(_reflex_internal_init=True) # ty:ignore[unknown-argument] state.assign() assert state.name == "y" assert state.key == "b" @@ -6914,7 +6947,7 @@ def test_setattr_alias_annotated_var(mocker: MockerFixture): error_mock.assert_not_called() # A mismatched value is logged by the guard, not raised. - state.key = 1 # pyright: ignore[reportAttributeAccessIssue] + state.key = 1 # ty:ignore[invalid-assignment] assert state.key == 1 error_mock.assert_called_once() @@ -7064,7 +7097,7 @@ class OwnFieldsState(BaseState): count: int = 0 _secret: str = "" - state = OwnFieldsState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + state = OwnFieldsState(_reflex_internal_init=True) # ty:ignore[unknown-argument] state.count = 2 pickled = state.__getstate__() @@ -7083,7 +7116,7 @@ class LegacyPickleState(BaseState): class LegacyPickleSubstate(LegacyPickleState): pass - state = LegacyPickleState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + state = LegacyPickleState(_reflex_internal_init=True) # ty:ignore[unknown-argument] state.__setstate__({ "count": 3, "_backend_vars": {"_secret": "s"}, @@ -7097,7 +7130,7 @@ class LegacyPickleSubstate(LegacyPickleState): assert "_backend_vars" not in state.__dict__ # Substate pickles carried copies of inherited backend vars; they are dropped. - substate = LegacyPickleSubstate(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + substate = LegacyPickleSubstate(_reflex_internal_init=True) # ty:ignore[unknown-argument] substate.__setstate__({"_backend_vars": {"_secret": "stale"}, "dirty_vars": set()}) assert "_secret" not in substate.__dict__ assert "dirty_vars" not in substate.__dict__ @@ -7112,7 +7145,7 @@ class GeneratedDefaultState(BaseState): session_id: Field[str] = field(default_factory=lambda: uuid.uuid4().hex) _token: Field[str] = field(default_factory=lambda: uuid.uuid4().hex) - state = GeneratedDefaultState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + state = GeneratedDefaultState(_reflex_internal_init=True) # ty:ignore[unknown-argument] state.count = 1 blob = pickle.dumps(state) first, second = pickle.loads(blob), pickle.loads(blob) @@ -7145,7 +7178,7 @@ class OtherHandlerState(BaseState): assert isinstance(Holder().on_done, EventHandler) assert isinstance( - OtherHandlerState(_reflex_internal_init=True).on_done, # pyright: ignore [reportCallIssue] + OtherHandlerState(_reflex_internal_init=True).on_done, # ty:ignore[unknown-argument] EventHandler, ) @@ -7162,7 +7195,7 @@ def bump(self): class OrphanChild(OrphanParent): pass - child = OrphanChild(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + child = OrphanChild(_reflex_internal_init=True) # ty:ignore[unknown-argument] assert child.value == 1 child.bump() assert child.value == 2 @@ -7201,7 +7234,7 @@ def test_previous_release_pickle_keys_are_reserved(): with pytest.raises(StateValueError, match="_backend_vars"): class ClashingState(BaseState): - _backend_vars: dict = {} # pyright: ignore[reportIncompatibleVariableOverride] + _backend_vars: dict = {} # ty:ignore[invalid-attribute-override] def test_setstate_drops_inherited_fields(): @@ -7213,7 +7246,7 @@ class InheritedFieldParent(BaseState): class InheritedFieldChild(InheritedFieldParent): own: int = 2 - child = InheritedFieldChild(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + child = InheritedFieldChild(_reflex_internal_init=True) # ty:ignore[unknown-argument] child.__setstate__({ "shared": 5, "own": 3, @@ -7244,7 +7277,7 @@ class SizeLimitParent(BaseState): class SizeLimitChild(SizeLimitParent): pass - parent = SizeLimitParent(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + parent = SizeLimitParent(_reflex_internal_init=True) # ty:ignore[unknown-argument] parent.payload = "x" * 4096 assert parent.substates monkeypatch.setattr(state_module, "TOO_LARGE_SERIALIZED_STATE", 1024) @@ -7285,7 +7318,7 @@ async def plain_async(self) -> int: async def timed_async(self) -> int: return self.count - state = TimestampState(_reflex_internal_init=True) # pyright: ignore [reportCallIssue] + state = TimestampState(_reflex_internal_init=True) # ty:ignore[unknown-argument] assert (state.plain, state.timed) == (1, 1) assert ( asyncio.run(cast(Any, state.plain_async)), @@ -7388,8 +7421,8 @@ def bump(self): state_cls = make_state() assert state_cls.__name__ != "GuardState" state = state_cls() # pyright: ignore[reportCallIssue] - state.bump() # pyright: ignore[reportAttributeAccessIssue] - state.bump_mixin() # pyright: ignore[reportAttributeAccessIssue] + state.bump() # ty:ignore[unresolved-attribute] + state.bump_mixin() # ty:ignore[unresolved-attribute] assert vars(state)["_GuardState__scratch"] == 1 assert vars(state)["_GuardMixin__from_mixin"] == 1 assert vars(state)["__marker__"] == 2 @@ -7414,7 +7447,7 @@ def bump(self): ("items", "MissingItem | None", _NO_DEFAULT), ("items", "MissingItem", _NO_DEFAULT), ("items", "MissingItem", None), - ("items", list[ForwardRef("MissingItem")], []), + ("items", list[ForwardRef("MissingItem")], []), # ty:ignore[invalid-type-form] ("_items", "list[MissingItem]", []), ], ids=[ diff --git a/tests/units/test_telemetry.py b/tests/units/test_telemetry.py index db2cc600e3a..bca740d6a7a 100644 --- a/tests/units/test_telemetry.py +++ b/tests/units/test_telemetry.py @@ -287,7 +287,7 @@ def test_prepare_event_merges_properties(event_defaults): assert event is not None assert event["event"] == "compile" - props: dict = event["properties"] # pyright: ignore[reportAssignmentType] + props: dict = event["properties"] # ty:ignore[invalid-assignment] assert props["pages_count"] == 7 assert props["trigger"] == "initial" # Existing default keys are preserved. @@ -444,7 +444,7 @@ def test_prepare_event_properties_override_kwargs(event_defaults): ) assert event is not None - props: dict = event["properties"] # pyright: ignore[reportAssignmentType] + props: dict = event["properties"] # ty:ignore[invalid-assignment] assert props["template"] == "from-properties" @@ -508,7 +508,7 @@ def test_get_event_defaults_encodes_ids_as_uuid_strings(stub_event_default_sourc defaults = telemetry._get_event_defaults() assert defaults is not None - props: dict = defaults["properties"] # pyright: ignore[reportAssignmentType] + props: dict = defaults["properties"] # ty:ignore[invalid-assignment] assert isinstance(props["distinct_id"], str) assert isinstance(props["distinct_app_id"], str) assert props["distinct_id"] == str(uuid.UUID(int=installation_id)) @@ -948,7 +948,7 @@ def test_send_event_posts_json_without_httpx(mocker: MockerFixture): urlopen = mocker.patch("reflex.utils.telemetry.urllib.request.urlopen") mocker.patch.dict(sys.modules, {"httpx": None}) - assert telemetry._send_event({"api_key": "k", "event": "e"}) # pyright: ignore[reportArgumentType] + assert telemetry._send_event({"api_key": "k", "event": "e"}) # ty:ignore[invalid-argument-type, missing-typed-dict-key] request = urlopen.call_args.args[0] assert request.full_url == telemetry.POSTHOG_API_URL @@ -962,4 +962,4 @@ def test_send_event_swallows_delivery_errors(mocker: MockerFixture): mocker.patch( "reflex.utils.telemetry.urllib.request.urlopen", side_effect=OSError("down") ) - assert not telemetry._send_event({"api_key": "k", "event": "e"}) # pyright: ignore[reportArgumentType] + assert not telemetry._send_event({"api_key": "k", "event": "e"}) # ty:ignore[invalid-argument-type, missing-typed-dict-key] diff --git a/tests/units/test_var.py b/tests/units/test_var.py index fe0639d53ac..44ae03579bd 100644 --- a/tests/units/test_var.py +++ b/tests/units/test_var.py @@ -1366,7 +1366,7 @@ def test_array_map(mocker: MockerFixture): mock_deprecate = mocker.patch("reflex_base.utils.console.deprecate") assert re.fullmatch( r"\[1, 2, 3\]\.map\(\(\((\w+)\) => \(\1 \* 2\)\)\)", - str(array_var.foreach(lambda x: x * 2)), # pyright: ignore[reportDeprecated] + str(array_var.foreach(lambda x: x * 2)), # ty:ignore[deprecated] ) mock_deprecate.assert_called_once() assert mock_deprecate.call_args.kwargs["feature_name"] == "ArrayVar.foreach" @@ -1516,7 +1516,7 @@ def test_type_chains(): == '(Object.entries(({ ["a"] : 1, ["b"] : 2, ["c"] : 3 }) ?? {})?.at?.(1)?.at?.(1) - 1)' ) assert ( - str(object_var["c"] + object_var["b"]) # pyright: ignore [reportCallIssue, reportOperatorIssue] + str(object_var["c"] + object_var["b"]) == '(({ ["a"] : 1, ["b"] : 2, ["c"] : 3 })?.["c"] + ({ ["a"] : 1, ["b"] : 2, ["c"] : 3 })?.["b"])' ) @@ -1526,7 +1526,7 @@ def test_nested_dict(): assert ( str(arr[0]["bar"][0]) - == '[({ ["bar"] : ["foo", "bar"] })]?.at?.(0)?.["bar"]?.at?.(0)' # pyright: ignore [reportIndexIssue] + == '[({ ["bar"] : ["foo", "bar"] })]?.at?.(0)?.["bar"]?.at?.(0)' ) @@ -1734,7 +1734,7 @@ def test_unsupported_types_for_contains(var: Var): var: The base var. """ with pytest.raises(TypeError) as err: - assert var.contains(1) # pyright: ignore [reportAttributeAccessIssue] + assert var.contains(1) # ty:ignore[unresolved-attribute] assert ( err.value.args[0] == f"Var of type {var._var_type} does not support contains check." @@ -1764,7 +1764,7 @@ def test_unsupported_types_for_string_contains(other): def test_unsupported_default_contains(): with pytest.raises(TypeError) as err: - assert 1 in Var(_js_expr="var", _var_type=str).guess_type() # pyright: ignore [reportOperatorIssue] + assert 1 in Var(_js_expr="var", _var_type=str).guess_type() assert ( err.value.args[0] == "'in' operator not supported for Var types, use Var.contains() instead." diff --git a/tests/units/utils/test_exec.py b/tests/units/utils/test_exec.py index 23ab8c31f42..a615219980e 100644 --- a/tests/units/utils/test_exec.py +++ b/tests/units/utils/test_exec.py @@ -36,9 +36,9 @@ def _run_granian_reload_test_app(app_dir: str, port_queue: Queue) -> None: """ app_path = Path(app_dir) sys.path.insert(0, app_dir) - exec_utils.get_app_instance_from_file = lambda: "reload_app:app" - exec_utils.get_reload_paths = lambda: [app_path] - exec_utils.get_dev_backend_reload_marker = lambda: app_path / ".reload" + exec_utils.get_app_instance_from_file = lambda: "reload_app:app" # ty:ignore[invalid-assignment] + exec_utils.get_reload_paths = lambda: [app_path] # ty:ignore[invalid-assignment] + exec_utils.get_dev_backend_reload_marker = lambda: app_path / ".reload" # ty:ignore[invalid-assignment] original_socket = socket.socket def report_listener(*args, **kwargs): @@ -424,8 +424,8 @@ def serve(self): ) (server,) = servers - server._init_shared_socket() # pyright: ignore[reportAttributeAccessIssue] - listener: socket.socket = server._sso # pyright: ignore[reportAttributeAccessIssue] + server._init_shared_socket() # ty:ignore[unresolved-attribute] + listener: socket.socket = server._sso # ty:ignore[unresolved-attribute] try: assert listener.get_inheritable() # Once a worker calls listen the supervisor's descriptor keeps the @@ -434,7 +434,7 @@ def serve(self): with socket.create_connection(listener.getsockname(), timeout=1): pass finally: - server._close_shared_socket() # pyright: ignore[reportAttributeAccessIssue] + server._close_shared_socket() # ty:ignore[unresolved-attribute] @pytest.mark.skipif(sys.platform != "linux", reason="Granian uses this path on Linux") diff --git a/tests/units/utils/test_format.py b/tests/units/utils/test_format.py index 3bfbbc13343..9f26322e1d8 100644 --- a/tests/units/utils/test_format.py +++ b/tests/units/utils/test_format.py @@ -723,7 +723,7 @@ def test_format_query_params(input, output): ("input", "output"), [ ( - TestState(_reflex_internal_init=True).dict(), # pyright: ignore [reportCallIssue] + TestState(_reflex_internal_init=True).dict(), # ty:ignore[missing-argument, unknown-argument] { TestState.get_full_name(): { "array" + FIELD_MARKER: [1, 2, 3.15], @@ -757,7 +757,7 @@ def test_format_query_params(input, output): }, ), ( - DateTimeState(_reflex_internal_init=True).dict(), # pyright: ignore [reportCallIssue] + DateTimeState(_reflex_internal_init=True).dict(), # ty:ignore[unknown-argument] { DateTimeState.get_full_name(): { "d" + FIELD_MARKER: "1989-11-09", diff --git a/tests/units/utils/test_path_ops.py b/tests/units/utils/test_path_ops.py index a9b31d2d84f..8201aae2d14 100644 --- a/tests/units/utils/test_path_ops.py +++ b/tests/units/utils/test_path_ops.py @@ -84,7 +84,7 @@ def pause_before_write(target: Path, value: dict[str, object]) -> None: raise TimeoutError(msg) original_write_json_file(target, value) - path_ops._write_json_file = pause_before_write + path_ops._write_json_file = pause_before_write # ty:ignore[invalid-assignment] path_ops.update_json_file(file_path, update) @@ -120,7 +120,7 @@ def crashing_dump(_value, file, **_kwargs): partial_dump_written.set() os._exit(23) - path_ops.json.dump = crashing_dump + path_ops.json.dump = crashing_dump # ty:ignore[invalid-assignment] path_ops.update_json_file(target, {"crashed": True}) diff --git a/tests/units/utils/test_telemetry_accounting.py b/tests/units/utils/test_telemetry_accounting.py index 80ab4ba359e..85b2cfe9b2c 100644 --- a/tests/units/utils/test_telemetry_accounting.py +++ b/tests/units/utils/test_telemetry_accounting.py @@ -255,7 +255,7 @@ def test_collect_compile_event_payload_shape(mocker: MockerFixture): ctx = TelemetryContext(trigger="cli_compile") payload = telemetry_accounting._collect_compile_event_payload( - app, # pyright: ignore[reportArgumentType] + app, ctx, ) @@ -281,7 +281,7 @@ def test_collect_compile_event_payload_with_exception(mocker: MockerFixture): ctx.set_exception(RuntimeError("oops")) payload = telemetry_accounting._collect_compile_event_payload( - app, # pyright: ignore[reportArgumentType] + app, ctx, ) assert payload["exception"] == {"type": "RuntimeError"} @@ -327,7 +327,7 @@ class StubMemoWrapper: children = () counts = telemetry_accounting._count_components( - [StubMemoWrapper()], # pyright: ignore[reportArgumentType] + [StubMemoWrapper()], # ty:ignore[invalid-argument-type] ) assert counts == {"Button": 1} @@ -336,7 +336,7 @@ class StubMemoWrapper: def test_collect_features_used_emits_every_known_key(): """All names in ``_KNOWN_FEATURES`` ship in the snapshot, defaulted to 0.""" features = telemetry_accounting._collect_features_used( - _fake_app(), # pyright: ignore[reportArgumentType] + _fake_app(), _fake_config(), [], ) @@ -355,7 +355,7 @@ class StorageState(BaseState): plain: int = 0 features = telemetry_accounting._collect_features_used( - _fake_app(), # pyright: ignore[reportArgumentType] + _fake_app(), _fake_config(), [StorageState], ) @@ -380,7 +380,7 @@ class StorageGrandchild(StorageChild): extra: str = Cookie() features = telemetry_accounting._collect_features_used( - _fake_app(), # pyright: ignore[reportArgumentType] + _fake_app(), _fake_config(), [StorageParent, StorageChild, StorageGrandchild], ) @@ -395,7 +395,7 @@ def test_collect_features_used_upload_reads_class_flag(mocker: MockerFixture): mocker.patch.object(Upload, "is_used", True) used = telemetry_accounting._collect_features_used( - _fake_app(), # pyright: ignore[reportArgumentType] + _fake_app(), _fake_config(), [], ) @@ -403,7 +403,7 @@ def test_collect_features_used_upload_reads_class_flag(mocker: MockerFixture): mocker.patch.object(Upload, "is_used", False) unused = telemetry_accounting._collect_features_used( - _fake_app(), # pyright: ignore[reportArgumentType] + _fake_app(), _fake_config(), [], ) @@ -420,7 +420,7 @@ class SharedTwo(rx.SharedState): y: int = 0 features = telemetry_accounting._collect_features_used( - _fake_app(), # pyright: ignore[reportArgumentType] + _fake_app(), _fake_config(), [SharedOne, SharedTwo], ) @@ -438,7 +438,7 @@ def test_collect_features_used_counts_dynamic_routes(): }, ) features = telemetry_accounting._collect_features_used( - app, # pyright: ignore[reportArgumentType] + app, _fake_config(), [], ) @@ -458,7 +458,7 @@ def reflex_internal_task(): app = _fake_app(_lifespan_tasks={user_task: None, reflex_internal_task: None}) features = telemetry_accounting._collect_features_used( - app, # pyright: ignore[reportArgumentType] + app, _fake_config(), [], ) @@ -474,7 +474,7 @@ def test_collect_features_used_counts_registered_db_models(mocker: MockerFixture ) features = telemetry_accounting._collect_features_used( - _fake_app(), # pyright: ignore[reportArgumentType] + _fake_app(), _fake_config(), [], ) @@ -484,7 +484,7 @@ def test_collect_features_used_counts_registered_db_models(mocker: MockerFixture def test_collect_features_used_records_state_manager_mode(): """The configured state-manager mode lights up exactly one boolean key.""" features = telemetry_accounting._collect_features_used( - _fake_app(), # pyright: ignore[reportArgumentType] + _fake_app(), _fake_config(state_manager_mode=SimpleNamespace(value="redis")), [], ) @@ -496,7 +496,7 @@ def test_collect_features_used_records_state_manager_mode(): def test_collect_features_used_records_cors_customized(): """A non-default ``cors_allowed_origins`` sets the cors counter to 1.""" features = telemetry_accounting._collect_features_used( - _fake_app(), # pyright: ignore[reportArgumentType] + _fake_app(), _fake_config(cors_allowed_origins=("https://example.com",)), [], ) @@ -506,7 +506,7 @@ def test_collect_features_used_records_cors_customized(): def test_collect_features_used_default_cors_stays_zero(): """Default ``("*",)`` origins read as not customized.""" features = telemetry_accounting._collect_features_used( - _fake_app(), # pyright: ignore[reportArgumentType] + _fake_app(), _fake_config(), [], ) @@ -526,7 +526,7 @@ def fast(self): """Foreground handler that must not be miscounted.""" features = telemetry_accounting._collect_features_used( - _fake_app(), # pyright: ignore[reportArgumentType] + _fake_app(), _fake_config(), [BgState], ) diff --git a/tests/units/utils/test_token_manager.py b/tests/units/utils/test_token_manager.py index af64cb86b7a..3d4c20f03af 100644 --- a/tests/units/utils/test_token_manager.py +++ b/tests/units/utils/test_token_manager.py @@ -695,8 +695,8 @@ async def test_socket_record_subscriber_restores_deleted_live_record(): ) manager.sid_to_token[sid] = token await manager._store_socket_record(token, record) - event_log = redis._internals["event_log"] # pyright: ignore[reportAttributeAccessIssue] - on_update = redis._internals["event_log_on_update"] # pyright: ignore[reportAttributeAccessIssue] + event_log = redis._internals["event_log"] # ty:ignore[unresolved-attribute] + on_update = redis._internals["event_log_on_update"] # ty:ignore[unresolved-attribute] async def logged(channel: bytes, data: bytes, start: int = 0): """Wait until the mock redis logs an event. @@ -905,9 +905,9 @@ async def test_redis_token_manager_lost_and_found( event_namespace_factory: Factory fixture for EventNamespace instances. """ event_namespace1 = event_namespace_factory() - emit1_mock: Mock = event_namespace1.emit # pyright: ignore[reportAssignmentType] + emit1_mock: Mock = event_namespace1.emit # ty:ignore[invalid-assignment] event_namespace2 = event_namespace_factory() - emit2_mock: Mock = event_namespace2.emit # pyright: ignore[reportAssignmentType] + emit2_mock: Mock = event_namespace2.emit # ty:ignore[invalid-assignment] await event_namespace1.on_connect(sid="sid1", environ=query_string_for("token1")) await event_namespace2.on_connect(sid="sid2", environ=query_string_for("token2")) @@ -960,9 +960,9 @@ async def test_redis_token_manager_lost_and_found_router_data( event_namespace_factory: Factory fixture for EventNamespace instances. """ event_namespace1 = event_namespace_factory() - emit1_mock: Mock = event_namespace1.emit # pyright: ignore[reportAssignmentType] + emit1_mock: Mock = event_namespace1.emit # ty:ignore[invalid-assignment] event_namespace2 = event_namespace_factory() - emit2_mock: Mock = event_namespace2.emit # pyright: ignore[reportAssignmentType] + emit2_mock: Mock = event_namespace2.emit # ty:ignore[invalid-assignment] await event_namespace1.on_connect(sid="sid1", environ=query_string_for("token1")) await event_namespace2.on_connect(sid="sid2", environ=query_string_for("token2")) diff --git a/tests/units/vars/test_dep_tracking.py b/tests/units/vars/test_dep_tracking.py index d2b82ebc125..a2679d226e0 100644 --- a/tests/units/vars/test_dep_tracking.py +++ b/tests/units/vars/test_dep_tracking.py @@ -334,7 +334,7 @@ def test_get_var_value_with_import_from(): async def get_state_import_from(self: DependencyTestState): from tests.units.states.mutation import MutableTestState - return await self.get_var_value(MutableTestState.hashmap) # pyright: ignore[reportArgumentType] + return await self.get_var_value(MutableTestState.hashmap) # ty:ignore[invalid-argument-type] from tests.units.states.mutation import MutableTestState @@ -481,7 +481,7 @@ def has_last_name(self) -> str: @has_last_name.var def _has_last_name_var(cls) -> Var[str]: # Reference an unrelated field here to confirm the tracker uses fget, not this. - return cls.unrelated # pyright: ignore[reportReturnType] + return cls.unrelated # ty:ignore[invalid-return-type] def func_using_hybrid_property(self): return self.has_last_name diff --git a/tests/units/vars/test_hybrid_property.py b/tests/units/vars/test_hybrid_property.py index 1c34941d632..93d7f3bb7b7 100644 --- a/tests/units/vars/test_hybrid_property.py +++ b/tests/units/vars/test_hybrid_property.py @@ -71,7 +71,7 @@ def custom(cls) -> StringVar: assert_type(TypedHybridState.lookup, ObjectVar[dict[str, int]]) assert_type(TypedHybridState.custom, StringVar) - state = TypedHybridState(_reflex_internal_init=True) # pyright: ignore[reportCallIssue] + state = TypedHybridState(_reflex_internal_init=True) # ty:ignore[unknown-argument] assert_type(state.greeting, str) assert_type(state.doubled, int) assert_type(state.positive, bool) @@ -133,7 +133,7 @@ def value(self) -> str: @value.var def _value_var(cls) -> Var[str]: - return cls._secret # pyright: ignore[reportReturnType] + return cls._secret # ty:ignore[invalid-return-type] with pytest.raises(HybridPropertyError, match="_secret"): _ = VarFnBackendState.value @@ -156,7 +156,7 @@ def value(self) -> str: def _value_var(cls) -> Var[str]: seen["name"] = cls.__name__ seen["module"] = cls.__module__ - return cls.name # pyright: ignore[reportReturnType] + return cls.name # ty:ignore[invalid-return-type] _ = DunderState.value assert seen == {"name": "DunderState", "module": DunderState.__module__} @@ -194,7 +194,7 @@ class StateA(Mixin, rx.State): @original.var def _full_var(cls) -> Var: - return cls.first # pyright: ignore[reportReturnType] + return cls.first # ty:ignore[invalid-return-type] class StateB(Mixin, rx.State): first: str = "x" @@ -251,7 +251,7 @@ def doubled(self) -> int: @doubled.var def _doubled_var(cls) -> Var[int]: calls.append("var") - return cls.count * 2 # pyright: ignore[reportReturnType] + return cls.count * 2 # ty:ignore[invalid-return-type] assert calls == [] _ = LazyState.doubled @@ -270,11 +270,11 @@ def doubled(self) -> int: @doubled.var def _doubled_var(cls) -> Var[int]: - return cls.count * 3 # pyright: ignore[reportReturnType] + return cls.count * 3 # ty:ignore[invalid-return-type] # the alias does not linger on the class assert "_doubled_var" not in AliasState.__dict__ - assert AliasState(_reflex_internal_init=True).doubled == 0 # pyright: ignore[reportCallIssue] + assert AliasState(_reflex_internal_init=True).doubled == 0 # ty:ignore[unknown-argument] assert str(Var.create(AliasState.doubled)) == str(Var.create(AliasState.count * 3)) @@ -368,7 +368,7 @@ def _full_setter(self, value: str) -> None: def _full_deleter(self) -> None: self.first = self.last = "" - state = NameState(_reflex_internal_init=True) # pyright: ignore[reportCallIssue] + state = NameState(_reflex_internal_init=True) # ty:ignore[unknown-argument] state.full = "Ada Lovelace" # pyright: ignore[reportAttributeAccessIssue] assert (state.first, state.last) == ("Ada", "Lovelace") assert state.full == "Ada Lovelace" @@ -395,9 +395,9 @@ def doubled(self) -> int: # pyright: ignore[reportRedeclaration] @doubled.var @classmethod def doubled(cls) -> Var[int]: - return cls.count * 4 # pyright: ignore[reportReturnType] + return cls.count * 4 # ty:ignore[invalid-return-type] - assert ClassmethodVarState(_reflex_internal_init=True).doubled == 0 # pyright: ignore[reportCallIssue] + assert ClassmethodVarState(_reflex_internal_init=True).doubled == 0 # ty:ignore[unknown-argument] assert str(Var.create(ClassmethodVarState.doubled)) == str( Var.create(ClassmethodVarState.count * 4) ) @@ -695,7 +695,7 @@ class GuardState(HybridBase, rx.State): assert calls == [] # The annotation must not shadow the inherited descriptor with storage. assert "_foo" not in GuardState.get_fields() - assert GuardState(_reflex_internal_init=True)._foo == 1 # pyright: ignore[reportCallIssue] + assert GuardState(_reflex_internal_init=True)._foo == 1 # ty:ignore[missing-argument, unknown-argument] assert calls == ["getter ran"] @@ -705,14 +705,14 @@ def test_hybrid_property_inherited_annotated_name_keeps_descriptor(): class HybridBase: @hybrid_property def doubled(self) -> int: - return self.count * 2 # pyright: ignore[reportAttributeAccessIssue] + return self.count * 2 # ty:ignore[unresolved-attribute] class InheritedState(HybridBase, rx.State): count: int = 3 doubled: int # pyright: ignore[reportIncompatibleVariableOverride] assert "doubled" not in InheritedState.get_fields() - assert InheritedState(_reflex_internal_init=True).doubled == 6 # pyright: ignore[reportCallIssue] + assert InheritedState(_reflex_internal_init=True).doubled == 6 # ty:ignore[missing-argument, unknown-argument] assert str(Var.create(InheritedState.doubled)) == str( Var.create(InheritedState.count * 2) ) @@ -756,7 +756,7 @@ def doubled(self) -> int: return self.count * 2 assert isinstance(AnnotatedState.__dict__["doubled"], hybrid_property) - assert AnnotatedState(_reflex_internal_init=True).doubled == 6 # pyright: ignore[reportCallIssue] + assert AnnotatedState(_reflex_internal_init=True).doubled == 6 # ty:ignore[unknown-argument] assert str(Var.create(AnnotatedState.doubled)) == str( Var.create(AnnotatedState.count * 2) ) @@ -862,14 +862,14 @@ def upper_names(self) -> list[str]: @upper_names.var @classmethod def _upper_names_var(cls) -> Var[list[str]]: - return cls.names # pyright: ignore[reportReturnType] + return cls.names # ty:ignore[invalid-return-type] # the operations these var types carry must be available on class access assert isinstance(LadderState.positive & True, Var) assert isinstance(LadderState.doubled + 1, Var) assert isinstance(LadderState.upper_names.length(), Var) # ... while the getter still serves the instance - state = LadderState(_reflex_internal_init=True) # pyright: ignore[reportCallIssue] + state = LadderState(_reflex_internal_init=True) # ty:ignore[unknown-argument] state.count = 2 state.names = ["a"] assert state.positive is True diff --git a/tests/units/vars/test_object.py b/tests/units/vars/test_object.py index 24d384d1f85..3b2dd7b1729 100644 --- a/tests/units/vars/test_object.py +++ b/tests/units/vars/test_object.py @@ -120,6 +120,24 @@ class ObjectState(rx.State): base_list: rx.Field[list[Base]] = rx.field([Base()]) + @rx.var + def base_computed(self) -> Base: + """A computed var returning a pydantic model. + + Returns: + The pydantic model. + """ + return self.base + + @rx.var + async def base_computed_async(self) -> Base: + """An async computed var returning a pydantic model. + + Returns: + The pydantic model. + """ + return self.base + @pytest.mark.parametrize("type_", [Base, Bare, SqlaModel, Dataclass]) def test_var_create(type_: type[Base | Bare | SqlaModel | Dataclass]) -> None: @@ -272,6 +290,10 @@ def test_typing() -> None: _ = assert_type(list_var, ArrayVar[Sequence[Base]]) list_var_0 = list_var[0] _ = assert_type(list_var_0, ObjectVar[Base]) + computed_var = ObjectState.base_computed + _ = assert_type(computed_var, ObjectVar[Base]) + computed_var = ObjectState.base_computed_async + _ = assert_type(computed_var, ObjectVar[Base]) # Sqla var = ObjectState.sqlamodel diff --git a/uv.lock b/uv.lock index 42feb8519e3..1f6db2fb04c 100644 --- a/uv.lock +++ b/uv.lock @@ -9,10 +9,10 @@ resolution-markers = [ "python_full_version == '3.14.*' and sys_platform == 'emscripten'", "python_full_version == '3.14.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'emscripten'", "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version < '3.12' and sys_platform == 'win32'", "python_full_version < '3.12' and sys_platform == 'emscripten'", @@ -37,11 +37,12 @@ reflex-components-code = false reflex-components-recharts = false reflex-components-core = false reflex-components-dataeditor = false +ty = false reflex-base = false reflex-components-markdown = false +virtualenv = "2026-10-22T00:00:00Z" reflex-build-sdk = false certifi = "2026-10-21T00:00:00Z" -virtualenv = "2026-10-22T00:00:00Z" reflex-components-internal = false reflex-components-lucide = false reflex-components-radix = false @@ -835,10 +836,10 @@ resolution-markers = [ "python_full_version == '3.14.*' and sys_platform == 'emscripten'", "python_full_version == '3.14.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'emscripten'", "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ @@ -2613,10 +2614,10 @@ resolution-markers = [ "python_full_version == '3.14.*' and sys_platform == 'emscripten'", "python_full_version == '3.14.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'emscripten'", "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] sdist = { url = "https://files.pythonhosted.org/packages/95/b0/c7453d0b6e2073c3264468b106ee1563750cecc910965e67357e3698c83e/numpy-2.5.4.tar.gz", hash = "sha256:9a94cf751c9ad8ebaa835bcd3d40dacf8534ad086b88c38029b65123c7999d2a", size = 20866315, upload-time = "2026-10-10T20:05:31.422Z" } @@ -3649,10 +3650,10 @@ resolution-markers = [ "python_full_version == '3.14.*' and sys_platform == 'emscripten'", "python_full_version == '3.14.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'emscripten'", "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ @@ -3681,19 +3682,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/38/bb/d215ee7c73b61497b28a5503f9f53523f294fcc936762b7caf90e0c1c2b5/pyparsing-3.3.3-py3-none-any.whl", hash = "sha256:ece8c00a69cf01b45d0b1dedabb469c90d8caf996d4fda40f147627a122849a4", size = 126420, upload-time = "2026-09-20T20:59:04.025Z" }, ] -[[package]] -name = "pyright" -version = "1.1.411" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nodeenv" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7e/ab/265f7dc69d28113ebba19092e57b075f41543b2ed048429c5f56e2b88eac/pyright-1.1.411.tar.gz", hash = "sha256:d885a0551f2e763b089a02702174e7f4ba77548cddabc972ab86d1f7f1b0f998", size = 4112861, upload-time = "2026-06-25T02:14:06.37Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/49/385be530a6a5b78d1cbcd5c2e38debc8959a2fc6bdb716f4e581002979fc/pyright-1.1.411-py3-none-any.whl", hash = "sha256:dc7c72a8e2700c55baa127554040e067041ea53ccfd50bf96308cc4291c7d5d9", size = 6181526, upload-time = "2026-06-25T02:14:04.691Z" }, -] - [[package]] name = "pysocks" version = "1.7.1" @@ -4078,7 +4066,6 @@ dev = [ { name = "psycopg" }, { name = "psycopg", extra = ["binary"], marker = "python_full_version < '3.15'" }, { name = "pydantic" }, - { name = "pyright" }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-benchmark" }, @@ -4175,7 +4162,6 @@ dev = [ { name = "psycopg", marker = "python_full_version >= '3.15'" }, { name = "psycopg", extras = ["binary"], marker = "python_full_version < '3.15'" }, { name = "pydantic" }, - { name = "pyright" }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-benchmark" }, @@ -4347,10 +4333,14 @@ name = "reflex-components-internal" source = { editable = "packages/reflex-components-internal" } dependencies = [ { name = "reflex" }, + { name = "reflex-base" }, ] [package.metadata] -requires-dist = [{ name = "reflex", editable = "." }] +requires-dist = [ + { name = "reflex", editable = "." }, + { name = "reflex-base", editable = "packages/reflex-base" }, +] [[package]] name = "reflex-components-lucide" @@ -4873,10 +4863,10 @@ resolution-markers = [ "python_full_version == '3.14.*' and sys_platform == 'emscripten'", "python_full_version == '3.14.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'emscripten'", "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ @@ -5392,27 +5382,27 @@ wheels = [ [[package]] name = "ty" -version = "0.0.88" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f5/e8/303e333a45289c2f1f006661c9aa535de83b316a6bfc2d2f97ba815be143/ty-0.0.88.tar.gz", hash = "sha256:5e3165a05b3757edd5a08b1fc6cb4a00c3b067100416d50afb2d13a5ec102206", size = 7968779, upload-time = "2026-10-15T09:41:07.334Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/de/7e/a62ddf5c56cf0f96fdc268bb0ec4bfe16e28b50d9158de8e7038b004e515/ty-0.0.88-py3-none-linux_armv6l.whl", hash = "sha256:19f24e69e97d9edfb05fb2e1c7fe2b6fcce275338415e2f7de23d74627f2b436", size = 14240767, upload-time = "2026-10-15T09:40:23.285Z" }, - { url = "https://files.pythonhosted.org/packages/77/b0/ca23cf93931c6dcf790376c2dac6d2cbcbc1c5fbbead6a536c52eae6ac22/ty-0.0.88-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:957f0db83b9b0f837b86fe4a0a8fb98db8da89444555246871e6eb2820629c1b", size = 13755861, upload-time = "2026-10-15T09:40:26.292Z" }, - { url = "https://files.pythonhosted.org/packages/8c/a6/91d2aa967a69535845445660d3a9412f7f4f746597c650e5d3a799c9e286/ty-0.0.88-py3-none-macosx_11_0_arm64.whl", hash = "sha256:021bd4a6d01d4a39e48a87e308161e7adea851b8cab9f4c71452dde6e365aa15", size = 12771934, upload-time = "2026-10-15T09:40:28.913Z" }, - { url = "https://files.pythonhosted.org/packages/2e/a4/266f2dacbded7fac1f567292363ad05d4d03b246a8bd5ccd68206d0c9ce0/ty-0.0.88-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcd956e6c3c8b038a3725f2bf255a45a284ece64a012a4e790fbf23db862af84", size = 13638979, upload-time = "2026-10-15T09:40:31.49Z" }, - { url = "https://files.pythonhosted.org/packages/18/c9/4d7ec25675e9d2d70d9a8635d47b4737540818852e35fc6b7ca47b3e7f99/ty-0.0.88-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a8beb5fe8ae4ee8853891647d27cec7b65f6547532e9250cd3439181993aa973", size = 13971852, upload-time = "2026-10-15T09:40:34.039Z" }, - { url = "https://files.pythonhosted.org/packages/57/5d/0753dd860127f2601333156948ce2680ac2f65534ee39c81e9d4623f51aa/ty-0.0.88-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6aa805d8d4ab6512ca9591c221f828d818c000cdd5bd5108923eb21405eefebd", size = 14876774, upload-time = "2026-10-15T09:40:36.86Z" }, - { url = "https://files.pythonhosted.org/packages/26/8b/706b59938c4c83caed1df9a74f9b6d1e9d7d196b5006f3655b618daab5da/ty-0.0.88-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7dfb625a98f8fb02995aa3e3fb762c910158f1419bf38d1d1dcb97f35526e4b0", size = 15249187, upload-time = "2026-10-15T09:40:39.643Z" }, - { url = "https://files.pythonhosted.org/packages/09/1a/1a214f674e66c65347380cc8b637ffbb50624ab4ff7dc0d6f0bf34c64303/ty-0.0.88-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6784a5398c69ea39ad43512ba5fa7850599d8f371b7caa974dc8603b9634e63f", size = 15202315, upload-time = "2026-10-15T09:40:42.436Z" }, - { url = "https://files.pythonhosted.org/packages/e4/9e/a8a0af89ce94e87f6b4fdec62dce473d2858223ba7298276911c568f413c/ty-0.0.88-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ec0c364abad7e81013c1b4ec788d811078b9b20a8a2e07ac8613499eb6f104f", size = 14447671, upload-time = "2026-10-15T09:40:44.842Z" }, - { url = "https://files.pythonhosted.org/packages/17/74/be3cd8bee9ad01615449a1c22c6be2cc9a5d652eb6c1e9b2e993dc8b9141/ty-0.0.88-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:96940e5393ec00732bfaa747825979ebd971f0bafe538538d164bcba4cec5408", size = 14728283, upload-time = "2026-10-15T09:40:47.47Z" }, - { url = "https://files.pythonhosted.org/packages/84/e7/5918d99b7aff20c4a55f50d64620186af822a023ca767b65d965a3fd4858/ty-0.0.88-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c245fab62af678d3df2e8bf26550c0f81f5567b72de670863e300cab07d0b891", size = 13637751, upload-time = "2026-10-15T09:40:49.832Z" }, - { url = "https://files.pythonhosted.org/packages/c5/df/2eb1ddfafd986fdfa7be9941f2665945fe6dbcc952309195ba536f6394fd/ty-0.0.88-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:90407c5c7e0387295aab0e2d4de0ed7a7942f9793a4628942f367257d431e55c", size = 13985403, upload-time = "2026-10-15T09:40:52.348Z" }, - { url = "https://files.pythonhosted.org/packages/67/12/f9fc5e038dd2f0372be8ffbf5b1e429ef084035efdede5288a6fae74c52f/ty-0.0.88-py3-none-musllinux_1_2_i686.whl", hash = "sha256:591ef09e37bec260399cd526d694a815b8f1dab55dc841a44bd9ccb78cca84a1", size = 14305076, upload-time = "2026-10-15T09:40:54.944Z" }, - { url = "https://files.pythonhosted.org/packages/5e/5a/8a5e7c43b5d981d1f383602ddeaea91e0fde18900d1808ee74e1c894570c/ty-0.0.88-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:092522f2fa87becfb3b098a1f58ec1b82dfd7c87eaa0533c5ce500a743d8e79e", size = 14637327, upload-time = "2026-10-15T09:40:57.462Z" }, - { url = "https://files.pythonhosted.org/packages/5f/16/426272696ea754575305868787b35f18c23a3851c363827f27c7c8093cff/ty-0.0.88-py3-none-win32.whl", hash = "sha256:954cc19cd68015d4e92eb3f9218760d324dbdf67daae0e0da2c0179b644f450f", size = 13178338, upload-time = "2026-10-15T09:41:00.059Z" }, - { url = "https://files.pythonhosted.org/packages/49/a1/db4113fa72d44a28aeeccf3a71f9a803b278d945b11fa7b070a703d8bffd/ty-0.0.88-py3-none-win_amd64.whl", hash = "sha256:c76f1c65a492fed594bc14a1c70a1fdacd8a3165440a1eaa5af7f3c248fee963", size = 13690632, upload-time = "2026-10-15T09:41:02.379Z" }, - { url = "https://files.pythonhosted.org/packages/70/16/bc82e209f0d4de6213d41f58dd619b3e65d24cb58a6da0cd7c6665dd6654/ty-0.0.88-py3-none-win_arm64.whl", hash = "sha256:9b4289f6dec4123cf671a5b3d9512cdbf03889996d6895efc595bdc50573eafc", size = 13251351, upload-time = "2026-10-15T09:41:04.912Z" }, +version = "0.0.73" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/90/c4e1bb4cead3b644c3e258a27f9b05c7dc5eb0ec96a4f5282194edae9e0d/ty-0.0.73.tar.gz", hash = "sha256:823d4ce0d237bfc7eb6bcee70842f2c0706113813a16951077840743712f4b74", size = 6712739, upload-time = "2026-08-19T03:12:43.381Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/0f/f5e1801e55cc631f2db193276675b30561b963a2403da832bffb5d100267/ty-0.0.73-py3-none-linux_armv6l.whl", hash = "sha256:90a946082bf9bc446b5e72973d9f4ff1222a240b2ca4c9e6eed61eb913e30810", size = 12715452, upload-time = "2026-08-19T03:12:06.673Z" }, + { url = "https://files.pythonhosted.org/packages/54/32/515dd05074c213b433524ab97eb003b0132ae7e358e0d75633ba7a314ed8/ty-0.0.73-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b7d6b5c6a6db7ea95fbbc16af514ef44a27a29a2fe1dc798900790364d170209", size = 12301870, upload-time = "2026-08-19T03:12:08.924Z" }, + { url = "https://files.pythonhosted.org/packages/50/4d/085b4889f0d4bbe4af8b96242d4a1cb209fff95967cfa239ea141983719b/ty-0.0.73-py3-none-macosx_11_0_arm64.whl", hash = "sha256:dd6f657f463e01372d8688f235be164750c8db722c97da27fa4903aa8d40b203", size = 12111741, upload-time = "2026-08-19T03:12:11.067Z" }, + { url = "https://files.pythonhosted.org/packages/95/f6/d6ec277cadfecf03ad4c18551b67c4c6eb7807a0560d801db14be99d7a89/ty-0.0.73-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2de468e33fd44c9ff1c43473a7316f4289480f5cba8995a67b6d22aee39ca9", size = 12196124, upload-time = "2026-08-19T03:12:13.14Z" }, + { url = "https://files.pythonhosted.org/packages/75/b7/ce78d8707563af9cae9bbd25328bfbc4931035085bd20089adf0c418f70e/ty-0.0.73-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2942fa0ef795a66034cdc8d75a72f453442f3b58ff2f69b4da05b7b954765b55", size = 12488557, upload-time = "2026-08-19T03:12:15.252Z" }, + { url = "https://files.pythonhosted.org/packages/d8/e8/329b9851b23502758c5c98e8cc875ea2a1b4c9674b4ca3a86da56a5063d3/ty-0.0.73-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e0f1ef14f642e18ac4e7a616a2796dcf7a5d82e28cd17f9796494acc7c4aabb", size = 13215606, upload-time = "2026-08-19T03:12:17.225Z" }, + { url = "https://files.pythonhosted.org/packages/36/38/67fedfd2cb77516ef0066b1642f487dba0eb3006493cf3475b15f5b8b228/ty-0.0.73-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16981e15fdceedb37d0aff76c5ac25914595dfee2675af95335550064251ad22", size = 13665497, upload-time = "2026-08-19T03:12:19.286Z" }, + { url = "https://files.pythonhosted.org/packages/8e/b3/154f4dd48ec5eebc186ab4b822c6e62f982fc5ddfd262d6e3903c2acba44/ty-0.0.73-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:644b2bec8a2e2e4957a942ae81d6cff5571c489bb5a8675e4d3886de537a694d", size = 13351231, upload-time = "2026-08-19T03:12:21.353Z" }, + { url = "https://files.pythonhosted.org/packages/35/5f/d462496903fbe453fb76363f8478be929c8e6ff21e6928c57dcd7e5fa21f/ty-0.0.73-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:338d565be3186f50ff8e9d10483685549c2d23f0754485d5ede3b54f4319188a", size = 12782586, upload-time = "2026-08-19T03:12:23.667Z" }, + { url = "https://files.pythonhosted.org/packages/87/52/ec6d24b74abe3ec324204c1c71e6d0c6c76a17ffc15fd51d603b0a302abe/ty-0.0.73-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:11c7b6d839309d2c102cb3a4c03d817176bbfab5b2fccc95a75ec5c9597421c9", size = 13247134, upload-time = "2026-08-19T03:12:25.956Z" }, + { url = "https://files.pythonhosted.org/packages/26/20/cc74650fec56a54786c6d7c89e09576fcad3092be34cf21715d39a406a9b/ty-0.0.73-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:488572db7ff97fb50ea36a76250f2d617c9727d143da6c7bf0623276eb0fc507", size = 12309344, upload-time = "2026-08-19T03:12:28.122Z" }, + { url = "https://files.pythonhosted.org/packages/89/bd/4b0a9087f4315d7fbadf77a3ce44c816cc9ffabed1ced06cc5be81fbc414/ty-0.0.73-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1b958ebceefbbf594e59eb8d3d55bbd033ce634026fcba3e4bc3179e78e45bb7", size = 12502319, upload-time = "2026-08-19T03:12:30.128Z" }, + { url = "https://files.pythonhosted.org/packages/11/80/0a925074911fe111912ea29d9eed309bcc183f43d2fb3eef07db056a0beb/ty-0.0.73-py3-none-musllinux_1_2_i686.whl", hash = "sha256:91a32993b3c34e42c3f323ad6c0399cb596bd1c27e9b7f20db7cd64c1067b68e", size = 12753688, upload-time = "2026-08-19T03:12:32.433Z" }, + { url = "https://files.pythonhosted.org/packages/24/6b/aeccaf89efbc2e112bd415340a22e2669ec998aa397242503e747b712ca4/ty-0.0.73-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:bab8a19fbf51f479bddb2a12c5fabfe52f918a5590362321ed5d89b44eb62c15", size = 13069050, upload-time = "2026-08-19T03:12:35.398Z" }, + { url = "https://files.pythonhosted.org/packages/d7/3e/eae485fd86c1585943fd4e1746b0757b2da01e2c43136ebe8c686fe1c7f1/ty-0.0.73-py3-none-win32.whl", hash = "sha256:03347a612f0fa020b19bfd8dbd521db6ecc75d377a3e4d4f6e6c2e62871da4cc", size = 12053187, upload-time = "2026-08-19T03:12:37.565Z" }, + { url = "https://files.pythonhosted.org/packages/a7/01/9b8b983786e3ce34924e372e8b76b92b508273ab65c589fc7e88cc03ee17/ty-0.0.73-py3-none-win_amd64.whl", hash = "sha256:cedd05122ded0b5dcc55431a370e974b747f99c41c290a3d2ab8c1867f197519", size = 12693838, upload-time = "2026-08-19T03:12:39.483Z" }, + { url = "https://files.pythonhosted.org/packages/ea/88/25333bbfea6a5dc064371d2002d3d4807db90b84d5448f9106b2712b0fbc/ty-0.0.73-py3-none-win_arm64.whl", hash = "sha256:e47068f8369dea5d641a26a2ad0a947a320b02ff87099b07e95de0323245a4dc", size = 12443573, upload-time = "2026-08-19T03:12:41.449Z" }, ] [[package]]