layout.path() treated every argument as a filename, so asking it for a
directory - layout.path('final'), which the rendering scripts do - built
a path to a file called 'final' INSIDE final/ and created an empty
final/final along the way. Directory names now resolve to the directory
itself.
Three scripts also held path literals split across two lines with
implicit string concatenation, where the rewrite had replaced only the
first fragment and left a dangling continuation. verify_core.py,
mo_gccheck.py and mo_mpc.py are corrected; all 52 files now compile
without warnings.
subdir_readmes.py writes a short README into each session subdirectory
saying what it holds, where it came from, and whether it is safe to
delete. Those three facts are what someone opening a folder cold needs,
and they belong with the data rather than in this repo.
Re-verified after the fix: closeup.py and triptych.py run end to end
against the reorganised session and leave no stray directories behind.
115 lines
4.2 KiB
Python
115 lines
4.2 KiB
Python
"""Where every file of a processed session lives.
|
|
|
|
The scripts used to sit inside the data directory and address it with absolute
|
|
paths. Now that they live in a repository and the data is organised into named
|
|
subdirectories, they need one place that knows the mapping - this module.
|
|
|
|
Two rules make it work:
|
|
|
|
* The session root comes from the ASTRO_SESSION environment variable, so the
|
|
same code runs against any session without editing. It falls back to the
|
|
NGC 5128 session these scripts were written against.
|
|
* A file's subdirectory is derived from its NAME, using the same rules the
|
|
directory was organised with. That means a script can go on asking for
|
|
"master-Red.fit" or "_stars.npz" and get the right path, without every call
|
|
site having to learn the layout.
|
|
|
|
Anything unrecognised lands at the session root, which is visible and easy to
|
|
correct rather than silently wrong.
|
|
"""
|
|
import os
|
|
|
|
SESSION = os.environ.get(
|
|
"ASTRO_SESSION",
|
|
r"C:\Users\lhorrocks-barlow\Downloads\NGC5128\20260721")
|
|
|
|
# Subdirectories, also created on demand by path().
|
|
RAW = "raw"
|
|
CALIBRATED = "calibrated"
|
|
MASTERS = os.path.join("stacks", "masters")
|
|
ORIGINAL = os.path.join("stacks", "original")
|
|
FINAL = "final"
|
|
RENDERINGS = "renderings"
|
|
FIGURES = os.path.join("science", "figures")
|
|
CATALOGUES = os.path.join("science", "catalogues")
|
|
SCIENCE_DATA = os.path.join("science", "data")
|
|
NOTES = os.path.join("science", "notes")
|
|
INTERMEDIATES = "intermediates"
|
|
|
|
# Names that are directories in their own right, not files.
|
|
_DIRS = {"final": FINAL, "original": ORIGINAL, "raw": RAW,
|
|
"calibrated": CALIBRATED, "renderings": RENDERINGS,
|
|
"_dss": os.path.join(INTERMEDIATES, "_dss")}
|
|
|
|
|
|
def subdir(name):
|
|
"""The subdirectory a given filename belongs in."""
|
|
low = name.lower()
|
|
if name in _DIRS:
|
|
return _DIRS[name]
|
|
if name.startswith("_"):
|
|
return INTERMEDIATES
|
|
if low.endswith(".zip") or (low.startswith("jpeg-") and
|
|
low.endswith(".jpg")):
|
|
return RAW
|
|
if low.startswith("calibrated-") and low.endswith((".fit", ".tif")):
|
|
return CALIBRATED
|
|
if low.startswith("raw-") and low.endswith((".fit", ".tif")):
|
|
return RAW
|
|
if low.startswith("master-") and low.endswith(".fit"):
|
|
return MASTERS
|
|
if low.startswith("original-"):
|
|
return ORIGINAL
|
|
if "final" in low and low.endswith((".png", ".tif", ".jpg")):
|
|
return FINAL
|
|
if low.startswith("notes-") and low.endswith(".md"):
|
|
return NOTES
|
|
if low.endswith(".csv"):
|
|
return CATALOGUES
|
|
if low.startswith("sb-") and low.endswith((".fits", ".npy", ".txt")):
|
|
return SCIENCE_DATA
|
|
if low.endswith(".png") and any(f"-{p}-" in low for p in ("gc", "sb", "mo")):
|
|
return FIGURES
|
|
if low.startswith(("ngc5128-lrgb", "ngc5128-img-")):
|
|
return RENDERINGS
|
|
if low.endswith(".md"):
|
|
return ""
|
|
return ""
|
|
|
|
|
|
def path(*parts, make=True):
|
|
"""Absolute path for a session file, addressed by name alone.
|
|
|
|
Extra leading components are accepted and ignored, so calls written
|
|
against the old flat layout - path("stacked", "_stars.npz") - still land
|
|
correctly. The last component is the one that decides.
|
|
"""
|
|
name = parts[-1]
|
|
if name in _DIRS:
|
|
# Asking for a directory by name returns the directory itself, not a
|
|
# file of that name nested inside it.
|
|
full = os.path.join(SESSION, _DIRS[name])
|
|
if make:
|
|
os.makedirs(full, exist_ok=True)
|
|
return full
|
|
full = os.path.join(SESSION, subdir(name), name)
|
|
if make:
|
|
os.makedirs(os.path.dirname(full), exist_ok=True)
|
|
return full
|
|
|
|
|
|
def describe():
|
|
lines = [f"session root: {SESSION}"]
|
|
for label, d in (("raw", RAW), ("calibrated", CALIBRATED),
|
|
("masters", MASTERS), ("original stacks", ORIGINAL),
|
|
("final images", FINAL), ("other renderings", RENDERINGS),
|
|
("science figures", FIGURES),
|
|
("science catalogues", CATALOGUES),
|
|
("science data", SCIENCE_DATA), ("notes", NOTES),
|
|
("intermediates", INTERMEDIATES)):
|
|
lines.append(f" {label:20s} {d}")
|
|
return "\n".join(lines)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print(describe())
|