Machine-settings layer + canonical user data dir - #135
Merged
Conversation
Introduce a machine-local settings overlay applied to every run type, and
move persisted machine-specific data to a canonical user data dir, so
c64cast works identically from a repo checkout, a pip install, or a PyPI
wheel (no more Path(__file__).parent.parent repo-anchoring).
New c64cast/paths.py (stdlib-only, no intra-package imports) is the single
source of truth for locations:
- settings_path(): ~/.config/c64cast/settings.toml (XDG-aware;
%APPDATA% on Windows; $C64CAST_SETTINGS overrides)
- data_root()/calibration_dir()/presets_dir()/loop_presets_dir():
~/.local/share/c64cast (XDG; %LOCALAPPDATA%; $C64CAST_DATA_DIR)
- legacy_data_root(): old repo anchor, only for doctor's mv hints
Machine settings (config.py): load_machine_settings/apply_machine_settings
overlay the file as the lowest layer above dataclass defaults, hooked into
load, load_master (ensemble master defaults + a machine-overlaid cascade
baseline so master TOML still beats machine settings), and
quickcast.build_config. Precedence: defaults -> machine settings ->
project/per-system TOML -> master cascade -> CLI -> env. [[scenes]] and
[ensemble] in the file are rejected. The per-section apply loop is factored
into _apply_toml_sections so the machine file and project file share code.
--save-settings (cli.py): a config-free command that persists this run's
-u/--url, -d/--device, --sid-model, -s/--system into the settings file
(sparse + atomic write, merges with existing, prints, exits 0; nothing
savable -> exit 2). $C64CAST_URL never auto-saves; the DMA password is never
written.
Data-dir consolidation: dac_calibration, transport, and wled_device now
resolve their paths through paths.* at use time; save_calibration uses the
shared atomic writer.
doctor: new _probe_machine_settings + _probe_data_dirs in the ENVIRONMENT
section report the resolved settings + data locations and, from a source
checkout, the exact mv to migrate legacy calibration/preset files.
Tests: new test_paths + test_save_settings; machine-settings precedence
coverage in config/ensemble/quickcast; the previously-missing
C64CAST_DMA_PASSWORD env test; dir-redirect tests switch from the removed
module globals to $C64CAST_DATA_DIR. A shared MachineSettingsIsolation test
helper keeps the load/round-trip suites hermetic against a real settings
file on the dev machine.
Docs (CLAUDE.md, docs/architecture.md, docs/usage.md) + the calibration/
and presets/ READMEs updated. No config-schema change.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #135 +/- ##
==========================================
+ Coverage 80.37% 80.56% +0.19%
==========================================
Files 86 87 +1
Lines 19700 19843 +143
Branches 2947 2969 +22
==========================================
+ Hits 15834 15987 +153
+ Misses 3187 3163 -24
- Partials 679 693 +14 ☔ View full report in Codecov by Harness. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a machine-local settings overlay applied to every run type, and moves persisted machine-specific data (DAC calibrations, WLED + loop presets) to a canonical user data dir — so c64cast works identically from a repo checkout, a
pip install, or a future PyPI wheel. This retires the fourPath(__file__).resolve().parent.parentrepo-anchored globals, which were a latent bug for any non-editable install.New
c64cast/paths.py(stdlib-only, no intra-package imports)Single source of truth for locations, resolved at use time so env overrides + tests work:
settings_path()→~/.config/c64cast/settings.toml(XDG-aware;%APPDATA%\c64cast\on Windows;$C64CAST_SETTINGSoverrides)data_root()/calibration_dir()/presets_dir()/loop_presets_dir()→~/.local/share/c64cast(XDG;%LOCALAPPDATA%;$C64CAST_DATA_DIRoverrides)legacy_data_root()→ the old repo anchor, only for doctor'smvhintsMachine settings (
config.py)load_machine_settings/apply_machine_settingsoverlay the file as the lowest layer above dataclass defaults, hooked intoload,load_master(the ensemble master-defaultsConfiggets the overlay first, andapply_master_defaultstakes a machine-overlaid baseline so master TOML still beats machine settings), andquickcast.build_config. Precedence:defaults → machine settings → project/per-system TOML → master cascade → CLI → env[[scenes]]/[ensemble]in the file are rejected (it holds cross-run defaults, not playlists). The per-section apply loop is factored into_apply_toml_sectionsso the machine file and project file share identical code (unknown-key warnings, validations, the[color]special case).--save-settings(cli.py)A config-free command that persists this invocation's machine-relevant flags —
-u/--url(decomposed viaconnect.parse_connection_uri),-d/--device,--sid-model,-s/--system— into the settings file: merges with any existing file, writes it sparsely + atomically, prints it, exits 0. Nothing savable → exit 2.$C64CAST_URLnever auto-saves; the DMA password can never be written.Data-dir consolidation
dac_calibration,transport, andwled_devicenow resolve their paths throughpaths.*;save_calibrationuses the shared atomic writer.Doctor
_probe_machine_settings+_probe_data_dirsin the ENVIRONMENT section report the resolved settings + data locations and — from a source checkout with old files still at the legacycalibration//presets/dirs — the exactmvto migrate them. No implicit migration.Tests
New
test_paths+test_save_settings; machine-settings precedence coverage acrossconfig/ensemble/quickcast; the previously-missingC64CAST_DMA_PASSWORDenv-precedence test; dir-redirect tests switched from the removed module globals to$C64CAST_DATA_DIR. A sharedMachineSettingsIsolationhelper keeps the load/round-trip suites hermetic against a real settings file on the developer's machine.No config-schema change (
make schemais a no-op).Verification
ruff,mypy --strict(config.py included),pyright, 2601 tests, schema-drift.--save-settingswrites a sparse/annotated/secret-free file and merges;--doctorENVIRONMENT shows settings + data dir + legacymvhints; quick playback inherits the settings connection with no-u.-u(connection sourced from the settings file).