db-process 0.1.0__tar.gz → 0.3.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.
- {db_process-0.1.0 → db_process-0.3.1}/LICENSE +2 -2
- db_process-0.3.1/PKG-INFO +215 -0
- db_process-0.3.1/README.md +199 -0
- {db_process-0.1.0 → db_process-0.3.1}/db_process/__init__.py +89 -83
- db_process-0.3.1/db_process/__main__.py +6 -0
- db_process-0.3.1/db_process/cli.py +92 -0
- {db_process-0.1.0 → db_process-0.3.1}/db_process/commands.py +449 -449
- {db_process-0.1.0 → db_process-0.3.1}/db_process/executable.py +76 -76
- {db_process-0.1.0 → db_process-0.3.1}/db_process/runner.py +330 -298
- db_process-0.3.1/db_process.egg-info/PKG-INFO +215 -0
- {db_process-0.1.0 → db_process-0.3.1}/db_process.egg-info/SOURCES.txt +11 -1
- db_process-0.3.1/db_process.egg-info/entry_points.txt +2 -0
- db_process-0.3.1/pyproject.toml +41 -0
- db_process-0.3.1/tests/test_cli.py +108 -0
- db_process-0.3.1/tests/test_cli_output.py +174 -0
- {db_process-0.1.0 → db_process-0.3.1}/tests/test_commands.py +316 -316
- db_process-0.3.1/tests/test_commands_extra.py +169 -0
- {db_process-0.1.0 → db_process-0.3.1}/tests/test_executable.py +47 -47
- db_process-0.3.1/tests/test_executable_defaults.py +92 -0
- db_process-0.3.1/tests/test_runner.py +441 -0
- db_process-0.3.1/tests/test_runner_subprocess.py +84 -0
- db_process-0.3.1/tests/test_status.py +59 -0
- db_process-0.1.0/PKG-INFO +0 -18
- db_process-0.1.0/README.md +0 -2
- db_process-0.1.0/db_process.egg-info/PKG-INFO +0 -18
- db_process-0.1.0/pyproject.toml +0 -29
- {db_process-0.1.0 → db_process-0.3.1}/db_process.egg-info/dependency_links.txt +0 -0
- {db_process-0.1.0 → db_process-0.3.1}/db_process.egg-info/requires.txt +0 -0
- {db_process-0.1.0 → db_process-0.3.1}/db_process.egg-info/top_level.txt +0 -0
- {db_process-0.1.0 → db_process-0.3.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2026
|
|
3
|
+
Copyright (c) 2026 DesignBuilder Software
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
18
18
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: db-process
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: Python interface to DesignBuilder command line processing.
|
|
5
|
+
Author: DesignBuilder Software
|
|
6
|
+
Project-URL: Homepage, https://github.com/DesignBuilderSoftware/db-process
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/DesignBuilderSoftware/db-process/issues
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: psutil>=5.9.0
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: pytest; extra == "dev"
|
|
14
|
+
Requires-Dist: ruff; extra == "dev"
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# db-process
|
|
18
|
+
|
|
19
|
+
Python interface to DesignBuilder's command-line driver — typed `/process=` commands, subprocess execution, and process discovery.
|
|
20
|
+
|
|
21
|
+
DesignBuilder is a Windows GUI app, but it exposes a `/process=` argument that runs a sequence of commands non-interactively and exits. `db-process` wraps that surface in real Python: dataclass commands instead of stringly-typed flags, a `ProcessChain` builder, blocking and non-blocking runners, and helpers to find/kill the process.
|
|
22
|
+
|
|
23
|
+
> For diagnostic-log parsing see [db-diag](https://github.com/DesignBuilderSoftware/db-diag).
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install db-process
|
|
29
|
+
# or, from the cloned repo:
|
|
30
|
+
pip install -e .[dev]
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Requires Python 3.10+ and `psutil`. DesignBuilder itself only runs on Windows;
|
|
34
|
+
on other platforms, the package imports fine but `run()` and the process
|
|
35
|
+
helpers will raise `FileNotFoundError`.
|
|
36
|
+
|
|
37
|
+
## Quick start
|
|
38
|
+
|
|
39
|
+
### Python — run a model with a chain of commands
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from db_process import ProcessChain, Screen, run
|
|
43
|
+
|
|
44
|
+
chain = (
|
|
45
|
+
ProcessChain()
|
|
46
|
+
.use_sim_manager()
|
|
47
|
+
.switch_screen(Screen.SIMULATION)
|
|
48
|
+
.sim_start_date(1, 1)
|
|
49
|
+
.sim_end_date(31, 12)
|
|
50
|
+
.change_attribute("OccupancyValue", 0.5)
|
|
51
|
+
.run()
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
result = run("models/office.dsb", chain, timeout=600)
|
|
55
|
+
print(result.success, result.duration_seconds)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Python — convenience factories for common runs
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from db_process import eplus_simulation, run
|
|
62
|
+
|
|
63
|
+
# A pre-built ProcessChain for "open model, run EnergyPlus, close".
|
|
64
|
+
result = run("models/office.dsb", eplus_simulation())
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Other factories: `sbem_calculation`, `export_xml`, `heating_and_cooling_design`,
|
|
68
|
+
`daylighting`, `cfd_simulation`.
|
|
69
|
+
|
|
70
|
+
### Python — non-blocking with idle-detection kill
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from db_process import run_async
|
|
74
|
+
|
|
75
|
+
handle = run_async("models/office.dsb")
|
|
76
|
+
# Block until DesignBuilder finishes its work and CPU drops, then kill it.
|
|
77
|
+
handle.kill_when_idle(idle_threshold=10, cpu_threshold=0.1)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`kill_when_idle` is the workaround for runs where DesignBuilder finishes the
|
|
81
|
+
calculation but doesn't exit — common with the GUI Sim Manager path.
|
|
82
|
+
|
|
83
|
+
### CLI
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
db-process status # is DesignBuilder running? show pid + exe path
|
|
87
|
+
db-process open # launch DesignBuilder
|
|
88
|
+
db-process open path/to.dsb # launch with a model
|
|
89
|
+
db-process close # kill any running DesignBuilder
|
|
90
|
+
db-process restart [model] # close + open (with a 1.5 s settle)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`db-process` is the entry point installed by the package; you can also run it as `python -m db_process`.
|
|
94
|
+
|
|
95
|
+
## Public API
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from db_process import (
|
|
99
|
+
# Executable discovery
|
|
100
|
+
find_designbuilder, # () -> Path
|
|
101
|
+
|
|
102
|
+
# Process status
|
|
103
|
+
is_running, find_process, status, # status() -> ProcessStatus
|
|
104
|
+
kill_process, kill_when_idle,
|
|
105
|
+
ProcessStatus, # is_running, pid, exe_path
|
|
106
|
+
|
|
107
|
+
# Run
|
|
108
|
+
run, run_async, RunHandle, RunResult,
|
|
109
|
+
|
|
110
|
+
# Command model
|
|
111
|
+
ProcessChain, Screen,
|
|
112
|
+
SwitchScreen, RunCalculation, TabChange,
|
|
113
|
+
SimStartDate, SimEndDate, ChangeAttributeValue,
|
|
114
|
+
ExternalCommand, ImportModelData, ImportLibraryData,
|
|
115
|
+
ExportAsXML, UseSimManager, NoClose,
|
|
116
|
+
|
|
117
|
+
# Convenience factories
|
|
118
|
+
eplus_simulation, sbem_calculation, export_xml,
|
|
119
|
+
heating_and_cooling_design, daylighting, cfd_simulation,
|
|
120
|
+
)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Executable discovery
|
|
124
|
+
|
|
125
|
+
`find_designbuilder(exe_path=None)` resolves DesignBuilder.exe in this order:
|
|
126
|
+
|
|
127
|
+
1. The explicit `exe_path` argument, if given.
|
|
128
|
+
2. `DESIGNBUILDER_EXE` environment variable.
|
|
129
|
+
3. `C:\Program Files (x86)\DesignBuilder\DesignBuilder.exe`,
|
|
130
|
+
then `C:\Program Files\DesignBuilder\DesignBuilder.exe`.
|
|
131
|
+
4. The system `PATH` (`shutil.which("DesignBuilder")`).
|
|
132
|
+
|
|
133
|
+
Raises `FileNotFoundError` with a hint to set `DESIGNBUILDER_EXE` if none match.
|
|
134
|
+
|
|
135
|
+
### Process status
|
|
136
|
+
|
|
137
|
+
`status()` is a one-shot snapshot:
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
from db_process import status
|
|
141
|
+
|
|
142
|
+
s = status()
|
|
143
|
+
# ProcessStatus(is_running=True, pid=12345, exe_path='C:\\...\\DesignBuilder.exe')
|
|
144
|
+
if not s.is_running and s.exe_path:
|
|
145
|
+
# Discovered but not running — safe to launch.
|
|
146
|
+
...
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`exe_path` is populated regardless of whether the process is running, so
|
|
150
|
+
callers can decide whether to launch without a second `find_designbuilder`
|
|
151
|
+
call.
|
|
152
|
+
|
|
153
|
+
### `ProcessChain` — building a `/process=` argument
|
|
154
|
+
|
|
155
|
+
`ProcessChain` is a fluent builder for the `/process=` command sequence
|
|
156
|
+
documented in DesignBuilder Help. Example output of `chain.to_string()`:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
/process=UseSimManager, miGSS, SimStartDate 1 1, SimEndDate 31 12,
|
|
160
|
+
ChangeAttributeValue OccupancyValue 0.5, miTUpdate
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Every command is also exposed as a plain dataclass, so you can construct
|
|
164
|
+
chains without the builder when that's clearer.
|
|
165
|
+
|
|
166
|
+
## Compatibility
|
|
167
|
+
|
|
168
|
+
- **DesignBuilder**: any version that supports the `/process=` argument.
|
|
169
|
+
Tested against the v25.1 / v26.1 lines.
|
|
170
|
+
- **Python**: 3.10+.
|
|
171
|
+
- **OS**: Windows for live runs. The command model is pure Python and imports on any platform — useful for unit tests on Linux CI.
|
|
172
|
+
|
|
173
|
+
## Development
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
pip install -e .[dev]
|
|
177
|
+
pytest
|
|
178
|
+
ruff check .
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Tests are split by area:
|
|
182
|
+
|
|
183
|
+
| File | Covers |
|
|
184
|
+
| --- | --- |
|
|
185
|
+
| `test_commands.py` | `ProcessChain` building + every command's `to_string()` |
|
|
186
|
+
| `test_executable.py` | `find_designbuilder` resolution order |
|
|
187
|
+
| `test_status.py` | `status` / `ProcessStatus` |
|
|
188
|
+
| `test_cli.py` | CLI argparse wiring (mocked subprocess) |
|
|
189
|
+
|
|
190
|
+
## Releasing
|
|
191
|
+
|
|
192
|
+
Every version is a tag. `pyproject.toml`'s `version` and the git tag must never
|
|
193
|
+
drift apart — consumers pin to `@vX.Y.Z`, and an untagged bump leaves them with
|
|
194
|
+
nothing to pin to but a commit SHA.
|
|
195
|
+
|
|
196
|
+
To cut a release, bump `version` in `pyproject.toml` on `main`:
|
|
197
|
+
|
|
198
|
+
```toml
|
|
199
|
+
[project]
|
|
200
|
+
version = "0.3.0"
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The `Release` workflow then tags that commit `v0.3.0` and opens a matching
|
|
204
|
+
GitHub Release with generated notes. It only fires on changes to
|
|
205
|
+
`pyproject.toml`, and skips silently if the tag already exists, so re-runs are
|
|
206
|
+
safe.
|
|
207
|
+
|
|
208
|
+
To tag manually instead — or to backfill a version that predates the workflow:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
git tag -a v0.3.0 -m "v0.3.0" && git push origin v0.3.0
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Bump the version in the same pull request as the change it describes, not as a
|
|
215
|
+
separate follow-up — that's how the two fell out of step before.
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# db-process
|
|
2
|
+
|
|
3
|
+
Python interface to DesignBuilder's command-line driver — typed `/process=` commands, subprocess execution, and process discovery.
|
|
4
|
+
|
|
5
|
+
DesignBuilder is a Windows GUI app, but it exposes a `/process=` argument that runs a sequence of commands non-interactively and exits. `db-process` wraps that surface in real Python: dataclass commands instead of stringly-typed flags, a `ProcessChain` builder, blocking and non-blocking runners, and helpers to find/kill the process.
|
|
6
|
+
|
|
7
|
+
> For diagnostic-log parsing see [db-diag](https://github.com/DesignBuilderSoftware/db-diag).
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install db-process
|
|
13
|
+
# or, from the cloned repo:
|
|
14
|
+
pip install -e .[dev]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Requires Python 3.10+ and `psutil`. DesignBuilder itself only runs on Windows;
|
|
18
|
+
on other platforms, the package imports fine but `run()` and the process
|
|
19
|
+
helpers will raise `FileNotFoundError`.
|
|
20
|
+
|
|
21
|
+
## Quick start
|
|
22
|
+
|
|
23
|
+
### Python — run a model with a chain of commands
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from db_process import ProcessChain, Screen, run
|
|
27
|
+
|
|
28
|
+
chain = (
|
|
29
|
+
ProcessChain()
|
|
30
|
+
.use_sim_manager()
|
|
31
|
+
.switch_screen(Screen.SIMULATION)
|
|
32
|
+
.sim_start_date(1, 1)
|
|
33
|
+
.sim_end_date(31, 12)
|
|
34
|
+
.change_attribute("OccupancyValue", 0.5)
|
|
35
|
+
.run()
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
result = run("models/office.dsb", chain, timeout=600)
|
|
39
|
+
print(result.success, result.duration_seconds)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Python — convenience factories for common runs
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from db_process import eplus_simulation, run
|
|
46
|
+
|
|
47
|
+
# A pre-built ProcessChain for "open model, run EnergyPlus, close".
|
|
48
|
+
result = run("models/office.dsb", eplus_simulation())
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Other factories: `sbem_calculation`, `export_xml`, `heating_and_cooling_design`,
|
|
52
|
+
`daylighting`, `cfd_simulation`.
|
|
53
|
+
|
|
54
|
+
### Python — non-blocking with idle-detection kill
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from db_process import run_async
|
|
58
|
+
|
|
59
|
+
handle = run_async("models/office.dsb")
|
|
60
|
+
# Block until DesignBuilder finishes its work and CPU drops, then kill it.
|
|
61
|
+
handle.kill_when_idle(idle_threshold=10, cpu_threshold=0.1)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`kill_when_idle` is the workaround for runs where DesignBuilder finishes the
|
|
65
|
+
calculation but doesn't exit — common with the GUI Sim Manager path.
|
|
66
|
+
|
|
67
|
+
### CLI
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
db-process status # is DesignBuilder running? show pid + exe path
|
|
71
|
+
db-process open # launch DesignBuilder
|
|
72
|
+
db-process open path/to.dsb # launch with a model
|
|
73
|
+
db-process close # kill any running DesignBuilder
|
|
74
|
+
db-process restart [model] # close + open (with a 1.5 s settle)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`db-process` is the entry point installed by the package; you can also run it as `python -m db_process`.
|
|
78
|
+
|
|
79
|
+
## Public API
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from db_process import (
|
|
83
|
+
# Executable discovery
|
|
84
|
+
find_designbuilder, # () -> Path
|
|
85
|
+
|
|
86
|
+
# Process status
|
|
87
|
+
is_running, find_process, status, # status() -> ProcessStatus
|
|
88
|
+
kill_process, kill_when_idle,
|
|
89
|
+
ProcessStatus, # is_running, pid, exe_path
|
|
90
|
+
|
|
91
|
+
# Run
|
|
92
|
+
run, run_async, RunHandle, RunResult,
|
|
93
|
+
|
|
94
|
+
# Command model
|
|
95
|
+
ProcessChain, Screen,
|
|
96
|
+
SwitchScreen, RunCalculation, TabChange,
|
|
97
|
+
SimStartDate, SimEndDate, ChangeAttributeValue,
|
|
98
|
+
ExternalCommand, ImportModelData, ImportLibraryData,
|
|
99
|
+
ExportAsXML, UseSimManager, NoClose,
|
|
100
|
+
|
|
101
|
+
# Convenience factories
|
|
102
|
+
eplus_simulation, sbem_calculation, export_xml,
|
|
103
|
+
heating_and_cooling_design, daylighting, cfd_simulation,
|
|
104
|
+
)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Executable discovery
|
|
108
|
+
|
|
109
|
+
`find_designbuilder(exe_path=None)` resolves DesignBuilder.exe in this order:
|
|
110
|
+
|
|
111
|
+
1. The explicit `exe_path` argument, if given.
|
|
112
|
+
2. `DESIGNBUILDER_EXE` environment variable.
|
|
113
|
+
3. `C:\Program Files (x86)\DesignBuilder\DesignBuilder.exe`,
|
|
114
|
+
then `C:\Program Files\DesignBuilder\DesignBuilder.exe`.
|
|
115
|
+
4. The system `PATH` (`shutil.which("DesignBuilder")`).
|
|
116
|
+
|
|
117
|
+
Raises `FileNotFoundError` with a hint to set `DESIGNBUILDER_EXE` if none match.
|
|
118
|
+
|
|
119
|
+
### Process status
|
|
120
|
+
|
|
121
|
+
`status()` is a one-shot snapshot:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from db_process import status
|
|
125
|
+
|
|
126
|
+
s = status()
|
|
127
|
+
# ProcessStatus(is_running=True, pid=12345, exe_path='C:\\...\\DesignBuilder.exe')
|
|
128
|
+
if not s.is_running and s.exe_path:
|
|
129
|
+
# Discovered but not running — safe to launch.
|
|
130
|
+
...
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`exe_path` is populated regardless of whether the process is running, so
|
|
134
|
+
callers can decide whether to launch without a second `find_designbuilder`
|
|
135
|
+
call.
|
|
136
|
+
|
|
137
|
+
### `ProcessChain` — building a `/process=` argument
|
|
138
|
+
|
|
139
|
+
`ProcessChain` is a fluent builder for the `/process=` command sequence
|
|
140
|
+
documented in DesignBuilder Help. Example output of `chain.to_string()`:
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
/process=UseSimManager, miGSS, SimStartDate 1 1, SimEndDate 31 12,
|
|
144
|
+
ChangeAttributeValue OccupancyValue 0.5, miTUpdate
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Every command is also exposed as a plain dataclass, so you can construct
|
|
148
|
+
chains without the builder when that's clearer.
|
|
149
|
+
|
|
150
|
+
## Compatibility
|
|
151
|
+
|
|
152
|
+
- **DesignBuilder**: any version that supports the `/process=` argument.
|
|
153
|
+
Tested against the v25.1 / v26.1 lines.
|
|
154
|
+
- **Python**: 3.10+.
|
|
155
|
+
- **OS**: Windows for live runs. The command model is pure Python and imports on any platform — useful for unit tests on Linux CI.
|
|
156
|
+
|
|
157
|
+
## Development
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
pip install -e .[dev]
|
|
161
|
+
pytest
|
|
162
|
+
ruff check .
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Tests are split by area:
|
|
166
|
+
|
|
167
|
+
| File | Covers |
|
|
168
|
+
| --- | --- |
|
|
169
|
+
| `test_commands.py` | `ProcessChain` building + every command's `to_string()` |
|
|
170
|
+
| `test_executable.py` | `find_designbuilder` resolution order |
|
|
171
|
+
| `test_status.py` | `status` / `ProcessStatus` |
|
|
172
|
+
| `test_cli.py` | CLI argparse wiring (mocked subprocess) |
|
|
173
|
+
|
|
174
|
+
## Releasing
|
|
175
|
+
|
|
176
|
+
Every version is a tag. `pyproject.toml`'s `version` and the git tag must never
|
|
177
|
+
drift apart — consumers pin to `@vX.Y.Z`, and an untagged bump leaves them with
|
|
178
|
+
nothing to pin to but a commit SHA.
|
|
179
|
+
|
|
180
|
+
To cut a release, bump `version` in `pyproject.toml` on `main`:
|
|
181
|
+
|
|
182
|
+
```toml
|
|
183
|
+
[project]
|
|
184
|
+
version = "0.3.0"
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The `Release` workflow then tags that commit `v0.3.0` and opens a matching
|
|
188
|
+
GitHub Release with generated notes. It only fires on changes to
|
|
189
|
+
`pyproject.toml`, and skips silently if the tag already exists, so re-runs are
|
|
190
|
+
safe.
|
|
191
|
+
|
|
192
|
+
To tag manually instead — or to backfill a version that predates the workflow:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
git tag -a v0.3.0 -m "v0.3.0" && git push origin v0.3.0
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Bump the version in the same pull request as the change it describes, not as a
|
|
199
|
+
separate follow-up — that's how the two fell out of step before.
|
|
@@ -1,83 +1,89 @@
|
|
|
1
|
-
"""
|
|
2
|
-
db-process
|
|
3
|
-
====================================
|
|
4
|
-
Python interface to DesignBuilder command line processing.
|
|
5
|
-
|
|
6
|
-
This package provides:
|
|
7
|
-
|
|
8
|
-
- **Executable discovery** — find DesignBuilder.exe across env vars,
|
|
9
|
-
default install paths, and the system PATH.
|
|
10
|
-
- **Typed command model** — dataclasses for every ``/process=`` command
|
|
11
|
-
documented in DesignBuilder Help, with a fluent builder API.
|
|
12
|
-
- **Subprocess execution** — blocking and non-blocking modes, timeout
|
|
13
|
-
handling, and idle-detection termination.
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
from db_process.commands import (
|
|
17
|
-
ChangeAttributeValue,
|
|
18
|
-
ExportAsXML,
|
|
19
|
-
ExternalCommand,
|
|
20
|
-
ImportLibraryData,
|
|
21
|
-
ImportModelData,
|
|
22
|
-
NoClose,
|
|
23
|
-
ProcessChain,
|
|
24
|
-
RunCalculation,
|
|
25
|
-
Screen,
|
|
26
|
-
SimEndDate,
|
|
27
|
-
SimStartDate,
|
|
28
|
-
SwitchScreen,
|
|
29
|
-
TabChange,
|
|
30
|
-
UseSimManager,
|
|
31
|
-
# Convenience factories
|
|
32
|
-
cfd_simulation,
|
|
33
|
-
daylighting,
|
|
34
|
-
eplus_simulation,
|
|
35
|
-
export_xml,
|
|
36
|
-
heating_and_cooling_design,
|
|
37
|
-
sbem_calculation,
|
|
38
|
-
)
|
|
39
|
-
from db_process.executable import find_designbuilder
|
|
40
|
-
from db_process.runner import (
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
|
|
1
|
+
"""
|
|
2
|
+
db-process
|
|
3
|
+
====================================
|
|
4
|
+
Python interface to DesignBuilder command line processing.
|
|
5
|
+
|
|
6
|
+
This package provides:
|
|
7
|
+
|
|
8
|
+
- **Executable discovery** — find DesignBuilder.exe across env vars,
|
|
9
|
+
default install paths, and the system PATH.
|
|
10
|
+
- **Typed command model** — dataclasses for every ``/process=`` command
|
|
11
|
+
documented in DesignBuilder Help, with a fluent builder API.
|
|
12
|
+
- **Subprocess execution** — blocking and non-blocking modes, timeout
|
|
13
|
+
handling, and idle-detection termination.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from db_process.commands import (
|
|
17
|
+
ChangeAttributeValue,
|
|
18
|
+
ExportAsXML,
|
|
19
|
+
ExternalCommand,
|
|
20
|
+
ImportLibraryData,
|
|
21
|
+
ImportModelData,
|
|
22
|
+
NoClose,
|
|
23
|
+
ProcessChain,
|
|
24
|
+
RunCalculation,
|
|
25
|
+
Screen,
|
|
26
|
+
SimEndDate,
|
|
27
|
+
SimStartDate,
|
|
28
|
+
SwitchScreen,
|
|
29
|
+
TabChange,
|
|
30
|
+
UseSimManager,
|
|
31
|
+
# Convenience factories
|
|
32
|
+
cfd_simulation,
|
|
33
|
+
daylighting,
|
|
34
|
+
eplus_simulation,
|
|
35
|
+
export_xml,
|
|
36
|
+
heating_and_cooling_design,
|
|
37
|
+
sbem_calculation,
|
|
38
|
+
)
|
|
39
|
+
from db_process.executable import find_designbuilder
|
|
40
|
+
from db_process.runner import (
|
|
41
|
+
ProcessStatus,
|
|
42
|
+
RunHandle,
|
|
43
|
+
RunResult,
|
|
44
|
+
find_process,
|
|
45
|
+
is_running,
|
|
46
|
+
kill_process,
|
|
47
|
+
kill_when_idle,
|
|
48
|
+
run,
|
|
49
|
+
run_async,
|
|
50
|
+
status,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
# Executable
|
|
55
|
+
"find_designbuilder",
|
|
56
|
+
# Commands
|
|
57
|
+
"ChangeAttributeValue",
|
|
58
|
+
"ExportAsXML",
|
|
59
|
+
"ExternalCommand",
|
|
60
|
+
"ImportLibraryData",
|
|
61
|
+
"ImportModelData",
|
|
62
|
+
"NoClose",
|
|
63
|
+
"ProcessChain",
|
|
64
|
+
"RunCalculation",
|
|
65
|
+
"Screen",
|
|
66
|
+
"SimEndDate",
|
|
67
|
+
"SimStartDate",
|
|
68
|
+
"SwitchScreen",
|
|
69
|
+
"TabChange",
|
|
70
|
+
"UseSimManager",
|
|
71
|
+
# Convenience factories
|
|
72
|
+
"cfd_simulation",
|
|
73
|
+
"daylighting",
|
|
74
|
+
"eplus_simulation",
|
|
75
|
+
"export_xml",
|
|
76
|
+
"heating_and_cooling_design",
|
|
77
|
+
"sbem_calculation",
|
|
78
|
+
# Runner / status
|
|
79
|
+
"RunHandle",
|
|
80
|
+
"RunResult",
|
|
81
|
+
"ProcessStatus",
|
|
82
|
+
"find_process",
|
|
83
|
+
"is_running",
|
|
84
|
+
"kill_process",
|
|
85
|
+
"kill_when_idle",
|
|
86
|
+
"run",
|
|
87
|
+
"run_async",
|
|
88
|
+
"status",
|
|
89
|
+
]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""db-process CLI.
|
|
2
|
+
|
|
3
|
+
Small command-line wrapper over the existing process-control primitives:
|
|
4
|
+
|
|
5
|
+
db-process status # is DB running? where's the exe?
|
|
6
|
+
db-process close # kill any running DesignBuilder
|
|
7
|
+
db-process open [MODEL.dsb] # launch DB; opens MODEL if given
|
|
8
|
+
db-process restart [MODEL.dsb] # close + open
|
|
9
|
+
|
|
10
|
+
Equivalent to:
|
|
11
|
+
|
|
12
|
+
python -m db_process <subcommand> [args]
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import subprocess
|
|
19
|
+
import sys
|
|
20
|
+
import time
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
from .executable import find_designbuilder
|
|
24
|
+
from .runner import find_process, is_running, kill_process, run_async, status as proc_status
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def cmd_status(args: argparse.Namespace) -> int:
|
|
28
|
+
s = proc_status()
|
|
29
|
+
print(f"DesignBuilder exe : {s.exe_path or '<not found>'}")
|
|
30
|
+
if not s.is_running:
|
|
31
|
+
print("DesignBuilder process : not running")
|
|
32
|
+
return 1
|
|
33
|
+
print(f"DesignBuilder process : pid={s.pid}")
|
|
34
|
+
return 0
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def cmd_close(args: argparse.Namespace) -> int:
|
|
38
|
+
if kill_process():
|
|
39
|
+
print("Closed running DesignBuilder.")
|
|
40
|
+
return 0
|
|
41
|
+
print("No DesignBuilder process to close.")
|
|
42
|
+
return 1
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def cmd_open(args: argparse.Namespace) -> int:
|
|
46
|
+
exe = find_designbuilder()
|
|
47
|
+
if args.model is not None:
|
|
48
|
+
print(f"Opening {args.model} with {exe} ...")
|
|
49
|
+
run_async(str(args.model))
|
|
50
|
+
else:
|
|
51
|
+
print(f"Launching {exe} (no model)...")
|
|
52
|
+
subprocess.Popen([str(exe)])
|
|
53
|
+
return 0
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def cmd_restart(args: argparse.Namespace) -> int:
|
|
57
|
+
if kill_process():
|
|
58
|
+
print(f"Closed existing process; settling for {args.settle}s ...")
|
|
59
|
+
time.sleep(args.settle)
|
|
60
|
+
return cmd_open(args)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
64
|
+
p = argparse.ArgumentParser(prog="db-process",
|
|
65
|
+
description="DesignBuilder process control")
|
|
66
|
+
sub = p.add_subparsers(dest="cmd", required=True)
|
|
67
|
+
|
|
68
|
+
sub.add_parser("status", help="Show DesignBuilder exe path and PID").set_defaults(func=cmd_status)
|
|
69
|
+
sub.add_parser("close", help="Kill any running DesignBuilder").set_defaults(func=cmd_close)
|
|
70
|
+
|
|
71
|
+
p_open = sub.add_parser("open", help="Launch DesignBuilder")
|
|
72
|
+
p_open.add_argument("model", nargs="?", type=Path, default=None,
|
|
73
|
+
help="Optional .dsb model to open")
|
|
74
|
+
p_open.set_defaults(func=cmd_open)
|
|
75
|
+
|
|
76
|
+
p_restart = sub.add_parser("restart", help="Close then open DesignBuilder")
|
|
77
|
+
p_restart.add_argument("model", nargs="?", type=Path, default=None,
|
|
78
|
+
help="Optional .dsb model to open after restart")
|
|
79
|
+
p_restart.add_argument("--settle", type=float, default=1.5,
|
|
80
|
+
help="Seconds to wait between close and open (default 1.5)")
|
|
81
|
+
p_restart.set_defaults(func=cmd_restart)
|
|
82
|
+
|
|
83
|
+
return p
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def main(argv: list[str] | None = None) -> int:
|
|
87
|
+
args = build_parser().parse_args(argv)
|
|
88
|
+
return args.func(args)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
if __name__ == "__main__":
|
|
92
|
+
sys.exit(main())
|