Skip to content

deprecate rx Model#6442

Open
adhami3310 wants to merge 1 commit intomainfrom
deprecate-rx-Model
Open

deprecate rx Model#6442
adhami3310 wants to merge 1 commit intomainfrom
deprecate-rx-Model

Conversation

@adhami3310
Copy link
Copy Markdown
Member

No description provided.

@adhami3310 adhami3310 requested a review from a team as a code owner May 1, 2026 22:20
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 1, 2026

Merging this PR will not alter performance

✅ 17 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing deprecate-rx-Model (adb1c0c) with main (b438de1)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 1, 2026

Greptile Summary

This PR deprecates rx.Model (SQLModel-based) by extracting all alembic migration and engine functions into standalone module-level functions, reducing the sqlmodel dependency requirement for database migration operations. All call sites in reflex.py, app.py, and prerequisites.py are updated accordingly, and Model methods now delegate to the standalone functions with deprecation warnings.

  • create_all is absent from the else: fallback block for missing sqlalchemy, causing a NameError instead of the expected ImportError with install guidance.
  • _alembic_render_item unconditionally injects import sqlmodel into autogenerated migration scripts even though it now lives in the sqlalchemy-only block; pure-SQLAlchemy users (without sqlmodel) will get broken migration files.

Confidence Score: 3/5

Not safe to merge without fixing the two P1 regressions in model.py

Two P1 issues: a missing fallback stub for create_all (NameError when sqlalchemy absent) and unconditional sqlmodel import injection in migration scripts for pure-SQLAlchemy users (broken migrations without sqlmodel). Both affect existing code paths exposed by this refactor.

reflex/model.py — specifically the sqlalchemy else-block (missing create_all stub) and _alembic_render_item (unconditional sqlmodel injection)

Important Files Changed

Filename Overview
reflex/model.py Core refactor: alembic functions extracted from Model class into standalone module-level functions; Model now delegates with deprecation warnings; two P1 bugs: missing create_all fallback and unconditional sqlmodel import injection in migration scripts
reflex/app.py Updates admin dashboard setup to use get_engine() directly instead of Model.get_db_engine(); straightforward call-site update
reflex/reflex.py DB CLI commands updated to call module-level alembic_init/migrate/alembic_autogenerate/get_engine instead of Model class methods
reflex/utils/prerequisites.py check_schema_up_to_date updated to use module-level get_engine/alembic_autogenerate instead of Model methods
tests/units/test_model.py Tests updated to import and call standalone functions; Model still used for SQLModel-based table definitions (expected, since Model is deprecated not removed)
tests/units/test_sqlalchemy.py Tests updated to standalone functions; two commented-out assertions remain that should be removed per project convention

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[find_spec sqlalchemy] -->|True| B[get_engine / create_all / ModelRegistry / sqla_session]
    A -->|False| C[_print_db_not_available stubs]

    B --> D[find_spec sqlalchemy + alembic]
    D -->|True| E[alembic_init / get_migration_history\nalembic_autogenerate / migrate\n_alembic_render_item adds 'import sqlmodel']
    D -->|False| F[_print_db_not_available stubs]

    B --> G[find_spec sqlmodel + sqlalchemy + pydantic]
    G -->|True| H[Model class deprecated wrapper\n_warn_about_model_deprecation\nsession / asession / serialize_sqlmodel]
    G -->|False| I[Model / session / asession not available]

    H -->|delegates to| B
    H -->|delegates to| E
Loading

Comments Outside Diff (1)

  1. reflex/model.py, line 260-265 (link)

    P1 create_all missing from sqlalchemy-unavailable fallback

    create_all() is defined inside if find_spec("sqlalchemy"): (line 122) but is absent from the matching else: block (lines 260-265). When sqlalchemy is not installed, calling create_all() raises NameError: name 'create_all' is not defined instead of the user-friendly ImportError that all other module-level stubs produce via _print_db_not_available.

Reviews (1): Last reviewed commit: "deprecate rx Model" | Re-trigger Greptile

Comment thread reflex/model.py
Comment on lines +322 to +345
def _alembic_render_item(
type_: str,
obj: Any,
autogen_context: alembic.autogenerate.api.AutogenContext,
):
"""Alembic render_item hook call.

This method is called to provide python code for the given obj,
but currently it is only used to add `sqlmodel` to the import list
when generating migration scripts.

See https://alembic.sqlalchemy.org/en/latest/api/runtime.html

Args:
type_: One of "schema", "table", "column", "index",
"unique_constraint", or "foreign_key_constraint".
obj: The object being rendered.
autogen_context: Shared AutogenContext passed to each render_item call.

Returns:
False - Indicating that the default rendering should be used.
"""
autogen_context.imports.add("import sqlmodel")
return False
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 _alembic_render_item injects import sqlmodel unconditionally

This function now lives in the find_spec("sqlalchemy") and find_spec("alembic") block, which does not require sqlmodel. It unconditionally adds "import sqlmodel" to every generated migration script.

Users using the new pure-SQLAlchemy path (ModelBase/sqla_session) without sqlmodel installed will find that every autogenerated migration file contains import sqlmodel, causing those migration scripts to fail at runtime with ModuleNotFoundError: No module named 'sqlmodel'.

The injection should be conditional:

if find_spec("sqlmodel"):
    autogen_context.imports.add("import sqlmodel")
return False

Comment thread reflex/model.py
Comment on lines +559 to +565
def _warn_about_model_deprecation():
console.deprecate(
feature_name="reflex.Model",
reason="",
deprecation_version="0.9.2",
removal_version="1.0.0",
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Empty reason leaves deprecation message unhelpful

reason="" produces a deprecation notice with a blank explanation, giving users no guidance on what to migrate to (e.g., sqla_session, ModelRegistry, get_engine). The reason field should describe the replacement or link to docs.

Comment thread reflex/model.py
Comment on lines +469 to +473
def migrate(autogenerate: bool = False) -> bool | None:
"""Execute alembic migrations for all sqlmodel Model classes.

If alembic is not installed or has not been initialized for the project,
then no action is performed.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Stale docstring still references sqlmodel

The standalone migrate() function says "Execute alembic migrations for all sqlmodel Model classes," but this function now operates independently of sqlmodel. The docstring should be updated to reflect that it works with any registered SQLAlchemy/SQLModel models.

Comment on lines +260 to 261
# assert migrate(autogenerate=True) #noqa: ERA001
# assert len(list(versions.glob("*.py"))) == 4 #noqa: ERA001
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Commented-out test assertions should be removed

Per project convention, commented-out code should be removed before merging. These two lines (the no-op autogenerate check) have been commented out and updated in this PR — if they're intentionally skipped, they should either be deleted or replaced with a pytest.mark.skip/xfail with a comment explaining why.

Rule Used: Remove commented-out code before merging PRs. (source)

Learned From
reflex-dev/reflex-web#1619

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant