uv/docs/concepts/projects/init.md
Zanie Blue ca9aaf1c48
Reorganize the project concept documentation (#9121)
- Adds a collapsible section for the project concept
- Splits the project concept document into several child documents.
- Moves the workspace and dependencies documents to under the project
section
- Adds a mkdocs plugin for redirects, so links to the moved documents
still work

I attempted to make the minimum required changes to the contents of the
documents here. There is a lot of room for improvement on the content of
each new child document. For review purposes, I want to do that work
separately. I'd prefer if the review focused on this structure and idea
rather than the content of the files.

I expect to do this to other documentation pages that would otherwise be
very nested.

The project concept landing page and nav (collapsed by default) looks
like this now:

<img width="1507" alt="Screenshot 2024-11-14 at 11 28 45 AM"
src="https://github.com/user-attachments/assets/88288b09-8463-49d4-84ba-ee27144b62a5">
2024-11-19 13:52:12 -06:00

6.6 KiB

Creating projects

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.

When creating projects, uv distinguishes between 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.

Applications are the default target for uv init, but can also be specified with the --app flag:

$ uv init --app example-app
$ tree example-app
example-app
├── .python-version
├── README.md
├── hello.py
└── pyproject.toml

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.

[project]
name = "example-app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []

The created script defines a main function with some standard boilerplate:

def main():
    print("Hello from example-app!")


if __name__ == "__main__":
    main()

And can be executed with uv run:

$ uv run hello.py
Hello from example-project!

Libraries

A library is a project that is intended to be built and distributed as a Python package, for example, by uploading it to PyPI. A library provides functions and objects for other projects to consume.

Libraries can be created by using the --lib flag:

$ uv init --lib example-lib
$ tree example-lib
example-lib
├── .python-version
├── README.md
├── pyproject.toml
└── src
    └── example_lib
        ├── py.typed
        └── __init__.py

When creating a library, uv defines a build system and places the source code 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.

[project]
name = "example-lib"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

!!! note

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.

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:

def hello() -> str:
    return "Hello from example-lib!"

And you can import and execute it using uv run:

$ uv run --directory example-lib python -c "import example_lib; print(example_lib.hello())"
Hello from example-lib!

You can select a different build backend template by using --build-backend with hatchling, flit-core, pdm-backend, setuptools, maturin, or scikit-build-core.

$ uv init --lib --build-backend maturin example-lib
$ tree example-lib
example-lib
├── .python-version
├── Cargo.toml
├── README.md
├── pyproject.toml
└── src
    ├── lib.rs
    └── example_lib
        ├── py.typed
        ├── __init__.py
        └── _core.pyi

And you can import and execute it using uv run:

$ uv run --directory example-lib python -c "import example_lib; print(example_lib.hello())"
Hello from example-lib!

!!! tip

Changes to `lib.rs` or `main.cpp` will require running `--reinstall` when using binary build
backends such as `maturin` and `scikit-build-core`.

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:

$ uv init --app --package example-packaged-app
$ tree example-packaged-app
example-packaged-app
├── .python-version
├── README.md
├── pyproject.toml
└── src
    └── example_packaged_app
        └── __init__.py

But the module defines a CLI function:

def main() -> None:
    print("Hello from example-packaged-app!")

And the pyproject.toml includes a script entrypoint:

[project]
name = "example-packaged-app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []

[project.scripts]
example-packaged-app = "example_packaged_app:main"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

Which can be executed with uv run:

$ uv run --directory example-packaged-app example-packaged-app
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.

In addition, you can further customize the build backend of a packaged application by specifying --build-backend including binary build backends such as maturin.

$ uv init --app --package --build-backend maturin example-packaged-app
$ tree example-packaged-app
example-packaged-app
├── .python-version
├── Cargo.toml
├── README.md
├── pyproject.toml
└── src
    ├── lib.rs
    └── example_packaged_app
        ├── __init__.py
        └── _core.pyi

Which can also be executed with uv run:

$ uv run --directory example-packaged-app example-packaged-app
Hello from example-packaged-app!