From 7aea2eec9ea557d49d37482a6f16fe0ff1402335 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Wed, 10 Apr 2024 12:52:47 +0300 Subject: [PATCH 1/3] gh-117692: Fix `AttributeError` in `DocTestFinder` on wrapped `builtin_or_method` (GH-117699) (cherry picked from commit 4bb7d121bc0a3fd00a3c72cd915b5dd8fac5616e) Co-authored-by: Nikita Sobolev Co-authored-by: Alex Waygood --- Lib/doctest.py | 9 ++++++++- Lib/test/test_doctest/test_doctest.py | 14 ++++++++++++++ .../2024-04-09-23-22-21.gh-issue-117692.EciInD.rst | 2 ++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2024-04-09-23-22-21.gh-issue-117692.EciInD.rst diff --git a/Lib/doctest.py b/Lib/doctest.py index 696bb966549255..d617d96a35a85a 100644 --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -1124,7 +1124,14 @@ def _find_lineno(self, obj, source_lines): obj = obj.fget if inspect.isfunction(obj) and getattr(obj, '__doc__', None): # We don't use `docstring` var here, because `obj` can be changed. - obj = inspect.unwrap(obj).__code__ + obj = inspect.unwrap(obj) + try: + obj = obj.__code__ + except AttributeError: + # Functions implemented in C don't necessarily + # have a __code__ attribute. + # If there's no code, there's no lineno + return None if inspect.istraceback(obj): obj = obj.tb_frame if inspect.isframe(obj): obj = obj.f_code if inspect.iscode(obj): diff --git a/Lib/test/test_doctest/test_doctest.py b/Lib/test/test_doctest/test_doctest.py index 9c8a8ba690d557..d6cebf687b0955 100644 --- a/Lib/test/test_doctest/test_doctest.py +++ b/Lib/test/test_doctest/test_doctest.py @@ -2496,6 +2496,20 @@ def test_look_in_unwrapped(): 'one other test' """ +@doctest_skip_if(support.check_impl_detail(cpython=False)) +def test_wrapped_c_func(): + """ + # https://github.com/python/cpython/issues/117692 + >>> import binascii + >>> from test.test_doctest.decorator_mod import decorator + + >>> c_func_wrapped = decorator(binascii.b2a_hex) + >>> tests = doctest.DocTestFinder(exclude_empty=False).find(c_func_wrapped) + >>> for test in tests: + ... print(test.lineno, test.name) + None b2a_hex + """ + def test_unittest_reportflags(): """Default unittest reporting flags can be set to control reporting diff --git a/Misc/NEWS.d/next/Library/2024-04-09-23-22-21.gh-issue-117692.EciInD.rst b/Misc/NEWS.d/next/Library/2024-04-09-23-22-21.gh-issue-117692.EciInD.rst new file mode 100644 index 00000000000000..98a6e125c440ef --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-04-09-23-22-21.gh-issue-117692.EciInD.rst @@ -0,0 +1,2 @@ +Fixes a bug when :class:`doctest.DocTestFinder` was failing on wrapped +``builtin_function_or_method``. From 2410d2a475e2c4006b0d479a20972a0389675c34 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Wed, 10 Apr 2024 16:57:59 +0300 Subject: [PATCH 2/3] Update test_doctest.py --- Lib/test/test_doctest/test_doctest.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_doctest/test_doctest.py b/Lib/test/test_doctest/test_doctest.py index d6cebf687b0955..0a0062b73c0337 100644 --- a/Lib/test/test_doctest/test_doctest.py +++ b/Lib/test/test_doctest/test_doctest.py @@ -2496,19 +2496,19 @@ def test_look_in_unwrapped(): 'one other test' """ -@doctest_skip_if(support.check_impl_detail(cpython=False)) -def test_wrapped_c_func(): - """ - # https://github.com/python/cpython/issues/117692 - >>> import binascii - >>> from test.test_doctest.decorator_mod import decorator - - >>> c_func_wrapped = decorator(binascii.b2a_hex) - >>> tests = doctest.DocTestFinder(exclude_empty=False).find(c_func_wrapped) - >>> for test in tests: - ... print(test.lineno, test.name) - None b2a_hex - """ +if support.check_impl_detail(cpython=True): + def test_wrapped_c_func(): + """ + # https://github.com/python/cpython/issues/117692 + >>> import binascii + >>> from test.test_doctest.decorator_mod import decorator + + >>> c_func_wrapped = decorator(binascii.b2a_hex) + >>> tests = doctest.DocTestFinder(exclude_empty=False).find(c_func_wrapped) + >>> for test in tests: + ... print(test.lineno, test.name) + None b2a_hex + """ def test_unittest_reportflags(): """Default unittest reporting flags can be set to control reporting From fd446ad289ca5bfed1644d6b6fa441a2cfcfbc10 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 10 Apr 2024 15:00:51 +0100 Subject: [PATCH 3/3] Update test_doctest.py --- Lib/test/test_doctest/test_doctest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_doctest/test_doctest.py b/Lib/test/test_doctest/test_doctest.py index 0a0062b73c0337..2722661a2363fe 100644 --- a/Lib/test/test_doctest/test_doctest.py +++ b/Lib/test/test_doctest/test_doctest.py @@ -2502,7 +2502,7 @@ def test_wrapped_c_func(): # https://github.com/python/cpython/issues/117692 >>> import binascii >>> from test.test_doctest.decorator_mod import decorator - + >>> c_func_wrapped = decorator(binascii.b2a_hex) >>> tests = doctest.DocTestFinder(exclude_empty=False).find(c_func_wrapped) >>> for test in tests: