Exploring uv#
Why can't I find a complete Chinese document or tutorial about uv?
Is the power of pip too strong? No, it should just be people's fear of accepting the unknown.
I'm recording my exploration process and route, so it will be super messy.
What is uv?#
You cut open the surface of a cube along a line and unfold all the faces, which gives you uv mapping. You can use uv mapping to apply textures to models.
...
Phew, the uv we are talking about here is a package manager.
This is a comparison of the installation speed between uv and pip.
Here we will explore some basic usages of uv, replacing several methods of pip. We will also try to compile my first Python package later (as long as it can be installed and run from GitHub).
Uh, additionally, you might feel uncomfortable with my recording style or find it hard to read; I understand, because I wrote it according to my exploration route, experimenting wherever I thought of something and then writing it down. This is also the whole idea of my learning process.
I may organize a usage guide later.
Reference:#
- Package Management Tool UV User Guide: A Comprehensive Alternative to conda
- UV Official Documentation
uv.lock + pyproject.toml vs requirements.txt#
uv.lock is generated after manually running uv lock
, based on pyproject.toml
, and generally should not be manually modified:
uv.lock is a human-readable TOML file but is managed by uv and should not be edited manually.
uv.lock 是一个人类可读的 TOML 文件,但由 uv 管理,不应手动编辑。
At first, I thought uv.lock could replace the Python dependency configuration in pyproject.toml, but later found it enhanced it.
Using uv add package
-> uv lock
-> uv run
/ uv sync
-> uv run
:
You can quickly modify dependency
and verify compatibility.
It also supports directly installing third-party libraries from GitHub repositories, making package dependency handling very precise.
During the process, updating uv.lock is also done by first updating pyproject.toml
and then uv lock
.
Moreover, uv.lock gives a strong sense of security; if you specifically look at the contents of uv.lock, it precisely indicates where the source was installed from. In contrast, requirements.txt is very sloppy.
Unlike the pyproject.toml, which is used to specify the broad requirements of your project, the lockfile contains the exact resolved versions that are installed in the project environment. This file should be checked into version control, allowing for consistent and reproducible installations across machines.
与用于指定项目总体要求的 pyproject.toml 文件不同,lockfile 文件包含项目环境中安装的精确解析版本。该文件应检查到版本控制中,以便在不同机器上进行一致和可重复的安装。
For the pyproject.toml
+ uv.lock
format, the human-readable part is pyproject.toml
, while uv.lock
is for machine reading. In contrast, the requirements generated by pip freeze
are unreadable for humans and troublesome for machines.
If you use uv add
, each package version and library is built and determined bit by bit, rather than being directly frozen.
The pyproject.toml will list the necessary packages and their versions, while dependency packages will be downloaded automatically. It is also recommended to only add necessary packages rather than dependency packages when using uv add
.
The requirements.txt
generated by pip freeze
is all dependency packages, which are not meant for human reading.
Sometimes I consider writing dependency packages by hand, but writing requirements.txt is quite a test of patience.
When I'm feeling lazy:
The requirements.txt I provide looks like this:
pyaml
gradio
And you must recreate a clean environment and then run pip install -r requirements.txt
to verify if it is complete.
Compared to uv add
-> uv lock
-> uv run script
, all dependencies can be quickly confirmed for compatibility with the environment. Because uv run
only runs based on uv.lock
.
And if I use the handwritten requirements.txt above (without version annotations), I am sure my users will discover on some day three months later that certain APIs seem to be deprecated or the latest versions are incompatible with each other?
On Windows, it will download the latest versions of pyaml and gradio. If I haven't updated in a long time, there is a high probability of issues.
On Linux, it gets even more ridiculous; it will download all versions of pyaml and gradio. I am not sure if it's a bug, but it downloaded at least 5 versions of gradio, and I am not sure which ones were finally installed.
By chance, I decided to get started with uv, and this decision from its official documentation forced me to overcome my previous psychological shadow, which was asking GPT and not understanding anything, leading to being misled for many days.
It made me use uv pip install uv.lock
..... I really...
However, before starting, I still need to familiarize myself with uv, as I can't find a complete Chinese document for this thing. Is the power of pip too strong? No, it should just be people's fear of the unknown. I wanted to understand it a long time ago, but it has been delayed until now, still by chance.
Installing uv and Final Recommendations.#
https://docs.astral.sh/uv/getting-started/installation/
My final recommendation is to globally install uv + use pyproject.toml + uv.lock to manage projects (Python lib).
For specific references:
https://github.com/yutto-dev/yutto
https://github.com/MrXnneHang/yutto-uiya
Or for convenience, you can simply use uv + conda to replace pip + conda for faster installation. The usage is to replace all:
pip install
-> uv pip install
.
Starting from uv run: Where are the executable files for uv run python/yutto/...?#
If we don't consider the global approach mentioned in that personal blog, the normal uv environment is located under the .venv
in the project root directory.
Writing uv run
is equivalent to accessing the executable files in our virtual environment directly using python/yutto, just like before in conda.
Python is generally located under .venv/bin
.
Independently using uv to create a venv.#
It is worth mentioning that when installing miniconda on Linux, we are prompted to choose whether to enable auto_activate_base
, which means whether to automatically activate the base environment every time we enter the terminal. When we try to use uv independently, we should consider disabling this option first:
Otherwise, you will find that the created venv is the Python version of the current virtual environment.
conda config --set auto_activate_base false
Then open a new terminal, and the base environment will not be activated automatically.
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv venv
Using CPython 3.13.0
Creating virtual environment at: .venv
Activate with: source .venv/bin/activate
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ ls .venv/
bin CACHEDIR.TAG lib lib64 pyvenv.cfg
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ ls .venv/bin/
activate activate.csh activate.nu activate_this.py pydoc.bat python3
activate.bat activate.fish activate.ps1 deactivate.bat python python3.13
It seems to have directly created a Python base environment of version 3.13.
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv run python tmp.py
Hello UV!
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv run tmp.py
Hello UV!
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv run python
Python 3.13.0 (main, Oct 16 2024, 03:23:02) [Clang 18.1.8 ] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
It seems to be working normally.
Moreover, the speed of creating the environment is surprisingly fast? Half a second?
This seems to be the reason:
If Python is already installed on your system, uv will detect and use it without configuration. However, uv can also install and manage Python versions. uv automatically installs missing Python versions as needed — you don't need to install Python to get started.
如果系统中已经安装了 Python,uv 将检测并使用它,而无需配置。uv 会根据需要自动安装缺失的 Python 版本,因此无需安装 Python 即可开始使用。
See: Install Python
We will also utilize this feature to directly obtain the required Python version from conda, as detailed in the next section.
How to install a specific version of Python?#
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv python install 3.12
Installed Python 3.12.9 in 53.73s
+ cpython-3.12.9-linux-x86_64-gnu
This installed it again. Based on the above, it can be inferred that my system does not have Python version 3.12.
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv run python
Python 3.13.0 (main, Oct 16 2024, 03:23:02) [Clang 18.1.8 ] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv run python3.12
Python 3.12.4 (main, Jul 9 2024, 09:31:23) [GCC 13.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv run python3.11
error: Failed to spawn: `python3.11`
Caused by: No such file or directory (os error 2)
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ ls .venv/bin/
activate activate.csh activate.nu activate_this.py pydoc.bat python3
activate.bat activate.fish activate.ps1 deactivate.bat python python3.13
As you can see, it seems that installing 3.12 is not done under .venv
. When I deleted .venv
and ran uv run python3.12
again, it still worked. This indicates that it is installed globally.
This actually poses some scary risks; global Python always has some loopholes. For example, I can use uv run python -m pip install matplotlib
. I can directly pollute the global environment.
Therefore, I personally think a more feasible approach is to use conda to manage these 3.10, 3.11, and 3.12 environments. When needed, we can copy the environment from conda to ./venv. Later, all our environment changes will target ./venv.
Specifying the Python version for venv:#
Because compared to the system-wide Python, conda's virtual environments are safer and easier to manage. We can even customize different starting packages, such as starting with selenium and web driver for web scraping, or starting with numpy and matplotlib for data analysis. Then when needed, copy them into .venv for the base environment.
My latter thought is wrong because uv venv
only inherits Python and does not inherit packages. So this idea is not feasible. The next content will prove this point.
On this point, I agree with that author:
conda activate 11
uv venv --seed -p 3.11
conda deactivate
uv pip install -r requirements.txt
source ./.venv/bin/activate
python main.py
Parameter explanation:
-p, --python <PYTHON>
The Python interpreter to use for the virtual environment. [env: UV_PYTHON=]
--seed
Install seed packages (one or more of: `pip`, `setuptools`, and `wheel`) into the virtual
environment [env: UV_VENV_SEED=]
I found that the expected copying
did not happen; it may not be copying the environment but just inheriting Python.
It utilizes a point that when uv venv
runs, it defaults to detecting the system's preferred Python as the Python for the venv. When we conda activate 11
, the default python XXX
we run is the conda Python. So, uv venv
will inherit this Python.
As for whether it will inherit packages, let's test it.
Testing whether venv creation will inherit the virtual environment's packages#
To conclude, it will not; it can only inherit Python.
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ conda activate numpy
(numpy) xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ python
Python 3.10.16 (main, Dec 11 2024, 16:24:50) [GCC 11.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> exit()
(numpy) xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ conda deactivate
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ conda activate numpy
(numpy) xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ python
Python 3.10.16 (main, Dec 11 2024, 16:24:50) [GCC 11.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> numpy.__version__
'2.2.2'
>>> exit()
(numpy) xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv venv -p 3.10 --seed
Using CPython 3.10.16 interpreter at: /home/xnne/miniconda3/envs/numpy/bin/python3.10
Creating virtual environment with seed packages at: .venv
+ pip==25.0.1
+ setuptools==75.8.0
+ wheel==0.45.1
Activate with: source .venv/bin/activate
(numpy) xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ conda deactivate
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv run python
Python 3.10.16 (main, Dec 11 2024, 16:24:50) [GCC 11.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'numpy'
>>>
Using CPython 3.10.16 interpreter at: /home/xnne/miniconda3/envs/numpy/bin/python3.10
indicates that it indeed used the Python from our conda environment. However, it only used the Interpreter
.
The difference between uv run pip install
and uv pip install
:#
uv run pip install
vs pip install
:#
To conclude, uv run pip install
will install into .venv, and it has the same effect as uv run python -m pip install
.
Earlier, we speculated that doing this is almost no different from using pip install normally, except that when we use conda, using pip install in the virtual environment does not pollute the global environment. As mentioned earlier, when we activate the virtual environment, the priority of the virtual environment is higher than the system environment, so pip install will install in the virtual environment.
Our uv only creates a local .venv.
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv run python
Python 3.10.16 (main, Dec 11 2024, 16:24:50) [GCC 11.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'numpy'
>>> exit()
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv run pip install numpy
Collecting numpy
Using cached numpy-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (62 kB)
Using cached numpy-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (16.4 MB)
Installing collected packages: numpy
Successfully installed numpy-2.2.3
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv run python
Python 3.10.16 (main, Dec 11 2024, 16:24:50) [GCC 11.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> numpy.__version__
'2.2.3'
>>>
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ ls .venv/lib/python3.10/site-packages/
_distutils_hack numpy.libs __pycache__ _virtualenv.py
distutils-precedence.pth pip setuptools wheel
numpy pip-25.0.1.dist-info setuptools-75.8.0.dist-info wheel-0.45.1.dist-info
numpy-2.2.3.dist-info pkg_resources _virtualenv.pth
When we directly run pip install
, we find that my system environment actually does not have pip
=-=/.
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ pip uninstall numpy
bash: pip: command not found
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ pip install numpy
bash: pip: command not found
This indicates that uv does not directly isolate us from the system environment like conda does; instead, it creates a local .venv in the current directory, and all uv run XXX
operations are performed in this .venv.
uv pip install
vs uv run pip install
:#
To conclude, both operate on the environment under .venv
.
However, uv run pip install
uses pip to install the environment, while uv pip install
uses uv to install the environment.
Let's take a quick look at the speed comparison:
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ time uv run pip install numpy
Collecting numpy
Using cached numpy-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (62 kB)
Using cached numpy-2.2.3-cp310-cp310-manylinux_2_17_x86_64.whl (16.4 MB)
Installing collected packages: numpy
Successfully installed numpy-2.2.3
real 0m3.090s
user 0m1.770s
sys 0m0.163s
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv pip uninstall numpy
Uninstalled 1 package in 55ms
- numpy==2.2.3
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ time uv pip install numpy
Resolved 1 package in 16ms
Installed 1 package in 31ms
+ numpy==2.2.3
real 0m0.064s
user 0m0.007s
sys 0m0.054s
Wow, the speed is not on the same level.
This means that we should use uv pip install
more often when installing environments.
A brief summary of how to use uv to replace pip's work.
#
If you are using miniconda and just want to use uv to speed up package installation, then after creating the environment each time:
pip install uv
uv pip install -r requirements.txt/packagename
This should be the simplest.
If you, like me, have a habit of packaging environments in the project root directory, you can try:
conda activate 10
uv venv --seed -p 3.10
conda deactivate
uv pip install -r requirements.txt/packagename
This uv needs to be installed globally. Refer to the links above.
Also, when uv cannot install a certain package, we need to revert to using pip, which is also the reason I spent a lot of time discussing uv pip
and uv run pip
.
For example:
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv run __main__.py
Traceback (most recent call last):
File "/home/xnne/code/yutto-uiya/src/uiya/__main__.py", line 3, in <module>
import gradio as gr
File "/home/xnne/code/yutto-uiya/src/uiya/.venv/lib/python3.10/site-packages/gradio/__init__.py", line 3, in <module>
import gradio._simple_templates
File "/home/xnne/code/yutto-uiya/src/uiya/.venv/lib/python3.10/site-packages/gradio/_simple_templates/__init__.py", line 1, in <module>
from .simpledropdown import SimpleDropdown
File "/home/xnne/code/yutto-uiya/src/uiya/.venv/lib/python3.10/site-packages/gradio/_simple_templates/simpledropdown.py", line 7, in <module>
from gradio.components.base import Component, FormComponent
File "/home/xnne/code/yutto-uiya/src/uiya/.venv/lib/python3.10/site-packages/gradio/components/__init__.py", line 1, in <module>
from gradio.components.annotated_image import AnnotatedImage
File "/home/xnne/code/yutto-uiya/src/uiya/.venv/lib/python3.10/site-packages/gradio/components/annotated_image.py", line 14, in <module>
from gradio import processing_utils, utils
File "/home/xnne/code/yutto-uiya/src/uiya/.venv/lib/python3.10/site-packages/gradio/processing_utils.py", line 120, in <module>
sync_client = httpx.Client(transport=sync_transport)
File "/home/xnne/code/yutto-uiya/src/uiya/.venv/lib/python3.10/site-packages/httpx/_client.py", line 697, in __init__
self._mounts: dict[URLPattern, BaseTransport | None] = {
File "/home/xnne/code/yutto-uiya/src/uiya/.venv/lib/python3.10/site-packages/httpx/_client.py", line 700, in <dictcomp>
else self._init_proxy_transport(
File "/home/xnne/code/yutto-uiya/src/uiya/.venv/lib/python3.10/site-packages/httpx/_transports/default.py", line 191, in __init__
raise ImportError(
ImportError: Using SOCKS proxy, but the 'socksio' package is not installed. Make sure to install httpx using `pip install httpx[socks]`.
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv pip install https[socks]
× No solution found when resolving dependencies:
╰─▶ Because there are no versions of https[socks] and you require https[socks], we can conclude that your requirements are unsatisfiable.
I cannot use uv pip install
to install httpx[socks]
, so I have to revert to uv run pip install
.
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv run pip install httpx[socks]
Requirement already satisfied: httpx[socks] in ./.venv/lib/python3.10/site-packages (0.28.1)
Requirement already satisfied: anyio in ./.venv/lib/python3.10/site-packages (from httpx[socks]) (4.8.0)
Requirement already satisfied: certifi in ./.venv/lib/python3.10/site-packages (from httpx[socks]) (2025.1.31)
Requirement already satisfied: httpcore==1.* in ./.venv/lib/python3.10/site-packages (from httpx[socks]) (1.0.7)
Requirement already satisfied: idna in ./.venv/lib/python3.10/site-packages (from httpx[socks]) (3.10)
Collecting socksio==1.* (from httpx[socks])
Using cached socksio-1.0.0-py3-none-any.whl.metadata (6.1 kB)
Requirement already satisfied: h11<0.15,>=0.13 in ./.venv/lib/python3.10/site-packages (from httpcore==1.*->httpx[socks]) (0.14.0)
Requirement already satisfied: exceptiongroup>=1.0.2 in ./.venv/lib/python3.10/site-packages (from anyio->httpx[socks]) (1.2.2)
Requirement already satisfied: sniffio>=1.1 in ./.venv/lib/python3.10/site-packages (from anyio->httpx[socks]) (1.3.1)
Requirement already satisfied: typing_extensions>=4.5 in ./.venv/lib/python3.10/site-packages (from anyio->httpx[socks]) (4.12.2)
Using cached socksio-1.0.0-py3-none-any.whl (12 kB)
Installing collected packages: socksio
Successfully installed socksio-1.0.0
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv run __main__.py
* Running on local URL: http://127.0.0.1:7860
To create a public link, set `share=True` in `launch()`.
solve.
uv lock, locking the environment.#
To run this, we first need a pyproject.toml
.
This is a simple configuration for Python + ruff: https://github.com/MrXnneHang/yutto-uiya/blob/gradio-webui/pyproject.toml
Then you run:
xnne@xnne-PC:~/code/yutto-uiya/src/uiya$ uv lock
Using CPython 3.13.0
Resolved 1 package in 4ms
You will find that it seems no packages are locked; if your pyproject.toml
does not provide:
[dependency-groups]
# dev = [
# "pyaml>=25.1.0",
# "gradio>=5.16.1",
# ]
However, if you need to manually write pyproject.toml
, it seems too tedious; can we directly extract it from .venv?
Late exporting is not a good habit. Just like pip freeze has significant limitations at the end of export, exporting many dependencies makes the dependencies unreadable.
You should gradually explore the specific third-party libraries you need and their versions. As for dependency libraries, you don't need to write them.
Finally, you write them in pyproject.toml, and then use uv lock, uv sync (optional), and uv run to confirm that they are runnable and compatible.
Possible issues after locking the environment. | Changes in the .venv directory | Different package names#
For example, if my __main__.py
and requirements.txt are not in the root directory. The .venv
I initially created is located in ./src/uiya
(relative to the root directory).
However, uv.lock
requires pyproject.toml
, and pyproject.toml
needs to be in the root directory. Then uv.lock will automatically search for pyproject.toml
in the parent folder and recreate a .venv
.
This means that my initial .venv
was located in ./src/uiya
, but now it has changed to ./
.
This initially caused me some confusion because I found that I could not use uv run
to access the .venv
in my subfolder, and as mentioned earlier, uv could not install httpx[socks]
for me, so I needed to install it manually.
Therefore, the best approach here is to create pyproject.toml
from the beginning. Then uv run
and uv pip install
will target the .venv
in the same directory as pyproject.toml
.
Here is a simple configuration:
name = "yutto-uiya"
version = "1.0.2"
description = ""
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"gradio==5.16.1",
"pyaml==25.1.0",
"socksio==1.0.0",
"yutto",
]
authors = [{ name = "MrXnneHang", email = "[email protected]" }]
keywords = []
license = { text = "MIT" }
classifiers = [
"Operating System :: OS Independent",
"License :: OSI Approved :: MIT License",
"Typing :: Typed",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: Implementation :: CPython",
]
[project.urls]
Homepage = "https://github.com/MrXnneHang/yutto-uiya"
Documentation = "https://github.com/MrXnneHang/yutto-uiya"
Repository = "https://github.com/MrXnneHang/yutto-uiya"
Issues = "https://github.com/MrXnneHang/yutto-uiya/issues"
[project.scripts]
uiya = "uiya.__main__:main"
[tool.uv.workspace]
members = ["packages/*"]
[tool.uv.sources]
yutto = { git = "https://github.com/MrXnneHang/yutto.git", rev = "depndency-adjust" }
[tool.pyright]
include = ["src/uiya", "tests"]
pythonVersion = "3.10"
typeCheckingMode = "strict"
[tool.hatch.build.targets.wheel]
packages = ["src/uiya"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
It is worth noting that dependencies and sources do not need to be written manually.
These can be added using uv add gradio==5.16.1
.
It also supports GitHub repositories, such as:
uv add git+https://github.com/MrXnneHang/yutto.git@depndency-adjust
Thus, uv is actually recommended to be used in conjunction with pyproject.toml
if you want to manage package versions, as uv lock
can only run if pyproject.toml
exists.
Additionally, while most dependencies can be directly migrated from requirements, attention should be paid to cases where package names differ, such as socksio
being named httpx[socks]
in pip.
However, once your pyproject.toml
and uv.lock
are ready, others only need to run uv run script
.
Moreover, locked versions can prevent others from worrying about compatibility issues with environment versions, making it friendly for everyone.
When you need to update uv.lock
, you need to first uv add packagename==version
, and then uv lock
.
I recommend not leaving any room for version flexibility. Furthermore, after uv lock
, you don't need to run uv pip install
to manually install packages; you can directly run uv run script
, and it will automatically configure packages based on uv.lock
. As long as you can run it this way, others can too. Of course, some cross-system issues with Windows and Linux using win32api do not count.
To be cross-system friendly, you should avoid using low-level APIs that depend on the system.
At this point, uv is basically about to graduate. Why am I suddenly so confident? Because I have gone through practical experience, organizing a previously chaotic project structure into a form that can be directly installed from GitHub.
https://github.com/MrXnneHang/yutto-uiya
The key lies in pyproject.toml
and uv.lock
. Among them, uv.lock is automatically generated based on pyproject.toml.
In fact, hands-on experience is much faster than just reading. Moreover, understanding will suddenly deepen because you will encounter various problems. The process of copying homework is painful, but once completed, it feels very comfortable.
By the way, I copied from:
https://github.com/yutto-dev/yutto
uv Running Scripts.#
Executable Files#
As mentioned earlier, you can use uv run pip
, uv run python
, etc., to run the contents under bin
.
I won't elaborate on this further.
Python Scripts.#
Here I will divide it into two situations: with pyproject.toml
and without pyproject.toml
.
With pyproject.toml
+ uv.lock
#
When running this, it actually runs based on the contents of uv.lock
, which will automatically create a .venv
in the same directory as uv.lock
, then configure the environment in this .venv
and run it.
So, the general pattern is:
Run the script:
git clone XXX
uv run XXX
You don't have to worry about anything; if it doesn't run, it's definitely not my problem, it's definitely the maintainer's issue.
If it's the maintainer, it generally goes like this:
uv add package==version
uv lock
uv run XXX # If successful, then upload; otherwise, consider adjusting the package version
After debugging successfully, if you are a good person, you will choose to upload uv.lock
together and tell your users that they can directly run uv run XXX
.
Because most people really don't know how to use uv. They will search for requirements.txt for a long time, not finding it, and then spend a long time trying uv pip install uv.lock
...
Then they can't figure out the difference between uv run pip
and uv pip
. I used to be like that, and I even had a psychological shadow.
Without pyproject.toml
+ uv.lock
#
This is more similar to directly replacing pip with uv pip
for acceleration.
Actually, I currently recommend using pyproject.toml
+ uv.lock
for management.
However, you can still use requirements.txt
.
In this case, there is no need to consider .venv
; just install uv and the environment in conda.
Principle: If you activate the conda environment, then uv pip install
, etc., will also default to installing in the conda environment.
Of course, if you really need an independent .venv
, you can also consider this approach:
conda activate 11 # Base environment of Python 3.11
uv venv --seed -p 3.11
conda deactivate # As mentioned earlier, you must exit the environment; otherwise, it will install in conda.
uv pip install -r requirements.txt
In this case, your .venv
will be independent. However, it has a limitation; it seems you can only create it in the current directory and access it there? If you run uv run XXX
.
It does not behave like the case with pyproject.toml
+ uv.lock
, where even if .venv
is in the root directory, you can access it from anywhere in the project directory.
So I personally only recommend the pyproject.toml
+ uv.lock
model and the conda + uv
replacing conda + pip
model.
After I package the project, how to repeatedly compile?#
Initially, the way I ran was:
uv run __main__.py
This is suitable for the development phase, for repeated debugging.
Later, I entered the compilation debugging phase, meaning I wanted to run my executable file directly. Here is uiya
.
My approach was quite silly; I uploaded it to GitHub and then used:
conda create -n test-uiya python=3.10
conda activate test-uiya
uv pip install git+https://github.com/MrXnneHang/yutto-uiya.git@gradio-webui
Then every time I updated the code, I would reinstall it with uv pip install
. Fortunately, it would detect the latest branch and wouldn't be affected by the cache, so there was no need to uninstall.
It indeed succeeded, and I was very excited when I first installed it successfully and got it running.
However, this method later made me very tired.
Because every time I needed to upload the code to GitHub first, then reinstall it. This process was very cumbersome.
I hoped to update automatically with one line of code.
Here we need to mention local compilation and updates. The above method I will call remote compilation =-=.
Local compilation to generate executable programs.#
Um, how should I say it?
It seems that no commands are needed.
The omnipotent uv run
.
You just need to run uv run uiya
.
It will run based on your latest code because at this point, it should actually be in an uncompiled state, and you configured uiya = "uiya.__main__:main"
in pyproject.toml
, so it will automatically run your __main__.py
.
And it seems there is no need to compile specifically; just like Vue can preview in real-time, this efficiency will always be higher than compiling and then checking.
My initial confusion about uv sync#
I thought it would play a significant role in our package management, but it seems that it can be done without it?
The translation of sync
is synchronization, which synchronizes the environment.
Perhaps it synchronizes after uv lock
? But I remember that uv run
seems to check the contents of uv.lock
every time.
Let's look at a use case:
If you want to debug locally, the best practice is to download the latest source code from GitHub to run
git clone [email protected]:yutto-dev/yutto.git
cd yutto/
uv sync
uv run yutto -v
https://github.com/yutto-dev/yutto/blob/main/CONTRIBUTING.md
It can be inferred that this sync is used to install the environment, but now it seems you can directly uv run yutto
.
This means that uv sync
should have been integrated into the steps of uv run
, so we do not need to manually run uv sync
.
Of course, if you occasionally encounter strange environment issues, you can use uv sync
to check what's going on.
According to our previous experiments, the .venv
generated by uv run
is in the same directory as pyproject.toml
and uv.lock
.
Let's test uv sync
:
xnne@xnne-PC:~$ git clone [email protected]:MrXnneHang/yutto-uiya.git
Cloning into 'yutto-uiya'...
remote: Enumerating objects: 898, done.
remote: Counting objects: 100% (57/57), done.
remote: Compressing objects: 100% (39/39), done.
remote: Total 898 (delta 23), reused 36 (delta 12), pack-reused 841 (from 1)
Receiving objects: 100% (898/898), 389.53 KiB | 429.00 KiB/s, done.
Processing deltas: 100% (512/512), done.
xnne@xnne-PC:~$ cd yutto-uiya/
xnne@xnne-PC:~/yutto-uiya$ uv sync
Using CPython 3.13.0
Creating virtual environment at: .venv
Resolved 64 packages in 2ms
Built yutto-uiya @ file:///home/xnne/yutto-uiya
Prepared 1 package in 1.49s
xnne@xnne-PC:~/yutto-uiya$ ls .venv/
bin/ CACHEDIR.TAG .gitignore lib/ lib64/ pyvenv.cfg
Here we see that it is indeed installing the environment and placing it under the root directory's .venv
.
The inference is correct.
However, there is a strange point regarding the Python version; it will default to finding the source with the highest priority. If you want to control the Python version, you can refer to the previous method of activating conda and then exiting.
(10) xnne@xnne-PC:~/yutto-uiya$ uv sync -p 3.10
Using CPython 3.10.16
Of course, it seems unnecessary to use conda because uv has its own global interpreter, and if the specified version is missing, it will automatically download it. However, the location is quite strange.
If there are issues with the environment, consider deleting .venv
and then running uv sync
again. If it still doesn't work, then go find the maintainer =-=.
Congratulations, uv graduates.
This seems long and absurd, but I wrote it in two days. Most of it is nonsense.
If I have time, I might organize a version of the usage, but I have always focused on exploration rather than organization.
So... let's see how it goes.