diff --git a/docs/concepts/projects.md b/docs/concepts/projects.md index 5bf25bd01..0e31ea2f0 100644 --- a/docs/concepts/projects.md +++ b/docs/concepts/projects.md @@ -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 diff --git a/docs/guides/publish.md b/docs/guides/publish.md index ede7257ab..4dd582e8b 100644 --- a/docs/guides/publish.md +++ b/docs/guides/publish.md @@ -12,7 +12,7 @@ distribution. If your project does not include a `[build-system]` definition in the `pyproject.toml`, uv will not build it by default. This means that your project may not be ready for distribution. Read more about the effect of declaring a build system in the -[project concept](../concepts/projects.md#project-types) documentation. +[project concept](../concepts/projects.md#build-systems) documentation. ## Building your package