Annie Voigt commited on
Commit
9c88c1e
·
1 Parent(s): 25b085e

refactor: move writable-dir constants to core.paths, fix workflow->tools layer violation

Browse files

OUTPUT_DIR/INPUT_DIR/GEO_CACHE_DIR + _resolve_dir lived in src/tools/rna/_base.py,
so src/workflows/integration.py imported upward from the tools layer to reach
OUTPUT_DIR -- a dependency-direction violation (tools sits above workflows).

These are shared infrastructure (env-resolved writable dirs) both layers need, so
they belong in core. Move them to src/core/paths.py; _base.py re-exports them
(unchanged for tool submodules) and integration.py imports from core.paths. Path
resolution is byte-for-byte identical (same base dir <root>/src, same env-var/tmp
fallback). No functional change. repo-quality-monitor architecture check: 0 findings.

src/core/paths.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Writable directory resolution for the agent.
3
+
4
+ These are shared infrastructure constants — an env-resolved input/output/cache
5
+ location — needed by both the ``tools`` layer (which writes analysis artifacts)
6
+ and the ``workflows`` layer (which writes combined datasets). They live in
7
+ ``core`` so both layers can import them downward without violating the layering
8
+ contract (``tools`` and ``workflows`` both build on ``core``).
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import os
14
+ from pathlib import Path
15
+
16
+ # core/paths.py lives at <root>/src/core/, so two levels up is <root>/src —
17
+ # the same base directory the tool package historically resolved against.
18
+ PROJECT_ROOT = Path(__file__).parent.parent.resolve()
19
+ _DEFAULT_INPUT = PROJECT_ROOT / "tmp" / "inputs"
20
+ _DEFAULT_OUTPUT = PROJECT_ROOT / "tmp" / "outputs"
21
+ _DEFAULT_GEO_CACHE = PROJECT_ROOT / "tmp" / "geo_cache"
22
+
23
+
24
+ def _resolve_dir(env_var: str, project_default: Path, hf_fallback: Path) -> Path:
25
+ """Return a writable directory: env var > project default > /tmp fallback."""
26
+ env_val = os.environ.get(env_var)
27
+ if env_val:
28
+ p = Path(env_val)
29
+ p.mkdir(parents=True, exist_ok=True)
30
+ return p
31
+ try:
32
+ project_default.mkdir(parents=True, exist_ok=True)
33
+ return project_default
34
+ except PermissionError:
35
+ hf_fallback.mkdir(parents=True, exist_ok=True)
36
+ return hf_fallback
37
+
38
+
39
+ INPUT_DIR = _resolve_dir("RNA_INPUT_DIR", _DEFAULT_INPUT, Path("/tmp/decoupleRpy/inputs"))
40
+ OUTPUT_DIR = _resolve_dir("RNA_OUTPUT_DIR", _DEFAULT_OUTPUT, Path("/tmp/decoupleRpy/outputs"))
41
+ GEO_CACHE_DIR = _resolve_dir(
42
+ "RNA_GEO_CACHE_DIR", _DEFAULT_GEO_CACHE, Path("/tmp/decoupleRpy/geo_cache")
43
+ )
src/tools/rna/_base.py CHANGED
@@ -28,32 +28,14 @@ from pydeseq2.ds import DeseqStats
28
  matplotlib.use("Agg")
29
  import matplotlib.pyplot as plt
30
 
31
- # Project structure
32
- PROJECT_ROOT = Path(__file__).parent.parent.parent.resolve()
33
- _DEFAULT_INPUT = PROJECT_ROOT / "tmp" / "inputs"
34
- _DEFAULT_OUTPUT = PROJECT_ROOT / "tmp" / "outputs"
35
- _DEFAULT_GEO_CACHE = PROJECT_ROOT / "tmp" / "geo_cache"
36
-
37
-
38
- def _resolve_dir(env_var: str, project_default: Path, hf_fallback: Path) -> Path:
39
- """Return a writable directory: env var > project default > /tmp fallback."""
40
- env_val = os.environ.get(env_var)
41
- if env_val:
42
- p = Path(env_val)
43
- p.mkdir(parents=True, exist_ok=True)
44
- return p
45
- try:
46
- project_default.mkdir(parents=True, exist_ok=True)
47
- return project_default
48
- except PermissionError:
49
- hf_fallback.mkdir(parents=True, exist_ok=True)
50
- return hf_fallback
51
-
52
-
53
- INPUT_DIR = _resolve_dir("RNA_INPUT_DIR", _DEFAULT_INPUT, Path("/tmp/decoupleRpy/inputs"))
54
- OUTPUT_DIR = _resolve_dir("RNA_OUTPUT_DIR", _DEFAULT_OUTPUT, Path("/tmp/decoupleRpy/outputs"))
55
- GEO_CACHE_DIR = _resolve_dir(
56
- "RNA_GEO_CACHE_DIR", _DEFAULT_GEO_CACHE, Path("/tmp/decoupleRpy/geo_cache")
57
  )
58
 
59
  # Timestamp for unique outputs
 
28
  matplotlib.use("Agg")
29
  import matplotlib.pyplot as plt
30
 
31
+ # Project structure. Writable directories now live in core.paths (shared
32
+ # infrastructure both tools and workflows build on); re-exported here so tool
33
+ # submodules keep importing them from _base unchanged.
34
+ from src.core.paths import ( # noqa: E402
35
+ GEO_CACHE_DIR,
36
+ INPUT_DIR,
37
+ OUTPUT_DIR,
38
+ PROJECT_ROOT,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  )
40
 
41
  # Timestamp for unique outputs
src/workflows/integration.py CHANGED
@@ -38,7 +38,7 @@ from typing import TYPE_CHECKING
38
  import anndata as ad
39
  import numpy as np
40
 
41
- from src.tools.rna._base import OUTPUT_DIR
42
 
43
  if TYPE_CHECKING:
44
  from anndata import AnnData
 
38
  import anndata as ad
39
  import numpy as np
40
 
41
+ from src.core.paths import OUTPUT_DIR
42
 
43
  if TYPE_CHECKING:
44
  from anndata import AnnData