使用 uv 管理 Python 项目

news2025/5/20 5:15:18

介绍

首先, 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 Flask

app = 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/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2325098.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《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;这次我打算…

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

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

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

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

新手SEO优化实战快速入门

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

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模型的…

Java学习笔记1——编程基础

一、整数类型变量 注意&#xff1a;每个字符型常量占两个字节 二、自动类型转换和强制类型转换 ​​​三、算术运算符 四、赋值运算符 五、比较运算符 六、逻辑运算符 七、运算符的优先级 运算符的优先级可以通过以下口诀来记忆&#xff1a; 括号优先&#xff0c;单目次之&am…

微服务核心知识点深度解析:从组件到架构设计

微服务核心知识点深度解析&#xff1a;从组件到架构设计 微服务核心知识点深度解析&#xff1a;从组件到架构设计一、Spring Cloud 5 大核心组件详解二、服务注册与发现&#xff1a;微服务的 “通讯录”概念解析Spring Cloud 中的实现 三、Nacos&#xff1a;不止是注册中心核心…

SpringBoot3+EasyExcel通过WriteHandler动态实现表头重命名

方案简介 为了通过 EasyExcel 实现动态表头重命名&#xff0c;可以封装一个方法&#xff0c;传入动态的新表头名称列表&#xff08;List<String>&#xff09;&#xff0c;并结合 WriteHandler 接口来重命名表头。同时&#xff0c;通过 EasyExcel 将数据直接写入到输出流…

Python小练习系列 Vol.11:回文数筛选(filter + 字符串反转)

&#x1f9e0; Python小练习系列 Vol.11&#xff1a;回文数筛选&#xff08;filter 字符串反转&#xff09; &#x1f50d; 本期我们用 Python 的 filter() 函数结合字符串反转技巧&#xff0c;一行代码搞定“回文数”的判断与筛选&#xff01; &#x1f9e9; 一、题目描述 回…

BUUCTF-web刷题篇(5)

13.upload1 文件上传漏洞&#xff08;上传图片&#xff09; 按照传统方法&#xff0c;新建文件&#xff08;xinjian&#xff09;写一句话木马&#xff0c;利用Windows文件后缀识别的特点&#xff0c;将后缀名改为图片后缀名(xinjian.jpg)&#xff0c;上传文件&#xff0c;抓包…

NestJS——创建项目、编写User模块

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…