Skip to content

Commit 001feeb

Browse files
Fix/pythonpath (#22)
Co-authored-by: Another Redbeard <[email protected]>
1 parent 0117bc8 commit 001feeb

File tree

7 files changed

+178
-17
lines changed

7 files changed

+178
-17
lines changed

.env

Lines changed: 0 additions & 2 deletions
This file was deleted.

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ labs-in-progress/
2020
# Misc
2121
*.log
2222

23-
# Exclude sensitive or generated files (except for root .env for Python)
23+
# Exclude sensitive or generated files
2424
.env
25-
!/.env
2625

2726
# Coverage data and reports
2827
.coverage

.vscode/settings.json

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
{
2-
"python.analysis.extraPaths": [
3-
"${workspaceFolder}/shared/python"
4-
],
5-
"python.analysis.completeFunctionParens": true,
2+
"plantuml.diagramsRoot": "diagrams/src",
3+
"plantuml.exportFormat": "svg",
4+
"plantuml.exportOutDir": "diagrams/out",
5+
"plantuml.java": "C:\\Program Files\\OpenJDK\\jdk-22.0.2\\bin\\java.exe",
6+
"plantuml.render": "Local",
67
"python.analysis.autoIndent": true,
8+
"python.analysis.completeFunctionParens": true,
79
"python.analysis.diagnosticSeverityOverrides": {
810
"reportDuplicateImport": "warning",
911
"reportUndefinedVariable": "information",
1012
"reportUnusedVariable": "information"
1113
},
14+
"python.analysis.extraPaths": [
15+
"${workspaceFolder}/shared/python"
16+
],
17+
"python.defaultInterpreterPath": "./venv/bin/python",
1218
"python.envFile": "${workspaceFolder}/.env",
13-
"plantuml.render": "Local",
14-
"plantuml.exportFormat": "svg",
19+
"python.terminal.activateEnvironment": true,
1520
"terminal.integrated.env.windows": {
1621
"PATH": "${env:PATH}"
17-
},
18-
"plantuml.java": "C:\\Program Files\\OpenJDK\\jdk-22.0.2\\bin\\java.exe",
19-
"plantuml.diagramsRoot": "diagrams/src",
20-
"plantuml.exportOutDir": "diagrams/out"
22+
}
2123
}

.vscode/tasks.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"label": "Setup Python Environment",
6+
"type": "shell",
7+
"command": "${config:python.pythonPath}",
8+
"args": [
9+
"setup/setup_python_path.py",
10+
"--generate-env"
11+
],
12+
"group": "build",
13+
"presentation": {
14+
"echo": true,
15+
"reveal": "always",
16+
"focus": false,
17+
"panel": "shared",
18+
"showReuseMessage": true,
19+
"clear": false
20+
},
21+
"problemMatcher": [],
22+
"detail": "Configure PYTHONPATH for cross-platform compatibility"
23+
}
24+
]
25+
}

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@ These prerequisites apply broadly across all infrastructure and samples. If ther
3434
Run through the following steps to create a Python virtual environment before doing anything else:
3535

3636
1. Open VS Code.
37-
1. Invoke the _Command Palette_ via the _View_ menu or a shortcut (on Windows: Ctrl + Shift + P).
37+
1. Invoke the _Command Palette_ via the _View_ menu or a shortcut (on Windows: Ctrl + Shift + P, on Mac: CMD + Shift + P).
3838
1. Select _Python: Create Environment_.
3939
1. Select _Venv_ as we want a local virtual environment.
4040
1. Select the desired, installed Python version.
41-
1. Check _requirements.txt_ to install the Python dependencies we need for this repo, then press _OK_. The install may take a few minutes. You can check on progress in the _OUTPUT_ window.
41+
1. Check _requirements.txt_ to install the Python dependencies we need for this repo, then press _OK_. The install may take a few minutes. You can check on progress in the _OUTPUT_ window (select `Python`).
4242
1. Verify the virtual environment is set up. You should see a new _.venv_ directory with a _pyveng.cfg_ file and the Python version you selected earlier.
43+
1. Set up the project environment by running `python setup/setup_python_path.py --generate-env` to configure the Python path.
44+
a. If for some reason the `python` command is not found, please try adding your virtual environment's `bin` or `Scripts` directory to your system's PATH variable. An example command to do this for a virtual environment named `venv` would be to run `source .venv/bin/activate`
4345

4446
The first time you run a Jupyter notebook, you'll be asked to install the Jupyter kernel package (ipykernel).
4547

@@ -174,4 +176,4 @@ The APIM team maintains an [APIM policy snippets repo](https://github.com/Azure/
174176

175177
This project has its roots in work done by [Alex Vieira](https://github.com/vieiraae) on the excellent Azure API Management [AI Gateway](https://github.com/Azure-Samples/AI-Gateway) GitHub repository. Much of the structure is similar and its reuse resulted in significant time savings. Thank you, Alex!
176178

177-
Furthermore, [Houssem Dellai](https://github.com/HoussemDellai) was instrumental in setting up a working Front Door to API Management [private connectivity lab](https://github.com/Azure-Samples/AI-Gateway/tree/main/labs/private-connectivity). This created a working baseline for one of this repository's infrastructures. Thank you, Houssem!
179+
Furthermore, [Houssem Dellai](https://github.com/HoussemDellai) was instrumental in setting up a working Front Door to API Management [private connectivity lab](https://github.com/Azure-Samples/AI-Gateway/tree/main/labs/private-connectivity). This created a working baseline for one of this repository's infrastructures. Thank you, Houssem!

setup/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Python Environment Setup
2+
3+
Configures cross-platform PYTHONPATH for APIM Samples.
4+
5+
## Usage
6+
7+
```shell
8+
python setup/setup_python_path.py --generate-env
9+
```
10+
11+
This script auto-detects the project root and generates a `.env` file that VS Code uses for Python path configuration. If for some reason the `python` command is not found, please try adding your virtual environment's `bin` or `Scripts` directory to your system's PATH variable. An example command to do this for a virtual environment named `venv` is:
12+
13+
```shell
14+
source .venv/bin/activate
15+
```

setup/setup_python_path.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
Cross-platform PYTHONPATH setup for APIM Samples.
5+
6+
This script automatically detects the project root and configures PYTHONPATH
7+
to include shared Python modules. Cross-platform compatibility is achieved by:
8+
- Using pathlib.Path for all file operations (handles Windows/Unix path separators)
9+
- Using absolute paths (eliminates relative path issues across platforms)
10+
- Using UTF-8 encoding explicitly (ensures consistent file encoding)
11+
- Using Python's sys.path for runtime PYTHONPATH configuration
12+
"""
13+
14+
import sys
15+
from pathlib import Path # Cross-platform path handling (Windows: \, Unix: /)
16+
17+
18+
def get_project_root() -> Path:
19+
"""
20+
Get the absolute path to the project root directory.
21+
22+
Cross-platform strategy:
23+
- Uses pathlib.Path for consistent path operations across OS
24+
- Searches upward from script location to find project indicators
25+
- Returns absolute paths that work on Windows, macOS, and Linux
26+
27+
Returns:
28+
Path: Absolute path to project root directory
29+
"""
30+
31+
# Start from script's parent directory (since we're in setup/ folder)
32+
# Path(__file__).resolve() gives absolute path, .parent.parent goes up two levels
33+
start_path = Path(__file__).resolve().parent.parent
34+
35+
# Project root indicators - files that should exist at project root
36+
# These help identify the correct directory regardless of where script is run
37+
indicators = ['README.md', 'requirements.txt', 'bicepconfig.json']
38+
current_path = start_path
39+
40+
# Walk up the directory tree until we find all indicators or reach filesystem root
41+
while current_path != current_path.parent: # Stop at filesystem root
42+
# Check if all indicator files exist in current directory
43+
if all((current_path / indicator).exists() for indicator in indicators):
44+
return current_path
45+
current_path = current_path.parent
46+
47+
# Fallback: if indicators not found, assume parent of script directory is project root
48+
# This handles cases where the project structure might be different
49+
return Path(__file__).resolve().parent.parent
50+
51+
52+
def setup_python_path() -> None:
53+
"""
54+
Add shared Python modules to PYTHONPATH for runtime import resolution.
55+
56+
This modifies sys.path in the current Python session to enable imports
57+
from the shared/python directory. Cross-platform compatibility:
58+
- Uses pathlib for path construction (handles OS-specific separators)
59+
- Converts to string only when needed for sys.path compatibility
60+
- Uses sys.path.insert(0, ...) to prioritize our modules
61+
"""
62+
63+
project_root = get_project_root()
64+
# Use pathlib's / operator for cross-platform path joining
65+
shared_python_path = project_root / 'shared' / 'python'
66+
67+
if shared_python_path.exists():
68+
# Convert Path object to string for sys.path compatibility
69+
shared_path_str = str(shared_python_path)
70+
71+
# Check if path is already in sys.path to avoid duplicates
72+
if shared_path_str not in sys.path:
73+
# Insert at beginning to prioritize our modules over system modules
74+
sys.path.insert(0, shared_path_str)
75+
print(f"Added to PYTHONPATH: {shared_path_str}")
76+
77+
78+
def generate_env_file() -> None:
79+
"""
80+
Generate .env file with cross-platform absolute paths for VS Code integration.
81+
Creates a .env file that VS Code's Python extension reads to configure
82+
the Python environment. Cross-platform features:
83+
- Uses absolute paths (no relative path issues)
84+
- Explicit UTF-8 encoding (consistent across platforms)
85+
- pathlib handles path separators automatically (\\ on Windows, / on Unix)
86+
- Works with VS Code's python.envFile setting
87+
"""
88+
89+
project_root = get_project_root()
90+
shared_python_path = project_root / 'shared' / 'python'
91+
92+
# Create .env file content with absolute paths
93+
# These paths will be automatically correct for the current platform
94+
env_content = f"""# Auto-generated PYTHONPATH for VS Code - Run 'python setup/setup_python_path.py' to regenerate
95+
PROJECT_ROOT={project_root}
96+
PYTHONPATH={shared_python_path}
97+
"""
98+
99+
env_file_path = project_root / '.env'
100+
101+
# Use explicit UTF-8 encoding for cross-platform text file compatibility
102+
# This ensures the file reads correctly on all operating systems
103+
with open(env_file_path, 'w', encoding='utf-8') as f:
104+
f.write(env_content)
105+
106+
print()
107+
print(f"Generated .env file : {env_file_path}")
108+
print(f"PROJECT_ROOT : {project_root}")
109+
print(f"PYTHONPATH : {shared_python_path}\n")
110+
print("All done!\n")
111+
112+
113+
# Script entry point - handles command-line arguments
114+
if __name__ == "__main__":
115+
# Check for --generate-env flag to create .env file for VS Code
116+
if len(sys.argv) > 1 and sys.argv[1] == "--generate-env":
117+
generate_env_file()
118+
else:
119+
# Default behavior: modify current session's PYTHONPATH
120+
setup_python_path()

0 commit comments

Comments
 (0)