Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pdoc trips over unittest.mock.Mock #350

Open
Terrance opened this issue Aug 6, 2021 · 3 comments · May be fixed by #352
Open

pdoc trips over unittest.mock.Mock #350

Terrance opened this issue Aug 6, 2021 · 3 comments · May be fixed by #352
Labels
upstream Issue affects a dependency of ours

Comments

@Terrance
Copy link

Terrance commented Aug 6, 2021

Expected behavior

I can document classes that include mock object members (for example, when documenting testing utilities).

Actual behavior

Traceback
Traceback (most recent call last):
  File "/usr/bin/pdoc", line 33, in <module>
    sys.exit(load_entry_point('pdoc3', 'console_scripts', 'pdoc')())
  File "/usr/lib/python3.9/site-packages/pdoc/cli.py", line 575, in main
    recursive_write_files(module, ext='.html', **template_config)
  File "/usr/lib/python3.9/site-packages/pdoc/cli.py", line 351, in recursive_write_files
    recursive_write_files(submodule, ext=ext, **kwargs)
  File "/usr/lib/python3.9/site-packages/pdoc/cli.py", line 346, in recursive_write_files
    f.write(m.html(**kwargs))
  File "/usr/lib/python3.9/site-packages/pdoc/__init__.py", line 880, in html
    html = _render_template('/html.mako', module=self, **kwargs)
  File "/usr/lib/python3.9/site-packages/pdoc/__init__.py", line 155, in _render_template
    return t.render(**config).strip()
  File "/usr/lib/python3.9/site-packages/mako/template.py", line 473, in render
    return runtime._render(self, self.callable_, args, data)
  File "/usr/lib/python3.9/site-packages/mako/runtime.py", line 878, in _render
    _render_context(
  File "/usr/lib/python3.9/site-packages/mako/runtime.py", line 920, in _render_context
    _exec_template(inherit, lclcontext, args=args, kwargs=kwargs)
  File "/usr/lib/python3.9/site-packages/mako/runtime.py", line 947, in _exec_template
    callable_(context, *args, **kwargs)
  File "_html_mako", line 143, in render_body
  File "_html_mako", line 45, in show_module
  File "_html_mako", line 500, in render_show_module
  File "_html_mako", line 321, in show_func
  File "/usr/lib/python3.9/site-packages/pdoc/__init__.py", line 1431, in params
    return self._params(self, annotate=annotate, link=link, module=self.module)
  File "/usr/lib/python3.9/site-packages/pdoc/__init__.py", line 1447, in _params
    signature = inspect.signature(doc_obj.obj)
  File "/usr/lib/python3.9/inspect.py", line 3130, in signature
    return Signature.from_callable(obj, follow_wrapped=follow_wrapped)
  File "/usr/lib/python3.9/inspect.py", line 2879, in from_callable
    return _signature_from_callable(obj, sigcls=cls,
  File "/usr/lib/python3.9/inspect.py", line 2330, in _signature_from_callable
    return _signature_from_function(sigcls, obj,
  File "/usr/lib/python3.9/inspect.py", line 2173, in _signature_from_function
    positional = arg_names[:pos_count]
TypeError: 'Mock' object is not subscriptable

A naive solution would be to just not treat mocks as functions:

diff --git a/pdoc/__init__.py b/pdoc/__init__.py
index 0f05b2c..7ac7eb7 100644
--- a/pdoc/__init__.py
+++ b/pdoc/__init__.py
@@ -27,4 +27,5 @@ from typing import (  # noqa: F401
     Optional, Set, Tuple, Type, TypeVar, Union,
 )
+from unittest.mock import Mock
 from warnings import warn

@@ -411,5 +412,5 @@ def _is_public(ident_name):

 def _is_function(obj):
-    return inspect.isroutine(obj) and callable(obj)
+    return inspect.isroutine(obj) and callable(obj) and not isinstance(obj, Mock)

To reproduce

class MockService:

    async def _run(value: int) -> int: ...
    run = AsyncMock(spec=_run, side_effect=lambda value: value + 1)

Additional info

  • pdoc version: 0.10.0 / master
@kernc
Copy link
Member

kernc commented Aug 9, 2021

This looks like one of the mock bugs in Python since inspect.signature(MockService.run) is what raises.

I guess we can apply the proposed workaround. Can you make it a pull request?

@kernc kernc added the upstream Issue affects a dependency of ours label Aug 9, 2021
@Terrance Terrance linked a pull request Aug 9, 2021 that will close this issue
@kernc
Copy link
Member

kernc commented Aug 9, 2021

+    return inspect.isroutine(obj) and callable(obj) and not isinstance(obj, Mock)

This will then fall through to interpreting MockService.run as a non-callable variable. How do we feel about that?

@Terrance
Copy link
Author

Terrance commented Aug 9, 2021

For my use case it's acceptable enough -- I only really need the bare minimum for documentation on these classes (namely the class docstring), and having non-descript members for mock objects at least indicates they're present.

Ideally it'd show the signature of the mock's function spec if it has one, though that doesn't seem to be easily accessible (Mock._spec_signature), and there's probably a whole rabbit hole of other mock "types" to consider. Can we just identify it as a Mock object somehow?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
upstream Issue affects a dependency of ours
Development

Successfully merging a pull request may close this issue.

2 participants