From ce6b36702ae0090d2f64c27f7963710217caf37a Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Fri, 13 Dec 2019 17:21:11 +0300 Subject: [PATCH] PY-34047 Handle keyword-only arguments in constructors of stub return values On the whole, such stub calls look shaggy and could probably be replaced by plain parameterless invocations altogether. It's also doubtful why we use them only when analyzing docstrings of non-function callables, but questioning whether they are needed in the first place seems out of scope of the current issue. At least we don't produce warnings while generating them anymore. GitOrigin-RevId: 25650f121e88141df081874f346d0cff2d31e3bb --- python/helpers/generator3/constants.py | 8 ++++++++ python/helpers/generator3/util_methods.py | 11 +++-------- .../after/cache/0881f89709/mod.py | 16 ++++++++++++++++ .../after/sdk_skeletons/mod.py | 16 ++++++++++++++++ .../lib.py | 9 +++++++++ .../mod.py | 15 +++++++++++++++ .../after/cache/6fa2ab704f/mod.py | 0 .../after/sdk_skeletons/mod.py | 0 .../mod.py | 0 .../tests/generator3_tests/test_generation.py | 6 +++++- 10 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/after/cache/0881f89709/mod.py create mode 100644 python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/after/sdk_skeletons/mod.py create mode 100644 python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/lib.py create mode 100644 python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/mod.py rename python/helpers/tests/generator3_tests/data/SkeletonGeneration/{keyword_only_arguments => keyword_only_arguments_in_signatures}/after/cache/6fa2ab704f/mod.py (100%) rename python/helpers/tests/generator3_tests/data/SkeletonGeneration/{keyword_only_arguments => keyword_only_arguments_in_signatures}/after/sdk_skeletons/mod.py (100%) rename python/helpers/tests/generator3_tests/data/SkeletonGeneration/{keyword_only_arguments => keyword_only_arguments_in_signatures}/mod.py (100%) diff --git a/python/helpers/generator3/constants.py b/python/helpers/generator3/constants.py index a3d8729f6a27..9797e3531deb 100644 --- a/python/helpers/generator3/constants.py +++ b/python/helpers/generator3/constants.py @@ -27,6 +27,10 @@ if version[0] >= 3: def the_exec(source, context): exec (source, context) + + # noinspection PyUnresolvedReferences + from inspect import getfullargspec + else: # < 3.0 import __builtin__ as the_builtins @@ -40,6 +44,10 @@ else: # < 3.0 #noinspection PyRedundantParentheses exec (source) in context + def getfullargspec(func): + import inspect + return inspect.getargspec(func) + ([], None, {}) + if version[0] == 2 and version[1] < 4: HAS_DECORATORS = False diff --git a/python/helpers/generator3/util_methods.py b/python/helpers/generator3/util_methods.py index aa610d215226..612c093531ba 100644 --- a/python/helpers/generator3/util_methods.py +++ b/python/helpers/generator3/util_methods.py @@ -429,12 +429,7 @@ def restore_by_inspect(p_func): """ Returns paramlist restored by inspect. """ - if version[0] > 2: - args, varg, kwarg, defaults, kwonlyargs, kwonlydefaults, _ = inspect.getfullargspec(p_func) - else: - args, varg, kwarg, defaults = inspect.getargspec(p_func) - kwonlyargs = [] - kwonlydefaults = None + args, varg, kwarg, defaults, kwonlyargs, kwonlydefaults, _ = getfullargspec(p_func) spec = [] if defaults: dcnt = len(defaults) - 1 @@ -544,8 +539,8 @@ def detect_constructor(p_class): # try to inspect the thing constr = getattr(p_class, "__init__") if constr and inspect and inspect.isfunction(constr): - args, _, _, _ = inspect.getargspec(constr) - return ", ".join(args) + args, _, _, _, kwonlyargs, _, _ = getfullargspec(constr) + return ", ".join(args + [a + '=' + a for a in kwonlyargs]) else: return None diff --git a/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/after/cache/0881f89709/mod.py b/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/after/cache/0881f89709/mod.py new file mode 100644 index 000000000000..94126b0a6c88 --- /dev/null +++ b/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/after/cache/0881f89709/mod.py @@ -0,0 +1,16 @@ +# encoding: utf-8 +# module mod +# from mod.py +# by generator 1000.0 +# no doc + +# imports +import lib as lib # + +# functions + +def function_like(p_int): # real signature unknown; restored from __doc__ + """ MyClass function_like(int) """ + return lib.MyClass(self, foo=foo) + +# no classes diff --git a/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/after/sdk_skeletons/mod.py b/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/after/sdk_skeletons/mod.py new file mode 100644 index 000000000000..94126b0a6c88 --- /dev/null +++ b/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/after/sdk_skeletons/mod.py @@ -0,0 +1,16 @@ +# encoding: utf-8 +# module mod +# from mod.py +# by generator 1000.0 +# no doc + +# imports +import lib as lib # + +# functions + +def function_like(p_int): # real signature unknown; restored from __doc__ + """ MyClass function_like(int) """ + return lib.MyClass(self, foo=foo) + +# no classes diff --git a/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/lib.py b/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/lib.py new file mode 100644 index 000000000000..ee20266cacec --- /dev/null +++ b/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/lib.py @@ -0,0 +1,9 @@ +class MyClass: + def __init__(self, *, foo=None): + pass + + def __call__(self): + """ + MyClass function_like() + """ + pass diff --git a/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/mod.py b/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/mod.py new file mode 100644 index 000000000000..9f3e08f33ab4 --- /dev/null +++ b/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_return_type_constructor/mod.py @@ -0,0 +1,15 @@ +import lib + + +class Factory: + def __call__(self, p): + """ + MyClass function_like(int) + """ + + +# Emulate synthetic non-function callable where the signature +# and the stub return value are restored from its docstring. +function_like = Factory().__call__ + +del Factory diff --git a/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments/after/cache/6fa2ab704f/mod.py b/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_signatures/after/cache/6fa2ab704f/mod.py similarity index 100% rename from python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments/after/cache/6fa2ab704f/mod.py rename to python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_signatures/after/cache/6fa2ab704f/mod.py diff --git a/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments/after/sdk_skeletons/mod.py b/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_signatures/after/sdk_skeletons/mod.py similarity index 100% rename from python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments/after/sdk_skeletons/mod.py rename to python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_signatures/after/sdk_skeletons/mod.py diff --git a/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments/mod.py b/python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_signatures/mod.py similarity index 100% rename from python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments/mod.py rename to python/helpers/tests/generator3_tests/data/SkeletonGeneration/keyword_only_arguments_in_signatures/mod.py diff --git a/python/helpers/tests/generator3_tests/test_generation.py b/python/helpers/tests/generator3_tests/test_generation.py index 4c40e9dd1907..0930e1ef20af 100644 --- a/python/helpers/tests/generator3_tests/test_generation.py +++ b/python/helpers/tests/generator3_tests/test_generation.py @@ -377,7 +377,11 @@ class SkeletonGenerationTest(FunctionalGeneratorTestCase): """) @python3_only - def test_keyword_only_arguments(self): + def test_keyword_only_arguments_in_signatures(self): + self.check_generator_output('mod', 'mod.py') + + @python3_only + def test_keyword_only_arguments_in_return_type_constructor(self): self.check_generator_output('mod', 'mod.py')