Merge "remove support for legacy v2 generator extensions"
This commit is contained in:
commit
fe11ed9afa
@ -15,7 +15,6 @@
|
||||
# under the License.
|
||||
|
||||
import functools
|
||||
import inspect
|
||||
import math
|
||||
import time
|
||||
|
||||
@ -545,90 +544,25 @@ class Resource(wsgi.Application):
|
||||
def deserialize(self, body):
|
||||
return JSONDeserializer().deserialize(body)
|
||||
|
||||
# NOTE(sdague): I didn't start the fire, however here is what all
|
||||
# of this is about.
|
||||
#
|
||||
# In the legacy v2 code stack, extensions could extend actions
|
||||
# with a generator that let 1 method be split into a top and
|
||||
# bottom half. The top half gets executed before the main
|
||||
# processing of the request (so effectively gets to modify the
|
||||
# request before it gets to the main method).
|
||||
#
|
||||
# Returning a response triggers a shortcut to fail out. The
|
||||
# response will nearly always be a failure condition, as it ends
|
||||
# up skipping further processing one level up from here.
|
||||
#
|
||||
# This then passes on the list of extensions, in reverse order,
|
||||
# on. post_process will run through all those, again with same
|
||||
# basic logic.
|
||||
#
|
||||
# In tree this is only used in the legacy v2 stack, and only in
|
||||
# the DiskConfig and SchedulerHints from what I can see.
|
||||
#
|
||||
# pre_process_extensions can be removed when the legacyv2 code
|
||||
# goes away. post_process_extensions can be massively simplified
|
||||
# at that point.
|
||||
def pre_process_extensions(self, extensions, request, action_args):
|
||||
# List of callables for post-processing extensions
|
||||
post = []
|
||||
|
||||
for ext in extensions:
|
||||
if inspect.isgeneratorfunction(ext):
|
||||
response = None
|
||||
|
||||
# If it's a generator function, the part before the
|
||||
# yield is the preprocessing stage
|
||||
try:
|
||||
with ResourceExceptionHandler():
|
||||
gen = ext(req=request, **action_args)
|
||||
response = next(gen)
|
||||
except Fault as ex:
|
||||
response = ex
|
||||
|
||||
# We had a response...
|
||||
if response:
|
||||
return response, []
|
||||
|
||||
# No response, queue up generator for post-processing
|
||||
post.append(gen)
|
||||
else:
|
||||
# Regular functions only perform post-processing
|
||||
post.append(ext)
|
||||
|
||||
# None is response, it means we keep going. We reverse the
|
||||
# extension list for post-processing.
|
||||
return None, reversed(post)
|
||||
|
||||
def post_process_extensions(self, extensions, resp_obj, request,
|
||||
action_args):
|
||||
def process_extensions(self, extensions, resp_obj, request,
|
||||
action_args):
|
||||
for ext in extensions:
|
||||
response = None
|
||||
if inspect.isgenerator(ext):
|
||||
# If it's a generator, run the second half of
|
||||
# processing
|
||||
try:
|
||||
with ResourceExceptionHandler():
|
||||
response = ext.send(resp_obj)
|
||||
except StopIteration:
|
||||
# Normal exit of generator
|
||||
continue
|
||||
except Fault as ex:
|
||||
response = ex
|
||||
else:
|
||||
# Regular functions get post-processing...
|
||||
try:
|
||||
with ResourceExceptionHandler():
|
||||
response = ext(req=request, resp_obj=resp_obj,
|
||||
**action_args)
|
||||
except exception.VersionNotFoundForAPIMethod:
|
||||
# If an attached extension (@wsgi.extends) for the
|
||||
# method has no version match its not an error. We
|
||||
# just don't run the extends code
|
||||
continue
|
||||
except Fault as ex:
|
||||
response = ex
|
||||
# Regular functions get post-processing...
|
||||
try:
|
||||
with ResourceExceptionHandler():
|
||||
response = ext(req=request, resp_obj=resp_obj,
|
||||
**action_args)
|
||||
except exception.VersionNotFoundForAPIMethod:
|
||||
# If an attached extension (@wsgi.extends) for the
|
||||
# method has no version match its not an error. We
|
||||
# just don't run the extends code
|
||||
continue
|
||||
except Fault as ex:
|
||||
response = ex
|
||||
|
||||
# We had a response...
|
||||
# We had a response return it, to exit early. This is
|
||||
# actually a failure mode. None is success.
|
||||
if response:
|
||||
return response
|
||||
|
||||
@ -727,16 +661,12 @@ class Resource(wsgi.Application):
|
||||
'context_project_id': context.project_id}
|
||||
return Fault(webob.exc.HTTPBadRequest(explanation=msg))
|
||||
|
||||
# Run pre-processing extensions
|
||||
response, post = self.pre_process_extensions(extensions,
|
||||
request, action_args)
|
||||
|
||||
if not response:
|
||||
try:
|
||||
with ResourceExceptionHandler():
|
||||
action_result = self.dispatch(meth, request, action_args)
|
||||
except Fault as ex:
|
||||
response = ex
|
||||
response = None
|
||||
try:
|
||||
with ResourceExceptionHandler():
|
||||
action_result = self.dispatch(meth, request, action_args)
|
||||
except Fault as ex:
|
||||
response = ex
|
||||
|
||||
if not response:
|
||||
# No exceptions; convert action_result into a
|
||||
@ -754,8 +684,8 @@ class Resource(wsgi.Application):
|
||||
# Do a preserialize to set up the response object
|
||||
if hasattr(meth, 'wsgi_code'):
|
||||
resp_obj._default_code = meth.wsgi_code
|
||||
# Process post-processing extensions
|
||||
response = self.post_process_extensions(post, resp_obj,
|
||||
# Process extensions
|
||||
response = self.process_extensions(extensions, resp_obj,
|
||||
request, action_args)
|
||||
|
||||
if resp_obj and not response:
|
||||
|
@ -10,8 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import inspect
|
||||
|
||||
import mock
|
||||
import six
|
||||
import testscenarios
|
||||
@ -785,7 +783,7 @@ class ResourceTest(MicroversionedTest):
|
||||
self.assertEqual(method, extended._delete)
|
||||
self.assertEqual(extensions, [])
|
||||
|
||||
def test_pre_process_extensions_regular(self):
|
||||
def test_process_extensions_regular(self):
|
||||
class Controller(object):
|
||||
def index(self, req, pants=None):
|
||||
return pants
|
||||
@ -803,96 +801,12 @@ class ResourceTest(MicroversionedTest):
|
||||
called.append(2)
|
||||
return None
|
||||
|
||||
extensions = [extension1, extension2]
|
||||
response, post = resource.pre_process_extensions(extensions, None, {})
|
||||
self.assertEqual(called, [])
|
||||
self.assertIsNone(response)
|
||||
self.assertEqual(list(post), [extension2, extension1])
|
||||
|
||||
def test_pre_process_extensions_generator(self):
|
||||
class Controller(object):
|
||||
def index(self, req, pants=None):
|
||||
return pants
|
||||
|
||||
controller = Controller()
|
||||
resource = wsgi.Resource(controller)
|
||||
|
||||
called = []
|
||||
|
||||
def extension1(req):
|
||||
called.append('pre1')
|
||||
yield
|
||||
called.append('post1')
|
||||
|
||||
def extension2(req):
|
||||
called.append('pre2')
|
||||
yield
|
||||
called.append('post2')
|
||||
|
||||
extensions = [extension1, extension2]
|
||||
response, post = resource.pre_process_extensions(extensions, None, {})
|
||||
post = list(post)
|
||||
self.assertEqual(called, ['pre1', 'pre2'])
|
||||
self.assertIsNone(response)
|
||||
self.assertEqual(len(post), 2)
|
||||
self.assertTrue(inspect.isgenerator(post[0]))
|
||||
self.assertTrue(inspect.isgenerator(post[1]))
|
||||
|
||||
for gen in post:
|
||||
try:
|
||||
gen.send(None)
|
||||
except StopIteration:
|
||||
continue
|
||||
|
||||
self.assertEqual(called, ['pre1', 'pre2', 'post2', 'post1'])
|
||||
|
||||
def test_pre_process_extensions_generator_response(self):
|
||||
class Controller(object):
|
||||
def index(self, req, pants=None):
|
||||
return pants
|
||||
|
||||
controller = Controller()
|
||||
resource = wsgi.Resource(controller)
|
||||
|
||||
called = []
|
||||
|
||||
def extension1(req):
|
||||
called.append('pre1')
|
||||
yield 'foo'
|
||||
|
||||
def extension2(req):
|
||||
called.append('pre2')
|
||||
|
||||
extensions = [extension1, extension2]
|
||||
response, post = resource.pre_process_extensions(extensions, None, {})
|
||||
self.assertEqual(called, ['pre1'])
|
||||
self.assertEqual(response, 'foo')
|
||||
self.assertEqual(post, [])
|
||||
|
||||
def test_post_process_extensions_regular(self):
|
||||
class Controller(object):
|
||||
def index(self, req, pants=None):
|
||||
return pants
|
||||
|
||||
controller = Controller()
|
||||
resource = wsgi.Resource(controller)
|
||||
|
||||
called = []
|
||||
|
||||
def extension1(req, resp_obj):
|
||||
called.append(1)
|
||||
return None
|
||||
|
||||
def extension2(req, resp_obj):
|
||||
called.append(2)
|
||||
return None
|
||||
|
||||
response = resource.post_process_extensions([extension2, extension1],
|
||||
response = resource.process_extensions([extension2, extension1],
|
||||
None, None, {})
|
||||
self.assertEqual(called, [2, 1])
|
||||
self.assertIsNone(response)
|
||||
|
||||
def test_post_process_extensions_regular_response(self):
|
||||
def test_process_extensions_regular_response(self):
|
||||
class Controller(object):
|
||||
def index(self, req, pants=None):
|
||||
return pants
|
||||
@ -910,70 +824,11 @@ class ResourceTest(MicroversionedTest):
|
||||
called.append(2)
|
||||
return 'foo'
|
||||
|
||||
response = resource.post_process_extensions([extension2, extension1],
|
||||
response = resource.process_extensions([extension2, extension1],
|
||||
None, None, {})
|
||||
self.assertEqual(called, [2])
|
||||
self.assertEqual(response, 'foo')
|
||||
|
||||
def test_post_process_extensions_generator(self):
|
||||
class Controller(object):
|
||||
def index(self, req, pants=None):
|
||||
return pants
|
||||
|
||||
controller = Controller()
|
||||
resource = wsgi.Resource(controller)
|
||||
|
||||
called = []
|
||||
|
||||
def extension1(req):
|
||||
yield
|
||||
called.append(1)
|
||||
|
||||
def extension2(req):
|
||||
yield
|
||||
called.append(2)
|
||||
|
||||
ext1 = extension1(None)
|
||||
next(ext1)
|
||||
ext2 = extension2(None)
|
||||
next(ext2)
|
||||
|
||||
response = resource.post_process_extensions([ext2, ext1],
|
||||
None, None, {})
|
||||
|
||||
self.assertEqual(called, [2, 1])
|
||||
self.assertIsNone(response)
|
||||
|
||||
def test_post_process_extensions_generator_response(self):
|
||||
class Controller(object):
|
||||
def index(self, req, pants=None):
|
||||
return pants
|
||||
|
||||
controller = Controller()
|
||||
resource = wsgi.Resource(controller)
|
||||
|
||||
called = []
|
||||
|
||||
def extension1(req):
|
||||
yield
|
||||
called.append(1)
|
||||
|
||||
def extension2(req):
|
||||
yield
|
||||
called.append(2)
|
||||
yield 'foo'
|
||||
|
||||
ext1 = extension1(None)
|
||||
next(ext1)
|
||||
ext2 = extension2(None)
|
||||
next(ext2)
|
||||
|
||||
response = resource.post_process_extensions([ext2, ext1],
|
||||
None, None, {})
|
||||
|
||||
self.assertEqual(called, [2])
|
||||
self.assertEqual(response, 'foo')
|
||||
|
||||
def test_resource_exception_handler_type_error(self):
|
||||
# A TypeError should be translated to a Fault/HTTP 400.
|
||||
def foo(a,):
|
||||
|
Loading…
x
Reference in New Issue
Block a user