Improvements to the application and library documentation (#6726)

This commit is contained in:
Zanie Blue 2024-08-27 18:15:12 -05:00 committed by GitHub
parent 3ee6ca31f4
commit 75a5066e10
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 184 additions and 46 deletions

View file

@ -10,7 +10,7 @@ Python projects help manage Python applications spanning multiple files.
Python project metadata is defined in a `pyproject.toml` file.
!!!
!!! tip
`uv init` can be used to create a new project. See [Creating projects](#creating-projects) for
details.
@ -24,58 +24,107 @@ version = "0.1.0"
description = "Add your description here"
```
It's recommended, but not required, to include a Python version requirement:
It's recommended, but not required, to include a Python version requirement in the `[project]`
section:
```toml title="pyproject.toml"
[project]
requires-python = ">=3.12"
```
This Python version requirement determines what syntax is valid in the project and affects the
versions of dependencies which can be used (they must support the same Python range).
Including a Python version requirement defines the Python syntax that is allowed in the project and
affects selection of dependency versions (they must support the same Python version range).
The `pyproject.toml` also lists dependencies of the project. uv supports modifying the standard
dependency list from the command line with `uv add` and `uv remove`. uv also supports
[extended package sources](./dependencies.md) for advanced users.
The `pyproject.toml` also lists dependencies of the project in the `project.dependencies` and
`project.optional-dependencies` fields. uv supports modifying the project's dependencies from the
command line with `uv add` and `uv remove`. uv also supports extending the standard dependency
definitions with [package sources](./dependencies.md) in `tool.uv.sources`.
!!! tip
See the official [`pyproject.toml` guide](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/) for more details on getting started with a `pyproject.toml`.
## Build systems
Projects _may_ define a `[build-system]` in the `pyproject.toml`. The build system defines how the
project should be packaged and installed.
uv uses the presence of a build system to determine if a project contains a package that should be
installed in the project virtual environment. If a build system is not defined, uv will not attempt
to build or install the project itself, just its dependencies. If a build system is defined, uv will
build and install the project into the project environment. Projects are installed in
[editable mode](https://setuptools.pypa.io/en/latest/userguide/development_mode.html) so changes to
the source code are reflected immediately, without reinstallation.
### Configuring project packaging
uv also allows manually declaring if a project should be packaged using the
[`tool.uv.package`](../reference/settings.md#package) setting.
Setting `tool.uv.package = true` will force a project to be built and installed into the project
environment. If no build system is defined, uv will use the setuptools legacy backend.
Setting `tool.uv.package = false` will force a project package _not_ to be built and installed into
the project environment. uv will ignore a declared build system when interacting with the project.
## Creating projects
uv supports initializing a project with `uv init`. By default, uv will create a project in the
working directory. Projects can be created in a target directory by providing a name, e.g.,
`uv init foo`. If there's already a project in the target directory, i.e., there's a
uv supports creating a project with `uv init`.
uv will create a project in the working directory, or, in a target directory by providing a name,
e.g., `uv init foo`. If there's already a project in the target directory, i.e., there's a
`pyproject.toml`, uv will exit with an error.
By default, uv will create a project for an [application](#applications). However, the `--lib` flag
can be used to create a project for a [library](#libraries).
When creating projects, uv distinguishes between two types: [**applications**](#applications) and
[**libraries**](#libraries).
## Project types
uv groups projects into two types: **applications** and **libraries**.
By default, uv will create a project for an application. The `--lib` flag can be used to create a
project for a library instead.
### Applications
Application projects are suitable for web servers, scripts, and command-line interfaces.
Application projects have the following traits:
Applications are the default target for `uv init`, but can also be specified with the `--app` flag:
- A build backend is not defined.
- Source code is often in the top-level directory, e.g., `hello.py`.
- The project package is not installed in the project environment.
```console
$ uv init --app example-app
$ tree example-app
example-app
├── README.md
├── hello.py
└── pyproject.toml
```
!!! note
When creating an application, uv will generate a minimal `pyproject.toml`. A build system is not
defined and the source code is in the top-level directory, e.g., `hello.py`. The project does not
contain a package that will be built and installed into the project environment.
The `--package` flag can be passed to `uv init` to create a distributable application,
e.g., if you want to publish a command-line interface via PyPI. uv will define a build
backend for the project, include a `[project.scripts]` entrypoint, and install the project
package into the project environment.
```toml title="pyproject.toml"
[project]
name = "example-app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []
```
Similarly, a build backend can be manually defined to treat any application as a distributable
package. This may require changes to the project directory structure, depending on the build
backend.
The created script defines a `main` function with some standard boilerplate:
```python title="hello.py"
def main():
print("Hello from example-app!")
if __name__ == "__main__":
main()
```
And can be executed with `uv run`:
```console
$ uv run hello.py
Hello from example-project!
```
### Libraries
@ -83,30 +132,119 @@ A library is a project that is intended to be built and distributed as a Python
example, by uploading it to PyPI. A library provides functions and objects for other projects to
consume.
Library projects have the following traits:
Libraries can be created by using the `--lib` flag:
- A build backend is required.
- Source code is typically in a `src/{package}` directory.
- The project package is installed in the project environment.
```console
$ uv init --lib example-lib
$ tree example-lib
example-lib
├── README.md
├── pyproject.toml
└── src
└── example_lib
└── __init__.py
```
Libraries can be created with `uv init` by providing the `--lib` flag. uv will assume that any
project that defines a `[build-system]` is a library.
When creating a library, uv defines a build system and places the source code in placed in a `src`
directory. These changes ensure that the library is isolated from any `python` invocations in the
project root and that distributed library code is well separated from the rest of the project source
code. The project includes a package at `src/example_lib` that will be built and installed into the
project environment.
### Other types
```toml title="pyproject.toml"
[project]
name = "example-lib"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []
By default, uv uses the presence of a `[build-system]` in the `pyproject.toml` to determine if a
project is an application or a library. However, uv also allows manually declaring if a project
should be treated as a package.
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
```
To enable or disable build and installation of the project package regardless of the presence of a
`[build-system]` definition, use the [`tool.uv.package`](../reference/settings.md#package) setting.
!!! note
Setting `tool.uv.package = true` will force a project package to be built and installed into the
project environment. If no build system is defined, uv will use the setuptools legacy backend.
uv does not provide a build backend yet. `hatchling` is used by default, but there are other
options. You may need to use the [hatch build](https://hatch.pypa.io/1.9/config/build/) options
to configure `hatchling` for your project structure.
Setting `tool.uv.package = false` will force a project package _not_ to be built and installed into
the project environment. uv will ignore the declared build system, if any, when interacting with the
project.
Progress towards a uv build backend can be tracked in [astral-sh/uv#3957](https://github.com/astral-sh/uv/issues/3957).
The created module defines a simple API function:
```python title="__init__.py"
def hello() -> str:
return "Hello from example-lib!"
```
And you can import and execute it using `uv run`:
```console
$ uv run python -c "import example_lib; print(example_lib.hello())"
Hello from example-lib!
```
### Packaged applications
The `--package` flag can be passed to `uv init` to create a distributable application, e.g., if you
want to publish a command-line interface via PyPI. uv will define a build backend for the project,
include a `[project.scripts]` entrypoint, and install the project package into the project
environment.
The project structure looks the same as a library:
```console
$ uv init --app --package example-packaged-app
$ tree example-packaged-app
example-packaged-app
├── README.md
├── pyproject.toml
└── src
└── example_packaged-app
└── __init__.py
```
But the module defines a CLI function:
```python title="__init__.py"
def hello():
print("Hello from example-packaged-app!")
```
And the `pyproject.toml` includes a script entrypoint:
```python title="pyproject.toml" hl_lines="9 10"
[project]
name = "example-packaged-app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []
[project.scripts]
hello = "example_packaged_app:hello"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
```
Which can be executed with `uv run`:
```console
$ uv run hello
Hello from example-packaged-app!
```
!!! tip
An existing application can be redefined as a distributable package by adding a build system.
However, this may require changes to the project directory structure, depending on the build
backend.
## Project environments