Skip to content

Commit b890729

Browse files
committed
feat: slides for week 5
Signed-off-by: Henry Schreiner <[email protected]>
1 parent 693e975 commit b890729

File tree

5 files changed

+296
-27
lines changed

5 files changed

+296
-27
lines changed

content/week01/intro.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -132,23 +132,23 @@ provides different printouts for different structures:
132132

133133
```python
134134
if isinstance(x, list):
135-
print(*x)
135+
print(*x)
136136
elif isinstance(x, dict):
137-
print(*(f"{k}={v}" for k, v in x.items()))
137+
print(*(f"{k}={v}" for k, v in x.items()))
138138
else:
139-
print(x)
139+
print(x)
140140
```
141141

142142
versus using pattern matching:
143143

144144
```python
145145
match x:
146-
case [*_]:
147-
print(*x)
148-
case {}:
149-
print(*(f"{k}={v}" for k, v in x.items()))
150-
case _:
151-
print(x)
146+
case [*_]:
147+
print(*x)
148+
case {}:
149+
print(*(f"{k}={v}" for k, v in x.items()))
150+
case _:
151+
print(x)
152152
```
153153

154154
The pattern matching case is more focused, so it takes less reading. You know

content/week05/packaging.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
# Packaging and quality control
22

3+
[Slides](https://henryiii.github.io/se-for-sci/slides/week-05-1)
4+
35
Now you have your Git Repo, it's time to talk about how you structure it to make
46
it distributable and usable by others. We'll focus on building a Python package,
57
though most of the ideas here are available in other ecosystems for modern
68
languages. C, C++, and Fortran stick out a bit for not having things like
79
standard package managers; you can substitute a build system for these.
810

9-
## Pip and PyPI
11+
## Pip / uv and PyPI
1012

1113
Most languages have at least one package manager; "pip" is the canonical package
1214
manager for Python. To distribute packages for pip to install, either SDists or
@@ -38,7 +40,11 @@ permission, or to your user's site-packages if you don't, or if you are in a
3840
virtual environment (more on those later), then it installs into that
3941
environment's site-packages.
4042

41-
## Conda/Mamba/MicroMamba and conda-forge
43+
There is also a Rust rewrite of pip (and several other tools) called "uv" that
44+
is faster (think 10-100x faster) and has an alternate high-level API. It's only
45+
about a year old, but already 20% of the PyPI downloads are now via uv.
46+
47+
## Conda/Mamba/MicroMamba/Pixi and conda-forge
4248

4349
Wheels have been a huge success in binary packaging, but before wheels solved
4450
many of the problems with binary packaging, conda was developed with different
@@ -58,6 +64,22 @@ that works everywhere, while conda packages bundle everything and are build with
5864
custom toolchains. Conda distributes Python itself - it's just another
5965
dependency to Conda, while Pip can only install to an existing Python.
6066

67+
There are several packages, so here's a quick summary:
68+
69+
- **Conda**: The original, written in Python. The resolver is now from Mamba,
70+
so it's much closer to speed in mamba that is used to be.
71+
a large ecosystem.
72+
- **Mamba**: A faster, drop-in replacement for conda that uses a different
73+
dependency resolver and is written in C++.
74+
- **MicroMamba**: Used to be different from Mamba, but now is simply a
75+
statically linked version of Mamba.
76+
- **Pixi**: A Rust rewrite of conda, designed around a new high-level API.
77+
Unlike uv, it does not have a low-level API to match conda/mamba.
78+
79+
It turns out, writing a tool that can get Python, in Python, has bad
80+
chicken-and-egg problem. That's why it's been rewritten not once, but twice, in
81+
compiled languages.
82+
6183
Which do you pick? I'll focus on PyPI; it's the "official" ecosystem, and most
6284
conda packages just build PyPI packages. But there are often places (like ML)
6385
where conda is preferred. Unless you are making your own package (in which case

content/week05/using_packages.md

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,20 @@ you don't expect to import it, _do not use pip_; use
5050
environment, but hide all that for you, and then you'll just have an application
5151
you can use with no global/user side effects!
5252

53+
`````{tab-set}
54+
````{tab-item} uv
55+
```bash
56+
uv tool install black
57+
black myfile.py
58+
```
59+
````
60+
````{tab-item} pipx
5361
```bash
54-
pip install pipx # Easier to install like this
55-
5662
pipx install black
5763
black myfile.py
5864
```
65+
````
66+
`````
5967

6068
Now you have "black", but nothing has changed in your global site packages! You
6169
cannot import black or any of it's dependencies! There are no conflicting
@@ -67,17 +75,26 @@ packages that have incompatible requirements).
6775
Pipx also has a very powerful feature: you can install and run an application in
6876
a temporary environment!
6977

70-
For example, this works just as well as the second two lines above:
78+
For example, this works just as well as the lines above:
7179

80+
`````{tab-set}
81+
````{tab-item} uv
82+
```bash
83+
uvx black myfile.py
84+
```
85+
````
86+
````{tab-item} pipx
7287
```bash
7388
pipx run black myfile.py
7489
```
90+
````
91+
`````
7592

7693
The first time you do this, pipx create a venv and puts black in it, then runs
7794
it. If you run it again, it will reuse the cached environment if it hasn't been
7895
cleaned up yet, so it's fast.
7996

80-
Another example:
97+
Another example (note: for uv, use `uv build`, which is built-in):
8198

8299
```bash
83100
pipx run build
@@ -87,13 +104,22 @@ pipx run build
87104
> you do not need `actions/setup-python` to run it.
88105
89106
If the command and the package have different names, then you may have to write
90-
this with a `--spec`, though pipx has a way to customize this, and it will try
107+
this with a `--spec` (`--from` with uvx), though pipx has a way to customize this, and it will try
91108
to guess if there's only one command in the package. You can also pin exactly,
92109
specify extras, etc:
93110

111+
`````{tab-set}
112+
````{tab-item} uv
113+
```bash
114+
uvx --from cibuildwheel==2.9.0 cibuildwheel --platform linux
115+
```
116+
````
117+
````{tab-item} pipx
94118
```bash
95119
pipx run --spec cibuildwheel==2.9.0 cibuildwheel --platform linux
96120
```
121+
````
122+
`````
97123

98124
#### Self-contained scripts
99125

@@ -165,11 +191,22 @@ rich >=9.8
165191
This is technically a valid `requirements.txt` file. If you wanted to use it,
166192
you would do:
167193

194+
`````{tab-set}
195+
````{tab-item} uv
168196
```bash
169-
python3 -m venv venv
170-
. venv/bin/activate
197+
uv venv
198+
. .venv/bin/activate
199+
uv pip install -r requirements.txt
200+
```
201+
````
202+
````{tab-item} pip
203+
```bash
204+
python3 -m venv .venv
205+
. .venv/bin/activate
171206
pip install -r requirements.txt
172207
```
208+
````
209+
`````
173210

174211
Use `deactivate` to "leave" the virtual environment.
175212

@@ -212,6 +249,20 @@ example, `pip install rich[jupyter]` will add some extra requirements for
212249
interacting with notebooks. _These add requirements only_, you can't change the
213250
package with an extra.
214251

252+
### Dependency-groups
253+
254+
You can also use dependency groups, which are a way to specify optional
255+
dependencies in `pyproject.toml`. This is a new feature, but most recent
256+
versions of most tools support it. It looks like this:
257+
258+
```toml
259+
[dependency-groups]
260+
dev = ["pytest"]
261+
```
262+
263+
You can install it with `--group dev`. The high-level interface to uv automatically
264+
installs the `dev` group, so using this makes `uv run` work out of the box.
265+
215266
### Conda environments
216267

217268
If you use Conda, the environment file is called `environment.yaml`. The one we

slides/week-01-1.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -106,23 +106,23 @@ for i in range(10):
106106

107107
```python
108108
if isinstance(x, list):
109-
print(*x)
109+
print(*x)
110110
elif isinstance(x, dict):
111-
print(*(f"{k}={v}" for k, v in x.items()))
111+
print(*(f"{k}={v}" for k, v in x.items()))
112112
else:
113-
print(x)
113+
print(x)
114114
```
115115

116116
vs.
117117

118118
```python
119119
match x:
120-
case [*_]:
121-
print(*x)
122-
case {}:
123-
print(*(f"{k}={v}" for k, v in x.items()))
124-
case _:
125-
print(x)
120+
case [*_]:
121+
print(*x)
122+
case {}:
123+
print(*(f"{k}={v}" for k, v in x.items()))
124+
case _:
125+
print(x)
126126
```
127127

128128
---

0 commit comments

Comments
 (0)