Skip to content

Commit f9f0693

Browse files
authored
Merge pull request #90 from berkeleybop/uv-migration
replace poetry with uv in best practices doc
2 parents b39b213 + 185a98d commit f9f0693

2 files changed

Lines changed: 174 additions & 92 deletions

File tree

best_practice/index.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -424,9 +424,9 @@ If there is anything you don't understand, **ask on slack**!
424424
- Follow conventional variable naming
425425
- Example: https://docs.fast.ai/dev/abbr.html
426426
- See the [Working with Python Environments](/best_practice/python_environments) guide for details on installing Python versions and managing virtual environments.
427-
- All repos should use [poetry](https://python-poetry.org/)
428-
- Set up this way: `poetry new --src my-project-name`
429-
- OR use `linkml-ws new` for schema-centric repos
427+
- All repos should use [uv](https://github.com/astral-sh/uv)
428+
- Set up this way: `uv init --package my-project-name`
429+
- OR use [`linkml-project-copier`](https://github.com/linkml/linkml-project-copier) for schema-centric repos
430430
- follow standard layouts, with code in `src/`
431431
- Linting/formatting:
432432
- Use [black](https://github.com/psf/black) and [flake8](https://pypi.org/project/flake8/) and ruff

best_practice/python_environments.md

Lines changed: 171 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -4,207 +4,289 @@ published: true
44
title: Working with Python Environments
55
---
66

7-
## Managing Python Versions
7+
## Managing Python Versions and Virtual Environments with uv
88

9-
Most projects we work on require Python 3.8 or greater. A few projects may require an even later version. In either case it is necessary to be able to have multiple versions of Python installed and easily switch between them. Both can be accomplished using [pyenv](https://github.com/pyenv/pyenv).
9+
Most projects we work on require Python 3.9 or greater. Many require a later version. In either case it is necessary to be able to have multiple versions of Python installed and easily switch between them, as well as manage project-specific dependencies. We use [uv](https://github.com/astral-sh/uv) to handle both Python version management and virtual environments.
1010

11-
### Installing pyenv
11+
### Installing uv
1212

13-
Use one of the [recommended installation methods](https://github.com/pyenv/pyenv#installation). If you are using Windows use the [pyenv-win fork](https://github.com/pyenv-win/pyenv-win/blob/master/docs/installation.md).
13+
Follow [uv's recommended installation methods](https://github.com/astral-sh/uv#installation). The quickest way is usually:
14+
15+
```shell
16+
curl -LsSf https://astral.sh/uv/install.sh | sh
17+
```
18+
19+
Or on macOS with Homebrew:
20+
21+
```shell
22+
brew install uv
23+
```
1424

1525
To verify that the installation was successful run the following and ensure that it prints out a version number:
1626

1727
```shell
18-
pyenv --version
28+
uv --version
1929
```
2030

2131
### Installing Python Versions
2232

23-
Running the `pyenv versions` command will list the versions of Python that pyenv knows about. If you just installed pyenv the output should say that either no Python version are installed:
33+
uv can install and manage Python versions directly. To see available Python versions:
34+
35+
```shell
36+
uv python list --all-versions
37+
```
38+
39+
To install a specific Python version:
2440

2541
```shell
26-
$ pyenv versions
27-
Warning: no Python detected on the system
42+
uv python install 3.11
2843
```
2944

30-
Or that a system version (not managed by pyenv) is installed and active (denoted by the asterisk):
45+
Or install the latest patch version of a minor release:
3146

3247
```shell
33-
$ pyenv versions
34-
* system (set by [...]/.pyenv/version)
48+
uv python install 3.11 # Installs latest 3.11.x
3549
```
3650

37-
Use the `pyenv install` command to install new versions of Python that will be managed by pyenv. For example to install a Python 3.8 version[^1]:
51+
To see which Python versions are currently installed:
3852

3953
```shell
40-
pyenv install 3.8.15
54+
uv python list
4155
```
4256

43-
This can be repeated for any other versions you would like to install. The `pyenv install --list` command will show all the versions available for installation.
57+
### Selecting a Python Version for Your Project
4458

45-
Once you have a few Python versions installed by pyenv, verify they are listed in the output of `pyenv versions`:
59+
When creating a new project, you can specify which Python version to use:
4660

4761
```shell
48-
pyenv versions
49-
* system (set by [...]/.pyenv/version)
50-
3.8.15
51-
3.9.15
52-
3.10.8
62+
uv init --python 3.11 my-project
63+
cd my-project
5364
```
5465

55-
### Selecting a Python Version
66+
For existing projects, uv will use the Python version specified in the `pyproject.toml` file's `requires-python` field. You can also specify a Python version when syncing:
5667

57-
pyenv allows setting a Python version at three levels: global, local, and shell[^2]. When getting set up for the first time, the most important version to set is the global version. Depending on the projects you work on, you may never use local or shell versions at all.
68+
```shell
69+
uv sync --python 3.11
70+
```
5871

59-
To set the global Python version use the `pyenv global <version>` command. For example:
72+
Or pin a specific Python version for your project:
6073

6174
```shell
62-
pyenv global 3.8.15
75+
uv python pin 3.11
6376
```
6477

65-
Verify that this version is now the default Python version by running:
78+
This creates a `.python-version` file in your project directory that uv will respect.
79+
80+
## Managing Virtual Environments
81+
82+
uv automatically creates and manages virtual environments for your projects. By default, it creates them in a `.venv` directory within your project folder.
83+
84+
### Creating Virtual Environments
85+
86+
For a new project:
6687

6788
```shell
68-
$ python --version
69-
Python 3.8.15
89+
uv init my-project
90+
cd my-project
91+
uv sync
7092
```
7193

72-
The selected version can also be verified with the `pyenv versions`. The asterisk indicates the currently selected Python version:
94+
You can also create a project with a specific structure:
7395

7496
```shell
75-
$ pyenv versions
76-
system
77-
* 3.8.15 (set by [...]/.pyenv/version)
78-
3.9.15
79-
3.10.8
97+
uv init --package my-project # Creates a package structure
98+
uv init --app my-project # Creates an application structure
8099
```
81100

82-
## Managing Virtual Environments
101+
For an existing project with a `pyproject.toml` file:
83102

84-
Dependencies for different projects need to managed independently in what Python calls virtual environments. Generally each project will have one virtual environment and we use [Poetry](https://python-poetry.org/docs/) to manage those environments.
103+
```shell
104+
uv sync
105+
```
85106

86-
### Installing Poetry
107+
This will:
108+
- Create a virtual environment in `.venv`
109+
- Install the Python version specified in `pyproject.toml`
110+
- Install all project dependencies
87111

88-
First you should have at least one Python 3.7+ version installed and set as the global version through pyenv. Then follow [Poetry's recommended installation methods](https://python-poetry.org/docs/#installation).
112+
### Adding Dependencies
89113

90-
To verify that the installation was successful run the following and ensure that it prints out a version number:
114+
Use `uv add` to add new dependencies to your project:
91115

92116
```shell
93-
poetry --version
117+
uv add requests
94118
```
95119

96-
### Configuring Poetry
120+
This updates your `pyproject.toml` and `uv.lock` files and installs the package.
97121

98-
By default Poetry creates virtual environments in one central location. However, we find it more convenient to have the virtual environment created within the project directory itself (specifically in a directory called `.venv`). This behavior can be enabled by running:
122+
For development dependencies:
99123

100124
```shell
101-
poetry config virtualenvs.in-project true
125+
uv add --dev pytest black mypy
102126
```
103127

104-
By default Poetry has its own mechanism for locating (but **not** installing) different Python versions[^3]. This can cause some confusion when used alongside pyenv. Instead of having Poetry attempt to find the right Python version when creating a virtual environment, we want to use pyenv to activate an appropriate version and then use that version to create the virtual environment[^4]. To allow that to work set the following option:
128+
For optional dependency groups:
105129

106130
```shell
107-
poetry config virtualenvs.prefer-active-python true
131+
uv add --group docs sphinx sphinx-rtd-theme
108132
```
109133

110-
### Creating Virtual Environments
134+
### Updating Dependencies
111135

112-
If you start working on an existing project that already uses Poetry (i.e. it has a `pyproject.toml` and `poetry.lock` file in the root of the project), first ensure that you have a compatible Python version. You can find out which Python versions are acceptable for the project by looking at the `python` entry in the `tool.poetry.dependencies` section of the `pyproject.toml` file. If necessary install and/or activate a compatible Python version using pyenv as described above.
136+
Update a specific package:
113137

114-
Next create the virtual environment and install the projects dependencies into it by running:
138+
```shell
139+
uv add requests@latest
140+
```
141+
142+
Update to a specific version:
115143

116144
```shell
117-
poetry install
145+
uv add requests==2.31.0
118146
```
119147

120-
To start a new project that uses Poetry use either the `poetry new` or `poetry init` command. `poetry new` generates a simple project directory structure, including a `pyproject.toml` file, based on a name you provide. Using the `--src` option to create a `src` directory is recommended:
148+
Update all packages to their latest compatible versions:
121149

122150
```shell
123-
poetry new --src my-project
124-
cd my-project
125-
poetry install
151+
uv sync --upgrade
126152
```
127153

128-
`poetry init` will interactively prompt you to build a custom `pyproject.toml` file. It does not create any other files.
154+
Update only specific packages:
129155

130156
```shell
131-
mkdir my-project
132-
cd my-project
133-
poetry init
134-
poetry install
157+
uv sync --upgrade-package requests --upgrade-package urllib3
135158
```
136159

137-
### Adding New Dependencies
160+
### Inspecting Dependencies
138161

139-
Use `poetry add` to add a new dependency to a project.
162+
View the dependency tree:
140163

141164
```shell
142-
poetry add requests
165+
uv tree
143166
```
144167

145-
This will install the requests package into the project's virtual environment, add it to the `pyproject.toml` file, and update the `poetry.lock` file with information about the exact version installed.
168+
Show outdated packages:
146169

147-
In order to synchronize your poetry.lock file with any manual changes to pyproject.yaml directly, be sure to run:
148170
```shell
149-
poetry lock --no-update
171+
uv pip list --outdated
150172
```
151173

152-
### Updating Dependencies
174+
### Running Commands
153175

154-
The `poetry add` command can also be used to upgrade a package to a particular version (or range of versions):
176+
Run commands in the project's virtual environment:
155177

156178
```shell
157-
poetry add requests@^2.25.0
179+
uv run python src/main.py
180+
uv run pytest
181+
uv run black .
158182
```
159183

160-
Or automatically upgrade to the latest version:
184+
For interactive sessions, you can activate the virtual environment:
161185

162186
```shell
163-
poetry add requests@latest
187+
source .venv/bin/activate # On Unix/macOS
188+
# or
189+
.venv\Scripts\activate # On Windows
190+
191+
python src/main.py # Uses the virtual environment's Python
192+
deactivate # Exit the virtual environment
164193
```
165194

166-
To update a dependency to the latest version that still respects what is specified in `pyproject.toml` use the `poetry update` command:
195+
## Advanced Features
196+
197+
### Running Tools Without Installation
198+
199+
Run Python tools without installing them globally:
167200

168201
```shell
169-
poetry update requests
202+
uv tool run black .
203+
uv tool run --from ruff ruff check
204+
uv tool run --python 3.12 mypy src/
170205
```
171206

172-
If you need to debug a dependency tree, use the `poetry show` command:
207+
### Installing Global Tools
208+
209+
Install tools globally for command-line use:
173210

174211
```shell
175-
poetry show --tree my_package
212+
uv tool install black
213+
uv tool install ruff
176214
```
177215

178-
### Running Commands
216+
### Working with Scripts
179217

180-
Use the `poetry run` command to run commands in the project's virtual environment. For example to run an arbitrary Python module:
218+
Run Python scripts with inline dependencies:
181219

182220
```shell
183-
poetry run python src/main.py
221+
uv run --with pandas,matplotlib analysis.py
184222
```
185223

186-
Or if your project (or one of its dependencies) provides a CLI (e.g. pytest):
224+
Create self-contained scripts with dependency declarations:
225+
226+
```python
227+
# /// script
228+
# requires-python = ">=3.11"
229+
# dependencies = [
230+
# "requests",
231+
# "rich",
232+
# ]
233+
# ///
234+
235+
import requests
236+
from rich import print
237+
238+
response = requests.get("https://api.github.com")
239+
print(response.json())
240+
```
241+
242+
Then run it with:
187243

188244
```shell
189-
poetry run pytest
245+
uv run script.py
190246
```
191247

192-
For interactive sessions it may be more convenient to activate the virtual environment in which case `poetry run` will not be necessary. This can be accomplished by running:
248+
### Working with Requirements Files
249+
250+
Export dependencies to a requirements file:
193251

194252
```shell
195-
poetry shell
196-
python src/main.py # this will use the virtual environment's Python version
197-
exit # deactivate the virtual environment
253+
uv pip compile pyproject.toml -o requirements.txt
198254
```
199255

200-
## Further Reading
256+
Install from a requirements file:
201257

202-
* [Documentation on all pyenv subcommands](https://github.com/pyenv/pyenv/blob/master/COMMANDS.md#command-reference)
203-
* [Documentation on all poetry subcommands](https://python-poetry.org/docs/cli/)
258+
```shell
259+
uv pip sync requirements.txt
260+
```
261+
262+
## Migrating from Other Tools
263+
264+
### From pip/venv
265+
266+
If you have a `requirements.txt` file:
267+
268+
```shell
269+
uv init
270+
uv pip sync requirements.txt
271+
uv add --dev <your-dev-packages>
272+
```
204273

205-
## Footnotes
274+
### From Poetry
275+
276+
uv can read `pyproject.toml` files created by Poetry. Simply run:
277+
278+
```shell
279+
uv sync
280+
```
281+
282+
To fully migrate, you may want to:
283+
1. Remove the `[tool.poetry]` sections from `pyproject.toml`
284+
2. Delete `poetry.lock`
285+
3. Run `uv sync` to generate `uv.lock`
286+
287+
## Further Reading
206288

207-
[^1]: Use `pyenv latest --known <prefix>` to list latest version that matches `<prefix>`. For example: `pyenv latest --known 3.8`.
208-
[^2]: This guide mainly focuses on setting the global Python version. See the pyenv documentation for more information about setting [local](https://github.com/pyenv/pyenv/blob/master/COMMANDS.md#pyenv-local) and [shell](https://github.com/pyenv/pyenv/blob/master/COMMANDS.md#pyenv-shell) versions.
209-
[^3]: For more information see the `poetry env` [documentation](https://python-poetry.org/docs/managing-environments/), but it **not** recommended to use this feature in conjunction with pyenv.
210-
[^4]: If an incompatible Python version was active when you attempt to create a virtual environment via `poetry install` you will see a message like: `The currently activated Python version 3.8.15 is not supported by the project (^3.9.0).` Or, when attempting to run the Python executable: `Current Python version (3.8.15) is not allowed by the project (^3.9.0).` In this case, instead of using the `poetry env` command just delete the virtual environment (`rm -rf .venv`), ensure a compatible Python version is activated via pyenv (`pyenv global 3.9.15`), and recreate the virtual environment (`poetry install`)
289+
* [uv Documentation](https://docs.astral.sh/uv/)
290+
* [uv Python Discovery](https://docs.astral.sh/uv/guides/python/)
291+
* [uv Configuration](https://docs.astral.sh/uv/configuration/)
292+
* [Migrating to uv](https://docs.astral.sh/uv/guides/migration/)

0 commit comments

Comments
 (0)