This repository serves as a template for creating a Python project, complete with fundamental tooling and configuration. It is meant to help new python projects get started quickly, letting the user focus on writing code. The template takes care of the minutia of directory structures, tool configurations, and automated testing until the user is ready to take over.
This template is generated using Copier, an open source tool for rendering project from templates and natively supports updating projects as the original template matures.
See this demo repository for an example created from this template.
This template includes a number of features to help you get started developing your Python project quickly:
You have two options for project generation from this template:
[!NOTE] DO NOT FORK this repository. Instead, use the Use this template feature.
To get started:
-
) instead of underscores.Python 3.10+: We recommend using pyenv for managing Python versions.
Copier: Install Copier using pip or pipx.
pip install --user copier
# OR
# Install pipx and add it to your PATH and then install Copier
pip install --user pipx && pipx ensurepath
pipx install copier
Operation System: Ubuntu/MacOS
Git: Ensure Git is installed and configured.
GitHub CLI: [OPTIONAL] Ensure GitHub CLI is installed and you are
authenticated (gh auth login
) if you would like to automate the repository creation and configuration like branch
protection.
Copier will ask you a series of questions to customise the project to your needs. Once you have answered all the questions, Copier will generate the project for you.
To generate the project run:
copier copy --trust gh:ONSdigital/ons-python-template /path/to/your/new/project
Replace /path/to/your/new/project
with the path to the directory where you want to create your new project. This
directory should match the name of the repository you want to create.
This step is only required if you answered No
to the Do you want to set up the git repository?
question.
Otherwise, this would
have been automatically done for you.
Go to your project directory, and initialise a git repository and make the initial commit
cd /path/to/your/new/project
git init -b main
git add .
git commit -m "Initial commit"
Create a new repo in GitHub. See [GitHub How-to](https://docs.github.com/en/repositories/creating-and-managing-repositories/quickstart-for-repositories]
Push your project to the repository on GitHub:
git remote add origin https://github.com/<repository_owner>/<repository_name>.git
git push -u origin main
Now you can start working on your project. :rocket:
To update your project when the template changes, see Updating Project with Template Changes
There are a few steps you should take after cloning your new repository to ensure it is fully configured and ready for use.
If your repository is private/internal, you should update the PIRR.md
file in the root of your repository with the
reasoning for the private/internal status of the repository.
Familiarise yourself with the ONS GitHub Policy and ensure your repository is compliant with the policy. Few key points to note are:
main
or any other primary branch is protected.If you answered Yes
to the Do you want to set up the git repository?
question, then these settings would have been
automatically configured for you. However, it is recommended to review these settings to ensure they meet your
requirements.
MegaLinter is set up to use the largest Docker image by default, containing all available linters and code analysis tools. This setup is designed for comprehensive coverage and serves as a solid starting point for new projects. However, you might not need every tool included in this image, as it can be quite large.
To save space and optimise your setup, you can choose a more specific MegaLinter Docker image, called a flavor. Each flavor includes a subset of linters and tools suited for particular languages or frameworks.
If you're unsure which flavor is best for you, try running MegaLinter with the default set up after your project has matured. After the run, MegaLinter will analyse the output and suggest a more suitable flavor if necessary. This helps you customise your setup to include only the tools you need, reducing the Docker image size and improving efficiency.
If you would like to auto-fix issues using MegaLinter and commit the changes back to the PR, you can will need to create a Personal Access Token and add it as a secret to your repository. Without a PAT token, commits/PRs made by workflows do not trigger other workflows, including the MegaLinter workflow. This is a security feature of GitHub Actions to prevent infinite loops. For more info, see MegaLinter: Auto-fixing issues.
[!CAUTION] CURRENTLY UNSUPPORTED: This is currently unsupported due to an upstream issue with Copier. Once the issue is resolved, this section will be updated with instructions on how to update your project with changes.
The structure of the templated repo is as follows:
├── .github # Contains GitHub-specific configurations, including Actions workflows for CI/CD processes.
│ ├── linters # Directory for config files used by linter run via MegaLinter, e.g. .markdown-lint.json, .yaml-lint.yml etc.
│ ├── workflows # Directory for GitHub Actions workflows.
│ │ ├── ci.yml # Workflow for Continuous Integration, running tests and other checks on commits to `main` and on pull requests.
│ │ ├── codeql.yml # CodeQL workflow for automated identification of security vulnerabilities in the codebase. (Public Repos Only)
│ │ └── mega-linter.yml # MegaLinter workflow for linting the project.
│ ├── dependabot.yml # Configuration for Dependabot, which automatically checks for outdated dependencies and creates pull requests to update them.
│ ├── ISSUE_TEMPLATE.md # Template for issues raised in the repository.
│ ├── PULL_REQUEST_TEMPLATE.md # Template for pull requests raised in the repository.
│ └── release.yml # Configuration on how to categorise changes into a structured changelog when using 'Generate release notes' feature.
├── app # Main Python package directory for the project, containing source code.
│ ├── __init__.py # Initialises the directory as a Python package, allowing its modules to be imported.
│ └── calculator.py # A simple Python class for demonstration purposes.
└── tests # Contains all test files.
│ ├── __init__.py # Marks the directory as a Python package, enabling the discovery of test modules by testing frameworks.
│ └── unit # Directory for unit tests, containing tests for individual components of the project.
│ ├── __init__.py # Further organises tests into a Python package structure.
│ ├── conftest.py # Contains pytest fixtures and configurations, applicable to all tests in the directory.
│ └── test_calculator.py # Unit tests for the functionality provided by sample python code for demonstration purposes.
├── .copier-answers.yml # Configuration file for Copier, specifying the answers to prompts when generating the project. Required for project updates.
├── .editorconfig # Configuration file for maintaining consistent coding styles for multiple developers working on the same project across various editors and IDEs.
├── .gitattributes # Git attributes file for defining attributes per path, such as line endings and merge strategies.
├── .gitignore # Specifies intentionally untracked files to ignore when using Git, like build outputs and temporary files.
├── .mega-linter.yml # Configuration file for MegaLinter, specifying the linters and code analysers to be used.
├── .pylintrc # Configuration file for Pylint.
├── .python-version # Specifies the Python version to be used with pyenv.
├── CODE_OF_CONDUCT.md # A code of conduct for the project, outlining the standards of behaviour for contributors.
├── CONTRIBUTING.md # Guidelines for contributing to the project, including information on how to raise issues and submit pull requests.
├── LICENSE # The license under which the project is made available.
├── Makefile # A script used with the make build automation tool, containing commands to automate common tasks.
├── PIRR.md # Private Internal Reasoning Record (PIRR) for the repository, documenting the reasoning for the private/internal status of the repository. (Private/Internal Repos Only)
├── poetry.lock # Lock file for Poetry, pinning exact versions of dependencies to ensure consistent builds. (Exists if poetry is selected as the package manager)
├── pyproject.toml # Central project configuration file for Python, used by Poetry package manager and tools like Ruff, black etc.
├── Pipfile # Used by pipenv package manager to specify dependencies and their versions. (Exists if pipenv is selected as the package manager)
├── Pipfile.lock # Lock file for Poetry, pinning exact versions of dependencies to ensure consistent builds. (Exists if pipenv is selected as the package manager)
├── README.md # The main README file providing an overview of the project, setup instructions, and other essential information.
└── SECURITY.md # A security policy for the project, providing information on how to report security vulnerabilities.
Although this template is opinionated, there are many alternatives to the tools used in this template which you may prefer. See the Alternatives Software/Tools section for more information.
1. Why use Poetry?
pipenv
instead of poetry
via the package_manager
selection
question.2. What is Ruff and why use Ruff?
3. Why use pylint and black when Ruff offers similar functionality?
4. Why use mypy for type checking instead of pytype, pyright, or pyre?
5. Why use pytest for testing instead of unittest?
6. What is MegaLinter?
7. Why is MegaLinter not used for Python?
8. Why not use SuperLinter?
9. Why does this not provide a full example of a Python project, i.e a Flask app, FastAPI app, Python package etc.?
10. My projects do not have a CodeQL workflow. Why?
11. Why is Secret Scanning and Push Protection not enabled?
There are many alternatives to the tools used in this template, and you may prefer to use some of these alternatives.
Python package management with:
Linting/Formatting with:
Type checking with:
Security with:
:TODO: Add instructions for development
See CONTRIBUTING.md for details.
See LICENSE for details.