plesty.lib.experiment.manifest ============================== .. py:module:: plesty.lib.experiment.manifest .. autoapi-nested-parse:: What an experiment module declares about itself, for a caller that runs it. A device answers ``describe`` and a console builds its panel from the reply, holding no per-device GUI code. An experiment is not a server and answers nothing, so the same knowledge has to leave it another way: ``python -m --manifest`` prints this document as JSON, and a caller reads the run command, the configuration the experiment takes, and the environment it needs without importing the module or guessing from ``--help``. The configuration schema is **not a new vocabulary**. It is ``{group: [parameter, ...]}`` — the very document a device's ``describe`` carries under ``parameters``, each entry a :meth:`~plesty.lib.device.params.ConfigParameter.to_dict`. So :func:`~plesty.lib.ui.device_panel.controls_for` turns an experiment's configuration into controls exactly as it turns a device's, and nothing that renders one has to learn the other. A configuration key that is not a scalar — a list of measurement targets, an open-ended mapping of fit options — is declared with ``dtype="yaml"``. There is no widget that edits an arbitrary document, and inventing one would be a form that quietly rejects what the experiment accepts; a renderer shows those as text. .. code-block:: python from plesty.lib.device.params import ConfigParameter from plesty.lib.experiment import EnvVar, Manifest manifest = Manifest( module="plesty.pol_pl", title="Polarization PL", schema={ "hwp": [ ConfigParameter("start_deg", default=0.0, dtype=float, unit="deg", min_value=0.0, max_value=360.0, description="First half-wave-plate angle."), ], }, environment=[EnvVar("HWP_ADDRESS", "ZMQ address of the rotation stage.")], ) manifest.to_dict()["schema"]["hwp"][0]["unit"] # → 'deg' Attributes ---------- .. autoapisummary:: plesty.lib.experiment.manifest.YAML_DTYPE plesty.lib.experiment.manifest.DEFAULT_GROUP Exceptions ---------- .. autoapisummary:: plesty.lib.experiment.manifest.ManifestError Classes ------- .. autoapisummary:: plesty.lib.experiment.manifest.EnvVar plesty.lib.experiment.manifest.Option plesty.lib.experiment.manifest.Manifest Functions --------- .. autoapisummary:: plesty.lib.experiment.manifest._parameter plesty.lib.experiment.manifest.group_of plesty.lib.experiment.manifest.yaml_parameter plesty.lib.experiment.manifest.env_vars plesty.lib.experiment.manifest.iter_parameters Module Contents --------------- .. py:data:: YAML_DTYPE :value: 'yaml' .. py:data:: DEFAULT_GROUP :value: 'default' .. py:exception:: ManifestError Bases: :py:obj:`ValueError` Raised when a manifest document is malformed or incomplete. Initialize self. See help(type(self)) for accurate signature. .. py:class:: EnvVar One environment variable the run reads. :ivar name: The variable, as the process environment spells it. :ivar description: What it is for, shown beside the field that sets it. :ivar required: Whether a run without it fails. An optional variable has a working default inside the experiment; a required one does not, and a caller can refuse to start rather than abort mid-plan. .. py:attribute:: name :type: str .. py:attribute:: description :type: str :value: '' .. py:attribute:: required :type: bool :value: True .. py:method:: to_dict() -> dict[str, Any] Return the variable as JSON primitives. .. py:method:: from_dict(raw: Mapping[str, Any]) -> EnvVar :classmethod: Rebuild a variable from :meth:`to_dict` output. :param raw: The mapping to read. :raises ManifestError: If ``name`` is missing or empty. .. py:class:: Option One extra command-line option the module adds to the standard set. :ivar flag: The option as it is typed, ``--prominence``. :ivar description: What it does — the option's own help text. :ivar dtype: Declared type name of its value; ``"bool"`` for a flag that takes none. :ivar sets: The configuration key the option overrides, written as a renderer addresses it (``analysis.fit_options.prominence``), or ``None`` when it changes something other than the configuration. .. py:attribute:: flag :type: str .. py:attribute:: description :type: str :value: '' .. py:attribute:: dtype :type: str :value: 'str' .. py:attribute:: sets :type: Optional[str] :value: None .. py:method:: to_dict() -> dict[str, Any] Return the option as JSON primitives. .. py:method:: from_dict(raw: Mapping[str, Any]) -> Option :classmethod: Rebuild an option from :meth:`to_dict` output. :param raw: The mapping to read. :raises ManifestError: If ``flag`` is missing or empty. .. py:class:: Manifest What one experiment module declares about running it. :ivar module: Import path served with ``python -m``, ``plesty.pol_pl``. :ivar title: Human title, shown wherever the experiment is named. :ivar schema: Configuration parameters by group. The ungrouped ones belong to :data:`DEFAULT_GROUP`, as they do on a device. :ivar environment: Variables the run reads from the environment or ``.env``. :ivar options: Extra command-line options beyond the standard set. :ivar config: Default configuration file, relative to the checkout. :ivar run_root: Where runs land when nothing overrides it. :ivar viz: Import path of the module's viewer (``python -m monitor``), or ``None`` when it ships none. :ivar chooses_devices: Whether ``python -m --devices --config `` names the devices of ``setup.yaml`` a run of that configuration uses; without it every device is served (#62). .. py:attribute:: module :type: str .. py:attribute:: title :type: str .. py:attribute:: schema :type: Mapping[str, Sequence[plesty.lib.device.params.ConfigParameter]] .. py:attribute:: environment :type: Sequence[EnvVar] :value: () .. py:attribute:: options :type: Sequence[Option] :value: () .. py:attribute:: config :type: str :value: 'config/default.yaml' .. py:attribute:: run_root :type: str :value: 'runs' .. py:attribute:: viz :type: Optional[str] :value: None .. py:attribute:: chooses_devices :type: bool :value: False .. py:method:: __post_init__() -> None Validate what a caller cannot recover from. :raises ManifestError: If the module is unnamed, or a parameter is declared twice in one group. .. py:method:: to_dict() -> dict[str, Any] Return the whole manifest as JSON primitives. This is what ``--manifest`` prints: everything a caller needs to offer the experiment's settings and start it, and nothing about how the experiment reaches its instruments. :returns: A mapping with ``module``, ``title``, ``config``, ``run_root``, ``viz``, ``schema`` (grouped, as a device's ``describe`` holds its parameters), ``environment``, ``options`` and ``chooses_devices``. .. py:method:: from_dict(raw: Mapping[str, Any]) -> Manifest :classmethod: Rebuild a manifest from a printed document. The parameters come back as :class:`ConfigParameter` objects carrying the declared type *name* rather than the type — the name is what crossed the wire, and what a renderer works from. :param raw: A :meth:`to_dict` document, as read back from ``--manifest``. :returns: The manifest. :raises ManifestError: If a required field is missing or malformed. .. py:method:: keys() -> set[str] Return every configuration key, written as a caller addresses it. A grouped key is ``group.parameter``; an ungrouped one is its bare name. This is the set a checker compares against the keys a shipped configuration file sets — a schema nobody keeps current is worse than none, because a console renders it as fact. :returns: The declared keys. .. py:method:: defaults() -> dict[str, Any] Return the declared defaults, shaped like the configuration file. Groups become nested mappings and ungrouped parameters stay at the top level, so the result can be written out as a starting configuration. A parameter that declares no default is left out rather than written as null — an absent key takes the experiment's own default, while a null overrides it with nothing. :returns: The configuration the defaults describe. .. py:method:: unknown_keys(config: Mapping[str, Any]) -> list[str] Return the keys *config* sets that the schema does not declare. Only the two levels the schema describes are examined — a top-level scalar and a group's members. What lies inside a ``yaml`` parameter is the experiment's business and is not walked into. :param config: A loaded configuration document. :returns: The undeclared keys, sorted, addressed as :meth:`keys` writes them. .. py:function:: _parameter(group: Any, raw: Any) -> plesty.lib.device.params.ConfigParameter Rebuild one configuration parameter from a printed manifest. :param group: The group it was printed under, for the error message. :param raw: The parameter mapping. :returns: The parameter, its ``dtype`` the declared type name. :raises ManifestError: If the entry is not a mapping, or has no name. .. py:function:: group_of(key: str) -> tuple[str, str] Split a configuration key into its group and parameter name. :param key: ``group.parameter``, or a bare name for an ungrouped parameter. :returns: The group (:data:`DEFAULT_GROUP` when the key carries none) and the parameter name. .. py:function:: yaml_parameter(name: str, description: str, default: Any = None) -> plesty.lib.device.params.ConfigParameter Declare a configuration key whose value is a document, not a scalar. :param name: The key. :param description: What it holds. :param default: The default document, if it has one. :returns: The parameter, typed :data:`YAML_DTYPE`. .. py:function:: env_vars(*names: str, **described: str) -> tuple[EnvVar, Ellipsis] Build required environment declarations. :param \*names: Variables with no description of their own. :param \*\*described: Variable name to description. :returns: One :class:`EnvVar` per name, in the order given. .. py:function:: iter_parameters(schema: Mapping[str, Sequence[plesty.lib.device.params.ConfigParameter]]) -> Iterable[tuple[str, plesty.lib.device.params.ConfigParameter]] Yield every ``(group, parameter)`` pair of a schema, groups in order. :param schema: The configuration schema. :Yields: The group name and one of its parameters.