Structuring Your Python Project
2023-04-04By “structure” we mean the decisions you make concerning how your project best meets its objective. We need to consider how to best leverage Python’s features to create clean, effective code. In practical terms, “structure” means making clean code whose logic and dependencies are clear as well as how the files and folders are organized in the filesystem.
Structure of the Repository
First Look
├──CHANGELOG.md
├──docs
├──LICENSE
├──Makefile
├──README.md
├──requirements.txt
├──setup.py
├──tests
│ ├──__init__.py
│ └──test_xhs.py
└──sample
├──__init__.py
├──core.py
└──help.py
My first practice project, xhs, is available on GitHub.
CHANGELOG.md
To keep track of changes made to software over time, a changelog is a file that contains a chronologically ordered list of significant updates for each version. For guidance on how to maintain a changelog within your repository, refer to this guide
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.1.1] - 2023-03-05
### Added
- Arabic translation (#444).
### Fixed
- Improve French translation (#377).
### Changed
- Upgrade dependencies: Ruby 3.2.1, Middleman, etc.
### Removed
- Unused normalize.css file
docs
The package reference documentation is located here. To generate and maintain the documentation, you can use the Sphinx documentation tool.
To use Sphinx to generate and maintain documentation, start by installing it from PyPI using the following command: pip install -U sphinx
. Then, navigate to the docs
directory and run sphinx-quickstart
to set up the project.
pip install -U sphinx
cd docs
sphinx-quickstart
Once you have set up the Sphinx project, you can generate the documentation by running the make html
command. This will create an HTML version of the documentation that you can then distribute to your users.
make html
LICENSE
This is arguably the most important part of your repository, aside from the source code itself. The full license text and copyright claims should exist in this file. If you aren’t sure which license you should use for your project, check out choosealicense.com.
Makefile
make is an incredibly useful tool for defining generic tasks for your project. You deserve it.
.PHONY: docs
init:
pip install -r requirements.txt
ci:
pytest tests --junitxml=report.xml
test:
tox -p
upload:
python setup.py sdist bdist_wheel
twine upload dist/*
rm -fr build dist .egg xhs.egg-info
docs:
cd docs && make html
As an example, if you were to run the command make init
, it would effectively run the command pip install -r requirements.txt
.
README.md
Your project’s README.md file serves as an introduction to your work and should include essential information such as the title, description, usage instructions, and licensing information.
requirements.txt
It should specify the dependencies required to contribute to the project: testing, building, and generating documentation.
setup.py
the package and distribution management. to build your project run command python setup.py sdist bdist_wheel
, then it will build wheel file and source file in ./dist
directory. there is a setup.py
example
from setuptools import setup
with open("README.md", "r", encoding="utf-8") as f:
readme = f.read()
setup(
name="your_package_name",
version="version",
description="description",
long_description=readme,
long_description_content_type="text/markdown",
author="author",
author_email="author_email"],
url=about"url",
license=about"license",
packages=["your_package_name"],
install_requires=["require1", "require2"],
keywords="keyword1 keyword2",
include_package_data=True,
zip_safe=False,
python_requires=">=3.7",
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development :: Libraries :: Python Modules",
],
)
tests
To use pytest
to run all of your test files, you can simply execute the command pytest tests
.
sample
Depending on the size of your project, your application package may be as simple as a single file, such as sample.py
.
reference project
Automate projects with GitHub actions
auto test:
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
os: [ubuntu-20.04, macOS-latest, windows-latest]
include:
- python-version: pypy-3.7
os: ubuntu-latest
experimental: false
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
make init
- name: Run tests
run: |
make ci
auto build doc
# .github/workflows/doc.yml
name: Sphinx Doc
on:
push:
branches: [master, docs]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build HTML
uses: ammaraskar/sphinx-action@master
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: html-docs
path: docs/_build/html/
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
personal_token: ${{ secrets.PERSONAL_TOKEN }}
publish_dir: docs/_build/html
auto upload PyPI
# .github/workflows/pypi.yml
name: PyPI
on:
push:
branches:
- master
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: "3.x"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
make
pip install build
- name: Build package
run: python -m build
- name: pypi-publish
uses: pypa/[email protected]
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}