Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ bundle exec jekyll serve --watch
# Browse to http://localhost:4000

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

Expand Down
39 changes: 39 additions & 0 deletions articles/_posts/2026-04-01-project-info-json-dump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
layout: post
title: "New Feature: pyb --project-info for Machine-Readable Project Configuration"
author: arcivanov
categories: news
---

PyBuilder now supports dumping the full project configuration as machine-readable
JSON, without running a build. Use `pyb -i` or `pyb --project-info` to inspect
everything PyBuilder knows about your project after loading plugins and running
initializers.

**Clean stdout/stderr separation.** JSON goes to stdout, log messages go to
stderr. This means you can pipe the output directly into `jq`, `python -m
json.tool`, or any JSON consumer:

```bash
# Get the project name
pyb -i 2>/dev/null | jq .project.name

# Inspect all properties with environment and overrides applied
pyb -i -E ci -P verbose=true 2>/dev/null | jq .properties

# Feed into CI scripts
PROJECT_VERSION=$(pyb -i 2>/dev/null | jq -r .project.version)
```

**What's included.** The JSON output covers: project metadata (name, version,
authors, license, URLs), all build properties (built-in and plugin-defined),
loaded plugins, runtime/build/plugin/extras dependencies, available tasks with
their descriptions and dependency graphs, manifest files, and package data.

**No side effects.** Plugin initializers run to populate properties, but no tasks
execute, no venvs are created, and no dependencies are installed. It is safe and
fast to run in any context.

See the [usage documentation](/documentation/manual.html#inspecting-project-configuration)
for details, or the [dedicated project-info page](/documentation/project-info.html)
for the full JSON schema reference and integration examples.
9 changes: 9 additions & 0 deletions articles/_release-notes/v0.13.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ list_title: Versions 0.13.x

# Release Notes - Versions 0.13.x

## Version 0.13.20

### New Features
* `pyb -i` / `pyb --project-info` — outputs the full project configuration as
pretty-printed JSON without running a build. Runs plugin initializers to
populate all properties but does not execute any tasks or create venvs.
JSON goes to stdout; log messages go to stderr so the output is
machine-parseable.

## Version 0.13.19

### New Features
Expand Down
5 changes: 5 additions & 0 deletions documentation/coding-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ pyb clean package
# List available tasks
pyb -t

# Dump project configuration as JSON (no build, stdout is clean JSON)
pyb -i 2>/dev/null | jq .

# Set a property from the command line
pyb -P property_name=value
```
Expand Down Expand Up @@ -218,6 +221,7 @@ This project uses PyBuilder. All build commands use `pyb`:
- `pyb` — full build
- `pyb run_unit_tests` — unit tests only
- `pyb run_integration_tests` — integration tests only
- `pyb -i` — dump project configuration as JSON (no build)
- `pyb -v` — verbose output
- `pyb -vX` — debug verbose output
```
Expand Down Expand Up @@ -268,6 +272,7 @@ This project uses PyBuilder. All build commands use `pyb`:
- `pyb` — full build (test + analyze + package)
- `pyb run_unit_tests` — unit tests only
- `pyb run_integration_tests` — integration tests only
- `pyb -i` — dump project configuration as JSON (no build)
- `pyb -v` — verbose output
- `pyb -vX` — debug verbose output

Expand Down
2 changes: 2 additions & 0 deletions documentation/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ title: PyBuilder Documentation

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

### [Project Info (JSON Dump)]({% link documentation/project-info.md %})

### [Plugins]({% link documentation/plugins.md %})

### [External Plugin List]({% link documentation/external-plugin-list.md %})
Expand Down
27 changes: 27 additions & 0 deletions documentation/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,33 @@ This command sets/ overrides the property with the name ```spam``` with the valu

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

#### Inspecting Project Configuration

Use `pyb -i` (or `pyb --project-info`) to dump the full project configuration as
pretty-printed JSON without running a build. This runs all plugin initializers to
populate properties but does not execute any tasks or create build/test venvs.

JSON is written to stdout and all log messages go to stderr, so the output is
safe to pipe into other tools:

<pre>
$ pyb -i 2>/dev/null | python -m json.tool
$ pyb -i 2>/dev/null | jq .project.name
$ pyb -i -E ci -P verbose=true 2>/dev/null | jq .properties
</pre>

The JSON output includes:

* **project** — name, version, basedir, summary, authors, license, URLs, etc.
* **properties** — all build properties (built-in and plugin-defined)
* **plugins** — list of loaded plugins
* **dependencies** — runtime, build, plugin, and extras dependencies
* **tasks** — available tasks with descriptions and dependency information
* **manifest_included_files**, **package_data**, **files_to_install**

This is useful for CI/CD pipelines, editor integrations, and debugging
property values without running a full build.

## Virtual Environment Infrastructure

*PyBuilder* manages isolated Python virtual environments for building and testing.
Expand Down
212 changes: 212 additions & 0 deletions documentation/project-info.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
---
layout: documentation
title: Project Info — JSON Configuration Dump
---

# Project Info — JSON Configuration Dump

The `pyb -i` (or `pyb --project-info`) command outputs the complete project
configuration as pretty-printed JSON to stdout, without running a build.

## Quick Start

```bash
# Dump full project configuration
pyb -i 2>/dev/null | python -m json.tool

# Extract a single value
pyb -i 2>/dev/null | jq -r .project.version

# Apply environment and property overrides
pyb -i -E ci -P coverage_break_build=false 2>/dev/null | jq .properties
```

## Output Separation

JSON is written to **stdout**. All log messages (plugin loading, initializer
execution, debug output) are written to **stderr**. This separation ensures
that the stdout stream is always valid JSON, regardless of verbosity level:

```bash
# JSON only
pyb -i 2>/dev/null

# JSON to file, logs visible
pyb -i > project.json

# JSON piped, debug logs to a file
pyb -i -X 2>debug.log | jq .

# Both visible (JSON to stdout, logs to stderr)
pyb -i
```

## What Runs

When `pyb -i` is invoked:

1. **`build.py` is loaded** — plugins are imported, project attributes are set.
2. **Plugin initializers run** — these populate default property values (e.g.
`dir_source_main_python`, `coverage_threshold_warn`). Initializers only call
`set_property_if_unset()` and bind utility functions; they do not create
directories, install packages, or modify the filesystem.
3. **Property overrides are applied** — values from `-P` flags override
plugin defaults.

**What does NOT run:** No tasks execute. No build/test virtual environments are
created. No dependencies are installed. No files are written to `target/`.

## JSON Schema

The output is a single JSON object with the following top-level keys:

### `pybuilder_version`

The PyBuilder version string.

### `project`

Project metadata:

| Field | Type | Description |
|-------|------|-------------|
| `name` | string | Project name (from `build.py` or directory name) |
| `version` | string | Declared version (e.g. `"1.0.dev"`) |
| `dist_version` | string | Distribution version with timestamp (e.g. `"1.0.dev20260401120000"`) |
| `basedir` | string | Absolute path to project root |
| `summary` | string | One-line project summary |
| `description` | string | Full project description |
| `author` | string | Primary author (legacy field) |
| `authors` | array | List of author objects with `name`, `email`, and optional `roles` |
| `maintainer` | string | Primary maintainer (legacy field) |
| `maintainers` | array | List of maintainer objects |
| `license` | string | License identifier |
| `url` | string | Primary project URL |
| `urls` | object | Named URL map (e.g. `{"Source Code": "https://..."}`) |
| `requires_python` | string | Python version specifier (e.g. `">=3.10"`) |
| `default_task` | string or array | Default task(s) when `pyb` is run without arguments |
| `obsoletes` | array | Obsoleted package names |
| `explicit_namespaces` | array | Explicit namespace packages |

### `environments`

Array of active environment names (from `-E` flags).

### `properties`

Object mapping property names to their values. Includes all built-in and
plugin-defined properties. Values that are not JSON-serializable (e.g. function
objects) are converted to their string representation.

### `plugins`

Array of loaded plugin names in load order.

### `dependencies`

Object with four sub-keys:

| Key | Contents |
|-----|----------|
| `runtime` | Dependencies from `depends_on()` |
| `build` | Dependencies from `build_depends_on()` |
| `plugin` | Dependencies from `plugin_depends_on()` |
| `extras` | Object mapping extra name to dependency array |

Each dependency is an object:

```json
{
"name": "requests",
"version": ">=2.28",
"url": null,
"extras": null,
"markers": "sys_platform == 'linux'",
"declaration_only": false,
"type": "dependency"
}
```

Requirements files have `"type": "requirements_file"` and only `name`,
`version` (always null), and `declaration_only` fields.

### `tasks`

Array of task objects:

```json
{
"name": "run_unit_tests",
"description": "Runs all unit tests",
"dependencies": [
{"name": "compile_sources", "optional": false},
{"name": "coverage", "optional": true}
]
}
```

### `manifest_included_files`

Array of glob patterns included in the distribution manifest.

### `package_data`

Object mapping package names to arrays of included file patterns.

### `files_to_install`

Array of `[destination, [filenames]]` pairs for files installed outside packages.

## Integration Examples

### CI/CD: Extract Version for Tagging

```bash
VERSION=$(pyb -i 2>/dev/null | jq -r .project.dist_version)
docker build -t myapp:$VERSION .
```

### Dependency Auditing

```bash
# List all runtime dependencies
pyb -i 2>/dev/null | jq -r '.dependencies.runtime[].name'

# Find dependencies without version constraints
pyb -i 2>/dev/null | jq '.dependencies.runtime[] | select(.version == null) | .name'
```

### Editor/IDE Integration

```bash
# Get source directory for language server configuration
SRC=$(pyb -i 2>/dev/null | jq -r '.properties.dir_source_main_python')

# Get test directory
TEST=$(pyb -i 2>/dev/null | jq -r '.properties.dir_source_unittest_python')
```

### Diffing Configuration Between Environments

```bash
diff <(pyb -i 2>/dev/null | jq -S .properties) \
<(pyb -i -E ci 2>/dev/null | jq -S .properties)
```

## Command Line Options

`pyb -i` is compatible with most project options:

| Flag | Effect |
|------|--------|
| `-E <env>` | Activate environment (repeatable) |
| `-P <key>=<value>` | Override property value |
| `-D <dir>` | Set project directory |
| `-O` | Offline mode |
| `--no-venvs` | Disable venv creation |
| `-X` | Debug log output (to stderr) |
| `-v` | Verbose log output (to stderr) |
| `-q` / `-Q` | Suppress log output (on stderr) |

`pyb -i` is mutually exclusive with `-t`, `-T`, `--start-project`, and
`--update-project`.
35 changes: 35 additions & 0 deletions documentation/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,41 @@ The distribution directory contains the same sources but in a Python-typical dir
You can also find the `setup.py` script there, as well as generated binary wheel and sdist gzip'ed tar in
`target/dist/dist`.

## Inspecting Project Configuration

At any point you can inspect the full project configuration as JSON without
running a build:

```
$ pyb -i 2>/dev/null | python -m json.tool
{
"pybuilder_version": "0.13.20",
"project": {
"name": "helloworld",
"version": "1.0.dev0",
...
},
"properties": {
"dir_source_main_python": "src/main/python",
"coverage_threshold_warn": 70,
...
},
"plugins": [
"python.core",
"python.unittest",
"python.coverage",
"python.distutils"
],
"tasks": [ ... ],
...
}
```

This is useful for verifying that properties are set correctly or for feeding
project metadata into CI/CD scripts. See the
[project-info documentation](/documentation/project-info.html) for the full
JSON schema and integration examples.

## Recap

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