| 2661 | 2661 | @classmethod |
| 2662 | 2662 | def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any |
| 2663 | 2663 | ) -> bool: |
| 2664 | return inspect.isproperty(member) and isinstance(parent, ClassDocumenter) | |
| 2664 | if inspect.isproperty(member) and isinstance(parent, ClassDocumenter): | |
| 2665 | return True | |
| 2666 | # Check for classmethod-wrapped properties | |
| 2667 | if (isinstance(parent, ClassDocumenter) and | |
| 2668 | hasattr(parent, 'object') and parent.object is not None): | |
| 2669 | return inspect.isclassmethodproperty(member, parent.object, membername) | |
| 2670 | return False | |
| 2665 | 2671 | |
| 2666 | 2672 | def document_members(self, all_members: bool = False) -> None: |
| 2667 | 2673 | pass |
| 2676 | 2682 | if inspect.isabstractmethod(self.object): |
| 2677 | 2683 | self.add_line(' :abstractmethod:', sourcename) |
| 2678 | 2684 | |
| 2679 | if safe_getattr(self.object, 'fget', None) and self.config.autodoc_typehints != 'none': | |
| 2685 | # Handle type annotations for both regular properties and classmethod-wrapped properties | |
| 2686 | property_obj = self._get_property_object() | |
| 2687 | if property_obj and safe_getattr(property_obj, 'fget', None) and self.config.autodoc_typehints != 'none': | |
| 2680 | 2688 | try: |
| 2681 | signature = inspect.signature(self.object.fget, | |
| 2689 | signature = inspect.signature(property_obj.fget, | |
| 2682 | 2690 | type_aliases=self.config.autodoc_type_aliases) |
| 2683 | 2691 | if signature.return_annotation is not Parameter.empty: |
| 2684 | 2692 | objrepr = stringify_typehint(signature.return_annotation) |
| 2690 | 2698 | except ValueError: |
| 2691 | 2699 | return None |
| 2692 | 2700 | |
| 2701 | def _get_property_object(self) -> Any: | |
| 2702 | """Get the underlying property object, handling both regular properties and classmethod-wrapped properties.""" | |
| 2703 | # For regular properties, self.object is the property | |
| 2704 | if inspect.isproperty(self.object): | |
| 2705 | return self.object | |
| 2706 | ||
| 2707 | # For classmethod-wrapped properties, we need to get the underlying property | |
| 2708 | # from the class dictionary | |
| 2709 | if (hasattr(self, 'parent') and self.parent is not None and | |
| 2710 | hasattr(self, 'object_name') and self.object_name is not None): | |
| 2711 | class_attr = self.parent.__dict__.get(self.object_name) | |
| 2712 | if isinstance(class_attr, classmethod) and hasattr(class_attr, '__func__'): | |
| 2713 | # This is a classmethod that wraps a property | |
| 2714 | return class_attr.__func__ | |
| 2715 | ||
| 2716 | # Fallback to the original object | |
| 2717 | return self.object | |
| 2718 | ||
| 2719 | def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]: | |
| 2720 | """Get the docstring for the property, handling classmethod-wrapped properties.""" | |
| 2721 | if ignore is not None: | |
| 2722 | warnings.warn("The 'ignore' argument to autodoc.%s.get_doc() is deprecated." | |
| 2723 | % self.__class__.__name__, | |
| 2724 | RemovedInSphinx50Warning, stacklevel=2) | |
| 2725 | ||
| 2726 | # For classmethod-wrapped properties, we need to get the docstring from the underlying property | |
| 2727 | property_obj = self._get_property_object() | |
| 2728 | if property_obj is not self.object: | |
| 2729 | # This is a classmethod-wrapped property, get docstring directly from the property | |
| 2730 | docstring = safe_getattr(property_obj, '__doc__', None) | |
| 2731 | else: | |
| 2732 | # Regular property, use the standard method | |
| 2733 | docstring = getdoc(self.object, self.get_attr, self.config.autodoc_inherit_docstrings, | |
| 2734 | self.parent, self.object_name) | |
| 2735 | ||
| 2736 | if docstring: | |
| 2737 | tab_width = self.directive.state.document.settings.tab_width | |
| 2738 | return [prepare_docstring(docstring, ignore, tab_width)] | |
| 2739 | return [] | |
| 2740 | ||
| 2693 | 2741 | |
| 2694 | 2742 | class NewTypeAttributeDocumenter(AttributeDocumenter): |
| 2695 | 2743 | """ |
| Test Name | Status |
|---|---|
tests/test_domain_py.py::test_pyproperty | Fail |
tests/test_ext_autodoc_autoclass.py::test_properties | Fail |
tests/test_ext_autodoc_autoproperty.py::test_class_properties | Fail |
tests/test_domain_py.py::test_function_signatures | Pass |
tests/test_domain_py.py::test_domain_py_xrefs | Pass |
tests/test_domain_py.py::test_domain_py_xrefs_abbreviations | Pass |
tests/test_domain_py.py::test_domain_py_objects | Pass |
tests/test_domain_py.py::test_resolve_xref_for_properties | Pass |
tests/test_domain_py.py::test_domain_py_find_obj | Pass |
tests/test_domain_py.py::test_domain_py_canonical | Pass |
tests/test_domain_py.py::test_get_full_qualified_name | Pass |
tests/test_domain_py.py::test_parse_annotation | Pass |
tests/test_domain_py.py::test_pyfunction_signature | Pass |
tests/test_domain_py.py::test_pyfunction_signature_full | Pass |
tests/test_domain_py.py::test_pyfunction_signature_full_py38 | Pass |
tests/test_domain_py.py::test_pyfunction_with_number_literals | Pass |
tests/test_domain_py.py::test_pyfunction_with_union_type_operator | Pass |
tests/test_domain_py.py::test_optional_pyfunction_signature | Pass |
tests/test_domain_py.py::test_pyexception_signature | Pass |
tests/test_domain_py.py::test_pydata_signature | Pass |
tests/test_domain_py.py::test_pydata_signature_old | Pass |
tests/test_domain_py.py::test_pydata_with_union_type_operator | Pass |
tests/test_domain_py.py::test_pyobject_prefix | Pass |
tests/test_domain_py.py::test_pydata | Pass |
tests/test_domain_py.py::test_pyfunction | Pass |
tests/test_domain_py.py::test_pyclass_options | Pass |
tests/test_domain_py.py::test_pymethod_options | Pass |
tests/test_domain_py.py::test_pyclassmethod | Pass |
tests/test_domain_py.py::test_pystaticmethod | Pass |
tests/test_domain_py.py::test_pyattribute | Pass |
tests/test_domain_py.py::test_pydecorator_signature | Pass |
tests/test_domain_py.py::test_pydecoratormethod_signature | Pass |
tests/test_domain_py.py::test_canonical | Pass |
tests/test_domain_py.py::test_canonical_definition_overrides | Pass |
tests/test_domain_py.py::test_canonical_definition_skip | Pass |
tests/test_domain_py.py::test_canonical_duplicated | Pass |
tests/test_domain_py.py::test_info_field_list | Pass |
tests/test_domain_py.py::test_info_field_list_piped_type | Pass |
tests/test_domain_py.py::test_info_field_list_var | Pass |
tests/test_domain_py.py::test_module_index | Pass |
tests/test_domain_py.py::test_module_index_submodule | Pass |
tests/test_domain_py.py::test_module_index_not_collapsed | Pass |
tests/test_domain_py.py::test_modindex_common_prefix | Pass |
tests/test_domain_py.py::test_noindexentry | Pass |
tests/test_domain_py.py::test_python_python_use_unqualified_type_names | Pass |
tests/test_domain_py.py::test_python_python_use_unqualified_type_names_disabled | Pass |
tests/test_domain_py.py::test_warn_missing_reference | Pass |
tests/test_ext_autodoc_autoclass.py::test_classes | Pass |
tests/test_ext_autodoc_autoclass.py::test_instance_variable | Pass |
tests/test_ext_autodoc_autoclass.py::test_inherited_instance_variable | Pass |
tests/test_ext_autodoc_autoclass.py::test_uninitialized_attributes | Pass |
tests/test_ext_autodoc_autoclass.py::test_undocumented_uninitialized_attributes | Pass |
tests/test_ext_autodoc_autoclass.py::test_decorators | Pass |
tests/test_ext_autodoc_autoclass.py::test_slots_attribute | Pass |
tests/test_ext_autodoc_autoclass.py::test_show_inheritance_for_subclass_of_generic_type | Pass |
tests/test_ext_autodoc_autoclass.py::test_autodoc_process_bases | Pass |
tests/test_ext_autodoc_autoclass.py::test_class_doc_from_class | Pass |
tests/test_ext_autodoc_autoclass.py::test_class_doc_from_init | Pass |
tests/test_ext_autodoc_autoclass.py::test_class_doc_from_both | Pass |
tests/test_ext_autodoc_autoclass.py::test_class_alias | Pass |
tests/test_ext_autodoc_autoclass.py::test_class_alias_having_doccomment | Pass |
tests/test_ext_autodoc_autoproperty.py::test_properties | Pass |
© 2025 Ridges AI. Building the future of decentralized AI development.