Thanks for your interest in contributing. This repository contains the PythonNative library, CLI, templates, a demo app, and a Django site used for docs/demo hosting and E2E. Contributions should keep the code reliable, cross‑platform, and easy to use.
Development uses Python ≥ 3.9.
# create and activate a venv (recommended)
python3 -m venv .venv && source .venv/bin/activate
# install dev tools (lint/format/test)
pip install -e ".[dev]"
# install library (editable) and CLI
pip install -e .
# run tests
pytest -q
# format and lint
black src examples tests || true
ruff check .Common library and CLI entry points:
# CLI help
pn --help
# create a new sample app (template fetch is remote)
pn init my_app
# run the Hello World example
cd examples/hello-world && pn run androidsrc/pythonnative/– installable library and CLIpythonnative/– core cross‑platform UI components and utilitiescli/–pncommand
tests/– unit tests for the librarytemplates/– Android/iOS project templates and zipsexamples/– runnable example appshello-world/– minimal demo app using the library
README.md,pyproject.toml– repo docs and packaging
- Style: Black; lint: Ruff; typing where useful. Keep APIs stable.
- Prefer explicit, descriptive names; keep platform abstractions clean.
- Add/extend tests under
tests/for new behavior. - Do not commit generated artifacts or large binaries; templates live under
templates/.
Common commands:
pytest -q # run tests
ruff check . # lint
black src examples tests # formatThis project uses Conventional Commits. Use the form:
<type>(<scope>): <subject>
[optional body]
[optional footer(s)]
- Encoding: UTF‑8 is allowed and preferred across subjects and bodies.
- Keep the subject ≤ 72 chars; avoid emoji.
Accepted types (standard):
build– build system or external dependencies (e.g., requirements, packaging)chore– maintenance (no library behavior change)ci– continuous integration configuration (workflows, pipelines)docs– documentation onlyfeat– user‑facing feature or capabilityfix– bug fixperf– performance improvementsrefactor– code change that neither fixes a bug nor adds a featurerevert– revert of a previous commitstyle– formatting/whitespace (no code behavior)test– add/adjust tests only
Recommended scopes (match the smallest accurate directory/module):
-
Library/CLI scopes:
cli–src/pythonnative/cli/(thepncommand)core–src/pythonnative/pythonnative/package internalscomponents– UI view modules undersrc/pythonnative/pythonnative/(e.g.,button.py,label.py)utils– utilities likeutils.pytests–tests/
-
Templates and examples:
templates–templates/(Android/iOS templates, zips)examples–examples/(e.g.,hello-world/)
- Repo‑level and ops:
deps– dependency updates and version pinsdocker– containerization files (e.g.,Dockerfile)repo– top‑level files (README.md,CONTRIBUTING.md,.gitignore, licenses)mkdocs– documentation site (MkDocs/Material) configuration and content underdocs/workflows– CI pipelines (e.g.,.github/workflows/)
Note: Avoid redundant type==scope pairs (e.g., docs(docs)). Prefer a module scope (e.g., docs(core)) or docs(repo) for top‑level updates.
Examples:
build(deps): refresh pinned versions
chore(repo): add contributing guidelines
ci(workflows): add publish job
docs(core): clarify ListView data contract
feat(components): add MaterialSearchBar
fix(cli): handle missing Android SDK gracefully
perf(core): reduce allocations in list diffing
refactor(utils): extract path helpers
test(tests): cover ios template copy flow
Examples (no scope):
build: update packaging metadata
chore: update .gitignore patterns
docs: add project overview
Breaking changes:
- Use
!after the type/scope or aBREAKING CHANGE:footer.
feat(core)!: rename Page.set_root_view to set_root
BREAKING CHANGE: API renamed; update app code and templates.
- Comma‑separate scopes without spaces:
type(scope1,scope2): ... - Prefer a single scope when possible; use multiple only when the change genuinely spans tightly related areas.
Scope ordering (house style):
- Put the most impacted scope first (e.g.,
repo), then any secondary scopes. - For extra consistency, alphabetize the remaining scopes after the primary.
- Keep it to 1–3 scopes max.
Example:
feat(templates,cli): add ios template and wire pn init
- PR title: use Conventional Commit format.
- Example:
feat(cli): add init subcommand - Imperative mood; no trailing period; ≤ 72 chars;
!for breaking changes.
- Example:
- PR description: include brief sections: What, Why, How (brief), Testing, Risks/Impact, Docs/Follow‑ups.
- Link issues with keywords (e.g.,
Closes #123).
- Link issues with keywords (e.g.,
- Merging: prefer “Squash and merge” with “Pull request title and description”.
- Keep PRs focused; avoid unrelated changes in the same PR.
Recommended PR template:
What
- Short summary of the change
Why
- Motivation/user value
How (brief)
- Key implementation notes or decisions
Testing
- Local/CI coverage; links to tests if relevant
Risks/Impact
- Compat, rollout, perf, security; mitigations
Docs/Follow-ups
- Docs updated or TODO next steps
Closes #123
BREAKING CHANGE: <details if any>
Co-authored-by: Name <email>
- PR title: Conventional Commits format (CI-enforced by
pr-lint.yml). - Tests: added/updated;
pytestpasses. - Lint/format:
ruff check .,blackpass. - Docs: update
README.mdif behavior changes. - Templates: update
templates/if generator output changes. - No generated artifacts committed.
- The version is tracked in
pyproject.toml(project.version) and mirrored insrc/pythonnative/__init__.pyas__version__. Both files are updated automatically by python-semantic-release. - Automated release pipeline (on every merge to
main):python-semantic-releasescans Conventional Commit messages since the last tag.- It determines the next SemVer bump:
feat→ minor,fix/perf→ patch,BREAKING CHANGE→ major (minor while version < 1.0). - Version files are updated,
CHANGELOG.mdis generated, and a tagged release commit (chore(release): vX.Y.Z) is pushed. - A GitHub Release is created with auto-generated release notes and the built sdist/wheel attached.
- When drafts are disabled, the package is also published to PyPI via Trusted Publishing.
- Draft / published toggle: the
DRAFT_RELEASEvariable at the top of.github/workflows/release.ymlcontrols release mode. Set to"true"(the default) for draft GitHub Releases with PyPI publishing skipped; flip to"false"to publish releases and upload to PyPI immediately. - Commit types that trigger a release:
feat(minor),fixandperf(patch),BREAKING CHANGE(major). All other types (build,chore,ci,docs,refactor,revert,style,test) are recorded in the changelog but do not trigger a release on their own. - Tag format:
v-prefixed (e.g.,v0.4.0). - Manual version bumps are no longer needed — just merge PRs with valid Conventional Commit titles. For ad-hoc runs, use the workflow's Run workflow button (
workflow_dispatch).
- Use lowercase kebab‑case; concise (≤ 40 chars).
- Prefix conventions:
feature/<scope>-<short-desc>fix/<issue-or-bug>-<short-desc>chore/<short-desc>docs/<short-desc>ci/<short-desc>refactor/<scope>-<short-desc>test/<short-desc>perf/<short-desc>build/<short-desc>release/vX.Y.Zhotfix/<short-desc>
Examples:
feature/cli-init
fix/core-threading-deadlock-123
docs/contributing
ci/publish-pypi
build/lock-versions
refactor/utils-paths
test/templates-android
release/v0.2.0
hotfix/cli-regression
- CI (
ci.yml): runs formatter, linter, type checker, and tests on every push and PR. - PR Lint (
pr-lint.yml): validates the PR title against Conventional Commits format (protects squash merges) and checks individual commit messages via commitlint (protects rebase merges). Recommended: add the PR title job as a required status check in branch-protection settings. - Release (
release.yml): runs on merge tomain; computes version, generates changelog, tags, creates GitHub Release, and (whenDRAFT_RELEASEis"false") publishes to PyPI. - Docs (
docs.yml): deploys documentation to GitHub Pages on push tomain.
- Avoid bundling secrets or credentials in templates or code.
- Prefer runtime configuration via environment variables for Django and CI.
By contributing, you agree that your contributions are licensed under the repository’s MIT License.