1- import os
2-
31import nox
42
53# Python versions from pyproject.toml
6- PYTHON_VERSIONS = ["3.9" , "3.10" , "3.11" , "3.12" , "3.13" ]
4+ PYTHON_VERSIONS = ['3.9' , '3.10' , '3.11' , '3.12' , '3.13' ]
5+
6+
7+ def _generate_stubs ():
8+ """Helper function to generate pyright stubs."""
9+ import os
10+ import shutil
11+ import subprocess
12+
13+ # Check if npx is available
14+ try :
15+ subprocess .run (['npx' , '--version' ], capture_output = True , check = True )
16+ except (subprocess .CalledProcessError , FileNotFoundError ):
17+ raise RuntimeError (
18+ 'npx not found. Please install Node.js to generate type stubs.\n '
19+ 'Visit: https://nodejs.org/ or use your package manager.'
20+ )
21+
22+ # Remove existing stubs to avoid duplication
23+ subprocess .run (['find' , 'python' , '-name' , '*.pyi' , '-type' , 'f' , '-delete' ])
24+
25+ # Generate stubs using npx pyright
26+ env = os .environ .copy ()
27+ env ['PYTHONPATH' ] = 'python'
28+
29+ try :
30+ subprocess .run (
31+ ['npx' , '-y' , 'pyright' , '--createstub' , 'coglet' ], env = env , check = True
32+ )
33+ except subprocess .CalledProcessError :
34+ print ('Warning: coglet stub creation may have failed' )
35+
36+ try :
37+ subprocess .run (
38+ ['npx' , '-y' , 'pyright' , '--createstub' , 'cog' ], env = env , check = True
39+ )
40+ except subprocess .CalledProcessError :
41+ print ('Warning: cog stub creation may have failed' )
42+
43+ # Move stubs from typings/ to alongside source
44+ if os .path .exists ('typings' ):
45+ shutil .copytree ('typings' , 'python' , dirs_exist_ok = True )
46+ shutil .rmtree ('typings' )
47+
748
849# Use uv for faster package installs
9- nox .options .default_venv_backend = "uv"
50+ nox .options .default_venv_backend = 'uv'
1051
1152
1253@nox .session (python = PYTHON_VERSIONS )
1354def tests (session ):
1455 """Run tests with pytest-xdist parallelization."""
15- session .install (" .[test]" )
16-
56+ session .install (' .[test]' )
57+
1758 # Pass through any arguments to pytest
18- pytest_args = [" -vv" , "-n" , " auto" ] + list (session .posargs )
19-
59+ pytest_args = [' -vv' , '-n' , ' auto' ] + list (session .posargs )
60+
2061 # Only add -n auto if -n isn't already specified
21- if any (arg .startswith ("-n" ) for arg in session .posargs ):
22- pytest_args = ["-vv" ] + list (session .posargs )
23-
24- session .run ("pytest" , * pytest_args )
62+ if any (arg .startswith ('-n' ) for arg in session .posargs ):
63+ pytest_args = ['-vv' ] + list (session .posargs )
2564
65+ session .run ('pytest' , * pytest_args )
2666
27- @nox .session (python = "3.11" ) # Single version for regular testing
67+
68+ @nox .session (python = '3.11' ) # Single version for regular testing
2869def test (session ):
2970 """Run tests on single Python version (faster for development)."""
30- session .install (" .[test]" )
31-
71+ session .install (' .[test]' )
72+
3273 # Pass through any arguments to pytest
33- pytest_args = [" -vv" , "-n" , " auto" ] + list (session .posargs )
34-
74+ pytest_args = [' -vv' , '-n' , ' auto' ] + list (session .posargs )
75+
3576 # Only add -n auto if -n isn't already specified
36- if any (arg .startswith ("-n" ) for arg in session .posargs ):
37- pytest_args = [" -vv" ] + list (session .posargs )
38-
39- session .run (" pytest" , * pytest_args )
77+ if any (arg .startswith ('-n' ) for arg in session .posargs ):
78+ pytest_args = [' -vv' ] + list (session .posargs )
79+
80+ session .run (' pytest' , * pytest_args )
4081
4182
4283@nox .session (python = None ) # Use current system Python, but create venv
4384def test_current (session ):
4485 """Run tests using current system Python with isolated venv (for CI)."""
45- session .install (" .[test]" )
46-
86+ session .install (' .[test]' )
87+
4788 # Pass through any arguments to pytest
48- pytest_args = [" -vv" , "-n" , " auto" ] + list (session .posargs )
49-
89+ pytest_args = [' -vv' , '-n' , ' auto' ] + list (session .posargs )
90+
5091 # Only add -n auto if -n isn't already specified
51- if any (arg .startswith ("-n" ) for arg in session .posargs ):
52- pytest_args = [" -vv" ] + list (session .posargs )
53-
54- session .run (" pytest" , * pytest_args )
92+ if any (arg .startswith ('-n' ) for arg in session .posargs ):
93+ pytest_args = [' -vv' ] + list (session .posargs )
94+
95+ session .run (' pytest' , * pytest_args )
5596
5697
5798@nox .session
5899def lint (session ):
59100 """Run ruff linting (check mode)."""
60- session .install (" .[dev]" )
101+ session .install (' .[dev]' )
61102 # Check if --fix is in posargs for local dev
62- if "--fix" in session .posargs :
63- session .run ("ruff" , "check" , "--fix" , "." )
103+ check_only = '--fix' not in session .posargs
104+ session .log (f'running lint... { "[check_only]" if check_only else "[auto_fix]" } ' )
105+ if '--fix' in session .posargs :
106+ session .run ('ruff' , 'check' , '--fix' , '.' )
64107 else :
65- session .run (" ruff" , " check" , "." )
108+ session .run (' ruff' , ' check' , '.' )
66109
67110
68111@nox .session
69112def format (session ):
70113 """Format code with ruff."""
71- session .install (" .[dev]" )
114+ session .install (' .[dev]' )
72115 # Check mode for CI, format mode for local
73- if " --check" in session .posargs :
74- session .run (" ruff" , " format" , " --check" , "." )
116+ if ' --check' in session .posargs :
117+ session .run (' ruff' , ' format' , ' --check' , '.' )
75118 else :
76- session .run ("ruff" , "format" , "." )
119+ session .run ('ruff' , 'format' , '.' )
120+
121+
122+ @nox .session
123+ def stubs (session ):
124+ """Generate pyright stubs."""
125+ session .log ('stubbing python modules...' )
126+ try :
127+ _generate_stubs ()
128+ session .log ('python module stubs generated successfully' )
129+ except RuntimeError as e :
130+ session .error (str (e ))
77131
78132
79133@nox .session
80134def typecheck (session ):
81135 """Run mypy type checking."""
82- session .install (".[dev]" )
136+ import os
137+
138+ session .log ('running typecheck...' )
139+ # Only generate stubs if not in CI (CI validates existing stubs separately)
140+ if not os .environ .get ('CI' ):
141+ session .log ('auto-generating python module stubs...' )
142+ # Run stubs generation inline instead of separate session
143+ _generate_stubs ()
144+ session .log ('done auto-generating python module stubs...' )
145+
146+ # Install dev deps (mypy) + test deps (pytest) + provided deps (pydantic)
147+ session .install ('.[dev,test,provided]' )
83148 session .run (
84- "mypy" , "." ,
85- "--exclude" , "build" ,
86- "--exclude" , "python/tests/cases" ,
87- "--exclude" , "python/tests/bad_inputs" ,
88- "--exclude" , "python/tests/bad_predictors" ,
89- "--exclude" , "python/tests/runners" ,
90- "--exclude" , "python/tests/schemas" ,
91- "--exclude" , "python/.*\\ .pyi" ,
92- * session .posargs
149+ 'mypy' ,
150+ '.' ,
151+ '--exclude' ,
152+ 'build' ,
153+ '--exclude' ,
154+ 'python/tests/cases' ,
155+ '--exclude' ,
156+ 'python/tests/bad_inputs' ,
157+ '--exclude' ,
158+ 'python/tests/bad_predictors' ,
159+ '--exclude' ,
160+ 'python/tests/runners' ,
161+ '--exclude' ,
162+ 'python/tests/schemas' ,
163+ '--exclude' ,
164+ 'python/.*\\ .pyi' ,
165+ * session .posargs ,
93166 )
94167
95168
96169@nox .session
97170def check_all (session ):
98171 """Run all checks (lint, format check, typecheck)."""
99- session .notify (" lint" )
100- session .notify (" format" , [" --check" ])
101- session .notify (" typecheck" )
172+ session .notify (' lint' )
173+ session .notify (' format' , [' --check' ])
174+ session .notify (' typecheck' )
0 commit comments