Restore deprecated DECORATED_PAGES and get_config(reload=True) shims

Merged
MA
2mo ago
+145-2

All Submissions:

  • Have you followed the guidelines stated in CONTRIBUTING.md file?
  • Have you checked to ensure there aren't any other open Pull Requests for the desired changed?

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • This change requires a documentation update

Changes To Core Features:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you successfully ran tests with your changes locally?

Defect

0.9.9a1 pre-release testing surfaced two 0.9.8 public names that #6382 removed outright, with no shim and confusing errors (FINDING-023 HIGH, FINDING-008 MEDIUM), plus two under-documented behavior changes (FINDING-009, FINDING-003):

  • from reflex.page import DECORATED_PAGES now raises ImportError: cannot import name 'DECORATED_PAGES' from 'PageNamespace' (unknown location). This breaks the published reflex-enterprise flow demo at import (it builds its index page from DECORATED_PAGES), and the error text gives no pointer to the replacement API.
  • get_config(reload=True) now raises a bare TypeError: get_config() got an unexpected keyword argument 'reload' with no mention of reload_config().

Both worked on 0.9.8, and the repo's deprecation policy asks for a fallback path during deprecation.

Fix

  • reflex/page.py: since the PageNamespace class replaces the module in sys.modules, a plain module __getattr__ (PEP 562) would never be consulted; the shim lives in a new PageNamespaceMeta.__getattr__. Reading DECORATED_PAGES emits console.deprecate (deprecated 0.9.9, removed 1.0) and returns a defaultdict(list) mapping the app name to the active RegistrationContext's live decorated_pages list — the exact 0.9.8 shape (dict[str, list[tuple[Callable, dict]]]), so 0.9.8-era access patterns like next(iter(DECORATED_PAGES.values())) keep working. A TYPE_CHECKING-only declaration keeps the from-import resolvable for type checkers. Modeled on the bundled_libraries shims in #6967.
  • reflex_base/config.py: get_config regains its 0.9.8 reload: bool = False parameter; passing a truthy value emits console.deprecate (0.9.9 -> 1.0) and delegates to reload_config(). get_config() without arguments is unchanged.
  • News fragments for the two approved documentation decisions: news/6382.breaking.md documents that a second bare rx.App() in one process now raises ReflexRuntimeError (use a fresh RegistrationContext / fork() for multiple apps) and the DECORATED_PAGES move with its deprecation shim; news/6593.bugfix.1.md documents that supersedes-based on_load cancellation on navigation also cancels on_load handlers that are background tasks (0.9.8 let them survive), while background tasks started from non-superseding events are unaffected. Deprecation fragments added for both shims.

Test plan

Regression tests were written first and shown to fail on unfixed main with the exact errors from the findings:

  • tests/units/test_page.py::test_decorated_pages_shim_from_import — failed with ImportError: cannot import name 'DECORATED_PAGES' from 'PageNamespace' (unknown location); now passes and asserts the mapping resolves to the active context's decorated_pages and warns once.
  • tests/units/test_page.py::test_decorated_pages_shim_module_attribute — covers the reflex.page module-attribute form, the app-name key, and defaultdict behavior for unknown keys.
  • tests/units/test_page.py::test_page_namespace_unknown_attribute_raises — unknown attributes still raise AttributeError naming reflex.page.
  • tests/units/test_config.py::test_get_config_reload_deprecated — failed with TypeError: get_config() got an unexpected keyword argument 'reload'; now passes and asserts get_config(reload=True) delegates to reload_config(), warns, caches the fresh config, and that get_config() does not warn.

Checks run locally: uv run ruff check . and uv run ruff format . clean; uv run pyright reflex tests and uv run pyright packages/reflex-base/src/reflex_base/config.py 0 errors; uv run pytest tests/units/test_page.py tests/units/test_config.py tests/units/test_app.py tests/units/reflex_base/test_registry.py all pass (275 tests). Also manually verified both 0.9.8 import forms and the flow demo's exact access pattern end-to-end through the reflex namespace.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x


Generated by Claude Code