pyfaro init¶
pyfaro init prepares a standalone project for uv-backed development: it adds
the [tool.pyfaro] opt-in to pyproject.toml and creates or refreshes
uv.lock. Use it to adopt an existing project, or to bootstrap a bare one.
By default it only previews the plan. Nothing is written until you pass
--apply.
init --apply works on Linux, macOS and Windows. Releases up to
0.5.0-beta.1 apply it on Linux only; there, --apply on macOS and Windows
stops with an unsupported-platform error before changing any file.
Quick example¶
$ pyfaro init demo
Initialization plan for demo:
Run uv init --bare (no Git, README, or Python pin files).
Ensure the following configuration in pyproject.toml:
[tool.pyfaro]
schema-version = 1
Run uv lock --no-build to create or update uv.lock.
Preview only: rerun with --apply to initialize this project.
$ pyfaro init demo --apply
Scenarios¶
1. Preview a new project¶
The path defaults to the current directory. In a directory without a
pyproject.toml, the plan is to run uv init --bare, add the Pyfaro table
and lock. The preview creates no file or directory and does not even need uv
installed.
2. Apply it¶
$ pyfaro init demo --apply
Initialization plan for demo:
…
Initialized project `demo`
Using CPython 3.13.11
Resolved 1 package in 1ms
Initialized demo with Pyfaro and uv.
$ cat demo/pyproject.toml
[project]
name = "demo"
version = "0.1.0"
requires-python = ">=3.13"
dependencies = []
[tool.pyfaro]
schema-version = 1
The result is just pyproject.toml and uv.lock. No Git repository, README,
.python-version or application source is created. Commit
pyproject.toml and uv.lock together.
Note
init does not install packages or create .venv. Run
pyfaro sync afterwards.
3. Adopt an existing project¶
An existing project needs a standard [project] table. init keeps
everything it finds (dependencies, [tool.uv], [tool.ruff], comments, build
settings) and only adds what is missing:
$ pyfaro init old --apply --offline
…
$ cat old/pyproject.toml
[project]
name = "old"
version = "1.2.3"
requires-python = ">=3.11"
dependencies = []
# keep me
[tool.ruff]
line-length = 100
[tool.pyfaro]
schema-version = 1
If [tool] or its pyfaro entry is written as an inline table, the preview
prints the complete proposed pyproject.toml so you can see the exact form:
$ pyfaro init inl3
Initialization plan for inl3:
Proposed pyproject.toml:
tool = {ruff = {line-length = 100}, pyfaro = { schema-version = 1 } }
[project]
name="i"
version="0.1.0"
Run uv lock --no-build to create or update uv.lock.
Preview only: rerun with --apply to initialize this project.
4. Run it again (idempotence)¶
Applying to an already initialized project is safe. The plan only lists what is left to do:
$ pyfaro init demo --apply
Initialization plan for demo:
[tool.pyfaro] is already configured.
Run uv lock --no-build to create or update uv.lock.
Using CPython 3.13.11
Resolved 1 package in 0.51ms
Initialized demo with Pyfaro and uv.
uv re-checks the lock without upgrading anything. If dependency metadata or an index changed meanwhile, uv may still update a stale lock.
5. Work offline with --offline¶
--offline disables uv's network access. A project without dependencies, or
whose metadata is already cached, locks fine offline:
6. Choose uv with --uv¶
--uv <path> selects the uv executable (a path, or a name looked up on
PATH). The default is uv. A relative path is resolved once, before
entering the project directory.
$ pyfaro init demo --apply --uv /nonexistent/uv
error: could not find uv at /nonexistent/uv; fix --uv <path> or install uv (https://docs.astral.sh/uv/getting-started/installation/, or `curl -LsSf https://astral.sh/uv/install.sh | sh`)
uv 0.9.26 or newer (stable) is required. Pyfaro never installs uv or Python,
and it passes --no-python-downloads, so a compatible interpreter must
already be installed.
Project selection¶
init takes a positional path and uses that exact directory. It does
not search ancestor directories like sync or
run do, so creating a project stays deliberate. There is no
--project option. Relative paths and paths with spaces work, and symlinks
in the path are resolved.
What it writes, and what it never writes¶
Writes (with --apply only): pyproject.toml (new, or with the missing
[tool.pyfaro] table added) and uv.lock.
Never writes: a virtual environment, installed packages, dependency
upgrades, a Git repository, README, .python-version or source files. Your
dependencies, [tool.uv] sources and indexes, Ruff, ty and pytest settings
and the build system are preserved.
If uv fails or you press Ctrl+C, Pyfaro restores the previous bytes of
pyproject.toml and uv.lock (removing incomplete new ones) on every
platform. Pressing Ctrl+C also stops uv and everything it started, and the
command exits with 130. Pyfaro writes each file by creating a temporary file
next to it and renaming it over the original, so a file is never left half
written. Applying a project that is already initialized again changes nothing.
Do not run another tool that writes those files at the same time.
Line endings. A pyproject.toml with CRLF line endings keeps them: the
[tool.pyfaro] table is added with CRLF too. A file that mixes both endings
takes the more common one when Pyfaro has to change it.
Read-only files. On Linux and macOS a read-only pyproject.toml is
replaced and keeps its permissions. Windows cannot rename over a read-only
file, so there --apply stops before changing anything and asks you to clear
the read-only attribute of pyproject.toml or uv.lock. It does the same,
naming the file, when another program holds it open without allowing it to be
replaced; close that program and run the command again.
Errors you may hit¶
| Message | Fix |
|---|---|
expected a standard [project] table in pyproject.toml |
The project uses Poetry-only metadata. Migrate it to [project] first. |
tool.pyfaro.schema-version must be the integer 1 |
Fix or remove the unsupported [tool.pyfaro] value. Unknown keys are rejected too. |
could not find uv … |
Install uv (>= 0.9.26) as the message says, or pass --uv <path>. |
uv's own error, then uv … failed |
Read uv's output above. Dynamic or source dependencies that need a build can fail with --no-build. |
… is read-only; clear its read-only attribute and rerun init |
Windows only. Make pyproject.toml or uv.lock writable, or change them by hand. |
cannot replace …: it is read-only or another program has it open |
Windows only. Close the editor, antivirus scan or tool that holds the file, then rerun. |
uv workspaces, and projects below a workspace root, are rejected before
anything is modified. Symlinked pyproject.toml or uv.lock files are
rejected too.
Exit codes¶
| Code | Meaning |
|---|---|
0 |
The preview was shown, or the project was initialized. |
1 |
A Pyfaro configuration or filesystem error, including a missing uv. |
2 |
A usage error, or a failing uv exit code of 2 (forwarded as is). |
| other | uv's numeric failure status is forwarded. |
130 |
Cancelled. The process tree was stopped first. |
See also¶
pyfaro sync: create the environment from the new lock.pyfaro create: generate a brand-new project instead.pyfaro doctor: check the setup.