{ "cells": [ { "cell_type": "markdown", "id": "2da76876-a40c-43ec-a94d-e1bdb5b93a84", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## What is a software package?" ] }, { "cell_type": "markdown", "id": "daaca570-180d-461e-893e-67d92ab2de2e", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## What is a software package?\n", "\n", "* A fixed, identifiable state of software" ] }, { "cell_type": "markdown", "id": "63854f55-cf2e-4933-979b-cd2347691ae7", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## What defines/goes into a software package?" ] }, { "cell_type": "markdown", "id": "bd20f835-93d3-4d45-8957-b55e7d2d26ae", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## What defines/goes into a software package?\n", "\n", "* Name\n", "* Version\n", "* License\n", "* Description\n", "* Requirements\n", "* Snapshot of software\n", "* Compiled binaries" ] }, { "cell_type": "markdown", "id": "93b14944-8ec1-4223-95d2-af1f5ac30d2d", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## How do we capture this in Python?" ] }, { "cell_type": "markdown", "id": "c5007ffc-64db-46a2-804c-0ef6b30c73f0", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## How do we capture this in Python?\n", "\n", "By writing this metadata out in `pyproject.toml`" ] }, { "cell_type": "markdown", "id": "00eef31a-4c64-47ca-96f8-29b7b771f14c", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## How do we capture this in Python?\n", "\n", "### Naming\n", "\n", "```toml\n", "# Add metadata about project here\n", "[project]\n", "# Pick a descriptive name for the project (use `-` not `_`)\n", "name = \"example-pyproject\"\n", "```" ] }, { "cell_type": "markdown", "id": "a2c07259-cb67-4bfa-ac84-5c2492c2bbf7", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "### How do we capture this in Python?\n", "\n", "#### Version\n", "\n", "```toml\n", "[project]\n", "name = \"example-pyproject\"\n", "# Pick a version (SemVer, EffVer, CalVer, etc.)\n", "version = \"0.1.0\"\n", "```" ] }, { "cell_type": "markdown", "id": "1ed537e8-0264-4e60-90b7-71c7c676b9e5", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## How do we capture this in Python?\n", "\n", "### Description\n", "\n", "```toml\n", "[project]\n", "name = \"example-pyproject\"\n", "version = \"0.1.0\"\n", "# Explain the focus and goal of this project succinctly\n", "description = \"Example packaging project\"\n", "# Readme file from the project shipped in the package\n", "readme = \"README.md\"\n", "```" ] }, { "cell_type": "markdown", "id": "b8c1fc6f-dfff-4bbc-8ac5-2dc555eb4d10", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## How do we capture this in Python?\n", "\n", "### License\n", "\n", "```toml\n", "[project]\n", "name = \"example-pyproject\"\n", "version = \"0.1.0\"\n", "description = \"Example packaging project\"\n", "readme = \"README.md\"\n", "# How can this project be used?\n", "license = \"BSD-3-Clause\" \n", "# Create and ship the license file\n", "license-files = [\"LICENSE.txt\"] \n", "```" ] }, { "cell_type": "markdown", "id": "4db0d7ab-3c8e-4e08-a5a0-8e890f2c96eb", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## How do we capture this in Python?\n", "\n", "### Project Developers\n", "\n", "```toml\n", "[project]\n", "name = \"example-pyproject\"\n", "version = \"0.1.0\"\n", "description = \"Example packaging project\"\n", "readme = \"README.md\"\n", "license = \"BSD-3-Clause\"\n", "license-files = [\"LICENSE.txt\"]\n", "# Who built this project? How can they be contacted?\n", "authors = [\n", " {name = \"Megan Scott\", email = \"megan.scott@alaska.edu\"},\n", "]\n", "# Who is maintaining it now? And how do we contact them?\n", "maintainers = [\n", " {name = \"Jim Ross\", email = \"jim.ross@alaska.edu\"},\n", "]\n", "```" ] }, { "cell_type": "markdown", "id": "675a6013-c234-4f7f-9998-8363fd713e7a", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## How do we capture this in Python?\n", "\n", "### Requirements\n", "\n", "```toml\n", "[project]\n", "name = \"example-pyproject\"\n", "version = \"0.1.0\"\n", "description = \"Example packaging project\"\n", "readme = \"README.md\"\n", "license = \"BSD-3-Clause\"\n", "license-files = [\"LICENSE.txt\"]\n", "authors = [\n", " {name = \"Megan Scott\", email = \"megan.scott@alaska.edu\"},\n", "]\n", "maintainers = [\n", " {name = \"Jim Ross\", email = \"jim.ross@alaska.edu\"},\n", "]\n", "# What Python versions are supported\n", "requires-python = \">=3.10\"\n", "# What is needed for the project to run\n", "dependencies = [\n", " \"numpy >= 1.25\",\n", "]\n", "```" ] }, { "cell_type": "markdown", "id": "4547f4d3-1071-4ed8-9a54-72179cb72726", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## How do we capture this in Python?\n", "\n", "### Keywords & classifiers\n", "\n", "```toml\n", "[project]\n", "name = \"example-pyproject\"\n", "version = \"0.1.0\"\n", "description = \"Example packaging project\"\n", "readme = \"README.md\"\n", "license = \"...\"\n", "authors = [\n", " {name = \"Megan Scott\", email = \"megan.scott@alaska.edu\"},\n", "]\n", "maintainers = [\n", " {name = \"Jim Ross\", email = \"jim.ross@alaska.edu\"},\n", "]\n", "requires-python = \">=3.10\"\n", "dependencies = [\n", " \"numpy >= 1.25\",\n", "]\n", "keywords = [\"packaging\"]\n", "classifiers = [\n", " \"Development Status :: 3 - Alpha\",\n", "]\n", "```" ] }, { "cell_type": "markdown", "id": "e5b38f4d-033e-444a-b86a-844f481c0162", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## How do we capture this in Python?\n", "\n", "### URLs - How to find out more info\n", "\n", "```toml\n", "[project]\n", "name = \"example-pyproject\"\n", "version = \"0.1.0\"\n", "# ...\n", "urls = {\n", " # What is the landing page\n", " Homepage = \"https://example-pyproject.acme.com\",\n", " # Where is the source\n", " Source = \"https://github.com/acme/example-pyproject\",\n", " # Where to report bugs or request features\n", " Issues = \"https://github.com/acme/example-pyproject/issues/new\"\n", "}\n", "```\n", "\n", "Alternatively\n", "\n", "```toml\n", "[project.urls]\n", "Homepage = \"https://example-pyproject.acme.com\"\n", "Source = \"https://github.com/acme/example-pyproject\"\n", "Issues = \"https://github.com/acme/example-pyproject/issues/new\"\n", "```" ] }, { "cell_type": "markdown", "id": "a2346de4-2c62-41db-b373-ed93ccb18e1e", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## What does the code look like?\n", "\n", "* So far this has been metadata (mostly)" ] }, { "cell_type": "markdown", "id": "a74625c2-889b-420c-a7ab-bf9c57a7a1e9", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Project structure\n", "\n", "```\n", "example-pyproject/ # <--- Git repo directory\n", "```" ] }, { "cell_type": "markdown", "id": "cbcab853-a323-4f2e-a0cd-f5be47787b07", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Project structure\n", "\n", "```\n", "example-pyproject/\n", "├── LICENSE.txt # <--- License file we picked\n", "└── README.md # <--- Initial docs new people see\n", "```" ] }, { "cell_type": "markdown", "id": "4f99a455-ddf8-4c15-82f3-92837bdd8a2b", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Project structure\n", "\n", "```\n", "example-pyproject/\n", "├── LICENSE.txt\n", "├── README.md\n", "└── example_pyproject # <--- Place source code here\n", "```" ] }, { "cell_type": "markdown", "id": "531ac2ac-bd16-4411-917b-f323a2e00d5b", "metadata": { "editable": true, "jp-MarkdownHeadingCollapsed": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Project structure\n", "\n", "```\n", "example-pyproject/\n", "├── LICENSE.txt\n", "├── README.md\n", "└── example_pyproject\n", " └── __init__.py # <--- Make this a Python package\n", "```" ] }, { "cell_type": "markdown", "id": "a63b11c3-c4f2-497e-b8ae-414135e3019e", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Project structure\n", "\n", "```\n", "example-pyproject/\n", "├── LICENSE.txt\n", "├── README.md\n", "└── example_pyproject\n", "```" ] }, { "cell_type": "markdown", "id": "cd144f2b-a030-42ae-8d10-03a4fbbbb7cf", "metadata": { "editable": true, "jp-MarkdownHeadingCollapsed": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Project structure\n", "\n", "```\n", "example-pyproject/\n", "├── LICENSE.txt\n", "├── README.md\n", "├── example_pyproject\n", "└── pyproject.toml # <--- Include our package metadata\n", "```" ] }, { "cell_type": "markdown", "id": "c747a202-bf68-4300-a3bf-78ad5af89177", "metadata": { "editable": true, "jp-MarkdownHeadingCollapsed": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Project structure\n", "\n", "```\n", "example-pyproject/\n", "├── CONTRIBUTING.md # <--- Add maintainer docs\n", "├── LICENSE.txt\n", "├── README.md\n", "├── docs # <--- Add user docs\n", "├── example_pyproject\n", "└── pyproject.toml\n", "```" ] }, { "cell_type": "markdown", "id": "585ad17e-e0f4-4fe4-83a8-29d2be55420e", "metadata": { "editable": true, "jp-MarkdownHeadingCollapsed": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Project structure\n", "\n", "```\n", "example-pyproject/\n", "├── CONTRIBUTING.md\n", "├── LICENSE.txt\n", "├── README.md\n", "├── docs\n", "├── example_pyproject\n", "├── pyproject.toml\n", "└── tests/ # <--- Include unit tests\n", "```" ] }, { "cell_type": "markdown", "id": "dfd7062a-e00a-4609-9e33-2b51659bd66e", "metadata": { "editable": true, "jp-MarkdownHeadingCollapsed": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Project structure\n", "\n", "```\n", "example-pyproject/\n", "├── .github/workflows # <--- GitHub CI\n", "├── CONTRIBUTING.md\n", "├── LICENSE.txt\n", "├── README.md\n", "├── docs\n", "├── example_pyproject\n", "├── pyproject.toml\n", "├── readthedocs.yml # <--- ReadTheDocs build\n", "└── tests/\n", "```" ] }, { "cell_type": "markdown", "id": "a9d42488-11d4-403e-ab76-97ac4fb0502b", "metadata": { "editable": true, "jp-MarkdownHeadingCollapsed": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Project structure\n", "\n", "```\n", "example-pyproject/\n", "├── .github/pull_request_template.md # <--- Checklist for PRs\n", "├── .github/issue_template.md # <--- Checklist for issues\n", "├── .github/workflows\n", "├── CONTRIBUTING.md\n", "├── LICENSE.txt\n", "├── README.md\n", "├── docs/\n", "├── example_pyproject\n", "├── pyproject.toml\n", "├── readthedocs.yml\n", "└── tests/\n", "```" ] }, { "cell_type": "markdown", "id": "043caa64-d397-48ad-adad-511d12671b1e", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## How do we tie this to the code?\n", "\n", "* We now have the metadata\n", "* Also we have structured the source\n", "* How do we build this in a package?" ] }, { "cell_type": "markdown", "id": "c98b1637-f1bd-4320-83ad-408a0198f28c", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Pick a build system\n", "\n", "### What kind of code are we packaging?\n", "\n", "* Pure Python\n", "* Python & Cython\n", "* Python & C/C++\n", "* ..." ] }, { "cell_type": "markdown", "id": "af11fc34-1aa3-44c2-ab04-7fef42ef5fda", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Pick a build system - Pure Python\n", "\n", "### Setuptools\n", "\n", "```toml\n", "[build-system]\n", "build-backend = \"setuptools.build_meta\"\n", "requires = [\n", " \"setuptools\",\n", "]\n", "```\n", "\n", "### Hatchling\n", "\n", "```toml\n", "[build-system]\n", "build-backend = \"hatchling.build\"\n", "requires = [\n", " \"hatchling\",\n", "]\n", "```\n", "\n", "### More options\n", "\n", "https://packaging.python.org/en/latest/glossary/#term-Build-Backend" ] }, { "cell_type": "markdown", "id": "966a52bd-1ef5-45ca-aeff-ccae7b952625", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Pick a build system - Cython\n", "\n", "### Setuptools\n", "\n", "#### `pyproject.toml`\n", "\n", "```toml\n", "[build-system]\n", "build-backend = \"setuptools.build_meta\"\n", "requires = [\n", " \"setuptools>=74.1.0\",\n", " \"cython>=3\",\n", "]\n", "\n", "...\n", "\n", "[tool.setuptools]\n", "ext-modules = [\n", " {name = \"example-pyproject.mylib\", sources = [\"example_pyproject/mylib.pyx\"]},\n", "]\n", "```\n", "\n", "#### Structure\n", "\n", "```\n", "example-pyproject/\n", "├── LICENSE.txt\n", "├── README.md\n", "└── example_pyproject\n", " ├── __init__.py\n", " └── mylib.pyx # <--- Cython module\n", "```" ] }, { "cell_type": "markdown", "id": "63f987b3-3f41-40df-8283-8401c04e8a0c", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Pick a build system - C/C++\n", "\n", "### Setuptools\n", "\n", "```toml\n", "[build-system]\n", "build-backend = \"setuptools.build_meta\"\n", "requires = [\n", " \"setuptools>=74.1.0\",\n", " \"cython>=3\",\n", "]\n", "\n", "...\n", "\n", "[tool.setuptools]\n", "ext-modules = [\n", " {name = \"example-pyproject.mylib\", sources = [\"example_pyproject/mylib.c\"]},\n", "]\n", "```" ] }, { "cell_type": "markdown", "id": "8ea55a0d-3e04-4430-a022-2d67d04990f2", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "### Pick a build system - Other features\n", "\n", "#### Dynamically configure version\n", "\n", "```toml\n", "[build-system]\n", "build-backend = \"setuptools.build_meta\"\n", "requires = [\n", " \"setuptools\",\n", " \"setuptools-scm>=8.1\",\n", "]\n", "\n", "[project]\n", "...\n", "dynamic = [\"version\"]\n", "\n", "[tool.setuptools_scm]\n", "version_scheme = \"guess-next-dev\"\n", "local_scheme = \"dirty-tag\"\n", "write_to = \"example_pyproject/_version.py\"\n", "```" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.5" } }, "nbformat": 4, "nbformat_minor": 5 }