From d022586b0edf41e5fa295ffd5afeb280767553fd Mon Sep 17 00:00:00 2001 From: Jakob Pinterits Date: Sun, 19 Jan 2025 13:36:37 +0100 Subject: [PATCH] update import convention for dataclasses & abc --- CONTRIBUTING.md | 120 +++++++++++------- extensions/rio_jobs.py | 4 +- rio/cli/nice_traceback.py | 18 +-- rio/cli/run_project/run_models.py | 6 +- rio/component_meta.py | 4 +- rio/components/app_root.py | 4 +- rio/components/auto_form.py | 7 +- rio/components/banner.py | 4 +- rio/components/button.py | 6 +- rio/components/calendar.py | 6 +- rio/components/card.py | 4 +- rio/components/checkbox.py | 6 +- rio/components/code_block.py | 4 +- rio/components/color_picker.py | 6 +- rio/components/component.py | 4 +- rio/components/date_input.py | 6 +- rio/components/devel_component.py | 6 +- rio/components/drawer.py | 6 +- rio/components/dropdown.py | 6 +- rio/components/file_picker_area.py | 10 +- rio/components/flow_container.py | 4 +- rio/components/grid.py | 6 +- rio/components/icon.py | 4 +- rio/components/icon_button.py | 4 +- rio/components/image.py | 4 +- rio/components/key_event_listener.py | 6 +- rio/components/labeled_column.py | 4 +- rio/components/markdown.py | 4 +- rio/components/mouse_event_listener.py | 16 +-- rio/components/multi_line_text_input.py | 8 +- rio/components/number_input.py | 10 +- rio/components/page_view.py | 6 +- rio/components/pointer_event_listener.py | 8 +- rio/components/popup.py | 4 +- rio/components/rectangle.py | 4 +- rio/components/revealer.py | 6 +- rio/components/scroll_container.py | 4 +- rio/components/scroll_target.py | 4 +- rio/components/separator.py | 4 +- rio/components/slider.py | 4 +- rio/components/slideshow.py | 4 +- rio/components/switch.py | 6 +- rio/components/switcher.py | 4 +- rio/components/switcher_bar.py | 4 +- rio/components/table.py | 22 ++-- rio/components/text.py | 6 +- rio/components/text_input.py | 10 +- rio/data_models.py | 12 +- rio/debug/dev_tools/component_attributes.py | 4 +- rio/debug/dev_tools/component_tree.py | 4 +- rio/debug/dev_tools/icons_page.py | 3 +- rio/debug/dev_tools/layout_display.py | 4 +- rio/debug/dev_tools/layout_subpage.py | 8 +- rio/debug/typing_utils.py | 4 +- rio/debug/validator.py | 4 +- rio/event.py | 8 +- rio/extension_event.py | 14 +- rio/fills.py | 12 +- rio/routing.py | 26 ++-- rio/snippets/project_template.py | 6 +- .../conversation.py | 8 +- .../pages/chat_page.py | 4 +- .../data_models.py | 8 +- .../pages/dashboard_page.py | 4 +- .../data_models.py | 8 +- .../data_models.py | 4 +- .../components/new_todo_item_input.py | 5 +- .../project-template-Todo App/data_models.py | 4 +- rio/snippets/snippet_manager.py | 4 +- rio/text_style.py | 8 +- rio/theme.py | 8 +- rio/user_settings_module.py | 6 +- rio/utils.py | 6 +- rio/version.py | 4 +- 74 files changed, 319 insertions(+), 278 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b3fe4ac8..10ea7196 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,10 +7,10 @@ Rio even better. Ready to jump in? We recommend checking out the how things work. All our code lives on GitHub, so you can easily see what's happening and get involved. -**Quick tip:** Chatting on discord with a maintainer before diving into a big -pull request can save you time. That way, you can make sure your idea aligns -with Rio's goals! Every contribution goes through the same fair review process, -no matter who submits it. +**Quick tip:** [A quick chat on discord](https://discord.gg/7ejXaPwhyH) with a +maintainer before diving into a big pull request can save you time. That way, +you can make sure your idea aligns with Rio's goals! We're very active on +discord - you can expect to get an answer in minutes when we aren't asleep. ## Feature Requests @@ -18,20 +18,12 @@ Feature Requests by the community are highly encouraged. Feel free to submit a new one or upvote an existing feature request on [Github Discussions](https://github.com/rio-labs/rio/discussions/categories/feature-requests). -## Code of Conduct - -This project, and everyone participating in it, are governed by Rio's Code of -Conduct. By participating, you are expected to uphold it. Make sure to read the -full text to understand which type of actions may or may not be tolerated. - ## Bugs Rio is using [GitHub issues](https://github.com/rio-labs/rio/issues) to manage bugs. We keep a close eye on them. Before filing a new issue, try to ensure your problem does not already exist. -
- ## Before Submitting a Pull Request The Rio core team will review your pull request and either merge it, request @@ -39,17 +31,17 @@ changes, or close it. ### Prerequisites -- You have [Python](https://www.python.org/) at `version 3.10 or higher` - installed. -- You have [Rye](https://rye.astral.sh/) at `version 0.33.0 or higher` - installed. -- You have [Node.js](https://nodejs.org/) at `version 20.0 or higher` installed. -- You are familiar with [Git](https://git-scm.com/). +- You have [Python](https://www.python.org/) version 3.10 or higher + installed +- You have [Rye](https://rye.astral.sh/) version 0.33.0 or higher + installed +- You have [Node.js](https://nodejs.org/) version 20.0 or higher installed +- You are familiar with [Git](https://git-scm.com/) ### Project structure - `frontend/` - TypeScript code for the Rio frontend -- `raw-icons` - In addition to the official material icons, Rio ships with some +- `raw-icons/` - In addition to the official material icons, Rio ships with some of its own. This directory contains any and all custom icons. - `rio/` - Python code for the Rio backend - `scripts/` - Contains scripts which are tangentially related to Rio, but not @@ -59,10 +51,6 @@ changes, or close it. ### Development Setup -While Rio allows users to write apps in 100% Python, Rio itself has both a -Python and a TypeScript component. In order to get started using Rio from the -repository, you'll have to build the typescript Component as well. - ### 1. Fork the repository [Go to the repository](https://github.com/rio-labs/rio) and fork it using your @@ -99,20 +87,24 @@ before creating commits: python -m pre_commit install ``` +While Rio allows users to write apps in 100% Python, Rio itself has both a +Python and a TypeScript component. In order to get started using Rio from the +repository, you'll have to build the typescript Component first + Install dev dependencies using `npm`: ```bash npm install ``` -Some developers have reported that they must explicitly import `sass`. If you -run into issues, try running: +The previous command doesn't reliably install `sass` for some reason. To be +on the safe side, install it manually: ```bash npm install sass ``` -Build the frontend: +Now build the frontend: ```bash rye run dev-build @@ -130,18 +122,18 @@ To avoid this, we've decided on a few conventions used throughout Rio: etc., NOT past tense (`on_changed`, `on_moved`). - Whenever a value has physical units attached, prefer to use SI base units. For - example, measure time in seconds, not milliseconds. + example, durations are measured in seconds, not milliseconds. Occasionally it can make sense to break this rule. For example, when - configuring how long a cache lasts, users will have a hard time understanding - a duration of days, when expressed in seconds. If you do decide to use a - different unit, always make that clear, by including the unit in the name - (e.g. `cache_duration_days`). + configuring how long a cache lasts, users will have a hard time + understanding a duration on the order of days expressed in seconds. If you + do decide to use a different unit, always make that clear, by including the + unit in the name (e.g. `cache_duration_in_days`). - Sometimes the library/language you're in already has a well established class - for this. For example, in Python the built-in `timedelta` class would be - preferable to all of the above. This way times can be expressed in any unit - the user prefers. + Sometimes the library/language you're in already has a well established + class for this. For example, in Python the built-in `timedelta` class would + be preferable to all of the above. This way times can be expressed in any + unit the user prefers. - Avoid negatives. For example, use `is_visible` instead of `is_hidden`. Nobody likes to think around corners. Here's some more examples @@ -150,8 +142,8 @@ To avoid this, we've decided on a few conventions used throughout Rio: - `is_sensitive` instead of `is_insensitive` - `is_active` instead of `is_disabled` - Along the same lines, **absolutely avoid double negatives**. Never, ever, ever - use names like `is_not_hidden` or `dont_hide_something`. + Along the same lines, **absolutely avoid double negatives**. Never, ever, + ever use names like `is_not_hidden` or `dont_hide_something`. - Python code follows Python naming conventions, such as all_lower_case for variables and functions, and CamelCase for classes. @@ -170,14 +162,50 @@ To avoid this, we've decided on a few conventions used throughout Rio: that don't stick to this convention. Feel free to report and/or change them if you spot any. -## Reporting Issues +- _In general,_ avoid importing values from modules. Import the modules + themselves, then include the module name when accessing values. Also avoid + renaming modules when imported. -Before submitting an issue, please check the existing issues to see if your -issue has already been reported. If it has, please add a comment to the existing -issue instead of creating a new one. + ```python + # Do this + import traceback + traceback.print_exc() -- You are experiencing a technical issue with Rio. -- Your issue title is concise, on-topic, and polite. -- You provide steps to reproduce the issue. -- Make sure the issue template is respected. -- Make sure your issue body is readable and [well formatted](https://docs.github.com/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax). + # Not this + from traceback import print_exc + print_exc() + + # Or this + import traceback as tb + tb.print_exc() + ``` + + A little bit of verbosity beats having to constantly think about whether a + value is available as `foo` or `foo.bar` in each file. + + This has limits however. Some modules, types & functions are so common that + the rules above can lead to unreadable code. Here are some conventions that + have been established over time: + + ```python + # These are fine, and encouraged + from __future__ import annotations + + from datetime import datetime, timezone, timedelta + from pathlib import Path + + import typing as t + import typing_extensions as te + + import numpy as np + import pandas as pd + import polars as pl + + # In Rio projects specifically + import components as comps + ``` + +- **Use type hints!** They don't take long to type, but help out **you**, anyone + else reading your code, and most importantly, your type checker. They really + pay off in the long run. Not to mention that they force you to think about + your data models a bit more critically, leading to better code. diff --git a/extensions/rio_jobs.py b/extensions/rio_jobs.py index f46a09d5..f64a2adc 100644 --- a/extensions/rio_jobs.py +++ b/extensions/rio_jobs.py @@ -7,11 +7,11 @@ exceptions and rescheduling the job for the future. from __future__ import annotations import asyncio +import dataclasses import inspect import logging import time import typing as t -from dataclasses import dataclass from datetime import datetime, timedelta, timezone import rio @@ -80,7 +80,7 @@ async def _call_sync_or_async_function( return result # type: ignore -@dataclass +@dataclasses.dataclass class ScheduledJob: """ A job that has been scheduled. diff --git a/rio/cli/nice_traceback.py b/rio/cli/nice_traceback.py index 87ac69a5..5db58753 100644 --- a/rio/cli/nice_traceback.py +++ b/rio/cli/nice_traceback.py @@ -3,19 +3,19 @@ Pretty-strings a traceback. The result looks very similar to Python's default, but is colored and just tweaked in general. """ +import dataclasses import html import io import linecache import sys import traceback import typing as t -from dataclasses import dataclass from pathlib import Path import revel -@dataclass +@dataclasses.dataclass class FormatStyle: bold: str nobold: str @@ -121,20 +121,20 @@ def _format_single_exception_raw( frame is tb_list[-1] and hasattr(frame, "colno") and hasattr(frame, "end_colno") - and frame.colno is not None - and frame.end_colno is not None + and frame.colno is not None # type: ignore + and frame.end_colno is not None # type: ignore ): if ( hasattr(frame, "end_lineno") - and frame.end_lineno is not None - and frame.end_lineno > frame.lineno + and frame.end_lineno is not None # type: ignore + and frame.end_lineno > frame.lineno # type: ignore ): end_col = len(source_line) - 1 # -1 to exclude the \n else: - end_col = frame.end_colno + end_col = frame.end_colno # type: ignore - before = style.escape(source_line[: frame.colno].lstrip()) - error = style.escape(source_line[frame.colno : end_col]) + before = style.escape(source_line[: frame.colno].lstrip()) # type: ignore + error = style.escape(source_line[frame.colno : end_col]) # type: ignore after = style.escape(source_line[end_col:].rstrip()) formatted_line = ( f"{before}{style.red}{error}{style.nored}{after}" diff --git a/rio/cli/run_project/run_models.py b/rio/cli/run_project/run_models.py index d58e8b1d..c67fa9c6 100644 --- a/rio/cli/run_project/run_models.py +++ b/rio/cli/run_project/run_models.py @@ -1,4 +1,4 @@ -from dataclasses import dataclass +import dataclasses from pathlib import Path @@ -6,7 +6,7 @@ class Event: pass -@dataclass +@dataclasses.dataclass class FileChanged(Event): """ A file in the project has changed, necessitating a reload. @@ -18,7 +18,7 @@ class FileChanged(Event): path_to_file: Path -@dataclass +@dataclasses.dataclass class StopRequested(Event): """ Request a shutdown of the running project. diff --git a/rio/component_meta.py b/rio/component_meta.py index 74adf678..dc02d923 100644 --- a/rio/component_meta.py +++ b/rio/component_meta.py @@ -1,12 +1,12 @@ from __future__ import annotations import asyncio +import dataclasses import sys import typing as t import warnings import weakref from collections import defaultdict -from dataclasses import field import introspection import typing_extensions as te @@ -29,7 +29,7 @@ C = t.TypeVar("C", bound="rio.Component") # `@te.dataclass_transform`, so we'll annotate it again... @te.dataclass_transform( eq_default=False, - field_specifiers=(internal_field, field), + field_specifiers=(internal_field, dataclasses.field), ) class ComponentMeta(RioDataclassMeta): # Cache for the set of all `StateProperty` instances in this class diff --git a/rio/components/app_root.py b/rio/components/app_root.py index de81e10a..36963877 100644 --- a/rio/components/app_root.py +++ b/rio/components/app_root.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY import rio @@ -115,7 +115,7 @@ class Sidebar(component.Component): class AppRoot(component.Component): - _: KW_ONLY + _: dataclasses.KW_ONLY fallback_build: t.Callable[[], rio.Component] | None = None _sidebar_is_open: bool = False diff --git a/rio/components/auto_form.py b/rio/components/auto_form.py index 7fc03e04..8b726924 100644 --- a/rio/components/auto_form.py +++ b/rio/components/auto_form.py @@ -3,7 +3,6 @@ from __future__ import annotations import dataclasses import enum import typing as t -from dataclasses import KW_ONLY, dataclass, is_dataclass import rio @@ -17,7 +16,7 @@ def prettify_name(name: str) -> str: return " ".join(p.title() for p in parts) -@dataclass +@dataclasses.dataclass class AutoFormChangeEvent: field_name: str value: t.Any @@ -33,12 +32,12 @@ class AutoForm(component.Component): """ value: t.Any - _: KW_ONLY + _: dataclasses.KW_ONLY on_change: rio.EventHandler[[AutoFormChangeEvent]] = None def __post_init__(self) -> None: # Make sure the passed value is a dataclass - if not is_dataclass(self.value): + if not dataclasses.is_dataclass(self.value): raise TypeError( f"The value to `AutoForm` must be a dataclass, not `{type(self.value)}`" ) diff --git a/rio/components/banner.py b/rio/components/banner.py index 3750bc83..131e0325 100644 --- a/rio/components/banner.py +++ b/rio/components/banner.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY import rio @@ -88,7 +88,7 @@ class Banner(component.Component): text: str | None style: t.Literal["info", "success", "warning", "danger"] - _: KW_ONLY + _: dataclasses.KW_ONLY markdown: bool = False icon: str | None = None diff --git a/rio/components/button.py b/rio/components/button.py index 67aa9bb1..ce91064f 100644 --- a/rio/components/button.py +++ b/rio/components/button.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY from uniserde import JsonDoc @@ -110,7 +110,7 @@ class Button(Component): """ content: str | rio.Component = "" - _: KW_ONLY + _: dataclasses.KW_ONLY icon: str | None = None shape: t.Literal["pill", "rounded", "rectangle"] = "pill" style: t.Literal[ @@ -204,7 +204,7 @@ class Button(Component): class _ButtonInternal(FundamentalComponent): - _: KW_ONLY + _: dataclasses.KW_ONLY on_press: rio.EventHandler[[]] content: rio.Component shape: t.Literal["pill", "rounded", "rectangle", "circle"] diff --git a/rio/components/calendar.py b/rio/components/calendar.py index a25cfcd2..63afe864 100644 --- a/rio/components/calendar.py +++ b/rio/components/calendar.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY, dataclass from datetime import date import imy.docstrings @@ -19,7 +19,7 @@ __all__ = [ @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class DateChangeEvent: """ Holds information regarding a date change event. @@ -104,7 +104,7 @@ class Calendar(FundamentalComponent): value: date - _: KW_ONLY + _: dataclasses.KW_ONLY on_change: rio.EventHandler[DateChangeEvent] = None diff --git a/rio/components/card.py b/rio/components/card.py index 7d393b49..8372ab44 100644 --- a/rio/components/card.py +++ b/rio/components/card.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY from uniserde import JsonDoc @@ -103,7 +103,7 @@ class Card(FundamentalComponent): """ content: rio.Component - _: KW_ONLY + _: dataclasses.KW_ONLY corner_radius: float | tuple[float, float, float, float] | None = None on_press: rio.EventHandler[[]] = None ripple: bool | None = None diff --git a/rio/components/checkbox.py b/rio/components/checkbox.py index 31fe724b..d6166741 100644 --- a/rio/components/checkbox.py +++ b/rio/components/checkbox.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY, dataclass import imy.docstrings from uniserde import JsonDoc @@ -18,7 +18,7 @@ __all__ = [ @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class CheckboxChangeEvent: """ Holds information regarding a checkbox change event. @@ -102,7 +102,7 @@ class Checkbox(FundamentalComponent): """ is_on: bool = False - _: KW_ONLY + _: dataclasses.KW_ONLY is_sensitive: bool = True on_change: rio.EventHandler[CheckboxChangeEvent] = None diff --git a/rio/components/code_block.py b/rio/components/code_block.py index d3da3c33..4eabf9e3 100644 --- a/rio/components/code_block.py +++ b/rio/components/code_block.py @@ -1,5 +1,5 @@ +import dataclasses import typing as t -from dataclasses import KW_ONLY from .. import deprecations from .fundamental_component import FundamentalComponent @@ -48,7 +48,7 @@ class CodeBlock(FundamentalComponent): code: str - _: KW_ONLY + _: dataclasses.KW_ONLY language: str | None = None show_controls: bool = True diff --git a/rio/components/color_picker.py b/rio/components/color_picker.py index c44f725c..beb4c371 100644 --- a/rio/components/color_picker.py +++ b/rio/components/color_picker.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY, dataclass import imy.docstrings from uniserde import JsonDoc @@ -18,7 +18,7 @@ __all__ = [ @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class ColorChangeEvent: """ Holds information regarding a color change event. @@ -98,7 +98,7 @@ class ColorPicker(FundamentalComponent): """ color: rio.Color - _: KW_ONLY + _: dataclasses.KW_ONLY pick_opacity: bool = False on_change: rio.EventHandler[ColorChangeEvent] = None diff --git a/rio/components/component.py b/rio/components/component.py index d06bed6e..c69218ab 100644 --- a/rio/components/component.py +++ b/rio/components/component.py @@ -1,9 +1,9 @@ from __future__ import annotations import abc +import dataclasses import io import typing as t -from dataclasses import KW_ONLY from pathlib import Path import typing_extensions as te @@ -206,7 +206,7 @@ class Component(abc.ABC, metaclass=ComponentMeta): bottom-aligned. """ - _: KW_ONLY + _: dataclasses.KW_ONLY key: str | int | None = internal_field(default=None, init=True) min_width: float = 0 diff --git a/rio/components/date_input.py b/rio/components/date_input.py index f9ce78b6..7b272757 100644 --- a/rio/components/date_input.py +++ b/rio/components/date_input.py @@ -1,8 +1,8 @@ from __future__ import annotations +import dataclasses import random import typing as t -from dataclasses import KW_ONLY, dataclass from datetime import date, datetime import imy.docstrings @@ -20,7 +20,7 @@ __all__ = [ @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class DateConfirmEvent: """ Holds information regarding a date confirm event. @@ -129,7 +129,7 @@ class DateInput(Component): value: date - _: KW_ONLY + _: dataclasses.KW_ONLY label: str = "" accessibility_label: str = "" diff --git a/rio/components/devel_component.py b/rio/components/devel_component.py index a071abb1..166ec714 100644 --- a/rio/components/devel_component.py +++ b/rio/components/devel_component.py @@ -1,10 +1,10 @@ from __future__ import annotations import concurrent.futures +import dataclasses import subprocess import tempfile import typing as t -from dataclasses import field from pathlib import Path import rio @@ -30,7 +30,9 @@ class DevelComponent(FundamentalComponent): `public`: False """ - children: t.Sequence[rio.Component] = field(default_factory=list) + children: t.Sequence[rio.Component] = dataclasses.field( + default_factory=list + ) def __init__( self, diff --git a/rio/components/drawer.py b/rio/components/drawer.py index 33d47b8a..f432ac6c 100644 --- a/rio/components/drawer.py +++ b/rio/components/drawer.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY, dataclass import imy.docstrings from uniserde import JsonDoc @@ -18,7 +18,7 @@ __all__ = [ @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class DrawerOpenOrCloseEvent: """ Holds information regarding a drawer open or close event. @@ -113,7 +113,7 @@ class Drawer(FundamentalComponent): anchor: rio.Component content: rio.Component - _: KW_ONLY + _: dataclasses.KW_ONLY on_open_or_close: rio.EventHandler[DrawerOpenOrCloseEvent] = None side: t.Literal["left", "right", "top", "bottom"] = "left" is_modal: bool = True diff --git a/rio/components/dropdown.py b/rio/components/dropdown.py index 6487ff6a..949b4d1e 100644 --- a/rio/components/dropdown.py +++ b/rio/components/dropdown.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY, dataclass import imy.docstrings from uniserde import JsonDoc @@ -21,7 +21,7 @@ T = t.TypeVar("T") @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class DropdownChangeEvent(t.Generic[T]): """ Holds information regarding a dropdown change event. @@ -126,7 +126,7 @@ class Dropdown(FundamentalComponent, t.Generic[T]): """ options: t.Mapping[str, T] - _: KW_ONLY + _: dataclasses.KW_ONLY label: str style: t.Literal["underlined", "rounded", "pill"] selected_value: T | utils.NotGiven = utils.NOT_GIVEN diff --git a/rio/components/file_picker_area.py b/rio/components/file_picker_area.py index 0a71ddbb..4b28061a 100644 --- a/rio/components/file_picker_area.py +++ b/rio/components/file_picker_area.py @@ -1,8 +1,8 @@ from __future__ import annotations +import dataclasses import logging import typing as t -from dataclasses import dataclass, field import imy.docstrings from uniserde import JsonDoc @@ -20,7 +20,7 @@ __all__ = [ @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class FilePickEvent: """ Holds information regarding a file upload event. @@ -99,8 +99,10 @@ class FilePickerArea(FundamentalComponent): if not t.TYPE_CHECKING: # At most one of these is set, the other `None`. If both are `None`, the # component will display a default message. - child_text: str | None = field(default=None, init=False) - child_component: rio.Component | None = field(default=None, init=False) + child_text: str | None = dataclasses.field(default=None, init=False) + child_component: rio.Component | None = dataclasses.field( + default=None, init=False + ) # The serializer can't handle Union types. Override the constructor, so it # splits the content into two values diff --git a/rio/components/flow_container.py b/rio/components/flow_container.py index e19c935e..4d2cb58a 100644 --- a/rio/components/flow_container.py +++ b/rio/components/flow_container.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY import typing_extensions as te from uniserde import JsonDoc @@ -53,7 +53,7 @@ class FlowContainer(FundamentalComponent): """ children: list[rio.Component] - _: KW_ONLY + _: dataclasses.KW_ONLY spacing: float | None row_spacing: float | None column_spacing: float | None diff --git a/rio/components/grid.py b/rio/components/grid.py index 5bed7e8d..a3be01f1 100644 --- a/rio/components/grid.py +++ b/rio/components/grid.py @@ -1,8 +1,8 @@ from __future__ import annotations +import dataclasses import math import typing as t -from dataclasses import KW_ONLY, dataclass import typing_extensions as te from uniserde import JsonDoc @@ -15,7 +15,7 @@ __all__ = ["Grid"] @t.final -@dataclass +@dataclasses.dataclass class GridChildPosition: row: int column: int @@ -89,7 +89,7 @@ class Grid(FundamentalComponent): ``` """ - _: KW_ONLY + _: dataclasses.KW_ONLY row_spacing: float column_spacing: float diff --git a/rio/components/icon.py b/rio/components/icon.py index ea90cbdd..ca7823f5 100644 --- a/rio/components/icon.py +++ b/rio/components/icon.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY from pathlib import Path from uniserde import JsonDoc @@ -83,7 +83,7 @@ class Icon(FundamentalComponent): """ icon: str - _: KW_ONLY + _: dataclasses.KW_ONLY fill: _IconFill @staticmethod diff --git a/rio/components/icon_button.py b/rio/components/icon_button.py index 5726a8b8..6f42bb42 100644 --- a/rio/components/icon_button.py +++ b/rio/components/icon_button.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY from uniserde import JsonDoc @@ -108,7 +108,7 @@ class IconButton(Component): """ icon: str - _: KW_ONLY + _: dataclasses.KW_ONLY style: t.Literal["major", "minor", "colored-text", "plain-text", "plain"] color: rio.ColorSet is_sensitive: bool diff --git a/rio/components/image.py b/rio/components/image.py index d5f79b0c..ff13066f 100644 --- a/rio/components/image.py +++ b/rio/components/image.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY from uniserde import Jsonable, JsonDoc @@ -112,7 +112,7 @@ class Image(FundamentalComponent): """ image: ImageLike - _: KW_ONLY + _: dataclasses.KW_ONLY fill_mode: t.Literal["fit", "stretch", "zoom"] = "fit" on_error: EventHandler[[]] = None corner_radius: float | tuple[float, float, float, float] = 0 diff --git a/rio/components/key_event_listener.py b/rio/components/key_event_listener.py index 0d02e16c..4ed3e545 100644 --- a/rio/components/key_event_listener.py +++ b/rio/components/key_event_listener.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY, dataclass import imy.docstrings from uniserde import Jsonable @@ -568,7 +568,7 @@ ModifierKey = t.Literal["alt", "control", "meta", "shift"] _MODIFIERS = ("control", "shift", "alt", "meta") -@dataclass(frozen=True) +@dataclasses.dataclass(frozen=True) class _KeyUpDownEvent: """ Holds information about a key event. @@ -662,7 +662,7 @@ class KeyEventListener(KeyboardFocusableFundamentalComponent): """ content: rio.Component - _: KW_ONLY + _: dataclasses.KW_ONLY on_key_down: rio.EventHandler[KeyDownEvent] = None on_key_up: rio.EventHandler[KeyUpEvent] = None on_key_press: rio.EventHandler[KeyPressEvent] = None diff --git a/rio/components/labeled_column.py b/rio/components/labeled_column.py index adb96152..94b281af 100644 --- a/rio/components/labeled_column.py +++ b/rio/components/labeled_column.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import field import typing_extensions as te @@ -42,7 +42,7 @@ class LabeledColumn(Component): `public`: False """ - _child_list: list[Component] = field(init=False) + _child_list: list[Component] = dataclasses.field(init=False) def __init__( self, diff --git a/rio/components/markdown.py b/rio/components/markdown.py index 52916859..0b502421 100644 --- a/rio/components/markdown.py +++ b/rio/components/markdown.py @@ -1,5 +1,5 @@ +import dataclasses import typing as t -from dataclasses import KW_ONLY from uniserde import JsonDoc @@ -66,7 +66,7 @@ class Markdown(FundamentalComponent): ''' text: str - _: KW_ONLY + _: dataclasses.KW_ONLY default_language: str | None = None selectable: bool = True justify: t.Literal["left", "right", "center", "justify"] = "left" diff --git a/rio/components/mouse_event_listener.py b/rio/components/mouse_event_listener.py index 8bff3840..9ea85898 100644 --- a/rio/components/mouse_event_listener.py +++ b/rio/components/mouse_event_listener.py @@ -1,8 +1,8 @@ from __future__ import annotations +import dataclasses import enum import typing as t -from dataclasses import KW_ONLY, dataclass import imy.docstrings from uniserde import JsonDoc @@ -34,12 +34,12 @@ class MouseButton(enum.Enum): RIGHT = "right" -@dataclass +@dataclasses.dataclass class _ButtonEvent: button: MouseButton -@dataclass +@dataclasses.dataclass class _PositionedEvent: """ ## Attributes @@ -57,7 +57,7 @@ class _PositionedEvent: @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class PressEvent(_ButtonEvent, _PositionedEvent): """ Holds information regarding a mouse press event. @@ -74,7 +74,7 @@ class PressEvent(_ButtonEvent, _PositionedEvent): @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class MouseDownEvent(_ButtonEvent, _PositionedEvent): """ Holds information regarding a mouse down event. @@ -91,7 +91,7 @@ class MouseDownEvent(_ButtonEvent, _PositionedEvent): @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class MouseUpEvent(_ButtonEvent, _PositionedEvent): """ Holds information regarding a mouse up event. @@ -142,7 +142,7 @@ class MouseLeaveEvent(_PositionedEvent): """ -@dataclass +@dataclasses.dataclass class _DragEvent(_ButtonEvent, _PositionedEvent): """ Holds information regarding a drag event. @@ -244,7 +244,7 @@ class MouseEventListener(FundamentalComponent): """ content: rio.Component - _: KW_ONLY + _: dataclasses.KW_ONLY on_press: rio.EventHandler[PressEvent] = None on_mouse_down: rio.EventHandler[MouseDownEvent] = None on_mouse_up: rio.EventHandler[MouseUpEvent] = None diff --git a/rio/components/multi_line_text_input.py b/rio/components/multi_line_text_input.py index 75bf9c65..43c005ab 100644 --- a/rio/components/multi_line_text_input.py +++ b/rio/components/multi_line_text_input.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY, dataclass import imy.docstrings from uniserde import JsonDoc @@ -19,7 +19,7 @@ __all__ = [ @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class MultiLineTextInputChangeEvent: """ Holds information regarding a text input change event. @@ -38,7 +38,7 @@ class MultiLineTextInputChangeEvent: @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class MultiLineTextInputConfirmEvent: """ Holds information regarding a text input confirm event. @@ -137,7 +137,7 @@ class MultiLineTextInput(KeyboardFocusableFundamentalComponent): """ text: str = "" - _: KW_ONLY + _: dataclasses.KW_ONLY label: str = "" accessibility_label: str = "" is_sensitive: bool = True diff --git a/rio/components/number_input.py b/rio/components/number_input.py index e956bbc3..fdd2b966 100644 --- a/rio/components/number_input.py +++ b/rio/components/number_input.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY, dataclass import imy.docstrings @@ -27,7 +27,7 @@ _multiplier_suffixes: t.Mapping[str, int] = { @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class NumberInputChangeEvent: """ Holds information regarding a number change event. @@ -46,7 +46,7 @@ class NumberInputChangeEvent: @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class NumberInputConfirmEvent: """ Holds information regarding a number confirm event. @@ -65,7 +65,7 @@ class NumberInputConfirmEvent: @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class NumberInputFocusEvent: """ Holds information regarding a number input focus event. @@ -190,7 +190,7 @@ class NumberInput(Component): """ value: float = 0 - _: KW_ONLY + _: dataclasses.KW_ONLY label: str = "" accessibility_label: str = "" style: t.Literal["underlined", "rounded", "pill"] = "underlined" diff --git a/rio/components/page_view.py b/rio/components/page_view.py index e4cedabc..6b881e81 100644 --- a/rio/components/page_view.py +++ b/rio/components/page_view.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY, field import rio @@ -110,7 +110,7 @@ class PageView(Component): # TODO: Link to the routing/multipage how-to page - _: KW_ONLY + _: dataclasses.KW_ONLY fallback_build: t.Callable[[], rio.Component] | None = None @@ -118,7 +118,7 @@ class PageView(Component): # for top-level PageViews, 1 for the next level, and so on. # # Initialized in `__post_init__`. - _level: int = field(init=False) + _level: int = dataclasses.field(init=False) def __post_init__(self) -> None: self.session._page_views.add(self) diff --git a/rio/components/pointer_event_listener.py b/rio/components/pointer_event_listener.py index 60bf76ad..c9f8cdf1 100644 --- a/rio/components/pointer_event_listener.py +++ b/rio/components/pointer_event_listener.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY, dataclass import imy.docstrings from uniserde import JsonDoc @@ -18,7 +18,7 @@ __all__ = [ @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class PointerEvent: """ Holds information regarding a pointer event. @@ -78,7 +78,7 @@ class PointerEvent: @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class PointerMoveEvent(PointerEvent): """ Holds information regarding a pointer move event. @@ -158,7 +158,7 @@ class PointerEventListener(FundamentalComponent): """ content: rio.Component - _: KW_ONLY + _: dataclasses.KW_ONLY on_press: rio.EventHandler[PointerEvent] = None on_pointer_down: rio.EventHandler[PointerEvent] = None on_pointer_up: rio.EventHandler[PointerEvent] = None diff --git a/rio/components/popup.py b/rio/components/popup.py index 70ecdff8..6c62e41e 100644 --- a/rio/components/popup.py +++ b/rio/components/popup.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY from uniserde import JsonDoc @@ -128,7 +128,7 @@ class Popup(FundamentalComponent): anchor: rio.Component content: rio.Component - _: KW_ONLY + _: dataclasses.KW_ONLY is_open: bool = False modal: bool = False user_closable: bool = False diff --git a/rio/components/rectangle.py b/rio/components/rectangle.py index a2db1dd6..a2621819 100644 --- a/rio/components/rectangle.py +++ b/rio/components/rectangle.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY from uniserde import JsonDoc @@ -125,7 +125,7 @@ class Rectangle(FundamentalComponent): you just want a simple rectangle. """ - _: KW_ONLY + _: dataclasses.KW_ONLY content: rio.Component | None = None transition_time: float = 1.0 cursor: rio.CursorStyle = cursor_style.CursorStyle.DEFAULT diff --git a/rio/components/revealer.py b/rio/components/revealer.py index 60b6e619..2bc6eb92 100644 --- a/rio/components/revealer.py +++ b/rio/components/revealer.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY, dataclass import imy.docstrings from uniserde import JsonDoc @@ -20,7 +20,7 @@ T = t.TypeVar("T") @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class RevealerChangeEvent: """ Holds information regarding a revealer change event. @@ -97,7 +97,7 @@ class Revealer(FundamentalComponent): header: str | None content: rio.Component - _: KW_ONLY + _: dataclasses.KW_ONLY header_style: ( t.Literal["heading1", "heading2", "heading3", "text"] | rio.TextStyle ) = "text" diff --git a/rio/components/scroll_container.py b/rio/components/scroll_container.py index 382e01aa..7e14792b 100644 --- a/rio/components/scroll_container.py +++ b/rio/components/scroll_container.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY import rio @@ -55,7 +55,7 @@ class ScrollContainer(FundamentalComponent): """ content: rio.Component - _: KW_ONLY + _: dataclasses.KW_ONLY scroll_x: t.Literal["never", "auto", "always"] = "auto" scroll_y: t.Literal["never", "auto", "always"] = "auto" initial_x: float = 0 diff --git a/rio/components/scroll_target.py b/rio/components/scroll_target.py index 6d6c945a..be2204e7 100644 --- a/rio/components/scroll_target.py +++ b/rio/components/scroll_target.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY from uniserde import JsonDoc @@ -61,7 +61,7 @@ class ScrollTarget(FundamentalComponent): id: str content: rio.Component | None = None - _: KW_ONLY + _: dataclasses.KW_ONLY copy_button_content: str | rio.Component | None = "ΒΆ" copy_button_spacing: float = 0.5 diff --git a/rio/components/separator.py b/rio/components/separator.py index 52a06a45..288a5bbe 100644 --- a/rio/components/separator.py +++ b/rio/components/separator.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY import rio @@ -46,7 +46,7 @@ class Separator(FundamentalComponent): ``` """ - _: KW_ONLY + _: dataclasses.KW_ONLY color: rio.Color | None = None diff --git a/rio/components/slider.py b/rio/components/slider.py index 12a7a055..b9738981 100644 --- a/rio/components/slider.py +++ b/rio/components/slider.py @@ -1,8 +1,8 @@ from __future__ import annotations +import dataclasses import math import typing as t -from dataclasses import dataclass import imy.docstrings from uniserde import JsonDoc @@ -19,7 +19,7 @@ __all__ = [ @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class SliderChangeEvent: """ Holds information regarding a slider change event. diff --git a/rio/components/slideshow.py b/rio/components/slideshow.py index 7f950c97..1cf84be8 100644 --- a/rio/components/slideshow.py +++ b/rio/components/slideshow.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY from datetime import timedelta from uniserde import JsonDoc @@ -65,7 +65,7 @@ class Slideshow(FundamentalComponent): """ children: list[rio.Component] - _: KW_ONLY + _: dataclasses.KW_ONLY linger_time: float corner_radius: None | float | tuple[float, float, float, float] diff --git a/rio/components/switch.py b/rio/components/switch.py index acd00945..343780bd 100644 --- a/rio/components/switch.py +++ b/rio/components/switch.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY, dataclass import imy.docstrings from uniserde import JsonDoc @@ -18,7 +18,7 @@ __all__ = [ @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class SwitchChangeEvent: """ Holds information regarding a switch change event. @@ -102,7 +102,7 @@ class Switch(FundamentalComponent): """ is_on: bool = False - _: KW_ONLY + _: dataclasses.KW_ONLY is_sensitive: bool = True on_change: rio.EventHandler[SwitchChangeEvent] = None diff --git a/rio/components/switcher.py b/rio/components/switcher.py index 7a427466..6e49b3d1 100644 --- a/rio/components/switcher.py +++ b/rio/components/switcher.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY import rio @@ -81,7 +81,7 @@ class Switcher(FundamentalComponent): content: rio.Component | None - _: KW_ONLY + _: dataclasses.KW_ONLY transition_time: float = 0.35 diff --git a/rio/components/switcher_bar.py b/rio/components/switcher_bar.py index d9b4b0fd..44ecd241 100644 --- a/rio/components/switcher_bar.py +++ b/rio/components/switcher_bar.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import dataclass import imy.docstrings from uniserde import JsonDoc @@ -21,7 +21,7 @@ T = t.TypeVar("T") @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class SwitcherBarChangeEvent(t.Generic[T]): """ Holds information regarding a switcher bar change event. diff --git a/rio/components/table.py b/rio/components/table.py index 10d73a08..55e67557 100644 --- a/rio/components/table.py +++ b/rio/components/table.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY, dataclass, field import narwhals as nw import typing_extensions as te @@ -25,7 +25,7 @@ TableValue = int | float | str @t.final -@dataclass +@dataclasses.dataclass class TableSelection: _table: Table @@ -378,26 +378,32 @@ class Table(FundamentalComponent): # TODO: add more content to docstring | numpy.ndarray ) - _: KW_ONLY + _: dataclasses.KW_ONLY show_row_numbers: bool = True # All headers, if present - _headers: list[str] | None = field(default=None, init=False) + _headers: list[str] | None = dataclasses.field(default=None, init=False) # The data, as a list of columns ("column major"). This is set in # `__post_init__`. - _columns: list[list[TableValue]] = field(default_factory=list, init=False) + _columns: list[list[TableValue]] = dataclasses.field( + default_factory=list, init=False + ) # All styles applied to the table, in the same order they were added - _styling: list[TableSelection] = field(default_factory=list, init=False) + _styling: list[TableSelection] = dataclasses.field( + default_factory=list, init=False + ) # These must be annotated, otherwise rio won't understand that tables have # child components and won't copy over the new values when two Tables are # reconciled. - _children: list[rio.Component] = field(default_factory=list, init=False) + _children: list[rio.Component] = dataclasses.field( + default_factory=list, init=False + ) - _child_positions: list[tuple[int, int]] = field( + _child_positions: list[tuple[int, int]] = dataclasses.field( default_factory=list, init=False ) diff --git a/rio/components/text.py b/rio/components/text.py index c64b1e20..ed550b09 100644 --- a/rio/components/text.py +++ b/rio/components/text.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY from uniserde import JsonDoc @@ -72,7 +72,7 @@ class Text(FundamentalComponent): """ text: str - _: KW_ONLY + _: dataclasses.KW_ONLY selectable: bool = True style: ( t.Literal["heading1", "heading2", "heading3", "text", "dim"] @@ -97,7 +97,7 @@ class Text(FundamentalComponent): since="0.10", old_name="wrap", new_name="overflow", - owner="rio.Text", + function="rio.Text", ) if self.wrap is True: diff --git a/rio/components/text_input.py b/rio/components/text_input.py index 1a8f42cb..a5c56c10 100644 --- a/rio/components/text_input.py +++ b/rio/components/text_input.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY, dataclass import imy.docstrings @@ -19,7 +19,7 @@ __all__ = [ @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class TextInputChangeEvent: """ Holds information regarding a text input change event. @@ -38,7 +38,7 @@ class TextInputChangeEvent: @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class TextInputConfirmEvent: """ Holds information regarding a text input confirm event. @@ -57,7 +57,7 @@ class TextInputConfirmEvent: @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class TextInputFocusEvent: """ Holds information regarding a text input focus event. @@ -161,7 +161,7 @@ class TextInput(KeyboardFocusableFundamentalComponent): """ text: str = "" - _: KW_ONLY + _: dataclasses.KW_ONLY label: str = "" accessibility_label: str = "" style: t.Literal["underlined", "rounded", "pill"] = "underlined" diff --git a/rio/data_models.py b/rio/data_models.py index b7eb993c..2b159854 100644 --- a/rio/data_models.py +++ b/rio/data_models.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import dataclass # Never import * from typing_extensions! It breaks `Any` on 3.10, preventing # users from connecting. Ask me how I know. @@ -13,7 +13,7 @@ import rio __all__ = ["BuildData", "ComponentLayout", "InitialClientMessage"] -@dataclass +@dataclasses.dataclass class BuildData: build_result: rio.Component @@ -25,7 +25,7 @@ class BuildData: build_generation: int -@dataclass +@dataclasses.dataclass class InitialClientMessage(uniserde.Serde): # The URL the client used to connect to the website. This can be quite # different from the URLs we see in FastAPI requests, because proxies like @@ -150,7 +150,7 @@ class InitialClientMessage(uniserde.Serde): # open_browser_on_startup: bool = True -@dataclass +@dataclasses.dataclass class ComponentLayout(uniserde.Serde): # The minimum amount of size needed by the component. The width is # calculated first, meaning the height can depend on the width. (i.e. a @@ -192,13 +192,13 @@ class ComponentLayout(uniserde.Serde): parent_id: int | None -@dataclass +@dataclasses.dataclass class UnittestComponentLayout(ComponentLayout): # Additional, component-specific information aux: dict[str, t.Any] -@dataclass +@dataclasses.dataclass class UnittestClientLayoutInfo: window_width: float window_height: float diff --git a/rio/debug/dev_tools/component_attributes.py b/rio/debug/dev_tools/component_attributes.py index 6b307b2e..8bb22e94 100644 --- a/rio/debug/dev_tools/component_attributes.py +++ b/rio/debug/dev_tools/component_attributes.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY from pathlib import Path import rio @@ -18,7 +18,7 @@ except Exception: class ComponentAttributes(rio.Component): component_id: int - _: KW_ONLY + _: dataclasses.KW_ONLY on_switch_to_layout_view: rio.EventHandler[[]] = None diff --git a/rio/debug/dev_tools/component_tree.py b/rio/debug/dev_tools/component_tree.py index 0ebf4f07..52638a1a 100644 --- a/rio/debug/dev_tools/component_tree.py +++ b/rio/debug/dev_tools/component_tree.py @@ -1,6 +1,6 @@ from __future__ import annotations -from dataclasses import KW_ONLY +import dataclasses from uniserde import JsonDoc @@ -24,7 +24,7 @@ class ComponentTree(FundamentalComponent): component_id: int # This can be invalid. The component must deal with it. - _: KW_ONLY + _: dataclasses.KW_ONLY # Triggered whenever the user selects a component in the tree. The passed # value is the component's ID. diff --git a/rio/debug/dev_tools/icons_page.py b/rio/debug/dev_tools/icons_page.py index 49bd2d43..f0bad00c 100644 --- a/rio/debug/dev_tools/icons_page.py +++ b/rio/debug/dev_tools/icons_page.py @@ -2,7 +2,6 @@ import dataclasses import functools import re import typing as t -from dataclasses import KW_ONLY import fuzzywuzzy.fuzz @@ -121,7 +120,7 @@ def get_available_icons() -> list[tuple[str, str, tuple[str | None, ...]]]: class IconsPage(rio.Component): - _: KW_ONLY + _: dataclasses.KW_ONLY search_text: str = "" matches: list[tuple[str, str, tuple[str | None, ...]]] = dataclasses.field( default_factory=list diff --git a/rio/debug/dev_tools/layout_display.py b/rio/debug/dev_tools/layout_display.py index e9ec25ba..2dd2100e 100644 --- a/rio/debug/dev_tools/layout_display.py +++ b/rio/debug/dev_tools/layout_display.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY from uniserde import JsonDoc @@ -18,7 +18,7 @@ __all__ = [ class LayoutDisplay(FundamentalComponent): component_id: int # This can be invalid. The component must deal with it. - _: KW_ONLY + _: dataclasses.KW_ONLY max_requested_height: float = 1 on_component_change: rio.EventHandler[int] = None diff --git a/rio/debug/dev_tools/layout_subpage.py b/rio/debug/dev_tools/layout_subpage.py index cbe8364c..8782fa19 100644 --- a/rio/debug/dev_tools/layout_subpage.py +++ b/rio/debug/dev_tools/layout_subpage.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY import rio import rio.components.fundamental_component @@ -15,7 +15,7 @@ class SizeControls(rio.Component): grow: bool min_value: float - _: KW_ONLY + _: dataclasses.KW_ONLY on_grow_change: rio.EventHandler[bool] = None on_min_change: rio.EventHandler[float] = None @@ -58,7 +58,7 @@ class AlignmentControls(rio.Component): label: str value: float | None - _: KW_ONLY + _: dataclasses.KW_ONLY on_change: rio.EventHandler[float | None] = None @@ -187,7 +187,7 @@ class ActionAnchor(rio.Component): class LayoutSubpage(rio.Component): component_id: int - _: KW_ONLY + _: dataclasses.KW_ONLY _layout_explainer: layout_explainer.LayoutExplainer | None = None _explanation_is_expanded: bool = True diff --git a/rio/debug/typing_utils.py b/rio/debug/typing_utils.py index f7b2884c..daed4d9e 100644 --- a/rio/debug/typing_utils.py +++ b/rio/debug/typing_utils.py @@ -1,12 +1,12 @@ +import dataclasses import types -from dataclasses import dataclass import introspection.typing __all__ = ["ScopedAnnotation"] -@dataclass +@dataclasses.dataclass class ScopedAnnotation: annotation: introspection.types.TypeAnnotation module: types.ModuleType diff --git a/rio/debug/validator.py b/rio/debug/validator.py index a552ca42..e76bfc0a 100644 --- a/rio/debug/validator.py +++ b/rio/debug/validator.py @@ -2,10 +2,10 @@ from __future__ import annotations import collections import copy +import dataclasses import json import re import typing as t -from dataclasses import dataclass from pathlib import Path from uniserde import Jsonable, JsonDoc @@ -21,7 +21,7 @@ __all__ = [ ] -@dataclass +@dataclasses.dataclass class ClientComponent: id: int type: str diff --git a/rio/event.py b/rio/event.py index a0505a91..707c8ea0 100644 --- a/rio/event.py +++ b/rio/event.py @@ -185,7 +185,7 @@ def on_populate( ```python import httpx - from dataclasses import field + import dataclasses class PypiVersionFetcher(rio.Component): @@ -193,7 +193,7 @@ def on_populate( # The `version` attribute is initialized to an empty # string, which will will act as a placeholder until # the HTTP request finishes - version: str = field(init=False, default="") + version: str = dataclasses.field(init=False, default="") @rio.event.on_populate async def on_populate(self): @@ -218,7 +218,9 @@ def on_populate( return handler -def on_unmount(handler: MethodWithNoParametersVar,) -> MethodWithNoParametersVar: +def on_unmount( + handler: MethodWithNoParametersVar, +) -> MethodWithNoParametersVar: """ Triggered when the component is removed from the component tree. diff --git a/rio/extension_event.py b/rio/extension_event.py index 5de2c5a0..84485ae4 100644 --- a/rio/extension_event.py +++ b/rio/extension_event.py @@ -1,8 +1,8 @@ from __future__ import annotations +import dataclasses import enum import typing as t -from dataclasses import dataclass import fastapi import imy.docstrings @@ -101,7 +101,7 @@ class ExtensionEventTag(enum.Enum): @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class ExtensionAsFastapiEvent: """ Holds information regarding an extension as_fastapi event. @@ -127,7 +127,7 @@ class ExtensionAsFastapiEvent: @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class ExtensionAppStartEvent: """ Holds information regarding an extension app start event. @@ -150,7 +150,7 @@ class ExtensionAppStartEvent: @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class ExtensionAppCloseEvent: """ Holds information regarding an extension app close event. @@ -173,7 +173,7 @@ class ExtensionAppCloseEvent: @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class ExtensionSessionStartEvent: """ Holds information regarding a session start event. @@ -196,7 +196,7 @@ class ExtensionSessionStartEvent: @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class ExtensionSessionCloseEvent: """ Holds information regarding a session close event. @@ -219,7 +219,7 @@ class ExtensionSessionCloseEvent: @t.final @imy.docstrings.mark_constructor_as_private -@dataclass +@dataclasses.dataclass class ExtensionPageChangeEvent: """ Holds information regarding a page change event. diff --git a/rio/fills.py b/rio/fills.py index e599dd06..56abaa87 100644 --- a/rio/fills.py +++ b/rio/fills.py @@ -1,8 +1,8 @@ from __future__ import annotations +import abc +import dataclasses import typing as t -from abc import ABC -from dataclasses import dataclass import typing_extensions as te from uniserde import Jsonable @@ -27,7 +27,7 @@ __all__ = [ since="0.8.5", description="The `Fill` base class will be removed.", ) -class Fill(SelfSerializing, ABC): +class Fill(SelfSerializing, abc.ABC): """ Base class for how shapes are filled. @@ -44,7 +44,7 @@ class Fill(SelfSerializing, ABC): """ -@dataclass(frozen=True, eq=True) +@dataclasses.dataclass(frozen=True, eq=True) class SolidFill(Fill): """ Fills a shape with a single color. @@ -66,7 +66,7 @@ class SolidFill(Fill): } -@dataclass(frozen=True, eq=True) +@dataclasses.dataclass(frozen=True, eq=True) class LinearGradientFill(Fill): """ Fills a shape with a linear gradient. @@ -219,7 +219,7 @@ class ImageFill(Fill): ) -@dataclass(frozen=True, eq=True) +@dataclasses.dataclass(frozen=True, eq=True) class FrostedGlassFill(Fill): """ Fills a shape with a frosted glass effect. diff --git a/rio/routing.py b/rio/routing.py index c5cba6a4..f85ef19e 100644 --- a/rio/routing.py +++ b/rio/routing.py @@ -1,10 +1,10 @@ from __future__ import annotations +import dataclasses import functools import logging import typing as t import warnings -from dataclasses import KW_ONLY, dataclass, field from pathlib import Path import imy.docstrings @@ -59,7 +59,7 @@ def _verify_url_and_parse_into_pattern( @t.final -@dataclass(frozen=True) +@dataclasses.dataclass(frozen=True) class Redirect: """ Redirects the user to a different page. @@ -106,7 +106,7 @@ class Redirect: # A pre-parsed URL pattern object, used to verify whether a URL matches # this page, as well as extracting path parameters - _url_pattern: url_pattern.UrlPattern = field(init=False) + _url_pattern: url_pattern.UrlPattern = dataclasses.field(init=False) def __post_init__(self) -> None: vars(self).update( @@ -121,7 +121,7 @@ class Redirect: old_name="page_url", new_name="url_segment", ) -@dataclass(frozen=True) +@dataclasses.dataclass(frozen=True) class ComponentPage: """ A routable page in a Rio app. @@ -211,23 +211,25 @@ class ComponentPage: name: str url_segment: str build: t.Callable[..., rio.Component] - _: KW_ONLY + _: dataclasses.KW_ONLY icon: str = DEFAULT_ICON - children: t.Sequence[ComponentPage | Redirect] = field(default_factory=list) + children: t.Sequence[ComponentPage | Redirect] = dataclasses.field( + default_factory=list + ) guard: t.Callable[[rio.GuardEvent], None | rio.URL | str] | None = None - meta_tags: dict[str, str] = field(default_factory=dict) + meta_tags: dict[str, str] = dataclasses.field(default_factory=dict) # This is used to allow users to order pages when using the `rio.page` # decorator. It's not public, but simply a convenient place to store this. - _page_order_: int | None = field(default=None, init=False) + _page_order_: int | None = dataclasses.field(default=None, init=False) # A pre-parsed URL pattern object, used to verify whether a URL matches # this page, as well as extracting path parameters - _url_pattern: url_pattern.UrlPattern = field(init=False) + _url_pattern: url_pattern.UrlPattern = dataclasses.field(init=False) # The names of the query parameters that are passed to the `build` function - _url_parameter_parsers: t.Mapping[str, UrlParameterParser] = field( - init=False + _url_parameter_parsers: t.Mapping[str, UrlParameterParser] = ( + dataclasses.field(init=False) ) def __post_init__(self) -> None: @@ -497,7 +499,7 @@ def _get_active_page_instances( @t.final @imy.docstrings.mark_constructor_as_private -@dataclass(frozen=True) +@dataclasses.dataclass(frozen=True) class GuardEvent: """ Holds information regarding a guard event. diff --git a/rio/snippets/project_template.py b/rio/snippets/project_template.py index a300a24d..6ba14d42 100644 --- a/rio/snippets/project_template.py +++ b/rio/snippets/project_template.py @@ -1,9 +1,9 @@ from __future__ import annotations import copy +import dataclasses import json import typing as t -from dataclasses import dataclass import typing_extensions as te import uniserde @@ -47,7 +47,7 @@ AvailableTemplatesLiteral: te.TypeAlias = t.Literal[ ] -@dataclass +@dataclasses.dataclass class _TemplateConfig(uniserde.Serde): """ Model for parsing the JSON file which comes along with each project @@ -79,7 +79,7 @@ class _TemplateConfig(uniserde.Serde): theme: str | None -@dataclass +@dataclasses.dataclass class ProjectTemplate: """ Project templates are stored as snippets. This class represents all diff --git a/rio/snippets/snippet-files/project-template-AI Chatbot/conversation.py b/rio/snippets/snippet-files/project-template-AI Chatbot/conversation.py index 378413ca..fb54d74f 100644 --- a/rio/snippets/snippet-files/project-template-AI Chatbot/conversation.py +++ b/rio/snippets/snippet-files/project-template-AI Chatbot/conversation.py @@ -1,11 +1,11 @@ +import dataclasses import typing as t -from dataclasses import dataclass, field from datetime import datetime, timezone import openai # type: ignore (hidden from user) -@dataclass +@dataclasses.dataclass class ChatMessage: """ A simple storage class containing all the information needed for a single @@ -17,7 +17,7 @@ class ChatMessage: text: str -@dataclass +@dataclasses.dataclass class Conversation: """ The start of the show. This class contains a list of messages and can @@ -25,7 +25,7 @@ class Conversation: """ # The entire message history - messages: list[ChatMessage] = field(default_factory=list) + messages: list[ChatMessage] = dataclasses.field(default_factory=list) async def respond(self, client: openai.AsyncOpenAI) -> ChatMessage: """ diff --git a/rio/snippets/snippet-files/project-template-AI Chatbot/pages/chat_page.py b/rio/snippets/snippet-files/project-template-AI Chatbot/pages/chat_page.py index 27ff000d..5880133a 100644 --- a/rio/snippets/snippet-files/project-template-AI Chatbot/pages/chat_page.py +++ b/rio/snippets/snippet-files/project-template-AI Chatbot/pages/chat_page.py @@ -1,6 +1,6 @@ from __future__ import annotations -from dataclasses import field +import dataclasses # from datetime import datetime, timezone @@ -32,7 +32,7 @@ class ChatPage(rio.Component): # Since Python's dataclasses don't allow for mutable default values, we need # to use a factory function to create a new instance of the conversation # class. - conversation: conversation.Conversation = field( + conversation: conversation.Conversation = dataclasses.field( default_factory=conversation.Conversation ) diff --git a/rio/snippets/snippet-files/project-template-Authentication/data_models.py b/rio/snippets/snippet-files/project-template-Authentication/data_models.py index c7d5a2db..c922bcd1 100644 --- a/rio/snippets/snippet-files/project-template-Authentication/data_models.py +++ b/rio/snippets/snippet-files/project-template-Authentication/data_models.py @@ -1,16 +1,16 @@ from __future__ import annotations +import dataclasses import hashlib import os import secrets import uuid -from dataclasses import dataclass from datetime import datetime, timezone import rio -@dataclass +@dataclasses.dataclass class UserSettings(rio.UserSettings): """ Model for data stored client-side for each user. @@ -25,7 +25,7 @@ class UserSettings(rio.UserSettings): auth_token: str -@dataclass +@dataclasses.dataclass class UserSession: # This ID uniquely identifies the session. It also serves as the # authentication token for the user. @@ -41,7 +41,7 @@ class UserSession: valid_until: datetime -@dataclass +@dataclasses.dataclass class AppUser: """ Model for a user of the application. diff --git a/rio/snippets/snippet-files/project-template-Crypto Dashboard/pages/dashboard_page.py b/rio/snippets/snippet-files/project-template-Crypto Dashboard/pages/dashboard_page.py index 99e62c4f..e5885c9f 100644 --- a/rio/snippets/snippet-files/project-template-Crypto Dashboard/pages/dashboard_page.py +++ b/rio/snippets/snippet-files/project-template-Crypto Dashboard/pages/dashboard_page.py @@ -1,4 +1,4 @@ -from dataclasses import field +import dataclasses # from pathlib import Path @@ -39,7 +39,7 @@ class DashboardPage(rio.Component): """ fetch_data_from_api: bool = False - coin_data: pd.DataFrame = field( + coin_data: pd.DataFrame = dataclasses.field( default=pd.DataFrame( { "date": np.zeros(5), diff --git a/rio/snippets/snippet-files/project-template-Multipage Website/data_models.py b/rio/snippets/snippet-files/project-template-Multipage Website/data_models.py index ab2217fc..5c7c664a 100644 --- a/rio/snippets/snippet-files/project-template-Multipage Website/data_models.py +++ b/rio/snippets/snippet-files/project-template-Multipage Website/data_models.py @@ -1,8 +1,8 @@ +import dataclasses import typing as t -from dataclasses import dataclass -@dataclass(frozen=True) +@dataclasses.dataclass(frozen=True) class PageLayout: """ Represents the layout configuration for a page. @@ -16,7 +16,7 @@ class PageLayout: device: t.Literal["desktop", "mobile"] -@dataclass() +@dataclasses.dataclass class Testimonial: """ Class to represent a testimonial on the website. @@ -36,7 +36,7 @@ class Testimonial: image: str -@dataclass() +@dataclasses.dataclass class BlogPost: """ Class to represent a blog post on the website. diff --git a/rio/snippets/snippet-files/project-template-Simple CRUD/data_models.py b/rio/snippets/snippet-files/project-template-Simple CRUD/data_models.py index 3b60eefb..9f508ca7 100644 --- a/rio/snippets/snippet-files/project-template-Simple CRUD/data_models.py +++ b/rio/snippets/snippet-files/project-template-Simple CRUD/data_models.py @@ -1,10 +1,10 @@ from __future__ import annotations import copy -from dataclasses import dataclass +import dataclasses -@dataclass +@dataclasses.dataclass class MenuItem: """ MenuItem data model. diff --git a/rio/snippets/snippet-files/project-template-Todo App/components/new_todo_item_input.py b/rio/snippets/snippet-files/project-template-Todo App/components/new_todo_item_input.py index 8eae094a..2f3f4a9c 100644 --- a/rio/snippets/snippet-files/project-template-Todo App/components/new_todo_item_input.py +++ b/rio/snippets/snippet-files/project-template-Todo App/components/new_todo_item_input.py @@ -1,8 +1,9 @@ from __future__ import annotations +import dataclasses + # import datetime -from dataclasses import field import rio @@ -25,7 +26,7 @@ class NewTodoItemInput(rio.Component): # This is a private field that we need for an attribute binding. We don't # want to create a constructor parameter for this field, so we set # `init=False`. - _title: str = field(init=False, default="") + _title: str = dataclasses.field(init=False, default="") async def _on_confirm( self, _: rio.TextInputConfirmEvent | None = None diff --git a/rio/snippets/snippet-files/project-template-Todo App/data_models.py b/rio/snippets/snippet-files/project-template-Todo App/data_models.py index 4a0bccdb..84c303c0 100644 --- a/rio/snippets/snippet-files/project-template-Todo App/data_models.py +++ b/rio/snippets/snippet-files/project-template-Todo App/data_models.py @@ -1,10 +1,10 @@ +import dataclasses import datetime -from dataclasses import dataclass import rio -@dataclass +@dataclasses.dataclass class TodoItem: title: str creation_time: datetime.datetime diff --git a/rio/snippets/snippet_manager.py b/rio/snippets/snippet_manager.py index c7ded539..30bace72 100644 --- a/rio/snippets/snippet_manager.py +++ b/rio/snippets/snippet_manager.py @@ -1,8 +1,8 @@ from __future__ import annotations +import dataclasses import re import typing as t -from dataclasses import dataclass from pathlib import Path __all__ = [ @@ -14,7 +14,7 @@ __all__ = [ SECTION_PATTERN = re.compile(r" *#\s*<(\/?[\w-]+)>") -@dataclass +@dataclasses.dataclass class Snippet: # The group the snippet is in group: str diff --git a/rio/text_style.py b/rio/text_style.py index 20892a7f..c7248763 100644 --- a/rio/text_style.py +++ b/rio/text_style.py @@ -1,8 +1,8 @@ from __future__ import annotations +import dataclasses import pathlib import typing as t -from dataclasses import KW_ONLY, dataclass from uniserde import JsonDoc @@ -22,7 +22,7 @@ __all__ = [ _TextFill = SolidFill | LinearGradientFill | ImageFill | Color -@dataclass(frozen=True) +@dataclasses.dataclass(frozen=True) class Font(SelfSerializing): """ A custom font face. @@ -79,7 +79,7 @@ Font.ROBOTO_MONO = Font( ) -@dataclass(frozen=True) +@dataclasses.dataclass(frozen=True) class TextStyle(SelfSerializing): """ A collection of styling properties for text. @@ -107,7 +107,7 @@ class TextStyle(SelfSerializing): `all_caps`: Whether the text is transformed to ALL CAPS or not. """ - _: KW_ONLY + _: dataclasses.KW_ONLY font: Font | None = None fill: _TextFill | None = None font_size: float = 1.0 diff --git a/rio/theme.py b/rio/theme.py index 4b9701f7..cdd7bd75 100644 --- a/rio/theme.py +++ b/rio/theme.py @@ -1,7 +1,7 @@ from __future__ import annotations +import dataclasses import typing as t -from dataclasses import KW_ONLY, dataclass from uniserde import Jsonable @@ -105,7 +105,7 @@ def _make_semantic_palette(color: rio.Color) -> Palette: @t.final -@dataclass() +@dataclasses.dataclass() class Palette: background: rio.Color background_variant: rio.Color @@ -147,7 +147,7 @@ class Palette: @t.final -@dataclass() +@dataclasses.dataclass() class Theme: """ Defines the visual style of the application. @@ -162,7 +162,7 @@ class Theme: stable interface. """ - _: KW_ONLY + _: dataclasses.KW_ONLY primary_palette: Palette secondary_palette: Palette diff --git a/rio/user_settings_module.py b/rio/user_settings_module.py index d26dd930..8ac793b6 100644 --- a/rio/user_settings_module.py +++ b/rio/user_settings_module.py @@ -1,8 +1,8 @@ from __future__ import annotations import copy +import dataclasses import typing as t -from dataclasses import field import imy.docstrings import typing_extensions as te @@ -85,12 +85,12 @@ class UserSettings(metaclass=RioDataclassMeta): # set outside of any sections. section_name: t.ClassVar[str] = "" - _rio_session_: session.Session | None = field( + _rio_session_: session.Session | None = dataclasses.field( default=None, init=False, repr=False, compare=False ) # Set of field names that have been modified and need to be saved - _rio_dirty_attribute_names_: set[str] = field( + _rio_dirty_attribute_names_: set[str] = dataclasses.field( default_factory=set, init=False, repr=False, compare=False ) diff --git a/rio/utils.py b/rio/utils.py index 6369e3ff..ae84ad88 100644 --- a/rio/utils.py +++ b/rio/utils.py @@ -1,5 +1,6 @@ from __future__ import annotations +import dataclasses import hashlib import io import mimetypes @@ -8,7 +9,6 @@ import re import secrets import socket import typing as t -from dataclasses import dataclass, field from io import BytesIO, StringIO from pathlib import Path @@ -140,7 +140,7 @@ def secure_string_hash(*values: str, hash_length: int = 32) -> str: return hasher.hexdigest() -@dataclass(frozen=True) +@dataclasses.dataclass(frozen=True) class FileInfo: """ Contains information about a file. @@ -166,7 +166,7 @@ class FileInfo: name: str size_in_bytes: int media_type: str - _contents: bytes | t.IO[bytes] = field(repr=False) + _contents: bytes | t.IO[bytes] = dataclasses.field(repr=False) def __init__( self, diff --git a/rio/version.py b/rio/version.py index ff39ffc7..06f62188 100644 --- a/rio/version.py +++ b/rio/version.py @@ -1,10 +1,10 @@ +import dataclasses import typing as t -from dataclasses import dataclass import typing_extensions as te -@dataclass(frozen=True) +@dataclasses.dataclass(frozen=True) class Version: major: int minor: int = 0