Repository navigation
feat: move workspace to platform cache directory (#12) - #29
Conversation
The per-document workspace previously lived in a .docx/<stem>/ folder next to the source file, cluttering user directories and risking collisions between same-named documents. It now lives under the platform user cache, in docx-editor/<hash>/ where <hash> is sha256 of the document's absolute path: Linux $XDG_CACHE_HOME/docx-editor (fallback ~/.cache/docx-editor) macOS ~/Library/Caches/docx-editor Windows %LOCALAPPDATA%\docx-editor (fallback ~/AppData/Local) The base directory can be overridden, in precedence order, by the workspace_dir argument to Document.open()/Workspace(), the DOCX_EDITOR_WORKSPACE_DIR environment variable, or the platform default. A relative override resolves against the source document's directory, so workspace_dir=".docx" reproduces the old next-to-file layout for debugging. Path resolution is centralized in Workspace._resolve_workspace_path(), replacing the duplicated logic in __init__, exists(), and delete(). Base directory cleanup suppresses OSError, since the base is now shared across documents and processes. No auto-migration: workspaces created by older versions are not found, and leftover .docx/ folders can be deleted.
|
Warning Review limit reached
Next review available in: 54 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthrough
ChangesWorkspace location and API integration
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant Document.open
participant Workspace
participant Filesystem
Caller->>Document.open: provide document path and workspace_dir
Document.open->>Workspace: resolve workspace and handle force_recreate
Workspace->>Filesystem: create or delete hashed workspace
Workspace-->>Document.open: workspace state
Document.open-->>Caller: opened Document
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #29 +/- ##
=======================================
- Coverage 94.6% 94.5% -0.1%
=======================================
Files 10 10
Lines 2526 2568 +42
Branches 565 572 +7
=======================================
+ Hits 2391 2429 +38
- Misses 36 41 +5
+ Partials 99 98 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Follow-up to the cache migration, from a multi-reviewer pass. Crash: the workspace dir was keyed by sha256(str(path).encode()), but str(Path) carries undecodable filename bytes as surrogates, which strict UTF-8 rejects. Opening e.g. "café.docx" (latin-1 on disk) raised UnicodeEncodeError. Hash via os.fsencode(os.path.normcase(path)) instead; this is byte-identical for all decodable paths, so no workspace moves. normcase also folds case on Windows, where one file could otherwise map to two workspaces. Data loss: close()/delete() removed the base directory when it was left empty. That was safe when the base was the library's own .docx/ folder, but the base is now the shared cache root -- or whatever directory the caller passed via workspace_dir=/DOCX_EDITOR_WORKSPACE_DIR. The library was deleting a directory it did not create. It now removes only the document's own workspace folder. Two tests asserted the old behavior and are rewritten. Path resolution: overrides are now tilde-expanded (DOCX_EDITOR_WORKSPACE_DIR =~/ws created a literal "~" directory next to each document), an empty or whitespace override counts as unset and falls through to the next precedence level (workspace_dir="" silently rebased onto the document's own directory), and a relative XDG_CACHE_HOME/%LOCALAPPDATA% is ignored per the XDG spec rather than scattering caches beside every document. Permissions: the workspace holds the document's plaintext in a shared, predictably-named cache, so it and its base are created 0o700 instead of inheriting a 0o775 umask default. mkdir(parents=True, mode=) applies the mode to the leaf only, so the base is created explicitly. Provenance: a workspace whose meta.json names a different source document is now refused instead of silently adopted -- adopting it would let a later save() pack that other document's XML over this one's source file. Errors: filesystem failures at the new cache boundary (unwritable base, no resolvable home) surfaced as raw PermissionError/RuntimeError out of Document.open(). They are now WorkspaceError, naming the override to set. Also: add a public Document.workspace_path -- the docs told users to inspect the preserved workspace but gave them no way to locate it now that it is an opaque hash under the cache. Drop the write-only self.workspace_dir, hoist the function-local shutil import, and correct the "unsaved edits in the workspace" wording (edits reach the workspace only on save()).
Found by a second adversarial pass over the previous commit. The permissions test guarded itself with skipif(os.getuid() == 0). A skipif condition is evaluated at collection time on every platform, and os.getuid does not exist on Windows, so the whole test module would die on import there -- taking with it the two tests that exist specifically to cover the Windows cache dir. Guard on os.name first; `or` short-circuits before os.geteuid. The provenance check compared the raw source path while the workspace key is normcase-folded. On a case-insensitive filesystem two spellings map to one workspace directory, which the check would then reject as "a different document" -- and the message tells the user to pass force_recreate=True, which would rmtree the workspace. Fold both sides the same way. Stripping the override with str(override).strip() also stripped Path inputs, silently redirecting a path that legitimately ends in whitespace to a different directory. Strip str overrides (where stray whitespace is config noise) and take a Path verbatim. Also document the WorkspaceError exits that the hardening added to Document.open(), and drop the literal ~ from the workspace_path example -- the value is always expanded.
Summary
The per-document workspace previously lived in a
.docx/<stem>/folder next to the source file, cluttering user directories and risking collisions between same-named documents.It now lives under the platform user cache, in
docx-editor/<hash>/where<hash>is the sha256 of the document's absolute path:$XDG_CACHE_HOME/docx-editor(falls back to~/.cache/docx-editor)~/Library/Caches/docx-editor%LOCALAPPDATA%\docx-editor(falls back to~\AppData\Local\docx-editor)Overrides
The base directory can be overridden, in precedence order:
workspace_dirargument toDocument.open()/Workspace()DOCX_EDITOR_WORKSPACE_DIRenvironment variableA relative override resolves against the source document's directory, so
workspace_dir=".docx"reproduces the old next-to-file layout for debugging. An absolute override is used as-is.Implementation notes
Workspace._resolve_workspace_path(), replacing the duplicatedparent / WORKSPACE_DIR / stemlogic in__init__,exists(), anddelete(). TheWORKSPACE_DIRconstant is gone.OSError: the base is shared across documents and processes, so the check-then-rmdir can race. It only ever removes a verified-empty directory.WorkspaceSyncErrormessages include the workspace path, which matters more now that the workspace isn't next to the file.Breaking change
No auto-migration. Workspaces created by older versions are no longer found, and any unsaved edits still in them are ignored. Leftover
.docx/folders can be deleted, or passworkspace_dir=".docx"to keep using the old layout.Testing
ruff checkandruff format --check: cleanTestDefaultCacheDir(platform matrix) andTestWorkspaceLocation(default cache / env var / param override / relative override / distinct-source isolation / sync-error message) coverageDOCX_EDITOR_WORKSPACE_DIRat a throwaway temp dir, so tests never touch the real user cacheCloses #12
Summary by CodeRabbit
New Features
Bug Fixes
Documentation