from __future__ import annotations
from typing import Literal
from pydantic import BaseModel, Field
from ._data import schema_version
Severity = Literal["error", "warning", "info"]
#: Where a diagnostic came from. It is the SARIF rule id and the Code Quality
#: check name, so a CI dashboard can group findings by the check that raised
#: them rather than by message text.
Category = Literal["schema", "func", "shape", "advisory", "pyxel-rule", "pyxel-load", "yaml"]
[docs]
class Diagnostic(BaseModel):
"""One finding about a config: what is wrong, where, and how much it matters."""
#: ``"error"`` makes the config invalid; ``"warning"`` and ``"info"`` do not.
severity: Severity
#: Where the finding is, as a JSON pointer into the config, such as
#: ``/pipeline/charge_generation/0/func``. Empty for the config as a whole.
path: str
#: What is wrong, in one sentence.
message: str
#: Further advice on putting it right, when there is any.
hint: str | None = None
#: The value most likely meant, such as the closest valid model for a typo.
suggestion: str | None = None
#: Values that would be accepted here, such as the valid models of a stage.
valid_options: list[str] | None = None
#: One concrete thing to do about it, phrased as an instruction. Filled in
#: by explain_config; validate_config leaves it empty.
next_step: str | None = None
#: The check that raised it, which is also its SARIF rule id and its Code
#: Quality check name.
category: Category = "schema"
[docs]
class ValidationResult(BaseModel):
"""The verdict on one config, from validate_config."""
#: True when no finding is an error.
valid: bool
#: Every finding, whatever its severity.
diagnostics: list[Diagnostic]
#: The Pyxel release the bundled schema was generated from, so every verdict
#: names the contract that judged it.
pyxel_version: str = Field(default_factory=schema_version)
#: True only when pyxel.load() itself was run on the config as well.
deep_checked: bool = False
#: The installed Pyxel release whose loader ran, when it did; it can differ
#: from pyxel_version, which names the bundled schema's release.
deep_pyxel_version: str | None = None
[docs]
class Explanation(BaseModel):
"""The verdict from explain_config: a summary, and a next step on each finding."""
#: True when no finding is an error.
valid: bool
#: One plain-English sentence a person can read before the list.
summary: str
#: Every finding, each with its next_step filled in.
diagnostics: list[Diagnostic]
#: The Pyxel release the bundled schema was generated from.
pyxel_version: str = Field(default_factory=schema_version)
#: True only when pyxel.load() itself was run on the config as well.
deep_checked: bool = False
#: The installed Pyxel release whose loader ran, when it did.
deep_pyxel_version: str | None = None
[docs]
class ParameterInfo(BaseModel):
"""One argument of a model, as the bundled Pyxel schema describes it."""
#: The argument's name.
name: str
#: Its type as Python spells it, such as ``float`` or ``list[int] | null``.
type: str
#: True when Pyxel needs the argument written in the step.
required: bool = False
#: True when the schema records a default for it (which can be null).
has_default: bool = False
#: Pyxel's own default, which a step that leaves the argument out gets.
#: A null default often means "from the detector" (quantum_efficiency).
default: object = None
#: The value Pyxel's example configs use, when they use one. An example,
#: not a default: writing it overrides Pyxel's own default.
example: object = None
[docs]
class ModelParameters(BaseModel):
"""A model's arguments, from model_parameters."""
#: The pipeline stage the model belongs to.
stage: str
#: The model's short name, such as ``load_image``.
model: str
#: Each argument, with its type and default.
parameters: list[ParameterInfo]
[docs]
class Tutorial(BaseModel):
"""One tutorial from the bundled catalog."""
#: The pipeline stage it was found under, such as ``charge_generation``.
group: str
#: The model it covers.
model: str
#: Its first heading, or the model's name when it has none.
title: str
#: The whole tutorial, as Markdown.
body_markdown: str
[docs]
class SemanticMatch(BaseModel):
"""One tutorial passage returned by a search."""
#: The pipeline stage of the tutorial the passage comes from.
group: str
#: The model that tutorial covers.
model: str
#: The tutorial's title.
title: str
#: The heading of the passage within the tutorial.
section: str
#: How close the passage is to the query; higher is closer. Keyword
#: results carry 0.
score: float
#: A short extract of the passage.
snippet: str
[docs]
class ModelInfo(BaseModel):
"""One model the bundled schema accepts."""
#: The pipeline stage it belongs to.
stage: str
#: The full ``func`` path to write in a config.
func: str
[docs]
class ModelCatalog(BaseModel):
"""The models the bundled schema accepts, from list_models."""
#: The stage that was asked for, or None for every stage.
stage: str | None = None
#: How many models are listed.
count: int
#: The models, sorted by stage and then by func.
models: list[ModelInfo]
[docs]
class TutorialSearchResult(BaseModel):
"""The answer to a tutorial search, naming the engine that gave it."""
#: ``"semantic"`` when the vector index answered, ``"keyword"`` when
#: keyword matching did.
mode: Literal["semantic", "keyword"]
#: True when keyword matching stood in for a vector index that could not
#: be used.
degraded: bool
#: Why the result is degraded, when it is.
message: str | None = None
#: The matching passages, best first.
matches: list[SemanticMatch]
[docs]
class ConfigFix(BaseModel):
"""One change autofix made to a config."""
#: The step that was changed, as a JSON pointer to its ``func`` before the
#: change.
path: str
#: ``"rename_func"`` when a mistyped model was renamed, ``"move_stage"``
#: when a model was moved to the stage it belongs to.
action: Literal["rename_func", "move_stage"]
#: The func name before a rename, or the stage before a move.
before: str
#: The func name after a rename, or the stage after a move.
after: str
#: The change, in one sentence.
detail: str
[docs]
class FixResult(BaseModel):
"""What autofix did to a config."""
#: True when at least one change was made.
changed: bool
#: Every change that was made.
changes: list[ConfigFix]
#: What autofix found but could not repair.
unresolved: list[Diagnostic]
#: The full validation findings for the corrected config.
remaining_diagnostics: list[Diagnostic]
#: The corrected config. The config that was passed in is never modified.
config: dict