Repository: tox-dev/sphinx-autodoc-typehints (python)

Issue:
Unexpected output when class attribute and constructor arg have same name (napoleon bug)
This is an upstream bug: https://github.com/sphinx-doc/sphinx/pull/11143

Suppose we have the following class:
```py
class Example:
    """
    A Class

    Parameters
    ----------
    blah:
        Description of parameter blah
    """
    def __init__(self, blah: CodeType):
        pass

    blah: ModuleType
```

We get the following output (just the parameters):
```
   Parameters:
      **blah** (*module*) -- Description of parameter blah
```
Expected output:
```
   Parameters:
      **blah** ("CodeType") -- Description of parameter blah
```
If you want I can provide a monkey patch that implements my fix in https://github.com/sphinx-doc/sphinx/pull/11143 on existing versions of sphinx. I'm not sure how far we want to go in patching with upstream bugs.

Pull request:
Disable GoogleDocstring._lookup_annotation
This function never does the correct thing and even if it did the correct thing it would be a problem for us because the rendered type annotation isn't processed by `sphinx-autodoc-typehints`.

Resolves #308

Patch:
diff --git a/src/sphinx_autodoc_typehints/__init__.py b/src/sphinx_autodoc_typehints/__init__.py
index c87d0d2..9185819 100644
--- a/src/sphinx_autodoc_typehints/__init__.py
+++ b/src/sphinx_autodoc_typehints/__init__.py
@@ -19,6 +19,7 @@ from sphinx.config import Config
 from sphinx.environment import BuildEnvironment
 from sphinx.ext.autodoc import Options
 from sphinx.ext.autodoc.mock import mock
+from sphinx.ext.napoleon.docstring import GoogleDocstring
 from sphinx.util import logging
 from sphinx.util.inspect import signature as sphinx_signature
 from sphinx.util.inspect import stringify_signature
@@ -808,6 +809,18 @@ def fix_autodoc_typehints_for_overloaded_methods() -> None:
     del MethodDocumenter.format_signature
 
 
+def patched_lookup_annotation(*_args: Any) -> str:  # noqa: U101
+    """GoogleDocstring._lookup_annotation sometimes adds incorrect type
+    annotations to constructor parameters (and otherwise does nothing). Disable
+    it so we can handle this on our own.
+    """
+    return ""
+
+
+def patch_google_docstring_lookup_annotation() -> None:
+    GoogleDocstring._lookup_annotation = patched_lookup_annotation  # type: ignore[assignment]
+
+
 def setup(app: Sphinx) -> dict[str, bool]:
     app.add_config_value("always_document_param_types", False, "html")
     app.add_config_value("typehints_fully_qualified", False, "env")
@@ -823,6 +836,7 @@ def setup(app: Sphinx) -> dict[str, bool]:
     app.connect("autodoc-process-docstring", process_docstring)
     fix_autodoc_typehints_for_overloaded_methods()
     patch_attribute_handling(app)
+    patch_google_docstring_lookup_annotation()
     return {"parallel_read_safe": True}
 
 


Test patch:
diff --git a/tests/test_integration.py b/tests/test_integration.py
index 2907dbf..b1d614e 100644
--- a/tests/test_integration.py
+++ b/tests/test_integration.py
@@ -5,8 +5,8 @@ from inspect import isclass
 from io import StringIO
 from mailbox import Mailbox
 from pathlib import Path
-from textwrap import dedent
-from types import CodeType
+from textwrap import dedent, indent
+from types import CodeType, ModuleType
 from typing import Any, Callable, Optional, TypeVar, Union, overload
 
 import pytest
@@ -909,6 +909,38 @@ def decorator_2(f: Any) -> Any:
     f
 
 
+@expected(
+    """
+    class mod.ParamAndAttributeHaveSameName(blah)
+
+       A Class
+
+       Parameters:
+          **blah** ("CodeType") -- Description of parameter blah
+
+       blah: "ModuleType"
+
+          Description of attribute blah
+
+    """
+)
+class ParamAndAttributeHaveSameName:
+    """
+    A Class
+
+    Parameters
+    ----------
+    blah:
+        Description of parameter blah
+    """
+
+    def __init__(self, blah: CodeType):  # noqa: U100
+        pass
+
+    blah: ModuleType
+    """Description of attribute blah"""
+
+
 AUTO_FUNCTION = ".. autofunction:: mod.{}"
 AUTO_CLASS = """\
 .. autoclass:: mod.{}
@@ -949,5 +981,6 @@ def test_integration(app: SphinxTestApp, status: StringIO, warning: StringIO, mo
     try:
         assert result.strip() == dedent(expected).strip()
     except Exception:
-        print(f"Result was:\n{result}\n\n")
+        indented = indent(f'"""\n{result}\n"""', " " * 4)
+        print(f"@expected(\n{indented}\n)\n")
         raise