-
Notifications
You must be signed in to change notification settings - Fork 0
Contributing and Development
This page covers working on PyCommander itself: the contribution workflow, setting up a development environment, running the tests, and the layout of the monorepo.
- Source: SiliconLabsSoftware/pycommander
-
License: Silicon Labs Master Software License Agreement (MSLA),
LicenseRef-MSLA. - Code of Conduct: see the agreements-and-guidelines repository.
PyCommander is open source and welcomes community patches. The authoritative process lives in the repository's .github/CONTRIBUTING.md; the essentials are summarized here.
- Open an issue first. Discuss the bug or enhancement before writing code so the change can be scoped and tracked.
- Fork, don't branch. Direct branching is disabled on the public Silicon Labs repositories — fork the repo and work on a branch in your fork.
-
Branch naming:
IssueNumber-short-title, e.g.99-bootloader-implementation, so work stays traceable to an issue. -
Signed & signed-off commits are required. Configure a GPG signing key and enable
git config commit.gpgsign true. Youruser.name(full name) and verifieduser.emailmust match your GitHub profile and the email used to sign commits. -
Commit messages start with
IssueNumber-summary-of-changesfollowed by a detailed description of what changed and why. -
Sign the CLA. Every new contributor must sign the Silicon Labs Contributor License Agreement during PR review — the
01-CLA-Assistantworkflow prompts you to comment your agreement on the PR. Signatures expire after 6 months. - Follow the coding standard. Adhere to the Silicon Labs coding guidelines and the conventions below.
- Fill out the pull request template.
- Reviewers are assigned automatically from
.github/CODEOWNERS. Add more if needed, but don't remove the code owners. - All CI workflows must pass and total test coverage should remain in the high 90s.
- Address review comments; if any are blocking, keep the PR in Draft until they're resolved.
The key directories of the monorepo are:
packages/
├── pycommander/ # meta-package (the `pycommander` command)
├── pycommander-cli/ # CLI flavor (bundles commander-cli, `pycommander-cli`)
│ └── src/pycommander_cli/_archive/ # bundled Commander CLI archive (fetched, not committed)
├── pycommander-gui/ # GUI flavor (bundles commander, `pycommander-gui`)
│ └── src/pycommander_gui/_archive/ # bundled Commander GUI archive (fetched, not committed)
└── pycommander-core/ # the framework (all real logic; no executable)
scripts/
├── download_commander_archives.py # fetch the Commander archives into the _archive/ dirs
└── run_tests.py # aggregate test runner
.github/
└── commander-version # pinned Commander release tag used by CI and the scriptSee Architecture-and-Packages for how the packages relate and how the bundled executable is located and extracted at runtime.
PyCommander targets Python 3.10+. Install all four packages in editable mode so changes are picked up immediately:
python -m pip install --upgrade pip
python -m pip install -e packages/pycommander-core \
-e packages/pycommander-cli \
-e packages/pycommander-gui \
-e packages/pycommander \
--force-reinstallThe core package depends on pyyaml and platformdirs.
The flavor packages need a Simplicity Commander archive under their _archive/ directory to actually run hardware commands. Place the platform-appropriate CLI and GUI archives into:
packages/pycommander-cli/src/pycommander_cli/_archive/packages/pycommander-gui/src/pycommander_gui/_archive/
The easiest way to populate both directories is the helper script:
python scripts/download_commander_archives.pyWith no arguments it reads the Commander release tag pinned in .github/commander-version, auto-detects the host platform, downloads the matching CLI and GUI archives from the GitHub release, and drops them into the two _archive/ directories (clearing out any existing Commander* archives first). This mirrors what the CI workflows do, so a local checkout ends up with the same executables that a released wheel would ship.
The script fails early if either the CLI or GUI archive is missing for the requested tag/platform, so you never end up with a half-populated checkout.
Options:
| Flag | Default | Description |
|---|---|---|
-t, --tag
|
value in .github/commander-version
|
Release tag to download, e.g. commander-1v24p3. |
-p, --platform
|
auto |
Which platform's archives to fetch. auto detects the host; explicit choices are linux-x86_64, linux-aarch64, linux-aarch32, macos, windows. |
--repo |
SiliconLabsSoftware/pycommander |
GitHub repository (owner/name) to pull the release from. |
--token |
GITHUB_TOKEN / GH_TOKEN env var |
GitHub token used for private forks. Not needed for the public repo. |
Examples:
# Pin a specific Commander release instead of the default:
python scripts/download_commander_archives.py --tag commander-1v24p3
# Fetch a platform other than the host (e.g. grab the Linux build from a Mac):
python scripts/download_commander_archives.py --platform linux-x86_64
# Pull from a private fork (needs a token with access to the release assets):
GITHUB_TOKEN=ghp_xxx python scripts/download_commander_archives.py --repo my-org/pycommander-forkNote: the archives live as GitHub release assets, not in the git tree, so you need network access (and, for private forks, a token) the first time you set up a checkout. The raw archives are placed as-is; runtime extraction is handled by
pycommander_core._ensure_commander.
You can also point the API at a specific executable at runtime via Commander(executable_path=...), which is handy for testing against a particular build without touching _archive/.
Each package has a tests/ suite. The aggregate runner discovers and runs all of them:
python scripts/run_tests.pyTo produce coverage like CI does:
python -m pip install coverage
python -m pip install -r packages/*/tests/requirements.txt
coverage run scripts/run_tests.py
coverage report
coverage html # writes htmlcov/The test suites use mock runners/adapters/commanders (see packages/pycommander-core/tests/), so most tests do not require real hardware.
Three GitHub Actions workflows live in .github/workflows/:
-
unittest-and-coverage.yml— runs the test suites and produces a combined coverage report across Linux (x86_64 / aarch64), macOS (arm64) and Windows. Runs on pushes and pull requests targetingmainordevelop/**, and can also be triggered manually (workflow_dispatch). It downloads the correct Commander archives into the flavor packages before installing and testing. Total coverage is expected to stay in the high 90s. -
build-wheels-and-publish.yml— builds platform-specific wheels (Linux x86_64/aarch64/aarch32, macOS arm64, Windows) and publishes to PyPI on av*.*.*tag. -
01-CLA-Assistant.yml— enforces the Contributor License Agreement on pull requests (see Contribution workflow below).
A few patterns to keep in mind when extending the code:
-
One module per CLI suite under
pycommander_core/commands/. Each command class subclassesBaseCommand, builds an argument list with the provided helpers (_get_ranges,_get_patches,_get_regions,_get_tokens,_get_include_sections, …), and returnsself._run(...).output. -
CommanderBaseauto-registers every command class fromcommands.__all__, deriving the attribute name from the class name (FlashCommand→commander.flash). When you add a suite, export it fromcommands/__init__.pyand add a type-hint attribute onCommanderBase. -
High-level helpers (Adapter-Class, Target-Class,
AemStreamBase) parse Commander's JSON into the dataclasses intypes.py. Validate inputs and raiseValueError/FileNotFoundErrorearly; returnNonefor failed look-ups andboolfor actions. -
All subprocess work goes through
runner.Runner, which centralizes timeouts, logging, JSON handling, and the mapping of return codes to typed exceptions.
- Create
pycommander_core/commands/<suite>.pywith aclass <Suite>Command(BaseCommand). - Add public methods that assemble args and call
self._run("<suite>", "<subcommand>", *args).output. Document each with a docstring (Args/Returns) — this wiki is generated from those. - Export the class in
commands/__init__.py(from .<suite> import <Suite>Commandand add to__all__). - Add a type-hint attribute on
CommanderBase(<suite> : "<Suite>Command"). - (Optional) Add a typed wrapper on
Adapter/Targetif the command maps to a common task. - Add tests under the relevant package's
tests/.
PyCommander · GitHub · Simplicity Commander docs · Licensed under the Silicon Labs MSLA
Getting started
Using PyCommander
Topics
Command reference
- Overview
- adapter · aem · vcom · ctune
- device · flash · verify · readmem · extflash
- security
- tokens · nvm3 · littlefs
- convert · ebl · gbl3 · gbl4 · ota · rps · postbuild
- util · serial · mfg917
Contributing