| 2691 | 2691 | return None |
| 2692 | 2692 | |
| 2693 | 2693 | |
| 2694 | class ClassPropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # type: ignore | |
| 2695 | """ | |
| 2696 | Specialized Documenter subclass for class properties (decorated with @classmethod and @property). | |
| 2697 | """ | |
| 2698 | objtype = 'classproperty' | |
| 2699 | member_order = 60 | |
| 2700 | ||
| 2701 | # before MethodDocumenter but after PropertyDocumenter | |
| 2702 | priority = MethodDocumenter.priority + 1 | |
| 2703 | ||
| 2704 | @classmethod | |
| 2705 | def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any | |
| 2706 | ) -> bool: | |
| 2707 | # Check if this is a classmethod that wraps a property | |
| 2708 | if not (inspect.ismethod(member) and isinstance(parent, ClassDocumenter)): | |
| 2709 | return False | |
| 2710 | ||
| 2711 | # Check if the member is a classmethod that wraps a property | |
| 2712 | # by looking at the class's __dict__ to get the original descriptor | |
| 2713 | cls_obj = parent.object if hasattr(parent, 'object') else parent | |
| 2714 | if not hasattr(cls_obj, '__dict__'): | |
| 2715 | return False | |
| 2716 | ||
| 2717 | original = cls_obj.__dict__.get(membername) | |
| 2718 | if not isinstance(original, classmethod): | |
| 2719 | return False | |
| 2720 | ||
| 2721 | # Check if the underlying function is a property | |
| 2722 | return isinstance(original.__func__, property) | |
| 2723 | ||
| 2724 | def import_object(self, raiseerror: bool = False) -> bool: | |
| 2725 | ret = super().import_object(raiseerror) | |
| 2726 | if not ret: | |
| 2727 | return ret | |
| 2728 | ||
| 2729 | # Get the original classmethod to access the underlying property | |
| 2730 | cls_obj = self.parent.object if hasattr(self.parent, 'object') else self.parent | |
| 2731 | if hasattr(cls_obj, '__dict__'): | |
| 2732 | original = cls_obj.__dict__.get(self.object_name) | |
| 2733 | if isinstance(original, classmethod) and isinstance(original.__func__, property): | |
| 2734 | # Set the object to the underlying property for proper docstring extraction | |
| 2735 | self._property_object = original.__func__ | |
| 2736 | else: | |
| 2737 | self._property_object = None | |
| 2738 | else: | |
| 2739 | self._property_object = None | |
| 2740 | ||
| 2741 | return ret | |
| 2742 | ||
| 2743 | def document_members(self, all_members: bool = False) -> None: | |
| 2744 | pass | |
| 2745 | ||
| 2746 | def get_real_modname(self) -> str: | |
| 2747 | real_modname = self.get_attr(self.parent or self.object, '__module__', None) | |
| 2748 | return real_modname or self.modname | |
| 2749 | ||
| 2750 | def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]: | |
| 2751 | # Use the docstring from the underlying property | |
| 2752 | if hasattr(self, '_property_object') and self._property_object is not None: | |
| 2753 | docstring = getdoc(self._property_object, self.get_attr, | |
| 2754 | self.config.autodoc_inherit_docstrings, | |
| 2755 | self.parent, self.object_name) | |
| 2756 | if docstring: | |
| 2757 | tab_width = self.directive.state.document.settings.tab_width | |
| 2758 | return [prepare_docstring(docstring, ignore, tab_width)] | |
| 2759 | return [] | |
| 2760 | else: | |
| 2761 | return super().get_doc(ignore) | |
| 2762 | ||
| 2763 | def add_directive_header(self, sig: str) -> None: | |
| 2764 | super().add_directive_header(sig) | |
| 2765 | sourcename = self.get_sourcename() | |
| 2766 | self.add_line(' :classmethod:', sourcename) | |
| 2767 | ||
| 2768 | # Add abstractmethod if the underlying property is abstract | |
| 2769 | if hasattr(self, '_property_object') and self._property_object is not None: | |
| 2770 | if inspect.isabstractmethod(self._property_object): | |
| 2771 | self.add_line(' :abstractmethod:', sourcename) | |
| 2772 | ||
| 2773 | if safe_getattr(self._property_object, 'fget', None) and self.config.autodoc_typehints != 'none': | |
| 2774 | try: | |
| 2775 | signature = inspect.signature(self._property_object.fget, | |
| 2776 | type_aliases=self.config.autodoc_type_aliases) | |
| 2777 | if signature.return_annotation is not Parameter.empty: | |
| 2778 | objrepr = stringify_typehint(signature.return_annotation) | |
| 2779 | self.add_line(' :type: ' + objrepr, sourcename) | |
| 2780 | except (TypeError, ValueError): | |
| 2781 | pass | |
| 2782 | ||
| 2783 | ||
| 2694 | 2784 | class NewTypeAttributeDocumenter(AttributeDocumenter): |
| 2695 | 2785 | """ |
| 2696 | 2786 | Specialized Documenter subclass for NewTypes. |
| 2753 | 2843 | app.add_autodocumenter(MethodDocumenter) |
| 2754 | 2844 | app.add_autodocumenter(AttributeDocumenter) |
| 2755 | 2845 | app.add_autodocumenter(PropertyDocumenter) |
| 2846 | app.add_autodocumenter(ClassPropertyDocumenter) | |
| 2756 | 2847 | app.add_autodocumenter(NewTypeAttributeDocumenter) |
| 2757 | 2848 | |
| 2758 | 2849 | app.add_config_value('autoclass_content', 'class', True, ENUM('both', 'class', 'init')) |
| 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.