Skip to content

Commit

Permalink
Dont try to initialize frame for python 3.11 and later
Browse files Browse the repository at this point in the history
  • Loading branch information
yglukhov committed May 4, 2023
1 parent cdcc5e4 commit 0f66f8e
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 12 deletions.
4 changes: 1 addition & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
nim-channel: [stable, devel]
python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10"]
python-version: ["2.7", "3.7", "3.8", "3.9", "3.10", "3.11"]
exclude:
- os: windows-latest
python-version: "2.7" # DLL not found, specific to CI?
- os: windows-latest
python-version: "3.10" # FIXME: eval doesn't work

name: ${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.nim-channel }}
runs-on: ${{ matrix.os }}
Expand Down
10 changes: 8 additions & 2 deletions nimpy.nim
Original file line number Diff line number Diff line change
Expand Up @@ -941,11 +941,15 @@ proc pyBuiltins*(): PyObject =

proc pyGlobals*(): PyObject =
initPyLibIfNeeded()
newPyObject(pyLib.PyEval_GetGlobals())
let r = pyLib.PyEval_GetGlobals()
if not r.isNil:
result = newPyObject(r)

proc pyLocals*(): PyObject =
initPyLibIfNeeded()
newPyObject(pyLib.PyEval_GetLocals())
let r = pyLib.PyEval_GetLocals()
if not r.isNil:
result = newPyObject(r)

proc dir*(v: PyObject): seq[string] =
let lst = pyLib.PyObject_Dir(v.rawPyObj)
Expand Down Expand Up @@ -1002,6 +1006,8 @@ macro toPyDictRaw(a: untyped): PPyObject =
template toPyDict*(a: untyped): PyObject =
newPyObjectConsumingRef(toPyDictRaw(a))

proc pyDict*(): PyObject =
newPyObjectConsumingRef(toPyDictRaw(()))

################################################################################
################################################################################
Expand Down
8 changes: 6 additions & 2 deletions nimpy/py_lib.nim
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,8 @@ proc initPyThreadFrame() =

# https://stackoverflow.com/questions/42974139/valueerror-call-stack-is-not-deep-enough-when-calling-ipython-embed-method
# needed for eval and stuff like pandas.query() otherwise crash (call stack is not deep enough)
#
# XXX Unfortunately this doesn't work with python 3.11 and later.
if unlikely pyLib.isNil:
initPyLib(pythonLibHandleFromExternalLib())
pyThreadFrameInited = true
Expand All @@ -502,7 +504,8 @@ proc initPyThreadFrame() =
of 2:
if not cast[ptr PyThreadState2](pyThread).frame.isNil: return
of 3:
if not cast[ptr PyThreadState3](pyThread).frame.isNil: return
if pyLib.pythonVersion < (3, 11, 0):
if not cast[ptr PyThreadState3](pyThread).frame.isNil: return
else:
doAssert(false, "unreachable")

Expand All @@ -523,7 +526,8 @@ proc initPyThreadFrame() =
of 2:
cast[ptr PyThreadState2](pyThread).frame = root_frame
of 3:
cast[ptr PyThreadState3](pyThread).frame = root_frame
if pyLib.pythonVersion < (3, 11, 0):
cast[ptr PyThreadState3](pyThread).frame = root_frame
else:
doAssert(false, "unreachable")

Expand Down
13 changes: 8 additions & 5 deletions tests/tpyfromnim.nim
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ proc test*() {.gcsafe.} =

block: # eval
let py = pyBuiltinsModule()
doAssert(py.eval("3+3").to(int) == 6)
doAssert(py.eval(""" "hello" * 2 """).to(string) == "hellohello")
doAssert(py.eval("3+3", pyDict(), pyDict()).to(int) == 6)
doAssert(py.eval(""" "hello" * 2 """, pyDict(), pyDict()).to(string) == "hellohello")

block:
var ints = newSeq[int]()
Expand Down Expand Up @@ -246,6 +246,7 @@ proc test*() {.gcsafe.} =
block: # Kinda subclassing python objects in nim and calling super
if pyImport("sys").version_info.major.to(int) >= 3: # Only test with python 3
let py = pyBuiltinsModule()
let locals = toPyDict(()) # Create empty dict

# Let's say there's this python code:
discard py.exec("""
Expand All @@ -255,7 +256,9 @@ proc test*() {.gcsafe.} =
def useFoo(foo):
return foo.overrideMe()
""".dedent())
""".dedent(), pyDict(), locals)

let fooClass = locals["Foo"]

# Create a subclass of Foo in Nim:
proc createFooSubclassInstance(): PyObject =
Expand All @@ -268,7 +271,7 @@ proc test*() {.gcsafe.} =
proc overrideMe(): int =
self.super.overrideMe().to(int) + 123 # Call super

self = py.`type`("_", (pyGlobals()["Foo"], ), toPyDict({
self = py.`type`("_", (fooClass, ), toPyDict({
"overrideMe": overrideMe
})).to(proc(): PyObject {.gcsafe.})()
return self
Expand All @@ -277,7 +280,7 @@ proc test*() {.gcsafe.} =
let b = createFooSubclassInstance()

# Get `useFoo` proc
let useFoo = pyGlobals()["useFoo"].to(proc(self: PyObject): int {.gcsafe.})
let useFoo = locals["useFoo"].to(proc(self: PyObject): int {.gcsafe.})

# Pass b to `useFoo`
doAssert(useFoo(b) == 125)
Expand Down

0 comments on commit 0f66f8e

Please sign in to comment.