当前位置: 首页 > article >正文

使用 uv 管理 Python 项目

介绍

首先, uv 工具是使用 rust 开发出来的, 速度要比传统的 pip, pipx 等一众包管理工具要快不少. 另外, 除了包管理之外, uv 还提供了脚手架的功能, 使用体验和前端开发使用过的 vue-cli 很相似, 可以帮助我们自动初始化项目, 创建好一个空的包含必要文件结构的文件夹. 此外, uv 可以同时管理多个不同 Python 版本, 方便快速切换使用. 当我们向项目中添加依赖时, 还会自动维护相关的包列表, 对于后续的打包和分发, 就相当友好. 更多功能和具体介绍参考官网文档:
https://docs.astral.sh/uv/

本文将在 WSL Ubuntu 环境中以一个简单的 Flask 项目作为示范, 使用 uv 对项目的整个生命周期进行管理.

安装 uv

可以使用官网提供的安装脚本, 对于已经安装了 Python 的环境, 可以直接用 pip install uv 安装. 需要留意, 对于 pip 方式安装, 需要确保系统环境变量 PATH 中包含了 pip 包安装后的 bin 文件夹路径. 否则直接直接执行 uv 命令时会出现找不到的情况.

# 检查已安装的 uv 版本
lpwm@Beijing:~/python-project$ uv --version
uv 0.5.9# 检查支持的所有 Python 版本
lpwm@Beijing:~/python-project$ uv python list
cpython-3.13.1+freethreaded-linux-x86_64-gnu    <download available>
cpython-3.13.1-linux-x86_64-gnu                 <download available>
cpython-3.12.8-linux-x86_64-gnu                 <download available>
cpython-3.12.3-linux-x86_64-gnu                 /usr/bin/python3.12
cpython-3.12.3-linux-x86_64-gnu                 /usr/bin/python3 -> python3.12
cpython-3.12.3-linux-x86_64-gnu                 /bin/python3.12
cpython-3.12.3-linux-x86_64-gnu                 /bin/python3 -> python3.12
cpython-3.11.11-linux-x86_64-gnu                /home/lpwm/.local/share/uv/python/cpython-3.11.11-linux-x86_64-gnu/bin/python3.11
cpython-3.10.16-linux-x86_64-gnu                /home/lpwm/.local/share/uv/python/cpython-3.10.16-linux-x86_64-gnu/bin/python3.10
cpython-3.9.21-linux-x86_64-gnu                 /home/lpwm/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/bin/python3.9
cpython-3.8.20-linux-x86_64-gnu                 <download available>
cpython-3.7.9-linux-x86_64-gnu                  <download available>
pypy-3.10.14-linux-x86_64-gnu                   <download available>
pypy-3.9.19-linux-x86_64-gnu                    <download available>
pypy-3.8.16-linux-x86_64-gnu                    <download available>
pypy-3.7.13-linux-x86_64-gnu                    <download available>

初始化新项目

这里特意使用一个当前系统中不存在的较老的 cpython-3.8.20 作为运行环境, 创建项目时指定 Python 版本 uv 会自动下载.

lpwm@Beijing:~/python-project$ uv init my-flask --python cpython-3.8.20
Initialized project `my-flask` at `/home/lpwm/python-project/my-flask`

会在当前路径中创建和项目同名的文件夹, 包含下面内容:

my-project/
├── .git
├── .gitignore
├── .python-version
├── README.md
├── hello.py
└── pyproject.toml

.python-version 记录了当前项目所使用的 Python 版本信息, 只定义到小数点后一位 3.8, 因为 Python 版本的小数点后第二位只用于安全补丁更新后递增, 支持语法特性上不会进行变动.

pyproject.toml 是项目的配置文件, 初始内容如下, 像描述性的属性可以随便修改, dependencies 部分实现的就是传统的 requirements.txt 功能, 可以手搓, 当然我们接着用 uv 的命令添加依赖, 会自动更新这一部分内容.

[project]
name = "my-flask"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.8"
dependencies = []

uv 文档上说的是它会使用系统中存在的 .pip 配置文件获取 index-url 镜像地址的配置, 但是实际体验下来, 好像有些命令不太灵, 所以稳妥的办法还是将镜像地址写到项目的这个配置文件中靠谱. 在配置的最后添加下面内容:

[pip]
index-url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"
[tool.uv]
index-url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"

管理依赖

使用 uv add 命令向项目中添加依赖

lpwm@Beijing:~/python-project/my-flask$ uv add flask
Using CPython 3.8.20
Creating virtual environment at: .venv
Resolved 17 packages in 492ms
Prepared 9 packages in 103ms
Installed 9 packages in 7ms+ blinker==1.8.2+ click==8.1.8+ flask==3.0.3+ importlib-metadata==8.5.0+ itsdangerous==2.2.0+ jinja2==3.1.6+ markupsafe==2.1.5+ werkzeug==3.0.6+ zipp==3.20.2

此时再检查 pyproject.toml 内容, dependencies 部分自动加上了包的信息.

[project]
name = "my-flask"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.8"
dependencies = ["flask>=3.0.3",
]
[pip]
index-url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"
[tool.uv]
index-url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"

这里默认安装的 Flask 版本太高了, 我想要使用特定的一个老版本 2.3.3, 所以需要先移除现在安装的包, 再指定版本添加依赖.

lpwm@Beijing:~/python-project/my-flask$ uv remove flask
Resolved 1 package in 1ms
Uninstalled 9 packages in 3ms- blinker==1.8.2- click==8.1.8- flask==3.0.3- importlib-metadata==8.5.0- itsdangerous==2.2.0- jinja2==3.1.6- markupsafe==2.1.5- werkzeug==3.0.6- zipp==3.20.2
lpwm@Beijing:~/python-project/my-flask$ uv add flask==2.3.3
Resolved 16 packages in 76ms
Prepared 1 package in 60ms
Installed 9 packages in 7ms+ blinker==1.8.2+ click==8.1.8+ flask==2.3.3+ importlib-metadata==8.5.0+ itsdangerous==2.2.0+ jinja2==3.1.6+ markupsafe==2.1.5+ werkzeug==3.0.6+ zipp==3.20.2

再次检查 pyproject.toml 内容, dependencies 部分同步更新. 优雅, 太优雅了!

dependencies = ["flask==2.3.3",
]

使用命令 uv tree 可以检查当前项目依赖的树结构

lpwm@Beijing:~/python-project/my-flask$ uv tree
Resolved 16 packages in 0.52ms
my-flask v0.1.0
└── flask v2.3.3├── blinker v1.8.2├── click v8.1.8├── importlib-metadata v8.5.0│   └── zipp v3.20.2├── itsdangerous v2.2.0├── jinja2 v3.1.6│   └── markupsafe v2.1.5└── werkzeug v3.0.6└── markupsafe v2.1.5

这个时候如果尝试直接运行 Flask 的命令, 会提示找不到, 因为我们还没有创建对应的虚拟环境. 其实这一步也不需要手动做, 在要执行的命令前面添加 uv run 就会自动创建 .venv 并且调用命令, 而无需切换到虚拟环境中.

lpwm@Beijing:~/python-project/my-flask$ uv run flask --version
Using CPython 3.8.20
Creating virtual environment at: .venv
Installed 9 packages in 6ms
Python 3.8.20
Flask 2.3.3
Werkzeug 3.0.6

当然, 我们也可以手动激活命令行到 .venv 的上下文环境.

lpwm@Beijing:~/python-project/my-flask$ source .venv/bin/activate
(my-flask) lpwm@Beijing:~/python-project/my-flask$ flask --version
Python 3.8.20
Flask 2.3.3
Werkzeug 3.0.6
(my-flask) lpwm@Beijing:~/python-project/my-flask$ deactivate
lpwm@Beijing:~/python-project/my-flask$

Flask 搓个 Demo 页面

在项目根路径下创建 app.py, 做个简单的首页.

from flask import Flaskapp = Flask(__name__)@app.get('/')
def index():return '<h1>Hello uv</h1>'

原神 启动!

lpwm@Beijing:~/python-project/my-flask$ uv run flask run* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.* Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [30/Mar/2025 22:48:43] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [30/Mar/2025 22:48:43] "GET /favicon.ico HTTP/1.1" 404 -

浏览器可以正常访问:
在这里插入图片描述
OK, 现在假装项目就开发完成了, 接着进入打包发布环节.

项目打包

首先删除项目默认创建的那个 hello.py 文件, 打包时要求根路径下只能有一个入口文件. 否则执行 uv build 会报错:
在这里插入图片描述

lpwm@Beijing:~/python-project/my-flask$ uv build
Building source distribution...
running egg_info
**** 此处省略 n 行 ****
Successfully built dist/my_flask-0.1.0.tar.gz
Successfully built dist/my_flask-0.1.0-py3-none-any.whl

打包完成后, 会在项目中多出 dist 文件夹, 其中包含了 .tar.gz.whl 两种格式. 如果需要发布到 PyPI 仓库的项目, 直接运行 uv publish 就可以, 本文不做演示. 下面我们来讨论使用 .whl 格式分发后的安装过程.

Wheel 方式分发安装

将上面打包好的 dist/my_flask-0.1.0-py3-none-any.whl 复制到一个新的文件夹中, 模拟分发后的环境.

# 另新建一个项目文件夹, 把 .whl 文件复制过去
lpwm@Beijing:~/python-project$ mkdir dep-flask
lpwm@Beijing:~/python-project$ cp my-flask/dist/my_flask-0.1.0-py3-none-any.whl ./dep-flask/
lpwm@Beijing:~/python-project$ cd dep-flask# 使用 uv 仅创建一个虚拟环境
lpwm@Beijing:~/python-project/dep-flask$ ls
my_flask-0.1.0-py3-none-any.whl
lpwm@Beijing:~/python-project/dep-flask$ uv venv --python 3.8
Using CPython 3.8.20
Creating virtual environment at: .venv
Activate with: source .venv/bin/activate# 激活虚拟环境后安装 whl 文件, 注意 pip 命令前添加 uv
lpwm@Beijing:~/python-project/dep-flask$ source .venv/bin/activate
(dep-flask) lpwm@Beijing:~/python-project/dep-flask$ uv pip install my_flask-0.1.0-py3-none-any.whl
Resolved 10 packages in 495ms
Prepared 1 package in 3ms
Installed 10 packages in 7ms+ blinker==1.8.2+ click==8.1.8+ flask==2.3.3+ importlib-metadata==8.5.0+ itsdangerous==2.2.0+ jinja2==3.1.6+ markupsafe==2.1.5+ my-flask==0.1.0 (from file:///home/lpwm/python-project/dep-flask/my_flask-0.1.0-py3-none-any.whl)+ werkzeug==3.0.6+ zipp==3.20.2# 检查已安装的依赖, 其中包含了我们的项目 my-flask 以及关联的依赖们
(dep-flask) lpwm@Beijing:~/python-project/dep-flask$ uv pip list
Package            Version
------------------ -------
blinker            1.8.2
click              8.1.8
flask              2.3.3
importlib-metadata 8.5.0
itsdangerous       2.2.0
jinja2             3.1.6
markupsafe         2.1.5
my-flask           0.1.0
werkzeug           3.0.6
zipp               3.20.2

后记

需要注意, 以上只是 .whl 格式文件安装的操作步骤演示, 我们使用 Flask 作为依赖框架开发的 WEB 项目在实际部署中其实并不太适用于这种方式, 编写 Dockerfile 使用容器方式部署才是正解.
先挖个坑, 后面再记录 uv 管理的项目使用 Docker 部署的实战过程.
https://docs.astral.sh/uv/guides/integration/docker/

相关文章:

使用 uv 管理 Python 项目

介绍 首先, uv 工具是使用 rust 开发出来的, 速度要比传统的 pip, pipx 等一众包管理工具要快不少. 另外, 除了包管理之外, uv 还提供了脚手架的功能, 使用体验和前端开发使用过的 vue-cli 很相似, 可以帮助我们自动初始化项目, 创建好一个空的包含必要文件结构的文件夹. 此外…...

【操作系统】软中断vs硬中断

在操作系统中&#xff0c;中断&#xff08;Interrupt&#xff09; 是 CPU 响应外部事件的重要机制&#xff0c;分为 硬中断&#xff08;Hardware Interrupt&#xff09; 和 软中断&#xff08;Software Interrupt&#xff09;。它们的核心区别在于 触发方式 和 处理机制。 1. 硬…...

《C++11:通过thread类编写C++多线程程序》

关于多线程的概念与理解&#xff0c;可以先了解Linux下的底层线程。当对底层线程有了一定程度理解以后&#xff0c;再学习语言级别的多线程编程就轻而易举了。 【Linux】多线程 -&#xff1e; 从线程概念到线程控制 【Linux】多线程 -&#xff1e; 线程互斥与死锁 语言级别的…...

19-dfs-排列数字(基础)

题目 来源 842. 排列数字 - AcWing题库 思路 由于相对简单&#xff0c;是dfs的模板题&#xff0c;具体思路详见代码 代码 #include<bits/stdc.h> using namespace std; const int N10; int state[N],path[N];//是否使用过&#xff0c;当前位置 int n; void dfs(int …...

32.代码题

接着上集...... 派对&#xff1a;超时了&#xff0c;总该受到惩罚吧&#xff1f; 洛西&#xff1a;至于吗&#xff1f;就0.1秒&#xff01; 晴/宇&#xff1a;十分应该。 洛西&#xff1a;我..................... 没办法&#xff0c;洛西只能按照要求去抓R了。 1.P1102 …...

nacos 3.x Java SDK 使用详解

Nacos 3.x Java SDK 使用详解 Nacos 3.x 是云原生服务治理的重要升级版本&#xff0c;其 Java SDK 在性能、协议和扩展性上均有显著优化。 一、环境要求与依赖配置 基础环境 JDK 版本&#xff1a;需使用 JDK 17&#xff08;Nacos 3.x 已放弃对 JDK 8 的支持&#xff09;。Spri…...

SPI-NRF24L01

模块介绍 NRF24L01是NORDIC公司生产的一款无线通信芯片&#xff0c;采用FSK调制&#xff0c;内部集成NORDIC自己的Enhanced Short Burst 协议&#xff0c;可以实现点对点或者1对6 的无线通信,通信速率最高可以达到2Mbps. NRF24L01采用SPI通信。 ①MOSI 主器件数据输出&#xf…...

python黑科技:无痛修改第三方库源码

需求不符合 很多时候&#xff0c;我们下载的 第三方库 是不会有需求不满足的情况&#xff0c;但也有极少的情况&#xff0c;第三方库 没有兼顾到需求&#xff0c;导致开发者无法实现相关功能。 如何通过一些操作将 第三方库 源码进行修改&#xff0c;是我们将要遇到的一个难点…...

一区严选!挑战5天一篇脂质体组学 DAY1-5

Day 1! 前期已经成功挑战了很多期NHANES啦&#xff01;打算来试试孟德尔随机化领域&#xff5e; 随着孟德尔随机化研究的普及&#xff0c;现在孟德尔发文的难度越来越高&#xff0c;简单的双样本想被接收更是难上加难&#xff0c;那么如何破除这个困境&#xff0c;这次我打算…...

【JavaScript】合体期功法——DOM(二)

目录 DOM事件监听案例关闭广告随机点名 事件监听版本事件类型 DOM 事件监听 事件&#xff1a;编程时系统内发生的动作或事情&#xff0c;例如用户在网页上单击一个按钮 事件监听&#xff1a;让程序检测是否产生事件&#xff0c;一旦事件触发&#xff0c;立即调用函数做出响应…...

23种设计模式中的中介者模式

定义了一个中介对象来封装一系列对象之间的交互。中介者使各对象直接不再显示地相互引用&#xff0c;从而使其松散耦合&#xff0c;且可以独立地改变它们之间的交互。 通过引入一个中介者对象&#xff0c;来协调和封装多个对象之间的交互&#xff0c;从而降低他们之间的耦合度。…...

量子计算:开启未来计算的新纪元

一、引言 在当今数字化时代&#xff0c;计算技术的飞速发展深刻地改变了我们的生活和工作方式。从传统的电子计算机到如今的高性能超级计算机&#xff0c;人类在计算能力上取得了巨大的进步。然而&#xff0c;随着科技的不断推进&#xff0c;我们面临着越来越多的复杂问题&…...

Docker 的实质作用是什么

Docker 的实质作用是什么 目录 Docker 的实质作用是什么**1. Docker 的实质作用****2. 为什么使用 Docker?****(1)解决环境一致性问题****(2)提升资源利用率****(3)简化部署与扩展****(4)加速开发与协作****3. 举例说明****总结**Docker 的实质是容器化平台,核心作用…...

Assembly语言的装饰器

Assembly语言的装饰器&#xff1a;灵活高效的代码复用 引言 在软件开发中&#xff0c;代码复用和模块化是两个至关重要的概念。它们不仅使得代码的维护变得更为简单&#xff0c;而且能极大提升开发效率。在高级语言中&#xff0c;装饰器是一种非常受欢迎的设计模式&#xff0…...

VITA 模型解读,实时交互式多模态大模型的 pioneering 之作

写在前面:实时交互llm 今天回顾一下多模态模型VITA,当时的背景是OpenAI 的 GPT-4o 惊艳亮相,然而,当我们将目光投向开源社区时,却发现能与之匹敌的模型寥寥无几。当时开源多模态大模型(MLLM),大多在以下一个或多个方面存在局限: 模态支持不全:大多聚焦于文本和图像,…...

自学-408-《计算机网络》(总结速览)

文章目录 第一章 计算机网络概述1. 计算机网络的定义2. 计算机网络的基本功能3. 计算机网络的分类4. 计算机网络的层次结构5. 计算机网络的协议6. 计算机网络的组成部分7. 计算机网络的应用8. 互联网的概念 物理层的主要功能第二章 数据链路层和局域网1. 数据链路层的功能2. 局…...

AF3 FeaturePipeline类解读

AlphaFold3 feature_pipeline 模块 FeaturePipeline 类是一个封装类,通过调用函数np_example_to_features 实现整个数据处理流程。 源代码: def np_to_tensor_dict(np_example: Mapping[str, np.ndarray],features: Sequence[str], ) -> TensorDict:"""C…...

【质量管理】纠正、纠正措施和预防的区别与解决问题的四重境界

“质量的定义就是符合要求”&#xff0c;我们在文章【质量管理】人们对于质量的五个错误观念-CSDN博客中提到过&#xff0c;这也是质量大师克劳士比所说的。“质量的系统就是预防”&#xff0c;防止出现产品不良而造成的质量损失。 质量问题的解决可以从微观和宏观两个方面来考…...

Java面试黄金宝典24

1. 什么是跳表 定义 跳表&#xff08;Skip List&#xff09;是一种随机化的数据结构&#xff0c;它基于有序链表发展而来&#xff0c;通过在每个节点中维护多个指向其他节点的指针&#xff0c;以多层链表的形式组织数据。其核心思想是在链表基础上增加额外层次&#xff0c;每…...

Windows 11系统下Kafka的详细安装与启动指南(JDK 1.8)

1. 安装前准备 在Windows 11系统中安装Kafka之前,需要确保满足以下条件: 1.1 系统要求 Windows 11操作系统(64位)至少4GB内存(建议8GB或更高)至少5GB可用磁盘空间管理员权限1.2 所需工具 浏览器(用于下载软件)解压工具(如7-Zip、WinRAR,Windows 11自带的解压功能也…...

树莓派超全系列文档--(16)无需交互使用raspi-config工具其三

无需交互使用raspi-config工具其三 无需交互的 raspi-configAdvanced optionsExpand filesystemNetwork interface namesNetwork proxy settingsBoot orderBootloader versionWaylandAudio config Update 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文…...

【蓝桥杯】算法笔记1

1.暴力枚举 给定一个正整数n,请找出所有满足a + b = n的整数对(a, b),其中a和b都是正整数,且a ≤ b。 输入格式:一个正整数n (1 ≤ n ≤ 10⁶) 输出格式:所有符合条件的(a, b)对,每行一对,按a的升序排列。如果没有符合条件的对,输出"No solution"。 问题分…...

爱因斯坦求和 torch

目录 向量点积 矩阵乘法 矩阵转置 向量转换相机坐标系 在 Python 的科学计算库&#xff08;如 NumPy&#xff09;中&#xff0c;einsum 是一个强大的函数&#xff0c;它可以简洁地表示各种张量运算。下面是几个不同类型的使用示例&#xff1a; 向量点积 向量点积是两个向量…...

Linux命令-sed指令

sed命令参数&#xff1a; 基本参数 -n&#xff1a;抑制默认输出&#xff0c;只显示匹配的行。 -e&#xff1a;指定 sed 脚本。 -i&#xff1a;直接修改文件内容。 -f&#xff1a;指定包含 sed 脚本的文件。 -r&#xff1a;启用扩展正则表达式。 常用操作 s&#xff1a;替换字符…...

新手SEO优化实战快速入门

内容概要 对于SEO新手而言&#xff0c;系统化掌握基础逻辑与实操路径是快速入门的关键。本指南以站内优化为切入点&#xff0c;从网站结构、URL设计到内链布局&#xff0c;逐层拆解搜索引擎友好的技术框架&#xff1b;同时聚焦关键词挖掘与内容策略&#xff0c;结合工具使用与…...

如何使不同的窗体控件,适应不同分辨率的屏幕?

问题 当屏幕分辨率提高或降低时&#xff0c;原分辨率显示正常的控件&#xff0c;将变得很小或很大&#xff0c;字体也变得太大或太小。 解决办法 当分辨率变化时&#xff0c;采用递归的方法&#xff0c;对所有的控件放大或缩小。 public static void MainForm_Load(object s…...

sqli-labs靶场 less 11

文章目录 sqli-labs靶场less 11 POS联合注入 sqli-labs靶场 每道题都从以下模板讲解&#xff0c;并且每个步骤都有图片&#xff0c;清晰明了&#xff0c;便于复盘。 sql注入的基本步骤 注入点注入类型 字符型&#xff1a;判断闭合方式 &#xff08;‘、"、’、“”&…...

tomcat部署项目打开是404?

问题描述 今天在帮助一个小伙伴解决问题的时候 部署成功了 就是打不开总是404 他这个项目是公司的一个18年的项目 巨老&#xff01;&#xff01;&#xff01; HTTP状态 404 - 未找到 类型 状态报告 描述 源服务器未能找到目标资源的表示或者是不愿公开一个已经存在的资源表示…...

[Linux]解决虚拟机 ubantu系统下网络的问题

问题来源&#xff1a;打开ubantu发现网络连接标识消失 解决步骤&#xff1a; 重新安装&#xff0c;前面操作无效 切换桥接模式、直连手机网络 已解决&#xff1a;...

如何使用stable diffusion 3获得最佳效果

参考&#xff1a;How to get the best results from Stable Diffusion 3 Scaling Rectified Flow Transformers for High-Resolution Image Synthesis prompting SD3 不再受限于CLIP的最长77个token的长度限制&#xff0c;可以输入更长的prompt。 &#xff08;两个CLIP模型的…...