ldsuv 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ldsuv-0.1.0/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ # sphinx build directories
2
+ _build/
3
+
4
+ # dotfiles
5
+ .*
6
+ !.gitignore
7
+ # compiled python files
8
+ *.py[co]
9
+ __pycache__/
10
+ # setup.py egg_info
11
+ *.egg-info
12
+ build/
13
+ dist/
14
+ # emacs backup files
15
+ *~
16
+ *-
17
+ _
@@ -0,0 +1,10 @@
1
+ # 默认忽略的文件
2
+ /shelf/
3
+ /workspace.xml
4
+ # 基于编辑器的 HTTP 客户端请求
5
+ /httpRequests/
6
+ # 已忽略包含查询文件的默认文件夹
7
+ /queries/
8
+ # Datasource local storage ignored files
9
+ /dataSources/
10
+ /dataSources.local.xml
@@ -0,0 +1,17 @@
1
+ # 更改日志
2
+
3
+ 此项目的所有显着更改都将记录在此文件中。
4
+
5
+ 此项目遵循[语义化版本](https://semver.org/lang/zh-CN/)。
6
+
7
+ ## [0.0.1]
8
+
9
+ **初始版本**
10
+
11
+ ### Added
12
+ - 无
13
+ ### Changed
14
+ - 无
15
+ ### Fixed
16
+ - 无
17
+
ldsuv-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,14 @@
1
+ Metadata-Version: 2.4
2
+ Name: ldsuv
3
+ Version: 0.1.0
4
+ Summary: 基于 uv 的环境管理与依赖备注工具
5
+ Author-email: Lds <85176878@qq.com>
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+
9
+ # lds_uv_env
10
+
11
+ 查看 [更改日志](https://github.com/ldsxp/lds_uv_env/blob/master/CHANGELOG.md)
12
+
13
+ https://github.com/ldsxp/lds_uv_env
14
+
ldsuv-0.1.0/README.md ADDED
@@ -0,0 +1,6 @@
1
+ # lds_uv_env
2
+
3
+ 查看 [更改日志](https://github.com/ldsxp/lds_uv_env/blob/master/CHANGELOG.md)
4
+
5
+ https://github.com/ldsxp/lds_uv_env
6
+
@@ -0,0 +1 @@
1
+ *
ldsuv-0.1.0/publish.py ADDED
@@ -0,0 +1,69 @@
1
+ import os
2
+ import shutil
3
+ import subprocess
4
+
5
+
6
+ def setup_token():
7
+ """
8
+ 配置 Token 环境变量:
9
+ 1. 优先检查系统环境变量
10
+ 2. 如果没有,则尝试从本地 .env 文件中读取
11
+ """
12
+ # 优先检查系统环境变量是否已经存在 Token
13
+ if os.getenv("UV_PUBLISH_TOKEN"):
14
+ print("✅ 检测到已存在系统环境变量: UV_PUBLISH_TOKEN")
15
+ return True
16
+
17
+ # 如果系统没有,尝试读取 .env 文件
18
+ env_file = ".env"
19
+ if os.path.exists(env_file):
20
+ with open(env_file, "r", encoding="utf-8") as f:
21
+ for line in f:
22
+ line = line.strip()
23
+ # 忽略空行和注释
24
+ if line and not line.startswith("#") and "=" in line:
25
+ key, value = line.split("=", 1)
26
+ if key.strip() == "UV_PUBLISH_TOKEN":
27
+ # 找到后,将其注入到当前运行的环境变量中
28
+ os.environ["UV_PUBLISH_TOKEN"] = value.strip()
29
+ print("✅ 已从本地 .env 文件中读取并注入 Token")
30
+ return True
31
+
32
+ return False
33
+
34
+
35
+ def main():
36
+ print("🚀 准备发布项目...\n")
37
+
38
+ # 配置 Token
39
+ if not setup_token():
40
+ print("❌ 错误: 未在系统环境变量或 .env 文件中找到 UV_PUBLISH_TOKEN")
41
+ print("💡 请配置环境变量,或在项目根目录创建包含 'UV_PUBLISH_TOKEN=你的token' 的 .env 文件。")
42
+ return
43
+
44
+ # 清理旧的构建文件
45
+ dist_dir = "dist"
46
+ if os.path.exists(dist_dir):
47
+ print(f"\n🧹 清理旧的 {dist_dir} 目录...")
48
+ shutil.rmtree(dist_dir)
49
+
50
+ try:
51
+ # 运行 uv build
52
+ print("📦 正在构建项目 (uv build)...")
53
+ subprocess.run(["uv", "build"], check=True)
54
+ print("✅ 构建成功!\n")
55
+
56
+ # 运行 uv publish
57
+ # 此时环境变量中一定已经有 UV_PUBLISH_TOKEN,uv publish 会自动获取它
58
+ print("🌐 正在发布到 PyPI (uv publish)...")
59
+ subprocess.run(["uv", "publish"], check=True)
60
+ print("🎉 发布成功!")
61
+
62
+ except subprocess.CalledProcessError as e:
63
+ print(f"\n❌ 执行失败,命令退出状态码: {e.returncode}")
64
+ except FileNotFoundError:
65
+ print("\n❌ 找不到 'uv' 命令,请确认 uv 已正确安装并配置在系统环境变量中。")
66
+
67
+
68
+ if __name__ == "__main__":
69
+ main()
@@ -0,0 +1,18 @@
1
+ [project]
2
+ name = "ldsuv"
3
+ version = "0.1.0"
4
+ description = "基于 uv 的环境管理与依赖备注工具"
5
+ authors = [
6
+ { name = "Lds", email = "85176878@qq.com" }
7
+ ]
8
+ dependencies = [
9
+ ]
10
+ readme = "README.md"
11
+ requires-python = ">=3.10"
12
+
13
+ [project.scripts]
14
+ ldsuv = "ldsuv.main:main"
15
+
16
+ [build-system]
17
+ requires = ["hatchling"]
18
+ build-backend = "hatchling.build"
File without changes
@@ -0,0 +1,252 @@
1
+ import os
2
+ import sys
3
+ import json
4
+ import subprocess
5
+
6
+ # 兼容性处理 tomllib
7
+ try:
8
+ import tomllib
9
+ except ImportError:
10
+ import pip._vendor.tomli as tomllib
11
+
12
+ SETTINGS_FILE = 'env_settings.json'
13
+ PYTHON_VERSION_FILE = '.python-version'
14
+ PYPROJECT_FILE = 'pyproject.toml'
15
+ VENV_DIR = '.venv'
16
+ LOCK_FILE = 'uv.lock'
17
+
18
+
19
+ def load_settings():
20
+ if os.path.exists(SETTINGS_FILE):
21
+ try:
22
+ with open(SETTINGS_FILE, 'r', encoding='utf-8') as f:
23
+ return json.load(f)
24
+ except Exception:
25
+ pass
26
+ return {"selected_mirror_name": "PyPI", "package_metadata": {}}
27
+
28
+
29
+ def save_settings(settings):
30
+ with open(SETTINGS_FILE, 'w', encoding='utf-8') as f:
31
+ json.dump(settings, f, ensure_ascii=False, indent=2)
32
+
33
+
34
+ class UVEnvManager:
35
+ def __init__(self):
36
+ self.settings = load_settings()
37
+ self.mirrors = {
38
+ "阿里": "https://mirrors.aliyun.com/pypi/simple/",
39
+ "清华大学": "https://pypi.tuna.tsinghua.edu.cn/simple/",
40
+ "PyPI": "https://pypi.org/simple",
41
+ }
42
+ try:
43
+ subprocess.run(["uv", "--version"], capture_output=True, check=True)
44
+ except:
45
+ print("错误: 未检测到 uv。请运行 'pip install uv' 安装。")
46
+ sys.exit(1)
47
+
48
+ def _run_uv(self, args, capture=False):
49
+ """增强版执行器:支持错误捕获显示"""
50
+ env = os.environ.copy()
51
+ if self.settings["selected_mirror_name"] != "PyPI":
52
+ env["UV_INDEX_URL"] = self.mirrors[self.settings["selected_mirror_name"]]
53
+
54
+ try:
55
+ if capture:
56
+ res = subprocess.run(["uv"] + args, env=env, capture_output=True, text=True, check=True)
57
+ return res.stdout
58
+ else:
59
+ # 使用 run 而不是 call,以便获取更详细的返回状态
60
+ res = subprocess.run(["uv"] + args, env=env)
61
+ return res.returncode == 0
62
+ except subprocess.CalledProcessError as e:
63
+ print(f"\n[uv 报错]:\n{e.stderr if e.stderr else e}")
64
+ return False
65
+ except Exception as e:
66
+ print(f"\n[执行异常]: {e}")
67
+ return False
68
+
69
+ def get_project_status(self):
70
+ status = {"has_toml": os.path.exists(PYPROJECT_FILE), "has_venv": os.path.exists(VENV_DIR),
71
+ "project_name": "Unknown", "dep_count": 0, "dev_dep_count": 0, "python_pinned": "未锁定"}
72
+ if status["has_toml"]:
73
+ try:
74
+ with open(PYPROJECT_FILE, "rb") as f:
75
+ data = tomllib.load(f)
76
+ status["project_name"] = data.get("project", {}).get("name", "未命名")
77
+ status["dep_count"] = len(data.get("project", {}).get("dependencies", []))
78
+ dev_deps = data.get("dependency-groups", {}).get("dev", [])
79
+ status["dev_dep_count"] = len(dev_deps)
80
+ except:
81
+ pass
82
+ if os.path.exists(PYTHON_VERSION_FILE):
83
+ try:
84
+ with open(PYTHON_VERSION_FILE, "r") as f:
85
+ status["python_pinned"] = f.read().strip()
86
+ except:
87
+ pass
88
+ return status
89
+
90
+ def migrate_requirements(self):
91
+ """智能迁移:自动去重,确保 Dev 组只包含增量库"""
92
+ print("\n" + "-" * 30)
93
+ print(" [迁移工具] 正在导入依赖...")
94
+ print("-" * 30)
95
+
96
+ # 预检查:如果手动修改了 toml,建议先删除 lock 文件以强制 uv 重新解析
97
+ if os.path.exists(LOCK_FILE):
98
+ confirm = input("检测到已存在 uv.lock,是否删除它以确保导入最新版本?[y/N]: ").strip().lower()
99
+ if confirm == 'y':
100
+ os.remove(LOCK_FILE)
101
+ print("✔ 已删除 uv.lock,将重新解析依赖。")
102
+
103
+ prod_pkgs = []
104
+ # 1. 导入生产依赖
105
+ if os.path.exists("requirements.txt"):
106
+ print(">> 正在导入生产依赖 (requirements.txt)...")
107
+ if self._run_uv(["add", "--requirements", "requirements.txt"]):
108
+ # 记录已导入的生产库名,防止重复进入 dev
109
+ st = self.get_project_status()
110
+ # 简单获取当前已记录的 dependencies (这一步是为了下一步去重)
111
+ print("✔ 生产依赖导入完成。")
112
+ else:
113
+ print("❌ 生产环境导入失败,停止后续操作。")
114
+ return
115
+
116
+ # 2. 导入开发依赖 (带去重逻辑)
117
+ if os.path.exists("requirements_dev.txt"):
118
+ print("\n>> 正在处理开发依赖 (requirements_dev.txt)...")
119
+
120
+ # 读取 dev 文件内容
121
+ with open("requirements_dev.txt", "r") as f:
122
+ lines = f.readlines()
123
+
124
+ # 过滤掉包含 "-r requirements.txt" 的行以及注释空行
125
+ clean_dev_lines = []
126
+ for line in lines:
127
+ l = line.strip()
128
+ if not l or l.startswith("#") or l.startswith("-r"):
129
+ continue
130
+ clean_dev_lines.append(l)
131
+
132
+ if clean_dev_lines:
133
+ # 临时创建一个干净的增量 dev 文件
134
+ temp_dev = "temp_dev_requirements.txt"
135
+ with open(temp_dev, "w") as f:
136
+ f.write("\n".join(clean_dev_lines))
137
+
138
+ print(f">> 正在同步 {len(clean_dev_lines)} 个开发增量库...")
139
+ success = self._run_uv(["add", "--dev", "--requirements", temp_dev])
140
+ os.remove(temp_dev) # 清理临时文件
141
+
142
+ if success:
143
+ print("✔ 开发依赖 (增量) 导入完成。")
144
+ else:
145
+ print("❌ 开发依赖导入过程中出错。")
146
+
147
+ self._run_uv(["sync"])
148
+ print("\n--- 迁移任务成功结束 ---")
149
+
150
+ def install_package(self):
151
+ pkg = input("\n请输入库名 (如 django): ").strip()
152
+ if not pkg: return
153
+
154
+ is_dev = input("是否安装为开发依赖 (Dev)? [y/N]: ").strip().lower() == 'y'
155
+ args = ["add", "--dev", pkg] if is_dev else ["add", pkg]
156
+
157
+ if self._run_uv(args):
158
+ # 去掉版本号保留纯净库名
159
+ pure_name = pkg.split('==')[0].split('>')[0].split('<')[0].split('[')[0].strip()
160
+ self.settings["package_metadata"].setdefault(pure_name, {"notes": ""})
161
+ note = input(f"为 {pure_name} 添加备注: ").strip()
162
+ if note:
163
+ self.settings["package_metadata"][pure_name]["notes"] = note
164
+ save_settings(self.settings)
165
+
166
+ def main_menu(self):
167
+ while True:
168
+ st = self.get_project_status()
169
+ print("\n" + "=" * 60)
170
+ print(f" 项目: {st['project_name']} | 生产: {st['dep_count']} | 开发(Dev): {st['dev_dep_count']}")
171
+ print(f" Python: {st['python_pinned']} | 镜像: {self.settings['selected_mirror_name']}")
172
+ if not st['has_toml']:
173
+ print(" ⚠ [状态] 项目未初始化")
174
+ elif not st['has_venv']:
175
+ print(" ⚠ [状态] 缺少虚拟环境 (.venv)")
176
+ print("=" * 60)
177
+
178
+ print("0. 初始化项目 (uv init)")
179
+ print("1. 检查并升级所有库 (uv lock --upgrade)")
180
+ print("2. 安装新库 (可按 y 选 Dev)")
181
+ print("3. 管理备注与链接 (JSON)")
182
+ print("4. Python 版本锁定")
183
+ print("5. 同步环境 (uv sync)")
184
+ print("6. 切换镜像源")
185
+ print("7. 导出 requirements.txt")
186
+ print("8. 【迁移】从旧文件导入 (带熔断保护)")
187
+ print("e. 退出")
188
+
189
+ c = input("\n指令: ").strip().lower()
190
+ if c == '0':
191
+ name = input("项目名称: ").strip()
192
+ if self._run_uv(["init"] + (["--name", name] if name else [])):
193
+ self._run_uv(["python", "pin", "3.12"])
194
+ elif c == '1':
195
+ if self._run_uv(["lock", "--upgrade"]): self._run_uv(["sync"])
196
+ elif c == '2':
197
+ self.install_package()
198
+ elif c == '3':
199
+ self.manage_metadata()
200
+ elif c == '4':
201
+ ver = input("版本 (如 3.12): ").strip()
202
+ if ver: self._run_uv(["python", "pin", ver])
203
+ elif c == '5':
204
+ self._run_uv(["sync"])
205
+ elif c == '6':
206
+ names = list(self.mirrors.keys())
207
+ for i, n in enumerate(names, 1): print(f"{i}. {n}")
208
+ idx = input("选择: ").strip()
209
+ if idx.isdigit() and 1 <= int(idx) <= len(names):
210
+ self.settings["selected_mirror_name"] = names[int(idx) - 1]
211
+ save_settings(self.settings)
212
+ elif c == '7':
213
+ self._run_uv(["export", "--output-file", "requirements_exported.txt"])
214
+ elif c == '8':
215
+ self.migrate_requirements()
216
+ elif c == 'e':
217
+ break
218
+
219
+ def manage_metadata(self):
220
+ try:
221
+ out = self._run_uv(["pip", "list", "--format=json"], capture=True)
222
+ if not out: return
223
+ pkgs = json.loads(out)
224
+ except:
225
+ print("获取列表失败,请先同步。")
226
+ return
227
+
228
+ search = input("搜索 (直接回车列出): ").strip().lower()
229
+ filtered = [p for p in pkgs if search in p['name'].lower()]
230
+ for idx, p in enumerate(filtered[:20], 1):
231
+ n = p['name']
232
+ info = self.settings["package_metadata"].get(n, {})
233
+ print(f"{idx}. {n:<20} | {info.get('notes', '无')}")
234
+
235
+ sel = input("\n编辑编号 (b返回): ").strip()
236
+ if sel.isdigit() and 1 <= int(sel) <= len(filtered):
237
+ name = filtered[int(sel) - 1]['name']
238
+ info = self.settings["package_metadata"].setdefault(name, {"repo_url": "", "notes": ""})
239
+ info["notes"] = input(f"备注: ").strip() or info["notes"]
240
+ info["repo_url"] = input(f"链接: ").strip() or info["repo_url"]
241
+ save_settings(self.settings)
242
+
243
+
244
+ def main():
245
+ try:
246
+ UVEnvManager().main_menu()
247
+ except KeyboardInterrupt:
248
+ sys.exit(0)
249
+
250
+
251
+ if __name__ == "__main__":
252
+ main()
ldsuv-0.1.0/uv.lock ADDED
@@ -0,0 +1,8 @@
1
+ version = 1
2
+ revision = 3
3
+ requires-python = ">=3.10"
4
+
5
+ [[package]]
6
+ name = "ldsuv"
7
+ version = "0.1.0"
8
+ source = { editable = "." }