plesty.sdk.commands.check ========================= .. py:module:: plesty.sdk.commands.check .. autoapi-nested-parse:: Check a module for plesty standard. Attributes ---------- .. autoapisummary:: plesty.sdk.commands.check._REQUIRED_PROJECT_FIELDS plesty.sdk.commands.check._NAME_PATTERN plesty.sdk.commands.check._VERSION_PATTERN plesty.sdk.commands.check._PLESTY_LIB_PREFIXES plesty.sdk.commands.check._REQUIRED_LICENSE_FILES plesty.sdk.commands.check._COVERAGE_THRESHOLD plesty.sdk.commands.check._ANALYZER_PIPELINE_GATES plesty.sdk.commands.check._EXPERIMENT_PIPELINE_GATES plesty.sdk.commands.check._gate_guidance_cache plesty.sdk.commands.check._PROTECTED_SCHEMA_NAMES plesty.sdk.commands.check._DEVICE_DOCS_PROBE plesty.sdk.commands.check._WRITE_MODE_CHARS plesty.sdk.commands.check._MANIFEST_FIELDS plesty.sdk.commands.check._MANIFEST_TIMEOUT plesty.sdk.commands.check._DEFAULT_SCHEMA_GROUP Exceptions ---------- .. autoapisummary:: plesty.sdk.commands.check.GateNotApplicable Functions --------- .. autoapisummary:: plesty.sdk.commands.check._gate_guidance plesty.sdk.commands.check._echo_pass plesty.sdk.commands.check._run_gate plesty.sdk.commands.check._standard_for_version plesty.sdk.commands.check.derive_standard plesty.sdk.commands.check.check_command plesty.sdk.commands.check._gate_sequence plesty.sdk.commands.check.check_metadata plesty.sdk.commands.check.run_linter plesty.sdk.commands.check.run_formatter_check plesty.sdk.commands.check.run_type_checker plesty.sdk.commands.check.check_api_interfaces plesty.sdk.commands.check._collect_plesty_lib_imports plesty.sdk.commands.check._resolve_base_name plesty.sdk.commands.check.check_data_compliance plesty.sdk.commands.check._missing_return_annotations plesty.sdk.commands.check._shadowed_schema_classes plesty.sdk.commands.check.check_documentation plesty.sdk.commands.check._assert_changelog_updated plesty.sdk.commands.check.check_dependency_coexistence plesty.sdk.commands.check.check_test_coverage plesty.sdk.commands.check._measured_coverage plesty.sdk.commands.check.check_semantic_versioning plesty.sdk.commands.check._check_tag_freshness plesty.sdk.commands.check.check_licensing plesty.sdk.commands.check._check_authorship_currency plesty.sdk.commands.check.check_vulnerability_audit plesty.sdk.commands.check.check_docs_build plesty.sdk.commands.check._is_device_module plesty.sdk.commands.check._run_mock_pipeline_drivers plesty.sdk.commands.check.check_device_api_pipeline plesty.sdk.commands.check.check_device_status_contract plesty.sdk.commands.check._status_contract_violations plesty.sdk.commands.check.check_device_docs plesty.sdk.commands.check._is_analyzer_module plesty.sdk.commands.check.check_analyzer_contract plesty.sdk.commands.check._is_experiment_module plesty.sdk.commands.check.check_experiment_contract plesty.sdk.commands.check.check_experiment_persistence plesty.sdk.commands.check.check_experiment_manifest plesty.sdk.commands.check._read_manifest plesty.sdk.commands.check._manifest_problems plesty.sdk.commands.check._parameter_problems plesty.sdk.commands.check._schema_drift plesty.sdk.commands.check._config_keys plesty.sdk.commands.check._declared_keys plesty.sdk.commands.check.check_field_test_findings plesty.sdk.commands.check._adhoc_persistence_calls plesty.sdk.commands.check._describe_persistence_call plesty.sdk.commands.check._has_write_mode plesty.sdk.commands.check._module_name_from_toml plesty.sdk.commands.check._import_path_from_toml plesty.sdk.commands.check._tail_text plesty.sdk.commands.check._run_subprocess Module Contents --------------- .. py:data:: _REQUIRED_PROJECT_FIELDS :value: ('name', 'description', 'authors', 'requires-python', 'license') .. py:data:: _NAME_PATTERN .. py:data:: _VERSION_PATTERN .. py:data:: _PLESTY_LIB_PREFIXES :value: ('plesty.lib', 'plesty_lib', 'plestylib') .. py:data:: _REQUIRED_LICENSE_FILES :value: ('LICENSE',) .. py:data:: _COVERAGE_THRESHOLD :value: 80 .. py:data:: _ANALYZER_PIPELINE_GATES :value: ('test_analyzer_subclass', 'test_schema_integrity', 'test_analyze_signature',... .. py:data:: _EXPERIMENT_PIPELINE_GATES :value: ('test_experiment_subclass', 'test_plan_deterministic', 'test_plan_ops_resolve',... .. py:data:: _gate_guidance_cache :type: dict[str, Any] | None :value: None .. py:function:: _gate_guidance() -> dict[str, Any] Load the per-gate failure guidance from the packaged asset (cached). .. py:function:: _echo_pass(message: str) -> None Echo a gate progress line unless --quiet is active. .. py:exception:: GateNotApplicable Bases: :py:obj:`Exception` The gate does not apply to this module, and says so as a skip. A device gate on an analyzer has not passed; it has not run. Recording it as a pass would let ``check.json`` claim a device contract the module was never held to, and a page that labels only what passed reads as though the rest passed too. The message is the full CLI line, so the terminal output is unchanged from when each gate echoed it itself. Initialize self. See help(type(self)) for accurate signature. .. py:function:: _run_gate(key: str, gate: collections.abc.Callable[[], None], report: plesty.sdk.report.CheckReport | None = None) -> None Run one gate, record its outcome, and explain a failure. :param key: Gate key into the packaged guidance asset. :param gate: Zero-argument callable executing the gate. :param report: Collector for ``reports/check.json``. Outcomes are recorded whether the gate passes, skips or fails — a run that stopped early must not read as a clean sweep of a shorter sequence. .. py:function:: _standard_for_version(version: str) -> str | None Map a version string to its compliance standard, or None when unparseable. :param version: Version string such as ``0.2.1`` or ``v1.0.0``. .. py:function:: derive_standard(project_dir: pathlib.Path, pyproject_toml: dict[str, Any]) -> tuple[str, str] Resolve the compliance standard for a project. An explicit ``[tool.plesty] standard`` always wins. Without it, the standard is derived from the declared release version so that shared prototypes ramp up automatically (plesty-sdk#19): ``< 0.1.0`` → pixel, ``< 1.0.0`` → nebula, ``>= 1.0.0`` → quantum. For projects with a dynamic version (versioningit), the latest git tag is used; a project without any release tag is a fresh prototype and maps to pixel. A project that declares neither a static nor a dynamic version falls back to quantum, the conservative default. :param project_dir: Root directory of the target project. :param pyproject_toml: Parsed pyproject.toml content. :returns: A ``(standard, reason)`` tuple; the reason is human-readable and echoed by ``plesty check``. .. py:function:: check_command(context: plesty.sdk.context.ApplicationContext, standard: Literal['pixel', 'nebula', 'quantum'] | None, no_report: bool) -> None Check compliance of a HUB module with the Plesty standard. Enforcement tiers: ``pixel`` runs Metadata & Code Hygiene only (fast, suitable for pre-commit); ``nebula`` runs gates 1–6 without network access and is the standard enforced by the pre-push git hook installed by ``plesty init``; ``quantum`` runs all gates locally, including the [SDK+CI] tier, for full verification. Unless ``--no-report`` is given, the run writes ``reports/check.json`` — the module's standard-gate results in the same envelope the field test publishes, so a quality page renders both as one story. .. py:function:: _gate_sequence(standard: str) -> tuple[str, Ellipsis] Return every gate key this standard runs, in order. Used to record the gates a failed run never reached: a partial report listing only the gates that happened to run before the failure would read as a clean sweep of a shorter sequence. :param standard: The resolved compliance standard. .. py:function:: check_metadata(project_dir: pathlib.Path, pyproject_toml: dict[str, Any]) -> None Validate required pyproject.toml fields and plesty namespace conventions. :param project_dir: Root directory of the target project. :param pyproject_toml: Parsed pyproject.toml content. .. py:function:: run_linter(project_directory: pathlib.Path) -> None Run ruff linter (E, F, W, D rules) on the project directory. :param project_directory: The target project directory. .. py:function:: run_formatter_check(project_directory: pathlib.Path) -> None Check ruff formatting without modifying files. :param project_directory: The target project directory. .. py:function:: run_type_checker(project_directory: pathlib.Path) -> None Run mypy type checker over the plesty namespace module source. :param project_directory: The target project directory. .. py:function:: check_api_interfaces(project_dir: pathlib.Path, pyproject_toml: dict[str, Any]) -> None Verify public classes inherit from the appropriate plesty-lib base class. Classes that import from plesty.lib.* must inherit from one of the imported base classes. The specific base class (e.g. BaseDeviceSyncModel) is enforced implicitly: if it is imported and not used as a base, the check fails. :param project_dir: Root directory of the target project. :param pyproject_toml: Parsed pyproject.toml content. .. py:function:: _collect_plesty_lib_imports(tree: ast.AST) -> set[str] Return names imported from plesty.lib.* in the given AST. :param tree: Parsed AST of a Python source file. .. py:function:: _resolve_base_name(node: ast.expr) -> str Extract the simple name from a base-class AST node. :param node: An AST expression representing a base class. .. py:function:: check_data_compliance(project_dir: pathlib.Path, pyproject_toml: dict[str, Any]) -> None Verify the module respects the unified plesty-lib data-layer schemas. Two static rules apply to every module (plesty-sdk#17, follow-up to plesty-lib#4): 1. **Return annotations**: every public function or method declares an explicit return type annotation. 2. **No schema shadowing** (except plesty-lib itself): the module must not define its own classes named after the plesty-lib schema models (:data:`_PROTECTED_SCHEMA_NAMES`) — that silently forks the data contract. Module-type-specific data rules live in their own gates: d2 (device status contract) and e2 (experiment persistence). :param project_dir: Root directory of the target project. :param pyproject_toml: Parsed pyproject.toml content. .. py:data:: _PROTECTED_SCHEMA_NAMES :value: ('ConfigParameter', 'ConfigGroup', 'Command', 'ConfigSystem', 'FuncMeta', 'FuncParam',... .. py:function:: _missing_return_annotations(tree: ast.AST, rel_path: pathlib.Path) -> list[str] Rule 1: report public functions without an explicit return annotation. :param tree: Parsed AST of a module source file. :param rel_path: Project-relative path used in violation messages. .. py:function:: _shadowed_schema_classes(tree: ast.AST, rel_path: pathlib.Path) -> list[str] Rule 2: report class definitions that shadow a plesty-lib schema model. :param tree: Parsed AST of a module source file. :param rel_path: Project-relative path used in violation messages. .. py:function:: check_documentation(project_dir: pathlib.Path) -> None Check docs directory structure and that CHANGELOG.md is current. :param project_dir: Root directory of the target project. .. py:function:: _assert_changelog_updated(project_dir: pathlib.Path) -> None Raise if Python source files changed since the last git tag without a CHANGELOG update. :param project_dir: Root directory of the target project. .. py:function:: check_dependency_coexistence(pyproject_toml: dict[str, Any]) -> None Reject exact version pins (==) in project dependencies. :param pyproject_toml: Parsed pyproject.toml content. .. py:function:: check_test_coverage(project_dir: pathlib.Path, report: plesty.sdk.report.CheckReport | None = None) -> None Run pytest with coverage and enforce the 80% threshold. :param project_dir: Root directory of the target project. :param report: When given, the measured percentage is recorded on it. The number is worth publishing: a threshold tells a reader the module cleared a bar, the percentage tells them by how much. .. py:function:: _measured_coverage(output: str) -> float | None Extract the total coverage percentage from pytest-cov's terminal output. :param output: Captured stdout of the coverage run. :returns: The percentage, or ``None`` when the output carries no total — a run that failed before collecting has no coverage to report, and zero would be a measurement rather than the absence of one. .. py:function:: check_semantic_versioning(project_dir: pathlib.Path, pyproject_toml: dict[str, Any] | None = None) -> None Diff the public API against the latest release published on PyPI. Breaking API changes require a version bump beyond the published release (a minor bump before 1.0.0, a major bump afterwards), witnessed by a git tag. The gate is advisory in local runs and authoritative in CI (``CI`` env set). When the package is unpublished or PyPI is unreachable, it falls back to the tag-freshness reminder. :param project_dir: Root directory of the target project. :param pyproject_toml: Parsed pyproject.toml content; when omitted, only the tag-freshness reminder runs. .. py:function:: _check_tag_freshness(project_dir: pathlib.Path) -> None Remind the developer to tag a release if commits exist since the last tag. Fallback for unpublished packages and offline runs, where the API diff against PyPI is not possible. :param project_dir: Root directory of the target project. .. py:function:: check_licensing(project_dir: pathlib.Path, pyproject_toml: dict[str, Any]) -> None Verify licensing declarations and REUSE compliance. Checks that pyproject.toml declares a license, that a root ``LICENSE`` file exists (so forges such as GitLab detect the license), and that the project is compliant with the REUSE specification via ``reuse lint``. The deep dependency tree scan (CI part of this gate) runs in plesty-ci. :param project_dir: Root directory of the target project. :param pyproject_toml: Parsed pyproject.toml content. .. py:function:: _check_authorship_currency(project_dir: pathlib.Path) -> None Ensure unpushed commit authors are credited on the files they changed. Part of the Licensing gate. Runs locally only (a no-op in CI, and when there is no base branch to compare against). When a commit author is not yet listed as a contributor or copyright holder on a Python file they changed, the push is blocked until `plesty license author` records them. :param project_dir: Root directory of the target project. .. py:function:: check_vulnerability_audit(project_dir: pathlib.Path) -> None Audit declared dependencies for known CVEs using pip-audit. Exports a flat requirements.txt from uv.lock and runs pip-audit against it. Requires network access to query the OSV vulnerability database. :param project_dir: Root directory of the target project. .. py:function:: check_docs_build(context: plesty.sdk.context.ApplicationContext) -> None Build the Sphinx documentation and fail on any errors or warnings. Runs locally and in merge-request pipelines, so docs-breaking changes fail before they merge. Skipped in CI branch pipelines (``CI=true`` without ``CI_PIPELINE_SOURCE=merge_request_event``) because ``hub-deploy-docs`` builds and deploys the docs there as a dedicated pipeline job. :param context: The application context for the target project. .. py:function:: _is_device_module(pyproject_toml: dict[str, Any]) -> bool Return True when ``[tool.plesty] module_type = "device"`` is declared. :param pyproject_toml: Parsed pyproject.toml content. .. py:function:: _run_mock_pipeline_drivers(project_dir: pathlib.Path) -> list[str] Return the names of test functions that drive ``run_mock_pipeline()``. Read with :mod:`ast` rather than by grepping: a name in a docstring or a comment is not a test that runs, and accepting one would let a module claim the contract without exercising it. :param project_dir: Root directory of the target project. :returns: Test function names containing a ``run_mock_pipeline`` call, in the order found. .. py:function:: check_device_api_pipeline(project_dir: pathlib.Path, pyproject_toml: dict[str, Any]) -> None Gate d1: Verify device modules run the standard mock pipeline. Modules that do not declare ``module_type = "device"`` in ``[tool.plesty]`` are silently skipped. For device modules, ``tests/`` must contain a test calling ``run_mock_pipeline()``, and it must pass without hardware. One call runs all eight gates and reports every failure it found, so the eight forwarding functions this gate used to require were boilerplate that said nothing a single call does not. ``plesty init mock-test`` generates the test from the module's own declarations. :param project_dir: Root directory of the target project. :param pyproject_toml: Parsed pyproject.toml content. .. py:function:: check_device_status_contract(project_dir: pathlib.Path, pyproject_toml: dict[str, Any]) -> None Gate d2: Verify device telemetry overrides keep their schema annotations. Modules that do not declare ``module_type = "device"`` in ``[tool.plesty]`` are silently skipped. For device modules, overrides of ``status()`` must be annotated to return ``DeviceStatus`` and overrides of ``device_state()`` to return ``str``, so consumers can rely on the plesty-lib telemetry schema (plesty-sdk#17, follow-up to plesty-lib#4). :param project_dir: Root directory of the target project. :param pyproject_toml: Parsed pyproject.toml content. .. py:function:: _status_contract_violations(tree: ast.AST, rel_path: pathlib.Path) -> list[str] Report device-class telemetry overrides with wrong return annotations. :param tree: Parsed AST of a module source file. :param rel_path: Project-relative path used in violation messages. .. py:data:: _DEVICE_DOCS_PROBE :value: Multiline-String .. raw:: html
Show Value .. code-block:: python """ import tomllib from plesty.sdk.commands.docs.generate import load_doc_device, render_device_pages with open("pyproject.toml", "rb") as fh: pyproject = tomllib.load(fh) device = load_doc_device(pyproject) model = device.doc_model() if not model.standard_methods: raise SystemExit("doc_model().standard_methods is empty") if not model.parameters and not model.functions: raise SystemExit("device documents neither parameters nor functions") render_device_pages(model) # must render without error print("D3_OK") """ .. raw:: html
.. py:function:: check_device_docs(project_dir: pathlib.Path, pyproject_toml: dict[str, Any]) -> None Gate d3: Verify device modules are documentable with zero effort. Modules that do not declare ``module_type = "device"`` in ``[tool.plesty]`` are silently skipped. For device modules, the package must import, expose a hardware-free ``DocDevice``/``Device`` factory, and produce a populated ``doc_model()`` that renders into the standard reference pages — so ``plesty docs`` can generate Parameters / Functions / Standard Methods pages without any hand-written content (plesty-sdk#18). :param project_dir: Root directory of the target project. :param pyproject_toml: Parsed pyproject.toml content. .. py:function:: _is_analyzer_module(pyproject_toml: dict[str, Any]) -> bool Return True when ``[tool.plesty] module_type = "analyzer"`` is declared. :param pyproject_toml: Parsed pyproject.toml content. .. py:function:: check_analyzer_contract(project_dir: pathlib.Path, pyproject_toml: dict[str, Any]) -> None Gate a1: Verify analyzer modules implement the AnalyzerPipeline test suite. Modules that do not declare ``module_type = "analyzer"`` in ``[tool.plesty]`` are silently skipped. For analyzer modules, all five contract gate test functions must be present in ``tests/`` and pass on schema-generated synthetic inputs — they validate the package against the ``plesty.lib.analyzer.Analyzer`` contract (public subclass, schema integrity, analyze-signature match, mock round-trip, provenance stamp). :param project_dir: Root directory of the target project. :param pyproject_toml: Parsed pyproject.toml content. .. py:function:: _is_experiment_module(pyproject_toml: dict[str, Any]) -> bool Return True when ``[tool.plesty] module_type = "experiment"`` is declared. :param pyproject_toml: Parsed pyproject.toml content. .. py:function:: check_experiment_contract(project_dir: pathlib.Path, pyproject_toml: dict[str, Any]) -> None Gate e1: Verify experiment modules implement the ExperimentPipeline test suite. Modules that do not declare ``module_type = "experiment"`` in ``[tool.plesty]`` are silently skipped. For experiment modules, all five contract gate test functions must be present in ``tests/`` and pass without hardware — they validate the package against the ``plesty.lib.experiment.Experiment`` contract (single public subclass, deterministic ``build_plan()``, resolvable step operations, JSON-serializable plans, async lifecycle hooks). :param project_dir: Root directory of the target project. :param pyproject_toml: Parsed pyproject.toml content. .. py:function:: check_experiment_persistence(project_dir: pathlib.Path, pyproject_toml: dict[str, Any]) -> None Gate e2: Verify experiment modules persist results through the data layer. Modules that do not declare ``module_type = "experiment"`` in ``[tool.plesty]`` are silently skipped. For experiment modules, direct persistence calls — ``np.save``/``np.savez``/``np.savez_compressed``, ``pickle.dump``, ``h5py.File`` opened with a write mode, and builtin ``open`` with a write mode — are rejected in the module package: results must be persisted via ``plesty.lib.data.save_result``/``ResultDocument`` (plesty-sdk#17, follow-up to plesty-lib#4). Calls whose mode cannot be resolved statically are left alone. :param project_dir: Root directory of the target project. :param pyproject_toml: Parsed pyproject.toml content. .. py:data:: _WRITE_MODE_CHARS .. py:data:: _MANIFEST_FIELDS :value: ('module', 'title', 'config', 'run_root', 'schema') .. py:data:: _MANIFEST_TIMEOUT :value: 60 .. py:function:: check_experiment_manifest(project_dir: pathlib.Path, pyproject_toml: dict[str, Any]) -> None Gate e3: Verify an experiment module declares how it is run. Modules that do not declare ``module_type = "experiment"`` in ``[tool.plesty]`` are silently skipped. For experiment modules, ``python -m --manifest`` must print the document described in :class:`plesty.lib.experiment.Manifest` — the run command, the run root, the environment the run reads and the configuration schema — so a console can offer the experiment's settings without being taught them one module at a time. Two things are checked beyond the document's shape, and they are the reason the gate exists: * **Every parameter says what it is.** A control rendered without a ``dtype`` and a ``description`` is a box with a name on it, and a bounded one without a ``unit`` shows bare numbers. ``unit=""`` is an answer — a count has no unit — but leaving it unset is not. * **The schema and the shipped configuration agree.** A key the configuration sets and the schema omits cannot be edited; a key the schema declares and no configuration sets renders as a setting that does nothing. A schema nobody keeps current is worse than none, because a console renders it as fact. :param project_dir: Root directory of the target project. :param pyproject_toml: Parsed pyproject.toml content. :raises GateNotApplicable: If the module is not an experiment module. :raises click.ClickException: If the manifest cannot be produced, is malformed, or disagrees with the module's own configuration files. .. py:function:: _read_manifest(project_dir: pathlib.Path, module: str) -> dict[str, Any] Run ``python -m --manifest`` and return the document it printed. :param project_dir: Root directory of the target project. :param module: The module's import path. :returns: The parsed document. :raises click.ClickException: If the command fails, times out, or prints something that is not a JSON object. .. py:function:: _manifest_problems(document: dict[str, Any], module: str) -> list[str] Return what the manifest document itself gets wrong. :param document: The parsed manifest. :param module: The module's import path, which the manifest must name. :returns: One line per problem; empty when the document is well formed. .. py:function:: _parameter_problems(group: str, entry: Any) -> list[str] Return what one declared configuration parameter is missing. :param group: The group it is declared under. :param entry: The parameter mapping. :returns: One line per problem. .. py:function:: _schema_drift(project_dir: pathlib.Path, document: dict[str, Any]) -> list[str] Return where the schema and the module's own configuration disagree. :param project_dir: Root directory of the target project. :param document: The parsed manifest. :returns: One line per key that only one of the two knows about. .. py:function:: _config_keys(config: dict[str, Any], groups: set[str]) -> set[str] Return the keys a configuration document sets, as the schema addresses them. Only the two levels a schema describes are walked: a top-level value, and the members of a declared group. What lies inside an open-ended document is the experiment's own business. :param config: The loaded configuration. :param groups: The non-default group names the schema declares. :returns: The keys, ``group.parameter`` for grouped ones. .. py:function:: _declared_keys(schema: dict[str, Any]) -> set[str] Return every key the schema declares, addressed as a renderer writes it. :param schema: The manifest's schema block. :returns: The declared keys. .. py:data:: _DEFAULT_SCHEMA_GROUP :value: 'default' .. py:function:: check_field_test_findings(project_dir: pathlib.Path) -> None Gate f1: no published field test report holds an ``error`` finding. A field test writes ``reports//field-test.json`` after running against real hardware. An ``error`` finding in one means the module declares an API the instrument does not have — a parameter the hardware refuses, or one it will not answer. The module is telling every caller that something exists which does not, so it must not be published in that state. A module that has never been field-tested publishes no report and skips this gate. Absence is the honest rendering: "never run" and "ran and found nothing" are different facts, and treating them alike is how an untested module reads as a verified one. :param project_dir: Root directory of the target project. :raises GateNotApplicable: If the module publishes no field test report. :raises click.ClickException: If any report holds an ``error`` finding, or a report cannot be read. .. py:function:: _adhoc_persistence_calls(tree: ast.AST, rel_path: pathlib.Path) -> list[str] Report direct persistence calls that bypass ``save_result``. :param tree: Parsed AST of a module source file. :param rel_path: Project-relative path used in violation messages. .. py:function:: _describe_persistence_call(node: ast.Call) -> str Return a description of *node* when it is an ad-hoc persistence call. :param node: A call expression to classify. :returns: A short human-readable description, or ``""`` when the call is fine. .. py:function:: _has_write_mode(node: ast.Call, default_write: bool = False) -> bool Return True when a call's mode argument statically requests writing. The mode is taken from the second positional argument or the ``mode`` keyword. A missing mode means read-only; a mode that is not a string constant cannot be judged statically and is treated as read-only. :param node: The ``open``/``h5py.File`` call expression. :param default_write: Result to return when no mode argument is present. .. py:function:: _module_name_from_toml(pyproject_toml: dict[str, Any]) -> str Derive the Python module name from the pyproject.toml package name. :param pyproject_toml: Parsed pyproject.toml content. .. py:function:: _import_path_from_toml(pyproject_toml: dict[str, Any]) -> str Return the import path the package is served with by ``python -m``. ``[tool.plesty] module`` wins where a module declares one; otherwise it is the package name under the ``plesty`` namespace, the convention every module follows (``plesty-pol-pl`` → ``plesty.pol_pl``). :param pyproject_toml: Parsed pyproject.toml content. .. py:function:: _tail_text(text: str, max_lines: int = 20) -> str Return a compact tail of non-empty build output. .. py:function:: _run_subprocess(cmd: list[str], gate: str, cwd: pathlib.Path | None = None) -> None Run a subprocess and exit with its return code on failure. :param cmd: Command and arguments to run. :param gate: Gate name used in error messages. :param cwd: Working directory for the subprocess.