diff --git a/lib/galaxy/jobs/mapper.py b/lib/galaxy/jobs/mapper.py index d97bba62df6..6be1e20ec82 100644 --- a/lib/galaxy/jobs/mapper.py +++ b/lib/galaxy/jobs/mapper.py @@ -1,10 +1,10 @@ import importlib -import inspect import logging import galaxy.jobs.rules from galaxy.jobs import stock_rules from galaxy.jobs.dynamic_tool_destination import map_tool_to_destination +from galaxy.util.getargspec import getfullargspec from galaxy.util.submodules import import_submodules from .rule_helper import RuleHelper @@ -56,7 +56,7 @@ class JobRunnerMapper(object): self.rules_module = importlib.import_module(module_name) def __invoke_expand_function(self, expand_function, destination): - function_arg_names = inspect.getargspec(expand_function).args + function_arg_names = getfullargspec(expand_function).args app = self.job_wrapper.app possible_args = { "job_id": self.job_wrapper.job_id, diff --git a/lib/galaxy/jobs/splitters/multi.py b/lib/galaxy/jobs/splitters/multi.py index 4396c98d905..cee060ad730 100644 --- a/lib/galaxy/jobs/splitters/multi.py +++ b/lib/galaxy/jobs/splitters/multi.py @@ -1,9 +1,9 @@ -import inspect import logging import os import shutil from galaxy import model, util +from galaxy.util.getargspec import getfullargspec log = logging.getLogger(__name__) @@ -157,7 +157,7 @@ def do_merge(job_wrapper, task_wrappers): % (len(output_files), len(task_dirs), output_file_name)) # First two args to merge always output_files and path of dataset. More # complicated merge methods may require more parameters. Set those up here. - extra_merge_arg_names = inspect.getargspec(output_type.merge).args[2:] + extra_merge_arg_names = getfullargspec(output_type.merge).args[2:] extra_merge_args = {} if "output_dataset" in extra_merge_arg_names: extra_merge_args["output_dataset"] = output_dataset diff --git a/lib/galaxy/tools/lint.py b/lib/galaxy/tools/lint.py index 237b6ab2925..99efabd8678 100644 --- a/lib/galaxy/tools/lint.py +++ b/lib/galaxy/tools/lint.py @@ -4,6 +4,7 @@ from __future__ import print_function import inspect from galaxy.util import submodules +from galaxy.util.getargspec import getfullargspec from .parser import get_tool_source @@ -42,7 +43,7 @@ def lint_tool_source_with(lint_context, tool_source, extra_modules=[]): # Look at the first argument to the linter to decide # if we should lint the XML description or the abstract # tool parser object. - first_arg = inspect.getargspec(value).args[0] + first_arg = getfullargspec(value).args[0] if first_arg == "tool_xml": if tool_xml is None: # XML linter and non-XML tool, skip for now diff --git a/lib/galaxy/tools/verify/asserts/__init__.py b/lib/galaxy/tools/verify/asserts/__init__.py index 8810a032c44..ccdadb057e1 100644 --- a/lib/galaxy/tools/verify/asserts/__init__.py +++ b/lib/galaxy/tools/verify/asserts/__init__.py @@ -1,8 +1,8 @@ -import inspect import logging import sys from galaxy.util import unicodify +from galaxy.util.getargspec import getfullargspec log = logging.getLogger(__name__) @@ -43,7 +43,7 @@ def verify_assertion(data, assertion_description): errmsg = "Unable to find test function associated with XML tag '%s'. Check your tool file syntax." % tag raise AssertionError(errmsg) - assert_function_args = inspect.getargspec(assert_function).args + assert_function_args = getfullargspec(assert_function).args args = {} for attribute, value in assertion_description["attributes"].items(): if attribute in assert_function_args: diff --git a/lib/galaxy/util/getargspec.py b/lib/galaxy/util/getargspec.py new file mode 100644 index 00000000000..47871901683 --- /dev/null +++ b/lib/galaxy/util/getargspec.py @@ -0,0 +1,9 @@ +import inspect + + +def getfullargspec(func): + try: + return inspect.getfullargspec(func) + except AttributeError: + # on python 2 + return inspect.getargspec(func) diff --git a/lib/galaxy/util/pastescript/loadwsgi.py b/lib/galaxy/util/pastescript/loadwsgi.py index 8d773283fcf..cae59562798 100644 --- a/lib/galaxy/util/pastescript/loadwsgi.py +++ b/lib/galaxy/util/pastescript/loadwsgi.py @@ -12,6 +12,7 @@ import pkg_resources from six import iteritems from six.moves.urllib.parse import unquote +from galaxy.util.getargspec import getfullargspec from galaxy.util.properties import NicerConfigParser @@ -58,11 +59,11 @@ def fix_type_error(exc_info, callable, varargs, kwargs): if exc_info is None: exc_info = sys.exc_info() if (exc_info[0] != TypeError or - str(exc_info[1]).find('arguments') == -1 or + str(exc_info[1]).find('argument') == -1 or getattr(exc_info[1], '_type_error_fixed', False)): return exc_info exc_info[1]._type_error_fixed = True - argspec = inspect.formatargspec(*inspect.getargspec(callable)) + argspec = inspect.formatargspec(*getfullargspec(callable)) args = ', '.join(map(_short_repr, varargs)) if kwargs and args: args += ', ' diff --git a/lib/galaxy/web/framework/decorators.py b/lib/galaxy/web/framework/decorators.py index d7e726c55fd..14779e5d501 100644 --- a/lib/galaxy/web/framework/decorators.py +++ b/lib/galaxy/web/framework/decorators.py @@ -1,4 +1,3 @@ -import inspect import logging from functools import wraps from json import loads @@ -12,6 +11,7 @@ from galaxy.util import ( parse_non_hex_float, unicodify ) +from galaxy.util.getargspec import getfullargspec from galaxy.util.json import safe_dumps from galaxy.web.framework import url_for @@ -176,7 +176,7 @@ def __extract_payload_from_request(trans, func, kwargs): # in the payload. Therefore, the decorated method's formal arguments are discovered through reflection and removed from # the payload dictionary. This helps to prevent duplicate argument conflicts in downstream methods. payload = kwargs.copy() - named_args, _, _, _ = inspect.getargspec(func) + named_args = getfullargspec(func).args for arg in named_args: payload.pop(arg, None) for k, v in payload.items(): diff --git a/test/unit/test_fix_type_error.py b/test/unit/test_fix_type_error.py new file mode 100644 index 00000000000..a107daf9ecc --- /dev/null +++ b/test/unit/test_fix_type_error.py @@ -0,0 +1,23 @@ +import six + +from galaxy.util.pastescript.loadwsgi import fix_type_error + +if six.PY2: + argtype = ' keyword' +else: + argtype = '' +EXP_STRING = "a_func() got multiple values for%s argument 'kwarg'; got (1, 2, kwarg=...), wanted (argone, kwarg=True)" % argtype + + +def a_func(argone, kwarg=True): + pass + + +def test_fix_type_error(): + args = [1, 2] + kwargs = {'kwarg': False} + try: + a_func(*args, **kwargs) + except TypeError: + exc_info = fix_type_error(None, a_func, args, kwargs) + assert exc_info[1].args[0] == EXP_STRING