qprogram-qdac 0.1.0__tar.gz → 0.2.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.
- qprogram_qdac-0.2.0/CHANGELOG.md +23 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/PKG-INFO +12 -46
- qprogram_qdac-0.2.0/README.md +83 -0
- qprogram_qdac-0.2.0/docs/developer/contributing.md +148 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/docs/developer/index.md +3 -12
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/docs/developer/lowering.md +124 -227
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/docs/getting-started.md +22 -64
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/docs/guide/capabilities.md +33 -106
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/docs/guide/index.md +2 -9
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/docs/guide/operations.md +31 -93
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/docs/guide/serialization.md +42 -106
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/docs/index.md +7 -26
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/docs/reference/api.md +6 -22
- qprogram_qdac-0.2.0/docs/reference/index.md +11 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/pyproject.toml +2 -2
- qprogram_qdac-0.2.0/tests/_header.py +43 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/tests/test_serialization.py +17 -11
- qprogram_qdac-0.1.0/CHANGELOG.md +0 -24
- qprogram_qdac-0.1.0/README.md +0 -117
- qprogram_qdac-0.1.0/docs/developer/contributing.md +0 -240
- qprogram_qdac-0.1.0/docs/reference/index.md +0 -21
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/.gitignore +0 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/LICENSE +0 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/src/qprogram_qdac/__init__.py +0 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/src/qprogram_qdac/mixin.py +0 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/src/qprogram_qdac/namespace.py +0 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/src/qprogram_qdac/operations.py +0 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/src/qprogram_qdac/profiles.py +0 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/src/qprogram_qdac/py.typed +0 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/tests/conftest.py +0 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/tests/test_docstring_style.py +0 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/tests/test_mixin.py +0 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/tests/test_namespace.py +0 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/tests/test_operations.py +0 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/tests/test_profile.py +0 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/tests/test_registration.py +0 -0
- {qprogram_qdac-0.1.0 → qprogram_qdac-0.2.0}/zensical.toml +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Notable changes to QProgram QDAC, newest first. Each entry starts life as a news fragment under `changelog/`, and `towncrier build` assembles the fragments into a release section here. See [Contributing](https://qilimanjaro-tech.github.io/qprogram-qdac/developer/contributing.html) for how to add one.
|
|
4
|
+
|
|
5
|
+
<!-- towncrier release notes start -->
|
|
6
|
+
|
|
7
|
+
## 0.2.0 (2026-09-08)
|
|
8
|
+
|
|
9
|
+
This release requires qprogram 0.2, which is what a `require qdac` line is now read against. One thing follows from the core release rather than from anything here: a `.qp` file written before it no longer loads, because its `#!QProgram 1.0` header reads as a later version than the `0.2` the core writes now, and nothing runs backwards. A file whose header is current is carried up instead, since a `require qdac` line naming an earlier major is migrated rather than refused.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- The `require qdac <major>.<minor>` line is read by the rule the core DSL applies to a file header, which needs qprogram 0.2. A line asking for more than the installed package provides is still refused, and the message now names what to install: `file requires qdac 1.0, newer than the installed qdac 0.2.0 — install qdac 1.0 or newer`. A line carrying a patch (`require qdac 0.1.0`) is refused rather than rounded down, since a patch release of this package changes code and never the wire form. A line naming an earlier major loads instead of being refused, so a release that changes an operation's wire form registers a rewrite for it with `qp.register_vendor_migration("qdac", "<major>.<minor>")` and the files users already have go on loading. Nothing in this package's own API changes. ([PR #4](https://github.com/qilimanjaro-tech/qprogram-qdac/pull/4))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## 0.1.0 (2026-08-25)
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- First release. QProgram QDAC adds the `qdac` vendor namespace to the core DSL, covering the QDevil QDAC, a slow high-precision DAC used most often for flux biasing. Importing the package is what turns it on.
|
|
21
|
+
- Four operations covering DC offsets, the waveform engine, and the chassis trigger network.
|
|
22
|
+
- A capability profile describing what a QDAC channel can do, so a program is validated against the hardware before it is run.
|
|
23
|
+
- `.qp` serialization for everything the package adds, registered so that a file naming the `qdac` vendor resolves without the caller importing this package first.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: qprogram-qdac
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: QDevil QDAC vendor extensions for the QProgram pulse-level quantum programming DSL.
|
|
5
5
|
Project-URL: Homepage, https://github.com/qilimanjaro-tech/qprogram-qdac
|
|
6
6
|
Project-URL: Documentation, https://qilimanjaro-tech.github.io/qprogram-qdac/
|
|
@@ -27,26 +27,16 @@ Classifier: Topic :: Scientific/Engineering :: Physics
|
|
|
27
27
|
Classifier: Topic :: Scientific/Engineering :: Quantum Computing
|
|
28
28
|
Classifier: Typing :: Typed
|
|
29
29
|
Requires-Python: >=3.11
|
|
30
|
-
Requires-Dist: qprogram>=0.
|
|
30
|
+
Requires-Dist: qprogram>=0.2.0
|
|
31
31
|
Description-Content-Type: text/markdown
|
|
32
32
|
|
|
33
33
|
# QProgram QDAC
|
|
34
34
|
|
|
35
|
-
[](https://github.com/qilimanjaro-tech/qprogram-qdac/actions/workflows/tests.yml)
|
|
36
|
-
[](https://github.com/qilimanjaro-tech/qprogram-qdac/actions/workflows/code_quality.yml)
|
|
37
|
-
[](https://www.python.org/)
|
|
38
|
-
[](LICENSE)
|
|
35
|
+
[](https://github.com/qilimanjaro-tech/qprogram-qdac/actions/workflows/tests.yml) [](https://github.com/qilimanjaro-tech/qprogram-qdac/actions/workflows/code_quality.yml) [](https://www.python.org/) [](LICENSE)
|
|
39
36
|
|
|
40
|
-
QDevil QDAC extensions for
|
|
41
|
-
[QProgram](https://github.com/qilimanjaro-tech/qprogram), the pulse-level
|
|
42
|
-
quantum programming DSL. The QDAC is a slow high-precision DAC, used most
|
|
43
|
-
often for flux biasing.
|
|
37
|
+
QDevil QDAC extensions for [QProgram](https://github.com/qilimanjaro-tech/qprogram), the pulse-level quantum programming DSL. The QDAC is a slow high-precision DAC, used most often for flux biasing.
|
|
44
38
|
|
|
45
|
-
The core DSL knows nothing about any instrument. This package adds the
|
|
46
|
-
`qdac` vendor namespace to it: four operations covering DC offsets, the
|
|
47
|
-
waveform engine, and the chassis trigger network, a capability profile that
|
|
48
|
-
says what a QDAC channel can do, and `.qp` serialization for all of it.
|
|
49
|
-
Importing the package is what turns those on.
|
|
39
|
+
The core DSL knows nothing about any instrument. This package adds the `qdac` vendor namespace to it: four operations covering DC offsets, the waveform engine, and the chassis trigger network, a capability profile that says what a QDAC channel can do, and `.qp` serialization for all of it. Importing the package is what turns those on.
|
|
50
40
|
|
|
51
41
|
## Installation
|
|
52
42
|
|
|
@@ -90,43 +80,19 @@ data = result.get(m0)
|
|
|
90
80
|
print(data.dims, data.shape) # ('bias', 'IQ') (41, 2)
|
|
91
81
|
```
|
|
92
82
|
|
|
93
|
-
The flux bias comes from the QDAC, the drive and readout from whatever
|
|
94
|
-
vendor owns those buses. One program describes both, and the nesting is
|
|
95
|
-
what makes a mixed platform accept it: the bias sweep dispatches from the
|
|
96
|
-
host, one upload per point, while the `average` block under it runs in the
|
|
97
|
-
real-time sequencer. Flatten the two into one block and no domain runs
|
|
98
|
-
both. `sync` names its buses because the argument-less form syncs every bus
|
|
99
|
-
in the program, and a QDAC channel is not something a real-time barrier can
|
|
100
|
-
wait on.
|
|
83
|
+
The flux bias comes from the QDAC, the drive and readout from whatever vendor owns those buses. One program describes both, and the nesting is what makes a mixed platform accept it: the bias sweep dispatches from the host, one upload per point, while the `average` block under it runs in the real-time sequencer. Flatten the two into one block and no domain runs both. `sync` names its buses because the argument-less form syncs every bus in the program, and a QDAC channel is not something a real-time barrier can wait on.
|
|
101
84
|
|
|
102
85
|
## What you get
|
|
103
86
|
|
|
104
|
-
- **Four operations under one namespace.** `set_offset` holds a DC voltage
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
- **Host-side sweeps, declared rather than guessed.** The QDAC has no FPGA,
|
|
110
|
-
so a swept parameter has to be re-uploaded from the host between
|
|
111
|
-
iterations. The `qdac-default-v1` profile says so through a domain
|
|
112
|
-
constraint, and `qp.explain(program, capabilities)` prints the enclosing
|
|
113
|
-
loop as `[host]` instead of failing at compile time.
|
|
114
|
-
- **Single-channel by declaration.** The profile lists only single-channel
|
|
115
|
-
waveform tokens. An IQ waveform on a QDAC bus is a `missing-capability`
|
|
116
|
-
error from `qp.validate`, not a runtime surprise.
|
|
117
|
-
- **Serialization included.** Every operation round-trips through the `.qp`
|
|
118
|
-
text format, under a `require qdac 0.1` header line. A file that names
|
|
119
|
-
`qdac` activates this package on load through its entry point, so the
|
|
120
|
-
reader does not have to import it first.
|
|
121
|
-
- **Typed access.** `QProgram` from this package is the core builder with a
|
|
122
|
-
typed `.qdac` property. `QdacMixin` composes with other vendor mixins
|
|
123
|
-
when a platform spans several instruments.
|
|
87
|
+
- **Four operations under one namespace.** `set_offset` holds a DC voltage on a channel, `play` uploads an envelope to the channel's waveform engine with explicit dwell, delay, repetitions and stepped mode, and `set_trigger` / `wait_trigger` wire the channel into the chassis trigger network so QDAC sequences line up with instruments driving other buses.
|
|
88
|
+
- **Host-side sweeps, declared rather than guessed.** The QDAC has no FPGA, so a swept parameter has to be re-uploaded from the host between iterations. The `qdac-default-v1` profile says so through a domain constraint, and `qp.explain(program, capabilities)` prints the enclosing loop as `[host]` instead of failing at compile time.
|
|
89
|
+
- **Single-channel by declaration.** The profile lists only single-channel waveform tokens. An IQ waveform on a QDAC bus is a `missing-capability` error from `qp.validate`, not a runtime surprise.
|
|
90
|
+
- **Serialization included.** Every operation round-trips through the `.qp` text format, under a `require qdac 0.2` header line. A file that names `qdac` activates this package on load through its entry point, so the reader does not have to import it first.
|
|
91
|
+
- **Typed access.** `QProgram` from this package is the core builder with a typed `.qdac` property. `QdacMixin` composes with other vendor mixins when a platform spans several instruments.
|
|
124
92
|
|
|
125
93
|
## Documentation
|
|
126
94
|
|
|
127
|
-
Full documentation, including the operation reference, the capability
|
|
128
|
-
profile, and the generated API reference, lives at
|
|
129
|
-
<https://qilimanjaro-tech.github.io/qprogram-qdac/>.
|
|
95
|
+
Full documentation, including the operation reference, the capability profile, and the generated API reference, lives at <https://qilimanjaro-tech.github.io/qprogram-qdac/>.
|
|
130
96
|
|
|
131
97
|
## Development
|
|
132
98
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# QProgram QDAC
|
|
2
|
+
|
|
3
|
+
[](https://github.com/qilimanjaro-tech/qprogram-qdac/actions/workflows/tests.yml) [](https://github.com/qilimanjaro-tech/qprogram-qdac/actions/workflows/code_quality.yml) [](https://www.python.org/) [](LICENSE)
|
|
4
|
+
|
|
5
|
+
QDevil QDAC extensions for [QProgram](https://github.com/qilimanjaro-tech/qprogram), the pulse-level quantum programming DSL. The QDAC is a slow high-precision DAC, used most often for flux biasing.
|
|
6
|
+
|
|
7
|
+
The core DSL knows nothing about any instrument. This package adds the `qdac` vendor namespace to it: four operations covering DC offsets, the waveform engine, and the chassis trigger network, a capability profile that says what a QDAC channel can do, and `.qp` serialization for all of it. Importing the package is what turns those on.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install qprogram-qdac
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The only dependency is `qprogram` itself.
|
|
16
|
+
|
|
17
|
+
## A first program
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import qprogram as qp
|
|
21
|
+
from qprogram import BusSchema
|
|
22
|
+
from qprogram.waveforms import IQPair, Square
|
|
23
|
+
from qprogram_qdac import QProgram
|
|
24
|
+
|
|
25
|
+
schema = BusSchema.flux_tunable_transmon()
|
|
26
|
+
q = schema.q
|
|
27
|
+
|
|
28
|
+
program = QProgram(label="flux-spectroscopy", schema=schema)
|
|
29
|
+
bias = program.variable("bias", units="V")
|
|
30
|
+
|
|
31
|
+
with program.sweep(bias).from_range(-0.2, 0.2, 0.01):
|
|
32
|
+
program.qdac.set_offset(q[0].flux, bias)
|
|
33
|
+
with program.average(shots=100):
|
|
34
|
+
program.play(q[0].drive, "pi_pulse")
|
|
35
|
+
program.sync([q[0].drive, q[0].readout])
|
|
36
|
+
m0 = program.measure(q[0].readout, "readout", "weights")
|
|
37
|
+
|
|
38
|
+
resolved = program.with_waveforms(
|
|
39
|
+
{
|
|
40
|
+
"pi_pulse": IQPair(Square(0.5, 40), Square(0.0, 40)),
|
|
41
|
+
"readout": IQPair(Square(1.0, 2000), Square(0.0, 2000)),
|
|
42
|
+
"weights": IQPair(Square(1.0, 2000), Square(1.0, 2000)),
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
result = qp.simulate(resolved)
|
|
47
|
+
data = result.get(m0)
|
|
48
|
+
print(data.dims, data.shape) # ('bias', 'IQ') (41, 2)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The flux bias comes from the QDAC, the drive and readout from whatever vendor owns those buses. One program describes both, and the nesting is what makes a mixed platform accept it: the bias sweep dispatches from the host, one upload per point, while the `average` block under it runs in the real-time sequencer. Flatten the two into one block and no domain runs both. `sync` names its buses because the argument-less form syncs every bus in the program, and a QDAC channel is not something a real-time barrier can wait on.
|
|
52
|
+
|
|
53
|
+
## What you get
|
|
54
|
+
|
|
55
|
+
- **Four operations under one namespace.** `set_offset` holds a DC voltage on a channel, `play` uploads an envelope to the channel's waveform engine with explicit dwell, delay, repetitions and stepped mode, and `set_trigger` / `wait_trigger` wire the channel into the chassis trigger network so QDAC sequences line up with instruments driving other buses.
|
|
56
|
+
- **Host-side sweeps, declared rather than guessed.** The QDAC has no FPGA, so a swept parameter has to be re-uploaded from the host between iterations. The `qdac-default-v1` profile says so through a domain constraint, and `qp.explain(program, capabilities)` prints the enclosing loop as `[host]` instead of failing at compile time.
|
|
57
|
+
- **Single-channel by declaration.** The profile lists only single-channel waveform tokens. An IQ waveform on a QDAC bus is a `missing-capability` error from `qp.validate`, not a runtime surprise.
|
|
58
|
+
- **Serialization included.** Every operation round-trips through the `.qp` text format, under a `require qdac 0.2` header line. A file that names `qdac` activates this package on load through its entry point, so the reader does not have to import it first.
|
|
59
|
+
- **Typed access.** `QProgram` from this package is the core builder with a typed `.qdac` property. `QdacMixin` composes with other vendor mixins when a platform spans several instruments.
|
|
60
|
+
|
|
61
|
+
## Documentation
|
|
62
|
+
|
|
63
|
+
Full documentation, including the operation reference, the capability profile, and the generated API reference, lives at <https://qilimanjaro-tech.github.io/qprogram-qdac/>.
|
|
64
|
+
|
|
65
|
+
## Development
|
|
66
|
+
|
|
67
|
+
The project uses [uv](https://docs.astral.sh/uv/).
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
git clone https://github.com/qilimanjaro-tech/qprogram-qdac
|
|
71
|
+
cd qprogram-qdac
|
|
72
|
+
|
|
73
|
+
uv sync --group dev # create .venv and install everything
|
|
74
|
+
uv run pytest # run the test suite
|
|
75
|
+
uv run ruff check . # lint
|
|
76
|
+
uv run ruff format . # format
|
|
77
|
+
uv run ty check # type-check
|
|
78
|
+
uv run --group docs zensical serve # preview the documentation
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
Apache License 2.0 - see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
The short version: open a small pull request, run the linter and the tests, write the docs for anything that changes user-visible behavior.
|
|
4
|
+
|
|
5
|
+
## Before you start
|
|
6
|
+
|
|
7
|
+
Skim two things first.
|
|
8
|
+
|
|
9
|
+
1. **[Lowering onto hardware](lowering.md).** It explains the five modules, the registration hooks, and what a platform does with each operation. Almost every change touches one of those.
|
|
10
|
+
2. **The core DSL's developer guide**, in particular [building a vendor extension](https://qilimanjaro-tech.github.io/qprogram/developer/vendor-extensions.html), the template this package follows, and [capability protocol internals](https://qilimanjaro-tech.github.io/qprogram/developer/capability-protocol.html), the normative account of tokens, slots and predicates. The AST, the validator, and the `.qp` format live there too. A change to this package that needs a core change is usually a core issue instead.
|
|
11
|
+
|
|
12
|
+
Then decide which repository the change belongs in. An operation only a QDAC can do belongs here. Anything a second backend would also want belongs in the core, so every backend gets it.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## Development workflow
|
|
16
|
+
|
|
17
|
+
1. **Install the package.**
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
uv sync --group dev
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
2. **Install the docs environment** (optional, only if you change docs).
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uv sync --group docs
|
|
27
|
+
uv run --group docs zensical serve
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`mkdocstrings` imports the package to render the API reference, so the docs build needs the project installed, not just the docs tooling.
|
|
31
|
+
|
|
32
|
+
3. **Make your change.**
|
|
33
|
+
|
|
34
|
+
4. **Lint and format.**
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
uv run ruff check .
|
|
38
|
+
uv run ruff format .
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
5. **Type-check.**
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
uv run ty check
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
6. **Run the tests.**
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
uv run pytest
|
|
51
|
+
uv run pytest --cov=qprogram_qdac # check coverage on touched files
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
7. **Update the docs.** Anything user-visible needs an entry in the relevant guide page and, for a new class or method, an entry in [`docs/reference/api.md`](../reference/api.md), whose `members:` lists are explicit.
|
|
55
|
+
|
|
56
|
+
8. **Add a changelog entry.** Anything a caller would notice gets one news fragment under `changelog/`, named `<pr-number>.<type>.md`, where the type is `added`, `changed`, `fixed`, or `removed`.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
uv run towncrier create 123.added.md
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Write one or two sentences about what changed for somebody using the package. A fragment written before the pull request has a number takes a `+` prefix and any name, as in `+trigger-network-reset.added.md`; rename it once the number exists so the entry carries a link. Internal refactors, test-only changes, and docs corrections do not need one.
|
|
63
|
+
|
|
64
|
+
9. **Open the pull request.** The workflows under `.github/workflows/` run on it. `tests.yml` runs the suite on Python 3.11 and 3.14 for a pull request, across 3.11 through 3.14 on a push to `main`, and uploads coverage from the 3.13 job. `code_quality.yml` runs `ruff check` and `ruff format --diff` once on 3.13, then `ty check` once per supported version. `docs.yml` builds this site, and deploys it on a push to `main`.
|
|
65
|
+
|
|
66
|
+
## What "small PR" means
|
|
67
|
+
|
|
68
|
+
One concept per pull request. A new operation plus a new predicate plus a serialization fix is three pull requests. Each one is easier to review, easier to revert, and easier to bisect against.
|
|
69
|
+
|
|
70
|
+
## The checklist for a new operation
|
|
71
|
+
|
|
72
|
+
All five code edits are listed in [Adding an operation](lowering.md#adding-an-operation). A complete pull request carries four kinds of change:
|
|
73
|
+
|
|
74
|
+
| Kind | What it means |
|
|
75
|
+
|-------------------|----------------------------------------------------------------------------------------------------------------------------------|
|
|
76
|
+
| **Code** | The node in `operations.py`, the method on `QdacNamespace`, the token in `profiles.py` twice, the registration in `__init__.py`. |
|
|
77
|
+
| **Tests** | One test per module in `tests/`: operations, namespace, serialization, registration, profile. |
|
|
78
|
+
| **Docs** | The operation's row and section in the user guide, its wire form in the serialization page, and anything the platform must know in [Lowering onto hardware](lowering.md). |
|
|
79
|
+
| **API reference** | The class and the namespace method added to the `members:` lists in `docs/reference/api.md`. |
|
|
80
|
+
|
|
81
|
+
Adding an operation is a minor version bump of the package, which is also the vendor protocol version in the `require qdac <major>.<minor>` header. Removing or renaming one, or changing what it means on the wire, is a major bump — and it needs a [migration](lowering.md#changing-one-that-already-exists) registered with `qp.register_vendor_migration("qdac", ...)` under the version that ships it, so the files users already have keep loading.
|
|
82
|
+
|
|
83
|
+
## Style notes
|
|
84
|
+
|
|
85
|
+
These are the rules the project enforces; they are not exhaustive. All of them are configured in `pyproject.toml`.
|
|
86
|
+
|
|
87
|
+
- **Ruff with `preview = true` and `select = ["ALL"]`**, minus a curated ignore list written as rule *names* rather than codes, so the reason for each exemption reads off the config. Suppression comments use the same form: `# ruff: ignore[import-outside-top-level]`, never a numeric code. Line length is 120 and the formatter owns it. Expect the linter to push back on most external code.
|
|
88
|
+
- **Docstrings are enforced.** Preview mode means both the `D` and the `DOC` families run, under the Google convention. Every parameter gets a `name (type): Description.` entry, with the parenthesized type as house style even though the signature is annotated. A non-`None` return needs a `Returns:` section unless the summary line already opens with the word "Return", and every exception a caller can observe needs a `Raises:` entry. Constructor arguments are documented on the **class** docstring, since `merge_init_into_class` is on and `undocumented-public-init` is ignored. `Attributes:` is for a value object whose fields are the interface and are not all constructor arguments.
|
|
89
|
+
- **Cross-references are Markdown, not Sphinx roles.** Write `` [`SetOffset`][qprogram_qdac.SetOffset] `` for a target this site documents, and `` [`Expression`][qprogram.Expression] `` for one the core DSL documents: `zensical.toml` loads that project's published `objects.inv` as an `inventories` entry, so a core type resolves to its page on that site. Plain `` `Expression` `` is for anything neither site renders, such as a builtin or a stdlib name. A Sphinx role such as `` :class:`~qprogram.Expression` `` would reach the page as literal text, since mkdocstrings reads a docstring as Markdown and has no reStructuredText reader; `tests/test_docstring_style.py` fails the suite on one. The docs build runs with `--strict`, so a cross-reference neither site can resolve fails CI as well.
|
|
90
|
+
- **Every file carries the Apache header**, the standard 13-line notice with `Copyright 2026 Qilimanjaro Quantum Tech`, above the module docstring. Ruff's `missing-copyright-notice` rule fails the lint on a file without it. Tests included.
|
|
91
|
+
- **Type hints everywhere.** `ty` is in the dev group and checks `src`, and CI runs it once per supported Python version.
|
|
92
|
+
- **Function-style tests.** No test classes. Use fixtures from `tests/conftest.py` and parametrization. Tests are exempt from the `ANN`, `D`, and `DOC` families, so a test needs no docstring, but one explaining *why* a case exists is worth writing.
|
|
93
|
+
- **Two-space indentation in `.qp` fixtures.** That is what the writer emits.
|
|
94
|
+
- **No new runtime dependencies.** This package depends on `qprogram` and nothing else, and that is on purpose. A vendor SDK belongs in the platform library that drives the instrument, not in the package that describes it.
|
|
95
|
+
|
|
96
|
+
## What goes where
|
|
97
|
+
|
|
98
|
+
| Change kind | Where it lands |
|
|
99
|
+
|------------------------------------|-----------------------------------------------------------------------|
|
|
100
|
+
| New operation | `src/qprogram_qdac/operations.py` plus the four other edits. |
|
|
101
|
+
| New method on the namespace | `src/qprogram_qdac/namespace.py`. |
|
|
102
|
+
| New capability token or predicate | `src/qprogram_qdac/profiles.py`. |
|
|
103
|
+
| New limit | `src/qprogram_qdac/profiles.py`, in `QDAC_DEFAULT_V1.limits`. |
|
|
104
|
+
| New profile bundle | `src/qprogram_qdac/profiles.py`, registered from `__init__.py`. |
|
|
105
|
+
| Registration or the typed program | `src/qprogram_qdac/__init__.py`. |
|
|
106
|
+
| Docs | `docs/`; the nav lives in `zensical.toml`. |
|
|
107
|
+
| Anything about the AST or `.qp` | The core DSL, not here. |
|
|
108
|
+
|
|
109
|
+
## Releasing
|
|
110
|
+
|
|
111
|
+
`CHANGELOG.md` is assembled from the fragments in `changelog/`, so it is written once per release rather than edited per PR. A release goes out from its own pull request:
|
|
112
|
+
|
|
113
|
+
1. Branch from an up-to-date `main`.
|
|
114
|
+
2. Set the new version. This writes both `pyproject.toml` and `uv.lock`; nothing else holds the literal, since the version is read from the installed metadata.
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
uv version 0.2.0
|
|
118
|
+
uv sync
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
3. Assemble the changelog. Pass the version explicitly. Left to guess, towncrier reads the *installed* metadata and can render a stale number into a heading that is never regenerated.
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
uv run towncrier build --draft --version "$(uv version --short)" # preview
|
|
125
|
+
uv run towncrier build --version "$(uv version --short)" --yes
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
4. Read the rendered section and edit it. Fragments are written weeks apart by different people and rarely read as one voice when they land together.
|
|
129
|
+
5. Open the release PR, and merge it once CI is green.
|
|
130
|
+
6. Create the GitHub Release on the merge commit, tagged with the version now in `pyproject.toml` and no `v` prefix. Publishing it starts `publish.yml`, which runs `uv build` for the wheel and the sdist, checks both with `twine check`, and uploads them through trusted publishing. Pre-releases publish too.
|
|
131
|
+
7. Approve the deployment. The run waits on the `pypi` environment until a reviewer releases it. PyPI never lets a file be replaced, so this approval is the last point at which a wrong version can be stopped.
|
|
132
|
+
|
|
133
|
+
`publish.yml` can also be started by hand from the Actions tab, which is how the first release goes out and how a run that failed on a transient error is retried. A manual run takes three inputs: `platform` chooses between PyPI and the `qilimanjaro` AWS CodeArtifact domain, `repository` names the CodeArtifact repository, and `dry_run` builds and validates the distributions without uploading them.
|
|
134
|
+
|
|
135
|
+
## Commit messages
|
|
136
|
+
|
|
137
|
+
Short, imperative, explanatory. The body matters more than the title: explain *why*, not *what*. The history in `git log` is a good template.
|
|
138
|
+
|
|
139
|
+
## License and attribution
|
|
140
|
+
|
|
141
|
+
`qprogram-qdac` is licensed under the Apache License, Version 2.0. The full text is in the `LICENSE` file at the repository root, and every source file carries the matching 13-line header. By opening a pull request you agree to license your contribution under the same terms.
|
|
142
|
+
|
|
143
|
+
## Where to ask
|
|
144
|
+
|
|
145
|
+
- **Bug reports and feature requests.** Open a GitHub issue; the templates are short on purpose. Include a minimal program and, for anything about the file format, its `.qp` text. A problem that reproduces without importing `qprogram_qdac` belongs in the core repository.
|
|
146
|
+
- **Design discussion.** Open an issue naming the affected code, the behavior you expect, and the guide page that documents it.
|
|
147
|
+
|
|
148
|
+
Pull requests with a clear scope and tests are the fastest path to a merge.
|
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
# Developer guide
|
|
2
2
|
|
|
3
|
-
These pages document the internals: what you need to drive real hardware from
|
|
4
|
-
a QDAC program, and what you need to change this package.
|
|
3
|
+
These pages document the internals: what you need to drive real hardware from a QDAC program, and what you need to change this package.
|
|
5
4
|
|
|
6
5
|
| Topic | What you find there |
|
|
7
6
|
|---------------------------------------|----------------------------------------------------------------------------------------------------------------|
|
|
8
7
|
| [Lowering onto hardware](lowering.md) | The module layout, the registration hooks, what a platform does with each operation, and how to add a new one. |
|
|
9
8
|
| [Contributing](contributing.md) | The uv workflow, the lint and test gate, style rules, and the checklist for a change. |
|
|
10
9
|
|
|
11
|
-
The [User guide](../guide/index.md) covers the same operations from the caller's
|
|
12
|
-
side, and the [API reference](../reference/api.md) is generated from the
|
|
13
|
-
docstrings under `src/`, so the code and the reference move together.
|
|
10
|
+
The [User guide](../guide/index.md) covers the same operations from the caller's side, and the [API reference](../reference/api.md) is generated from the docstrings under `src/`, so the code and the reference move together.
|
|
14
11
|
|
|
15
|
-
This package is only the QDAC half. The AST, the `.qp` format, the capability
|
|
16
|
-
protocol, and the reference executor all live in the core DSL. Two of its
|
|
17
|
-
developer pages are the background for everything here:
|
|
18
|
-
[building a vendor extension](https://qilimanjaro-tech.github.io/qprogram/developer/vendor-extensions.html)
|
|
19
|
-
is the template this package follows, and
|
|
20
|
-
[capability protocol internals](https://qilimanjaro-tech.github.io/qprogram/developer/capability-protocol.html)
|
|
21
|
-
is the normative account of tokens, slots and predicates.
|
|
12
|
+
This package is only the QDAC half. The AST, the `.qp` format, the capability protocol, and the reference executor all live in the core DSL. Two of its developer pages are the background for everything here: [building a vendor extension](https://qilimanjaro-tech.github.io/qprogram/developer/vendor-extensions.html) is the template this package follows, and [capability protocol internals](https://qilimanjaro-tech.github.io/qprogram/developer/capability-protocol.html) is the normative account of tokens, slots and predicates.
|