Skip to content

bug: Error when a PEP 695 generic class inherits from a class imported as an alias #449

@watsonjj

Description

@watsonjj

Description of the bug

When generated the docs with mkdocs serve, one of the classes in my project is represented by as a griffe._internal.models.Alias. This class is a typing.Generic class defined in a python stub file, declared in the PEP 695 style. This class is passed to _merge_stubs_type_parameters which produces the error AttributeError: property 'type_parameters' of 'Alias' object has no setter.

If I declare the class in the old style, where I inherit from typing.Generic, then there is no error.

To Reproduce

I don't know the internals of griffe, so I can't comment on exactly why my class is interpreted as an Alias. I've attempted to reproduce the error with simple standard Python classes, but they don't seem to be wrapped into Alias, so I have not been able to reproduce with a simple example... but I will try to explain my setup.

Inside a python stub file, I am overriding the typing of a class generated from pybind11, declaring it as a generic class in the style of PEP 695:

# Inside __init__.pyi

import typing
from sstcam_eventbuilder._sstcam_eventbuilder_buffer import EventBuffer as _EventBuffer

T = typing.TypeVar("T")

class EventBuffer[T](_EventBuffer):
    ...

And exposing the original object from the pybind11 binary in the __init__.py

# Inside __init__.py

from sstcam_eventbuilder._sstcam_eventbuilder_buffer import (
    EventBuffer,
)

__all__ = (
    "EventBuffer",
)

The error also occurs for other pybind11-generated objects if I attempt the same pattern as above with them. Otherwise they are fine.

If I instead do the old style for declaring Generics, then no error is raised and the docs are generated without problem.

# Inside __init__.pyi

import typing
from sstcam_eventbuilder._sstcam_eventbuilder_buffer import EventBuffer as _EventBuffer

T = typing.TypeVar("T")

class EventBuffer(_EventBuffer, typing.Generic[T]):
    ...

Full traceback

Full traceback
ERROR   -  Error reading page 'reference/sstcam_eventbuilder/index.md': property 'type_parameters' of 'Alias' object has no setter
Traceback (most recent call last):
  File "/Users/watsonjj/miniforge3/envs/sstcam/bin/mkdocs", line 10, in <module>
    sys.exit(cli())
             ^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/click/core.py", line 1485, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/click/core.py", line 1406, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/click/core.py", line 1873, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/click/core.py", line 1269, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/click/core.py", line 824, in invoke
    return callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/mkdocs/__main__.py", line 272, in serve_command
    serve.serve(**kwargs)
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/mkdocs/commands/serve.py", line 85, in serve
    builder(config)
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/mkdocs/commands/serve.py", line 67, in builder
    build(config, serve_url=None if is_clean else serve_url, dirty=is_dirty)
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/mkdocs/commands/build.py", line 310, in build
    _populate_page(file.page, config, files, dirty)
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/mkdocs/commands/build.py", line 167, in _populate_page
    page.render(config, files)
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/mkdocs/structure/pages.py", line 285, in render
    self.content = md.convert(self.markdown)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/markdown/core.py", line 363, in convert
    root = self.parser.parseDocument(self.lines).getroot()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/markdown/blockparser.py", line 117, in parseDocument
    self.parseChunk(self.root, '\n'.join(lines))
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/markdown/blockparser.py", line 136, in parseChunk
    self.parseBlocks(parent, text.split('\n\n'))
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/markdown/blockparser.py", line 158, in parseBlocks
    if processor.run(parent, blocks) is not False:
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/mkdocstrings/_internal/extension.py", line 127, in run
    html, handler, _ = self._process_block(identifier, block, heading_level)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/mkdocstrings/_internal/extension.py", line 178, in _process_block
    data: CollectorItem = handler.collect(identifier, options)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/mkdocstrings_handlers/python/_internal/handler.py", line 220, in collect
    loader.load(
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/griffe/_internal/loader.py", line 190, in load
    top_module = self._load_package(package, submodules=submodules)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/griffe/_internal/loader.py", line 540, in _load_package
    top_module = self._load_module(package.name, package.path, submodules=submodules)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/griffe/_internal/loader.py", line 563, in _load_module
    return self._load_module_path(module_name, module_path, submodules=submodules, parent=parent)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/griffe/_internal/loader.py", line 595, in _load_module_path
    self._load_submodules(module)
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/griffe/_internal/loader.py", line 600, in _load_submodules
    self._load_submodule(module, subparts, subpath)
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/griffe/_internal/loader.py", line 651, in _load_submodule
    parent_module.set_member(submodule_name, submodule)
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/griffe/_internal/mixins.py", line 199, in set_member
    value = merge_stubs(member, value)  # type: ignore[arg-type]
            ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/griffe/_internal/merger.py", line 172, in merge_stubs
    _merge_module_stubs(module, stubs)
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/griffe/_internal/merger.py", line 21, in _merge_module_stubs
    _merge_stubs_members(module, stubs)
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/griffe/_internal/merger.py", line 138, in _merge_stubs_members
    _merge_class_stubs(obj_member, stub_member)  # type: ignore[arg-type]
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/griffe/_internal/merger.py", line 27, in _merge_class_stubs
    _merge_stubs_type_parameters(class_, stubs)
  File "/Users/watsonjj/miniforge3/envs/sstcam/lib/python3.12/site-packages/griffe/_internal/merger.py", line 62, in _merge_stubs_type_parameters
    obj.type_parameters = stubs.type_parameters
    ^^^^^^^^^^^^^^^^^^^
AttributeError: property 'type_parameters' of 'Alias' object has no setter

Environment information

griffe --debug-info  # | xclip -selection clipboard
  • System: macOS-15.7.4-arm64-arm-64bit
  • Python: cpython 3.12.12 (/Users/watsonjj/miniforge3/envs/sstcam/bin/python3)
  • Environment variables:
  • Installed packages:
    • griffelib v2.0.0
    • griffecli v2.0.0
    • griffe v2.0.0

Additional context

I understand support for PEP 695 was added in #348.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions