pyxel-config-core 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyxel-config-core might be problematic. Click here for more details.

Files changed (140) hide show
  1. pyxel_config_core-0.7.0/CHANGELOG.md +361 -0
  2. pyxel_config_core-0.7.0/LICENSE +21 -0
  3. pyxel_config_core-0.7.0/MANIFEST.in +7 -0
  4. pyxel_config_core-0.7.0/PKG-INFO +560 -0
  5. pyxel_config_core-0.7.0/README.md +507 -0
  6. pyxel_config_core-0.7.0/conftest.py +29 -0
  7. pyxel_config_core-0.7.0/pyproject.toml +131 -0
  8. pyxel_config_core-0.7.0/pyxel_config_core/__init__.py +107 -0
  9. pyxel_config_core-0.7.0/pyxel_config_core/_data.py +48 -0
  10. pyxel_config_core-0.7.0/pyxel_config_core/_deep_worker.py +95 -0
  11. pyxel_config_core-0.7.0/pyxel_config_core/banner.py +197 -0
  12. pyxel_config_core-0.7.0/pyxel_config_core/cli.py +1282 -0
  13. pyxel_config_core-0.7.0/pyxel_config_core/config_shape.py +236 -0
  14. pyxel_config_core-0.7.0/pyxel_config_core/console.py +200 -0
  15. pyxel_config_core-0.7.0/pyxel_config_core/data/BUNDLE.json +6 -0
  16. pyxel_config_core-0.7.0/pyxel_config_core/data/modelParameters.json +1153 -0
  17. pyxel_config_core-0.7.0/pyxel_config_core/data/pyxel_schema.json +8558 -0
  18. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeCollection_fixed_pattern_noise.md +151 -0
  19. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeCollection_glow.md +163 -0
  20. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeCollection_persistence.md +160 -0
  21. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeCollection_simple_collection.md +143 -0
  22. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeCollection_simple_full_well.md +153 -0
  23. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeCollection_simple_persistence.md +161 -0
  24. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_apd_gain.md +182 -0
  25. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_apply_qe_curve.md +163 -0
  26. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_avalanche_gain.md +169 -0
  27. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_charge_blocks.md +162 -0
  28. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_charge_deposition.md +169 -0
  29. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_charge_deposition_in_mct.md +168 -0
  30. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_conversion_with_3d_qe_map.md +163 -0
  31. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_conversion_with_qe_map.md +160 -0
  32. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_cosmix.md +167 -0
  33. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_dark_current.md +162 -0
  34. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_dark_current_dd.md +174 -0
  35. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_dark_current_prerad.md +177 -0
  36. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_dark_current_rule07.md +165 -0
  37. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_dark_current_rule22.md +172 -0
  38. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_dark_current_saphira.md +164 -0
  39. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_dark_current_tid.md +175 -0
  40. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_exponential_qe.md +160 -0
  41. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_load_charge.md +159 -0
  42. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_radiation_induced_dark_current.md +172 -0
  43. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_simple_conversion.md +159 -0
  44. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeGeneration_simple_dark_current.md +165 -0
  45. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_ac_crosstalk.md +168 -0
  46. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_alternating_column_noise_cmos.md +154 -0
  47. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_correlated_pink_noise_cmos.md +189 -0
  48. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_dc_crosstalk.md +165 -0
  49. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_dc_offset.md +156 -0
  50. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_ktc_noise.md +172 -0
  51. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_nghxrg.md +113 -0
  52. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_output_node_linearity_poly.md +162 -0
  53. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_output_node_noise.md +173 -0
  54. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_output_node_noise_cmos.md +175 -0
  55. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_output_pixel_reset_voltage_apd.md +168 -0
  56. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_physical_non_linearity.md +166 -0
  57. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_physical_non_linearity_with_saturation.md +169 -0
  58. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_readout_noise_saphira.md +171 -0
  59. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_simple_ipc.md +172 -0
  60. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_simple_measurement.md +155 -0
  61. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_simple_physical_non_linearity.md +162 -0
  62. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeMeasurement_uncorrelated_pink_noise_cmos.md +181 -0
  63. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeTransfer_arctic_add.md +162 -0
  64. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeTransfer_arctic_remove.md +165 -0
  65. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeTransfer_cdm.md +165 -0
  66. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeTransfer_multiplication_register.md +164 -0
  67. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ChargeTransfer_multiplication_register_cic.md +162 -0
  68. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/DataProcessing_extract_roi_to_xarray.md +171 -0
  69. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/DataProcessing_linear_regression.md +170 -0
  70. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/DataProcessing_mean_variance.md +171 -0
  71. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/DataProcessing_plot_roi.md +173 -0
  72. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/DataProcessing_remove_cosmic_rays.md +178 -0
  73. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/DataProcessing_signal_to_noise_ratio.md +169 -0
  74. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/DataProcessing_source_extractor.md +175 -0
  75. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/DataProcessing_statistics.md +171 -0
  76. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/Phasing_pulse_processing.md +171 -0
  77. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/PhotonCollection_illumination.md +138 -0
  78. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/PhotonCollection_load_image.md +138 -0
  79. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/PhotonCollection_load_psf.md +161 -0
  80. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/PhotonCollection_load_wavelength_psf.md +167 -0
  81. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/PhotonCollection_optical_psf.md +159 -0
  82. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/PhotonCollection_shot_noise.md +155 -0
  83. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/PhotonCollection_simple_collection.md +140 -0
  84. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/PhotonCollection_stripe_pattern.md +143 -0
  85. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/PhotonCollection_usaf_illumination.md +150 -0
  86. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/PhotonCollection_wavelength_dependence_airs.md +165 -0
  87. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ReadoutElectronics_dead_time_filter.md +171 -0
  88. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ReadoutElectronics_sar_adc.md +167 -0
  89. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ReadoutElectronics_sar_adc_with_noise.md +170 -0
  90. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ReadoutElectronics_simple_adc.md +160 -0
  91. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ReadoutElectronics_simple_amplifier.md +164 -0
  92. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/ReadoutElectronics_simple_phase_conversion.md +166 -0
  93. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/SceneGeneration_load_image.md +183 -0
  94. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/SceneGeneration_load_star_map.md +167 -0
  95. pyxel_config_core-0.7.0/pyxel_config_core/data/tutorials/SceneGeneration_usaf_illumination.md +179 -0
  96. pyxel_config_core-0.7.0/pyxel_config_core/diagnostics.py +58 -0
  97. pyxel_config_core-0.7.0/pyxel_config_core/discriminator.py +488 -0
  98. pyxel_config_core-0.7.0/pyxel_config_core/embedder.py +37 -0
  99. pyxel_config_core-0.7.0/pyxel_config_core/expressions.py +315 -0
  100. pyxel_config_core-0.7.0/pyxel_config_core/formats.py +265 -0
  101. pyxel_config_core-0.7.0/pyxel_config_core/fpa.py +489 -0
  102. pyxel_config_core-0.7.0/pyxel_config_core/knowledge.py +393 -0
  103. pyxel_config_core-0.7.0/pyxel_config_core/mcp_server.py +121 -0
  104. pyxel_config_core-0.7.0/pyxel_config_core/models.py +209 -0
  105. pyxel_config_core-0.7.0/pyxel_config_core/py.typed +0 -0
  106. pyxel_config_core-0.7.0/pyxel_config_core/rag.py +236 -0
  107. pyxel_config_core-0.7.0/pyxel_config_core/readout_times.py +177 -0
  108. pyxel_config_core-0.7.0/pyxel_config_core/run_rules.py +811 -0
  109. pyxel_config_core-0.7.0/pyxel_config_core/validation.py +945 -0
  110. pyxel_config_core-0.7.0/pyxel_config_core/yaml_dialect.py +60 -0
  111. pyxel_config_core-0.7.0/pyxel_config_core/yaml_read.py +174 -0
  112. pyxel_config_core-0.7.0/pyxel_config_core.egg-info/PKG-INFO +560 -0
  113. pyxel_config_core-0.7.0/pyxel_config_core.egg-info/SOURCES.txt +138 -0
  114. pyxel_config_core-0.7.0/pyxel_config_core.egg-info/dependency_links.txt +1 -0
  115. pyxel_config_core-0.7.0/pyxel_config_core.egg-info/entry_points.txt +4 -0
  116. pyxel_config_core-0.7.0/pyxel_config_core.egg-info/requires.txt +29 -0
  117. pyxel_config_core-0.7.0/pyxel_config_core.egg-info/top_level.txt +1 -0
  118. pyxel_config_core-0.7.0/setup.cfg +4 -0
  119. pyxel_config_core-0.7.0/tests/cmos_config.yaml +59 -0
  120. pyxel_config_core-0.7.0/tests/galaxy_config.yaml +114 -0
  121. pyxel_config_core-0.7.0/tests/observation_config.yaml +60 -0
  122. pyxel_config_core-0.7.0/tests/test_audit_findings.py +327 -0
  123. pyxel_config_core-0.7.0/tests/test_cli.py +542 -0
  124. pyxel_config_core-0.7.0/tests/test_deep.py +456 -0
  125. pyxel_config_core-0.7.0/tests/test_discriminator.py +186 -0
  126. pyxel_config_core-0.7.0/tests/test_docs_quickstart.py +40 -0
  127. pyxel_config_core-0.7.0/tests/test_expressions.py +325 -0
  128. pyxel_config_core-0.7.0/tests/test_fixtures.py +67 -0
  129. pyxel_config_core-0.7.0/tests/test_formats.py +266 -0
  130. pyxel_config_core-0.7.0/tests/test_fpa.py +370 -0
  131. pyxel_config_core-0.7.0/tests/test_mcp_enhancements.py +365 -0
  132. pyxel_config_core-0.7.0/tests/test_mcp_server_surface.py +224 -0
  133. pyxel_config_core-0.7.0/tests/test_packaging.py +373 -0
  134. pyxel_config_core-0.7.0/tests/test_rag.py +57 -0
  135. pyxel_config_core-0.7.0/tests/test_readout_times.py +66 -0
  136. pyxel_config_core-0.7.0/tests/test_run_rules.py +257 -0
  137. pyxel_config_core-0.7.0/tests/test_smoke.py +79 -0
  138. pyxel_config_core-0.7.0/tests/test_validation.py +359 -0
  139. pyxel_config_core-0.7.0/tests/test_yaml_dialect.py +53 -0
  140. pyxel_config_core-0.7.0/tests/test_yaml_read.py +187 -0
@@ -0,0 +1,361 @@
1
+ # Changelog
2
+
3
+ All notable changes to pyxel-config-core are recorded here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ Releases up to 0.5.0 were published to PyPI before the repository tagged its
8
+ releases, so they link to PyPI. From 0.6.0 on, each release is published from a
9
+ `core-v` tag.
10
+
11
+ ## [Unreleased]
12
+
13
+ ## [0.7.0] - 2026-11-06
14
+
15
+ ### Security
16
+
17
+ - The deep check's safety gate now refuses every file Pyxel opens or looks for
18
+ while it loads. `charge_to_volt`'s `value` and `from_capacitance`, plain or
19
+ under `sensitive` and `reference`, are read as images when they are text, so
20
+ a config could make the machine send a request to a URL, and the answer said
21
+ which local files exist. Any text in a detector's characteristics is now
22
+ refused as a file, along with a calibration's `target_data_path` and
23
+ `weights_from_file`. A new drift guard reads Pyxel's source and fails when a
24
+ release adds a place that opens or evaluates something during a load.
25
+ - An APD converter's `lambda` may no longer ask for unbounded arithmetic.
26
+ `lambda x: 9**9**9**9` never returned, and `lambda x: 1 << 10**11` asked for
27
+ about 12.5 GB. A power now takes a plain exponent of at most 64 and a base
28
+ with no power in it, and shifts and bit operations are refused.
29
+ - The deep check runs `pyxel.load()` in a process of its own, with a time limit
30
+ (120 seconds; `--deep-timeout` or `deep_timeout=` changes it). A load still
31
+ running then is stopped and reported as an error. Without trust, the process
32
+ also has a limit on its memory where the system allows one, and it never
33
+ imports modules from the current folder.
34
+ - Text past 20,000 characters is not read as Python. On Python 3.10 a chain of
35
+ some 100,000 operators in `times`, `values` or an APD `function` ended the
36
+ whole process with a segmentation fault, where a config now gets a refusal
37
+ that says why.
38
+
39
+ ### Added
40
+
41
+ - `--deep-timeout SECONDS` on `validate`, and `deep_timeout=` in the library.
42
+ - More of what Pyxel refuses as it loads a config is refused without running
43
+ it: readout `times` that are zero, not increasing, empty, or not below
44
+ `start_time`; a custom observation with no file of values; and a
45
+ `charge_to_volt` value outside Pyxel's range.
46
+ - What stops a run once it has started is refused too: a pipeline with no step
47
+ to run, a `save_data_to_file` bucket Pyxel cannot save, an observation
48
+ parameter whose key or values Pyxel cannot use, a sweep whose parameters are
49
+ all disabled, and a model missing what it reads from the detector (such as
50
+ `dark_current` with no temperature).
51
+ - A focal plane's `scene_generation` steps are checked: their keys and their
52
+ `func`. So is a plane's geometry, where `height: 0` ends in a singular matrix
53
+ at run, and its readout, with the same rules as a flat config's.
54
+ - A `func` with no dot, with a trailing dot, or under a misspelled `pyxel.model.`
55
+ is refused, on flat configs and on tiles alike, since Pyxel cannot import it.
56
+
57
+ ### Changed
58
+
59
+ - `validate` reads a readout's `times` the way Pyxel does, so a plane accepts
60
+ `numpy.linspace(1, 3, 3)`, `times_from_file` and `exposure: {}`, all of which
61
+ Pyxel runs.
62
+ - A step that is not a known model answers to the schema's generic branch. A
63
+ user's own model with `enabled: maybe` gets one finding instead of 21, and
64
+ `func: 123` gets one that names `func`.
65
+ - `-n` on `search` must be a positive number; 0 and negative numbers exit 2.
66
+ - `pyxel-config-mcp` without the `mcp` extra explains the fix, as
67
+ `pyxel-config mcp` does, rather than showing a traceback.
68
+
69
+ ### Fixed
70
+
71
+ - Text Pyxel's reader cannot read is a finding at its line rather than an
72
+ internal error: `2026-13-45`, `!!int abc`, `0b_` and the like. So are a `row`
73
+ of hundreds of digits, a key holding a slash or written as both `1` and `"1"`,
74
+ a tile named `"²"`, a non-text stage in `fix`, and `range()` of a huge number
75
+ in `--deep`.
76
+ - `fix --json` works on a config holding `!!binary`, and `fix` on an unreadable
77
+ encoding reports it and exits as `validate` does.
78
+ - `validate --deep --strict` with no Pyxel installed exits 3, as the README says.
79
+ - A reader closing the pipe early on Windows no longer turns into exit 120.
80
+ - `params` takes the full path that `list_models` hands out.
81
+ - `explain` gives a next step on every finding, run rules and missing required
82
+ fields included.
83
+ - `fix` gives the same suggestion on every run, and never suggests the same name
84
+ it just refused. A `func` of 20,000 characters no longer takes seconds.
85
+ - A merging map shallower than its anchor is no longer reported as a duplicate
86
+ key.
87
+
88
+ ## [0.6.1] - 2026-10-14
89
+
90
+ ### Added
91
+
92
+ - A documentation site at https://pyxel-config-lab-ede25c.gitlab.io/docs/:
93
+ installation, a quickstart, guides to the command line, the library, the MCP
94
+ server and semantic search, how validation works, and an API reference read
95
+ from the docstrings. Its guide pages include sections of the README, so the
96
+ two cannot say different things, and the quickstart's printed output is a
97
+ test (`tests/test_docs_quickstart.py`).
98
+ - NumPy-style docstrings on every public function and result type.
99
+ - A `docs` extra with what builds the site.
100
+ - A pipeline step without `func` is refused: Pyxel builds every step from it,
101
+ a disabled one included, although its schema leaves it optional.
102
+ - A focal-plane tile with more than one detector block is refused, as Pyxel's
103
+ tile loader refuses it, and only Pyxel's four detector keys count as a
104
+ detector block.
105
+ - `model_parameters(model, stage=None)`, `pyxel-config params` and the
106
+ `get_pyxel_model_parameters` MCP tool cover every model the bundled schema
107
+ accepts (`glow`, the CMOS noise models, `load_detector` and `save_detector`
108
+ among the 19 that had nothing). Each argument carries its type, `required`,
109
+ `has_default`, Pyxel's own `default` and the `example` value Pyxel's example
110
+ configs use. `stage` picks between the two stages a name such as
111
+ `simple_collection` exists in.
112
+
113
+ ### Changed
114
+
115
+ - The package's Documentation link points at the documentation site instead
116
+ of the README.
117
+ - Text that cannot be read as a config (a YAML syntax error, a key written
118
+ twice, an alias bomb, nesting hundreds of levels deep, text that is not
119
+ UTF-8) is a finding in the `validate` and `explain` reports, with exit code
120
+ 1, rather than stopping the run with exit code 3. One such file no longer
121
+ leaves a SARIF or Code Quality report empty. A file that cannot be opened is
122
+ listed in the report too, and the run still exits with 3.
123
+ - A file saved as UTF-16 or UTF-32 (as Windows PowerShell 5.1's `>` writes
124
+ it) is an error, since Pyxel reads a config file as UTF-8 only. Its content
125
+ is still checked.
126
+ - `ParameterInfo.default` is Pyxel's own default rather than the catalogue's
127
+ example value, which is now `ParameterInfo.example`. A step that leaves an
128
+ argument out gets the default; writing the example overrides it (for
129
+ `simple_conversion`'s `quantum_efficiency`, the detector's own value).
130
+ Types are spelled as Python spells them: `float`, `list[int] | null`.
131
+ - A number written as text, such as `1e3`, is reported only where text is
132
+ not what the field takes: a step's `name` or an output folder is left
133
+ alone, while a number field, or one that takes a number or a file name
134
+ (`charge_to_volt`'s `value`), still is.
135
+ - `fix` refuses `-w` and `-o FILE` together (exit code 2) instead of quietly
136
+ repairing in place. With `-o` or to stdout, a config with nothing to repair
137
+ is written exactly as it was, comments included.
138
+
139
+ ### Fixed
140
+
141
+ - `.nan` and `.inf` in a detector field Pyxel bounds (temperature, quantum
142
+ efficiency, full well capacity, the sizes) are refused, as Pyxel's own range
143
+ checks refuse them.
144
+ - A top-level key that is not text (`yes:`, `1:`, `~:`) no longer crashes
145
+ `validate_config`, `explain_config` or `autofix`.
146
+ - SARIF and Code Quality reports read each file once: a report with 3,000
147
+ findings took over four minutes and now takes well under a second. A
148
+ finding inside a mapping merged with `<<: *anchor` lands on its own line,
149
+ and a file outside the working directory is a `file:` URI in SARIF.
150
+ - The deep check hands Pyxel the file's text exactly as written, comments
151
+ included, and the deep check and `fix` write files as bytes: a config saved
152
+ with Windows line endings no longer arrives with every line break doubled.
153
+ - A semantic search tried before the index is built no longer makes the
154
+ index look built to `doctor` and to every later search.
155
+ - The semantic search guide installs `"pyxel-config-core[rag]"` from PyPI
156
+ rather than an editable install that only works in a clone, and the README
157
+ says which engine each tutorial search uses.
158
+
159
+ ### Security
160
+
161
+ - The deep check's safety gate refuses binary data (YAML `!!binary`) anywhere
162
+ in a config: Pyxel unpickles an APD converter function given that way, which
163
+ can run any code. Without trust it also refuses the files Pyxel opens while
164
+ it loads (`times_from_file`, a custom observation's `from_file`, an APD
165
+ converter's `filename`, URLs included) and a value range of more than a
166
+ million values. `--trust-config` (or `trusted=True`) lifts all three for a
167
+ config you wrote yourself; on the MCP server they apply whenever it was
168
+ started with `--allow-deep`.
169
+
170
+ ## [0.6.0] - 2026-10-03
171
+
172
+ ### Added
173
+
174
+ - `validate_config(config, deep=True)` hands the YAML to `pyxel.load()` when
175
+ Pyxel is installed and reports anything the loader rejects, which catches
176
+ what the JSON schema cannot express (readout times out of order, for
177
+ example).
178
+ `ValidationResult.deep_checked` says whether the loader actually ran. The
179
+ same switch is `--deep` on the `validate` and `explain` commands and
180
+ `deep=true` on the `validate_pyxel_config` and `explain_pyxel_config` MCP
181
+ tools.
182
+ - Loading runs part of a config: Pyxel evaluates text such as a readout's
183
+ `times` as Python and imports each model's module. Before it loads, the deep
184
+ check reads every such value and refuses to run the config unless each is
185
+ plain data or a known harmless call (`pyxel_config_core/expressions.py`).
186
+ `--trust-config` (or `trusted=True`) skips that reading for a config you
187
+ wrote yourself. On the MCP server the deep check is off unless the server is
188
+ started with `pyxel-config mcp --allow-deep`.
189
+ - The deep check names the Pyxel that judged the config:
190
+ `ValidationResult.deep_pyxel_version` and `Explanation.deep_pyxel_version`
191
+ carry the installed release whose loader ran, the summary says "and loads
192
+ in Pyxel 3.0.2", and the CLI's report and JSON say the same. Warnings
193
+ Pyxel raises while loading (those Python shows a user, not its own
194
+ deprecation notices) are reported as warning findings.
195
+ - `--deep` that cannot run (Pyxel missing, or installed but failing to import,
196
+ with the real import error named) exits with 3, "could not run", instead of
197
+ passing with 0. Any unexpected error also exits with 3, never with 1, which
198
+ means "the config has errors".
199
+ - `explain_config` returns an `Explanation`: `valid`, a one-sentence `summary`
200
+ ("This CCD exposure config has 2 problems in the charge_generation stage"),
201
+ and the diagnostics, each carrying a concrete `next_step` (the model name to
202
+ rename to, the accepted types, the section to add, the release that renamed
203
+ a field).
204
+ - `pyxel_config_core/config_shape.py`, the Python port of the browser app's
205
+ `configShape.js`: it names the running mode and detector a config uses,
206
+ reports a missing or duplicated one, and offers a did-you-mean for a
207
+ misspelled top-level key (`ccd_detecor`, `exposre`). The root-level anyOf
208
+ chorus ("'ccd_detector' is a required property", four times) is gone.
209
+ - `--format {text,json,sarif,codequality}` on `validate` and `explain`.
210
+ `--json` remains as the short spelling of `--format json`. SARIF 2.1.0 and
211
+ GitLab Code Quality reports carry the line of the offending key, found by
212
+ walking the YAML.
213
+ - `pyxel_config_core/data/BUNDLE.json`, a manifest naming the Pyxel release
214
+ the bundled schema was generated from and the schema's SHA-256.
215
+ `schema_version()` exposes it, `ValidationResult.pyxel_version` and
216
+ `Explanation.pyxel_version` carry it on every verdict, and `doctor` prints
217
+ it alongside whether the shipped schema still matches the manifest.
218
+ - `Diagnostic.category` (`schema`, `func`, `shape`, `advisory`, `pyxel-load`),
219
+ which is the SARIF rule id and the Code Quality check name.
220
+ - `search_pyxel_tutorials` takes an explicit `semantic: bool = False`; it was
221
+ documented as keyword search but silently used the vector index when one
222
+ existed.
223
+ - `py.typed`, `[tool.ruff]` and `[tool.mypy]` configuration, a `dev` extra,
224
+ and Python 3.13 in the classifiers.
225
+ - A `.pre-commit-hooks.yaml` at the repo root exposing `pyxel-config-validate`.
226
+ - `scripts/refresh_bundle.py` at the repo root: the one reproducible command
227
+ for upgrading every bundled artifact to a new Pyxel release, with `--check`
228
+ for CI.
229
+
230
+ - Run rules (`run_rules.py`): what Pyxel 3.0.2 refuses at load or stops on at
231
+ run time although its schema accepts it, reported as errors in the new
232
+ `pyxel-rule` category. A readout with both `times` and `times_from_file`, a
233
+ calibration with both `weights` and `weights_from_file`, an observation with
234
+ no parameters, `simple_measurement` with neither a `gain` nor a detector
235
+ `charge_to_volt`, `simple_amplifier` without `pre_amplification`, and
236
+ `simple_adc` without its ADC settings. The browser applies the same rules,
237
+ and CI runs a fixture for each through the real Pyxel.
238
+ - A run rule for whole numbers written as decimals where Pyxel refuses one:
239
+ a detector's `row` or `col` and a CCD's `image_row` or `overscan_row` stop
240
+ `pyxel.load()` when written `128.0`, and an exposure's `pipeline_seed`
241
+ stops the run. Fields Pyxel takes a decimal in (`adc_bit_resolution`, a
242
+ wavelength's `resolution`) are left alone.
243
+ - A run rule for a model whose own code refuses the config's detector
244
+ class: 19 of Pyxel 3.0.2's models check the class and raise a TypeError
245
+ on any other (`cdm` on a CMOS detector, `apd_gain` on a CCD). Each was
246
+ found by calling the model on every class, and CI repeats that against
247
+ the installed Pyxel. Models Pyxel's metadata restricts but whose code runs
248
+ on any detector are left alone.
249
+ - Focal plane arrays, which the Config Lab exports and the bundled schema
250
+ has no branch for, are validated instead of refused as a config missing
251
+ its detector and pipeline (`pyxel_config_core/fpa.py`). The plane is
252
+ checked against Pyxel's focal-plane loader as the browser checks it (one
253
+ running mode, exposure only; a physical geometry with one scale above 0;
254
+ tile IDs 1..N; positions as mappings with an angle of 0, 90, 180 or 270;
255
+ a plane-wide scene; nothing beside `focal_plane_array`), and each tile is
256
+ validated against the schema and the run rules as the flat config Pyxel
257
+ builds it from. Every finding names its tile and its path in the plane; a
258
+ finding in the plane's running mode is said once. `fix` repairs model
259
+ names inside tiles, `explain` says which tiles hold the problems, and the
260
+ deep check reads every tile and the plane-wide scene before Pyxel loads
261
+ the plane. The pre-commit hook and the MCP tools follow.
262
+
263
+ ### Changed
264
+
265
+ - Schema errors are grouped by path. The anyOf alternatives of a single field
266
+ collapse into one line naming every accepted type ("'x' is not one of the
267
+ accepted types: number, object, null"), at most eight paths are listed, and
268
+ a closing diagnostic counts what was left out. Previously the first five
269
+ unique (path, message) pairs were shown and the rest silently dropped.
270
+ - A pipeline step whose `func` is known is validated against that model's own
271
+ definition, so a mistyped argument reports as itself instead of alongside
272
+ the required arguments of every other model in the stage.
273
+ - The stale-detector heuristic in the advisory warnings now looks for any
274
+ `*_detector` key rather than requiring a `geometry` block under it.
275
+ - `search` exits 4 on zero hits with `--json` too; it was 0.
276
+ - `rag.semantic_search` reuses one embedder and one Qdrant client per index
277
+ directory instead of building both on every call.
278
+ - The bundled `tests/galaxy_config.yaml` fixture is valid under Pyxel 3.0.2
279
+ (`charge_to_volt` instead of the 2.x `charge_to_volt_conversion`).
280
+
281
+ ### Deprecated
282
+
283
+ - The `pyxel-config-index` console script. It prints a notice and forwards
284
+ to `pyxel-config index`, which is the same operation.
285
+
286
+ ### Fixed
287
+
288
+ - A model of the user's own (a `func` outside `pyxel.`, which Pyxel's schema
289
+ accepts through its generic ModelFunction branch) is no longer reported as
290
+ unknown, and `fix` no longer rewrites it into the built-in it resembles. A
291
+ typo under `pyxel.` is still caught.
292
+ - `pyxel-config fix --json -w` and `fix --json -o FILE` never wrote the
293
+ repaired config; the JSON branch returned before the write.
294
+ - `autofix` on a misspelled stage key moved the steps to the owning stage but
295
+ left the empty misspelled key behind, so the "fixed" config still failed
296
+ with "Additional properties are not allowed".
297
+ - Text that cannot be read as a config (a YAML syntax error, or a document
298
+ that is not a mapping) made `validate_config`, `explain_config` and
299
+ `autofix` raise, so an MCP client got a bare tool failure with no reason.
300
+ Each now returns a finding in the new `yaml` category that says what is
301
+ wrong and on which line.
302
+ - A few hundred bytes of nested YAML aliases load into a structure that
303
+ walks as tens of millions of values, and validating it kept the CLI, the
304
+ pre-commit hook or the MCP server busy for minutes. Text that expands past
305
+ its own length (or 100,000 values, whichever is larger) is now refused
306
+ before anything walks it (`pyxel_config_core/yaml_read.py`); no config
307
+ without aliases can reach that.
308
+ - A reader that closed the pipe early (`pyxel-config validate x.yaml | head`)
309
+ turned a failing check into exit 0. The verdict's exit code now stands.
310
+ - A config saved by Windows PowerShell 5.1's `>` or `Out-File` (UTF-16 with a
311
+ byte order mark) crashed the command line with exit 1. Files and stdin are
312
+ decoded by their byte order mark (UTF-8, UTF-16 or UTF-32), and other text
313
+ that is not UTF-8 is refused with exit 3, naming the byte that failed.
314
+ - `fix -w` wrote back a config with nothing to repair, which dropped its
315
+ comments and formatting. Such a config is now left exactly as it is.
316
+ - `fix -o -` and `tutorial --raw` wrote through the console's code page, so on
317
+ Windows a redirect turned characters outside it into question marks. Both
318
+ write UTF-8.
319
+ - A key written twice in one mapping (a second `pipeline:` block, say) was
320
+ accepted, while Pyxel keeps only the last. The reader now refuses it and
321
+ names both lines; keys a merge (`<<`) brings in may still be overridden.
322
+ - `fix` reported no remaining problems for any config without a root
323
+ `pipeline`, so it exited 0 on a config missing its pipeline. It now
324
+ reports the full verdict after its repairs, whatever the config holds.
325
+ - SARIF and Code Quality reports named each file as typed on the command
326
+ line, so a report written on Windows carried backslashes and pointed at
327
+ nothing on a CI runner, and stdin was "-". Files are now named relative to
328
+ the working directory with forward slashes (a `file:` URI in SARIF when
329
+ outside it, percent-encoded in SARIF either way), and stdin is "stdin".
330
+ - The `rag` extra allowed qdrant-client 1.7, but semantic search calls
331
+ `query_points` (added in 1.10), so with 1.7 to 1.9 every search fell back
332
+ to keywords with only "AttributeError" as the reason. The floor is now
333
+ 1.10, an older client is named with the command that fixes it, and a
334
+ degraded result carries the cause's message.
335
+ - The pre-commit hook checked every YAML file by default, so a repository's
336
+ own `.gitlab-ci.yml` (or a GitHub workflow) failed the commit. It now
337
+ leaves the common CI and tooling YAML files alone.
338
+ - The sdist shipped the test suite without the three configs it reads, so
339
+ its tests stopped at collection. A MANIFEST.in now adds them and the
340
+ conftest; the cross-language tests skip outside the repository.
341
+ - The bundled schema and tutorials reached the wheel only because setuptools
342
+ guessed at their folders, with a warning that a later release may stop
343
+ guessing. Both folders are now declared packages, and a test holds every
344
+ file in the package to the declared list.
345
+ - The README's GitLab CI recipe ran the plain check first, so a failing
346
+ verdict stopped the job before the Code Quality report was written. The
347
+ report now comes first and is uploaded with `when: always`.
348
+
349
+ ## [0.5.0] - 2026-09-19
350
+
351
+ ### Added
352
+
353
+ - The `pyxel-config` command line: `validate`, `explain`, `fix`, `models`,
354
+ `params`, `tutorial`, `search`, `index`, `mcp`, `doctor` and `banner`, with
355
+ the exit code as the verdict and stdout kept clean for pipes.
356
+
357
+ [Unreleased]: https://gitlab.com/dobybaxter127/pyxel-config-lab/-/compare/core-v0.7.0...main
358
+ [0.7.0]: https://gitlab.com/dobybaxter127/pyxel-config-lab/-/tags/core-v0.7.0
359
+ [0.6.1]: https://gitlab.com/dobybaxter127/pyxel-config-lab/-/tags/core-v0.6.1
360
+ [0.6.0]: https://gitlab.com/dobybaxter127/pyxel-config-lab/-/tags/core-v0.6.0
361
+ [0.5.0]: https://pypi.org/project/pyxel-config-core/0.5.0/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Doby Baxter
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,7 @@
1
+ # What the sdist carries beyond the package and its data: the test suite with
2
+ # the configs it reads and the conftest that points it at this copy, so the
3
+ # tests run from an unpacked sdist. The cross-language fixtures live at the
4
+ # repository root; the tests that need them skip outside it.
5
+ include conftest.py
6
+ include CHANGELOG.md
7
+ recursive-include tests *.py *.yaml