Past maintainers include Maximilien Riehl and Michael Gruber.
- As of 2020 Arcadiy Ivanov is actively developing PyBuilder.
+ Arcadiy Ivanov is the current maintainer and active developer of PyBuilder.
diff --git a/articles/_posts/2022-06-15-version-0.13.6-python-3.11.md b/articles/_posts/2022-06-15-version-0.13.6-python-3.11.md
new file mode 100644
index 0000000..77d44ce
--- /dev/null
+++ b/articles/_posts/2022-06-15-version-0.13.6-python-3.11.md
@@ -0,0 +1,15 @@
+---
+layout: post
+title: "Python 3.11 Support in PyBuilder 0.13.6"
+author: arcivanov
+categories: news
+---
+
+PyBuilder 0.13.6 adds support for Python 3.11, which introduced breaking changes
+to both the `multiprocessing` module's spawn mechanism and the `unittest.TestCase`
+internal results API. Both are core to PyBuilder's test isolation infrastructure
+and required targeted fixes.
+
+This release also drops support for Python 3.6.
+
+See the [release notes](/release-notes/v0.13.x) for details.
diff --git a/articles/_posts/2022-11-03-version-0.13.8-debug-venvs.md b/articles/_posts/2022-11-03-version-0.13.8-debug-venvs.md
new file mode 100644
index 0000000..f682d01
--- /dev/null
+++ b/articles/_posts/2022-11-03-version-0.13.8-debug-venvs.md
@@ -0,0 +1,18 @@
+---
+layout: post
+title: "PyBuilder 0.13.8: Debug Python Support and Log Formatting"
+author: arcivanov
+categories: news
+---
+
+PyBuilder 0.13.8 brings two notable improvements:
+
+**Debug/release venv distinction.** Managed virtual environments now distinguish
+between debug and release builds of Python. Debug builds (compiled with `--with-pydebug`)
+get their own isolated venv directories, preventing ABI-incompatible packages from
+being mixed between debug and release environments.
+
+**Configurable log format.** A new `--log-format` command line parameter allows
+customizing PyBuilder's log output format.
+
+See the [release notes](/release-notes/v0.13.x) for details.
diff --git a/articles/_posts/2024-02-14-version-0.13.11-python-3.12.md b/articles/_posts/2024-02-14-version-0.13.11-python-3.12.md
new file mode 100644
index 0000000..a6fc7bf
--- /dev/null
+++ b/articles/_posts/2024-02-14-version-0.13.11-python-3.12.md
@@ -0,0 +1,12 @@
+---
+layout: post
+title: "PyBuilder 0.13.11: Python 3.12 Support"
+author: arcivanov
+categories: news
+---
+
+PyBuilder 0.13.11 officially supports Python 3.12. Preliminary fixes for 3.12
+compatibility landed in v0.13.10, and this release completes the work with full
+CI coverage across CPython 3.8 through 3.12 on Linux, macOS, and Windows.
+
+See the [release notes](/release-notes/v0.13.x) for details.
diff --git a/articles/_posts/2024-06-04-version-0.13.13-drop-python-3.8.md b/articles/_posts/2024-06-04-version-0.13.13-drop-python-3.8.md
new file mode 100644
index 0000000..ef0108b
--- /dev/null
+++ b/articles/_posts/2024-06-04-version-0.13.13-drop-python-3.8.md
@@ -0,0 +1,15 @@
+---
+layout: post
+title: "PyBuilder 0.13.13: Python 3.8 End of Life"
+author: arcivanov
+categories: news
+---
+
+PyBuilder 0.13.13 drops support for Python 3.8, which reached end of life in
+October 2024. The minimum supported version is now Python 3.9.
+
+This release also improves handling of dependency extras in the `Dependency` class,
+fixing cases where extras specifications were not properly considered during
+dependency resolution.
+
+See the [release notes](/release-notes/v0.13.x) for details.
diff --git a/articles/_posts/2025-01-15-version-0.13.14-python-3.13.md b/articles/_posts/2025-01-15-version-0.13.14-python-3.13.md
new file mode 100644
index 0000000..6c7a0b9
--- /dev/null
+++ b/articles/_posts/2025-01-15-version-0.13.14-python-3.13.md
@@ -0,0 +1,12 @@
+---
+layout: post
+title: "PyBuilder 0.13.14: Python 3.13 and Security Fix"
+author: arcivanov
+categories: news
+---
+
+PyBuilder 0.13.14 adds official support for Python 3.13 and fixes
+[CVE-2024-53899](https://nvd.nist.gov/vuln/detail/CVE-2024-53899)
+in the bundled VirtualEnv dependency.
+
+See the [release notes](/release-notes/v0.13.x) for details.
diff --git a/articles/_posts/2025-08-22-version-0.13.17-pep517-build.md b/articles/_posts/2025-08-22-version-0.13.17-pep517-build.md
new file mode 100644
index 0000000..eff267e
--- /dev/null
+++ b/articles/_posts/2025-08-22-version-0.13.17-pep517-build.md
@@ -0,0 +1,21 @@
+---
+layout: post
+title: "PyBuilder 0.13.16-0.13.17: Free-Threaded Python and PEP 517 Build"
+author: arcivanov
+categories: news
+---
+
+Two releases bring significant modernization to PyBuilder's packaging pipeline:
+
+**0.13.16** adds support for free-threaded Python (3.13t and 3.14t), where the GIL
+is disabled. Free-threaded builds get their own venv directories (suffixed with `t`)
+to keep ABI-incompatible packages separate. This release also fixes deprecation
+warnings from the `pkg_resources` module.
+
+**0.13.17** migrates distribution building from the legacy
+`python setup.py sdist/bdist_wheel` invocation to the
+[PEP 517](https://peps.python.org/pep-0517/) `build` module. This aligns PyBuilder
+with the modern Python packaging ecosystem and avoids deprecation warnings from
+setuptools.
+
+See the [release notes](/release-notes/v0.13.x) for details.
diff --git a/articles/_posts/2026-03-27-version-0.13.19-extras-python-3.14.md b/articles/_posts/2026-03-27-version-0.13.19-extras-python-3.14.md
new file mode 100644
index 0000000..4f67100
--- /dev/null
+++ b/articles/_posts/2026-03-27-version-0.13.19-extras-python-3.14.md
@@ -0,0 +1,34 @@
+---
+layout: post
+title: "PyBuilder 0.13.19: Extras, Markers, Python 3.14, and Fedora Fix"
+author: arcivanov
+categories: news
+---
+
+PyBuilder 0.13.19 is a feature release with several notable additions:
+
+**Full extras and markers support.** The `depends_on()` method now accepts `extra`
+and `markers` keyword arguments. Extras let you define optional dependency groups
+that users install via `pip install mypackage[extra_name]`. Markers support PEP 508
+environment markers for platform-conditional dependencies:
+
+```python
+@init
+def initialize(project):
+ project.depends_on("pywin32", markers="sys_platform == 'win32'")
+ project.depends_on("cryptography", extra="security")
+```
+
+The generated `setup.py` now includes `extras_require` for extras and proper marker
+annotations for conditional dependencies.
+
+**Python 3.14 support.** Full CI coverage on CPython 3.14.
+
+**Python 3.9 dropped.** The minimum supported version is now Python 3.10.
+
+**Fedora/RHEL lib64 fix.** On distributions that install platform-specific packages
+to `lib64/` instead of `lib/` (Fedora, RHEL, CentOS), PyBuilder now correctly
+includes both paths in the venv's site-packages search, fixing `ModuleNotFoundError`
+for packages with C extensions like `coverage`.
+
+See the [release notes](/release-notes/v0.13.x) for details.
diff --git a/articles/_release-notes/v0.13.x.md b/articles/_release-notes/v0.13.x.md
index 69c094a..d48c013 100644
--- a/articles/_release-notes/v0.13.x.md
+++ b/articles/_release-notes/v0.13.x.md
@@ -6,12 +6,116 @@ list_title: Versions 0.13.x
# Release Notes - Versions 0.13.x
+## Version 0.13.19
+
+### New Features
+* [#941 Full extras and markers support for dependencies](https://github.com/pybuilder/pybuilder/pull/941)
+* Python 3.14 support
+
+### Removed Features
+* [#938 Dropped Python 3.9 support](https://github.com/pybuilder/pybuilder/pull/938)
+
+### Bugs Fixed
+* [#942 Fix lib64 site-packages not added to sys.path on Fedora/RHEL](https://github.com/pybuilder/pybuilder/pull/942)
+
+## Version 0.13.18
+
+### Vendorized Dependency Upgrades
+* Bumped vendorized dependencies
+* Upgraded coveralls to ~=4.0
+
+## Version 0.13.17
+
+### New Features
+* [#932 Migrate from `python setup.py sdist/bdist_wheel` to PEP 517 `build`](https://github.com/pybuilder/pybuilder/pull/932)
+
+## Version 0.13.16
+
+### New Features
+* Free-threaded Python support (3.13t, 3.14t)
+* [#929 Fix deprecated pkg_resource usage](https://github.com/pybuilder/pybuilder/pull/929)
+
+### Vendorized Dependency Upgrades
+* Bumped vendorized dependencies
+
## Version 0.13.14
### New Features
* Python 3.13 support
* Fix CVE-2024-53899 in bundled VirtualEnv
+## Version 0.13.13
+
+### Removed Features
+* Dropped Python 3.8 support
+
+### Bugs Fixed
+* [#913 Take extras into consideration for Dependency](https://github.com/pybuilder/pybuilder/pull/913)
+
+### Vendorized Dependency Upgrades
+* Vendorize packaging directly to avoid #909
+
+## Version 0.13.12
+
+### Vendorized Dependency Upgrades
+* Vendorize latest dependencies
+
+## Version 0.13.11
+
+### New Features
+* Python 3.12 officially supported
+
+## Version 0.13.10
+
+### Bugs Fixed
+* [#889 Fixes for Python 3.12](https://github.com/pybuilder/pybuilder/pull/889)
+
+### Removed Features
+* Dropped Python 3.7 support
+
+## Version 0.13.9
+
+### New Features
+* [#881 Add `eager_update` option to dependencies](https://github.com/pybuilder/pybuilder/pull/881)
+
+## Version 0.13.8
+
+### New Features
+* [#872 Managed venvs distinguish between debug and release versions of Python](https://github.com/pybuilder/pybuilder/pull/872)
+* [#659 Configurable log format command line parameter](https://github.com/pybuilder/pybuilder/pull/659)
+
+## Version 0.13.7
+
+### Bugs Fixed
+* Coverage source_path trailing slash fix
+* Python 3.11b3 compatibility
+
+## Version 0.13.6
+
+### New Features
+* Python 3.11 support
+
+### Bugs Fixed
+* Fix multiprocessing spawn for Python 3.11+
+* Fix unittest.TestCase results API for Python 3.11+
+* Fix vendorization on Windows with cp1252 encoding
+
+### Removed Features
+* Dropped Python 3.6 support
+
+## Version 0.13.5
+
+### Vendorized Dependency Upgrades
+* Bumped vendorized dependencies
+
+## Version 0.13.4
+
+### New Features
+* PyPy 3.8 support
+* Flake8 upgraded to >=4.0
+* Coverage upgraded to >=6.0
+* Fix site-packages path for PyPy venvs
+
## Version 0.13.3
### New Features
diff --git a/documentation/coding-agents.md b/documentation/coding-agents.md
new file mode 100644
index 0000000..115ff82
--- /dev/null
+++ b/documentation/coding-agents.md
@@ -0,0 +1,289 @@
+---
+layout: documentation
+title: Coding Agents
+---
+
+# Using PyBuilder with Coding Agents
+
+AI coding agents such as Claude Code, GitHub Copilot, Cursor, Windsurf and others
+can work effectively with PyBuilder projects when given the right context. This page
+provides guidance for coding agents on PyBuilder's conventions, and describes how to
+configure agent instruction files for PyBuilder projects.
+
+## Quick Reference for Agents
+
+This section is written for coding agents directly. If you are a coding agent working
+on a PyBuilder project, the information below tells you what you need to know.
+
+### Build Commands
+
+All build commands use `pyb` (the PyBuilder CLI):
+
+```bash
+# Full build (compile, test, analyze, package, publish)
+pyb
+
+# Verbose output
+pyb -v
+
+# Debug verbose output (all debug logging)
+pyb -vX
+
+# Run only unit tests
+pyb run_unit_tests
+
+# Run only integration tests
+pyb run_integration_tests
+
+# Clean and rebuild
+pyb clean package
+
+# List available tasks
+pyb -t
+
+# Set a property from the command line
+pyb -P property_name=value
+```
+
+### Project Layout
+
+PyBuilder uses a convention-based directory layout similar to Maven:
+
+```
+build.py # Build descriptor (like pom.xml or build.gradle)
+src/main/python/ # Main Python source code
+src/main/scripts/ # Executable scripts
+src/unittest/python/ # Unit tests (*_tests.py)
+src/integrationtest/python/ # Integration tests (*_tests.py)
+target/ # Build output (gitignored)
+target/dist/ # Distribution artifacts
+target/reports/ # Test and analysis reports
+```
+
+These paths are defaults and can be overridden in `build.py` via project properties.
+
+### The build.py File
+
+`build.py` is a Python script that configures the project. It declares metadata,
+plugins, and dependencies:
+
+```python
+from pybuilder.core import use_plugin, init
+
+# Plugins provide build capabilities
+use_plugin("python.core")
+use_plugin("python.unittest")
+use_plugin("python.coverage")
+use_plugin("python.flake8")
+use_plugin("python.distutils")
+
+# Project metadata (module-level variables)
+name = "my-project"
+default_task = "publish"
+
+@init
+def initialize(project):
+ # Runtime dependencies
+ project.depends_on("requests", ">=2.20")
+ project.depends_on("click")
+
+ # Build/test dependencies
+ project.build_depends_on("mockito")
+
+ # Plugin configuration via properties
+ project.set_property("coverage_break_build", False)
+ project.set_property("flake8_max_line_length", 120)
+```
+
+### Dependencies
+
+Dependencies are declared in initializer functions:
+
+```python
+@init
+def initialize(project):
+ # Runtime dependency with version constraint
+ project.depends_on("requests", ">=2.20")
+
+ # Build-time dependency (testing, analysis, etc.)
+ project.build_depends_on("mockito")
+
+ # Plugin dependency (installed into plugin venv)
+ project.plugin_depends_on("my-custom-plugin")
+
+ # From a requirements file
+ project.depends_on_requirements("requirements.txt")
+ project.build_depends_on_requirements("requirements-dev.txt")
+```
+
+### Writing Tests
+
+Unit tests go in `src/unittest/python/` and must match the glob `*_tests.py`:
+
+```python
+# src/unittest/python/my_module_tests.py
+import unittest
+from my_module import my_function
+
+class MyModuleTests(unittest.TestCase):
+ def test_my_function(self):
+ self.assertEqual(my_function(2), 4)
+```
+
+Integration tests go in `src/integrationtest/python/` with the same naming convention.
+
+### Virtual Environments
+
+PyBuilder manages isolated venvs automatically. Do not install dependencies manually;
+declare them in `build.py` and PyBuilder handles the rest.
+
+- `.pybuilder/plugins/{version}/` — plugin dependencies (PyPI plugins)
+- `target/venv/build/{version}/` — build/test tool dependencies (`build_depends_on()` + `depends_on()`)
+- `target/venv/test/{version}/` — integration test runtime (`depends_on()` only)
+
+Unit tests run in the **build** venv. Integration tests run in the **test** venv.
+
+### Build Output and Logs
+
+After a build, look for:
+
+- `target/reports/unittest` — unit test console output
+- `target/reports/unittest.json` — structured unit test results
+- `target/reports/TEST-*.xml` — JUnit XML test results
+- `target/reports/integrationtests/{test_name}` — per-integration-test stdout
+- `target/reports/integrationtests/{test_name}.err` — per-integration-test stderr
+- `target/reports/{name}_coverage.json` — coverage data per module
+- `target/reports/{name}_coverage_html/` — interactive HTML coverage report
+- `target/dist/` — distribution package
+- `target/logs/install_dependencies/` — pip install logs
+
+Use `pyb -v` to see individual test names. Use `pyb -vX` for full debug logging
+including subprocess sys.path details and remoting diagnostics.
+
+### Key Differences from setuptools/poetry/hatch
+
+- **No `setup.py` or `pyproject.toml` to edit** — PyBuilder generates `setup.py`
+ from `build.py` configuration. The `pyproject.toml`, if present, is a PEP 517
+ build backend shim, not the project configuration.
+- **Source code is not at the repo root** — it is under `src/main/python/`.
+- **Tests are not in a `tests/` directory** — they are under `src/unittest/python/`
+ and `src/integrationtest/python/`.
+- **Dependencies are not in a requirements file by default** — they are declared
+ programmatically in `build.py` via `project.depends_on()`.
+- **Build output goes to `target/`** — not `dist/` or `build/`.
+
+## Setting Up Agent Instructions
+
+Most coding agents support project-level instruction files that provide context
+about the project's conventions. When working on a PyBuilder project, the agent
+instruction file should describe the build system so the agent knows how to build,
+test, and navigate the project.
+
+### Supported Instruction Files
+
+Most coding agents read a Markdown file from the project root for context.
+`AGENTS.md` is an emerging cross-tool standard supported by many agents.
+Some agents also have their own tool-specific files:
+
+| Agent | File | Notes |
+|-------|------|-------|
+| [AGENTS.md standard](https://agents.md/) | `AGENTS.md` | Cross-tool standard (OpenAI Codex, GitHub Copilot, Google Jules/Gemini CLI, Cursor, Roo Code, Aider, JetBrains Junie) |
+| Claude Code | `CLAUDE.md` | Also supports `.claude/rules/*.md` for modular rules |
+| GitHub Copilot | `.github/copilot-instructions.md` | Also reads `AGENTS.md` |
+| Cursor | `.cursor/rules/*.mdc` | MDC format with YAML frontmatter; also reads `AGENTS.md` |
+| Windsurf | `.windsurfrules` or `.windsurf/rules/*.md` | 6000 char limit per file |
+| Cline | `.clinerules` or `.clinerules/*.md` | Inserted into system prompt verbatim |
+| Roo Code | `.roo/rules/*.md` | Also reads `AGENTS.md` |
+| Aider | `CONVENTIONS.md` | Loaded via `--read` flag; also reads `AGENTS.md` |
+| Gemini CLI | `GEMINI.md` | Supports `@file.md` imports |
+| JetBrains Junie | `.junie/guidelines.md` | Configurable to read `AGENTS.md` instead |
+| Amazon Q Developer | `.amazonq/rules/*.md` | Directory of Markdown rule files |
+
+All formats use plain Markdown for the instruction body. A practical approach for
+maximum coverage is to maintain an `AGENTS.md` (covers most tools) and a `CLAUDE.md`
+(covers Claude Code), with both sharing largely the same content.
+
+### Recommended Content
+
+A good agent instruction file for a PyBuilder project should include:
+
+**Project overview** — what the project does, one or two sentences.
+
+**Build commands** — how to build, test, and run analysis. Always include:
+```markdown
+## Building & Testing
+
+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 -v` — verbose output
+- `pyb -vX` — debug verbose output
+```
+
+**Project layout** — if the defaults are used, a brief note is enough.
+If directories are customized, specify the actual paths:
+```markdown
+## Project Layout
+
+- Source: `src/main/python/`
+- Unit tests: `src/unittest/python/` (files matching `*_tests.py`)
+- Integration tests: `src/integrationtest/python/`
+- Build descriptor: `build.py`
+```
+
+**Code style** — any linting or formatting rules enforced by the build:
+```markdown
+## Code Style
+
+- flake8 is enforced by the build (max line length: 120)
+- All source files have Apache License 2.0 headers
+```
+
+**Dependency management** — how to add dependencies:
+```markdown
+## Adding Dependencies
+
+Edit `build.py` and add to the initializer:
+- Runtime: `project.depends_on("package-name", ">=1.0")`
+- Build/test: `project.build_depends_on("package-name")`
+```
+
+### Example CLAUDE.md
+
+Here is a complete example for a typical PyBuilder project:
+
+```markdown
+# My Project — Project Instructions
+
+## Overview
+
+MyProject is a REST API client library for the Acme service.
+
+## Building & Testing
+
+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 -v` — verbose output
+- `pyb -vX` — debug verbose output
+
+## Project Layout
+
+Standard PyBuilder layout:
+- `build.py` — build descriptor
+- `src/main/python/` — source code
+- `src/unittest/python/` — unit tests (`*_tests.py`)
+- `src/integrationtest/python/` — integration tests
+
+## Code Style
+
+- Max line length: 120 (flake8 enforced)
+
+## Git Workflow
+
+PRs to `master`. Always run `pyb` before pushing.
+```
diff --git a/documentation/developing-pybuilder.md b/documentation/developing-pybuilder.md
index b0afe40..5b5d7d4 100644
--- a/documentation/developing-pybuilder.md
+++ b/documentation/developing-pybuilder.md
@@ -12,4 +12,14 @@ This script behaves exactly as the PyBuilder program `pyb`.
You can use the `install_dependencies` task with `./build.py install_dependencies` to pull in all the required runtime and build dependencies.
Afterwards, running `./build.py` will do a full build including all tests, linting and packaging.
-[The following screencast](https://asciinema.org/a/8811) shows how to get the sources and run a full build from scratch. Please note that you need [virtualenv](http://www.virtualenv.org/en/latest/) installed.
+PyBuilder requires Python 3.10 or later. We recommend using a
+[virtual environment](https://docs.python.org/3/library/venv.html) for development:
+
+```bash
+git clone https://github.com/pybuilder/pybuilder
+cd pybuilder
+python3 -m venv venv
+source venv/bin/activate
+pip install pybuilder
+./build.py
+```
diff --git a/documentation/index.md b/documentation/index.md
index 3d33eb9..76458c9 100644
--- a/documentation/index.md
+++ b/documentation/index.md
@@ -21,6 +21,8 @@ title: PyBuilder Documentation
### [IDE Integration]({% link documentation/ide.md %})
+### [Coding Agents]({% link documentation/coding-agents.md %})
+
## Developer Documentation
### [Writing Plugins]({% link documentation/writing-plugins.md %})
diff --git a/documentation/installation.md b/documentation/installation.md
index 12fd4fa..09f54d1 100644
--- a/documentation/installation.md
+++ b/documentation/installation.md
@@ -7,20 +7,19 @@ title: Installing PyBuilder
## PIP
-Prior to version 0.12.0 the recommendation was to install *PyBuilder* into a
-[virtual environment](http://pypi.python.org/pypi/virtualenv) using [pip](http://pypi.python.org/pypi/pip):
+*PyBuilder* can be installed using [pip](https://pypi.python.org/pypi/pip):
`pip install pybuilder`
-While this is still a preferred way, beginning with version 0.12.0 *PyBuilder* no longer alters the environment
-it is installed in by virtue of managing its own `venvs` and therefore can be safely installed into the
-system-wide Python via `sudo pip install pybuilder`.
+*PyBuilder* manages its own virtual environments and does not alter the environment
+it is installed in. It can be safely installed into a
+[virtual environment](https://docs.python.org/3/library/venv.html) or system-wide.
## Installing From Source
-Starting with version 0.12.0 PyBuilder supports PEP-517 (`pyproject.toml`) and can be installed with PIP from source:
+PyBuilder supports PEP-517 (`pyproject.toml`) and can be installed with pip from source:
-`pip install git+git://github.com/pybuilder/pybuilder`
+`pip install git+https://github.com/pybuilder/pybuilder`
## Building From Source
diff --git a/documentation/manual.md b/documentation/manual.md
index 6842e91..6db5049 100644
--- a/documentation/manual.md
+++ b/documentation/manual.md
@@ -85,12 +85,14 @@ receive components:
A logger instance which can be used to issue messages to the user.
project
An instance of the project that is currently being built.
+
reactor
+
An instance of the Reactor that manages the build lifecycle.
Thus we can rewrite the task above to use the logger:
-
from pythonbuilder.core import task
+
from pybuilder.core import task
@task
def say_hello (logger):
@@ -212,3 +214,387 @@ Properties can be set or overridden using command line switches.
This command sets/ overrides the property with the name ```spam``` with the value ```spam message```.
Note that command line switches only allow properties to be set/ overridden using string values.
+
+## Virtual Environment Infrastructure
+
+*PyBuilder* manages isolated Python virtual environments for building and testing.
+Understanding this infrastructure is essential for troubleshooting dependency issues
+and configuring advanced build scenarios.
+
+### The Four Python Environments
+
+PyBuilder maintains up to four distinct Python environments during a build:
+
+
+
+
Name
+
Location
+
Purpose
+
What Gets Installed
+
+
+
system
+
The Python running PyBuilder
+
Baseline environment, fallback when venvs are disabled
+
PyBuilder itself
+
+
+
pybuilder
+
.pybuilder/plugins/{version}/
+
Plugin dependencies (PyPI plugins)
+
Packages required by use_plugin("pypi:...") and plugin_depends_on()
+
+
+
build
+
target/venv/build/{version}/
+
Build and test tools
+
build_depends_on() + depends_on() dependencies
+
+
+
test
+
target/venv/test/{version}/
+
Integration test runtime
+
depends_on() dependencies only
+
+
+
+The `{version}` directory name is derived from the Python implementation and version,
+for example `cpython-3.13.2` or `pypy-7.3.12`. Free-threaded builds append `t`
+(e.g. `cpython-3.14.0t`) and debug builds append `-debug`.
+
+### Environment Lifecycle
+
+The environments are created in this order during a build:
+
+1. **system** is registered at startup from the Python running `pyb`.
+2. **pybuilder** is created during `prepare_build()`, *before* any plugins are loaded.
+ Its site-packages are added to `sys.path` so that plugin imports succeed.
+3. **build** and **test** are created during the `prepare` task, after plugins and
+ initializers have run. Dependencies declared via `depends_on()` and
+ `build_depends_on()` are installed via pip into the appropriate venvs.
+
+### Directory Layout
+
+
+
+### Which Environment Runs What
+
+- **Unit tests** run in the **build** environment by default
+ (controlled by `unittest_python_env` property).
+- **Integration tests** run in the **test** environment by default
+ (controlled by `integrationtest_python_env` property).
+- **Plugin code** (flake8, coverage, pylint, etc.) runs using packages from the
+ **pybuilder** environment.
+
+### Controlling Venv Behavior
+
+
@init
+def initialize(project):
+ # Force recreation of venvs on every build
+ project.set_property("refresh_venvs", True)
+
+ # Customize which venvs are created (default: ["build", "test"])
+ project.set_property("venv_names", ["build", "test"])
+
+ # Override default dependency mapping per venv
+ project.set_property("venv_dependencies", {
+ "build": [Dependency("pytest"), Dependency("coverage")],
+ "test": [Dependency("requests")]
+ })
+
+
+### Running Without Venvs
+
+Passing `--no-venvs` to `pyb` disables virtual environment creation. All environments
+fall back to the system Python. This is a legacy mode primarily used for debugging
+and is not recommended for normal builds, as it can lead to dependency conflicts
+and unreliable coverage results.
+
+## Unit Testing in Detail
+
+The `python.unittest` plugin executes unit tests using Python's `unittest` module
+with subprocess isolation and remote object proxying.
+
+### Test Discovery
+
+Tests are discovered by scanning `src/unittest/python/` (configurable via
+`dir_source_unittest_python`) for files matching the `unittest_module_glob` pattern
+(default: `*_tests`). File paths are converted to Python module names:
+
+- `src/unittest/python/foo_tests.py` becomes module `foo_tests`
+- `src/unittest/python/pkg/bar_tests.py` becomes module `pkg.bar_tests`
+
+### Subprocess Isolation and Remoting
+
+Unit tests do **not** run in the main PyBuilder process. Instead, the plugin uses
+a remoting mechanism based on Python's `multiprocessing` module:
+
+1. **Spawn subprocess**: A child process is started using the **build** venv's
+ Python interpreter. The `multiprocessing` module is patched so that:
+ - The child uses the build venv's `python` executable
+ - The child's `sys.path` is remapped to use the build venv's site-packages
+ instead of the parent process's
+
+2. **Load tests in child**: The subprocess inserts `src/unittest/python/` and
+ `src/main/python/` at the front of `sys.path`, then uses
+ `unittest.defaultTestLoader.loadTestsFromNames()` to import and discover tests.
+
+3. **Proxy tests to parent**: The loaded test suite is exposed to the parent process
+ through a `RemoteObjectPipe`. The parent receives a proxy object that can invoke
+ methods on the real test objects in the child.
+
+4. **Execute via runner**: The parent's test runner (default: `XMLTestRunner`) calls
+ `runner.run(tests)`. Each test method invocation is proxied as an RPC call to the
+ child process, where the actual test code executes. Results are marshaled back
+ via pickle serialization.
+
+5. **Collect results**: After all tests complete, the pipe is closed and the
+ subprocess terminates.
+
+This architecture ensures that:
+- Test imports cannot pollute the build process
+- Each test run starts with clean module state
+- Build tool dependencies (coverage, xmlrunner) are available via the build venv
+- Source code is imported from `src/main/python/`, not from installed packages
+
+### Unit Test Logs and Reports
+
+Unit test output is written to `target/reports/`:
+
+
+
+
File
+
Format
+
Contents
+
+
+
target/reports/unittest
+
Text
+
Console output from the test run
+
+
+
target/reports/unittest.json
+
JSON
+
Structured results: test count, errors, failures with tracebacks
+
+
+
target/reports/TEST-*.xml
+
JUnit XML
+
Per-test-class XML results (generated by xmlrunner)
+
+
+
+Use `pyb -v` to see individual test names as they execute. Use `pyb -vX` for full
+debug logging including subprocess sys.path details and remoting diagnostics.
+
+## Integration Testing in Detail
+
+The `python.integrationtest` plugin runs each integration test as a standalone
+subprocess. Unlike unit tests, there is no remoting or RPC; each test file is
+executed as an independent Python script.
+
+### Test Discovery
+
+Integration tests are discovered by scanning `src/integrationtest/python/`
+(configurable via `dir_source_integrationtest_python`) for files matching
+`integrationtest_file_glob` (default: `*_tests.py`).
+
+### Execution Model
+
+Each test file is executed in its own process:
+
+
# Effective command for each test:
+/path/to/target/venv/test/{version}/bin/python test_file.py [additional_args]
+
+
+The test venv's Python executable is used (controlled by
+`integrationtest_python_env`, default: `"test"`).
+
+### Classpath and PYTHONPATH
+
+Integration tests import source code from the **built distribution**, not from
+`src/main/python/` directly. The `PYTHONPATH` is set to:
+
+
+
+This means the `package` task must complete before integration tests run (which is
+enforced by task dependencies). The distribution in `target/dist/` contains the
+compiled/copied source code, ensuring tests run against the actual distributable
+package.
+
+### Environment Variables
+
+The integration test environment is constructed in layers:
+
+1. **PYTHONPATH** is set to the distribution and test source directories.
+2. **Additional environment** variables from the `integrationtest_additional_environment`
+ property (a dict) are merged in.
+3. If `integrationtest_inherit_environment` is `True` (default: `False`), the test
+ venv's full environment (including PATH with venv bin directory) is used as the
+ base. Otherwise, only the explicitly set variables are passed.
+
+### Integration Test Logs and Reports
+
+Each integration test produces its own output files in `target/reports/integrationtests/`:
+
+
+
+
File
+
Contents
+
+
+
target/reports/integrationtests/{test_name}
+
Standard output from the test process
+
+
+
target/reports/integrationtests/{test_name}.err
+
Standard error from the test process
+
+
+
+Where `{test_name}` is the test filename without its `.py` extension.
+
+On failure (non-zero exit code), or when `integrationtest_always_verbose` is `True`,
+the content of both stdout and stderr files is printed to the console. On success,
+output is silent unless verbose mode is enabled.
+
+## Coverage in Detail
+
+The `python.coverage` plugin measures code coverage by instrumenting test execution.
+It does not re-run tests; instead, it wraps the test task so that coverage measurement
+is active during the single test execution.
+
+### How Coverage Works
+
+The coverage task executes *after* the tasks it measures (e.g. `run_unit_tests`).
+However, coverage instrumentation occurs during task execution through environment
+override:
+
+1. **During `prepare`**: The plugin checks which tasks are eligible for coverage
+ measurement (tasks registered via `CoveredTask`, typically `run_unit_tests`).
+
+2. **During `coverage` task execution**: For each covered task:
+ - A `CoverageTool` is registered with the reactor
+ - The Python environment for the covered task is overridden to inject a coverage
+ shim script into the subprocess
+ - The covered task (e.g. `run_unit_tests`) is re-executed with coverage active
+ - Coverage data is collected from the subprocess via `coverage.combine()`
+
+3. **After execution**: Coverage data from all covered tasks is aggregated, thresholds
+ are checked, and reports are generated.
+
+### Thresholds
+
+Coverage enforces three independent threshold types:
+
+
+
+
Property
+
Default
+
What It Measures
+
+
+
coverage_threshold_warn
+
70
+
Percentage of statements executed
+
+
+
coverage_branch_threshold_warn
+
0 (disabled)
+
Percentage of branches taken
+
+
+
coverage_branch_partial_threshold_warn
+
0 (disabled)
+
Percentage of branches not partially executed
+
+
+
+When `coverage_break_build` is `True` (the default) and any threshold is violated,
+the build fails with a `BuildFailedException`.
+
+### Module Discovery for Coverage
+
+Coverage measures modules found in `coverage_source_path` (default:
+`$dir_source_main_python`). Modules listed in `coverage_exceptions` are excluded.
+Modules with syntax errors are automatically excluded with a warning. Each module's
+coverage is reported individually, and an aggregate is computed across all modules.
+
+### Coverage Reports
+
+Coverage generates reports in `target/reports/`:
+
+
+
+
File
+
Format
+
Contents
+
+
+
target/reports/{name}_coverage
+
Text
+
Human-readable coverage summary
+
+
+
target/reports/{name}_coverage.json
+
JSON
+
Per-module coverage data with line/branch details
+
+
+
target/reports/{name}_coverage.xml
+
Cobertura XML
+
For CI/CD integration (Jenkins, GitHub Actions, etc.)
+
+
+
target/reports/{name}_coverage_html/
+
HTML
+
Interactive coverage report with source annotation
+
+
+
+Where `{name}` is derived from the project name (e.g. `My_Project_coverage.json`).
+
+### Reading Coverage Output
+
+In verbose mode (`pyb -v`), coverage reports per-module statistics:
+
+
+[INFO] Overall my_project coverage is 85%
+[INFO] Overall my_project branch coverage is 72%
+
+
+The HTML report in `target/reports/{name}_coverage_html/index.html` provides the
+most detailed view, with source files annotated line-by-line showing which
+statements and branches were covered.
diff --git a/documentation/plugins.md b/documentation/plugins.md
index 17f0488..b6cc0f6 100644
--- a/documentation/plugins.md
+++ b/documentation/plugins.md
@@ -68,6 +68,20 @@ The plugin executes all test cases found in modules ending with `_tests.py` in t
unittest_module_glob with an appropriate glob pattern by prefixing the
value with an asterisk (*) and removing the ".py" extension.
+
+
+
unittest_breaks_build
+
boolean
+
True
+
Break the build when unit tests fail.
+
+
+
+
unittest_python_env
+
string
+
build
+
The Python environment to use for running unit tests.
+
### Measuring unittest coverage
@@ -115,28 +129,28 @@ Use the ```python.coverage``` module to activate coverage.
-
coverage_allow_non_imported_modules
-
bool
-
True
-
Allow modules which were not imported by the covered tests.
-
+
coverage_exceptions
+
list of strings
+
empty
+
List of package names to exclude from coverage analysis.
List of package names to exclude from coverage analyzation.
+
coverage_source_path
+
string
+
$dir_source_main_python
+
The source path to measure coverage for.
-Please note that properties `coverage_reload_modules` and `coverage_fork` are deprecated and will not be used.
+Please note that properties `coverage_allow_non_imported_modules`, `coverage_reset_modules`, `coverage_reload_modules` and `coverage_fork` are deprecated and will not be used.
### SonarQube integration
@@ -170,53 +184,6 @@ Using the plugin `python.sonarqube` will add the task `run_sonar_analysis` to yo
### Linting python sources
-#### Frosted plugin
-
-Frosted is a fork of pyflakes (originally created by Phil Frost) that aims at more open contribution from the outside public, a smaller more maintainable code base, and a better Python checker for all.
-
-
-##### Frosted configuration
-
-
-
-
Name
-
Type
-
Default Value
-
Description
-
-
-
-
frosted_break_build
-
boolean
-
False
-
Break the build if warnings are found
-
-
-
-
frosted_include_test_sources
-
boolean
-
False
-
Also run frosted on integrationtest and unittest sources
-
-
-
-
frosted_include_scripts
-
boolean
-
False
-
Also run the frosted linter on all files in $dir_source_main_scripts
-
-
-
-
frosted_ignore
-
List of strings
-
[ ]
-
List of warnings to exclude
- Example: ["E205", "W101"].
- See here, section Frosted error codes, for reference (or use frosted --verbose to check).
-
-
-
-
#### Flake8 plugin
*PyBuilder* can lint your files and verify (or enforce) compliance with
@@ -270,6 +237,14 @@ Use the ```python.flake8``` module to activate linting.
Maximum allowed line length
+
+
flake8_include_patterns
+
string
+
None
+
Comma separated list of file patterns to include
+ Example: "*.py"
+
+
flake8_exclude_patterns
string
@@ -280,42 +255,27 @@ Use the ```python.flake8``` module to activate linting.
-
flake8_verbose_output
-
boolean
-
False
-
Display flake8 warnings and errors in command line output.
+
flake8_max_complexity
+
integer
+
None
+
Maximum allowed McCabe complexity. When set, enables the flake8 complexity checker.
-
-
-
-#### Pychecker plugin
-
-Using the plugin `python.pychecker` will let pychecker run on python source modules.
-
-##### Pychecker configuration
-
-
-
Name
-
Type
-
Default Value
-
Description
+
flake8_extend_ignore
+
string
+
None
+
Comma separated list of error codes to add to the ignore list (extends rather than overrides flake8_ignore)
+ Example: "E303,F401"
-
pychecker_break_build
+
flake8_verbose_output
boolean
-
True
-
Break the build if warnings are found.
+
False
+
Display flake8 warnings and errors in command line output.
-
-
pychecker_break_build_threshold
-
integer
-
0
-
Threshold to break the build. A threshold of `n` means: "break the build if more than `x` warnings are found".
-
#### Pylint plugin
@@ -338,6 +298,27 @@ Using the plugin `python.pylint` will let pylint run on python source modules.
Also run pylint on integrationtest and unittest sources.
+
+
+
+
pylint_include_scripts
+
boolean
+
False
+
Also run pylint on all files in $dir_source_main_scripts.
+
#### Pep8 plugin
@@ -442,32 +423,41 @@ the production source directory.
integrationtest_file_glob with an appropriate glob pattern by prefixing the
value with an asterisk (*).
-
-
-
-
Python 3.2 warning
-We have experienced strange problems (EOFErrors) on python 3.2. This seems to be due to a bug with pickling randomly raising EOFError. We recomment updating to python 3.3 or 3.4, where it works fine.
-
+
+
integrationtest_breaks_build
+
boolean
+
True
+
Break the build when integration tests fail.
+
+
+
+
integrationtest_always_verbose
+
boolean
+
False
+
Always display integration test output, not only on failures.
+
+
+
+
integrationtest_python_env
+
string
+
test
+
The Python environment to use for running integration tests.
+
+
+
+
integrationtest_python_env_recreate
+
boolean
+
False
+
Recreate the integration test Python environment before running tests.
+
+
### Running Cram tests
[Cram is a functional testing framework for command line applications based on Mercurial's unified test format.](https://pypi.python.org/pypi/cram)
The plugin `python.cram` can be used to run tests written for cram. Cram tests run during `run_integration_tests` but there is also a separate task available (`run_cram_tests`).
-
-
-
Python 3.2.3 warning
-Cram crashes on python 3.2.3 : https://bitbucket.org/brodie/cram/issue/28/crash-on-323 (no longer available). An easy workaround is to not use the plugin on python 3.2 :
-
-
-
-if not sys.version_info[0:2] == (3,2):
- use_plugin("python.cram")
-
-
-
-
#### Cram properties
@@ -609,6 +599,19 @@ Note that the `*_depends_on` methods accept the following arguments :
url
Optional keyword argument (None default). Set it to an editable URL where the dependency should be downloaded from.
+
+
+
extra
+
Optional keyword argument (None default). Only available on depends_on.
+ Assigns the dependency to an extras group (e.g. extra="security"). Users can then install it
+ via pip install mypackage[security].
+
+
+
+
markers
+
Optional keyword argument (None default). PEP 508 environment markers for conditional
+ dependencies (e.g. markers="sys_platform == 'win32'").
+
The logic of version goes as follows:
@@ -743,7 +746,7 @@ def initialize (project):
distutils_commands
list of strings
-
sdist, bdist_dump
+
sdist, wheel
Commands to execute using the generated setup.py script during publish
@@ -783,12 +786,6 @@ def initialize (project):
The identity to sign each file with, when distutils_upload_sign is True
from other famous build tools like Apache Maven and Gradle.
- PyBuilder runs on Python 3.9 to 3.13 and PyPy.
+ PyBuilder runs on Python 3.10 to 3.14 and PyPy.
Every commit is tested via
GitHub Actions
- on CPython 3.9, 3.10, 3.11, 3.12, 3.13 and PyPy on Linux, MacOS
+ on CPython 3.10, 3.11, 3.12, 3.13, 3.14 and PyPy on Linux, MacOS
(with and without Homebrew) and Windows.
+
+ v0.13.17 is the last version supporting Python 3.9.
+
v0.13.13 is the last version supporting Python 3.8.
@@ -182,7 +185,7 @@
pip install pybuilder
- We recommend using virtualenv.
+ We recommend using a virtual environment.
Please see the dedicated installation page.