Skip to content

Commit f6ab2ac

Browse files
authored
Document --project-info (-i) CLI option (#96)
## Summary Documentation for pybuilder/pybuilder#946 (`pyb --project-info` / `pyb -i`). - Release notes entry for v0.13.20 in `articles/_release-notes/v0.13.x.md` - New dedicated page `documentation/project-info.md` with full JSON schema reference and integration examples (CI/CD version extraction, dependency auditing, IDE integration, env diffing) - New section in `documentation/manual.md` ("Inspecting Project Configuration") - New section in `documentation/tutorial.md` showing `pyb -i` on the tutorial project - Updated `documentation/coding-agents.md` with `pyb -i` in build commands and example CLAUDE.md - Added link in `documentation/index.md` - Blog post `articles/_posts/2026-04-01-project-info-json-dump.md` ## Test plan - [ ] Verify Jekyll site builds locally (`bundle exec jekyll serve`) - [ ] Verify all new links resolve correctly - [ ] Verify project-info page renders tables and code blocks properly
2 parents 26d9b16 + 258c0da commit f6ab2ac

File tree

8 files changed

+330
-0
lines changed

8 files changed

+330
-0
lines changed

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ bundle exec jekyll serve --watch
7676
# Browse to http://localhost:4000
7777

7878
# Full CI-equivalent build (build + htmlproofer + prod rebuild)
79+
# Output goes to _site/
7980
./build.sh
8081
```
8182

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
layout: post
3+
title: "New Feature: pyb --project-info for Machine-Readable Project Configuration"
4+
author: arcivanov
5+
categories: news
6+
---
7+
8+
PyBuilder now supports dumping the full project configuration as machine-readable
9+
JSON, without running a build. Use `pyb -i` or `pyb --project-info` to inspect
10+
everything PyBuilder knows about your project after loading plugins and running
11+
initializers.
12+
13+
**Clean stdout/stderr separation.** JSON goes to stdout, log messages go to
14+
stderr. This means you can pipe the output directly into `jq`, `python -m
15+
json.tool`, or any JSON consumer:
16+
17+
```bash
18+
# Get the project name
19+
pyb -i 2>/dev/null | jq .project.name
20+
21+
# Inspect all properties with environment and overrides applied
22+
pyb -i -E ci -P verbose=true 2>/dev/null | jq .properties
23+
24+
# Feed into CI scripts
25+
PROJECT_VERSION=$(pyb -i 2>/dev/null | jq -r .project.version)
26+
```
27+
28+
**What's included.** The JSON output covers: project metadata (name, version,
29+
authors, license, URLs), all build properties (built-in and plugin-defined),
30+
loaded plugins, runtime/build/plugin/extras dependencies, available tasks with
31+
their descriptions and dependency graphs, manifest files, and package data.
32+
33+
**No side effects.** Plugin initializers run to populate properties, but no tasks
34+
execute, no venvs are created, and no dependencies are installed. It is safe and
35+
fast to run in any context.
36+
37+
See the [usage documentation](/documentation/manual.html#inspecting-project-configuration)
38+
for details, or the [dedicated project-info page](/documentation/project-info.html)
39+
for the full JSON schema reference and integration examples.

articles/_release-notes/v0.13.x.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ list_title: Versions 0.13.x
66

77
# Release Notes - Versions 0.13.x
88

9+
## Version 0.13.20
10+
11+
### New Features
12+
* `pyb -i` / `pyb --project-info` — outputs the full project configuration as
13+
pretty-printed JSON without running a build. Runs plugin initializers to
14+
populate all properties but does not execute any tasks or create venvs.
15+
JSON goes to stdout; log messages go to stderr so the output is
16+
machine-parseable.
17+
918
## Version 0.13.19
1019

1120
### New Features

documentation/coding-agents.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ pyb clean package
4141
# List available tasks
4242
pyb -t
4343

44+
# Dump project configuration as JSON (no build, stdout is clean JSON)
45+
pyb -i 2>/dev/null | jq .
46+
4447
# Set a property from the command line
4548
pyb -P property_name=value
4649
```
@@ -218,6 +221,7 @@ This project uses PyBuilder. All build commands use `pyb`:
218221
- `pyb` — full build
219222
- `pyb run_unit_tests` — unit tests only
220223
- `pyb run_integration_tests` — integration tests only
224+
- `pyb -i` — dump project configuration as JSON (no build)
221225
- `pyb -v` — verbose output
222226
- `pyb -vX` — debug verbose output
223227
```
@@ -268,6 +272,7 @@ This project uses PyBuilder. All build commands use `pyb`:
268272
- `pyb` — full build (test + analyze + package)
269273
- `pyb run_unit_tests` — unit tests only
270274
- `pyb run_integration_tests` — integration tests only
275+
- `pyb -i` — dump project configuration as JSON (no build)
271276
- `pyb -v` — verbose output
272277
- `pyb -vX` — debug verbose output
273278

documentation/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ title: PyBuilder Documentation
1515

1616
### [Manual]({% link documentation/manual.md %})
1717

18+
### [Project Info (JSON Dump)]({% link documentation/project-info.md %})
19+
1820
### [Plugins]({% link documentation/plugins.md %})
1921

2022
### [External Plugin List]({% link documentation/external-plugin-list.md %})

documentation/manual.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,33 @@ This command sets/ overrides the property with the name ```spam``` with the valu
215215

216216
Note that command line switches only allow properties to be set/ overridden using string values.
217217

218+
#### Inspecting Project Configuration
219+
220+
Use `pyb -i` (or `pyb --project-info`) to dump the full project configuration as
221+
pretty-printed JSON without running a build. This runs all plugin initializers to
222+
populate properties but does not execute any tasks or create build/test venvs.
223+
224+
JSON is written to stdout and all log messages go to stderr, so the output is
225+
safe to pipe into other tools:
226+
227+
<pre>
228+
$ pyb -i 2>/dev/null | python -m json.tool
229+
$ pyb -i 2>/dev/null | jq .project.name
230+
$ pyb -i -E ci -P verbose=true 2>/dev/null | jq .properties
231+
</pre>
232+
233+
The JSON output includes:
234+
235+
* **project** — name, version, basedir, summary, authors, license, URLs, etc.
236+
* **properties** — all build properties (built-in and plugin-defined)
237+
* **plugins** — list of loaded plugins
238+
* **dependencies** — runtime, build, plugin, and extras dependencies
239+
* **tasks** — available tasks with descriptions and dependency information
240+
* **manifest_included_files**, **package_data**, **files_to_install**
241+
242+
This is useful for CI/CD pipelines, editor integrations, and debugging
243+
property values without running a full build.
244+
218245
## Virtual Environment Infrastructure
219246

220247
*PyBuilder* manages isolated Python virtual environments for building and testing.

documentation/project-info.md

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
---
2+
layout: documentation
3+
title: Project Info — JSON Configuration Dump
4+
---
5+
6+
# Project Info — JSON Configuration Dump
7+
8+
The `pyb -i` (or `pyb --project-info`) command outputs the complete project
9+
configuration as pretty-printed JSON to stdout, without running a build.
10+
11+
## Quick Start
12+
13+
```bash
14+
# Dump full project configuration
15+
pyb -i 2>/dev/null | python -m json.tool
16+
17+
# Extract a single value
18+
pyb -i 2>/dev/null | jq -r .project.version
19+
20+
# Apply environment and property overrides
21+
pyb -i -E ci -P coverage_break_build=false 2>/dev/null | jq .properties
22+
```
23+
24+
## Output Separation
25+
26+
JSON is written to **stdout**. All log messages (plugin loading, initializer
27+
execution, debug output) are written to **stderr**. This separation ensures
28+
that the stdout stream is always valid JSON, regardless of verbosity level:
29+
30+
```bash
31+
# JSON only
32+
pyb -i 2>/dev/null
33+
34+
# JSON to file, logs visible
35+
pyb -i > project.json
36+
37+
# JSON piped, debug logs to a file
38+
pyb -i -X 2>debug.log | jq .
39+
40+
# Both visible (JSON to stdout, logs to stderr)
41+
pyb -i
42+
```
43+
44+
## What Runs
45+
46+
When `pyb -i` is invoked:
47+
48+
1. **`build.py` is loaded** — plugins are imported, project attributes are set.
49+
2. **Plugin initializers run** — these populate default property values (e.g.
50+
`dir_source_main_python`, `coverage_threshold_warn`). Initializers only call
51+
`set_property_if_unset()` and bind utility functions; they do not create
52+
directories, install packages, or modify the filesystem.
53+
3. **Property overrides are applied** — values from `-P` flags override
54+
plugin defaults.
55+
56+
**What does NOT run:** No tasks execute. No build/test virtual environments are
57+
created. No dependencies are installed. No files are written to `target/`.
58+
59+
## JSON Schema
60+
61+
The output is a single JSON object with the following top-level keys:
62+
63+
### `pybuilder_version`
64+
65+
The PyBuilder version string.
66+
67+
### `project`
68+
69+
Project metadata:
70+
71+
| Field | Type | Description |
72+
|-------|------|-------------|
73+
| `name` | string | Project name (from `build.py` or directory name) |
74+
| `version` | string | Declared version (e.g. `"1.0.dev"`) |
75+
| `dist_version` | string | Distribution version with timestamp (e.g. `"1.0.dev20260401120000"`) |
76+
| `basedir` | string | Absolute path to project root |
77+
| `summary` | string | One-line project summary |
78+
| `description` | string | Full project description |
79+
| `author` | string | Primary author (legacy field) |
80+
| `authors` | array | List of author objects with `name`, `email`, and optional `roles` |
81+
| `maintainer` | string | Primary maintainer (legacy field) |
82+
| `maintainers` | array | List of maintainer objects |
83+
| `license` | string | License identifier |
84+
| `url` | string | Primary project URL |
85+
| `urls` | object | Named URL map (e.g. `{"Source Code": "https://..."}`) |
86+
| `requires_python` | string | Python version specifier (e.g. `">=3.10"`) |
87+
| `default_task` | string or array | Default task(s) when `pyb` is run without arguments |
88+
| `obsoletes` | array | Obsoleted package names |
89+
| `explicit_namespaces` | array | Explicit namespace packages |
90+
91+
### `environments`
92+
93+
Array of active environment names (from `-E` flags).
94+
95+
### `properties`
96+
97+
Object mapping property names to their values. Includes all built-in and
98+
plugin-defined properties. Values that are not JSON-serializable (e.g. function
99+
objects) are converted to their string representation.
100+
101+
### `plugins`
102+
103+
Array of loaded plugin names in load order.
104+
105+
### `dependencies`
106+
107+
Object with four sub-keys:
108+
109+
| Key | Contents |
110+
|-----|----------|
111+
| `runtime` | Dependencies from `depends_on()` |
112+
| `build` | Dependencies from `build_depends_on()` |
113+
| `plugin` | Dependencies from `plugin_depends_on()` |
114+
| `extras` | Object mapping extra name to dependency array |
115+
116+
Each dependency is an object:
117+
118+
```json
119+
{
120+
"name": "requests",
121+
"version": ">=2.28",
122+
"url": null,
123+
"extras": null,
124+
"markers": "sys_platform == 'linux'",
125+
"declaration_only": false,
126+
"type": "dependency"
127+
}
128+
```
129+
130+
Requirements files have `"type": "requirements_file"` and only `name`,
131+
`version` (always null), and `declaration_only` fields.
132+
133+
### `tasks`
134+
135+
Array of task objects:
136+
137+
```json
138+
{
139+
"name": "run_unit_tests",
140+
"description": "Runs all unit tests",
141+
"dependencies": [
142+
{"name": "compile_sources", "optional": false},
143+
{"name": "coverage", "optional": true}
144+
]
145+
}
146+
```
147+
148+
### `manifest_included_files`
149+
150+
Array of glob patterns included in the distribution manifest.
151+
152+
### `package_data`
153+
154+
Object mapping package names to arrays of included file patterns.
155+
156+
### `files_to_install`
157+
158+
Array of `[destination, [filenames]]` pairs for files installed outside packages.
159+
160+
## Integration Examples
161+
162+
### CI/CD: Extract Version for Tagging
163+
164+
```bash
165+
VERSION=$(pyb -i 2>/dev/null | jq -r .project.dist_version)
166+
docker build -t myapp:$VERSION .
167+
```
168+
169+
### Dependency Auditing
170+
171+
```bash
172+
# List all runtime dependencies
173+
pyb -i 2>/dev/null | jq -r '.dependencies.runtime[].name'
174+
175+
# Find dependencies without version constraints
176+
pyb -i 2>/dev/null | jq '.dependencies.runtime[] | select(.version == null) | .name'
177+
```
178+
179+
### Editor/IDE Integration
180+
181+
```bash
182+
# Get source directory for language server configuration
183+
SRC=$(pyb -i 2>/dev/null | jq -r '.properties.dir_source_main_python')
184+
185+
# Get test directory
186+
TEST=$(pyb -i 2>/dev/null | jq -r '.properties.dir_source_unittest_python')
187+
```
188+
189+
### Diffing Configuration Between Environments
190+
191+
```bash
192+
diff <(pyb -i 2>/dev/null | jq -S .properties) \
193+
<(pyb -i -E ci 2>/dev/null | jq -S .properties)
194+
```
195+
196+
## Command Line Options
197+
198+
`pyb -i` is compatible with most project options:
199+
200+
| Flag | Effect |
201+
|------|--------|
202+
| `-E <env>` | Activate environment (repeatable) |
203+
| `-P <key>=<value>` | Override property value |
204+
| `-D <dir>` | Set project directory |
205+
| `-O` | Offline mode |
206+
| `--no-venvs` | Disable venv creation |
207+
| `-X` | Debug log output (to stderr) |
208+
| `-v` | Verbose log output (to stderr) |
209+
| `-q` / `-Q` | Suppress log output (on stderr) |
210+
211+
`pyb -i` is mutually exclusive with `-t`, `-T`, `--start-project`, and
212+
`--update-project`.

documentation/tutorial.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,41 @@ The distribution directory contains the same sources but in a Python-typical dir
580580
You can also find the `setup.py` script there, as well as generated binary wheel and sdist gzip'ed tar in
581581
`target/dist/dist`.
582582

583+
## Inspecting Project Configuration
584+
585+
At any point you can inspect the full project configuration as JSON without
586+
running a build:
587+
588+
```
589+
$ pyb -i 2>/dev/null | python -m json.tool
590+
{
591+
"pybuilder_version": "0.13.20",
592+
"project": {
593+
"name": "helloworld",
594+
"version": "1.0.dev0",
595+
...
596+
},
597+
"properties": {
598+
"dir_source_main_python": "src/main/python",
599+
"coverage_threshold_warn": 70,
600+
...
601+
},
602+
"plugins": [
603+
"python.core",
604+
"python.unittest",
605+
"python.coverage",
606+
"python.distutils"
607+
],
608+
"tasks": [ ... ],
609+
...
610+
}
611+
```
612+
613+
This is useful for verifying that properties are set correctly or for feeding
614+
project metadata into CI/CD scripts. See the
615+
[project-info documentation](/documentation/project-info.html) for the full
616+
JSON schema and integration examples.
617+
583618
## Recap
584619

585620
In this tutorial we saw how PyBuilder can be used to "build" a typical Python project. Building in an interpreted

0 commit comments

Comments
 (0)