plesty-sdk 0.1.0.dev2__tar.gz → 0.2.1__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.
Files changed (70) hide show
  1. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/CHANGELOG.md +24 -0
  2. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/PKG-INFO +1 -1
  3. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/docs/commands/init.md +27 -18
  4. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/docs/commands/update.md +8 -11
  5. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/gl-secret-detection-report.json +5 -5
  6. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/ruff.toml +3 -0
  7. plesty_sdk-0.2.1/plesty/sdk/assets/templates/template/docs/toc.yaml +1 -0
  8. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/template/pyproject.toml.jinja +11 -7
  9. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/commands/check.py +91 -0
  10. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/commands/docs/sphinx_builder.py +1 -1
  11. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/commands/init.py +1 -0
  12. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/pyproject.toml +1 -0
  13. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/tests/test_init.py +6 -0
  14. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/.coverage +0 -0
  15. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/.gitignore +0 -0
  16. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/.gitlab-ci.yml +0 -0
  17. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/COPYING +0 -0
  18. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/COPYING.LESSER +0 -0
  19. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/LICENSE +0 -0
  20. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/README.md +0 -0
  21. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/docs/commands/check.md +0 -0
  22. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/docs/commands/docs.md +0 -0
  23. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/docs/commands/license.md +0 -0
  24. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/docs/commands/manual.md +0 -0
  25. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/docs/getting-started.md +0 -0
  26. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/docs/index.md +0 -0
  27. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/docs/toc.yaml +0 -0
  28. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/__init__.py +0 -0
  29. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/docs-build-gitlab-ci.yml +0 -0
  30. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/gitlab-ci.yml +0 -0
  31. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/logos/plesty_icon.png +0 -0
  32. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/logos/plesty_logo.png +0 -0
  33. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/copier.yml +0 -0
  34. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/extras/device/base_device.py +0 -0
  35. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/extras/device/device.py +0 -0
  36. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/template/.gitignore +0 -0
  37. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/template/CHANGELOG.md.jinja +0 -0
  38. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/template/COPYING +0 -0
  39. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/template/LICENSE +0 -0
  40. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/template/LICENSES/GPL-3.0-or-later.txt +0 -0
  41. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/template/LICENSES/LGPL-3.0-or-later.txt +0 -0
  42. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/template/README.md.jinja +0 -0
  43. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/template/docs/index.md.jinja +0 -0
  44. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/template/plesty/{{module_name}}/__init__.py.jinja +0 -0
  45. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/template/plesty/{{module_name}}/__main__.py.jinja +0 -0
  46. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/template/spdx.tmpl.jinja +0 -0
  47. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/template/tests/__init__.py +0 -0
  48. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/assets/templates/template/tests/test_{{module_name}}.py.jinja +0 -0
  49. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/cache.py +0 -0
  50. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/cli.py +0 -0
  51. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/commands/__init__.py +0 -0
  52. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/commands/docs/__init__.py +0 -0
  53. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/commands/docs/deploy.py +0 -0
  54. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/commands/docs/serve.py +0 -0
  55. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/commands/license.py +0 -0
  56. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/commands/manual.py +0 -0
  57. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/commands/update.py +0 -0
  58. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/plesty/sdk/context.py +0 -0
  59. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/tests/__init__.py +0 -0
  60. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/tests/test_cache.py +0 -0
  61. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/tests/test_check.py +0 -0
  62. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/tests/test_cli.py +0 -0
  63. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/tests/test_context.py +0 -0
  64. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/tests/test_docs_deploy.py +0 -0
  65. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/tests/test_docs_serve.py +0 -0
  66. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/tests/test_license.py +0 -0
  67. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/tests/test_manual.py +0 -0
  68. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/tests/test_sphinx_builder.py +0 -0
  69. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/tests/test_update.py +0 -0
  70. {plesty_sdk-0.1.0.dev2 → plesty_sdk-0.2.1}/uv.lock +0 -0
@@ -2,6 +2,30 @@
2
2
 
3
3
  The format is based on [Keep a Changelog](https://keepachangelog.com).
4
4
 
5
+ ## [2026-06-26]
6
+
7
+ ### Added
8
+ - Gate d1 — Device API Pipeline: optional gate (runs under `quantum`) that verifies
9
+ all eight standard `DevicePipeline` mock-gate test functions are present and pass.
10
+ Gate activation is controlled by `module_type = "device"` in `[tool.plesty]` of
11
+ `pyproject.toml`; modules without this entry skip the gate automatically. Gates are
12
+ numbered with a `d` prefix (d1, d2, …) to distinguish them from the core SDK gates.
13
+ - Gate 1 now validates `module_type` in `[tool.plesty]`: if present, must be one of
14
+ `"device"`, `"experiment"`, `"analyzer"`, `"core"`. Absent is accepted (non-hub modules).
15
+ - `plesty init device/experiment/analyzer` scaffolds `module_type` automatically in
16
+ the generated `pyproject.toml`.
17
+ - `plesty-sdk` itself declares `module_type = "core"` in its own `pyproject.toml`.
18
+
19
+ ## [2026-06-24b]
20
+
21
+ ### Fixed
22
+ - `plesty init` generated `.gitlab-ci.yml` now passes `access_token: $CI_BOT_TOKEN` to
23
+ `hub-module` so docs deployment can push to the `docs-build` branch.
24
+ - Dev dependencies moved from `[project.optional-dependencies.dev]` to
25
+ `[dependency-groups.dev]` so `uv run` includes them by default without `--extra dev`.
26
+ - Gate 2 mypy run now passes `--exclude tests` to avoid namespace-package
27
+ double-discovery errors in generated projects.
28
+
5
29
  ## [2026-06-24]
6
30
 
7
31
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plesty-sdk
3
- Version: 0.1.0.dev2
3
+ Version: 0.2.1
4
4
  Summary: Command-line application for developing Python modules compliant with the Plesty standard.
5
5
  Author: Plesty Development Team
6
6
  License-Expression: LGPL-3.0-or-later
@@ -37,11 +37,8 @@ name, so `plesty-foo-bar` → `foo_bar` without needing `--name`.
37
37
  | `--name` | inferred | Python module name — lowercase letters, digits, and `_` only (e.g. `foo_bar`). Inferred from the directory name by stripping the `plesty-` prefix and converting hyphens to underscores. |
38
38
  | `--author` | `John Doe` | Author name written into `pyproject.toml` and `spdx.tmpl` |
39
39
  | `--email` | `john.doe@example.com` | Author email written into `pyproject.toml` and `spdx.tmpl` |
40
- | `--ci-stages` | all stages | Comma-separated pipeline stages to include in `.gitlab-ci.yml`. Pass `""` to omit the CI file. |
41
-
42
- ### Available CI stages
43
-
44
- `check`, `test`, `build`, `release`, `deploy`
40
+ | `--standard` | `quantum` | Compliance standard for the generated CI pipeline: `pixel`, `nebula`, or `quantum`. |
41
+ | `--no-ci` | off | Skip generating `.gitlab-ci.yml` entirely. |
45
42
 
46
43
  ## Directory rules
47
44
 
@@ -57,12 +54,13 @@ After copying the template, `plesty init` automatically:
57
54
  2. **Creates the initial git commit** — required by `versioningit` to resolve a package
58
55
  version from git history.
59
56
  3. **Installs the pre-push hook** — writes `.git/hooks/pre-push` to run
60
- `plesty check --standard nebula` automatically before every `git push`.
57
+ `plesty check` automatically before every `git push` (standard read from
58
+ `[tool.plesty] standard` in `pyproject.toml`, default: `quantum`).
61
59
 
62
60
  ## Examples
63
61
 
64
62
  ```bash
65
- # Minimal: module name inferred from directory, all CI stages, default author
63
+ # Minimal: module name inferred from directory, quantum CI, default author
66
64
  mkdir plesty-power-meter && cd plesty-power-meter
67
65
  plesty init device
68
66
 
@@ -72,15 +70,15 @@ plesty --project-dir ~/projects/plesty-power-meter init device \
72
70
  --author "Jane Doe" \
73
71
  --email jane@example.com
74
72
 
75
- # Only include check and build stages in CI
73
+ # Use nebula standard in CI (gates 1–6 only)
76
74
  plesty --project-dir ~/projects/plesty-scan-exp init experiment \
77
75
  --name scan_exp \
78
- --ci-stages "check,build"
76
+ --standard nebula
79
77
 
80
78
  # Skip CI file entirely
81
79
  plesty --project-dir ~/projects/plesty-internal-tool init device \
82
80
  --name internal_tool \
83
- --ci-stages ""
81
+ --no-ci
84
82
  ```
85
83
 
86
84
  ## Generated project layout
@@ -90,21 +88,26 @@ plesty-foo-bar/
90
88
  ├── plesty/
91
89
  │ └── foo_bar/
92
90
  │ ├── __init__.py
93
- └── __main__.py
94
- └── base_device.py # device only
91
+ ├── __main__.py
92
+ ├── base_device.py # device only
95
93
  │ └── device.py # device only
96
94
  ├── docs/
97
- └── index.md
95
+ ├── index.md
96
+ │ └── toc.yaml
98
97
  ├── tests/
98
+ │ ├── __init__.py
99
+ │ └── test_foo_bar.py # smoke tests covering all public methods
99
100
  ├── CHANGELOG.md
100
101
  ├── .git/
101
102
  │ └── hooks/
102
- │ └── pre-push # runs plesty check --standard nebula
103
- ├── .gitlab-ci.yml # omitted when --ci-stages ""
103
+ │ └── pre-push # runs plesty check (standard from pyproject.toml)
104
+ ├── .gitlab-ci.yml # omitted when --no-ci
104
105
  ├── .gitignore
105
106
  ├── COPYING
106
107
  ├── LICENSE
107
108
  ├── LICENSES/
109
+ │ ├── GPL-3.0-or-later.txt
110
+ │ └── LGPL-3.0-or-later.txt
108
111
  ├── pyproject.toml
109
112
  ├── README.md
110
113
  └── spdx.tmpl
@@ -114,8 +117,14 @@ The `pyproject.toml` is pre-configured with:
114
117
  - The PyPI distribution name `plesty-foo-bar` (kebab-case)
115
118
  - `packages = ["plesty"]` so the module installs under the `plesty` namespace (`import plesty.foo_bar`)
116
119
  - Dynamic versioning via `versioningit`
117
- - `plesty-lib` as a dependency
118
- - `pytest`, `pytest-cov`, and `mypy` under `[optional-dependencies] dev`
120
+ - `plesty-lib` as a runtime dependency
121
+ - `pytest`, `pytest-cov`, `mypy`, and `plesty-sdk` under `[dependency-groups] dev`
122
+ (included automatically by `uv run` — no `--extra dev` needed)
119
123
  - Sphinx docs settings under `[tool.plesty.docs]`
120
124
 
121
- Use `plesty update` to change author info, the PyPI name, or CI stages after initialisation.
125
+ The generated `.gitlab-ci.yml` uses the unified `hub-module` CI component from `plesty-ci`
126
+ and passes `access_token: $CI_BOT_TOKEN`. Configure a project access token with
127
+ `read_repository` + `write_repository` scopes and **Maintainer** role, then set it as a
128
+ masked CI/CD variable named `CI_BOT_TOKEN`.
129
+
130
+ Use `plesty update` to change author info, the PyPI name, or CI standard after initialisation.
@@ -17,14 +17,11 @@ working directory).
17
17
  | `--author TEXT` | New author name — updates `[project].authors[0].name` in `pyproject.toml` and `Author:` in `spdx.tmpl` |
18
18
  | `--email TEXT` | New author email — updates `[project].authors[0].email` in `pyproject.toml` and `Email:` in `spdx.tmpl` |
19
19
  | `--name NAME` | New PyPI distribution name — updates `[project].name` in `pyproject.toml` |
20
- | `--ci-stages STAGES` | Comma-separated pipeline stages — regenerates `.gitlab-ci.yml`. Pass `""` to remove the CI file. |
20
+ | `--standard STANDARD` | Regenerate `.gitlab-ci.yml` using the given compliance standard (`pixel`, `nebula`, or `quantum`). |
21
+ | `--no-ci` | Remove the `.gitlab-ci.yml` file if present. |
21
22
 
22
23
  At least one option must be provided.
23
24
 
24
- ### Available CI stages
25
-
26
- `check`, `test`, `build`, `release`, `deploy`
27
-
28
25
  ## Examples
29
26
 
30
27
  ```bash
@@ -34,14 +31,14 @@ plesty update --author "Jane Doe" --email jane@example.com
34
31
  # Rename the PyPI distribution
35
32
  plesty update --name plesty-pm100d-device
36
33
 
37
- # Narrow the CI pipeline to check + build only
38
- plesty update --ci-stages "check,build"
34
+ # Regenerate CI with nebula standard
35
+ plesty update --standard nebula
39
36
 
40
37
  # Remove the CI file
41
- plesty update --ci-stages ""
38
+ plesty update --no-ci
42
39
 
43
40
  # Combine multiple updates in one call
44
- plesty update --author "Jane Doe" --email jane@example.com --ci-stages "check,build,release"
41
+ plesty update --author "Jane Doe" --email jane@example.com --standard quantum
45
42
 
46
43
  # Update a project in another directory
47
44
  plesty --project-dir ../plesty-power_meter-device update --author "Jane Doe"
@@ -54,5 +51,5 @@ plesty --project-dir ../plesty-power_meter-device update --author "Jane Doe"
54
51
  identity into all `.py` file headers.
55
52
  - `--name` changes only `[project].name`. The Python package directory name and all import
56
53
  paths in source files are left unchanged.
57
- - `--ci-stages` fully regenerates `.gitlab-ci.yml` from scratch; any manual edits to that
58
- file will be lost.
54
+ - `--standard` fully regenerates `.gitlab-ci.yml` from scratch using the `hub-module` CI
55
+ component; any manual edits to that file will be lost.
@@ -19,19 +19,19 @@
19
19
  "version": "8.30.1"
20
20
  },
21
21
  "type": "secret_detection",
22
- "start_time": "2026-06-24T10:28:20",
23
- "end_time": "2026-06-24T10:28:21",
22
+ "start_time": "2026-06-26T14:32:03",
23
+ "end_time": "2026-06-26T14:32:03",
24
24
  "status": "success",
25
25
  "observability": {
26
26
  "events": [
27
27
  {
28
28
  "event": "collect_secrets_analyzer_scan_metrics_from_pipeline",
29
- "time_s": 0.521656153,
29
+ "time_s": 0.466512051,
30
30
  "exit_code": 0,
31
31
  "git_strategy": "FetchShallow",
32
- "repo_size_kb": 553,
32
+ "repo_size_kb": 591,
33
33
  "commit_count": 1,
34
- "bytes_scanned": 798,
34
+ "bytes_scanned": 947,
35
35
  "pipeline_type": "Tag"
36
36
  },
37
37
  {
@@ -9,3 +9,6 @@ ignore = ["E203", "D401", "D205"]
9
9
 
10
10
  [lint.pydocstyle]
11
11
  convention = "google"
12
+
13
+ [lint.per-file-ignores]
14
+ "tests/**" = ["D100", "D101", "D102", "D103", "D104"]
@@ -20,15 +20,11 @@ dependencies = [
20
20
  {% endif %}
21
21
  ]
22
22
 
23
- [project.optional-dependencies]
24
- dev = [
25
- "pytest>=9.0.0",
26
- "pytest-cov>=5.0",
27
- "mypy>=1.0",
28
- ]
29
-
30
23
  [tool.plesty]
31
24
  standard = "quantum"
25
+ {% if project_type in ('device', 'experiment', 'analyzer') %}
26
+ module_type = "{{ project_type }}"
27
+ {% endif %}
32
28
 
33
29
  [tool.plesty.docs]
34
30
  site-name = "Plesty {{ module_name | replace('_', ' ') | title }} {{ project_type | title }}"
@@ -42,6 +38,14 @@ build-backend = "hatchling.build"
42
38
  [tool.hatch.build.targets.wheel]
43
39
  packages = ["plesty"]
44
40
 
41
+ [dependency-groups]
42
+ dev = [
43
+ "pytest>=9.0.0",
44
+ "pytest-cov>=5.0",
45
+ "mypy>=1.0",
46
+ "plesty-sdk>=0.2.0",
47
+ ]
48
+
45
49
  [tool.uv]
46
50
  cache-dir = ".uv-cache"
47
51
 
@@ -46,6 +46,18 @@ _PLESTY_LIB_PREFIXES = ("plesty.lib", "plesty_lib", "plestylib")
46
46
  _REQUIRED_LICENSE_FILES = ("LICENSE", "COPYING")
47
47
  _COVERAGE_THRESHOLD = 80
48
48
 
49
+ # Device gate constants
50
+ _DEVICE_PIPELINE_GATES = (
51
+ "test_schema_integrity",
52
+ "test_param_key_resolution",
53
+ "test_params_mock",
54
+ "test_funcs_mock",
55
+ "test_lifecycle",
56
+ "test_identity",
57
+ "test_check_errors",
58
+ "test_state_coverage",
59
+ )
60
+
49
61
 
50
62
  # ── Command ────────────────────────────────────────────────────────────────────
51
63
 
@@ -125,6 +137,11 @@ def check_command(
125
137
  if standard == "quantum":
126
138
  check_docs_build(context)
127
139
 
140
+ if standard in ("quantum", "ci"):
141
+ # ── Device gates (d1, d2, …) — only active for device modules ──────────
142
+ # Gate d1 — Device API Pipeline [Device]
143
+ check_device_api_pipeline(project_dir, pyproject_toml)
144
+
128
145
  click.echo("\nAll checks passed.")
129
146
 
130
147
 
@@ -179,6 +196,14 @@ def check_metadata(project_dir: Path, pyproject_toml: dict[str, Any]) -> None:
179
196
  f"'{expected_pkg}' or a parent namespace (e.g. 'plesty'). Found: {wheel_packages}"
180
197
  )
181
198
 
199
+ _KNOWN_MODULE_TYPES = ("device", "experiment", "analyzer", "core")
200
+ module_type = pyproject_toml.get("tool", {}).get("plesty", {}).get("module_type")
201
+ if module_type is not None and module_type not in _KNOWN_MODULE_TYPES:
202
+ raise click.ClickException(
203
+ f"[Metadata] Unknown module_type '{module_type}' in [tool.plesty]. "
204
+ f"Valid values: {', '.join(repr(t) for t in _KNOWN_MODULE_TYPES)}."
205
+ )
206
+
182
207
  click.echo(" ✓ Metadata & Namespace")
183
208
 
184
209
 
@@ -241,6 +266,7 @@ def run_type_checker(project_directory: Path) -> None:
241
266
  "tests",
242
267
  ],
243
268
  gate="Code Hygiene",
269
+ cwd=project_directory,
244
270
  )
245
271
  click.echo(" ✓ Code Hygiene (types)")
246
272
 
@@ -261,6 +287,11 @@ def check_api_interfaces(project_dir: Path, pyproject_toml: dict[str, Any]) -> N
261
287
  pyproject_toml: Parsed pyproject.toml content.
262
288
  """
263
289
  module_name = _module_name_from_toml(pyproject_toml)
290
+
291
+ if module_name == "lib":
292
+ click.echo(" ✓ API Interface Matching (N/A — plesty-lib defines the base classes)")
293
+ return
294
+
264
295
  module_dir = project_dir / "plesty" / module_name
265
296
 
266
297
  violations: list[str] = []
@@ -640,6 +671,66 @@ def check_docs_build(context: ApplicationContext) -> None:
640
671
  click.echo(" ✓ Docs Build")
641
672
 
642
673
 
674
+ # ── Device gates (d1, d2, …) ──────────────────────────────────────────────────
675
+
676
+
677
+ def _is_device_module(pyproject_toml: dict[str, Any]) -> bool:
678
+ """Return True when ``[tool.plesty] module_type = "device"`` is declared.
679
+
680
+ Args:
681
+ pyproject_toml: Parsed pyproject.toml content.
682
+ """
683
+ return pyproject_toml.get("tool", {}).get("plesty", {}).get("module_type") == "device"
684
+
685
+
686
+ def check_device_api_pipeline(project_dir: Path, pyproject_toml: dict[str, Any]) -> None:
687
+ """Gate d1: Verify device modules implement the standard DevicePipeline test suite.
688
+
689
+ Modules that do not declare ``module_type = "device"`` in ``[tool.plesty]``
690
+ are silently skipped. For device modules, all eight mock pipeline gate
691
+ test functions must be present in ``tests/`` and pass without hardware.
692
+
693
+ Args:
694
+ project_dir: Root directory of the target project.
695
+ pyproject_toml: Parsed pyproject.toml content.
696
+ """
697
+ if not _is_device_module(pyproject_toml):
698
+ click.echo(" ✓ Device API Pipeline (N/A — not a device module)")
699
+ return
700
+
701
+ # Collect test node IDs to verify each gate function is present.
702
+ collect = subprocess.run(
703
+ ["pytest", "--collect-only", "-q", "tests/"],
704
+ cwd=str(project_dir),
705
+ capture_output=True,
706
+ text=True,
707
+ )
708
+ collected = collect.stdout + collect.stderr
709
+
710
+ missing = [g for g in _DEVICE_PIPELINE_GATES if g not in collected]
711
+ if missing:
712
+ raise click.ClickException(
713
+ "[Device API] Missing required DevicePipeline gate test(s):\n"
714
+ + "\n".join(f" - {g}" for g in missing)
715
+ + "\nAdd these test functions via plesty.lib.test.device_pipeline.DevicePipeline."
716
+ )
717
+
718
+ # Run only the gate tests.
719
+ gate_filter = " or ".join(_DEVICE_PIPELINE_GATES)
720
+ p = subprocess.run(
721
+ ["pytest", "-k", gate_filter, "--tb=short", "-q", "tests/"],
722
+ cwd=str(project_dir),
723
+ capture_output=True,
724
+ text=True,
725
+ )
726
+ print(p.stdout)
727
+ if p.returncode != 0:
728
+ print(p.stderr)
729
+ raise SystemExit(p.returncode)
730
+
731
+ click.echo(f" ✓ Device API Pipeline (d1 — {len(_DEVICE_PIPELINE_GATES)} mock gates pass)")
732
+
733
+
643
734
  # ── Helpers ────────────────────────────────────────────────────────────────────
644
735
 
645
736
 
@@ -115,7 +115,7 @@ def make_sphinx_config(
115
115
  if settings.toc_file is not None:
116
116
  config["extensions"].append("sphinx_external_toc")
117
117
  config.update(
118
- suppress_warnings=["etoc.toctree"],
118
+ suppress_warnings=["etoc.toctree", "myst.xref_missing"],
119
119
  external_toc_path=settings.toc_file,
120
120
  )
121
121
 
@@ -217,6 +217,7 @@ def generate_gitlab_ci(project_dir: Path, standard: str = "quantum") -> None:
217
217
  " inputs:",
218
218
  f" standard: {standard}",
219
219
  " extra_branch: exp",
220
+ " access_token: $CI_BOT_TOKEN",
220
221
  ]
221
222
 
222
223
  (project_dir / ".gitlab-ci.yml").write_text("\n".join(lines) + "\n", encoding="utf-8")
@@ -43,6 +43,7 @@ cache-dir = ".uv-cache"
43
43
 
44
44
  [tool.plesty]
45
45
  standard = "quantum"
46
+ module_type = "core"
46
47
 
47
48
  [tool.plesty.docs]
48
49
  site-name = "SDK"
@@ -168,6 +168,12 @@ class TestGenerateGitlabCi:
168
168
  content = (tmp_path / ".gitlab-ci.yml").read_text()
169
169
  assert "extra_branch: exp" in content
170
170
 
171
+ def test_access_token_ci_bot_token(self, tmp_path):
172
+ """access_token is set to $CI_BOT_TOKEN for docs deploy."""
173
+ generate_gitlab_ci(tmp_path)
174
+ content = (tmp_path / ".gitlab-ci.yml").read_text()
175
+ assert "access_token: $CI_BOT_TOKEN" in content
176
+
171
177
 
172
178
  # ---------------------------------------------------------------------------
173
179
  # Full end-to-end init (uses real copier with local assets)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes