Skip to content

Commit 9271db1

Browse files
Fix stubtest failures with mypy 1.20 (#1202)
* Mark dunder method parameters as positional-only in stubs * CHANGELOG * Revert generator changes, fix __replace__ stub * Remove unused allowlist entry
1 parent 8b1d1f5 commit 9271db1

4 files changed

Lines changed: 122 additions & 117 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
- Added `getMemUsed()`, `getMemTotal()`, and `getMemExternEstim()` methods
77
### Fixed
88
- Removed `Py_INCREF`/`Py_DECREF` on `Model` in `catchEvent`/`dropEvent` that caused memory leak for imbalanced usage
9-
- Used `getIndex()` instead of `ptr()` for sorting nonlinear expression terms to avoid nondeterministic behavior
9+
- Used `getIndex()` instead of `ptr()` for sorting nonlinear expression terms to avoid nondeterministic behavior
10+
- Fixed stubtest failures with mypy 1.20 by marking dunder method parameters as positional-only
1011
### Changed
1112
- Speed up `constant * Expr` via C-level API
1213
### Removed

scripts/generate_stubs.py

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ class StubGenerator:
4848

4949
# Special methods that need specific type hints
5050
COMPARISON_METHODS = {
51-
'__eq__': 'def __eq__(self, other: object) -> bool: ...',
52-
'__ne__': 'def __ne__(self, other: object) -> bool: ...',
53-
'__lt__': 'def __lt__(self, other: object) -> bool: ...',
54-
'__le__': 'def __le__(self, other: object) -> bool: ...',
55-
'__gt__': 'def __gt__(self, other: object) -> bool: ...',
56-
'__ge__': 'def __ge__(self, other: object) -> bool: ...',
51+
'__eq__': 'def __eq__(self, other: object, /) -> bool: ...',
52+
'__ne__': 'def __ne__(self, other: object, /) -> bool: ...',
53+
'__lt__': 'def __lt__(self, other: object, /) -> bool: ...',
54+
'__le__': 'def __le__(self, other: object, /) -> bool: ...',
55+
'__gt__': 'def __gt__(self, other: object, /) -> bool: ...',
56+
'__ge__': 'def __ge__(self, other: object, /) -> bool: ...',
5757
}
5858

5959
SPECIAL_METHODS = {
@@ -63,8 +63,8 @@ class StubGenerator:
6363
'__init__': 'def __init__(self, *args: Incomplete, **kwargs: Incomplete) -> None: ...',
6464
'__repr__': 'def __repr__(self) -> str: ...',
6565
'__str__': 'def __str__(self) -> str: ...',
66-
'__delitem__': 'def __delitem__(self, key: Incomplete) -> None: ...',
67-
'__setitem__': 'def __setitem__(self, key: Incomplete, value: Incomplete) -> None: ...',
66+
'__delitem__': 'def __delitem__(self, key: Incomplete, /) -> None: ...',
67+
'__setitem__': 'def __setitem__(self, key: Incomplete, value: Incomplete, /) -> None: ...',
6868
}
6969

7070
# Methods that should NOT appear in stubs (internal Cython methods)
@@ -80,24 +80,24 @@ class StubGenerator:
8080

8181
# Methods with specific type hints (no *args, **kwargs)
8282
TYPED_METHODS = {
83-
'__getitem__': 'def __getitem__(self, index: Incomplete) -> Incomplete: ...',
83+
'__getitem__': 'def __getitem__(self, index: Incomplete, /) -> Incomplete: ...',
8484
'__iter__': 'def __iter__(self) -> Incomplete: ...',
8585
'__next__': 'def __next__(self) -> Incomplete: ...',
86-
'__add__': 'def __add__(self, other: Incomplete) -> Incomplete: ...',
87-
'__radd__': 'def __radd__(self, other: Incomplete) -> Incomplete: ...',
88-
'__sub__': 'def __sub__(self, other: Incomplete) -> Incomplete: ...',
89-
'__rsub__': 'def __rsub__(self, other: Incomplete) -> Incomplete: ...',
90-
'__mul__': 'def __mul__(self, other: Incomplete) -> Incomplete: ...',
91-
'__rmul__': 'def __rmul__(self, other: Incomplete) -> Incomplete: ...',
92-
'__truediv__': 'def __truediv__(self, other: Incomplete) -> Incomplete: ...',
93-
'__rtruediv__': 'def __rtruediv__(self, other: Incomplete) -> Incomplete: ...',
94-
'__rpow__': 'def __rpow__(self, other: Incomplete) -> Incomplete: ...',
86+
'__add__': 'def __add__(self, other: Incomplete, /) -> Incomplete: ...',
87+
'__radd__': 'def __radd__(self, other: Incomplete, /) -> Incomplete: ...',
88+
'__sub__': 'def __sub__(self, other: Incomplete, /) -> Incomplete: ...',
89+
'__rsub__': 'def __rsub__(self, other: Incomplete, /) -> Incomplete: ...',
90+
'__mul__': 'def __mul__(self, other: Incomplete, /) -> Incomplete: ...',
91+
'__rmul__': 'def __rmul__(self, other: Incomplete, /) -> Incomplete: ...',
92+
'__truediv__': 'def __truediv__(self, other: Incomplete, /) -> Incomplete: ...',
93+
'__rtruediv__': 'def __rtruediv__(self, other: Incomplete, /) -> Incomplete: ...',
94+
'__rpow__': 'def __rpow__(self, other: Incomplete, /) -> Incomplete: ...',
9595
'__neg__': 'def __neg__(self) -> Incomplete: ...',
9696
'__abs__': 'def __abs__(self) -> Incomplete: ...',
97-
'__iadd__': 'def __iadd__(self, other: Incomplete) -> Incomplete: ... # noqa: PYI034',
98-
'__isub__': 'def __isub__(self, other: Incomplete) -> Incomplete: ... # noqa: PYI034',
99-
'__imul__': 'def __imul__(self, other: Incomplete) -> Incomplete: ... # noqa: PYI034',
100-
'__matmul__': 'def __matmul__(self, other: Incomplete) -> Incomplete: ...',
97+
'__iadd__': 'def __iadd__(self, other: Incomplete, /) -> Incomplete: ... # noqa: PYI034',
98+
'__isub__': 'def __isub__(self, other: Incomplete, /) -> Incomplete: ... # noqa: PYI034',
99+
'__imul__': 'def __imul__(self, other: Incomplete, /) -> Incomplete: ... # noqa: PYI034',
100+
'__matmul__': 'def __matmul__(self, other: Incomplete, /) -> Incomplete: ...',
101101
'__array_ufunc__': 'def __array_ufunc__(self, ufunc: Incomplete, method: Incomplete, *args: Incomplete, **kwargs: Incomplete) -> Incomplete: ...',
102102
}
103103

@@ -521,6 +521,11 @@ def _generate_method_stub(self, method_name: str, params: list, is_static: bool
521521
else:
522522
param_strs.append(f'{param_name}: Incomplete')
523523

524+
# Dunder methods (except __init__) have positional-only parameters
525+
is_dunder = method_name.startswith('__') and method_name.endswith('__')
526+
if is_dunder and method_name != '__init__' and not is_static:
527+
param_strs.append('/')
528+
524529
params_str = ', '.join(param_strs)
525530
return f'def {method_name}({params_str}) -> {return_type}: ...'
526531

src/pyscipopt/scip.pyi

Lines changed: 93 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,13 @@ class Column:
121121
def getUb(self) -> Incomplete: ...
122122
def getVar(self) -> Incomplete: ...
123123
def isIntegral(self) -> Incomplete: ...
124-
def __eq__(self, other: object) -> bool: ...
125-
def __ge__(self, other: object) -> bool: ...
126-
def __gt__(self, other: object) -> bool: ...
124+
def __eq__(self, other: object, /) -> bool: ...
125+
def __ge__(self, other: object, /) -> bool: ...
126+
def __gt__(self, other: object, /) -> bool: ...
127127
def __hash__(self) -> int: ...
128-
def __le__(self, other: object) -> bool: ...
129-
def __lt__(self, other: object) -> bool: ...
130-
def __ne__(self, other: object) -> bool: ...
128+
def __le__(self, other: object, /) -> bool: ...
129+
def __lt__(self, other: object, /) -> bool: ...
130+
def __ne__(self, other: object, /) -> bool: ...
131131

132132
@disjoint_base
133133
class ColumnExact:
@@ -260,13 +260,13 @@ class Constraint:
260260
def isSeparated(self) -> Incomplete: ...
261261
def isStickingAtNode(self) -> Incomplete: ...
262262
def ptr(self) -> Incomplete: ...
263-
def __eq__(self, other: object) -> bool: ...
264-
def __ge__(self, other: object) -> bool: ...
265-
def __gt__(self, other: object) -> bool: ...
263+
def __eq__(self, other: object, /) -> bool: ...
264+
def __ge__(self, other: object, /) -> bool: ...
265+
def __gt__(self, other: object, /) -> bool: ...
266266
def __hash__(self) -> int: ...
267-
def __le__(self, other: object) -> bool: ...
268-
def __lt__(self, other: object) -> bool: ...
269-
def __ne__(self, other: object) -> bool: ...
267+
def __le__(self, other: object, /) -> bool: ...
268+
def __lt__(self, other: object, /) -> bool: ...
269+
def __ne__(self, other: object, /) -> bool: ...
270270

271271
@disjoint_base
272272
class Cutsel:
@@ -303,13 +303,13 @@ class Event:
303303
def getRow(self) -> Incomplete: ...
304304
def getType(self) -> Incomplete: ...
305305
def getVar(self) -> Incomplete: ...
306-
def __eq__(self, other: object) -> bool: ...
307-
def __ge__(self, other: object) -> bool: ...
308-
def __gt__(self, other: object) -> bool: ...
306+
def __eq__(self, other: object, /) -> bool: ...
307+
def __ge__(self, other: object, /) -> bool: ...
308+
def __gt__(self, other: object, /) -> bool: ...
309309
def __hash__(self) -> int: ...
310-
def __le__(self, other: object) -> bool: ...
311-
def __lt__(self, other: object) -> bool: ...
312-
def __ne__(self, other: object) -> bool: ...
310+
def __le__(self, other: object, /) -> bool: ...
311+
def __lt__(self, other: object, /) -> bool: ...
312+
def __ne__(self, other: object, /) -> bool: ...
313313

314314
@disjoint_base
315315
class Eventhdlr:
@@ -332,26 +332,26 @@ class Expr:
332332
def degree(self) -> Incomplete: ...
333333
def normalize(self) -> Incomplete: ...
334334
def __abs__(self) -> Incomplete: ...
335-
def __add__(self, other: Incomplete) -> Incomplete: ...
336-
def __eq__(self, other: object) -> bool: ...
337-
def __ge__(self, other: object) -> bool: ...
338-
def __getitem__(self, index: Incomplete) -> Incomplete: ...
339-
def __gt__(self, other: object) -> bool: ...
340-
def __iadd__(self, other: Incomplete) -> Incomplete: ... # noqa: PYI034
335+
def __add__(self, other: Incomplete, /) -> Incomplete: ...
336+
def __eq__(self, other: object, /) -> bool: ...
337+
def __ge__(self, other: object, /) -> bool: ...
338+
def __getitem__(self, index: Incomplete, /) -> Incomplete: ...
339+
def __gt__(self, other: object, /) -> bool: ...
340+
def __iadd__(self, other: Incomplete, /) -> Incomplete: ... # noqa: PYI034
341341
def __iter__(self) -> Incomplete: ...
342-
def __le__(self, other: object) -> bool: ...
343-
def __lt__(self, other: object) -> bool: ...
344-
def __mul__(self, other: Incomplete) -> Incomplete: ...
345-
def __ne__(self, other: object) -> bool: ...
342+
def __le__(self, other: object, /) -> bool: ...
343+
def __lt__(self, other: object, /) -> bool: ...
344+
def __mul__(self, other: Incomplete, /) -> Incomplete: ...
345+
def __ne__(self, other: object, /) -> bool: ...
346346
def __neg__(self) -> Incomplete: ...
347-
def __pow__(self, other: Incomplete, modulo: Incomplete = ...) -> Incomplete: ...
348-
def __radd__(self, other: Incomplete) -> Incomplete: ...
349-
def __rmul__(self, other: Incomplete) -> Incomplete: ...
350-
def __rpow__(self, other: Incomplete) -> Incomplete: ...
351-
def __rsub__(self, other: Incomplete) -> Incomplete: ...
352-
def __rtruediv__(self, other: Incomplete) -> Incomplete: ...
353-
def __sub__(self, other: Incomplete) -> Incomplete: ...
354-
def __truediv__(self, other: Incomplete) -> Incomplete: ...
347+
def __pow__(self, other: Incomplete, modulo: Incomplete = ..., /) -> Incomplete: ...
348+
def __radd__(self, other: Incomplete, /) -> Incomplete: ...
349+
def __rmul__(self, other: Incomplete, /) -> Incomplete: ...
350+
def __rpow__(self, other: Incomplete, /) -> Incomplete: ...
351+
def __rsub__(self, other: Incomplete, /) -> Incomplete: ...
352+
def __rtruediv__(self, other: Incomplete, /) -> Incomplete: ...
353+
def __sub__(self, other: Incomplete, /) -> Incomplete: ...
354+
def __truediv__(self, other: Incomplete, /) -> Incomplete: ...
355355

356356
@disjoint_base
357357
class ExprCons:
@@ -363,12 +363,12 @@ class ExprCons:
363363
) -> None: ...
364364
def normalize(self) -> Incomplete: ...
365365
def __bool__(self) -> bool: ...
366-
def __eq__(self, other: object) -> bool: ...
367-
def __ge__(self, other: object) -> bool: ...
368-
def __gt__(self, other: object) -> bool: ...
369-
def __le__(self, other: object) -> bool: ...
370-
def __lt__(self, other: object) -> bool: ...
371-
def __ne__(self, other: object) -> bool: ...
366+
def __eq__(self, other: object, /) -> bool: ...
367+
def __ge__(self, other: object, /) -> bool: ...
368+
def __gt__(self, other: object, /) -> bool: ...
369+
def __le__(self, other: object, /) -> bool: ...
370+
def __lt__(self, other: object, /) -> bool: ...
371+
def __ne__(self, other: object, /) -> bool: ...
372372

373373
@disjoint_base
374374
class GenExpr:
@@ -378,23 +378,23 @@ class GenExpr:
378378
def degree(self) -> Incomplete: ...
379379
def getOp(self) -> Incomplete: ...
380380
def __abs__(self) -> GenExpr: ...
381-
def __add__(self, other: Incomplete) -> Incomplete: ...
382-
def __eq__(self, other: object) -> bool: ...
383-
def __ge__(self, other: object) -> bool: ...
384-
def __gt__(self, other: object) -> bool: ...
385-
def __le__(self, other: object) -> bool: ...
386-
def __lt__(self, other: object) -> bool: ...
387-
def __mul__(self, other: Incomplete) -> Incomplete: ...
388-
def __ne__(self, other: object) -> bool: ...
381+
def __add__(self, other: Incomplete, /) -> Incomplete: ...
382+
def __eq__(self, other: object, /) -> bool: ...
383+
def __ge__(self, other: object, /) -> bool: ...
384+
def __gt__(self, other: object, /) -> bool: ...
385+
def __le__(self, other: object, /) -> bool: ...
386+
def __lt__(self, other: object, /) -> bool: ...
387+
def __mul__(self, other: Incomplete, /) -> Incomplete: ...
388+
def __ne__(self, other: object, /) -> bool: ...
389389
def __neg__(self) -> Incomplete: ...
390-
def __pow__(self, other: Incomplete, modulo: Incomplete = ...) -> Incomplete: ...
391-
def __radd__(self, other: Incomplete) -> Incomplete: ...
392-
def __rmul__(self, other: Incomplete) -> Incomplete: ...
393-
def __rpow__(self, other: Incomplete) -> Incomplete: ...
394-
def __rsub__(self, other: Incomplete) -> Incomplete: ...
395-
def __rtruediv__(self, other: Incomplete) -> Incomplete: ...
396-
def __sub__(self, other: Incomplete) -> Incomplete: ...
397-
def __truediv__(self, other: Incomplete) -> Incomplete: ...
390+
def __pow__(self, other: Incomplete, modulo: Incomplete = ..., /) -> Incomplete: ...
391+
def __radd__(self, other: Incomplete, /) -> Incomplete: ...
392+
def __rmul__(self, other: Incomplete, /) -> Incomplete: ...
393+
def __rpow__(self, other: Incomplete, /) -> Incomplete: ...
394+
def __rsub__(self, other: Incomplete, /) -> Incomplete: ...
395+
def __rtruediv__(self, other: Incomplete, /) -> Incomplete: ...
396+
def __sub__(self, other: Incomplete, /) -> Incomplete: ...
397+
def __truediv__(self, other: Incomplete, /) -> Incomplete: ...
398398

399399
@disjoint_base
400400
class Heur:
@@ -532,7 +532,7 @@ class MatrixExprCons(np.ndarray):
532532
*args: Incomplete,
533533
**kwargs: Incomplete,
534534
) -> Incomplete: ...
535-
def __eq__(self, other: object) -> bool: ...
535+
def __eq__(self, other: object, /) -> bool: ...
536536

537537
class MatrixGenExpr(MatrixExpr): ...
538538

@@ -1624,13 +1624,13 @@ class Model:
16241624
filename: Incomplete = ...,
16251625
write_zeros: Incomplete = ...,
16261626
) -> Incomplete: ...
1627-
def __eq__(self, other: object) -> bool: ...
1628-
def __ge__(self, other: object) -> bool: ...
1629-
def __gt__(self, other: object) -> bool: ...
1627+
def __eq__(self, other: object, /) -> bool: ...
1628+
def __ge__(self, other: object, /) -> bool: ...
1629+
def __gt__(self, other: object, /) -> bool: ...
16301630
def __hash__(self) -> int: ...
1631-
def __le__(self, other: object) -> bool: ...
1632-
def __lt__(self, other: object) -> bool: ...
1633-
def __ne__(self, other: object) -> bool: ...
1631+
def __le__(self, other: object, /) -> bool: ...
1632+
def __lt__(self, other: object, /) -> bool: ...
1633+
def __ne__(self, other: object, /) -> bool: ...
16341634

16351635
@disjoint_base
16361636
class NLRow:
@@ -1642,13 +1642,13 @@ class NLRow:
16421642
def getLhs(self) -> Incomplete: ...
16431643
def getLinearTerms(self) -> Incomplete: ...
16441644
def getRhs(self) -> Incomplete: ...
1645-
def __eq__(self, other: object) -> bool: ...
1646-
def __ge__(self, other: object) -> bool: ...
1647-
def __gt__(self, other: object) -> bool: ...
1645+
def __eq__(self, other: object, /) -> bool: ...
1646+
def __ge__(self, other: object, /) -> bool: ...
1647+
def __gt__(self, other: object, /) -> bool: ...
16481648
def __hash__(self) -> int: ...
1649-
def __le__(self, other: object) -> bool: ...
1650-
def __lt__(self, other: object) -> bool: ...
1651-
def __ne__(self, other: object) -> bool: ...
1649+
def __le__(self, other: object, /) -> bool: ...
1650+
def __lt__(self, other: object, /) -> bool: ...
1651+
def __ne__(self, other: object, /) -> bool: ...
16521652

16531653
@disjoint_base
16541654
class Node:
@@ -1668,13 +1668,13 @@ class Node:
16681668
def getType(self) -> Incomplete: ...
16691669
def isActive(self) -> Incomplete: ...
16701670
def isPropagatedAgain(self) -> Incomplete: ...
1671-
def __eq__(self, other: object) -> bool: ...
1672-
def __ge__(self, other: object) -> bool: ...
1673-
def __gt__(self, other: object) -> bool: ...
1671+
def __eq__(self, other: object, /) -> bool: ...
1672+
def __ge__(self, other: object, /) -> bool: ...
1673+
def __gt__(self, other: object, /) -> bool: ...
16741674
def __hash__(self) -> int: ...
1675-
def __le__(self, other: object) -> bool: ...
1676-
def __lt__(self, other: object) -> bool: ...
1677-
def __ne__(self, other: object) -> bool: ...
1675+
def __le__(self, other: object, /) -> bool: ...
1676+
def __lt__(self, other: object, /) -> bool: ...
1677+
def __ne__(self, other: object, /) -> bool: ...
16781678

16791679
@disjoint_base
16801680
class Nodesel:
@@ -2091,13 +2091,13 @@ class Row:
20912091
def isLocal(self) -> Incomplete: ...
20922092
def isModifiable(self) -> Incomplete: ...
20932093
def isRemovable(self) -> Incomplete: ...
2094-
def __eq__(self, other: object) -> bool: ...
2095-
def __ge__(self, other: object) -> bool: ...
2096-
def __gt__(self, other: object) -> bool: ...
2094+
def __eq__(self, other: object, /) -> bool: ...
2095+
def __ge__(self, other: object, /) -> bool: ...
2096+
def __gt__(self, other: object, /) -> bool: ...
20972097
def __hash__(self) -> int: ...
2098-
def __le__(self, other: object) -> bool: ...
2099-
def __lt__(self, other: object) -> bool: ...
2100-
def __ne__(self, other: object) -> bool: ...
2098+
def __le__(self, other: object, /) -> bool: ...
2099+
def __lt__(self, other: object, /) -> bool: ...
2100+
def __ne__(self, other: object, /) -> bool: ...
21012101

21022102
@disjoint_base
21032103
class RowExact:
@@ -2125,8 +2125,8 @@ class Solution:
21252125
def getOrigin(self) -> Incomplete: ...
21262126
def retransform(self) -> Incomplete: ...
21272127
def translate(self, target: Incomplete) -> Incomplete: ...
2128-
def __getitem__(self, index: Incomplete) -> Incomplete: ...
2129-
def __setitem__(self, key: Incomplete, value: Incomplete) -> None: ...
2128+
def __getitem__(self, index: Incomplete, /) -> Incomplete: ...
2129+
def __setitem__(self, key: Incomplete, value: Incomplete, /) -> None: ...
21302130

21312131
class Statistics:
21322132
status: str
@@ -2205,16 +2205,16 @@ class Term:
22052205
ptrtuple: Incomplete
22062206
vartuple: Incomplete
22072207
def __init__(self, *vartuple: Incomplete) -> None: ...
2208-
def __mul__(self, other: Term) -> Term: ...
2209-
def __eq__(self, other: object) -> bool: ...
2210-
def __ge__(self, other: object) -> bool: ...
2211-
def __getitem__(self, index: Incomplete) -> Incomplete: ...
2212-
def __gt__(self, other: object) -> bool: ...
2208+
def __mul__(self, other: Term, /) -> Term: ...
2209+
def __eq__(self, other: object, /) -> bool: ...
2210+
def __ge__(self, other: object, /) -> bool: ...
2211+
def __getitem__(self, index: Incomplete, /) -> Incomplete: ...
2212+
def __gt__(self, other: object, /) -> bool: ...
22132213
def __hash__(self) -> int: ...
2214-
def __le__(self, other: object) -> bool: ...
2214+
def __le__(self, other: object, /) -> bool: ...
22152215
def __len__(self) -> int: ...
2216-
def __lt__(self, other: object) -> bool: ...
2217-
def __ne__(self, other: object) -> bool: ...
2216+
def __lt__(self, other: object, /) -> bool: ...
2217+
def __ne__(self, other: object, /) -> bool: ...
22182218

22192219
class UnaryExpr(GenExpr):
22202220
def __init__(self, *args: Incomplete, **kwargs: Incomplete) -> None: ...

stubs/allowlist

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
.*.__reduce_cython__
22
.*.__setstate_cython__
33
pyscipopt.scip.__test__
4-
pyscipopt._version.__conditional_annotations__

0 commit comments

Comments
 (0)