Skip to content

Commit 8c0258c

Browse files
authored
feat: add tutorial on using hatch scripts (#624)
* feat: hatch scripts * feat: copy edits * feat: copy edits
1 parent 66e3d38 commit 8c0258c

2 files changed

Lines changed: 149 additions & 0 deletions

File tree

tutorials/intro.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ understanding the steps involved in creating a Python package.
3535
:caption: Python Packaging Tutorial Setup
3636

3737
Get to know Hatch <get-to-know-hatch>
38+
Run standalone Python scripts with Hatch <run-python-scripts-hatch>
3839
:::
3940

4041
:::{toctree}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
---
2+
:og:description: Learn how to run standalone Python scripts with Hatch using
3+
inline metadata so dependencies and Python versions are managed
4+
automatically.
5+
:og:title: Run standalone Python scripts with Hatch
6+
---
7+
8+
# Run standalone Python scripts with Hatch
9+
10+
Python supports inline metadata for scripts (a feature added in 2024). This makes it possible to run
11+
standalone scripts with dependencies and Python versions managed
12+
automatically.
13+
14+
Many tools support this workflow, including PDM, Hatch, and uv. In this
15+
tutorial, we focus on Hatch and UV. The same metadata format can also be used with
16+
other tools.
17+
18+
:::{seealso}
19+
20+
* [Hatch: How to run Python scripts](https://hatch.pypa.io/latest/how-to/run/python-scripts/)
21+
* [uv: Running scripts](https://docs.astral.sh/uv/guides/scripts/#creating-a-python-script)
22+
:::
23+
24+
## How to create a reproducible script
25+
26+
Sometimes you want to share or run a single script without creating a full
27+
package. To do this, you can use inline script metadata. This format lets you
28+
specify dependencies and Python versions at the top of your script in a
29+
comment block.
30+
31+
When you add metadata at the top of a script, Hatch (or PDM or uv) will use
32+
that metadata to:
33+
34+
* Create an isolated virtual Python environment for that script.
35+
* Install the dependencies listed in the script into that environment.
36+
* Use the required Python version that you specify in the metadata.
37+
38+
This approach is useful for workflows that you want to make reproducible, but
39+
that do not need to become full Python packages.
40+
41+
## Why use Hatch for scripts?
42+
43+
Inline metadata helps you make scripts reproducible. Anyone can run your
44+
script without manually creating a new environment or guessing which
45+
dependencies it needs. Hatch takes care of installing dependencies and using
46+
the correct Python version.
47+
48+
## How to add inline metadata to your script
49+
50+
You will use Hatch in this example, but you can also use uv if that is your
51+
preferred tool.
52+
53+
First, create a new file named `script.py` with the block below at the top.
54+
The metadata block starts with `# /// script` and ends with `# ///`.
55+
Everything in between must be TOML metadata written as comments.
56+
57+
In the example below, the script requires Python 3.11 or newer, and NumPy is
58+
declared as a dependency.
59+
60+
```python
61+
# /// script
62+
# requires-python = ">=3.11"
63+
# dependencies = [
64+
# "numpy",
65+
# ]
66+
# ///
67+
68+
import numpy as np
69+
70+
temperatures_c = np.array([12.4, 13.1, 14.8, 15.2, 16.0, 14.4, 13.7])
71+
mean_temp = np.mean(temperatures_c)
72+
anomalies = temperatures_c - mean_temp
73+
74+
print(f"Mean temperature: {mean_temp:.2f} C")
75+
print("Temperature anomalies:", np.round(anomalies, 2))
76+
```
77+
78+
## Run the script with Hatch
79+
80+
Open your terminal and change to the directory where `script.py` lives.
81+
Then run:
82+
83+
```bash
84+
hatch run script.py
85+
```
86+
87+
On first run, Hatch will create an environment and install dependencies. On
88+
later runs, Hatch will reuse that environment so startup is faster.
89+
90+
:::{note}
91+
The environment name is based on the script path. If you move the script to a
92+
new location, Hatch will treat it as a new script environment.
93+
:::
94+
95+
## Optional: configure script environment behavior
96+
97+
You can control script-specific Hatch behavior in the same metadata block.
98+
For example, to use `pip` instead of `uv` as the installer:
99+
100+
```python
101+
# /// script
102+
# requires-python = ">=3.11"
103+
# dependencies = ["numpy"]
104+
#
105+
# [tool.hatch]
106+
# installer = "pip"
107+
# ///
108+
```
109+
110+
:::{admonition} Run the same script with uv
111+
112+
If you prefer uv, you can run the same inline-metadata script with:
113+
114+
```bash
115+
uv run script.py
116+
```
117+
118+
The same `# /// script` metadata block works with uv, including
119+
`requires-python` and `dependencies`.
120+
121+
For more on using uv to run scripts, see the guide:
122+
[Running scripts with uv](https://docs.astral.sh/uv/guides/scripts/#creating-a-python-script).
123+
:::
124+
125+
## When to use scripts vs. packages
126+
127+
You may be wondering when to use scripts versus creating a package.
128+
129+
This depends on your use case. Scripts are often useful when:
130+
131+
* You have one small task, or a specific workflow that is not generalizable.
132+
* Your workflow is still evolving, but you want to run it in a reproducible
133+
environment.
134+
* You want reproducible dependencies quickly.
135+
* You are sharing a single file with collaborators.
136+
137+
Create a full package when:
138+
139+
* You are building reusable modules for multiple projects.
140+
* You need tests, documentation, releases, and long-term maintenance.
141+
* Your codebase is growing beyond one or two scripts.
142+
143+
:::{seealso}
144+
145+
* [Get to know Hatch](get-to-know-hatch.md)
146+
* [Create a Python package](create-python-package.md)
147+
* [Command line reference guide](command-line-reference.md)
148+
:::

0 commit comments

Comments
 (0)