You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: Make Delete Operator Strict, Improve Error Messages, Remove Color Formatting, and Make Local Raw References Lazy (#5)
* Remove idempotent terminology and make delete operator error on missing keys
* Refactor location tracking terminology and enhance merge context
Rename SourceLocation -> Location and MetadataRegistry -> LocationRegistry
to better reflect their purpose. Introduce MergeContext dataclass to
consolidate location tracking during config merging, enabling better error
messages with source locations for delete operator failures.
Key changes:
- Rename src/sparkwheel/metadata.py -> src/sparkwheel/locations.py
- Update all references to SourceLocation to use Location
- Update all references to MetadataRegistry to use LocationRegistry
- Add MergeContext class for threading location info through merge operations
- Enhance delete operator error messages with source location context
- Track locations for individual keys during YAML loading
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* Drop formatters
* Improve error message in instantiationerror
* Add more operator tests
* Improve errors with locations and better messages
* Improve error messages and add comprehensive test coverage for preprocessor
## Error Message Improvements
### Enhanced delete operator error messages (config.py)
- Show relevant available keys based on context (top-level vs nested)
- For nested keys like `model::missing`, display parent container's keys
- Use `parent_key` parameter for better error formatting
- Extract child key name for clearer nested error messages
### Enhanced raw reference error messages (preprocessor.py)
- Add source file location tracking for all raw reference errors
- Show specific missing key instead of full path (e.g., "Key 'data' not found" vs "Key 'data' not found at path 'data'")
- Display available keys at point of failure (up to 10 keys)
- Consistent error formatting for dict keys, list indices, and type errors
- Use custom exceptions (ConfigKeyError, CircularReferenceError) for proper newline formatting
- Thread LocationRegistry through external file loads for complete error context
## Test Coverage
### Preprocessor tests (test_preprocessor.py)
- Added 14 new tests covering:
- Missing keys (first level and nested)
- Invalid list indices (first level and nested)
- Type errors with proper context
- Raw reference errors with location tracking
- External file references (success and failure)
- Circular reference detection with locations
- Available keys truncation
- Raw reference expansion scenarios
- Total: 19 tests, all passing
### Config tests (test_config.py)
- test_delete_nonexistent_top_level_key_shows_available_keys
- test_delete_nonexistent_nested_key_shows_parent_keys
- test_delete_nested_key_when_parent_doesnt_exist
- test_update_from_file_with_nested_paths_merges_locations
### Operator tests (test_operators.py)
- Fixed contradictory comments in test_validate_skips_dict_under_remove
## Type Safety
### Type annotations (preprocessor.py)
- Added TYPE_CHECKING import block to avoid circular imports
- Properly typed `locations` parameter as `Optional["LocationRegistry"]` in:
- process_raw_refs()
- _process_raw_refs_recursive()
- _expand_raw_ref()
- Removed all `# type: ignore` comments
## Documentation
### Updated operators.md
- Removed misleading "idempotent delete" section
- Clarified delete operator is strict (raises on missing keys)
- Added three approaches for writing portable/reusable configs:
1. Document required keys
2. Use composition/override instead of delete
3. Conditional deletion with lists
- Updated examples to reflect strict delete semantics
## Results
- 633 tests passing (1 skipped)
- Zero regressions
- Improved error messages show exact file:line and relevant suggestions
- Complete type safety for location tracking
* Extract get_by_id to path_utils and improve error consistency
- Move _get_by_id from Preprocessor to standalone get_by_id function in path_utils
- Config._get_by_id now delegates to the shared get_by_id function
- Change ValueError to TypeError when indexing non-dict/list values
- Improve InstantiationError handling to preserve source location and suggestion
- Move related tests from test_preprocessor.py to test_path_utils.py
* Add a test for instantiation error
* Make local raw references lazy to support CLI overrides
Local % refs (%key) are now expanded during resolve() instead of update(),
allowing CLI overrides to affect values used by local raw references.
External file refs (%file.yaml::key) remain eager since external files are frozen.
This fixes the surprising behavior where CLI overrides were silently ignored
for values referenced by local % refs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
* Update the test
* Update README
---------
Co-authored-by: Claude <[email protected]>
Sparkwheel is a hard fork of [MONAI Bundle](https://github.com/Project-MONAI/MONAI/tree/dev/monai/bundle)'s configuration system, refined and expanded for general-purpose use. We're deeply grateful to the MONAI team for their excellent foundation.
107
-
108
-
Sparkwheel powers [Lighter](https://project-lighter.github.io/lighter/), our configuration-driven deep learning framework built on PyTorch Lightning.
109
-
110
-
## License
111
-
112
-
Apache License 2.0 - See [LICENSE](LICENSE) for details.
65
+
Sparkwheel is a hard fork of [MONAI Bundle](https://github.com/Project-MONAI/MONAI/tree/dev/monai/bundle)'s config system, with the goal of making a more general-purpose configuration library for Python projects. It combines the best of MONAI Bundle and [Hydra](http://hydra.cc/)/[OmegaComf](https://omegaconf.readthedocs.io/), while introducing new features and improvements not found in either.
Copy file name to clipboardExpand all lines: docs/user-guide/operators.md
+43-39Lines changed: 43 additions & 39 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -126,11 +126,14 @@ Remove keys or list items with `~key`:
126
126
### Delete Entire Keys
127
127
128
128
```yaml
129
-
# Remove keys (idempotent - no error if missing!)
129
+
# Remove keys explicitly
130
130
~old_param: null
131
131
~debug_settings: null
132
132
```
133
133
134
+
!!! warning "Key Must Exist"
135
+
The delete operator will raise an error if the key doesn't exist. This helps catch typos and configuration mistakes.
136
+
134
137
### Delete Dict Keys
135
138
136
139
Use path notation for nested keys:
@@ -214,28 +217,6 @@ dataloaders:
214
217
215
218
**Why?** Path notation is designed for dict keys, not list indices. The batch syntax handles index normalization and processes deletions correctly (high to low order).
216
219
217
-
### Idempotent Delete
218
-
219
-
Delete operations don't error if the key doesn't exist:
220
-
221
-
```yaml
222
-
# production.yaml - Remove debug settings if they exist
223
-
~debug_mode: null
224
-
~dev_logger: null
225
-
~test_data: null
226
-
# No errors if these don't exist!
227
-
```
228
-
229
-
This enables **reusable configs** that work with multiple bases:
0 commit comments