refactor(routes): move gallery domain into routes/gallery subpackage (#4903)

Move the gallery route domain into routes/gallery/ while preserving backward-compatible legacy import shims.

- app imports the canonical gallery route module
- canonical gallery route code imports canonical gallery helpers
- legacy gallery route/helper paths remain compatibility aliases
- add shim regression coverage for module identity and monkeypatch behavior
- repoint gallery source-introspection tests to the canonical paths

No intended behavior change.
This commit is contained in:
Tal.Yuan
2026-06-28 17:40:34 +08:00
committed by GitHub
parent 5b8bfdabab
commit 8066a8e0cd
17 changed files with 2165 additions and 2077 deletions
+1 -1
View File
@@ -40,7 +40,7 @@ def test_direct_upload_routes_use_bounded_reads():
"routes/stt_routes.py": [
"read_upload_limited(file, STT_MAX_AUDIO_BYTES",
],
"routes/gallery_routes.py": [
"routes/gallery/gallery_routes.py": [
"read_upload_limited(file, GALLERY_UPLOAD_MAX_BYTES",
"read_upload_limited(file, GALLERY_TRANSFORM_UPLOAD_MAX_BYTES",
],
+1 -1
View File
@@ -377,7 +377,7 @@ def test_compare_endpoint_key_lookup_is_owner_scoped():
def test_gallery_image_endpoint_lookups_are_owner_scoped():
body = Path("routes/gallery_routes.py").read_text(encoding="utf-8")
body = Path("routes/gallery/gallery_routes.py").read_text(encoding="utf-8")
helper_body = body.split("def _visible_image_endpoint_query", 1)[1].split(
"def _first_visible_image_endpoint", 1
)[0]
+1 -1
View File
@@ -12,7 +12,7 @@ from pathlib import Path
def _function_sources():
source = Path("routes/gallery_routes.py").read_text(encoding="utf-8")
source = Path("routes/gallery/gallery_routes.py").read_text(encoding="utf-8")
tree = ast.parse(source)
return {
node.name: ast.get_source_segment(source, node) or ""
+1 -1
View File
@@ -15,7 +15,7 @@ metadata range.
import ast
from pathlib import Path
SRC = Path(__file__).resolve().parent.parent / "routes" / "gallery_routes.py"
SRC = Path(__file__).resolve().parent.parent / "routes" / "gallery" / "gallery_routes.py"
def _function_source(src_text: str, func_name: str) -> str:
+2 -2
View File
@@ -32,8 +32,8 @@ def extract_exif(monkeypatch):
return MagicMock()
monkeypatch.setitem(sys.modules, "core.database", _DBStub("core.database"))
monkeypatch.delitem(sys.modules, "routes.gallery_helpers", raising=False)
mod = importlib.import_module("routes.gallery_helpers")
monkeypatch.delitem(sys.modules, "routes.gallery.gallery_helpers", raising=False)
mod = importlib.import_module("routes.gallery.gallery_helpers")
return mod._extract_exif
+1 -1
View File
@@ -128,7 +128,7 @@ def test_gallery_replace_rejects_symlink_escape(tmp_path, monkeypatch):
def test_gallery_file_operations_use_confining_resolver():
source = Path("routes/gallery_routes.py").read_text(encoding="utf-8")
source = Path("routes/gallery/gallery_routes.py").read_text(encoding="utf-8")
assert 'Path("data/generated_images") / img.filename' not in source
assert 'os.path.join("data", "generated_images", img.filename)' not in source
+1 -1
View File
@@ -15,7 +15,7 @@ GATED_IMAGE_FUNCTIONS = {
def _gallery_source():
return Path("routes/gallery_routes.py").read_text(encoding="utf-8")
return Path("routes/gallery/gallery_routes.py").read_text(encoding="utf-8")
def _function_sources(source):
+52
View File
@@ -0,0 +1,52 @@
"""Regression test for the gallery route shim (slice 2a, #4082/#4071).
The backward-compat shims at ``routes/gallery_routes.py`` and
``routes/gallery_helpers.py`` use ``sys.modules`` replacement so the legacy
import path and the canonical ``routes.gallery.*`` path resolve to the *same*
module object. This test pins that contract: if the shim is ever changed to a
plain ``from ... import *`` (or removed), these assertions catch it before the
monkeypatch-based gallery tests silently start patching the wrong module.
"""
import importlib
import routes.gallery_routes as _shim_routes # noqa: F401
import routes.gallery_helpers as _shim_helpers # noqa: F401
def test_legacy_and_canonical_route_module_are_same_object():
"""``import routes.gallery_routes`` must alias the canonical module."""
legacy = importlib.import_module("routes.gallery_routes")
canonical = importlib.import_module("routes.gallery.gallery_routes")
assert legacy is canonical, (
"routes.gallery_routes shim must resolve to the canonical "
"routes.gallery.gallery_routes module object"
)
def test_legacy_and_canonical_helpers_module_are_same_object():
"""``import routes.gallery_helpers`` must alias the canonical module."""
legacy = importlib.import_module("routes.gallery_helpers")
canonical = importlib.import_module("routes.gallery.gallery_helpers")
assert legacy is canonical, (
"routes.gallery_helpers shim must resolve to the canonical "
"routes.gallery.gallery_helpers module object"
)
def test_monkeypatch_via_legacy_path_affects_canonical(monkeypatch):
"""Patching through the legacy path must reach the canonical module.
Several gallery tests do ``import routes.gallery_routes as gr`` followed by
``monkeypatch.setattr(gr, "get_current_user", ...)``. For that to take
effect at runtime, the legacy module object and the canonical one must be
identical.
"""
legacy = importlib.import_module("routes.gallery_routes")
canonical = importlib.import_module("routes.gallery.gallery_routes")
sentinel = object()
monkeypatch.setattr(legacy, "setup_gallery_routes", sentinel)
assert canonical.setup_gallery_routes is sentinel, (
"monkeypatch via legacy path did not reach the canonical module"
)
+3 -3
View File
@@ -1099,9 +1099,9 @@ def _import_session_routes_for_filename():
def _import_gallery_routes_for_filename():
# Same rationale as the session route helper: import _sanitize_gallery_filename
# against the real core.database and leave a clean, real module cached.
_drop_route_module_cache("routes.gallery_routes")
_drop_route_module_cache("routes.gallery_helpers")
return importlib.import_module("routes.gallery_routes")
_drop_route_module_cache("routes.gallery.gallery_routes")
_drop_route_module_cache("routes.gallery.gallery_helpers")
return importlib.import_module("routes.gallery.gallery_routes")
def test_export_filename_sanitizer_blocks_header_and_path_chars():
+2 -2
View File
@@ -80,7 +80,7 @@ def test_non_positive_env_rejected(monkeypatch, env):
def test_routes_import_from_upload_limits_not_local_defs():
"""Routes must import the constant, not redefine it via raw getenv / literal."""
forbidden = {
"routes/gallery_routes.py": [
"routes/gallery/gallery_routes.py": [
'int(os.getenv("ODYSSEUS_GALLERY_UPLOAD_MAX_BYTES"',
'int(os.getenv("ODYSSEUS_GALLERY_TRANSFORM_UPLOAD_MAX_BYTES"',
],
@@ -97,7 +97,7 @@ def test_routes_import_from_upload_limits_not_local_defs():
# And each imports from upload_limits.
imports = {
"routes/gallery_routes.py": "GALLERY_UPLOAD_MAX_BYTES",
"routes/gallery/gallery_routes.py": "GALLERY_UPLOAD_MAX_BYTES",
"routes/memory_routes.py": "MEMORY_IMPORT_MAX_BYTES",
"routes/personal_routes.py": "PERSONAL_UPLOAD_MAX_BYTES",
"routes/email_routes.py": "EMAIL_COMPOSE_UPLOAD_MAX_BYTES",
+1 -1
View File
@@ -89,7 +89,7 @@ def test_request_vision_call_sites_pass_owner():
processor_source = (ROOT / "src" / "document_processor.py").read_text()
upload_source = (ROOT / "routes" / "upload_routes.py").read_text()
document_source = (ROOT / "routes" / "document_routes.py").read_text()
gallery_source = (ROOT / "routes" / "gallery_routes.py").read_text()
gallery_source = (ROOT / "routes" / "gallery" / "gallery_routes.py").read_text()
memory_source = (ROOT / "routes" / "memory_routes.py").read_text()
assert 'analyze_image_with_vl_result(file_info["path"], owner=owner)' in chat_source