#!/usr/bin/env python # coding: utf-8 # ## What is a software package? # ## What is a software package? # # * A fixed, identifiable state of software # ## What defines/goes into a software package? # ## What defines/goes into a software package? # # * Name # * Version # * License # * Description # * Requirements # * Snapshot of software # * Compiled binaries # ## How do we capture this in Python? # ## How do we capture this in Python? # # By writing this metadata out in `pyproject.toml` # ## How do we capture this in Python? # # ### Naming # # ```toml # # Add metadata about project here # [project] # # Pick a descriptive name for the project (use `-` not `_`) # name = "example-pyproject" # ``` # ### How do we capture this in Python? # # #### Version # # ```toml # [project] # name = "example-pyproject" # # Pick a version (SemVer, EffVer, CalVer, etc.) # version = "0.1.0" # ``` # ## How do we capture this in Python? # # ### Description # # ```toml # [project] # name = "example-pyproject" # version = "0.1.0" # # Explain the focus and goal of this project succinctly # description = "Example packaging project" # # Readme file from the project shipped in the package # readme = "README.md" # ``` # ## How do we capture this in Python? # # ### License # # ```toml # [project] # name = "example-pyproject" # version = "0.1.0" # description = "Example packaging project" # readme = "README.md" # # How can this project be used? # license = "BSD-3-Clause" # # Create and ship the license file # license-files = ["LICENSE.txt"] # ``` # ## How do we capture this in Python? # # ### Project Developers # # ```toml # [project] # name = "example-pyproject" # version = "0.1.0" # description = "Example packaging project" # readme = "README.md" # license = "BSD-3-Clause" # license-files = ["LICENSE.txt"] # # Who built this project? How can they be contacted? # authors = [ # {name = "Megan Scott", email = "megan.scott@alaska.edu"}, # ] # # Who is maintaining it now? And how do we contact them? # maintainers = [ # {name = "Jim Ross", email = "jim.ross@alaska.edu"}, # ] # ``` # ## How do we capture this in Python? # # ### Requirements # # ```toml # [project] # name = "example-pyproject" # version = "0.1.0" # description = "Example packaging project" # readme = "README.md" # license = "BSD-3-Clause" # license-files = ["LICENSE.txt"] # authors = [ # {name = "Megan Scott", email = "megan.scott@alaska.edu"}, # ] # maintainers = [ # {name = "Jim Ross", email = "jim.ross@alaska.edu"}, # ] # # What Python versions are supported # requires-python = ">=3.10" # # What is needed for the project to run # dependencies = [ # "numpy >= 1.25", # ] # ``` # ## How do we capture this in Python? # # ### Keywords & classifiers # # ```toml # [project] # name = "example-pyproject" # version = "0.1.0" # description = "Example packaging project" # readme = "README.md" # license = "..." # authors = [ # {name = "Megan Scott", email = "megan.scott@alaska.edu"}, # ] # maintainers = [ # {name = "Jim Ross", email = "jim.ross@alaska.edu"}, # ] # requires-python = ">=3.10" # dependencies = [ # "numpy >= 1.25", # ] # keywords = ["packaging"] # classifiers = [ # "Development Status :: 3 - Alpha", # ] # ``` # ## How do we capture this in Python? # # ### URLs - How to find out more info # # ```toml # [project] # name = "example-pyproject" # version = "0.1.0" # # ... # urls = { # # What is the landing page # Homepage = "https://example-pyproject.acme.com", # # Where is the source # Source = "https://github.com/acme/example-pyproject", # # Where to report bugs or request features # Issues = "https://github.com/acme/example-pyproject/issues/new" # } # ``` # # Alternatively # # ```toml # [project.urls] # Homepage = "https://example-pyproject.acme.com" # Source = "https://github.com/acme/example-pyproject" # Issues = "https://github.com/acme/example-pyproject/issues/new" # ``` # ## What does the code look like? # # * So far this has been metadata (mostly) # ## Project structure # # ``` # example-pyproject/ # <--- Git repo directory # ``` # ## Project structure # # ``` # example-pyproject/ # ├── LICENSE.txt # <--- License file we picked # └── README.md # <--- Initial docs new people see # ``` # ## Project structure # # ``` # example-pyproject/ # ├── LICENSE.txt # ├── README.md # └── example_pyproject # <--- Place source code here # ``` # ## Project structure # # ``` # example-pyproject/ # ├── LICENSE.txt # ├── README.md # └── example_pyproject # └── __init__.py # <--- Make this a Python package # ``` # ## Project structure # # ``` # example-pyproject/ # ├── LICENSE.txt # ├── README.md # └── example_pyproject # ``` # ## Project structure # # ``` # example-pyproject/ # ├── LICENSE.txt # ├── README.md # ├── example_pyproject # └── pyproject.toml # <--- Include our package metadata # ``` # ## Project structure # # ``` # example-pyproject/ # ├── CONTRIBUTING.md # <--- Add maintainer docs # ├── LICENSE.txt # ├── README.md # ├── docs # <--- Add user docs # ├── example_pyproject # └── pyproject.toml # ``` # ## Project structure # # ``` # example-pyproject/ # ├── CONTRIBUTING.md # ├── LICENSE.txt # ├── README.md # ├── docs # ├── example_pyproject # ├── pyproject.toml # └── tests/ # <--- Include unit tests # ``` # ## Project structure # # ``` # example-pyproject/ # ├── .github/workflows # <--- GitHub CI # ├── CONTRIBUTING.md # ├── LICENSE.txt # ├── README.md # ├── docs # ├── example_pyproject # ├── pyproject.toml # ├── readthedocs.yml # <--- ReadTheDocs build # └── tests/ # ``` # ## Project structure # # ``` # example-pyproject/ # ├── .github/pull_request_template.md # <--- Checklist for PRs # ├── .github/issue_template.md # <--- Checklist for issues # ├── .github/workflows # ├── CONTRIBUTING.md # ├── LICENSE.txt # ├── README.md # ├── docs/ # ├── example_pyproject # ├── pyproject.toml # ├── readthedocs.yml # └── tests/ # ``` # ## How do we tie this to the code? # # * We now have the metadata # * Also we have structured the source # * How do we build this in a package? # ## Pick a build system # # ### What kind of code are we packaging? # # * Pure Python # * Python & Cython # * Python & C/C++ # * ... # ## Pick a build system - Pure Python # # ### Setuptools # # ```toml # [build-system] # build-backend = "setuptools.build_meta" # requires = [ # "setuptools", # ] # ``` # # ### Hatchling # # ```toml # [build-system] # build-backend = "hatchling.build" # requires = [ # "hatchling", # ] # ``` # # ### More options # # https://packaging.python.org/en/latest/glossary/#term-Build-Backend # ## Pick a build system - Cython # # ### Setuptools # # #### `pyproject.toml` # # ```toml # [build-system] # build-backend = "setuptools.build_meta" # requires = [ # "setuptools>=74.1.0", # "cython>=3", # ] # # ... # # [tool.setuptools] # ext-modules = [ # {name = "example-pyproject.mylib", sources = ["example_pyproject/mylib.pyx"]}, # ] # ``` # # #### Structure # # ``` # example-pyproject/ # ├── LICENSE.txt # ├── README.md # └── example_pyproject # ├── __init__.py # └── mylib.pyx # <--- Cython module # ``` # ## Pick a build system - C/C++ # # ### Setuptools # # ```toml # [build-system] # build-backend = "setuptools.build_meta" # requires = [ # "setuptools>=74.1.0", # "cython>=3", # ] # # ... # # [tool.setuptools] # ext-modules = [ # {name = "example-pyproject.mylib", sources = ["example_pyproject/mylib.c"]}, # ] # ``` # ### Pick a build system - Other features # # #### Dynamically configure version # # ```toml # [build-system] # build-backend = "setuptools.build_meta" # requires = [ # "setuptools", # "setuptools-scm>=8.1", # ] # # [project] # ... # dynamic = ["version"] # # [tool.setuptools_scm] # version_scheme = "guess-next-dev" # local_scheme = "dirty-tag" # write_to = "example_pyproject/_version.py" # ```