Skip to content
Open
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
157 changes: 25 additions & 132 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,146 +1,39 @@
# Contributing to B2 Python SDK

We encourage outside contributors to perform changes on our codebase. Many such changes have been merged already.
In order to make it easier to contribute, core developers of this project:
We encourage outside contributors to perform changes on our codebase. Many such changes have been merged
already.

* provide guidance (through the issue reporting system)
* provide tool assisted code review (through the Pull Request system)
* maintain a set of unit tests
* maintain a set of integration tests (run with a production cloud)
* maintain development automation tools using [nox](https://github.com/theacodes/nox) that can easily:
* format the code using [ruff](https://github.com/astral-sh/ruff)
* runs linters to find subtle/potential issues with maintainability
* run the test suite on multiple Python versions using [pytest](https://github.com/pytest-dev/pytest)
* maintain Continuous Integration (by using GitHub Actions) that:
* runs all sorts of linters
* checks if the Python distribution can be built
* runs all tests on a matrix of 8 versions of Python (including pypy) and 3 operating systems
(Linux, Mac OS X and Windows)
* checks if the documentation can be built properly
* maintain other Continuous Integration tools (coverage tracker)
**The full contributors guide is published at
[b2-sdk-python.readthedocs.io/en/master/contributing.html](https://b2-sdk-python.readthedocs.io/en/master/contributing.html)**
(source: [`doc/source/contributing.rst`](doc/source/contributing.rst)). It is the canonical reference for
environment setup, the available `nox` sessions, dependency management, testing, and building the
documentation. This file is a short entry point only — please keep detailed guidance in the published
guide rather than duplicating it here.

## Versioning
## Getting started

This package's versions adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and the versions are
established by reading git tags, i.e. no code or manifest file changes are required when working on PRs.
You'll need [nox](https://github.com/theacodes/nox) and [uv](https://docs.astral.sh/uv/):

## Changelog
pip install nox uv

Each PR needs to have at least one changelog (aka news) item added. This is done by creating files in `changelog.d`.
`towncrier` is used for compiling these files into [CHANGELOG.md](CHANGELOG.md). There are several types of changes
(news):

1. fixed
2. changed
3. added
4. deprecated
5. removed
6. infrastructure
7. doc


The `changelog.d` file name convention is:

1. If the PR closes a github issue: `{issue_number}.{type}.md` e.g. `157.fixed.md`. Note that the
change description still has to be complete, linking an issue is just there for convenience, a change like
`fixed #157` will not be accepted.
2. If the PR is not related to a github issue: `+{unique_string}.{type}.md` e.g. `+foobar.fixed.md`.

These files can either be created manually, or using `towncrier` e.g.

towncrier create -c 'write your description here' 157.fixed.md

`towncrier create` also takes care of duplicates automatically (if there is more than 1 news fragment of one type
for a given github issue).

## Developer Info

You'll need to have [nox](https://github.com/theacodes/nox) and [uv](https://docs.astral.sh/uv/) installed:

* `pip install nox uv`

With `nox`, you can run different sessions (default are `lint` and `test`):

* `format` -> Format the code.
* `lint` -> Run linters.
* `test` (`test-3.10`, `test-3.11`, `test-3.12`, `test-3.13`, `test-3.14`, `test-pypy3.10`) -> Run test suite.
* `cover` -> Perform coverage analysis.
* `build` -> Build the distribution.
* `doc` -> Build the documentation.
* `doc_cover` -> Perform coverage analysis for the documentation.

For example:

$ nox -s format
nox > Running session format
nox > Creating virtual environment (virtualenv) using python3.14 in .nox/format
...

$ nox -s format
nox > Running session format
nox > Re-using existing virtual environment at .nox/format.
...

$ nox --no-venv -s format
nox > Running session format
...

Sessions `test` ,`unit`, and `integration` can run on many Python versions, 3.10-3.14 (+ pypy3.10) by default.

Sessions other than `test` use the last CPython version from `NOX_PYTHONS`, 3.14 by default.

You can change it:

export NOX_PYTHONS=3.12,3.14

With the above setting, session `test` will run on Python 3.12 and 3.14, and all other sessions on Python 3.14.

Given Python interpreters should be installed in the operating system or via [pyenv](https://github.com/pyenv/pyenv).

## Managing dependencies

We use [uv](https://docs.astral.sh/uv/) for managing dependencies and developing locally.
If you want to change any of the project requirements (or requirement bounds) in `pyproject.toml`,
make sure that `uv.lock` file reflects those changes by using `uv add`, `uv lock` or other
commands - see [documentation](https://docs.astral.sh/uv/). You can verify that the lock file
is up to date by running `uv lock --check`.

## Linting

To run all available linters:
Then, to run the linters and the test suite:

nox -s lint

## Testing

To run all tests on every available Python version:

nox -s test

To run all tests on a specific version:

nox -s test-3.10

To run just unit tests:

nox -s unit-3.10

To run just integration tests:

export B2_TEST_APPLICATION_KEY=your_app_key
export B2_TEST_APPLICATION_KEY_ID=your_app_key_id
nox -s integration-3.10

To run tests by keyword expressions:

nox -s unit-3.10 -- -k keyword

## Documentation

To build the documentation and watch for changes (including the source code):
Integration tests need real B2 credentials; see the published guide for details.

nox -s doc
## Before you open a pull request

To just build the documentation:
* **Add a changelog entry.** Every PR needs at least one news fragment in `changelog.d`, or CI will
fail. Name it `{issue_number}.{type}.md` (e.g. `157.fixed.md`) when the PR closes an issue, or
`+{unique_string}.{type}.md` (e.g. `+foobar.fixed.md`) otherwise. Valid types are `fixed`, `changed`,
`added`, `deprecated`, `removed`, `infrastructure` and `doc`. The description must stand on its own —
a change like `fixed #157` will not be accepted. [towncrier](https://towncrier.readthedocs.io/)
compiles these into [CHANGELOG.md](CHANGELOG.md).
* **Don't bump the version.** Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
and are established by reading git tags, so no code or manifest changes are required in a PR.
* **Update `uv.lock` if you touched dependencies.** Use `uv add` or `uv lock`, and verify with
`uv lock --check`.

nox --non-interactive -s doc
Releases are cut by maintainers; see [README.release.md](README.release.md).
107 changes: 106 additions & 1 deletion README.release.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,108 @@
# Release Process

- Run `nox -s make_release_commit -- X.Y.Z` where `X.Y.Z` is the version you're releasing, and follow the instructions
Releasing **b2sdk** is part automated and part manual. A `nox` session prepares the changelog, a
maintainer commits and tags by hand, and the *Continuous Delivery* workflow
([`.github/workflows/cd.yml`](.github/workflows/cd.yml)) does everything from the tag onwards.

Nothing in the release is triggered by merging to `master`. Publishing begins only when a `v*` tag is
pushed.

## Prerequisites

* **A clean worktree.** `make_release_commit` aborts if `git diff --stat` reports anything. Note that
it inspects tracked files only, so untracked files will not stop it.
* **Release from `master`.** The session only *warns* when you are on another branch, it does not stop
you. Releasing from a feature branch is almost never what you want.
* **A version of the form `X.Y.Z`**, with integers and no leading `v` and no suffix. Anything else is
rejected.
* **An `upstream` remote** pointing at the release repository. `noxfile.py` defines the expected URL as
`UPSTREAM_REPO_URL`; the session prints a command to add it if it is missing.
* **Changelog fragments** for everything going out. Every PR should already have added one to
`changelog.d`; review that directory before starting, because whatever is there becomes the release
notes.

## Steps

### 1. Build the changelog

```
nox -s make_release_commit -- X.Y.Z
```

Despite the session's name, **this does not commit and does not tag.** It runs `towncrier build`, which
folds the `changelog.d` fragments into `CHANGELOG.md` and deletes the fragment files, then prints the
commands for the remaining steps. Review the resulting `CHANGELOG.md` diff before going further — this
is the last convenient moment to fix wording.

### 2. Commit and push

```
git commit -m "release X.Y.Z"
git push upstream master
```

### 3. Wait for CI

Let the *Continuous Integration* workflow finish on the pushed commit. Tagging a commit whose CI is red
means publishing a broken release, and a version number cannot be reused on PyPI.

### 4. Tag and push the tag

```
git tag vX.Y.Z
git push upstream vX.Y.Z
```

Pushing the tag is the point of no return.

## What the CD workflow does

Triggered by any pushed tag matching `v*`:

1. Decides whether the release is a prerelease, based only on whether the tag's last character is a
digit. `v1.2.3` is a normal release.
2. Builds the distribution with `nox -s build`, which also asserts the built package imports from
`site-packages` rather than the checkout. The version is derived from the tag, not from any file.
3. Reads the notes for that version out of `CHANGELOG.md`. If the tag and the changelog heading do not
match, there will be no release body.
4. Creates a GitHub release and attaches the distribution.
5. Uploads to PyPI — **only** when the `B2_PYPI_PASSWORD` secret is present *and* the release is not a
prerelease. A repository without that secret still gets a GitHub release and silently publishes
nothing to PyPI, so do not treat a green CD run as proof that PyPI was updated.

## After the release

* Confirm the GitHub release exists, has release notes, and has the distribution attached.
* If a PyPI publish was expected, confirm the new version is actually on PyPI.
* Confirm `pip install b2sdk==X.Y.Z` resolves.

## If something goes wrong

### Before the tag is pushed

Everything is still local and reversible. Remember that `towncrier build` **deleted** the changelog
fragments, so recovering means restoring them:

* Fragments deleted but not yet committed: `git checkout -- changelog.d CHANGELOG.md`.
* Already committed: `git reset --hard HEAD~1` (only if the commit has not been pushed), or revert it.

Then fix the problem and start again from step 1.

### After the tag is pushed, before PyPI published

Delete the tag locally and upstream, fix the problem, and re-tag:

```
git push upstream :refs/tags/vX.Y.Z
git tag -d vX.Y.Z
```

Delete the GitHub release too, if one was created. Re-using the version number is safe only while
nothing has reached PyPI.

### After PyPI published

The version is spent. PyPI does not allow re-uploading a version, even after deleting it. Do not try to
reuse the number — fix the problem and release the next patch version instead. If the published release
is actively harmful, yank it on PyPI (which hides it from new resolutions without breaking pins that
already reference it) and follow up with a fixed release.
10 changes: 5 additions & 5 deletions b2sdk/_internal/replication/monitoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ class ReplicationMonitor:

:param b2sdk.v2.Bucket bucket: replication source bucket
:param b2sdk.v2.ReplicationRule rule: replication rule to be monitored;
should belong to `bucket`'s replication configuration
should belong to `bucket`'s replication configuration
:param b2sdk.v2.B2Api destination_api: B2Api instance for destination
bucket; if destination bucket is on the same account as source bucket,
omit this parameter and then source bucket's B2Api will be used
bucket; if destination bucket is on the same account as source bucket,
omit this parameter and then source bucket's B2Api will be used
:param b2sdk.v2.ProgressReport report: instance of ProgressReport which will report
scanning progress, by default to stdout
scanning progress, by default to stdout
:param b2sdk.v2.ScanPoliciesManager scan_policies_manager: a strategy to scan
files, so that several files that match some criteria may be omitted
files, so that several files that match some criteria may be omitted
:rtype: b2sdk.v2.ReplicationMonitor
"""

Expand Down
1 change: 1 addition & 0 deletions changelog.d/+interface-boundary.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
State explicitly that being importable from a versioned namespace such as `b2sdk.v3` is not a compatibility promise, and document how to tell whether a name is public, internal, or unclassified.
1 change: 1 addition & 0 deletions changelog.d/584.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix the Quick Start examples to match the public `b2sdk.v3` interface: `EncryptionSetting` rather than `EncryptionSettings`, `EncryptionKey(key_id=...)` rather than `id=`, both required mappings for `BasicSyncEncryptionSettingsProvider`, and `file_info=` rather than `file_infos=`.
1 change: 1 addition & 0 deletions changelog.d/585.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Use `update_file_retention` instead of `update_file_legal_hold` in the Quick Start file-lock examples that pass a `FileRetentionSetting`.
1 change: 1 addition & 0 deletions changelog.d/586.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix the Advanced usage patterns guide to reference `UploadSourceLocalFile` rather than the nonexistent `LocalUploadSource`, and to call `bucket.create_file` rather than an undefined `planner` object.
1 change: 1 addition & 0 deletions changelog.d/588.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove the nonexistent `deploy` Nox session from the Contributors Guide and describe how releases are actually published by the Continuous Delivery workflow.
1 change: 1 addition & 0 deletions changelog.d/589.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Correct the stale CI test matrix description in the contributor guides, which claimed eight Python versions instead of the currently supported set.
1 change: 1 addition & 0 deletions changelog.d/590.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Correct the Installation Guide's development-install instructions, which told readers to check out the repository and then install the published package from PyPI instead of their local checkout.
1 change: 1 addition & 0 deletions changelog.d/591.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix typos in the Advanced usage patterns guide and remove an outdated time-relative claim about the library's age from the overview.
1 change: 1 addition & 0 deletions changelog.d/592.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Document how to choose a location for a new test in the Contributors Guide, covering the shared unit directories, the per-interface `v0`-`v3` directories, `v_all`, integration tests, the `apiver` marker, and a checklist for changes to `b2sdk/_internal`.
1 change: 1 addition & 0 deletions changelog.d/593.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Expand the release guide into a maintainer runbook covering prerequisites, the changelog build, the commit/CI/tag sequence, what the Continuous Delivery workflow does, post-release verification, and recovery before and after a tag is pushed.
1 change: 1 addition & 0 deletions changelog.d/595.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a task-oriented replication guide covering setup, required application-key capabilities, per-file replication status, monitoring and how to read a scan report, plus API reference pages for the public replication classes.
1 change: 1 addition & 0 deletions changelog.d/599.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Consolidate contributor guidance into the published Contributors Guide, and reduce `CONTRIBUTING.md` to a short entry point that links to it, so the two copies can no longer drift apart.
1 change: 1 addition & 0 deletions changelog.d/601.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Resolve the embedded documentation TODOs: drop the obsolete ones, make the "Why use b2sdk?" list consistent and linked, and document the progress reporters and the exception hierarchy properly.
Loading
Loading