Closed jordanbriere closed 3 years ago
Okay, after a quick investigation, it appears to be caused by a thread/frame issue related to hibernation combined with the compiled expression bound to CFunction::__call__
through raw_method.
Basically, when that expression is compiled by the interpreter at that time, PyEval_GetGlobals returns NULL
resulting into the globals/locals being empty dictionaries. Normally, this is not really an issue, but since the compiled expression returns a nested lambda, and that globals == locals
, it tries to resolve its namespace from the original scope instead of the calling frame.
Weirdly enough, it is reproducible 100% of the times by adding the following import:
import entities.hooks
from players.entity import Player
Player(1).give_named_item('weapon_awp')
Not really sure why that is at this point, but raw_method fixes it while also being slightly faster. Tested the following:
"""
struct Foo { object dummy(boost::python::tuple args, dict kwargs) { return object(); } };
class_<Foo>("Foo")
.def("bar", raw_method(&Foo::dummy))
.def("baz", eval("lambda method: lambda *args, **kw: method(args[0], args[1:], kw)")(
make_function(&Foo::dummy))
)
;
"""
from time import *
foo = Foo()
t = time()
for i in range(10000000):
foo.bar()
print('Without eval:', time() - t)
t = time()
for i in range(10000000):
foo.baz()
print('With eval:', time() - t)
Results:
Without eval: 4.681713581085205
With eval: 5.766758680343628
While playing around #384, I ran across an issue that I was able to reproduce randomly with the following steps:
Randomly results into:
Not sure yet why exactly this happens, but it is also reproducible on master.