Skip to content

Commit ee33f72

Browse files
Fix uv check (#134)
1 parent f6cf00a commit ee33f72

6 files changed

Lines changed: 451 additions & 49 deletions

File tree

.github/workflows/python-tests.yml

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ permissions:
1515
jobs:
1616
test:
1717
runs-on: ubuntu-latest
18+
env:
19+
PYTHONPATH: ${{ github.workspace }}/shared/python:${{ github.workspace }}
1820
strategy:
1921
matrix:
2022
python-version: [ '3.12', '3.13', '3.14' ]
@@ -45,7 +47,7 @@ jobs:
4547
run: |
4648
mkdir -p tests/python/pylint/reports
4749
# Use python -m pylint and tee to ensure output is captured and visible in logs
48-
PYTHONPATH=$(pwd) uv run python -m pylint --rcfile .pylintrc infrastructure samples setup shared 2>&1 | tee tests/python/pylint/reports/latest.txt
50+
uv run python -m pylint --rcfile .pylintrc infrastructure samples setup shared 2>&1 | tee tests/python/pylint/reports/latest.txt
4951
5052
- name: Upload pylint reports
5153
uses: actions/upload-artifact@v4
@@ -62,7 +64,7 @@ jobs:
6264
- name: Run pytest with coverage and generate JUnit XML
6365
id: pytest
6466
run: |
65-
PYTHONPATH=$(pwd) COVERAGE_FILE=tests/python/.coverage-${{ matrix.python-version }} uv run pytest --cov=shared/python --cov-config=tests/python/.coveragerc --cov-report=html:tests/python/htmlcov-${{ matrix.python-version }} --cov-report=term-missing --junitxml=tests/python/junit-${{ matrix.python-version }}.xml tests/python/
67+
COVERAGE_FILE=tests/python/.coverage-${{ matrix.python-version }} uv run pytest --cov=shared/python --cov-config=tests/python/.coveragerc --cov-report=html:tests/python/htmlcov-${{ matrix.python-version }} --cov-report=term-missing --junitxml=tests/python/junit-${{ matrix.python-version }}.xml tests/python/
6668
6769
- name: Upload coverage HTML report
6870
uses: actions/upload-artifact@v4
@@ -95,7 +97,7 @@ jobs:
9597
9698
# Coverage Percentage
9799
if [ -f "tests/python/.coverage-${{ matrix.python-version }}" ]; then
98-
TOTAL_COV=$(PYTHONPATH=$(pwd) COVERAGE_FILE=tests/python/.coverage-${{ matrix.python-version }} uv run python -m coverage report | grep TOTAL | awk '{print $NF}')
100+
TOTAL_COV=$(COVERAGE_FILE=tests/python/.coverage-${{ matrix.python-version }} uv run python -m coverage report | grep TOTAL | awk '{print $NF}')
99101
echo "coverage=$TOTAL_COV" >> "$GITHUB_OUTPUT"
100102
else
101103
echo "coverage=N/A" >> "$GITHUB_OUTPUT"
@@ -106,7 +108,6 @@ jobs:
106108
if: github.event_name == 'pull_request'
107109
uses: marocchino/sticky-pull-request-comment@v2
108110
with:
109-
repo-token: ${{ secrets.GITHUB_TOKEN }}
110111
header: python-results-${{ matrix.python-version }}
111112
message: |
112113
## 🐍 Python ${{ matrix.python-version }} Results
@@ -121,13 +122,17 @@ jobs:
121122
122123
- name: Generate Job Summary
123124
run: |
125+
PYLINT_SCORE="${{ steps.metrics.outputs.pylint_score }}"
126+
PYTEST_OUTCOME="${{ steps.pytest.outcome }}"
127+
COVERAGE="${{ steps.metrics.outputs.coverage }}"
128+
124129
echo "## 🐍 Python ${{ matrix.python-version }} Execution Summary" >> $GITHUB_STEP_SUMMARY
125130
echo "" >> $GITHUB_STEP_SUMMARY
126131
echo "| Category | Status | Detail |" >> $GITHUB_STEP_SUMMARY
127132
echo "| :--- | :---: | :--- |" >> $GITHUB_STEP_SUMMARY
128-
echo "| **Pylint** | ${{ steps.pylint.outcome == 'success' && '✅' || '⚠️' }} | Score: `${{ steps.metrics.outputs.pylint_score }}` |" >> $GITHUB_STEP_SUMMARY
129-
echo "| **Pytest** | ${{ steps.pytest.outcome == 'success' && '✅' || '❌' }} | Outcome: `${{ steps.pytest.outcome }}` |" >> $GITHUB_STEP_SUMMARY
130-
echo "| **Coverage** | 📊 | Total: `${{ steps.metrics.outputs.coverage }}` |" >> $GITHUB_STEP_SUMMARY
133+
echo "| **Pylint** | ${{ steps.pylint.outcome == 'success' && '✅' || '⚠️' }} | Score: \`${PYLINT_SCORE:-N/A}\` |" >> $GITHUB_STEP_SUMMARY
134+
echo "| **Pytest** | ${{ steps.pytest.outcome == 'success' && '✅' || '❌' }} | Outcome: \`${PYTEST_OUTCOME:-N/A}\` |" >> $GITHUB_STEP_SUMMARY
135+
echo "| **Coverage** | 📊 | Total: \`${COVERAGE:-N/A}\` |" >> $GITHUB_STEP_SUMMARY
131136
echo "" >> $GITHUB_STEP_SUMMARY
132137
echo "---" >> $GITHUB_STEP_SUMMARY
133138

setup/local_setup.py

Lines changed: 138 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,32 @@ def check_bicep_cli_installed():
9999
print("❌ Azure Bicep CLI is not installed. Install with: az bicep install")
100100
return False
101101

102+
def check_uv_installed():
103+
"""Check if uv is installed and provide installation guidance if not."""
104+
uv_path = shutil.which('uv')
105+
if not uv_path:
106+
print("❌ uv is not installed.")
107+
print(" uv provides fast Python package management and is recommended for this project.")
108+
print(" Installation instructions:")
109+
if os.name == 'nt': # Windows
110+
print(" • PowerShell: irm https://astral.sh/uv/install.ps1 | iex")
111+
print(" • Or download from: https://github.com/astral-sh/uv/releases")
112+
else: # macOS/Linux
113+
print(" • curl -LsSf https://astral.sh/uv/install.sh | sh")
114+
print(" • Official docs: https://docs.astral.sh/uv/getting-started/installation/")
115+
return False
116+
117+
try:
118+
result = subprocess.run([uv_path, '--version'], capture_output=True, text=True, check=True)
119+
version = result.stdout.strip()
120+
print(f"✅ uv is installed ({version})")
121+
return True
122+
except subprocess.CalledProcessError:
123+
print("❌ uv is installed but not functioning correctly")
124+
print(" Try reinstalling: https://docs.astral.sh/uv/getting-started/installation/")
125+
return False
126+
127+
102128
def check_azure_providers_registered():
103129
"""Check if required Azure resource providers are registered in the current subscription."""
104130
az_path = shutil.which('az') or shutil.which('az.cmd') or shutil.which('az.bat')
@@ -529,54 +555,139 @@ def setup_complete_environment():
529555

530556
print("🚀 Setting up complete APIM Samples environment...\n")
531557

532-
# Step 1: Check Azure prerequisites
533-
print("1/5) Checking Azure prerequisites...\n")
534-
azure_cli_ok = check_azure_cli_installed()
535-
bicep_ok = check_bicep_cli_installed()
536-
providers_ok = check_azure_providers_registered()
558+
# Step 1: Check uv installation (recommended but not blocking)
559+
print("1/7) Checking uv installation (recommended)...\n")
560+
uv_ok = False
561+
try:
562+
uv_ok = check_uv_installed()
563+
except Exception as e:
564+
print(f"⚠️ Error checking uv installation: {e}")
565+
print(" Continuing with setup...")
537566

538-
if not (azure_cli_ok and bicep_ok and providers_ok):
539-
print("\n⚠️ Some Azure prerequisites are missing. Please address the issues above and re-run this script.")
540-
return
567+
# Step 2: Check Azure prerequisites
568+
print("\n2/7) Checking Azure prerequisites...\n")
569+
azure_cli_ok = False
570+
bicep_ok = False
571+
providers_ok = False
541572

542-
# Step 2: Generate .env file
543-
print("\n2/5) Generating .env file for Python path configuration...")
544-
generate_env_file()
573+
try:
574+
azure_cli_ok = check_azure_cli_installed()
575+
except Exception as e:
576+
print(f"⚠️ Error checking Azure CLI: {e}")
577+
print(" Continuing with setup...")
545578

546-
# Step 3: Register Jupyter kernel
547-
print("3/5) Registering standardized Jupyter kernel...\n")
548-
kernel_success = install_jupyter_kernel()
579+
try:
580+
bicep_ok = check_bicep_cli_installed()
581+
except Exception as e:
582+
print(f"⚠️ Error checking Bicep CLI: {e}")
583+
print(" Continuing with setup...")
549584

550-
# Step 4: Configure VS Code settings with minimal, merged defaults
551-
print("\n4/5) Configuring VS Code workspace settings...\n")
552-
vscode_success = create_vscode_settings()
585+
try:
586+
providers_ok = check_azure_providers_registered()
587+
except Exception as e:
588+
print(f"⚠️ Error checking Azure providers: {e}")
589+
print(" Continuing with setup...")
553590

554-
# Step 5: Enforce kernel consistency
555-
print("\n5/5) Enforcing kernel consistency for future reliability...\n")
556-
consistency_success = force_kernel_consistency()
591+
if not (azure_cli_ok and bicep_ok):
592+
print("\n⚠️ Some Azure prerequisites are missing. Please address the issues above.")
593+
print(" Continuing with environment setup...\n")
594+
595+
# Step 3: Generate .env file
596+
print("\n3/7) Generating .env file for Python path configuration...")
597+
env_success = False
598+
try:
599+
generate_env_file()
600+
env_success = True
601+
except Exception as e:
602+
print(f"❌ Failed to generate .env file: {e}")
603+
print(" Continuing with setup...")
604+
605+
# Step 4: Register Jupyter kernel
606+
print("\n4/7) Registering standardized Jupyter kernel...\n")
607+
kernel_success = False
608+
try:
609+
kernel_success = install_jupyter_kernel()
610+
except Exception as e:
611+
print(f"❌ Error installing Jupyter kernel: {e}")
612+
print(" Continuing with setup...")
613+
614+
# Step 5: Configure VS Code settings with minimal, merged defaults
615+
print("\n5/7) Configuring VS Code workspace settings...\n")
616+
vscode_success = False
617+
try:
618+
vscode_success = create_vscode_settings()
619+
except Exception as e:
620+
print(f"❌ Error creating VS Code settings: {e}")
621+
print(" Continuing with setup...")
622+
623+
# Step 6: Enforce kernel consistency
624+
print("\n6/7) Enforcing kernel consistency for future reliability...\n")
625+
consistency_success = False
626+
try:
627+
consistency_success = force_kernel_consistency()
628+
except Exception as e:
629+
print(f"❌ Error enforcing kernel consistency: {e}")
630+
print(" Continuing with setup...")
631+
632+
# Step 7: Run uv sync if uv is available
633+
print("\n7/7) Syncing dependencies with uv (if available)...\n")
634+
sync_success = False
635+
if uv_ok:
636+
try:
637+
uv_path = shutil.which('uv')
638+
if uv_path:
639+
subprocess.run([uv_path, 'sync'], check=True, capture_output=True, text=True)
640+
print("✅ Dependencies synced successfully with uv")
641+
sync_success = True
642+
else:
643+
print("⚠️ uv reported installed but executable not found in PATH; skipping sync")
644+
print(" Install uv and run 'uv sync' for dependency management")
645+
except subprocess.CalledProcessError as e:
646+
print(f"⚠️ Failed to sync dependencies with uv: {e}")
647+
print(" You can manually run 'uv sync' after setup")
648+
except Exception as e:
649+
print(f"⚠️ Error during uv sync: {e}")
650+
print(" You can manually run 'uv sync' after setup")
651+
else:
652+
print("⚠️ Skipping dependency sync (uv not available)")
653+
print(" Install uv and run 'uv sync' for dependency management")
557654

558655
# Summary
559656
print("\n" + "="*50)
560657
print("📋 Setup Summary:")
561-
print(" ✅ Azure CLI and Bicep: Available")
562-
print(" ✅ Azure resource providers: Registered")
563-
print(" ✅ Python path configuration: Complete")
658+
print(f" {'✅' if uv_ok else '⚠️ '} uv installation: {'Available' if uv_ok else 'Not installed (recommended)'}")
659+
print(f" {'✅' if azure_cli_ok else '❌'} Azure CLI: {'Available' if azure_cli_ok else 'Not installed'}")
660+
print(f" {'✅' if bicep_ok else '❌'} Azure Bicep: {'Available' if bicep_ok else 'Not installed'}")
661+
print(f" {'✅' if providers_ok else '⚠️ '} Azure resource providers: {'Registered' if providers_ok else 'Not all registered'}")
662+
print(f" {'✅' if env_success else '❌'} Python path configuration: {'Complete' if env_success else 'Failed'}")
564663
print(f" {'✅' if kernel_success else '❌'} Jupyter kernel registration: {'Complete' if kernel_success else 'Failed'}")
565664
print(f" {'✅' if vscode_success else '❌'} VS Code settings: {'Complete' if vscode_success else 'Failed'}")
566665
print(f" {'✅' if consistency_success else '❌'} Kernel trust refresh: {'Complete' if consistency_success else 'Failed'}")
666+
print(f" {'✅' if sync_success else '⚠️ '} Dependency sync: {'Complete' if sync_success else 'Skipped or failed'}")
567667

568-
if kernel_success and vscode_success and consistency_success:
569-
print("\n🎉 Setup complete! Your local environment now matches the dev container experience.")
668+
critical_success = env_success and kernel_success and vscode_success and consistency_success
669+
670+
if critical_success:
671+
print("\n🎉 Setup complete! Your local environment is configured.")
570672
print(f" • Notebooks can use the '{KERNEL_DISPLAY_NAME}' kernel")
571673
print(" • Python modules from shared/ directory are available")
572674
print(" • VS Code is configured for optimal workflow")
573675
print(" • User customizations are preserved across reruns")
676+
if not uv_ok:
677+
print("\n⚠️ Note: uv is not installed but is recommended for faster dependency management")
678+
print(" See installation instructions above")
574679
print("\n💡 Next steps:")
575680
print(" 1. Restart VS Code to apply all settings")
576-
print(" 2. Open any notebook - it should automatically use the correct kernel")
577-
print(" 3. The kernel should remain consistent across all notebooks")
681+
if uv_ok and sync_success:
682+
print(" 2. Dependencies are synced and ready to use")
683+
elif uv_ok:
684+
print(" 2. Run 'uv sync' to install dependencies")
685+
else:
686+
print(" 2. Install uv and run 'uv sync' for dependency management")
687+
print(" 3. Open any notebook - it should automatically use the correct kernel")
578688
else:
579689
print("\n⚠️ Setup completed with some issues. Check error messages above.")
690+
print(" The environment may still be partially functional.")
580691

581692

582693
def show_help():

setup/verify_local_setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def check_uv_sync():
6767
"""Check if uv is available and sync dependencies if it is."""
6868
uv_path = shutil.which("uv")
6969
if not uv_path:
70-
return True, "uv is not installed (optional - install from https://docs.astral.sh/uv/)"
70+
return False, "Install uv for faster dependency management: https://docs.astral.sh/uv/ (or use 'Complete environment setup' in Developer CLI)"
7171

7272
venv_path = Path.cwd() / ".venv"
7373
if not venv_path.exists():

0 commit comments

Comments
 (0)