Skip to content

Commit ee4bfea

Browse files
authored
feat: new lesson on hatch envs (#529)
* feat: new lesson on hatch envs * feat: more updates to lessons and use uv with nox
1 parent 017c59c commit ee4bfea

File tree

4 files changed

+284
-1
lines changed

4 files changed

+284
-1
lines changed

noxfile.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
sys.path.insert(0, str(pathlib.Path(__file__).parent.absolute()))
1010
import conf
1111

12+
nox.needs_version = ">=2024.3.2"
13+
nox.options.default_venv_backend = "uv|virtualenv"
1214

1315
## Sphinx related options
1416

tutorials/create-python-package.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
:og:description: Learn how to create a Python package and make your code installable using Hatch. This tutorial walks you through structuring your code and configuring a pyproject.toml so others can easily install and use your package.
2+
:og:description: "Learn how to create a Python package and make your code installable using Hatch. This tutorial walks you through structuring your code and configuring a pyproject.toml so others can easily install and use your package."
33
:og:title: Create a Python package from scratch, a beginner-friendly tutorial
44
---
55

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
---
2+
:og:description: "The pyOpenSci pure Python package template uses Hatch to manage environments and run tests, docs, and other maintenance steps. Learn how to use Hatch environments to manage your Python package."
3+
:og:title: "Use Hatch environments with your Python package: a beginner-friendly tutorial"
4+
---
5+
6+
(develop-package)=
7+
# Use Hatch environments with your pure Python package
8+
9+
:::{admonition} About this lesson
10+
:class: tip
11+
12+
[In a previous lesson](create-pure-python-package), you learned how to create a Python package using the pyOpenSci copier template. In this lesson, you'll learn how to manage and use the Hatch environments set up by de
13+
**What you need to complete this lesson**
14+
15+
To complete this lesson, you will need a local Python
16+
environment and shell on your computer.
17+
You will need to have created a package using our pyOpenSci copier template. You should also have [Hatch installed](get-to-know-hatch).
18+
19+
If you are using Windows or are not familiar with Shell, you may want to check out the [Carpentries shell lesson](https://swcarpentry.github.io/shell-novice/). Windows users will likely need to configure a tool such as [GitBash](https://gitforwindows.org/) for any Shell and git-related steps.
20+
21+
:::
22+
23+
Welcome to your shiny new package! This page will help you get started with using Hatch to run tests, build and check your package, and build your documentation.
24+
25+
To begin, have a look at the `pyproject.toml` file in your package directory. This file contains the configuration for your package. This file is written using a .toml format. [You can learn more about toml here.](https://www.pyopensci.org/python-package-guide/package-structure-code/pyproject-toml-python-package-metadata.html) Here's the TL&DR:
26+
27+
* Each `[]` section in the toml file is called a table.
28+
* You can nest tables with double brackets like this`[[]]`
29+
* Tables contain information about a certain thing that you want to configure.
30+
31+
:::{tip}
32+
You can configure Hatch to use UV by default for environment management. UV is a package manager built in Rust. It is fast and will significantly speed up environment creation.
33+
34+
To use UV with Hatch, configure Hatch in the "tools" section of your `pyproject.toml` file.
35+
36+
```toml
37+
[tool.hatch.envs.default]
38+
installer = "uv"
39+
```
40+
:::
41+
42+
## Using Hatch for developing, building, and maintaining your pure Python package
43+
44+
In the pyOpenSci Python package template, we have set up Hatch environments. You will notice at the bottom of the file, a [hatch environment](https://hatch.pypa.io/1.13/environment/) section, that looks like this:
45+
46+
```
47+
########################################
48+
# Hatch Environments
49+
########################################
50+
```
51+
52+
Hatch allows you to configure and run environments and scripts similar to a workflow tool like tox or nox.
53+
54+
:::{tip}
55+
Hatch defaults to using `venv` to manage environments. However, you can configure it to use other environment tools, such as conda or mamba.
56+
57+
[Read the hatch documentation to learn more about environments. ](https://hatch.pypa.io/1.13/tutorials/environment/basic-usage/)
58+
:::
59+
60+
61+
Below is the Hatch environment used to build and test your package.
62+
Anytime you see: `tool.hatch.envs.test`, it tells Hatch:
63+
64+
> "Hey, Hatch, this is the definition for an environment.`test` is the name of the environment that I want you to create."
65+
66+
So `tool.hatch.envs.build` will create an environment called `build`.
67+
68+
Below the environment "declaration," you can see the definition of what should be in that environment.
69+
70+
## A Hatch environment to build your package
71+
72+
Below is a Hatch environment definition that you will find in your [new project's pyproject.toml file](create-python-package). It is set up to [build your package's](build-package) distribution files ([source distribution](python-source-distribution) and [wheel](python-wheel)).
73+
74+
Notice that the environment definition declares two dependencies: `pip` and `twine`, which the environment needs to run successfully. This declaration is similar to declaring dependencies for your package at the top of your `pyproject.toml`. This section tells Hatch to create a new VENV with pip and twine installed.
75+
76+
```toml
77+
[tool.hatch.envs.build]
78+
description = """Test the installation the package."""
79+
dependencies = [
80+
"pip",
81+
"twine",
82+
]
83+
detached = true
84+
```
85+
86+
:::{admonition} Hatch will install your package in editable mode by default
87+
Notice the `detached = True` flag at the bottom of the environment. By default, hatch will install your package in editable mode into any environment it creates. `detached=True` tells it not to install your package into the environment.
88+
:::
89+
90+
91+
### Hatch scripts
92+
93+
Hatch supports defining scripts that run in specific Hatch environments.
94+
95+
Above, you have defined a new environment called 'build' that Hatch will create as a virtual environment (venv). Because `detached = True` in that environment, Hatch won't install your package into it.
96+
97+
You can then use that environment to run "scripts". The definition below tells Hatch to run the following scripts in the build environment.
98+
99+
`[tool.hatch.envs.build.scripts]`
100+
101+
You define this `scripts` to run using the following syntax, where:
102+
103+
* `tool.hatch`: Alerts Hatch that this table is for Hatch to use
104+
* `envs.build`: Use the defined build environment.
105+
* `scripts`: Define what scripts to run. In this case, Hatch will run shell scripts.
106+
107+
108+
Below is the `build.scripts` table that defines 3 shell commands to be run:
109+
110+
* `pip check` # verifies your dependencies
111+
* `hatch build --clean` # build your packages distribution files.
112+
* `twine check dist/*` # use twine to check that your package's sdist (source distribution) is ok.
113+
114+
```toml
115+
# This table installs the command hatch run install:check, which will build and check your package.
116+
[tool.hatch.envs.build.scripts]
117+
check = [
118+
"pip check",
119+
"hatch build {args:--clean}",
120+
"twine check dist/*",
121+
]
122+
detached = true
123+
```
124+
125+
:::{tip}
126+
Hatch, by default, will install your package in editable mode into any virtual environment (venv) that it creates. If `detached=True` is set, then it will skip that step.
127+
:::
128+
129+
### Running the build script
130+
131+
You can run the build script and build your package like this:
132+
133+
`hatch run build:check`
134+
135+
This step updates the build environment and then builds and checks the output distributions of your package.
136+
137+
You can enter the build environment in your shell to check it out:
138+
139+
```console
140+
$ hatch shell build
141+
```
142+
143+
If you run `pip list` in the environment, twine will be there:
144+
145+
```console
146+
$ pip list
147+
```
148+
149+
To leave the environment use:
150+
151+
```console
152+
$ deactivate
153+
```
154+
155+
### Hatch, testing, and matrix environments
156+
157+
It's always helpful to run your tests on the Python versions that you expect your users to be using. In this section, you'll explore the test environment setup in the pyOpenSci template package.
158+
159+
Below, you see the Hatch environment test table.
160+
161+
Similar to the above build environment, the environment below defines the dependencies that Hatch needs to install into the test environment (required to run your tests).
162+
163+
```toml
164+
[tool.hatch.envs.test]
165+
description = """Run the test suite."""
166+
dependencies = [
167+
"pytest",
168+
"pytest-cov",
169+
"pytest-raises",
170+
"pytest-randomly",
171+
"pytest-xdist",
172+
]
173+
```
174+
175+
### Your test environment has a matrix associated with it
176+
177+
If the environment has a matrix associated with it, that tells Hatch to run the tests across different Python versions. Below, you are running tests on versions 3.10 through 3.13.
178+
179+
:::{tip}
180+
Hatch by default will install Python [using UV](https://docs.astral.sh/uv/guides/install-python/) both when you install Hatch and also when you declare a matrix environment like the one below
181+
:::
182+
183+
```toml
184+
[[tool.hatch.envs.test.matrix]]
185+
python = ["3.10", "3.11", "3.12", "3.13"]
186+
```
187+
188+
In your project, if you run `hatch shell test`, you will see the output below.
189+
This means that because there is a matrix of Python versions to choose from, you need to select the environment with the Python version you want to use.
190+
191+
```console
192+
hatch shell test
193+
Environment `test` defines a matrix, choose one of the following instead:
194+
195+
test.py3.10
196+
test.py3.11
197+
test.py3.12
198+
test.py3.13
199+
```
200+
201+
Pick the Python test environment that you want to use and enter it, like this (this will open Python 3.13):
202+
203+
```console
204+
$ hatch shell test.py3.13
205+
```
206+
207+
To leave the environment use:
208+
209+
```console
210+
$ deactivate
211+
```
212+
213+
### Hatch scripts for tests
214+
215+
In that same tests section, you will see a `tool.hatch.envs.test.scripts` section.
216+
Similar to what you saw above with the build steps, this is where the "script" to run your tests is defined.
217+
218+
Notice that below, the script has a script called `run`. And that script runs pytest with a set of arguments, including generating code coverage.
219+
220+
```toml
221+
[tool.hatch.envs.test.scripts]
222+
run = "pytest {args:--cov=greatproject --cov-report=term-missing}"
223+
```
224+
225+
To run this script in your terminal, use the syntax:
226+
227+
`hatch run test:run`
228+
229+
:::{admonition} Reminder
230+
:class: tip
231+
232+
* `hatch run`: this calls hatch and tells it that it will be running a command
233+
* `test:run` defines the environment you want it to run (`test`) in this case, and the script is defined as `run`
234+
:::
235+
236+
If you have a matrix setup for tests, then it will both install the needed Python version using UV and run your tests in each version of the Python environment. In this case, since there are four Python versions in the environment, your tests will be run four times, once in each Python version listed in the matrix table.
237+
238+
```
239+
@lwasser ➜ /workspaces/pyopensci-scipy25-create-python-package (main) $ hatch run test:run
240+
──────────────────────────────────────────────────────────────────────── test.py3.10 ────────────────────────────────────────────────────────────────────────
241+
==================================================================== test session starts ====================================================================
242+
platform linux -- Python 3.10.16, pytest-8.4.1, pluggy-1.6.0
243+
Using --randomly-seed=1490740387
244+
rootdir: /workspaces/pyopensci-scipy25-create-python-package
245+
configfile: pyproject.toml
246+
testpaths: tests
247+
plugins: xdist-3.8.0, randomly-3.16.0, raises-0.11, cov-6.2.1
248+
collected 2 items
249+
250+
tests/system/test_import.py . [ 50%]
251+
tests/unit/test_example.py . [100%
252+
253+
****************** SOME OUTPUT IS INTENTIONALLY DELETED ********************
254+
====================================================================== tests coverage =======================================================================
255+
_____________________________________________________ coverage: platform linux, python 3.11.12-final-0 ______________________________________________________
256+
257+
Name Stmts Miss Branch BrPart Cover Missing
258+
----------------------------------------------------------------------------
259+
src/greatproject/__init__.py 0 0 0 0 100.00%
260+
src/greatproject/example.py 2 0 0 0 100.00%
261+
----------------------------------------------------------------------------
262+
TOTAL 2 0 0 0 100.00%
263+
===================================================================== 2 passed in 0.05s =====================================================================
264+
```
265+
266+
## Build your documentation with Hatch environments
267+
268+
Finally, you can build and serve your documentation using hatch.
269+
To build a static HTML version of the docs run:
270+
271+
`hatch run docs:build`
272+
273+
To run a local server with your docs updated as you update your markdown files, run:
274+
275+
`hatch run docs:serve`
276+
277+
To stop serving the docs use:
278+
279+
mac: <kbd>ctrl + c</kbd>
280+
windows:

tutorials/intro.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Publish to conda-forge <publish-conda-forge>
5151
:hidden:
5252
:caption: Project information files & metadata
5353

54+
Develop package (Hatch environments) <develop-python-package-hatch>
5455
Add README file <add-readme>
5556
Add a license & code of conduct <add-license-coc>
5657
Update metadata in pyproject.toml <pyproject-toml>

0 commit comments

Comments
 (0)