Skip to content

fix(generate): read WORKSPACE_DIR dynamically so relocated output isn't lost - #287

Open
kevin9327 wants to merge 1 commit into
lightningpixel:devfrom
kevin9327:fix/generation-dynamic-workspace-dir
Open

fix(generate): read WORKSPACE_DIR dynamically so relocated output isn't lost#287
kevin9327 wants to merge 1 commit into
lightningpixel:devfrom
kevin9327:fix/generation-dynamic-workspace-dir

Conversation

@kevin9327

Copy link
Copy Markdown
Contributor

What

After the workspace is relocated at runtime (POST /settings/paths), 3D generations kept writing their output into the previous workspace directory, while /workspace/{path} served files from the new one — so the finished mesh 404s and never appears in the app.

Why it triggers

api/routers/generation.py bound the workspace path with from services.generator_registry import WORKSPACE_DIR, capturing the Path at import time. POST /settings/pathsgenerator_registry.update_paths() rebinds the WORKSPACE_DIR module global (and repoints every loaded generator's outputs_dir):

# services/generator_registry.py
_self_module.WORKSPACE_DIR = workspace_dir
for gen in self._generators.values():
    gen.outputs_dir = workspace_dir

Because _run_generation used the stale imported name, it recomputed coll_dir = WORKSPACE_DIR / collection against the old directory and set gen.outputs_dir back to it — overriding the value update_paths had just written — then built output_url relative to the same stale path. /workspace/... reads the current WORKSPACE_DIR dynamically, so it can't find the file.

This affects both /generate/from-image and /workflow-runs/from-image (both funnel through _run_generation).

Fix

Reference the module attribute registry.WORKSPACE_DIR at call time instead of a name captured at import — the same way optimize.ply_to_splat (comment: "workspace dir may change at runtime") and the settings router already read it.

Verification

  • Added api/tests/test_generation_router.py: drives _run_generation with a fake generator after relocating the workspace, and asserts the output is filed under the current workspace (and that output_url matches). Fails before, passes after.
  • python -m unittest discover -s tests in api/ (venv with fastapi + python-multipart + httpx): all pass, 0 failures.

@lightningpixel

Copy link
Copy Markdown
Owner

Code review

Found 1 issue:

  1. Merging as-is will break /generate/from-image with a NameError on every request. The PR's branch was cut before sanitize_collection() was added to dev; that function still references the bare name WORKSPACE_DIR, which this PR removes from the module's import (from services.generator_registry import generator_registry, WORKSPACE_DIRimport services.generator_registry as registry / from services.generator_registry import generator_registry). sanitize_collection is called unconditionally at the top of generate_from_image, so the endpoint would raise NameError: name 'WORKSPACE_DIR' is not defined on line 73 for every call. The PR's own new test only exercises _run_generation directly and doesn't go through sanitize_collection, so it doesn't catch this.

try:
(WORKSPACE_DIR / collection).resolve().relative_to(WORKSPACE_DIR.resolve())
except (OSError, ValueError):
(current dev, showing the bare WORKSPACE_DIR usage inside sanitize_collection that this PR's import change would orphan)

collection = sanitize_collection(collection)
(current dev, showing sanitize_collection is called unconditionally on every request)

Fix: rebase onto current dev and update sanitize_collection's two WORKSPACE_DIR references (and its docstring) to registry.WORKSPACE_DIR, consistent with this PR's own stated rule in the import comment.

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

…'t lost

`_run_generation` imported `WORKSPACE_DIR` by name, so it kept the value bound
at import time. `POST /settings/paths` rebinds the registry's global when the
user relocates the workspace, so every generation after that was written under
the old directory and its `/workspace/...` URL 404'd in the app.

Import the module instead and read `registry.WORKSPACE_DIR` at call time.
`sanitize_collection()` (added to dev after this branch was cut) checks the
collection's containment against the same root before the job is filed, so it
reads the live binding the same way; a test now drives `generate_from_image`
through it after a relocation, which is where a stale or missing module-level
name surfaces as a NameError on every request.
@kevin9327
kevin9327 force-pushed the fix/generation-dynamic-workspace-dir branch from cd8230a to 4f47b21 Compare September 2, 2026 22:02
@kevin9327

Copy link
Copy Markdown
Contributor Author

Rebased onto current dev and addressed the review: sanitize_collection() now reads registry.WORKSPACE_DIR as well (its containment check runs at the top of generate_from_image), so no bare WORKSPACE_DIR remains in the module. Added GenerateFromImageWorkspaceTests, which drives generate_from_image itself after relocating the workspace -- on the rebased branch without the fix it fails with NameError: name 'WORKSPACE_DIR' is not defined, and passes with it.

Verification (venv with fastapi/python-multipart/httpx, run from api/): python -c "import routers.generation, routers.workflow_runs" OK; python -m unittest discover -s tests -> Ran 69 tests, OK (skipped=2).

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.

2 participants