{"id":16235996,"url":"https://github.com/browniebroke/pypackage-template","last_synced_at":"2025-05-07T11:47:35.488Z","repository":{"id":37019148,"uuid":"272191674","full_name":"browniebroke/pypackage-template","owner":"browniebroke","description":"A project template for Python package with heavy use of Github actions","archived":false,"fork":false,"pushed_at":"2025-05-03T21:45:50.000Z","size":1128,"stargazers_count":76,"open_issues_count":13,"forks_count":20,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-05-03T22:25:58.298Z","etag":null,"topics":["copier-template","django-package","package","pypi","python","uv"],"latest_commit_sha":null,"homepage":"","language":"Jinja","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/browniebroke.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["browniebroke"],"patreon":"browniebroke","polar":"browniebroke","ko_fi":"browniebroke","buy_me_a_coffee":"browniebroke","custom":["https://paypal.me/browneibroke"]}},"created_at":"2020-06-14T11:50:11.000Z","updated_at":"2025-05-03T21:45:54.000Z","dependencies_parsed_at":"2023-02-17T06:05:18.723Z","dependency_job_id":"465f6458-6a61-4531-8386-dbd896c69164","html_url":"https://github.com/browniebroke/pypackage-template","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/browniebroke%2Fpypackage-template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/browniebroke%2Fpypackage-template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/browniebroke%2Fpypackage-template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/browniebroke%2Fpypackage-template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/browniebroke","download_url":"https://codeload.github.com/browniebroke/pypackage-template/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252873938,"owners_count":21817708,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["copier-template","django-package","package","pypi","python","uv"],"created_at":"2024-10-10T13:28:39.033Z","updated_at":"2025-05-07T11:47:35.474Z","avatar_url":"https://github.com/browniebroke.png","language":"Jinja","funding_links":["https://github.com/sponsors/browniebroke","https://patreon.com/browniebroke","https://polar.sh/browniebroke","https://ko-fi.com/browniebroke","https://buymeacoffee.com/browniebroke","https://paypal.me/browneibroke"],"categories":[],"sub_categories":[],"readme":"# Python Package Template\n\n[![CI Status](https://img.shields.io/github/actions/workflow/status/browniebroke/pypackage-template/ci.yml?branch=main\u0026label=Test\u0026logo=github\u0026style=flat-square)](https://github.com/browniebroke/pypackage-template/actions/workflows/ci.yml?query=branch%3Amain)\n[![Copier](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/copier-org/copier/master/img/badge/badge-grayscale-inverted-border-orange.json)](https://github.com/copier-org/copier)\n\nProject template for a Python Package using Copier.\n\n## Features\n\n- Project for Python 3.9+.\n- Testing with Pytest using GitHub actions.\n- Packaging powered by [uv].\n- Optionally generates a CLI entry point powered by [Typer] and [Rich].\n- Optionally makes it a Django package.\n- Uses [Ruff] for formatting and linting.\n- Comes with [pre-commit] hook config for [Ruff].\n- Style guide enforced on CI.\n- Dependencies kept up to date by [Renovate].\n- Follow the [all-contributors] specification.\n- Follow to [the conventional commits][conventional-commits] specification.\n- Automated releasing using [python-semantic-release][python-semantic-release].\n- Documentation configured with Sphinx and [MyST Parser][myst].\n- Follows the contributor covenant code of conduct.\n- Standardised list of GitHub labels synchronised on push to master using [the labels CLI][pylabels].\n\n## Usage\n\nGenerate a new project with:\n\n```shell\ncopier copy --trust \"gh:browniebroke/pypackage-template\" path-to-project\n```\n\nThis will prompt you for a few questions and create new directory with the name you used as project slug.\n\n\u003e _Note:_\n\u003e the `--trust` option is required because this template may execute some tasks after generating the project, like initialising the git repo, installing dependencies and so forth. These are all listed in the `copier.yml` of this repo, under the `_tasks` key. They are all optional and safe to run. You can take my word for it, or better, check the code yourself!\n\n### Start developing\n\nThe project uses [uv] for dependencies management and packaging. Make sure you have it installed in your development machine. To install the development dependencies in a virtual environment, type:\n\n```shell\nuv sync\n```\n\nThis will also generate a `uv.lock` file, you should track this file in version control. To execute the test suite, call pytest inside uv's virtual environment via `uv run`:\n\n```shell\nuv run pytest\n```\n\nCheck out the [uv] documentation for more information on the available commands.\n\n### GitHub Actions\n\nWhen you first push to GitHub, it'll start a `ci` GitHub workflow that you can see in the \"Actions\" tab of your repository. This workflow runs a couple of jobs:\n\n- The `test` job will run your test suite with Pytest against all Python version from 3.8 to 3.11\n- A few things will run in the lint job:\n  - Ruff format\n  - Ruff lint with several flake8, isort and pyupgrade plugins.\n\nA `labels` workflow will also run and synchronise the GitHub labels based on the `.github/labels.toml` file.\n\n### Secrets\n\nThe workflows need [a few secrets][gh-secrets] to be setup in your GitHub repository:\n\n- `GH_PAT` a [personal access token (PAT) with the `repo` scope][create-pat] for opening pull requests and updating the repository topics. This is used by the `upgrader` and `labels` workflows.\n- `CODECOV_TOKEN` to upload coverage data to [codecov.io][codecov] in the Test workflow.\n\nIf you have the GitHub CLI installed and chose to set up GitHub, they will be created with a dummy value (`changeme`).\n\n### Automated release\n\nBy following the conventional commits specification, we're able to completely automate versioning and releasing to PyPI. It runs on every push to your main branch, as part of the `release` job of the `ci.yml` workflow. You shouldn't need to create a token, but you'll need to setup [trusted publisher](https://docs.pypi.org/trusted-publishers/using-a-publisher/) for the project.\n\n#### Trusted publisher setup\n\nThe first time you push, the workflow will try to create a release in PyPI, however the project doesn't exist there yet, which seems like a chicken and egg situation. Luckily, you can add a trusted publisher before creating the PyPI project here: https://pypi.org/manage/account/publishing/. Here are the infos that you should use:\n\n- PyPI project name: what you've entered as \"project slug\"\n- Owner: your GitHub username\n- Repository name: what you've entered as \"project slug\"\n- Workflow name: `ci.yml`\n- Environment name: `release`\n\nIf the release phase failed the first time, you might have to remove the release and tag from GitHub, and perhaps tidy up the changelog.\n\n#### How it works\n\nHere is an overview of what it's doing:\n\n- Check the commit log since the last release, and determine the next version to be released.\n- If no significant change detected, stop here (e.g. just dependencies update).\n- Otherwise, bump the version in code locations specified in `setup.cfg`.\n- Update the `CHANGELOG.md` file.\n- Commit changes.\n- Create a git tag.\n- Push to GitHub.\n- Create a release in GitHub with the changes as release notes.\n- Build the source and binary distribution (wheel).\n- Upload the sources to PyPI and attach them to the Github release, using trusted publisher.\n\nFor more details, check out the [conventional commits website][conventional-commits] and [Python semantic release][python-semantic-release] GitHub action.\n\n### Optional: Django package\n\nIf your package is a reusable Django app, you should answer \"yes\" to the question \"Is the project a Django package?\". This will generate a bit more boilerplate for you to make it easier to develop and test:\n\n- At the root, you'll get a `manage.py` which is going to come handy if your package contain any models and you need to run migrations for it.\n- Testing will use tox as the Django-Python support matrix can be complicated.\n- Inside your package source, you'll get a `conf.py` to include your reusable app settings, for the users of your app to configure your app. This is following the pattern explained in [this blog post](https://overtag.dk/v2/blog/a-settings-pattern-for-reusable-django-apps/).\n- The tests will come in with settings and URLs files, along with an test app with basic models.\n\n#### Migrations\n\nYou should be able to use the provided `manage.py` to create migrations for your reusable app. Create or change your models and run `uv run python manage.py makemigrations`.\n\n### Pre-commit\n\nThe project comes with the config for [pre-commit]. If you're not familiar with it, follow their documentation on how to install it and set it up.\n\n### Documentation\n\nThe project assumes that the documentation will be hosted on Read the Docs and written in Markdown with the [MyST parser for Sphinx][myst].\n\nTo enable it, you might need to go [into your dashboard][rtd-dashboard] and import the project from Github. Everything else should work out of the box.\n\n### Dependencies update\n\nThe project dependencies are kept up to date with [Renovate] which requires [the Github app][renovate-gh-app] to be installed.\n\nThe main advantage of Renovate over Dependabot is the auto-merge option, which is configured to automatically merge minor/patch updates with all the CI checks passing. It supports a variety of package managers, including uv, GitHub actions and pre-commit hooks which are used by default.\n\n### All contributors\n\nThis is a specification that help you highlight every open source contribution in your README. This is easy to maintain as it comes with a GitHub bot to do the updates for you, so more manual updates on the contributors file.\n\nIf you never used it before, you will have to [install the Github app][all-contribs-install] and give it access to your repo.\n\n## Contributors ✨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://browniebroke.com/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/861044?v=4?s=80\" width=\"80px;\" alt=\"Bruno Alla\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eBruno Alla\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/browniebroke/pypackage-template/commits?author=browniebroke\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#ideas-browniebroke\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"https://github.com/browniebroke/pypackage-template/commits?author=browniebroke\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://cloudreactor.io/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/1079646?v=4?s=80\" width=\"80px;\" alt=\"Jeff Tsay\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJeff Tsay\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/browniebroke/pypackage-template/commits?author=jtsay362\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/34j\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/55338215?v=4?s=80\" width=\"80px;\" alt=\"34j\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003e34j\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/browniebroke/pypackage-template/commits?author=34j\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/kroimon\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/628587?v=4?s=80\" width=\"80px;\" alt=\"Stefan Rado\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eStefan Rado\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/browniebroke/pypackage-template/commits?author=kroimon\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/codejedi365\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/17354856?v=4?s=80\" width=\"80px;\" alt=\"codejedi365\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ecodejedi365\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/browniebroke/pypackage-template/commits?author=codejedi365\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://www.habet.dev\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/82916197?v=4?s=80\" width=\"80px;\" alt=\"Abe Hanoka\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAbe Hanoka\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/browniebroke/pypackage-template/issues?q=author%3Aabe-101\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n\n[uv]: https://docs.astral.sh/uv/\n[Typer]: https://typer.tiangolo.com\n[Rich]: https://rich.readthedocs.io\n[Ruff]: https://pypi.org/project/ruff/\n[pre-commit]: https://pre-commit.com/\n[renovate]: https://docs.renovatebot.com/\n[renovate-gh-app]: https://github.com/apps/renovate\n[all-contributors]: https://github.com/all-contributors/all-contributors\n[conventional-commits]: https://www.conventionalcommits.org\n[python-semantic-release]: https://github.com/relekang/python-semantic-release\n[myst]: https://myst-parser.readthedocs.io\n[pylabels]: https://github.com/hackebrot/labels\n[gh-secrets]: https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets\n[codecov]: https://codecov.io/\n[pypi]: https://pypi.org/\n[create-pat]: https://github.com/settings/tokens/new?scopes=repo\n[rtd-dashboard]: https://readthedocs.org/dashboard/\n[all-contribs-install]: https://allcontributors.org/docs/en/bot/installation\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrowniebroke%2Fpypackage-template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrowniebroke%2Fpypackage-template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrowniebroke%2Fpypackage-template/lists"}