Skip to content

Commit d20d357

Browse files
committed
feat: add search feature to env manager UI
1 parent 7cea36b commit d20d357

File tree

12 files changed

+779
-104
lines changed

12 files changed

+779
-104
lines changed

README.md

Lines changed: 57 additions & 51 deletions
Large diffs are not rendered by default.
Lines changed: 354 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,354 @@
1+
# Search Paths and Glob Patterns
2+
3+
This guide explains how to configure where the Python Environments extension searches for Python environments using search paths and glob patterns. By the end, you'll understand how to effectively customize environment discovery to match your development workflow.
4+
5+
## Overview
6+
7+
By default, the Python Environments extension automatically discovers environments in well-known locations like the workspace folders, common virtual environment directories, and system Python installations. However, you can customize where the extension searches using two settings:
8+
9+
- **`python-envs.globalSearchPaths`**: Global search paths applied to all workspaces
10+
- **`python-envs.workspaceSearchPaths`**: Search paths specific to the current workspace
11+
12+
Both settings support **glob patterns**, which allow you to specify flexible search patterns that match multiple directories.
13+
14+
## When to Use Custom Search Paths
15+
16+
Consider configuring custom search paths when:
17+
18+
| Scenario | Example |
19+
| ------------------------------- | -------------------------------------------------------------- |
20+
| Centralized environment storage | All environments stored in `~/python-envs/` |
21+
| Mono-repo structure | Multiple projects with nested `.venv` folders |
22+
| Non-standard locations | Environments in `/opt/`, network drives, or custom directories |
23+
| Team conventions | Standardized environment naming patterns |
24+
| Testing scenarios | Temporary environments in test directories |
25+
26+
## Configuring Search Paths
27+
28+
### Global search paths
29+
30+
Global search paths apply across all your VS Code workspaces. Use these for environment locations that are consistent across projects.
31+
32+
1. Open Settings (`Cmd+,` on macOS, `Ctrl+,` on Windows/Linux).
33+
2. Search for `python-envs.globalSearchPaths`.
34+
3. Click **Add Item** to add a new path.
35+
4. Enter an absolute path or glob pattern.
36+
37+
Example configuration:
38+
39+
```json
40+
{
41+
"python-envs.globalSearchPaths": [
42+
"/Users/username/python-envs",
43+
"/Users/username/projects/*/venv",
44+
"/opt/python-environments/**"
45+
]
46+
}
47+
```
48+
49+
### Workspace search paths
50+
51+
Workspace search paths apply only to the current workspace. Use these for project-specific environment locations.
52+
53+
1. Open Settings (`Cmd+,` on macOS, `Ctrl+,` on Windows/Linux).
54+
2. Switch to **Workspace** scope (not User).
55+
3. Search for `python-envs.workspaceSearchPaths`.
56+
4. Click **Add Item** to add a new path.
57+
5. Enter a relative path (from workspace root) or absolute path.
58+
59+
Example configuration:
60+
61+
```json
62+
{
63+
"python-envs.workspaceSearchPaths": [".venv", "tests/**/.venv", "services/*/env"]
64+
}
65+
```
66+
67+
> **Note**: Relative paths in `workspaceSearchPaths` are resolved from the workspace root directory.
68+
69+
## Glob Pattern Syntax
70+
71+
Glob patterns provide a flexible way to match multiple directories using wildcards. The extension supports standard glob syntax:
72+
73+
### Basic wildcards
74+
75+
| Pattern | Matches | Example |
76+
| ------- | --------------------------------------------------------- | ------------------------------------------------------------------ |
77+
| `*` | Any sequence of characters within a single path component | `envs/*` matches `envs/project1` but not `envs/nested/project2` |
78+
| `**` | Any sequence of path components (recursive) | `projects/**/.venv` matches `.venv` at any depth under `projects/` |
79+
| `?` | Any single character | `project?` matches `project1`, `projectA` |
80+
| `[...]` | Any character inside the brackets | `project[0-9]` matches `project0` through `project9` |
81+
82+
### Pattern examples
83+
84+
```json
85+
{
86+
"python-envs.globalSearchPaths": [
87+
// Specific directory (no wildcard needed)
88+
"/Users/username/main-env",
89+
90+
// All direct subdirectories of envs/
91+
"/Users/username/envs/*",
92+
93+
// All .venv directories at any depth
94+
"/Users/username/projects/**/.venv",
95+
96+
// All venv directories at any depth
97+
"/Users/username/projects/**/venv",
98+
99+
// Numbered project directories
100+
"/Users/username/project[0-9]",
101+
102+
// Multiple levels with wildcards
103+
"/Users/username/clients/*/projects/*/env"
104+
]
105+
}
106+
```
107+
108+
## How Glob Expansion Works
109+
110+
When you specify a glob pattern, the extension:
111+
112+
1. **Expands the pattern** to find all matching directories
113+
2. **Filters to directories only** (files are ignored unless they're Python executables)
114+
3. **Searches each directory** recursively for Python environments
115+
116+
### Example expansion
117+
118+
Given the pattern `/Users/username/projects/**/.venv`:
119+
120+
```
121+
projects/
122+
├── backend/
123+
│ └── .venv/ ← Matches
124+
├── frontend/
125+
│ └── scripts/
126+
│ └── .venv/ ← Matches
127+
└── ml-pipeline/
128+
├── training/
129+
│ └── .venv/ ← Matches
130+
└── inference/
131+
└── .venv/ ← Matches
132+
```
133+
134+
All four `.venv` directories are added to the search paths.
135+
136+
## Performance Considerations
137+
138+
⚠️ **Important**: Glob patterns can significantly impact discovery performance if used incorrectly.
139+
140+
### What to avoid
141+
142+
| Pattern | Problem | Impact |
143+
| -------------------- | ------------------------------ | -------------------------- |
144+
| `/**` | Searches the entire filesystem | Very slow, may time out |
145+
| `/Users/username/**` | Searches all user files | Extremely slow |
146+
| `path/to/project/**` | Lists every subdirectory | Redundant, slows discovery |
147+
148+
### Best practices
149+
150+
**DO**: Use specific patterns
151+
152+
```json
153+
{
154+
"python-envs.workspaceSearchPaths": [
155+
".venv", // Root-level .venv
156+
"tests/**/.venv", // .venv directories under tests/
157+
"services/*/env" // env directories one level under services/
158+
]
159+
}
160+
```
161+
162+
**DON'T**: Use overly broad patterns
163+
164+
```json
165+
{
166+
"python-envs.workspaceSearchPaths": [
167+
"**", // Every directory! Very slow
168+
"/Users/username/**" // Entire home directory! Extremely slow
169+
]
170+
}
171+
```
172+
173+
### Understanding `**` vs. no pattern
174+
175+
| Configuration | Behavior |
176+
| ----------------------- | ------------------------------------------------------------------------------ |
177+
| `"/path/to/project"` | ✅ Extension searches this directory recursively for environments |
178+
| `"/path/to/project/**"` | ⚠️ Extension treats EVERY subdirectory as a separate search path (inefficient) |
179+
180+
> **Tip**: In most cases, you don't need `**` alone. Just specify the root directory and let the extension search recursively.
181+
182+
## Common Use Cases
183+
184+
### Find all .venv directories in a mono-repo
185+
186+
```json
187+
{
188+
"python-envs.workspaceSearchPaths": ["**/.venv"]
189+
}
190+
```
191+
192+
This finds `.venv` directories at any depth without treating every subdirectory as a search path.
193+
194+
### Centralized environment storage
195+
196+
```json
197+
{
198+
"python-envs.globalSearchPaths": ["/Users/username/python-environments/*"]
199+
}
200+
```
201+
202+
This searches all direct subdirectories of your centralized environment folder.
203+
204+
### Team convention: environments named "env" or "venv"
205+
206+
```json
207+
{
208+
"python-envs.workspaceSearchPaths": ["**/env", "**/venv"]
209+
}
210+
```
211+
212+
### Multiple project structures
213+
214+
```json
215+
{
216+
"python-envs.workspaceSearchPaths": [
217+
".venv", // Root workspace environment
218+
"backend/.venv", // Backend service environment
219+
"services/*/venv", // Service-specific environments
220+
"tests/**/test-env" // Test environments at any depth
221+
]
222+
}
223+
```
224+
225+
### Development and testing environments
226+
227+
```json
228+
{
229+
"python-envs.globalSearchPaths": ["/opt/python/dev/*", "/opt/python/test/*", "/Users/username/temp/envs/*"]
230+
}
231+
```
232+
233+
## Integration with Legacy Settings
234+
235+
The extension merges custom search paths with legacy Python extension settings for backward compatibility.
236+
237+
### Settings that are merged
238+
239+
| Legacy Setting | Equivalent Modern Setting |
240+
| -------------------- | ------------------------------------------- |
241+
| `python.venvPath` | Merged into `python-envs.globalSearchPaths` |
242+
| `python.venvFolders` | Merged into `python-envs.globalSearchPaths` |
243+
244+
If you have both configured, the extension combines all paths into one search list.
245+
246+
### Migration example
247+
248+
**Before** (legacy Python extension):
249+
250+
```json
251+
{
252+
"python.venvPath": "/Users/username/envs",
253+
"python.venvFolders": ["venv", ".venv"]
254+
}
255+
```
256+
257+
**After** (modern Python Environments):
258+
259+
```json
260+
{
261+
"python-envs.globalSearchPaths": ["/Users/username/envs/*", "**/venv", "**/.venv"]
262+
}
263+
```
264+
265+
> **Note**: You can continue using legacy settings, but migrating to `python-envs.globalSearchPaths` provides more flexibility with glob patterns.
266+
267+
## Troubleshooting
268+
269+
### Environments not appearing
270+
271+
If your environments aren't discovered:
272+
273+
1. **Verify paths are absolute** (for global search paths) or relative to workspace root (for workspace search paths)
274+
2. **Check path separators**: Use `/` even on Windows
275+
3. **Test without glob patterns first**: Start with a simple directory path, then add patterns
276+
4. **Check extension logs**: Open **Output** panel and select **Python Environments** to see discovery logs
277+
5. **Verify directory exists**: Glob patterns that match nothing are silently ignored
278+
279+
### Slow environment discovery
280+
281+
If discovery is taking too long:
282+
283+
1. **Review glob patterns**: Look for overly broad patterns like `**` or `/Users/**`
284+
2. **Be more specific**: Replace `projects/**` with `projects/**/.venv` to target specific directories
285+
3. **Reduce search paths**: Remove paths that don't contain environments
286+
4. **Use root directories**: Instead of `path/**`, use `path` and let the extension search recursively
287+
288+
### Duplicate environments
289+
290+
If environments appear multiple times:
291+
292+
1. **Check for overlapping paths**: Ensure patterns don't match the same directories
293+
2. **Remove redundant patterns**: If you specify both `projects/` and `projects/**/.venv`, the latter is sufficient
294+
3. **Review workspace vs. global settings**: Ensure you're not duplicating paths across scopes
295+
296+
## Quick Reference: Settings
297+
298+
| Setting | Scope | Description |
299+
| ---------------------------------- | ----------------- | -------------------------------------------------------------------------- |
300+
| `python-envs.globalSearchPaths` | User or Workspace | Array of absolute paths or glob patterns searched across all workspaces |
301+
| `python-envs.workspaceSearchPaths` | Workspace | Array of relative or absolute paths searched in the current workspace only |
302+
| `python.venvPath` | User or Workspace | Legacy setting merged into global search paths |
303+
| `python.venvFolders` | User or Workspace | Legacy setting merged into global search paths |
304+
305+
## Pattern Reference
306+
307+
### Quick pattern guide
308+
309+
```json
310+
{
311+
"python-envs.globalSearchPaths": [
312+
"/absolute/path", // Specific directory
313+
"/parent/*", // Direct children only
314+
"/parent/**/target", // Target directories at any depth
315+
"/parent/child[0-9]", // Numbered children
316+
"/parent/child?", // Single character wildcard
317+
"/parent/{option1,option2}/env" // Alternative branches (if supported)
318+
]
319+
}
320+
```
321+
322+
### Platform-specific examples
323+
324+
**macOS/Linux**:
325+
326+
```json
327+
{
328+
"python-envs.globalSearchPaths": [
329+
"/opt/python-envs/*",
330+
"~/.local/share/virtualenvs/*",
331+
"/usr/local/python-environments/*"
332+
]
333+
}
334+
```
335+
336+
**Windows**:
337+
338+
```json
339+
{
340+
"python-envs.globalSearchPaths": [
341+
"C:/Python/Environments/*",
342+
"C:/Users/username/python-envs/*",
343+
"D:/Development/*/venv"
344+
]
345+
}
346+
```
347+
348+
> **Note**: Use forward slashes `/` even on Windows.
349+
350+
## Related Resources
351+
352+
- [Managing Python Projects](managing-python-projects.md): Learn how to organize projects with their own environments
353+
- [Environment Management](../README.md#environment-management): Learn about creating and managing Python environments
354+
- [Settings Reference](../README.md#settings-reference): Complete list of extension settings

package.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"type": "string",
4848
"description": "%python-envs.defaultEnvManager.description%",
4949
"default": "ms-python.python:venv",
50-
"scope": "window"
50+
"scope": "application"
5151
},
5252
"python-envs.defaultPackageManager": {
5353
"type": "string",
@@ -213,6 +213,12 @@
213213
"category": "Python",
214214
"icon": "$(refresh)"
215215
},
216+
{
217+
"command": "python-envs.managerSearch",
218+
"title": "%python-envs.managerSearch.title%",
219+
"category": "Python",
220+
"icon": "$(search)"
221+
},
216222
{
217223
"command": "python-envs.refreshPackages",
218224
"title": "%python-envs.refreshPackages.title%",
@@ -545,6 +551,11 @@
545551
"group": "navigation",
546552
"when": "view == env-managers"
547553
},
554+
{
555+
"command": "python-envs.managerSearch",
556+
"group": "navigation",
557+
"when": "view == env-managers"
558+
},
548559
{
549560
"command": "python-envs.refreshAllManagers",
550561
"group": "navigation",

package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"python-envs.setEnvSelected.title": "Set!",
3232
"python-envs.remove.title": "Delete Environment",
3333
"python-envs.refreshAllManagers.title": "Refresh All Environment Managers",
34+
"python-envs.managerSearch.title": "Manage Environment Search",
3435
"python-envs.refreshPackages.title": "Refresh Packages List",
3536
"python-envs.packages.title": "Manage Packages",
3637
"python-envs.clearCache.title": "Clear Cache",

0 commit comments

Comments
 (0)