Skip to content

Commit 3009e41

Browse files
buptanswerclaude
andcommitted
feat: Add multi-Python version detection and selection (v1.1.0)
Major enhancements: - Auto-detect all Python installations using 'where python' and 'py -0p' - Allow users to select specific Python version for global environment reset - Auto-select when only one version is found - Added comprehensive input validation for version selection - All pip operations now use 'python -m pip' for version-specific execution Technical changes: - Enabled delayed variable expansion throughout the script - Added :SelectPythonVersion subroutine for multi-version detection - Added :CheckDuplicate subroutine for path deduplication - Introduced SELECTED_PYTHON variable for consistent Python execution - Script size increased from 197 to 333 lines Documentation updates: - Updated README.md with multi-version support information (bilingual) - Updated CHANGELOG.md with v1.1.0 release notes - Added CLAUDE.md for future Claude Code instances - Removed redundant release_note.txt 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent fefa13f commit 3009e41

5 files changed

Lines changed: 287 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.1.0] - 2025-12-15
9+
10+
### Added
11+
- 🐍 **Multi-Python Version Detection and Selection**
12+
- Automatically detects all Python installations using both `where python` and Python Launcher (`py -0p`)
13+
- Allows users to select which Python version to reset when operating on global environment
14+
- Automatic deduplication of detected Python paths
15+
- Single-version auto-selection when only one Python installation is found
16+
- ✨ Enhanced global environment workflow with version selection
17+
- 🔧 Enabled delayed variable expansion for improved script reliability
18+
19+
### Changed
20+
- All `python` and `pip` commands now use the selected Python version
21+
- Improved script robustness with consistent use of delayed expansion variables
22+
- Enhanced Python path extraction from `py -0p` output
23+
24+
### Technical Details
25+
- Added `:SelectPythonVersion` subroutine for multi-version detection
26+
- Added `:CheckDuplicate` subroutine for removing duplicate Python paths
27+
- Modified all pip operations to use `python -m pip` for version-specific execution
28+
- Introduced `SELECTED_PYTHON` variable to track the chosen Python interpreter
29+
830
## [1.0.0] - 2025-12-02
931

1032
### Added

CLAUDE.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
This is a Windows batch script tool for safely resetting Python virtual environments. The tool automatically detects common virtual environment directories, uninstalls all packages, and reinstalls essential base packages (pip, setuptools, wheel).
8+
9+
**Key characteristics:**
10+
- Single-file batch script (`env-reset.bat`)
11+
- Bilingual interface (Chinese/English)
12+
- UTF-8 encoded for international character support
13+
- Safety-first design with multiple confirmation steps
14+
15+
## Core Script Architecture
16+
17+
The `env-reset.bat` script follows a state-machine pattern with labeled sections using batch `goto` statements:
18+
19+
1. **Initialization** (lines 1-4): Enable delayed expansion, set UTF-8 encoding, change to script directory
20+
2. **Virtual Environment Detection** (lines 11-37): Checks for `.venv`, `venv`, `env`, `.env` in order
21+
3. **Environment Display** (`:ShowEnv`, `:ShowVersion`): Shows activated venv details, sets `SELECTED_PYTHON=python`
22+
4. **Global Warning** (`:NoVenvWarning`): Strong warnings when no venv detected
23+
5. **Python Version Selection** (`:SelectPythonVersion`, lines 107-214): NEW in v1.1.0
24+
- Detects all Python installations using `where python` and `py -0p`
25+
- Deduplicates findings via `:CheckDuplicate` subroutine
26+
- Auto-selects if only one version found
27+
- Prompts user selection for multiple versions
28+
- Sets `SELECTED_PYTHON` to chosen Python executable path
29+
6. **Package Enumeration** (`:GetPackages`): Uses `pip freeze` to list packages
30+
7. **Uninstallation** (lines 270+): Batch uninstall via temp file
31+
8. **Base Package Installation** (`:InstallBase`): Reinstalls pip, setuptools, wheel
32+
33+
**Critical implementation details:**
34+
- `setlocal EnableDelayedExpansion` at line 2 enables delayed expansion for entire script
35+
- Virtual environment activation happens BEFORE `goto` to avoid variable scope issues
36+
- `SELECTED_PYTHON` variable stores the Python interpreter path throughout script execution
37+
- All `python` and `pip` commands use `!SELECTED_PYTHON!` with delayed expansion
38+
- All pip operations use `"!SELECTED_PYTHON!" -m pip` for version-specific execution
39+
- `where python` shows current Python path (first result only for cleanliness)
40+
- Global environment operations require typing "YES" (uppercase, exact match)
41+
- Temp files: `temp_packages.txt` (package list), `temp_python_list.txt` (detected Pythons), `temp_python_list.txt.dedup` (deduplicated)
42+
43+
## Testing the Script
44+
45+
**Manual testing workflow:**
46+
1. Create a test virtual environment: `python -m venv .venv`
47+
2. Install some packages: `.venv\Scripts\activate && pip install requests numpy`
48+
3. Run the script: `env-reset.bat`
49+
4. Verify only base packages remain: `pip list`
50+
51+
**Test scenarios to cover:**
52+
- Virtual environment with packages (normal case)
53+
- Empty virtual environment (should skip to base package installation)
54+
- No virtual environment with single Python installation (should auto-select)
55+
- No virtual environment with multiple Python installations (should prompt for selection)
56+
- Different venv names (`.venv`, `venv`, `env`, `.env`)
57+
- Broken pip (error handling verification)
58+
- Invalid user input during version selection (input validation)
59+
60+
**Version selection testing:**
61+
- Test with only one Python in PATH: should auto-select without prompting
62+
- Test with multiple Python versions: should display list and accept numeric input
63+
- Test invalid selection input: should re-prompt with error message
64+
- Test selection out of range: should re-prompt with error message
65+
66+
## Working with Batch Scripts
67+
68+
**When modifying `env-reset.bat`:**
69+
- Preserve UTF-8 encoding (`chcp 65001`)
70+
- Maintain bilingual output (Chinese primary, context for English)
71+
- **IMPORTANT**: Always use `!SELECTED_PYTHON!` for python/pip commands (delayed expansion)
72+
- Test all `goto` label paths to avoid dead code
73+
- Use `errorlevel` checks after critical operations (pip, file operations)
74+
- Keep temp file cleanup in all code paths
75+
- Validate changes don't break variable scoping
76+
- When adding new Python version detection methods, update `:SelectPythonVersion`
77+
- Ensure `SELECTED_PYTHON` is set in both venv and global paths
78+
79+
**Batch scripting gotchas in this codebase:**
80+
- `setlocal EnableDelayedExpansion` is required at script start for `!var!` syntax
81+
- Variables set inside `call`ed scripts may not persist - hence early detection logic
82+
- `for /f` loops: use `!var!` for variables modified within the loop
83+
- `if errorlevel 1` means "if errorlevel >= 1" (not "if errorlevel == 1")
84+
- `>nul 2>&1` suppresses both stdout and stderr
85+
- `/i` flag makes string comparisons case-insensitive
86+
- When extracting tokens from `for /f`, `tokens=*` gets entire line, `tokens=1,2` gets first two space-delimited tokens
87+
- `for %%x in (!LINE!)` iterates over space-separated tokens, last assignment wins (used to get last token)
88+
- Always quote paths in delayed expansion: `"!SELECTED_PYTHON!"` not `!SELECTED_PYTHON!`
89+
90+
## File Structure
91+
92+
- `env-reset.bat` - Main executable script (333 lines, v1.1.0)
93+
- `README.md` - Bilingual documentation with usage examples
94+
- `CHANGELOG.md` - Version history (currently v1.1.0)
95+
- `CLAUDE.md` - This file, guidance for Claude Code
96+
- `LICENSE` - MIT license
97+
- `.gitignore` - Standard git ignore patterns
98+
99+
**Major version changes:**
100+
- v1.0.0 (197 lines): Initial release with basic venv reset
101+
- v1.1.0 (333 lines): Added multi-Python version detection and selection (+136 lines)
102+
103+
This is a simple, single-purpose tool with no dependencies beyond Windows and Python 3.x.

README.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ A lightweight Windows batch script tool for safely resetting Python virtual envi
1515

1616
- 🔍 **Auto-Detection**: Automatically detects common virtual environment directories (`.venv`, `venv`, `env`, `.env`)
1717
- 🛡️ **Safety First**: Warns users when operating on global Python environment
18+
- 🐍 **Multi-Version Support**: Automatically detects and allows selection from multiple Python installations
1819
- 📦 **Clean Reset**: Uninstalls all packages and reinstalls base packages (pip, setuptools, wheel)
1920
- 🎯 **User-Friendly**: Clear prompts and confirmations before any destructive operations
2021
- 🌐 **UTF-8 Support**: Properly handles Chinese and other Unicode characters
@@ -59,7 +60,15 @@ The script will:
5960
If no virtual environment is detected, the script will:
6061
1. Display a **strong warning**
6162
2. Require explicit confirmation (type `YES` in uppercase)
62-
3. Proceed only if confirmed
63+
3. **Detect all Python installations** on your system
64+
4. Allow you to **select a specific Python version** to reset
65+
5. Proceed with the reset on the selected Python installation
66+
67+
**Multi-Version Detection:**
68+
- The script uses both `where python` and Python Launcher (`py -0p`) to find all installations
69+
- Automatically removes duplicates
70+
- If only one version is found, it will be used automatically
71+
- If multiple versions are found, you can choose which one to reset
6372

6473
### 🔧 Supported Virtual Environment Names
6574

@@ -132,6 +141,7 @@ Created with ❤️ for Python developers
132141

133142
- 🔍 **自动检测**:自动检测常见的虚拟环境目录(`.venv``venv``env``.env`
134143
- 🛡️ **安全优先**:在操作全局 Python 环境时会发出强烈警告
144+
- 🐍 **多版本支持**:自动检测并允许从多个 Python 安装中选择
135145
- 📦 **彻底清理**:卸载所有包并重新安装基础包(pip、setuptools、wheel)
136146
- 🎯 **用户友好**:在执行任何破坏性操作前都有清晰的提示和确认
137147
- 🌐 **UTF-8 支持**:正确处理中文和其他 Unicode 字符
@@ -176,7 +186,15 @@ env-reset.bat
176186
如果未检测到虚拟环境,脚本将:
177187
1. 显示**强烈警告**
178188
2. 要求明确确认(输入大写的 `YES`
179-
3. 仅在确认后才继续执行
189+
3. **检测系统中所有 Python 安装**
190+
4. 允许你**选择特定的 Python 版本**进行重置
191+
5. 对选定的 Python 安装执行重置操作
192+
193+
**多版本检测功能:**
194+
- 脚本使用 `where python` 和 Python Launcher (`py -0p`) 查找所有安装
195+
- 自动去除重复项
196+
- 如果只找到一个版本,将自动使用
197+
- 如果找到多个版本,可以选择要重置的版本
180198

181199
### 🔧 支持的虚拟环境名称
182200

env-reset.bat

Lines changed: 142 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@echo off
2+
setlocal EnableDelayedExpansion
23
chcp 65001 >nul
34
cd /d "%~dp0"
45

@@ -37,6 +38,8 @@ goto :NoVenvWarning
3738

3839
:ShowEnv
3940
:: 到这里说明已经在虚拟环境中了
41+
:: 虚拟环境中直接使用 python 命令
42+
set "SELECTED_PYTHON=python"
4043
echo.
4144
echo 当前 Python 环境:
4245
echo ------------------------------------------
@@ -47,7 +50,7 @@ for /f "tokens=*" %%i in ('where python') do (
4750
)
4851

4952
:ShowVersion
50-
python --version
53+
!SELECTED_PYTHON! --version
5154
echo ------------------------------------------
5255
echo.
5356

@@ -98,13 +101,146 @@ echo.
98101
echo 你已确认操作全局环境...
99102
echo.
100103

104+
:: 检测并选择 Python 版本
105+
goto :SelectPythonVersion
106+
107+
:SelectPythonVersion
108+
echo ==========================================
109+
echo 检测 Python 版本
110+
echo ==========================================
111+
echo.
112+
113+
:: 创建临时文件存储Python路径
114+
set TEMP_PYTHON_LIST=temp_python_list.txt
115+
if exist "%TEMP_PYTHON_LIST%" del "%TEMP_PYTHON_LIST%"
116+
117+
:: 方法1: 使用 where python 获取 PATH 中的所有 python.exe
118+
where python >nul 2>&1
119+
if not errorlevel 1 (
120+
for /f "tokens=*" %%i in ('where python 2^>nul') do (
121+
echo %%i >> "%TEMP_PYTHON_LIST%"
122+
)
123+
)
124+
125+
:: 方法2: 使用 py launcher 获取所有已安装的 Python 版本
126+
py -0p >nul 2>&1
127+
if not errorlevel 1 (
128+
for /f "tokens=*" %%i in ('py -0p 2^>nul') do (
129+
set "LINE=%%i"
130+
:: 提取最后一个token (Python路径)
131+
for %%p in (!LINE!) do set "PYTHON_PATH=%%p"
132+
:: 检查是否是.exe文件
133+
echo !PYTHON_PATH! | findstr /i "\.exe$" >nul
134+
if not errorlevel 1 (
135+
echo !PYTHON_PATH! >> "%TEMP_PYTHON_LIST%"
136+
)
137+
)
138+
)
139+
140+
:: 检查是否找到任何 Python 版本
141+
if not exist "%TEMP_PYTHON_LIST%" (
142+
echo [错误] 未找到任何 Python 安装!
143+
pause
144+
exit /b 1
145+
)
146+
147+
:: 去重并编号显示
148+
echo 检测到以下 Python 版本:
149+
echo ------------------------------------------
150+
set INDEX=0
151+
set TOTAL=0
152+
153+
:: 先计算总数并去重
154+
for /f "usebackq tokens=*" %%i in ("%TEMP_PYTHON_LIST%") do (
155+
set "CURRENT_PATH=%%i"
156+
call :CheckDuplicate "!CURRENT_PATH!"
157+
)
158+
159+
:: 如果只有一个版本,直接使用
160+
if %TOTAL%==1 (
161+
for /f "usebackq tokens=*" %%i in ("%TEMP_PYTHON_LIST%.dedup") do (
162+
set "SELECTED_PYTHON=%%i"
163+
)
164+
echo.
165+
echo 检测到唯一 Python 版本: !SELECTED_PYTHON!
166+
"!SELECTED_PYTHON!" --version 2>nul
167+
echo.
168+
del "%TEMP_PYTHON_LIST%" >nul 2>&1
169+
del "%TEMP_PYTHON_LIST%.dedup" >nul 2>&1
170+
goto :GetPackages
171+
)
172+
173+
:: 显示所有版本供用户选择
174+
set INDEX=0
175+
for /f "usebackq tokens=*" %%i in ("%TEMP_PYTHON_LIST%.dedup") do (
176+
set /a INDEX+=1
177+
set "PYTHON_PATH_!INDEX!=%%i"
178+
echo [!INDEX!] %%i
179+
"%%i" --version 2>nul | findstr /r "Python" >nul
180+
if not errorlevel 1 (
181+
for /f "tokens=*" %%v in ('"%%i" --version 2^>^&1') do echo %%v
182+
)
183+
)
184+
echo ------------------------------------------
185+
echo.
186+
187+
:AskVersion
188+
set /p PYTHON_CHOICE=请选择 Python 版本 [1-%TOTAL%]:
189+
190+
:: 验证输入
191+
echo %PYTHON_CHOICE%| findstr /r "^[0-9][0-9]*$" >nul
192+
if errorlevel 1 (
193+
echo [错误] 请输入有效的数字!
194+
goto :AskVersion
195+
)
196+
197+
if %PYTHON_CHOICE% LSS 1 (
198+
echo [错误] 请输入 1%TOTAL% 之间的数字!
199+
goto :AskVersion
200+
)
201+
202+
if %PYTHON_CHOICE% GTR %TOTAL% (
203+
echo [错误] 请输入 1%TOTAL% 之间的数字!
204+
goto :AskVersion
205+
)
206+
207+
:: 获取选定的 Python 路径
208+
call set "SELECTED_PYTHON=%%PYTHON_PATH_%PYTHON_CHOICE%%%"
209+
210+
echo.
211+
echo 已选择: !SELECTED_PYTHON!
212+
"!SELECTED_PYTHON!" --version
213+
echo.
214+
215+
:: 清理临时文件
216+
del "%TEMP_PYTHON_LIST%" >nul 2>&1
217+
del "%TEMP_PYTHON_LIST%.dedup" >nul 2>&1
218+
219+
goto :GetPackages
220+
221+
:CheckDuplicate
222+
set "CHECK_PATH=%~1"
223+
set "IS_DUP=0"
224+
225+
if exist "%TEMP_PYTHON_LIST%.dedup" (
226+
for /f "usebackq tokens=*" %%d in ("%TEMP_PYTHON_LIST%.dedup") do (
227+
if /i "%%d"=="%CHECK_PATH%" set "IS_DUP=1"
228+
)
229+
)
230+
231+
if !IS_DUP!==0 (
232+
echo %CHECK_PATH% >> "%TEMP_PYTHON_LIST%.dedup"
233+
set /a TOTAL+=1
234+
)
235+
exit /b
236+
101237
:GetPackages
102238
echo ==========================================
103239
echo 获取已安装包列表
104240
echo ==========================================
105241
echo.
106242

107-
pip freeze > temp_packages.txt 2>nul
243+
"!SELECTED_PYTHON!" -m pip freeze > temp_packages.txt 2>nul
108244

109245
if errorlevel 1 (
110246
echo [错误] 无法获取已安装包列表,pip 可能损坏
@@ -142,7 +278,7 @@ echo 正在卸载包...
142278
echo ==========================================
143279
echo.
144280

145-
pip uninstall -r temp_packages.txt -y
281+
"!SELECTED_PYTHON!" -m pip uninstall -r temp_packages.txt -y
146282

147283
if errorlevel 1 (
148284
echo.
@@ -160,14 +296,14 @@ echo ==========================================
160296
echo.
161297

162298
echo [1/2] 升级 pip...
163-
python -m pip install --upgrade pip --quiet
299+
"!SELECTED_PYTHON!" -m pip install --upgrade pip --quiet
164300

165301
if errorlevel 1 (
166302
echo [警告] pip 升级失败,尝试继续...
167303
)
168304

169305
echo [2/2] 安装 setuptools 和 wheel...
170-
pip install --upgrade setuptools wheel --quiet
306+
"!SELECTED_PYTHON!" -m pip install --upgrade setuptools wheel --quiet
171307

172308
if errorlevel 1 (
173309
echo [错误] 基础包安装失败!
@@ -182,7 +318,7 @@ echo ==========================================
182318
echo.
183319
echo 当前环境包列表:
184320
echo ------------------------------------------
185-
pip list
321+
"!SELECTED_PYTHON!" -m pip list
186322
echo ------------------------------------------
187323
echo.
188324

release_note.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)