|
1 | 1 | --- |
2 | 2 | downloads: |
3 | | - - file: index.md |
4 | | - title: Source File |
5 | 3 | - url: slides/1_01_setup.html |
6 | 4 | static: false |
7 | 5 | title: Slides |
@@ -288,7 +286,8 @@ have to remember to update things too! |
288 | 286 |
|
289 | 287 | Another thing we can do is single-file scripts. They look like this: |
290 | 288 |
|
291 | | -```python |
| 289 | +```{code} python |
| 290 | +:filename: simple.py |
292 | 291 | # /// script |
293 | 292 | # dependencies = ["numpy"] |
294 | 293 | # /// |
@@ -329,11 +328,154 @@ How you specify your dependencies depends a bit on the tool you are using, |
329 | 328 | since it is not standardized like libraries are. But you can always use `[project]` |
330 | 329 | and make it an unpublishable library by adding this: |
331 | 330 |
|
332 | | -```toml |
| 331 | +```{code} toml |
| 332 | +:filename: pyproject.toml |
333 | 333 | [project] |
334 | 334 | classifiers = [ |
335 | 335 | "Private :: Do Not Upload", |
336 | 336 | ] |
337 | 337 | ``` |
338 | 338 |
|
339 | 339 | ### Libraries |
| 340 | + |
| 341 | +A library is something that can be shared with others. The key feature is that |
| 342 | +it must be able to share an environment with whatever else the user of the |
| 343 | +library needs. If a user is expected to `import` your code, it's a library. |
| 344 | + |
| 345 | +Later sections will explain a lot more about packages, so let's just present a basic `pyproject.toml`: |
| 346 | + |
| 347 | +```{code} toml |
| 348 | +:filename: pyproject.toml |
| 349 | +[build-system] |
| 350 | +requires = ["hatchling"] |
| 351 | +build-backend = "hatchling.build" |
| 352 | +
|
| 353 | +[project] |
| 354 | +name = "example" |
| 355 | +version = "0.1.0" |
| 356 | +``` |
| 357 | + |
| 358 | +Notice the `[build-system]` section; this tells tools how to build the package |
| 359 | +into something you can distribute and install. There are quite a few build |
| 360 | +backends; the one above uses `hatchling`. |
| 361 | + |
| 362 | +There are a lot of places to put dependencies; here's an expanded version with annotations: |
| 363 | + |
| 364 | +```{code} toml |
| 365 | +:linenos: |
| 366 | +:filename: pyproject.toml |
| 367 | +:emphasize-lines: 2,8,11,14 |
| 368 | +[build-system] |
| 369 | +requires = ["hatchling"] # 1 |
| 370 | +build-backend = "hatchling.build" |
| 371 | +
|
| 372 | +[project] |
| 373 | +name = "example" |
| 374 | +version = "0.1.0" |
| 375 | +dependencies = [] # 2 |
| 376 | +
|
| 377 | +[project.optional-dependencies] |
| 378 | +extra = [] # 3 |
| 379 | +
|
| 380 | +[dependency-groups] |
| 381 | +dev = [] # 4 |
| 382 | +``` |
| 383 | + |
| 384 | +:::{glossary} |
| 385 | +build-system.requires |
| 386 | +: Requirements that are installed when building distributions. This is your |
| 387 | +build-backend, and anything else require to assemble your package from source. |
| 388 | +These are not available at runtime for users. Noted with `# 1` above. |
| 389 | + |
| 390 | +project.dependencies |
| 391 | +: Libraries that must always be installed to use your package. Any installation |
| 392 | +of your package will also install these. Noted with `# 2` above. |
| 393 | + |
| 394 | +project.optional-dependencies |
| 395 | +: This is a table with arbitrary keys. When a user is installing your package, |
| 396 | +they can add `[extra]` to install the list of dependencies named `extra`. |
| 397 | +These will not neccisarly be present if the user didn't request then. Also |
| 398 | +known as "extras". These are part of the public package metadata. Noted with |
| 399 | +`# 3` above. |
| 400 | + |
| 401 | +dependency-groups |
| 402 | +: This is a table with arbitrary keys. Unlike project.optional-dependencies, these |
| 403 | +do not become part of the package metadata; you must have the `pyproject.toml` file |
| 404 | +to install them. They also do not require you install the package. Commonly |
| 405 | +used for development dependencies, like tests, docs, coverage, and the like. |
| 406 | +Noted with `# 4` above. |
| 407 | +::: |
| 408 | + |
| 409 | +A quick comparison: |
| 410 | + |
| 411 | +| | `b-s.r` | `p.d` | `p.o-d` | `d-g` | |
| 412 | +| ------------------------------ | ------- | ----- | ------- | ----- | |
| 413 | +| Public metadata | ✅ | ✅ | ✅ | ❌ | |
| 414 | +| Always installed | ❌ | ✅ | ❌ | ❌ | |
| 415 | +| Named groups | ❌ | ❌ | ✅ | ✅ | |
| 416 | +| Can be independently installed | ❌ | ❌ | ✅ | ✅ | |
| 417 | + |
| 418 | +#### High level project management with uv |
| 419 | + |
| 420 | +When dependency-groups were introduced, uv made a brilliant decision: if there's |
| 421 | +a group named `dev`, it is installed by default when using `uv run`. This enables |
| 422 | +the following file: |
| 423 | + |
| 424 | +```{code} toml |
| 425 | +:filename: pyproject.toml |
| 426 | +[build-system] |
| 427 | +requires = ["hatchling"] |
| 428 | +build-backend = "hatchling.build" |
| 429 | +
|
| 430 | +[project] |
| 431 | +name = "example" |
| 432 | +version = "0.1.0" |
| 433 | +requires-python = ">=3.12" |
| 434 | +dependencies = ["numpy"] |
| 435 | +
|
| 436 | +[dependency-groups] |
| 437 | +dev = ["pytest"] |
| 438 | +``` |
| 439 | + |
| 440 | +to be all you need to use `uv run`. For example, |
| 441 | + |
| 442 | +```bash |
| 443 | +uv run pytest |
| 444 | +``` |
| 445 | + |
| 446 | +will: |
| 447 | + |
| 448 | +- Download Python if you don't have a valid copy |
| 449 | +- Make a virtual environment at `.venv` if it doesn't exist |
| 450 | +- Install dependencies from a `uv.lock` lockfile if it exists |
| 451 | +- Create a `uv.lock` file from `project.dependencies` and `dependency-groups.dev` if it doesn't exist and install |
| 452 | +- Make an editable install of your project |
| 453 | +- Run whatever command you give it from that virtual environment |
| 454 | + |
| 455 | +If you edit the dependencies, then the lockfile and `.venv` will be updated |
| 456 | +when you `uv run` again. |
| 457 | + |
| 458 | +Any command works, so `uv run python` starts up `python`, if you have command |
| 459 | +line apps you can use `uv run ...`, etc. |
| 460 | + |
| 461 | +:::{exercise} Development environment |
| 462 | +:label: uv-dev-env |
| 463 | + |
| 464 | +The most downloaded Python package in the world is probably `packaging` (not |
| 465 | +counting AWS). Download the `https://github.com/pypa/packaging` repository from |
| 466 | +github, and run the test suite with `pytest` using uv. |
| 467 | + |
| 468 | +::: |
| 469 | + |
| 470 | +:::{solution} uv-dev-env |
| 471 | +:class: dropdown |
| 472 | + |
| 473 | +Assuming a unix-like system and bash: |
| 474 | + |
| 475 | +```bash |
| 476 | +git clone https://github.com/pypa/packaging |
| 477 | +cd packaging |
| 478 | +uv run pytest |
| 479 | +``` |
| 480 | + |
| 481 | +::: |
0 commit comments