Skip to content

Commit e3b2892

Browse files
Replace weakref.proxy with strong references for plugin self.model (#… (#1194)
* Replace weakref.proxy with strong references for plugin self.model (#1193) * Remove stale Py_DECREF from plugin Free callbacks and fix IISfinder/dealloc * remove need for dropEvent * Fix stubs and comment for weakref removal * Clarify plugin lifecycle and hide eventhdlr bookkeeping * Swallow SCIPfree retcode in _free_scip_instance
1 parent b311726 commit e3b2892

22 files changed

Lines changed: 182 additions & 86 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
- Used `getIndex()` instead of `ptr()` for sorting nonlinear expression terms to avoid nondeterministic behavior
1111
- Fixed stubtest failures with mypy 1.20 by marking dunder method parameters as positional-only
1212
- Return `MatrixGenExpr` in `buildGenExprObj` instead of `MatrixExpr`
13+
- Plugins now hold strong references to their `Model` instead of `weakref.proxy`, fixing `ReferenceError` during cleanup callbacks (#1193)
1314
### Changed
1415
- Speed up `constant * Expr` via C-level API
1516
- Speed up `Term.__eq__` via the C-level API

src/pyscipopt/benders.pxi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ cdef SCIP_RETCODE PyBendersFree (SCIP* scip, SCIP_BENDERS* benders) noexcept wit
7676
bendersdata = SCIPbendersGetData(benders)
7777
PyBenders = <Benders>bendersdata
7878
PyBenders.bendersfree()
79-
Py_DECREF(PyBenders)
8079
return SCIP_OKAY
8180

8281
cdef SCIP_RETCODE PyBendersInit (SCIP* scip, SCIP_BENDERS* benders) noexcept with gil:

src/pyscipopt/benderscut.pxi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ cdef SCIP_RETCODE PyBenderscutFree (SCIP* scip, SCIP_BENDERSCUT* benderscut) noe
3131
benderscutdata = SCIPbenderscutGetData(benderscut)
3232
PyBenderscut = <Benderscut>benderscutdata
3333
PyBenderscut.benderscutfree()
34-
Py_DECREF(PyBenderscut)
3534
return SCIP_OKAY
3635

3736
cdef SCIP_RETCODE PyBenderscutInit (SCIP* scip, SCIP_BENDERSCUT* benderscut) noexcept with gil:

src/pyscipopt/branchrule.pxi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ cdef SCIP_RETCODE PyBranchruleFree (SCIP* scip, SCIP_BRANCHRULE* branchrule) noe
4747
branchruledata = SCIPbranchruleGetData(branchrule)
4848
PyBranchrule = <Branchrule>branchruledata
4949
PyBranchrule.branchfree()
50-
Py_DECREF(PyBranchrule)
5150
return SCIP_OKAY
5251

5352
cdef SCIP_RETCODE PyBranchruleInit (SCIP* scip, SCIP_BRANCHRULE* branchrule) noexcept with gil:

src/pyscipopt/conshdlr.pxi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,6 @@ cdef SCIP_RETCODE PyConshdlrCopy (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_Bool
159159
cdef SCIP_RETCODE PyConsFree (SCIP* scip, SCIP_CONSHDLR* conshdlr) noexcept with gil:
160160
PyConshdlr = getPyConshdlr(conshdlr)
161161
PyConshdlr.consfree()
162-
Py_DECREF(PyConshdlr)
163162
return SCIP_OKAY
164163

165164
cdef SCIP_RETCODE PyConsInit (SCIP* scip, SCIP_CONSHDLR* conshdlr, SCIP_CONS** conss, int nconss) noexcept with gil:

src/pyscipopt/cutsel.pxi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ cdef SCIP_RETCODE PyCutselFree (SCIP* scip, SCIP_CUTSEL* cutsel) noexcept with g
3737
cutseldata = SCIPcutselGetData(cutsel)
3838
PyCutsel = <Cutsel>cutseldata
3939
PyCutsel.cutselfree()
40-
Py_DECREF(PyCutsel)
4140
return SCIP_OKAY
4241

4342
cdef SCIP_RETCODE PyCutselInit (SCIP* scip, SCIP_CUTSEL* cutsel) noexcept with gil:

src/pyscipopt/event.pxi

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
cdef class Eventhdlr:
44
cdef public Model model
55
cdef public str name
6+
# eventtypes caught via `Model.catchEvent`, auto-dropped on `eventexit`.
7+
cdef list _caught_events
8+
9+
def __cinit__(self):
10+
self._caught_events = []
611

712
def eventcopy(self):
813
'''sets copy callback for all events of this event handler '''
@@ -51,7 +56,6 @@ cdef SCIP_RETCODE PyEventCopy (SCIP* scip, SCIP_EVENTHDLR* eventhdlr) noexcept w
5156
cdef SCIP_RETCODE PyEventFree (SCIP* scip, SCIP_EVENTHDLR* eventhdlr) noexcept with gil:
5257
PyEventhdlr = getPyEventhdlr(eventhdlr)
5358
PyEventhdlr.eventfree()
54-
Py_DECREF(PyEventhdlr)
5559
return SCIP_OKAY
5660

5761
cdef SCIP_RETCODE PyEventInit (SCIP* scip, SCIP_EVENTHDLR* eventhdlr) noexcept with gil:
@@ -62,6 +66,10 @@ cdef SCIP_RETCODE PyEventInit (SCIP* scip, SCIP_EVENTHDLR* eventhdlr) noexcept w
6266
cdef SCIP_RETCODE PyEventExit (SCIP* scip, SCIP_EVENTHDLR* eventhdlr) noexcept with gil:
6367
PyEventhdlr = getPyEventhdlr(eventhdlr)
6468
PyEventhdlr.eventexit()
69+
# Auto-drop any events not explicitly dropped by the user
70+
for eventtype in PyEventhdlr._caught_events:
71+
SCIPdropEvent(scip, eventtype, eventhdlr, NULL, -1)
72+
PyEventhdlr._caught_events = []
6573
return SCIP_OKAY
6674

6775
cdef SCIP_RETCODE PyEventInitsol (SCIP* scip, SCIP_EVENTHDLR* eventhdlr) noexcept with gil:

src/pyscipopt/heuristic.pxi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ cdef SCIP_RETCODE PyHeurFree (SCIP* scip, SCIP_HEUR* heur) noexcept with gil:
3838
heurdata = SCIPheurGetData(heur)
3939
PyHeur = <Heur>heurdata
4040
PyHeur.heurfree()
41-
Py_DECREF(PyHeur)
4241
return SCIP_OKAY
4342

4443
cdef SCIP_RETCODE PyHeurInit (SCIP* scip, SCIP_HEUR* heur) noexcept with gil:

src/pyscipopt/iisfinder.pxi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
##@file iisfinder.pxi
22
#@brief Base class of the IIS finder Plugin
33
cdef class IISfinder:
4+
cdef public Model model
45
cdef public IIS iis
5-
cdef SCIP_IIS* scip_iis
6+
cdef SCIP_IIS* scip_iis
67
cdef SCIP_IISFINDER* scip_iisfinder
78

89
def iisfinderfree(self):
@@ -22,7 +23,6 @@ cdef SCIP_RETCODE PyiisfinderFree (SCIP* scip, SCIP_IISFINDER* iisfinder) noexce
2223
iisfinderdata = SCIPiisfinderGetData(iisfinder)
2324
PyIIS = <IISfinder>iisfinderdata
2425
PyIIS.iisfinderfree()
25-
Py_DECREF(PyIIS)
2626
return SCIP_OKAY
2727

2828
cdef SCIP_RETCODE PyiisfinderExec (SCIP_IIS* iis, SCIP_IISFINDER* iisfinder, SCIP_RESULT* result) noexcept with gil:

src/pyscipopt/nodesel.pxi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ cdef SCIP_RETCODE PyNodeselFree (SCIP* scip, SCIP_NODESEL* nodesel) noexcept wit
5050
nodeseldata = SCIPnodeselGetData(nodesel)
5151
PyNodesel = <Nodesel>nodeseldata
5252
PyNodesel.nodefree()
53-
Py_DECREF(PyNodesel)
5453
return SCIP_OKAY
5554

5655
cdef SCIP_RETCODE PyNodeselInit (SCIP* scip, SCIP_NODESEL* nodesel) noexcept with gil:

0 commit comments

Comments
 (0)