Commit f5599ffc authored by Jason Madden's avatar Jason Madden

Catch the ValueError that sys._getframe() can raise when there are no Python frames.

This can happen in the embedded case, when the CPython C api is used to directly call Greenlet.spawn, which itself is now implemented in C.

Fixes #1212.
parent 5e1aab55
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
- Nothing changed yet. - Nothing changed yet.
- Fix embedded uses of :func:`gevent.Greenlet.spawn`, especially under
uwsgi. Reported in :issue:`1212` by Kunal Gangakhedkar.
1.3.0 (2018-05-11) 1.3.0 (2018-05-11)
================== ==================
......
...@@ -130,7 +130,18 @@ def _Frame_from_list(frames): ...@@ -130,7 +130,18 @@ def _Frame_from_list(frames):
return previous return previous
def _extract_stack(limit): def _extract_stack(limit):
try:
frame = sys_getframe() frame = sys_getframe()
except ValueError:
# In certain embedded cases that directly use the Python C api
# to call Greenlet.spawn (e.g., uwsgi) this can raise
# `ValueError: call stack is not deep enough`. This is because
# the Cython stack frames for Greenlet.spawn ->
# Greenlet.__init__ -> _extract_stack are all on the C level,
# not the Python level.
# See https://github.com/gevent/gevent/issues/1212
frame = None
frames = [] frames = []
while limit and frame is not None: while limit and frame is not None:
......
...@@ -18,11 +18,12 @@ ...@@ -18,11 +18,12 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
import re
import unittest
import greentest import greentest
import gevent import gevent
import re
from gevent import sleep, with_timeout, getcurrent from gevent import sleep, with_timeout, getcurrent
from gevent import greenlet from gevent import greenlet
from gevent.event import AsyncResult from gevent.event import AsyncResult
...@@ -699,6 +700,22 @@ class TestBasic(greentest.TestCase): ...@@ -699,6 +700,22 @@ class TestBasic(greentest.TestCase):
gevent.sleep(0.01) gevent.sleep(0.01)
def test_getframe_value_error(self):
def get():
raise ValueError("call stack is not deep enough")
try:
ogf = greenlet.sys_getframe
except AttributeError:
# Must be running cython compiled
raise unittest.SkipTest("Cannot mock when Cython compiled")
greenlet.sys_getframe = get
try:
child = greenlet.Greenlet()
self.assertIsNone(child.spawning_stack)
finally:
greenlet.sys_getframe = ogf
class TestStart(greentest.TestCase): class TestStart(greentest.TestCase):
def test(self): def test(self):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment