From cd664bdd3b83e544feb3a80c75e4037f5da72d39 Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Sun, 7 Dec 2014 00:02:30 -0800 Subject: [PATCH] Correctly identify stack level in ``_extract_engine`` Add on the needed frame evaluation logic to be able to correctly locate where users frames start and ours end so that we can correctly report the stack level in the deprecation messages (which the warning module will use to show the location of the users code that is using the deprecated usage). Change-Id: Iae5919fb0f79ffbf9e1784723dc8da1cefdb9f27 --- taskflow/engines/helpers.py | 87 +++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 28 deletions(-) diff --git a/taskflow/engines/helpers.py b/taskflow/engines/helpers.py index 5877ee41..9ffff0dc 100644 --- a/taskflow/engines/helpers.py +++ b/taskflow/engines/helpers.py @@ -15,6 +15,8 @@ # under the License. import contextlib +import itertools +import traceback from oslo.utils import importutils import six @@ -34,39 +36,68 @@ ENGINES_NAMESPACE = 'taskflow.engines' # The default entrypoint engine type looked for when it is not provided. ENGINE_DEFAULT = 'default' +# TODO(harlowja): only used during the deprecation cycle, remove it once +# ``_extract_engine_compat`` is also gone... +_FILE_NAMES = [__file__] +if six.PY2: + # Due to a bug in py2.x the __file__ may point to the pyc file & since + # we are using the traceback module and that module only shows py files + # we have to do a slight adjustment to ensure we match correctly... + # + # This is addressed in https://www.python.org/dev/peps/pep-3147/#file + if __file__.endswith("pyc"): + _FILE_NAMES.append(__file__[0:-1]) +_FILE_NAMES = tuple(_FILE_NAMES) + -@deprecation.renamed_kwarg('engine_conf', 'engine', - version="0.6", removal_version="?", - # This is set to none since this function is called - # from 2 other functions in this module, both of - # which have different stack levels, possibly we - # can fix this in the future... - stacklevel=None) def _extract_engine(**kwargs): """Extracts the engine kind and any associated options.""" - options = {} - kind = kwargs.pop('engine', None) - engine_conf = kwargs.pop('engine_conf', None) - if engine_conf is not None: - if isinstance(engine_conf, six.string_types): - kind = engine_conf + + def _compat_extract(**kwargs): + options = {} + kind = kwargs.pop('engine', None) + engine_conf = kwargs.pop('engine_conf', None) + if engine_conf is not None: + if isinstance(engine_conf, six.string_types): + kind = engine_conf + else: + options.update(engine_conf) + kind = options.pop('engine', None) + if not kind: + kind = ENGINE_DEFAULT + # See if it's a URI and if so, extract any further options... + try: + uri = misc.parse_uri(kind) + except (TypeError, ValueError): + pass else: - options.update(engine_conf) - kind = options.pop('engine', None) - if not kind: - kind = ENGINE_DEFAULT - # See if it's a URI and if so, extract any further options... - try: - uri = misc.parse_uri(kind) - except (TypeError, ValueError): - pass + kind = uri.scheme + options = misc.merge_uri(uri, options.copy()) + # Merge in any leftover **kwargs into the options, this makes it so + # that the provided **kwargs override any URI or engine_conf specific + # options. + options.update(kwargs) + return (kind, options) + + engine_conf = kwargs.get('engine_conf', None) + if engine_conf is not None: + # Figure out where our code ends and the calling code begins (this is + # needed since this code is called from two functions in this module, + # which means the stack level will vary by one depending on that). + finder = itertools.takewhile(lambda frame: frame[0] in _FILE_NAMES, + reversed(traceback.extract_stack())) + stacklevel = sum(1 for _frame in finder) + decorator = deprecation.renamed_kwarg('engine_conf', 'engine', + version="0.6", + removal_version="?", + # Three is added on since the + # decorator adds three of its own + # stack levels that we need to + # hop out of... + stacklevel=stacklevel + 3) + return decorator(_compat_extract)(**kwargs) else: - kind = uri.scheme - options = misc.merge_uri(uri, options.copy()) - # Merge in any leftover **kwargs into the options, this makes it so that - # the provided **kwargs override any URI or engine_conf specific options. - options.update(kwargs) - return (kind, options) + return _compat_extract(**kwargs) def _fetch_factory(factory_name):