API Reference (Config)¶
RobustConfig¶
sciwork.config.config.RobustConfig()
¶
Unified, high-level API for loading, merging, validating and generating INI/JSON configuration files. Internally delegates to sciwork.config.{loader,schema,templates,store}.
Typical flow: rc = RobustConfig() rc.load_ini_configs(["job.ini"]) rc.validate_with_schema_json("config_projects.json", template="data_handler", sections=["main"])
You can also generate skeleton configs from a JSON template: rc.create_ini_from_template("config_projects.json", "out.ini", template="data_handler", sections=["main"]) rc.create_json_from_template("config_projects.json", "out.json", template="data_handler", sections=["main"])
Source code in src/sciwork/config/config.py
29 30 31 | |
_data = {}
instance-attribute
¶
_schema_defaults = {}
instance-attribute
¶
__enter__()
¶
Enable with RobustConfig() as rc: ... usage.
No resources are acquired here; this returns self for convenience.
Source code in src/sciwork/config/config.py
50 51 52 53 54 55 | |
__exit__(exc_type, exc_val, exc_tb)
¶
Context-manager exit hook.
Logs any exception that occurred inside the with block and returns
False to let the exception propagate (default Python behavior).
Returns:
| Type | Description |
|---|---|
bool
|
|
Source code in src/sciwork/config/config.py
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | |
__repr__()
¶
Returns string like RobustConfig(sections=['main', 'dev']).
Source code in src/sciwork/config/config.py
33 34 35 36 | |
__str__()
¶
Lists sections and how many keys each section contains. Designed for quick diagnostics (not a full dump).
Source code in src/sciwork/config/config.py
38 39 40 41 42 43 44 45 46 47 48 | |
clear(*, sections=None, keep_defaults=False)
¶
Clear in-memory configuration data (all sections or only selected ones).
When the sections parameter is None (default), all sections are removed.
Otherwise, only the provided section names are removed (case-insensitive).
By default, any previously loaded schema defaults are kept;
pass keep_defaults=False to clear them as well.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sections
|
Optional[Iterable[str]]
|
Iterable of section names to delete; |
None
|
keep_defaults
|
bool
|
Keep schema defaults ( |
False
|
Returns:
| Type | Description |
|---|---|
'RobustConfig'
|
self (for fluent chaining). |
Source code in src/sciwork/config/config.py
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | |
create_ini_from_template(schema_json_path, dest_path, *, template, sections, project=None, include_defaults=True, placeholder='', header_comment=None, overwrite=False)
staticmethod
¶
Generate an INI file by applying a template object to sections.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schema_json_path
|
PathLike
|
Path to the schema JSON. |
required |
dest_path
|
PathLike
|
Where to write the INI file. |
required |
template
|
str
|
Template object name (e.g., |
required |
sections
|
Iterable[str]
|
Section names to include. |
required |
project
|
Optional[str]
|
Optional project name when using |
None
|
include_defaults
|
bool
|
Insert defaults when present in schema. |
True
|
placeholder
|
Optional[str]
|
Placeholder value for keys without defaults. |
''
|
header_comment
|
Optional[str]
|
Optional multi-line text to add at the top as |
None
|
overwrite
|
bool
|
When False and file exist, it raises |
False
|
Returns:
| Type | Description |
|---|---|
Path
|
Absolute path to the written INI file. |
Raises:
| Type | Description |
|---|---|
FileExistsError
|
If the destination exists and |
OSError
|
On write errors. |
ConfigError
|
On schema/template errors. |
Source code in src/sciwork/config/config.py
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | |
create_json_from_template(schema_json_path, dest_path, *, template, sections, project=None, include_defaults=True, placeholder='', drop_nulls=False, overwrite=False, indent=2)
staticmethod
¶
Generate a JSON configuration by applying a template object to sections.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schema_json_path
|
PathLike
|
Path to the schema JSON. |
required |
dest_path
|
PathLike
|
Destination JSON file path. |
required |
template
|
str
|
Template object name. |
required |
sections
|
Iterable[str]
|
Section names to include in output. |
required |
project
|
Optional[str]
|
Optional project name when using a |
None
|
include_defaults
|
bool
|
Insert defaults when present in schema. |
True
|
placeholder
|
Optional[str]
|
Placeholder value for missing defaults. |
''
|
drop_nulls
|
bool
|
Remove keys with the value |
False
|
overwrite
|
bool
|
When False and file exist, it raises |
False
|
indent
|
int
|
JSON indent for readability (default 2). |
2
|
Returns:
| Type | Description |
|---|---|
Path
|
Absolute path to a written JSON file. |
Raises:
| Type | Description |
|---|---|
FileExistsError
|
If the destination exists and |
OSError
|
On write errors. |
ConfigError
|
On schema/template errors. |
Source code in src/sciwork/config/config.py
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 | |
load_ini_config(path, *, interpolation='extended', csv_delimiters=None)
¶
Load a single INI file and merge it into the currently loaded data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
PathLike
|
INI file path. |
required |
interpolation
|
str
|
'extended' for ConfigParser.ExtendedInterpolation, or 'none'. |
'extended'
|
csv_delimiters
|
Optional[Sequence[str]]
|
Optional list of delimiters used by the loader for CSV-like parsing. |
None
|
Returns:
| Type | Description |
|---|---|
'RobustConfig'
|
self. |
Raises:
| Type | Description |
|---|---|
ConfigError
|
On parsing/IO errors. |
Source code in src/sciwork/config/config.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | |
load_ini_configs(files, *, interpolation='extended', csv_delimiters=None)
¶
Load multiple INI files (later override earlier) and merge into current data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
files
|
Iterable[PathLike]
|
Iterable of INI paths. |
required |
interpolation
|
str
|
'extended' or 'none'. |
'extended'
|
csv_delimiters
|
Optional[Sequence[str]]
|
Optional list of CSV-like delimiters. |
None
|
Returns:
| Type | Description |
|---|---|
'RobustConfig'
|
self. |
Raises:
| Type | Description |
|---|---|
ConfigError
|
On parsing/IO errors. |
Source code in src/sciwork/config/config.py
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | |
load_json_config(path)
¶
Merge a single JSON config (shape: section->key->value) into current data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
PathLike
|
JSON file path. |
required |
Returns:
| Type | Description |
|---|---|
'RobustConfig'
|
self. |
Raises:
| Type | Description |
|---|---|
ConfigError
|
On read/shape errors. |
Source code in src/sciwork/config/config.py
125 126 127 128 129 130 131 132 133 134 135 136 | |
load_json_configs(files)
¶
Merge multiple JSON configs (shape: section->key->value) into current data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
files
|
Iterable[PathLike]
|
Iterable of JSON file paths. |
required |
Returns:
| Type | Description |
|---|---|
'RobustConfig'
|
self. |
Raises:
| Type | Description |
|---|---|
ConfigError
|
On read/shape errors. |
Source code in src/sciwork/config/config.py
138 139 140 141 142 143 144 145 146 147 148 149 | |
section(name, *, missing_ok=False)
¶
Return one section mapping (lowercased name)
Source code in src/sciwork/config/config.py
361 362 363 364 365 366 | |
to_dict()
¶
Return a deep (but still mutable) dict representation of current data.
Source code in src/sciwork/config/config.py
357 358 359 | |
validate(*, schema_map)
¶
Validate current data against a KeySpec mapping.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schema_map
|
Mapping[str, Mapping[str, KeySpec]]
|
Mapping section -> key -> KeySpec |
required |
Returns:
| Type | Description |
|---|---|
'RobustConfig'
|
self. |
Raises:
| Type | Description |
|---|---|
ConfigError
|
On any validation problem. |
Source code in src/sciwork/config/config.py
152 153 154 155 156 157 158 159 160 161 162 163 164 | |
validate_with_schema_json(schema_path, *, template=None, project=None, sections=None)
¶
Convenience: load a JSON schema and validate current data.
Behavior: - If template is provided: apply that template to sections (or to all currently loaded sections when sections are None). - If template is omitted: treat JSON as {section -> key -> spec}, or you can add auto-detection later.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schema_path
|
PathLike
|
Path to JSON schema file. |
required |
template
|
Optional[str]
|
Optional template name to apply (e.g. "data_handler"). |
None
|
project
|
Optional[str]
|
Optional project name when schema has a "projects" wrapper. |
None
|
sections
|
Optional[Iterable[str]]
|
Target sections; defaults to current loaded sections. |
None
|
Returns:
| Type | Description |
|---|---|
'RobustConfig'
|
self. |
Raises:
| Type | Description |
|---|---|
ConfigError
|
On schema/read/validate errors. |
Source code in src/sciwork/config/config.py
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | |
Schema types¶
sciwork.config.schema.KeySpec(expected_type, required=False, validator=None)
dataclass
¶
Specification for a configuration key used during validation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
expected_type
|
Union[type, Tuple[type, ...]]
|
Allowed type (or tuple of types) for the key's value. Use Python types (e.g., |
required |
required
|
bool
|
Whether the key must be present in the section. |
False
|
validator
|
Optional[Validator]
|
Optional callable that receives the parsed value and must raise on invalid content. |
None
|
expected_type
instance-attribute
¶
required = False
class-attribute
instance-attribute
¶
validator = None
class-attribute
instance-attribute
¶
__post_init__()
¶
Source code in src/sciwork/config/schema.py
32 33 34 | |
Supporting modules¶
loader¶
Functions for reading INI and JSON files
sciwork.config.loader
¶
LOG = logging.getLogger(__name__)
module-attribute
¶
PathLike = Union[str, Path]
module-attribute
¶
__all__ = ['ConfigError', 'choose_interpolation', 'parse_value', 'merge_layer', 'merge_dicts', 'load_ini_files', '_resolve_inheritance', 'load_json_files']
module-attribute
¶
ConfigError
¶
Bases: Exception
Generic configuration error used by loader utilities.
This module defines its own exception to avoid circular imports. A package-level errors.py can later centralize this if desired.
_cp_to_typed_dict(cp, *, csv_delimiters=None)
¶
Project a ConfigParser into a nested dict with parsed value types.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cp
|
ConfigParser
|
Prepared ConfigParser (already read). |
required |
csv_delimiters
|
Optional[Union[str, Iterable[str]]]
|
Optional CSV delimiters for value parsing. |
None
|
Returns:
| Type | Description |
|---|---|
Dict[str, Dict[str, Any]]
|
Dict[section]->Dict[key->typed value] (lowercased section/key names). |
Source code in src/sciwork/config/loader.py
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | |
_resolve_inheritance(data)
¶
Support extends key in sections to mix in parent keys (shallow merge per level).
Example: [dev] extends = base, other
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
MutableMapping[str, Dict[str, Any]]
|
Dict of sections to resolve (modified in place). |
required |
Raises:
| Type | Description |
|---|---|
ConfigError
|
When a referenced parent section does not exist. |
Source code in src/sciwork/config/loader.py
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | |
_split_csv(text, delimiters)
¶
Split text by a set of single-character delimiters, respecting quotes and escapes.
Supports both single and double quotes and the backslash escape inside quoted parts. Delimiters must be single characters (e.g. ',', ';', '\t', ' ').
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Input string to split. |
required |
delimiters
|
Optional[Union[str, Iterable[str]]]
|
Either a string of delimiter characters or an iterable of single-character strings. If None, no splitting is performed. |
required |
Returns:
| Type | Description |
|---|---|
List[str]
|
List of token strings (untrimmed; caller may strip/parse further). |
Source code in src/sciwork/config/loader.py
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | |
choose_interpolation(interpolation)
¶
Return an interpolation object for configparser based on a textual flag.
If interpolation is one of {"none","no","off","false","f","raw"}, the interpolation is disabled (returns None). Otherwise, ExtendedInterpolation is used.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
interpolation
|
Optional[str]
|
Text flag controlling interpolation behavior. |
required |
Returns:
| Type | Description |
|---|---|
Optional[Interpolation]
|
Interpolation object or None. |
Source code in src/sciwork/config/loader.py
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | |
load_ini_files(files, *, interpolation='extended', csv_delimiters=None)
¶
Load one or more INI files and return a typed, merged mapping of sections.
Later files override earlier ones (ConfigParser layering). Values are parsed to
Python types via :func:parse_value. Sections support inheritance via the
extends key (resolved after reading all files).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
files
|
Iterable[PathLike]
|
Iterable of INI file paths. |
required |
interpolation
|
Optional[str]
|
Text flag to control interpolation ('extended' or 'none' etc.). |
'extended'
|
csv_delimiters
|
Optional[Union[str, Iterable[str]]]
|
Optional CSV delimiters to enable CSV-like value parsing. |
None
|
Returns:
| Type | Description |
|---|---|
Tuple[Dict[str, Dict[str, Any]], List[Path]]
|
(data, loaded_files) |
Raises:
| Type | Description |
|---|---|
ConfigError
|
On missing file(s) or IO errors. |
Source code in src/sciwork/config/loader.py
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | |
load_json_files(files)
¶
Load and merge multiple JSON config files into a single mapping.
Each JSON file must be a top-level object with the shape: { "section": { "key": value, ... }, ... }
Later files override earlier ones at section/key granularity.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
files
|
Iterable[PathLike]
|
Iterable of JSON paths. |
required |
Returns:
| Type | Description |
|---|---|
Dict[str, Dict[str, Any]]
|
Merged mapping. |
Raises:
| Type | Description |
|---|---|
ConfigError
|
On IO/parse errors or invalid shapes. |
Source code in src/sciwork/config/loader.py
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | |
merge_dicts(base, *layers)
¶
Deep-merge one or more layers into base at section/key granularity.
Later layers overwrite earlier ones for identical keys.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base
|
MutableMapping[str, Dict[str, Any]]
|
Destination mapping (modified in place). |
required |
layers
|
Mapping[str, Mapping[str, Any]]
|
One or more mappings to overlay. |
()
|
Returns:
| Type | Description |
|---|---|
MutableMapping[str, Dict[str, Any]]
|
The mutated base (for chaining). |
Source code in src/sciwork/config/loader.py
174 175 176 177 178 179 180 181 182 183 184 185 186 187 | |
merge_layer(base, layer)
¶
Deep-merge layer into base at the section/key level.
Later (right) values overwrite earlier (left) values for identical keys.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base
|
MutableMapping[str, Dict[str, Any]]
|
Destination mapping (modified in place). |
required |
layer
|
Mapping[str, Mapping[str, Any]]
|
Source mapping to overlay. |
required |
Source code in src/sciwork/config/loader.py
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | |
parse_value(raw, *, csv_delimiters=None)
¶
Parse a raw INI string into a typed Python value.
The parser attempts, in order:
1) ast.literal_eval for safe Python literals (numbers, strings, lists, dicts, booleans, None).
2) Common textual None markers: none, null, na, n/a.
3) Booleans: true/yes/on → True, false/no/off → False.
4) CSV-like splitting only if csv_delimiters is provided (items parsed recursively).
5) Numeric fallback (int/float).
6) Otherwise the original string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raw
|
str
|
Source text as read from ConfigParser. |
required |
csv_delimiters
|
Optional[Union[str, Iterable[str]]]
|
Optional set of single-char delimiters to enable CSV splitting. |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
Best-effort typed value. |
Source code in src/sciwork/config/loader.py
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | |
schema¶
Types and helpers for schema parsing and validation
sciwork.config.schema
¶
PathLike = Union[str, Path]
module-attribute
¶
Validator = Callable[[Any], None]
module-attribute
¶
_TYPE_MAP = {'str': str, 'string': str, 'int': int, 'integer': int, 'float': float, 'number': float, 'bool': bool, 'boolean': bool, 'null': type(None), 'none': type(None), 'list': list, 'array': list, 'dict': dict, 'object': dict}
module-attribute
¶
__all__ = ['KeySpec', 'Validator', '_parse_type_tokens', 'make_choices_validator', 'schema_parse_to_keyspecs', 'load_schema_from_json', 'load_schema_template_from_json', 'apply_defaults', 'validate_data']
module-attribute
¶
ConfigError
¶
Bases: Exception
Generic configuration error used by loader utilities.
This module defines its own exception to avoid circular imports. A package-level errors.py can later centralize this if desired.
KeySpec(expected_type, required=False, validator=None)
dataclass
¶
Specification for a configuration key used during validation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
expected_type
|
Union[type, Tuple[type, ...]]
|
Allowed type (or tuple of types) for the key's value. Use Python types (e.g., |
required |
required
|
bool
|
Whether the key must be present in the section. |
False
|
validator
|
Optional[Validator]
|
Optional callable that receives the parsed value and must raise on invalid content. |
None
|
_parse_type_tokens(type_field)
¶
Convert a type descriptor into a tuple of Python types for KeySpec.expected_type.
Supported tokens (case-insensitive):
- primitives: "str", "int", "float", "bool", "null" (or "none")
- containers: "list", "dict"
- parametric list: "list[str]" etc. → treated as list for expected_type
- union: a JSON list like ["int", "null"]
Unknown tokens degrade gracefully to str (so validation still works).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
type_field
|
Union[str, List[Optional[str]]]
|
String token (e.g., |
required |
Returns:
| Type | Description |
|---|---|
Tuple[type, ...]
|
Tuple of acceptable Python types (e.g., |
Source code in src/sciwork/config/schema.py
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | |
_read_json_object(path_like, what)
¶
Load a JSON file and ensure the top-level is an object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path_like
|
PathLike
|
Path to the JSON file. |
required |
what
|
str
|
Human label used in error messages (e.g., |
required |
Returns:
| Type | Description |
|---|---|
Dict[str, Any]
|
Parsed top-level object. |
Raises:
| Type | Description |
|---|---|
ConfigError
|
On IO/parse errors or when the JSON is not an object. |
Source code in src/sciwork/config/schema.py
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | |
apply_defaults(data, defaults)
¶
Apply per-section defaults into data for keys that are missing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
Dict[str, Dict[str, Any]]
|
Configuration values (modified in place). |
required |
defaults
|
Mapping[str, Mapping[str, Any]]
|
Mapping |
required |
Source code in src/sciwork/config/schema.py
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | |
load_schema_from_json(path)
¶
Load a schema JSON file and return its top-level object.
This does not perform any transformation; it is a thin convenience wrapper
for :func:_read_json_object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
PathLike
|
Path to JSON schema. |
required |
Returns:
| Type | Description |
|---|---|
Dict[str, Dict[str, Any]]
|
Top-level JSON object. |
Raises:
| Type | Description |
|---|---|
ConfigError
|
On IO/parse errors or invalid top-level type. |
Source code in src/sciwork/config/schema.py
193 194 195 196 197 198 199 200 201 202 203 204 | |
load_schema_template_from_json(path, *, template, project=None, sections=None)
¶
Load a template schema (e.g. "data_handler") and apply it to many sections.
Accepted JSON shapes: 1) Direct sections (no wrapper): ... code-block:: JSON
{
"data_handler": { "...": { "type": "str", "required": true } }
}
2) With project wrapper: ... code-block:: JSON
{
"projects": {
"my_project": {
"data_handler": { "...": { "type": "str" } }
}
}
}
The selected template (template) is replicated for each section name in
sections. If sections is omitted, the function uses an empty list and
still returns parsed (schema, defaults) for possible later application.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
PathLike
|
Path to the schema JSON. |
required |
template
|
str
|
Template object name to use (e.g., |
required |
project
|
Optional[str]
|
Optional project name when using a |
None
|
sections
|
Optional[List[str]]
|
Section names to which to apply the template; if |
None
|
Returns:
| Type | Description |
|---|---|
Tuple[Dict[str, Dict[str, KeySpec]], Dict[str, Dict[str, Any]]]
|
|
Raises:
| Type | Description |
|---|---|
ConfigError
|
On missing template or invalid shapes. |
Source code in src/sciwork/config/schema.py
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | |
make_choices_validator(choices)
¶
Build a validator that ensures the value is one of the allowed choices.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
choices
|
Iterable[Any]
|
Iterable of allowed values (compared using equality). |
required |
Returns:
| Type | Description |
|---|---|
Validator
|
A callable that raises |
Source code in src/sciwork/config/schema.py
81 82 83 84 85 86 87 88 89 90 91 92 93 94 | |
schema_parse_to_keyspecs(root)
¶
Convert a schema root mapping into (KeySpec mapping, default mapping).
Expected per-key spec shape (all fields optional unless noted): ... code-block:: JSON
{
"type": "str | int | float | bool | null | list | dict | list[str] | ...",
"required": true,
"choices": ["foo", "bar", 10, null],
"default": <any JSON value>
}
Notes¶
typemay be a string or a list (logical OR). Parametric lists like"list[str]"are accepted, but the expected type is justlist; element typing is out of scope for this straightforward validator.- When the
choicesparameter is given, a validator checking membership is attached. defaultvalues are collected separately and not applied here.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
root
|
Mapping[str, Mapping[str, Any]]
|
Mapping of |
required |
Returns:
| Type | Description |
|---|---|
Tuple[Dict[str, Dict[str, KeySpec]], Dict[str, Dict[str, Any]]]
|
|
Raises:
| Type | Description |
|---|---|
ConfigError
|
On invalid shapes or unsupported field types. |
Source code in src/sciwork/config/schema.py
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | |
validate_data(data, schema)
¶
Validate presence, types, and custom constraints for data.
For each section defined in schema the validator checks:
* missing required keys,
* isinstance(value, expected_type) for present keys,
* runs optional validator(value).
All problems are aggregated and raised together as ConfigError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
Mapping[str, Mapping[str, Any]]
|
Parsed configuration values ( |
required |
schema
|
Mapping[str, Mapping[str, KeySpec]]
|
Validation schema ( |
required |
Raises:
| Type | Description |
|---|---|
ConfigError
|
When any validation error occurs. |
Source code in src/sciwork/config/schema.py
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | |
store¶
Thin in-memory store used by RobustConfig
sciwork.config.store
¶
LOG = logging.getLogger(__name__)
module-attribute
¶
PathLike = Union[str, Path]
module-attribute
¶
__all__ = ['PathLike', 'user_config_dir', 'project_config_dir', 'resolve_config_path', 'ensure_config_file', 'read_text', 'write_text', 'read_json', 'write_json', 'list_configs']
module-attribute
¶
_atomic_write_json(dest, obj, *, indent=2, backup_ext=None)
¶
Atomically write JSON obj to dest with UTF-8 encoding.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dest
|
Path
|
Destination file path. |
required |
obj
|
Any
|
JSON-serializable object to write. |
required |
indent
|
int
|
Indentation for readability. |
2
|
backup_ext
|
Optional[str]
|
Optional backup extension (e.g., |
None
|
Raises:
| Type | Description |
|---|---|
TypeError
|
If obj is not JSON serializable. |
OSError
|
On I/O errors. |
Source code in src/sciwork/config/store.py
131 132 133 134 135 136 137 138 139 140 141 142 143 | |
_atomic_write_text(dest, text, *, encoding='utf-8', backup_ext=None)
¶
Atomically write text to dest. Optionally, create a backup of the original.
Strategy: - write to a temporary file in the same directory, - flush + fsync, - optional backup, - os.replace(temp, dest) (atomic on POSIX/NTFS).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dest
|
Path
|
Destination file path. |
required |
text
|
str
|
Text content to write. |
required |
encoding
|
str
|
Target encoding. |
'utf-8'
|
backup_ext
|
Optional[str]
|
If provided (e.g., |
None
|
Raises:
| Type | Description |
|---|---|
OSError
|
On I/O errors. |
Source code in src/sciwork/config/store.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | |
_ensure_parent(path)
¶
Create parent directories for path if missing.
Source code in src/sciwork/config/store.py
82 83 84 | |
ensure_config_file(path, *, initial=None, overwrite=False)
¶
Ensure a text config file exists at path. If missing (or overwrite=True), write initial.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
PathLike
|
Target config path. |
required |
initial
|
Optional[str]
|
Initial file content to write (empty string when None). |
None
|
overwrite
|
bool
|
Rewrite even if the file already exists. |
False
|
Returns:
| Type | Description |
|---|---|
Path
|
The absolute path to the file. |
Raises:
| Type | Description |
|---|---|
OSError
|
On I/O errors. |
Source code in src/sciwork/config/store.py
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | |
list_configs(directory, pattern='*.json')
¶
Return a list of config files in directory matching pattern.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
directory
|
PathLike
|
Directory to search for config files. |
required |
pattern
|
str
|
Glob pattern (default |
'*.json'
|
Returns:
| Type | Description |
|---|---|
list[Path]
|
List of absolute Paths. |
Source code in src/sciwork/config/store.py
252 253 254 255 256 257 258 259 260 261 | |
project_config_dir(project_root=None, app='sciwork')
¶
Return a project-local configuration directory <project_root>/<app>/configs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
project_root
|
Optional[PathLike]
|
Project root directory. If |
None
|
app
|
str
|
Application namespace directory name. |
'sciwork'
|
Returns:
| Type | Description |
|---|---|
Path
|
Absolute path to the project config directory (not guaranteed to exist). |
Source code in src/sciwork/config/store.py
32 33 34 35 36 37 38 39 40 41 | |
read_json(path)
¶
Read and parse JSON from path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
PathLike
|
JSON file path. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
Parsed Python object. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the file does not exist. |
json.JSONDecodeError
|
For invalid JSON. |
OSError
|
On I/O errors. |
Source code in src/sciwork/config/store.py
208 209 210 211 212 213 214 215 216 217 218 219 220 | |
read_text(path, *, encoding='utf-8')
¶
Read a text file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
PathLike
|
File path. |
required |
encoding
|
str
|
Text encoding. |
'utf-8'
|
Returns:
| Type | Description |
|---|---|
str
|
File contents as a string. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the file does not exist. |
OSError
|
On I/O errors. |
Source code in src/sciwork/config/store.py
165 166 167 168 169 170 171 172 173 174 175 176 177 | |
resolve_config_path(name, *, prefer='user', project_root=None, env_var=None, app='sciwork')
¶
Resolve an absolute path for a config file name with a clear precedence.
Precedence:
1) If env_var is provided and the environment variable is set → use that path.
2) If prefer == 'project' → project_config_dir(project_root)/name.
3) Otherwise → user_config_dir(app)/name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
File name (e.g., |
required |
prefer
|
Literal['user', 'project']
|
Either |
'user'
|
project_root
|
Optional[PathLike]
|
Optional project root for project-local resolution. |
None
|
env_var
|
Optional[str]
|
Optional environment variable that can override the path. |
None
|
app
|
str
|
Application namespace directory. |
'sciwork'
|
Returns:
| Type | Description |
|---|---|
Path
|
The absolute path (may or may not exist yet). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/sciwork/config/store.py
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | |
user_config_dir(app='sciwork')
¶
Return a per-user configuration directory.
On Windows this is %APPDATA%/<app>, on POSIX $XDG_CONFIG_HOME/<app> or ~/.config/<app>.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
app
|
str
|
Application namespace directory name. |
'sciwork'
|
Returns:
| Type | Description |
|---|---|
Path
|
Absolute path to the user config directory (not guaranteed to exist). |
Source code in src/sciwork/config/store.py
16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
write_json(path, obj, *, indent=2, overwrite=True, backup_ext='.bak')
¶
Write JSON atomically, optionally creating a backup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
PathLike
|
Destination JSON path. |
required |
obj
|
Any
|
JSON-serializable object to write. |
required |
indent
|
int
|
Indent for pretty output. |
2
|
overwrite
|
bool
|
If |
True
|
backup_ext
|
Optional[str]
|
Backup extension ( |
'.bak'
|
Returns:
| Type | Description |
|---|---|
Path
|
The absolute path of the file. |
Raises:
| Type | Description |
|---|---|
FileExistsError
|
If destination exists and |
TypeError
|
If the object is not JSON-serializable. |
OSError
|
On I/O errors. |
Source code in src/sciwork/config/store.py
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | |
write_text(path, text, *, encoding='utf-8', overwrite=True, backup_ext='.bak')
¶
Write a text file atomically, optionally creating a backup of the previous content.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
PathLike
|
Destination path. |
required |
text
|
str
|
Content to write. |
required |
encoding
|
str
|
Target encoding. |
'utf-8'
|
overwrite
|
bool
|
If |
True
|
backup_ext
|
Optional[str]
|
Backup extension; set |
'.bak'
|
Returns:
| Type | Description |
|---|---|
Path
|
Absolute path written. |
Raises:
| Type | Description |
|---|---|
FileExistsError
|
When destination exists and |
OSError
|
On I/O errors. |
Source code in src/sciwork/config/store.py
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | |
templates¶
Utilities for simple template applications
sciwork.config.templates
¶
LOG = logging.getLogger(__name__)
module-attribute
¶
PathLike = Union[str, Path]
module-attribute
¶
KeySpec(expected_type, required=False, validator=None)
dataclass
¶
Specification for a configuration key used during validation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
expected_type
|
Union[type, Tuple[type, ...]]
|
Allowed type (or tuple of types) for the key's value. Use Python types (e.g., |
required |
required
|
bool
|
Whether the key must be present in the section. |
False
|
validator
|
Optional[Validator]
|
Optional callable that receives the parsed value and must raise on invalid content. |
None
|
_build_mapping_from_schema(schema, defaults, *, sections=None, include_defaults=True, placeholder='')
¶
Build a section→key→value mapping from a parsed schema and defaults.
If sections are provided, only those sections are included. Otherwise, all sections found in schema are used.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schema
|
Mapping[str, Mapping[str, KeySpec]]
|
Section → key → KeySpec. |
required |
defaults
|
Mapping[str, Mapping[str, Any]]
|
Section → key → default (optional keys only). |
required |
sections
|
Optional[Iterable[str]]
|
Optional subset of section names to include. |
None
|
include_defaults
|
bool
|
When True, use defaults where available. |
True
|
placeholder
|
Optional[str]
|
Value used for keys without defaults (can be '', None, or text). |
''
|
Returns:
| Type | Description |
|---|---|
Dict[str, Dict[str, Any]]
|
Dictionary ready to be dumped as INI/JSON content. |
Source code in src/sciwork/config/templates.py
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | |
_ensure_parent(path)
¶
Create parent directories for path if missing.
Source code in src/sciwork/config/templates.py
18 19 20 | |
_to_ini_scalar(value)
¶
Convert a Python value to a string suitable for INI emission.
Strategy: * None -> "null" * bool -> "true"/"false" * numbers/strings -> str(value) * lists/dicts/other -> JSON
This matches our parser in that: - "null" is recognized as None - "true"/"false" -> booleans, - JSON-like for complex types is safely parseable again.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
Python value to convert. |
required |
Returns:
| Type | Description |
|---|---|
str
|
String suitable for INI emission. |
Source code in src/sciwork/config/templates.py
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | |
load_schema_template_from_json(path, *, template, project=None, sections=None)
¶
Load a template schema (e.g. "data_handler") and apply it to many sections.
Accepted JSON shapes: 1) Direct sections (no wrapper): ... code-block:: JSON
{
"data_handler": { "...": { "type": "str", "required": true } }
}
2) With project wrapper: ... code-block:: JSON
{
"projects": {
"my_project": {
"data_handler": { "...": { "type": "str" } }
}
}
}
The selected template (template) is replicated for each section name in
sections. If sections is omitted, the function uses an empty list and
still returns parsed (schema, defaults) for possible later application.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
PathLike
|
Path to the schema JSON. |
required |
template
|
str
|
Template object name to use (e.g., |
required |
project
|
Optional[str]
|
Optional project name when using a |
None
|
sections
|
Optional[List[str]]
|
Section names to which to apply the template; if |
None
|
Returns:
| Type | Description |
|---|---|
Tuple[Dict[str, Dict[str, KeySpec]], Dict[str, Dict[str, Any]]]
|
|
Raises:
| Type | Description |
|---|---|
ConfigError
|
On missing template or invalid shapes. |
Source code in src/sciwork/config/schema.py
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | |
render_ini_from_template(schema_json_path, *, template, sections, project=None, include_defaults=True, placeholder='')
¶
Render an INI text from a JSON schema template applied to many sections.
This function:
1) loads a schema JSON file (optionally inside a projects wrapper),
2) extracts the chosen template object,
3) applies it to the provided sections,
4) returns an INI-formatted string and the intermediate mapping used.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schema_json_path
|
PathLike
|
Path to the schema JSON. |
required |
template
|
str
|
Template object name in the schema (e.g., |
required |
sections
|
Iterable[str]
|
Section names to include in the generated INI. |
required |
project
|
Optional[str]
|
Optional project name when schema uses a |
None
|
include_defaults
|
bool
|
Insert defaults from schema when available. |
True
|
placeholder
|
Optional[str]
|
Value for keys without defaults (e.g., |
''
|
Returns:
| Type | Description |
|---|---|
Tuple[str, Dict[str, Dict[str, Any]]]
|
|
Raises:
| Type | Description |
|---|---|
ConfigError
|
On IO/parse errors or invalid schema shapes. |
Source code in src/sciwork/config/templates.py
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | |
render_json_from_template(schema_json_path, *, template, sections, project=None, include_defaults=True, placeholder='', drop_nulls=False)
¶
Render a JSON-serializable mapping from a schema template.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schema_json_path
|
PathLike
|
Path to the schema JSON. |
required |
template
|
str
|
Template object name (e.g., |
required |
sections
|
Iterable[str]
|
Section names to include. |
required |
project
|
Optional[str]
|
Optional project name when schema uses |
None
|
include_defaults
|
bool
|
Insert defaults from schema when available. |
True
|
placeholder
|
Optional[str]
|
Value for keys without defaults (e.g., |
''
|
drop_nulls
|
bool
|
If True, omit keys whose value is |
False
|
Returns:
| Type | Description |
|---|---|
Dict[str, Dict[str, Any]]
|
A mapping |
Raises:
| Type | Description |
|---|---|
ConfigError
|
On schema/template errors. |
Source code in src/sciwork/config/templates.py
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | |
write_ini_from_template(schema_json_path, dest_path, *, template, sections, project=None, include_defaults=True, placeholder='', header_comment=None, overwrite=False)
¶
Generate and write an INI file from a schema template.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schema_json_path
|
PathLike
|
Path to the schema JSON. |
required |
dest_path
|
PathLike
|
Where to write the INI file. |
required |
template
|
str
|
Template object name (e.g., |
required |
sections
|
Iterable[str]
|
Section names to include. |
required |
project
|
Optional[str]
|
Optional project name when using |
None
|
include_defaults
|
bool
|
Insert defaults when present in schema. |
True
|
placeholder
|
Optional[str]
|
Placeholder value for keys without defaults. |
''
|
header_comment
|
Optional[str]
|
Optional multi-line text to add at the top as |
None
|
overwrite
|
bool
|
When False and file exist, it raises |
False
|
Returns:
| Type | Description |
|---|---|
Path
|
Absolute path to the written INI file. |
Raises:
| Type | Description |
|---|---|
FileExistsError
|
If the destination exists and |
OSError
|
On write errors. |
ConfigError
|
On schema/template errors. |
Source code in src/sciwork/config/templates.py
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | |
write_json_from_template(schema_json_path, dest_path, *, template, sections, project=None, include_defaults=True, placeholder='', drop_nulls=False, overwrite=False, indent=2)
¶
Generate and write a JSON configuration from a schema template.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schema_json_path
|
PathLike
|
Path to the schema JSON. |
required |
dest_path
|
PathLike
|
Destination JSON file path. |
required |
template
|
str
|
Template object name. |
required |
sections
|
Iterable[str]
|
Section names to include in output. |
required |
project
|
Optional[str]
|
Optional project name when using a |
None
|
include_defaults
|
bool
|
Insert defaults when present in schema. |
True
|
placeholder
|
Optional[str]
|
Placeholder value for missing defaults. |
''
|
drop_nulls
|
bool
|
Remove keys with the value |
False
|
overwrite
|
bool
|
When False and file exist, it raises |
False
|
indent
|
int
|
JSON indent for readability (default 2). |
2
|
Returns:
| Type | Description |
|---|---|
Path
|
Absolute path to a written JSON file. |
Raises:
| Type | Description |
|---|---|
FileExistsError
|
If the destination exists and |
OSError
|
On write errors. |
ConfigError
|
On schema/template errors. |
Source code in src/sciwork/config/templates.py
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | |