Skip to content

Commit abb178c

Browse files
author
CI Runner
committed
fix: make CI green — ruff/pyright violations, reflex module resolution, export working-directory
- Split 46 E701/E702 compound one-liners (if/raise, semicolon-chained statements) across auth_adapter.py, migrations/env.py, 0001_application_spine.py, analysis.py, auth.py, cli.py, models.py, services.py, worker.py — cosmetic, no behavior change. - auth_adapter.py: add missing @rx.event on do_logout (fixes pyright reportIncompatibleVariableOverride — parent's do_logout is @rx.event, the override wasn't); capture require()'s return in create_user instead of discarding it (fixes reportOptionalMemberAccess on principal.user_id, and was a real narrowing bug, not just a type-checker complaint). - rxconfig.py: add app_module_import="starter_web.app" — Reflex's default convention expects starter_web/starter_web.py, but the app lives in src/starter_web/app.py (src-layout). Without this, `reflex export`/`reflex run` never worked at all: "Module starter_web.starter_web not found". This was never caught because no CI run ever got past the earlier ruff/pyright gap to reach this step. - ci.yml: add working-directory: apps/web to the reflex export step — rxconfig.py lives there, not at repo root, so the step 404'd on "rxconfig.py not found" even with the module fix applied. - apps/web/.gitignore, apps/web/reflex.lock/: first successful `reflex init` in this repo's history generated these; committing the lockfile for reproducible frontend builds (same rationale as uv.lock). Verified locally: ruff check, pyright, pytest -m "not database", and reflex export --frontend-only --no-zip (from apps/web) all pass clean.
1 parent 8c95eaa commit abb178c

14 files changed

Lines changed: 1250 additions & 28 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ jobs:
1313
- run: uv run pyright apps packages
1414
- run: uv run pytest -m "not database"
1515
- run: uv run reflex export --frontend-only --no-zip
16+
working-directory: apps/web

apps/web/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.states
2+
__pycache__/
3+
.web
4+
*.py[cod]
5+
*.db
6+
assets/external/

apps/web/reflex.lock/bun.lock

Lines changed: 1132 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/web/reflex.lock/package.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"name": "reflex",
3+
"type": "module",
4+
"scripts": {
5+
"dev": "react-router dev --host",
6+
"export": "react-router build"
7+
},
8+
"dependencies": {
9+
"@radix-ui/react-form": "0.1.8",
10+
"@radix-ui/themes": "3.3.0",
11+
"@react-router/node": "7.15.0",
12+
"isbot": "5.1.40",
13+
"lucide-react": "1.14.0",
14+
"react": "19.2.6",
15+
"react-dom": "19.2.6",
16+
"react-error-boundary": "6.1.1",
17+
"react-helmet": "6.1.0",
18+
"react-router": "7.15.0",
19+
"react-router-dom": "7.15.0",
20+
"socket.io-client": "4.8.3",
21+
"sonner": "2.0.7",
22+
"universal-cookie": "7.2.2"
23+
},
24+
"devDependencies": {
25+
"@emotion/react": "11.14.0",
26+
"@react-router/dev": "7.15.0",
27+
"@react-router/fs-routes": "7.15.0",
28+
"autoprefixer": "10.5.0",
29+
"postcss": "8.5.14",
30+
"postcss-import": "16.1.1",
31+
"vite": "8.0.12"
32+
},
33+
"overrides": {
34+
"cookie": "1.1.1"
35+
}
36+
}

apps/web/rxconfig.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
import os
22
import reflex as rx
3-
config = rx.Config(app_name="starter_web", db_url=os.environ.get("DATABASE_URL"))
3+
config = rx.Config(app_name="starter_web", app_module_import="starter_web.app", db_url=os.environ.get("DATABASE_URL"))

apps/web/src/starter_web/auth_adapter.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,25 @@ class AppAuthState(reflex_local_auth.LocalAuthState):
1111
@rx.var(cache=False)
1212
def principal(self) -> Principal | None:
1313
user = self.authenticated_user
14-
if user.id is None or user.id < 0 or not user.enabled: return None
14+
if user.id is None or user.id < 0 or not user.enabled:
15+
return None
1516
with rx.session() as session:
1617
profile = session.exec(select(UserProfile).where(UserProfile.local_user_id == user.id)).one_or_none()
17-
if profile is None: return None
18+
if profile is None:
19+
return None
1820
return Principal(user_id=user.id, email=profile.email or user.username, role=Role(profile.role), is_active=True)
21+
22+
@rx.event
1923
def do_logout(self):
2024
return reflex_local_auth.LocalAuthState.do_logout
2125

2226
def create_user(self, username: str, password: str, email: str | None, role: Role) -> None:
2327
"""Admin-only account flow; role is checked server-side, never accepted from a client as authority."""
24-
principal = self.principal
25-
require(principal, Capability.MANAGE_USERS)
28+
principal = require(self.principal, Capability.MANAGE_USERS)
2629
validate_password(password)
2730
with rx.session() as session:
2831
user = reflex_local_auth.LocalUser(username=username, password_hash=reflex_local_auth.LocalUser.hash_password(password), enabled=True)
29-
session.add(user); session.flush()
32+
session.add(user)
33+
session.flush()
3034
session.add(UserProfile(local_user_id=user.id, email=email, role=role, created_by_user_id=principal.user_id))
3135
session.commit()

migrations/env.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@
55
target_metadata = Base.metadata
66
def run_migrations_offline() -> None:
77
context.configure(url=config.get_main_option("sqlalchemy.url"), target_metadata=target_metadata, literal_binds=True)
8-
with context.begin_transaction(): context.run_migrations()
8+
with context.begin_transaction():
9+
context.run_migrations()
910
def run_migrations_online() -> None:
1011
connectable = engine_from_config(config.get_section(config.config_ini_section, {}), prefix="sqlalchemy.", poolclass=pool.NullPool)
1112
with connectable.connect() as connection:
1213
context.configure(connection=connection, target_metadata=target_metadata)
13-
with context.begin_transaction(): context.run_migrations()
14-
if context.is_offline_mode(): run_migrations_offline()
15-
else: run_migrations_online()
14+
with context.begin_transaction():
15+
context.run_migrations()
16+
if context.is_offline_mode():
17+
run_migrations_offline()
18+
else:
19+
run_migrations_online()

migrations/versions/0001_application_spine.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,7 @@ def upgrade() -> None:
2525
op.create_table("analysis_jobs", sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True), sa.Column("dataset_id", postgresql.UUID(as_uuid=True), sa.ForeignKey("datasets.id"), nullable=False), sa.Column("submitted_by_user_id", sa.Integer(), sa.ForeignKey("localuser.id"), nullable=False), sa.Column("prompt", sa.Text(), nullable=False), sa.Column("status", sa.String(20), nullable=False), sa.Column("result", postgresql.JSONB()), sa.Column("error", sa.Text()), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("completed_at", sa.DateTime(timezone=True)))
2626
op.create_table("audit_events", sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True), sa.Column("actor_user_id", sa.Integer(), sa.ForeignKey("localuser.id")), sa.Column("action", sa.String(100), nullable=False), sa.Column("subject", sa.String(255), nullable=False), sa.Column("details", postgresql.JSONB()), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()))
2727
def downgrade() -> None:
28-
op.drop_table("audit_events"); op.drop_table("analysis_jobs"); op.drop_table("datasets"); op.drop_table("user_profiles")
28+
op.drop_table("audit_events")
29+
op.drop_table("analysis_jobs")
30+
op.drop_table("datasets")
31+
op.drop_table("user_profiles")

packages/core/src/starter_core/analysis.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from dataclasses import dataclass
22
from typing import Protocol
33
@dataclass(frozen=True, slots=True)
4-
class AnalysisResult: summary: str; rows_examined: int
4+
class AnalysisResult:
5+
summary: str
6+
rows_examined: int
57
class AnalysisEngine(Protocol):
68
async def analyze(self, *, dataset_name: str, prompt: str) -> AnalysisResult: ...
79
class MockAnalysisEngine:
Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
from dataclasses import dataclass
22
from enum import StrEnum
33
from .types import Role
4-
class AuthorizationError(PermissionError): pass
5-
class Capability(StrEnum): MANAGE_USERS = "manage_users"; CREATE_DATASET = "create_dataset"; SUBMIT_ANALYSIS = "submit_analysis"; VIEW_RESULTS = "view_results"
4+
class AuthorizationError(PermissionError):
5+
pass
6+
class Capability(StrEnum):
7+
MANAGE_USERS = "manage_users"
8+
CREATE_DATASET = "create_dataset"
9+
SUBMIT_ANALYSIS = "submit_analysis"
10+
VIEW_RESULTS = "view_results"
611
@dataclass(frozen=True, slots=True)
7-
class Principal: user_id: int; email: str; role: Role; is_active: bool
12+
class Principal:
13+
user_id: int
14+
email: str
15+
role: Role
16+
is_active: bool
817
PERMISSIONS = {Role.ADMIN: frozenset(Capability), Role.MEMBER: frozenset({Capability.CREATE_DATASET, Capability.SUBMIT_ANALYSIS, Capability.VIEW_RESULTS}), Role.VIEWER: frozenset({Capability.VIEW_RESULTS})}
918
def require(principal: Principal | None, capability: Capability) -> Principal:
10-
if principal is None or not principal.is_active or capability not in PERMISSIONS[principal.role]: raise AuthorizationError("not authorized")
19+
if principal is None or not principal.is_active or capability not in PERMISSIONS[principal.role]:
20+
raise AuthorizationError("not authorized")
1121
return principal
1222
def validate_password(password: str) -> None:
13-
if not 12 <= len(password) <= 256: raise ValueError("password must be between 12 and 256 characters")
23+
if not 12 <= len(password) <= 256:
24+
raise ValueError("password must be between 12 and 256 characters")

0 commit comments

Comments
 (0)