Skip to content

Commit 3d3ad1b

Browse files
committed
NeuroServe
0 parents  commit 3d3ad1b

68 files changed

Lines changed: 3724 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.flake8

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[flake8]
2+
max-line-length = 120
3+
exclude = .venv,.git,__pycache__,build,dist,*.egg-info

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto eol=lf

.github/workflows/ci-gpu.yml

Lines changed: 362 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,362 @@
1+
name: CI (Windows Self-Hosted + GPU)
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
paths:
7+
- "**.py"
8+
- "pyproject.toml"
9+
- "requirements*.txt"
10+
- ".github/workflows/ci-gpu.yml"
11+
- "app/**"
12+
- "tests/**"
13+
pull_request:
14+
branches: [ main ]
15+
workflow_dispatch:
16+
17+
permissions:
18+
contents: read
19+
20+
concurrency:
21+
group: ci-${{ github.ref }}-${{ github.workflow }}
22+
cancel-in-progress: true
23+
24+
env:
25+
PIP_DISABLE_PIP_VERSION_CHECK: "1"
26+
PIP_NO_PYTHON_VERSION_WARNING: "1"
27+
PYTHONDONTWRITEBYTECODE: "1"
28+
PYTHONUTF8: "1"
29+
PIP_CACHE_DIR: ${{ github.workspace }}\.pip-cache
30+
PY_DIR: "" # optional; discovery will override
31+
32+
defaults:
33+
run:
34+
shell: powershell
35+
36+
jobs:
37+
lint:
38+
name: Lint (ruff/flake + basic checks)
39+
runs-on: [self-hosted, Windows, X64]
40+
steps:
41+
- name: Checkout
42+
uses: actions/checkout@v4
43+
44+
- name: Ensure pip cache dir
45+
run: New-Item -ItemType Directory -Force -Path $env:PIP_CACHE_DIR | Out-Null
46+
47+
- name: Discover & use Python 3.12
48+
shell: powershell
49+
run: |
50+
$candidates = @()
51+
if ($env:PY_DIR) { $candidates += $env:PY_DIR }
52+
$candidates += @(
53+
"R:\tools\python\3.12.10\x64",
54+
"R:\tools\python\3.12\x64",
55+
"C:\Python312",
56+
"C:\Python312\amd64",
57+
"$env:LocalAppData\Programs\Python\Python312"
58+
)
59+
$py = $null
60+
$pyLauncher = Get-Command py.exe -ErrorAction SilentlyContinue
61+
if ($pyLauncher) {
62+
try {
63+
$ver = & py -3.12 -c "import platform;print(platform.python_version())" 2>$null
64+
if ($LASTEXITCODE -eq 0 -and $ver) {
65+
$dir = & py -3.12 -c "import sys,os;print(os.path.dirname(sys.executable))"
66+
if ($LASTEXITCODE -eq 0 -and (Test-Path $dir)) { $py = Join-Path $dir "python.exe" }
67+
}
68+
} catch {}
69+
}
70+
if (-not $py) {
71+
foreach ($root in $candidates | Where-Object { $_ -and (Test-Path $_) }) {
72+
$exe = Join-Path $root "python.exe"
73+
if (Test-Path $exe) { $py = $exe; break }
74+
}
75+
}
76+
if (-not $py -and (Test-Path "R:\actions-runner")) {
77+
$found = Get-ChildItem -Path "R:\actions-runner" -Filter "python.exe" -File -Recurse -ErrorAction SilentlyContinue |
78+
Where-Object { $_.FullName -match "Python\\3\.12" } |
79+
Select-Object -First 1
80+
if ($found) { $py = $found.FullName }
81+
}
82+
if (-not $py) { Write-Error "Python 3.12 not found"; exit 1 }
83+
$pyDir = Split-Path $py -Parent
84+
$scriptsDir = Join-Path $pyDir "Scripts"
85+
$env:PATH = "$pyDir;$scriptsDir;$env:PATH"
86+
$pyDir | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
87+
$scriptsDir | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
88+
"PY_DIR=$pyDir" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
89+
& "$py" --version
90+
& "$py" -m pip --version 2>$null | Out-Null
91+
if ($LASTEXITCODE -ne 0) {
92+
& "$py" -m ensurepip --upgrade
93+
& "$py" -m pip install -U pip wheel setuptools
94+
}
95+
& "$py" -m pip --version
96+
97+
- name: Cache pip
98+
uses: actions/cache@v4
99+
with:
100+
path: ${{ env.PIP_CACHE_DIR }}
101+
key: pip-${{ hashFiles('**/requirements*.txt', 'pyproject.toml') }}
102+
restore-keys: |
103+
pip-
104+
105+
- name: Install tooling
106+
shell: powershell
107+
run: |
108+
python -m ensurepip --upgrade
109+
python -m pip install -U pip wheel setuptools --cache-dir $env:PIP_CACHE_DIR
110+
python -m pip install ruff flake8 --cache-dir $env:PIP_CACHE_DIR
111+
112+
- name: Ruff check
113+
run: ruff check .
114+
shell: powershell
115+
116+
- name: Flake8
117+
run: flake8 .
118+
shell: powershell
119+
120+
tests-cpu:
121+
name: Tests (CPU)
122+
runs-on: [self-hosted, Windows, X64]
123+
needs: [lint]
124+
steps:
125+
- name: Checkout
126+
uses: actions/checkout@v4
127+
128+
- name: Ensure pip cache dir
129+
run: New-Item -ItemType Directory -Force -Path $env:PIP_CACHE_DIR | Out-Null
130+
131+
132+
- name: Discover & use Python 3.12
133+
run: |
134+
# -- Python discovery (PowerShell) --
135+
$candidates = @()
136+
if ($env:PY_DIR) { $candidates += $env:PY_DIR }
137+
$candidates += @(
138+
"R:\tools\python\3.12.10\x64",
139+
"R:\tools\python\3.12\x64",
140+
"C:\Python312",
141+
"C:\Python312\amd64",
142+
"$env:LocalAppData\Programs\Python\Python312"
143+
)
144+
145+
$py = $null
146+
$pyLauncher = Get-Command py.exe -ErrorAction SilentlyContinue
147+
if ($pyLauncher) {
148+
try {
149+
$ver = & py -3.12 -c "import platform;print(platform.python_version())" 2>$null
150+
if ($LASTEXITCODE -eq 0 -and $ver) {
151+
$dir = & py -3.12 -c "import sys,os;print(os.path.dirname(sys.executable))"
152+
if ($LASTEXITCODE -eq 0 -and (Test-Path $dir)) { $py = Join-Path $dir "python.exe" }
153+
}
154+
} catch {}
155+
}
156+
157+
if (-not $py) {
158+
foreach ($root in $candidates | Where-Object { $_ -and (Test-Path $_) }) {
159+
$exe = Join-Path $root "python.exe"
160+
if (Test-Path $exe) { $py = $exe; break }
161+
}
162+
}
163+
164+
if (-not $py -and (Test-Path "R:\actions-runner")) {
165+
$found = Get-ChildItem -Path "R:\actions-runner" -Filter "python.exe" -File -Recurse -ErrorAction SilentlyContinue |
166+
Where-Object { $_.FullName -match "Python\\3\.12" } |
167+
Select-Object -First 1
168+
if ($found) { $py = $found.FullName }
169+
}
170+
171+
if (-not $py) { Write-Error "Python 3.12 not found"; exit 1 }
172+
173+
$pyDir = Split-Path $py -Parent
174+
$scriptsDir = Join-Path $pyDir "Scripts"
175+
176+
# PATH for this step
177+
$env:PATH = "$pyDir;$scriptsDir;$env:PATH"
178+
# Export for next steps
179+
$pyDir | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
180+
$scriptsDir | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
181+
"PY_DIR=$pyDir" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
182+
183+
& "$py" --version
184+
& "$py" -m pip --version 2>$null | Out-Null
185+
if ($LASTEXITCODE -ne 0) {
186+
Write-Host "Bootstrapping pip..."
187+
& "$py" -m ensurepip --upgrade
188+
& "$py" -m pip install -U pip wheel setuptools
189+
}
190+
& "$py" -m pip --version
191+
192+
- name: Cache pip
193+
uses: actions/cache@v4
194+
with:
195+
path: ${{ env.PIP_CACHE_DIR }}
196+
key: pip-${{ hashFiles('**/requirements*.txt', 'pyproject.toml') }}
197+
restore-keys: |
198+
pip-
199+
200+
- name: Install deps
201+
run: |
202+
python -m ensurepip --upgrade
203+
python -m pip install -U pip wheel setuptools --cache-dir $env:PIP_CACHE_DIR
204+
if (Test-Path "requirements.txt") { pip install -r requirements.txt --cache-dir $env:PIP_CACHE_DIR }
205+
if (Test-Path "requirements-dev.txt") { pip install -r requirements-dev.txt --cache-dir $env:PIP_CACHE_DIR }
206+
if (Test-Path "pyproject.toml") { pip install -e . --config-settings editable_mode=compat }
207+
208+
- name: Print Python and Torch info
209+
continue-on-error: true
210+
run: |
211+
$code = @'
212+
import platform
213+
print("Python:", platform.python_version())
214+
try:
215+
import torch
216+
print("Torch:", getattr(torch, "__version__", "not installed"))
217+
ok = hasattr(torch, "cuda") and torch.cuda.is_available()
218+
print("CUDA available:", ok)
219+
if ok:
220+
print("CUDA devices:", torch.cuda.device_count())
221+
except Exception as e:
222+
print("Torch not installed or failed:", e)
223+
'@
224+
$code | python -
225+
226+
- name: Run pytest (CPU-only)
227+
env:
228+
PYTEST_ADDOPTS: "-q"
229+
run: |
230+
New-Item -ItemType Directory -Force -Path .\test-logs | Out-Null
231+
pytest -q -m "not gpu and not gpu_cuda and not gpu_mps" --maxfail=1 --disable-warnings `
232+
--log-cli-level=INFO `
233+
2>&1 | Tee-Object -FilePath .\test-logs\pytest_cpu.txt
234+
235+
236+
tests-gpu:
237+
name: Tests (GPU)
238+
runs-on: [self-hosted, Windows, X64]
239+
needs: [tests-cpu]
240+
env:
241+
242+
PIP_CACHE_DIR: ${{ github.workspace }}\_pip_cache
243+
steps:
244+
- name: Checkout
245+
uses: actions/checkout@v4
246+
247+
- name: Ensure pip cache dir
248+
shell: powershell
249+
run: |
250+
New-Item -ItemType Directory -Force -Path $env:PIP_CACHE_DIR | Out-Null
251+
252+
- name: Discover & use Python 3.12
253+
shell: powershell
254+
run: |
255+
$candidates = @()
256+
if ($env:PY_DIR) { $candidates += $env:PY_DIR }
257+
$candidates += @(
258+
"R:\tools\python\3.12.10\x64",
259+
"R:\tools\python\3.12\x64",
260+
"C:\Python312",
261+
"C:\Python312\amd64",
262+
"$env:LocalAppData\Programs\Python\Python312"
263+
)
264+
$py = $null
265+
$pyLauncher = Get-Command py.exe -ErrorAction SilentlyContinue
266+
if ($pyLauncher) {
267+
try {
268+
$ver = & py -3.12 -c "import platform;print(platform.python_version())" 2>$null
269+
if ($LASTEXITCODE -eq 0 -and $ver) {
270+
$dir = & py -3.12 -c "import sys,os;print(os.path.dirname(sys.executable))"
271+
if ($LASTEXITCODE -eq 0 -and (Test-Path $dir)) { $py = Join-Path $dir "python.exe" }
272+
}
273+
} catch {}
274+
}
275+
if (-not $py) {
276+
foreach ($root in $candidates | Where-Object { $_ -and (Test-Path $_) }) {
277+
$exe = Join-Path $root "python.exe"
278+
if (Test-Path $exe) { $py = $exe; break }
279+
}
280+
}
281+
if (-not $py -and (Test-Path "R:\actions-runner")) {
282+
$found = Get-ChildItem -Path "R:\actions-runner" -Filter "python.exe" -File -Recurse -ErrorAction SilentlyContinue |
283+
Where-Object { $_.FullName -match "Python\\3\.12" } |
284+
Select-Object -First 1
285+
if ($found) { $py = $found.FullName }
286+
}
287+
if (-not $py) { Write-Error "Python 3.12 not found"; exit 1 }
288+
$pyDir = Split-Path $py -Parent
289+
$scriptsDir = Join-Path $pyDir "Scripts"
290+
$env:PATH = "$pyDir;$scriptsDir;$env:PATH"
291+
$pyDir | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
292+
$scriptsDir | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
293+
"PY_DIR=$pyDir" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
294+
& "$py" --version
295+
& "$py" -m pip --version
296+
297+
- name: Cache pip
298+
uses: actions/cache@v4
299+
with:
300+
path: ${{ env.PIP_CACHE_DIR }}
301+
key: pip-${{ hashFiles('**/requirements*.txt', 'pyproject.toml') }}
302+
restore-keys: |
303+
pip-
304+
305+
- name: Install deps
306+
shell: powershell
307+
run: |
308+
python -m ensurepip --upgrade
309+
python -m pip install -U pip wheel setuptools --cache-dir $env:PIP_CACHE_DIR
310+
if (Test-Path "requirements.txt") { pip install -r requirements.txt --cache-dir $env:PIP_CACHE_DIR }
311+
if (Test-Path "requirements-dev.txt") { pip install -r requirements-dev.txt --cache-dir $env:PIP_CACHE_DIR }
312+
if (Test-Path "pyproject.toml") { pip install -e . --config-settings editable_mode=compat }
313+
314+
- name: Show NVIDIA GPU
315+
id: nvsmi
316+
shell: powershell
317+
continue-on-error: true
318+
run: |
319+
$exists = Get-Command nvidia-smi -ErrorAction SilentlyContinue
320+
if ($null -eq $exists) {
321+
Write-Host "nvidia-smi not found"
322+
"has_gpu=false" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
323+
} else {
324+
nvidia-smi
325+
"has_gpu=true" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
326+
}
327+
328+
329+
330+
- name: Torch CUDA availability
331+
shell: powershell
332+
continue-on-error: true
333+
run: |
334+
$lines = @(
335+
'import platform'
336+
'print("Python:", platform.python_version())'
337+
'try:'
338+
' import torch'
339+
' print("Torch:", getattr(torch, "__version__", "not installed"))'
340+
' has_cuda = torch.cuda.is_available()'
341+
' print("CUDA available:", has_cuda)'
342+
' cnt = torch.cuda.device_count() if has_cuda else 0'
343+
' print("CUDA device count:", cnt)'
344+
' if has_cuda and cnt > 0:'
345+
' i = torch.cuda.current_device()'
346+
' print("Current device index:", i)'
347+
' print("Device name:", torch.cuda.get_device_name(i))'
348+
'except Exception as e:'
349+
' print("Torch probe failed:", e)'
350+
)
351+
$code = $lines -join "`n"
352+
$code | python -
353+
354+
355+
356+
357+
- name: Run pytest (GPU markers)
358+
if: steps.nvsmi.outputs.has_gpu == 'true'
359+
shell: powershell
360+
run: |
361+
pytest -q -m "gpu or gpu_cuda or gpu_mps" --maxfail=1 --disable-warnings --log-cli-level=INFO
362+

0 commit comments

Comments
 (0)