Merge branch 'dev' of ssh://gitlab.com/team-rio/rio into dev

This commit is contained in:
Sn3llius
2024-04-12 07:51:20 +02:00
26 changed files with 115 additions and 73 deletions

View File

@@ -2,9 +2,9 @@ repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.5
hooks:
- id: ruff
args: [ --select, F401, --fix ]
- id: ruff-format
- id: ruff
args: [--select, F401, --fix]
- id: ruff-format
- repo: https://github.com/pycqa/isort
rev: 5.13.2
@@ -15,3 +15,4 @@ repos:
rev: v4.0.0-alpha.8
hooks:
- id: prettier
exclude: '\.md$'

View File

@@ -16,7 +16,7 @@ apps.
🐍 Rio is based **entirely on Python**. You **won't need a single line of HTML, CSS, or
JavaScript** to create beautiful, modern apps.
[Tutorial](https://rio.dev/docs/tutorial-simple-dashboard/1-rio-setup) - [Examples](https://rio.dev/examples) - [Discord](https://discord.gg/7ejXaPwhyH) - [docs](https://rio.dev/docs) - [Source Code](https://gitlab.com/team-rio/rio)
[Tutorial](https://rio.dev/docs/tutorial-simple-dashboard/1-rio-setup) - [Examples](https://rio.dev/examples) - [Discord](https://discord.gg/7ejXaPwhyH) - [Docs](https://rio.dev/docs) - [Source Code](https://gitlab.com/team-rio/rio)
Rio brings React-style components to Python. Pull from a wealth of built-in
components and combine them to create your own custom components. Then combine

View File

@@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry]
license = "LGPL-3.0" # TODO
name = "rio-ui"
version = "0.5.1"
version = "0.5.3"
description = "Build modern Websites and Apps just with Python"
authors = ["Jakob Pinterits <jakob.pinterits@gmail.com>", "Paul Pinterits"]
readme = "README.md"
@@ -50,7 +50,7 @@ fastapi = "^0.109.1"
fuzzywuzzy = "^0.18.0"
gitignore-parser = "^0.1.9"
httpx = "^0.25.1"
imy = "^0.2.1"
imy = "^0.2.2"
introspection = "^1.7.13"
keyring = "^24.3.0"
pillow = "^10.2.0"
@@ -62,7 +62,7 @@ python-levenshtein = "^0.23.0"
python-multipart = "^0.0.6"
pytz = "^2024.1"
pywebview = { version = "^4.2.2", optional = true }
revel = "0.8.19"
revel = "^0.9.0"
timer-dict = "^1.0.0"
tomlkit = "^0.12.3"
typing-extensions = "^4.5.0"
@@ -71,6 +71,7 @@ uniserde = "^0.3.12"
uvicorn = { extras = ["standard"], version = "^0.23.2" }
watchfiles = "^0.21.0"
yarl = "^1.9.2"
isort = "^5.13.2"
[tool.poetry.extras]
window = ["cefpython3", "platformdirs", "pygobject", "pywebview"]
@@ -79,7 +80,6 @@ window = ["cefpython3", "platformdirs", "pygobject", "pywebview"]
alt-pytest-asyncio = "^0.7.2"
black = "^23.1.0"
coverage = "^7.2.2"
isort = "^5.12.0"
pre-commit = "^3.1.1"
pyfakefs = "^5.3.0"
pytest = "^7.3.1"

View File

@@ -1,9 +1,9 @@
import logging
from typing import Literal
import imy.package_metadata
import introspection
import revel
from revel import error, fatal, print, success, warning
from revel import * # type: ignore
import rio.snippets
@@ -17,7 +17,9 @@ revel.GLOBAL_STYLES.add_alias("primary", ["cyan"])
revel.GLOBAL_STYLES.add_alias("bg-primary", ["bg-cyan"])
app = revel.App(
summary="An easy to use, app & web framework for Python",
nicename="Rio",
command_name="rio",
summary="An easy to use, web & app framework for Python",
details="""
Rio is a framework for building reactive apps and websites in Python. It's
designed to be easy to use, and to get out of your way as much as possible.
@@ -25,6 +27,7 @@ designed to be easy to use, and to get out of your way as much as possible.
This is the command line interface for Rio. You can use it to easily create new
projects, run them, and more.
""",
version=imy.package_metadata.get_package_version("rio-ui"),
)
@@ -192,7 +195,7 @@ class {class_name}(rio.Component):
def build(self) -> rio.Component:
return rio.Markdown('''
## This is a sample component
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
''')
"""

View File

@@ -1,3 +1,4 @@
import io
import re
import shutil
import string
@@ -5,6 +6,7 @@ from pathlib import Path
from typing import * # type: ignore
import introspection
import isort
import revel
from revel import fatal, print, success
@@ -47,7 +49,7 @@ def write_init_file(fil: IO, snippets: Iterable[rio.snippets.Snippet]) -> None:
def generate_root_init(
fil: TextIO,
out: TextIO,
*,
raw_name: str,
project_type: Literal["app", "website"],
@@ -84,7 +86,9 @@ def generate_root_init(
# Imports
default_theme = rio.Theme.from_color()
fil.write(
buffer = io.StringIO()
buffer.write(
f"""
from __future__ import annotations
@@ -102,11 +106,12 @@ from . import components as comps
try:
additional_imports = root_init_snippet.get_section("additional-imports")
except KeyError:
pass
needs_isort = False
else:
fil.write("\n")
fil.write(additional_imports)
fil.write("\n\n")
buffer.write("\n")
buffer.write(additional_imports)
buffer.write("\n\n")
needs_isort = True
# Additional code
try:
@@ -114,12 +119,12 @@ from . import components as comps
except KeyError:
pass
else:
fil.write("\n")
fil.write(additional_code)
fil.write("\n\n")
buffer.write("\n")
buffer.write(additional_code)
buffer.write("\n\n")
# Theme & App generation
fil.write(
buffer.write(
f"""
# Define a theme for Rio to use.
#
@@ -143,16 +148,24 @@ app = rio.App(
# Some parameters are optional
if on_app_start is not None:
fil.write(
buffer.write(
f" # This function will be called once the app is ready.\n"
f" #\n"
f" # `rio run` will also call it again each time the app is reloaded.\n"
f" on_app_start={on_app_start},\n"
)
fil.write(" theme=theme,\n")
fil.write(' assets_dir=Path(__file__).parent / "assets",\n')
fil.write(")\n\n")
buffer.write(" theme=theme,\n")
buffer.write(' assets_dir=Path(__file__).parent / "assets",\n')
buffer.write(")\n\n")
# Due to imports coming from different sources they're often not sorted.
# -> Apply `isort`
if needs_isort:
formatted_code = isort.code(buffer.getvalue())
out.write(formatted_code)
else:
out.write(buffer.getvalue())
def strip_invalid_filename_characters(name: str) -> str:
@@ -226,7 +239,9 @@ def write_component_file(
Writes the Python file containing a component or page to the given file.
"""
# Common imports
out.write(
buffer = io.StringIO()
buffer.write(
f"""from __future__ import annotations
from dataclasses import KW_ONLY, field
@@ -243,13 +258,22 @@ from .. import components as comps
try:
additional_imports = snip.get_section("additional-imports")
except KeyError:
pass
needs_isort = False
else:
out.write(additional_imports)
out.write("\n")
buffer.write(additional_imports)
buffer.write("\n")
needs_isort = True
# The component proper
out.write(snip.get_section("component"))
buffer.write(snip.get_section("component"))
# Due to imports coming from different sources they're often not sorted.
# -> Apply `isort`
if needs_isort:
formatted_code = isort.code(buffer.getvalue())
out.write(formatted_code)
else:
out.write(buffer.getvalue())
def generate_dependencies_file(project_dir: Path, dependencies: dict[str, str]) -> None:
@@ -358,7 +382,7 @@ def create_project(
# Generate /project/__init__.py
with open(main_module_dir / "__init__.py", "w") as fil:
generate_root_init(
fil=fil,
out=fil,
raw_name=raw_name,
project_type=type,
components=template.component_snippets,

View File

@@ -1,5 +1,3 @@
import typing
from .auto_form import *
from .banner import *
from .button import *
@@ -55,5 +53,5 @@ from .tooltip import *
from .website import *
assert (
Container is not typing.Container
Container.__module__ != "typing"
), "Looks like somebody imported `typing.Container`, thus accidentally overwriting `rio.Container`. Are you missing an `__all__` in some component?"

View File

@@ -70,12 +70,12 @@ class Sidebar(component.Component):
rio.Text(
self.session.app.name,
style="heading2",
align_x=0,
justify='left',
),
rio.Text(
"TODO: Subtext",
style="dim",
align_x=0,
justify='left',
),
align_y=0,
),

View File

@@ -23,7 +23,6 @@ import rio
from .. import event, global_state, inspection
from ..dataclass import RioDataclassMeta, class_local_fields, internal_field
from ..state_properties import StateBindingMaker, StateProperty
from . import fundamental_component
__all__ = ["Component"]
@@ -514,6 +513,8 @@ class Component(abc.ABC, metaclass=ComponentMeta):
include_self: bool,
recurse_into_high_level_components: bool,
) -> Iterable[Component]:
from . import fundamental_component # Avoid circular import problem
# Special case the component itself to handle `include_self`
if include_self:
yield self
@@ -538,6 +539,8 @@ class Component(abc.ABC, metaclass=ComponentMeta):
"""
Iterate over all components in the component tree, with this component as the root.
"""
from . import fundamental_component # Avoid circular import problem
yield self
if isinstance(self, fundamental_component.FundamentalComponent):

View File

@@ -10,7 +10,10 @@ import rio
from .. import common, inspection
from .component import Component
__all__ = ["FundamentalComponent", "KeyboardFocusableFundamentalComponent"]
__all__ = [
"FundamentalComponent",
"KeyboardFocusableFundamentalComponent",
]
JAVASCRIPT_SOURCE_TEMPLATE = """

View File

@@ -102,7 +102,7 @@ class LabeledColumn(Component):
def build(self) -> Component:
rows = [
[
rio.Text(label, align_x=1),
rio.Text(label, justify='right'),
child,
]
for label, child in self.content.items()

View File

@@ -195,7 +195,7 @@ class SimpleListItem(Component):
text_children = [
rio.Text(
self.text,
align_x=0,
justify='left',
)
]
@@ -205,7 +205,7 @@ class SimpleListItem(Component):
self.secondary_text,
wrap=True,
style="dim",
align_x=0,
justify='left',
)
)

View File

@@ -106,7 +106,7 @@ class ComponentDetails(rio.Component):
rio.Text(
text,
style="dim" if is_label else "text",
align_x=1 if is_label else 0,
justify='right' if is_label else 'left',
),
row_index,
column_index,
@@ -126,7 +126,7 @@ class ComponentDetails(rio.Component):
rio.Text(
target.key,
style="dim",
align_x=0,
justify='left',
),
]
@@ -160,7 +160,7 @@ class ComponentDetails(rio.Component):
rio.Text(
f"{file} line {line}",
style="dim",
align_x=0,
justify='left',
),
row_index,
0,
@@ -227,8 +227,8 @@ class ComponentDetails(rio.Component):
row_index += 1
# Header
result.add(rio.Text("width", style="dim", align_x=0), row_index, 1)
result.add(rio.Text("height", style="dim", align_x=0), row_index, 2)
result.add(rio.Text("width", style="dim", justify='left'), row_index, 1)
result.add(rio.Text("height", style="dim", justify='left'), row_index, 2)
row_index += 1
# The size as specified in Python

View File

@@ -1,6 +1,7 @@
from typing import * # type: ignore
import rio
import rio.components.class_container
import rio.components.debugger_connector
from . import (
deploy_page,

View File

@@ -8,7 +8,7 @@ class DeployPage(rio.Component):
"Deploy",
style="heading2",
margin=1,
align_x=0,
justify='left',
),
rio.Column(
rio.Icon(

View File

@@ -8,7 +8,7 @@ class DocsPage(rio.Component):
"Documentation",
style="heading2",
margin=1,
align_x=0,
justify='left',
),
rio.Column(
rio.Text(

View File

@@ -206,7 +206,13 @@ class IconsPage(rio.Component):
children = []
# Heading
children.append(rio.Text("Configure", style="heading3", align_x=0))
children.append(
rio.Text(
"Configure",
style="heading3",
justify='left',
)
)
# Fill
children.append(
@@ -279,7 +285,7 @@ class IconsPage(rio.Component):
rio.Text(
"Example Code",
style="heading3",
align_x=0,
justify='left',
margin_top=1,
)
)

View File

@@ -36,13 +36,13 @@ class ProjectPage(rio.Component):
rio.Text(
project_name,
style="heading2",
align_x=0,
justify='left',
),
rio.Text(
str(self.project.project_directory),
style="dim",
margin_bottom=2,
align_x=0,
justify='left',
),
rio.Text(
"To launch your project, Rio needs to know the name of your python module and in which variable you've stored your app. You can configure those here.",

View File

@@ -201,7 +201,7 @@ class PalettePicker(rio.Component): #
fill=palette.foreground,
),
selectable=False,
align_x=0,
justify='left',
),
rio.Text(
f"#{palette.background.hex}",
@@ -209,7 +209,7 @@ class PalettePicker(rio.Component): #
font_size=1,
fill=palette.foreground.replace(opacity=0.5),
),
align_x=0,
justify='left',
),
spacing=0.2,
margin_x=1,
@@ -346,7 +346,7 @@ class ThemePickerPage(rio.Component):
# "Theme Colors",
# style="heading3",
# margin_bottom=1,
# align_x=0,
# justify='left',
# ),
PalettePicker(
shared_open_key=self.bind().shared_open_key,
@@ -419,7 +419,7 @@ class ThemePickerPage(rio.Component):
style="heading3",
margin_top=1,
margin_bottom=1,
align_x=0,
justify='left',
),
radius_sliders,
# Theme Variants
@@ -428,7 +428,7 @@ class ThemePickerPage(rio.Component):
style="heading3",
margin_top=1,
margin_bottom=1,
align_x=0,
justify='left',
),
rio.Row(
rio.Spacer(),
@@ -451,7 +451,7 @@ class ThemePickerPage(rio.Component):
style="heading3",
margin_top=1,
# margin_bottom=1, Not used for now, since markdown has an oddly large margin anyway
align_x=0,
justify='left',
),
rio.Markdown(
f"""

View File

@@ -1,6 +1,6 @@
from typing import * # type: ignore
import rio
import rio.components.component_tree
from . import component_details
@@ -19,7 +19,7 @@ class TreePage(rio.Component):
"Component Tree",
style="heading2",
margin=margin,
align_x=0,
justify="left",
),
rio.components.component_tree.ComponentTree(
width=10,

View File

@@ -31,6 +31,7 @@ AvailableTemplatesLiteral: TypeAlias = Literal[
"Empty",
# Sort the remainder alphabetically
"AI Chatbot",
"Simple CRUD",
"Simple Dashboard",
"Tic-Tac-Toe",
]

View File

@@ -19,19 +19,19 @@ class AboutMe(rio.Component):
rio.Text(
"Jane Doe",
style="heading1",
align_x=0,
justify='left',
),
rio.Text(
"Data Analyst",
align_x=0,
justify='left',
),
rio.Text(
"AI Researcher",
align_x=0,
justify='left',
),
rio.Text(
"Python Developer",
align_x=0,
justify='left',
),
spacing=0.5,
align_y=0,

View File

@@ -33,7 +33,7 @@ class Contact(rio.Component):
image,
rio.Text(
self.text,
align_x=0,
justify='left',
width="grow",
),
width="grow",

View File

@@ -30,20 +30,20 @@ class HistoryItem(rio.Component):
rio.Column(
rio.Text(
f"{self.from_string} - {self.to_string}",
align_x=0,
justify='left',
style=rio.TextStyle(fill=rio.Color.GREY),
),
rio.Text(
f"{self.title} at {self.organization}",
style="heading3",
align_x=0,
justify='left',
),
rio.Revealer(
None,
rio.Text(
self.details,
wrap=True,
align_x=0,
justify='left',
),
is_open=self.is_open,
),

View File

@@ -14,7 +14,7 @@ class SkillBars(rio.Component):
rio.Column(
rio.Text(
name,
align_x=0,
justify='left',
),
rio.ProgressBar(
level / 10,

View File

@@ -1,8 +1,6 @@
# <additional-imports>
import openai
import rio
# </additional-imports>

View File

@@ -0,0 +1,4 @@
{
"level": "intermediate",
"summary": "TODO"
}