Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .env

This file was deleted.

3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ labs-in-progress/
# Misc
*.log

# Exclude sensitive or generated files (except for root .env for Python)
# Exclude sensitive or generated files
.env
!/.env

# Coverage data and reports
.coverage
Expand Down
22 changes: 12 additions & 10 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
{
"python.analysis.extraPaths": [
"${workspaceFolder}/shared/python"
],
"python.analysis.completeFunctionParens": true,
"plantuml.diagramsRoot": "diagrams/src",
"plantuml.exportFormat": "svg",
"plantuml.exportOutDir": "diagrams/out",
"plantuml.java": "C:\\Program Files\\OpenJDK\\jdk-22.0.2\\bin\\java.exe",
"plantuml.render": "Local",
"python.analysis.autoIndent": true,
"python.analysis.completeFunctionParens": true,
"python.analysis.diagnosticSeverityOverrides": {
"reportDuplicateImport": "warning",
"reportUndefinedVariable": "information",
"reportUnusedVariable": "information"
},
"python.analysis.extraPaths": [
"${workspaceFolder}/shared/python"
],
"python.defaultInterpreterPath": "./venv/bin/python",
"python.envFile": "${workspaceFolder}/.env",
"plantuml.render": "Local",
"plantuml.exportFormat": "svg",
"python.terminal.activateEnvironment": true,
"terminal.integrated.env.windows": {
"PATH": "${env:PATH}"
},
"plantuml.java": "C:\\Program Files\\OpenJDK\\jdk-22.0.2\\bin\\java.exe",
"plantuml.diagramsRoot": "diagrams/src",
"plantuml.exportOutDir": "diagrams/out"
}
}
25 changes: 25 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Setup Python Environment",
"type": "shell",
"command": "${config:python.pythonPath}",
"args": [
"setup/setup_python_path.py",
"--generate-env"
],
"group": "build",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
},
"problemMatcher": [],
"detail": "Configure PYTHONPATH for cross-platform compatibility"
}
]
}
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,14 @@ These prerequisites apply broadly across all infrastructure and samples. If ther
Run through the following steps to create a Python virtual environment before doing anything else:

1. Open VS Code.
1. Invoke the _Command Palette_ via the _View_ menu or a shortcut (on Windows: Ctrl + Shift + P).
1. Invoke the _Command Palette_ via the _View_ menu or a shortcut (on Windows: Ctrl + Shift + P, on Mac: CMD + Shift + P).
1. Select _Python: Create Environment_.
1. Select _Venv_ as we want a local virtual environment.
1. Select the desired, installed Python version.
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.
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`).
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.
1. Set up the project environment by running `python setup/setup_python_path.py --generate-env` to configure the Python path.
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`

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

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

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!

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!
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!
15 changes: 15 additions & 0 deletions setup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Python Environment Setup

Configures cross-platform PYTHONPATH for APIM Samples.

## Usage

```shell
python setup/setup_python_path.py --generate-env
```

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:

```shell
source .venv/bin/activate
```
120 changes: 120 additions & 0 deletions setup/setup_python_path.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/env python3

"""
Cross-platform PYTHONPATH setup for APIM Samples.

This script automatically detects the project root and configures PYTHONPATH
to include shared Python modules. Cross-platform compatibility is achieved by:
- Using pathlib.Path for all file operations (handles Windows/Unix path separators)
- Using absolute paths (eliminates relative path issues across platforms)
- Using UTF-8 encoding explicitly (ensures consistent file encoding)
- Using Python's sys.path for runtime PYTHONPATH configuration
"""

import sys
from pathlib import Path # Cross-platform path handling (Windows: \, Unix: /)


def get_project_root() -> Path:
"""
Get the absolute path to the project root directory.

Cross-platform strategy:
- Uses pathlib.Path for consistent path operations across OS
- Searches upward from script location to find project indicators
- Returns absolute paths that work on Windows, macOS, and Linux

Returns:
Path: Absolute path to project root directory
"""

# Start from script's parent directory (since we're in setup/ folder)
# Path(__file__).resolve() gives absolute path, .parent.parent goes up two levels
start_path = Path(__file__).resolve().parent.parent

# Project root indicators - files that should exist at project root
# These help identify the correct directory regardless of where script is run
indicators = ['README.md', 'requirements.txt', 'bicepconfig.json']
current_path = start_path

# Walk up the directory tree until we find all indicators or reach filesystem root
while current_path != current_path.parent: # Stop at filesystem root
# Check if all indicator files exist in current directory
if all((current_path / indicator).exists() for indicator in indicators):
return current_path
current_path = current_path.parent

# Fallback: if indicators not found, assume parent of script directory is project root
# This handles cases where the project structure might be different
return Path(__file__).resolve().parent.parent


def setup_python_path() -> None:
"""
Add shared Python modules to PYTHONPATH for runtime import resolution.

This modifies sys.path in the current Python session to enable imports
from the shared/python directory. Cross-platform compatibility:
- Uses pathlib for path construction (handles OS-specific separators)
- Converts to string only when needed for sys.path compatibility
- Uses sys.path.insert(0, ...) to prioritize our modules
"""

project_root = get_project_root()
# Use pathlib's / operator for cross-platform path joining
shared_python_path = project_root / 'shared' / 'python'

if shared_python_path.exists():
# Convert Path object to string for sys.path compatibility
shared_path_str = str(shared_python_path)

# Check if path is already in sys.path to avoid duplicates
if shared_path_str not in sys.path:
# Insert at beginning to prioritize our modules over system modules
sys.path.insert(0, shared_path_str)
print(f"Added to PYTHONPATH: {shared_path_str}")


def generate_env_file() -> None:
"""
Generate .env file with cross-platform absolute paths for VS Code integration.
Creates a .env file that VS Code's Python extension reads to configure
the Python environment. Cross-platform features:
- Uses absolute paths (no relative path issues)
- Explicit UTF-8 encoding (consistent across platforms)
- pathlib handles path separators automatically (\\ on Windows, / on Unix)
- Works with VS Code's python.envFile setting
"""

project_root = get_project_root()
shared_python_path = project_root / 'shared' / 'python'

# Create .env file content with absolute paths
# These paths will be automatically correct for the current platform
env_content = f"""# Auto-generated PYTHONPATH for VS Code - Run 'python setup/setup_python_path.py' to regenerate
PROJECT_ROOT={project_root}
PYTHONPATH={shared_python_path}
"""

env_file_path = project_root / '.env'

# Use explicit UTF-8 encoding for cross-platform text file compatibility
# This ensures the file reads correctly on all operating systems
with open(env_file_path, 'w', encoding='utf-8') as f:
f.write(env_content)

print()
print(f"Generated .env file : {env_file_path}")
print(f"PROJECT_ROOT : {project_root}")
print(f"PYTHONPATH : {shared_python_path}\n")
print("All done!\n")


# Script entry point - handles command-line arguments
if __name__ == "__main__":
# Check for --generate-env flag to create .env file for VS Code
if len(sys.argv) > 1 and sys.argv[1] == "--generate-env":
generate_env_file()
else:
# Default behavior: modify current session's PYTHONPATH
setup_python_path()