From 616cdea25a062126382274eebdb4fcb60e755583 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Dec 05 2022 14:26:31 +0000 Subject: [PATCH 1/2] Replace deprecated inspect methods Related: https://pagure.io/koji/issue/3610 --- diff --git a/hub/kojixmlrpc.py b/hub/kojixmlrpc.py index 2d802ff..c6deb43 100644 --- a/hub/kojixmlrpc.py +++ b/hub/kojixmlrpc.py @@ -127,6 +127,7 @@ class HandlerRegistry(object): if defaults and aname in defaults: # shouldn't happen, but... del defaults[aname] + self.argspec_cache[func] = ret return ret def list_api(self): @@ -134,28 +135,23 @@ class HandlerRegistry(object): for name, func in self.funcs.items(): # the keys in self.funcs determine the name of the method as seen over xmlrpc # func.__name__ might differ (e.g. for dotted method names) - args = self._getFuncArgs(func) + sig = inspect.signature(func) + args = [] + argdesc = [] + for pname, param in sig.parameters.items(): + if param.default != inspect._empty: + args.append([pname, param.default]) + else: + args.append(pname) + argdesc = '(%s)' % ', '.join([str(x) for x in sig.parameters.values()]) argspec = self.getargspec(func) funcs.append({'name': name, 'doc': func.__doc__, 'argspec': argspec, - 'argdesc': inspect.formatargspec(*argspec), + 'argdesc': argdesc, 'args': args}) return funcs - def _getFuncArgs(self, func): - args = [] - for x in range(0, func.__code__.co_argcount): - if x == 0 and func.__code__.co_varnames[x] == "self": - continue - if func.__defaults__ and func.__code__.co_argcount - x <= len(func.__defaults__): - args.append( - (func.__code__.co_varnames[x], - func.__defaults__[x - func.__code__.co_argcount + len(func.__defaults__)])) - else: - args.append(func.__code__.co_varnames[x]) - return args - def system_listMethods(self): return list(self.funcs.keys()) @@ -167,10 +163,11 @@ class HandlerRegistry(object): func = self.funcs.get(method) if func is None: return "" - args = inspect.formatargspec(*self.getargspec(func)) - ret = '%s%s' % (method, args) + sig = inspect.signature(func) + args = ', '.join([str(x) for x in sig.parameters.values()]) + ret = f'{method}({args})' if func.__doc__: - ret += "\ndescription: %s" % func.__doc__ + ret += f'\ndescription: {func.__doc__}' return ret def get(self, name): From a141d95e569a5285a084bf6dbb19225827ae4f25 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Dec 05 2022 14:26:31 +0000 Subject: [PATCH 2/2] basic tests for kojixmlrpc --- diff --git a/hub/kojixmlrpc.py b/hub/kojixmlrpc.py index c6deb43..5c12f56 100644 --- a/hub/kojixmlrpc.py +++ b/hub/kojixmlrpc.py @@ -131,6 +131,7 @@ class HandlerRegistry(object): return ret def list_api(self): + """List available API calls""" funcs = [] for name, func in self.funcs.items(): # the keys in self.funcs determine the name of the method as seen over xmlrpc @@ -139,7 +140,7 @@ class HandlerRegistry(object): args = [] argdesc = [] for pname, param in sig.parameters.items(): - if param.default != inspect._empty: + if param.default != param.empty: args.append([pname, param.default]) else: args.append(pname) diff --git a/tests/test_hub/test_kojixmlrpc.py b/tests/test_hub/test_kojixmlrpc.py new file mode 100644 index 0000000..f81e1af --- /dev/null +++ b/tests/test_hub/test_kojixmlrpc.py @@ -0,0 +1,92 @@ +import unittest + +import kojixmlrpc + + +class TestHandler(unittest.TestCase): + def test_list_api(self): + basic_api = [ + { + 'name': '_listapi', + 'doc': 'List available API calls', + 'argspec': ([], None, None, None, [], None, {}), + 'argdesc': '()', + 'args': [] + }, + { + 'name': 'system.listMethods', + 'doc': None, + 'argspec': ([], None, None, None, [], None, {}), + 'argdesc': '()', + 'args': [] + }, + { + 'name': 'system.methodSignature', + 'doc': None, + 'argspec': (['method'], None, None, None, [], None, {}), + 'argdesc': '(method)', + 'args': ['method']}, + { + 'name': 'system.methodHelp', + 'doc': None, + 'argspec': (['method'], None, None, None, [], None, {}), + 'argdesc': '(method)', 'args': ['method'] + } + ] + h = kojixmlrpc.HandlerRegistry() + result = h.list_api() + self.assertEqual(result, basic_api) + + def test_list_methods(self): + basic_methods = { + '_listapi', + 'system.methodSignature', + 'system.listMethods', + 'system.methodHelp', + } + h = kojixmlrpc.HandlerRegistry() + result = h.system_listMethods() + self.assertEqual(set(result), basic_methods) + + def test_methodSignature(self): + h = kojixmlrpc.HandlerRegistry() + result = h.system_methodSignature('any method') + self.assertEqual(result, 'signatures not supported') + + def test_methodHelp(self): + help = '_listapi()\ndescription: List available API calls' + h = kojixmlrpc.HandlerRegistry() + result = h.system_methodHelp('_listapi') + self.assertEqual(result, help) + + def _random_method(self, par1, par2, par3=None, par4='text'): + """Random method docstring""" + pass + + def test_registered_func(self): + h = kojixmlrpc.HandlerRegistry() + h.register_function(self._random_method, name='endpoint') + + result = h.system_listMethods() + self.assertIn('endpoint', set(result)) + + result = h.list_api() + methods = {x['name']: x for x in result} + self.assertIn('endpoint', methods.keys()) + + api = methods['endpoint'] + self.assertEqual(api, { + 'name': 'endpoint', + 'doc': 'Random method docstring', + 'args': ['par1', 'par2', ['par3', None], ['par4', 'text']], + 'argdesc': "(par1, par2, par3=None, par4='text')", + 'argspec': ( + ['par1', 'par2', 'par3', 'par4'], + None, None, (None, 'text'), [], None, {} + ), + }) + + result = h.system_methodHelp('endpoint') + help = "endpoint(par1, par2, par3=None, par4='text')\ndescription: Random method docstring" + self.assertEqual(result, help) +