From b5fe6a7561c2a21f70e7aaaf415bcc4d2146846f Mon Sep 17 00:00:00 2001 From: Johann Petrak Date: Wed, 21 Oct 2020 15:16:28 +0200 Subject: [PATCH 1/7] Possible way to address issue 276. This shows "property" if a variable is a property with a setter and/or a deleter and "ro-property" (read only property) if it is a property which does not have either a setter or getter. --- pdoc/__init__.py | 20 ++++++++++++++++++-- pdoc/templates/html.mako | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/pdoc/__init__.py b/pdoc/__init__.py index 8211395d..92020aa1 100644 --- a/pdoc/__init__.py +++ b/pdoc/__init__.py @@ -982,12 +982,23 @@ def definition_order_index( self.doc[name] = Function( name, self.module, obj, cls=self) else: + # check if the variable is really a property and if yes, if it does have a setter or deleter + # in which case it is not read-only + # dict(inspect.getmembers(clazz))[name] + if isinstance(obj, property): + if obj.fdel is not None or obj.fset is not None: + vartype = "property" + else: + vartype = "ro-property" + else: + vartype = "var" self.doc[name] = Variable( name, self.module, docstring=( var_docstrings.get(name) or (inspect.isclass(obj) or _is_descriptor(obj)) and inspect.getdoc(obj)), cls=self, + vartype=vartype, obj=getattr(obj, 'fget', getattr(obj, '__get__', None)), instance_var=(_is_descriptor(obj) or name in getattr(self.obj, '__slots__', ()))) @@ -1463,10 +1474,10 @@ class Variable(Doc): Representation of a variable's documentation. This includes module, class, and instance variables. """ - __slots__ = ('cls', 'instance_var') + __slots__ = ('cls', 'instance_var', 'vartype') def __init__(self, name, module, docstring, *, - obj=None, cls: Class = None, instance_var=False): + obj=None, cls: Class = None, instance_var=False, vartype=None): """ Same as `pdoc.Doc`, except `cls` should be provided as a `pdoc.Class` object when this is a class or instance @@ -1486,6 +1497,11 @@ def __init__(self, name, module, docstring, *, opposed to class variable). """ + self.vartype = vartype + """ + One of `var`, `property`, or `property(R/O)`. + """ + @property def qualname(self) -> str: if self.cls: diff --git a/pdoc/templates/html.mako b/pdoc/templates/html.mako index d8213543..bd986418 100644 --- a/pdoc/templates/html.mako +++ b/pdoc/templates/html.mako @@ -234,7 +234,7 @@
% for v in inst_vars: <% return_type = get_annotation(v.type_annotation) %> -
var ${ident(v.name)}${return_type}
+
${v.vartype} ${ident(v.name)}${return_type}
${show_desc(v)}
% endfor
From 8c2bb0ddde09529759cd14e75db3fdb9046349f9 Mon Sep 17 00:00:00 2001 From: Johann Petrak Date: Wed, 21 Oct 2020 16:15:17 +0200 Subject: [PATCH 2/7] Shorten comment line --- pdoc/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pdoc/__init__.py b/pdoc/__init__.py index 92020aa1..c2f5ed86 100644 --- a/pdoc/__init__.py +++ b/pdoc/__init__.py @@ -982,7 +982,8 @@ def definition_order_index( self.doc[name] = Function( name, self.module, obj, cls=self) else: - # check if the variable is really a property and if yes, if it does have a setter or deleter + # check if the variable is really a property and if yes, + # if it does have a setter or deleter # in which case it is not read-only # dict(inspect.getmembers(clazz))[name] if isinstance(obj, property): From 8b2e439697d007499cebb935828f1ec2aa9d7a89 Mon Sep 17 00:00:00 2001 From: Johann Petrak Date: Wed, 28 Oct 2020 14:46:49 +0100 Subject: [PATCH 3/7] Rename "vartype" to "kind". Also make property now show get/set/del depending on what is defined, e.g. propert/get/set --- pdoc/__init__.py | 24 ++++++++++++++---------- pdoc/templates/html.mako | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/pdoc/__init__.py b/pdoc/__init__.py index c2f5ed86..9d0033b3 100644 --- a/pdoc/__init__.py +++ b/pdoc/__init__.py @@ -987,19 +987,22 @@ def definition_order_index( # in which case it is not read-only # dict(inspect.getmembers(clazz))[name] if isinstance(obj, property): - if obj.fdel is not None or obj.fset is not None: - vartype = "property" - else: - vartype = "ro-property" + kind = "property" + if obj.fget is not None: + kind += "/get" + if obj.fset is not None: + kind += "/set" + if obj.fdel is not None: + kind += "/del" else: - vartype = "var" + kind = "var" self.doc[name] = Variable( name, self.module, docstring=( var_docstrings.get(name) or (inspect.isclass(obj) or _is_descriptor(obj)) and inspect.getdoc(obj)), cls=self, - vartype=vartype, + kind=kind, obj=getattr(obj, 'fget', getattr(obj, '__get__', None)), instance_var=(_is_descriptor(obj) or name in getattr(self.obj, '__slots__', ()))) @@ -1475,10 +1478,10 @@ class Variable(Doc): Representation of a variable's documentation. This includes module, class, and instance variables. """ - __slots__ = ('cls', 'instance_var', 'vartype') + __slots__ = ('cls', 'instance_var', 'kind') def __init__(self, name, module, docstring, *, - obj=None, cls: Class = None, instance_var=False, vartype=None): + obj=None, cls: Class = None, instance_var=False, kind=None): """ Same as `pdoc.Doc`, except `cls` should be provided as a `pdoc.Class` object when this is a class or instance @@ -1498,9 +1501,10 @@ def __init__(self, name, module, docstring, *, opposed to class variable). """ - self.vartype = vartype + self.kind = kind """ - One of `var`, `property`, or `property(R/O)`. + One of `var`, `property/get/set/del` with one or more of get, set, del, e.g. property/get/set for + a property that can be read and set. """ @property diff --git a/pdoc/templates/html.mako b/pdoc/templates/html.mako index bd986418..88911a21 100644 --- a/pdoc/templates/html.mako +++ b/pdoc/templates/html.mako @@ -234,7 +234,7 @@
% for v in inst_vars: <% return_type = get_annotation(v.type_annotation) %> -
${v.vartype} ${ident(v.name)}${return_type}
+
${v.kind} ${ident(v.name)}${return_type}
${show_desc(v)}
% endfor
From c43c886074ad3cf918b12317c83430edc03fbc59 Mon Sep 17 00:00:00 2001 From: Johann Petrak Date: Wed, 28 Oct 2020 16:35:11 +0100 Subject: [PATCH 4/7] Remove unnecessary comment. --- pdoc/__init__.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pdoc/__init__.py b/pdoc/__init__.py index 008e2dab..c6221042 100644 --- a/pdoc/__init__.py +++ b/pdoc/__init__.py @@ -985,10 +985,6 @@ def definition_order_index( self.doc[name] = Function( name, self.module, obj, cls=self) else: - # check if the variable is really a property and if yes, - # if it does have a setter or deleter - # in which case it is not read-only - # dict(inspect.getmembers(clazz))[name] if isinstance(obj, property): kind = "property" if obj.fget is not None: From a5bf43baa9743dc18f2391a90031b924159524d9 Mon Sep 17 00:00:00 2001 From: Johann Petrak Date: Wed, 28 Oct 2020 19:03:56 +0100 Subject: [PATCH 5/7] Make linter happy about line length. --- pdoc/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdoc/__init__.py b/pdoc/__init__.py index c6221042..9ff2d520 100644 --- a/pdoc/__init__.py +++ b/pdoc/__init__.py @@ -1502,8 +1502,8 @@ def __init__(self, name, module, docstring, *, self.kind = kind """ - One of `var`, `property/get/set/del` with one or more of get, set, del, e.g. property/get/set for - a property that can be read and set. + One of `var`, `property/get/set/del` with one or more of get, set, del, + e.g. property/get/set for a property that can be read and set. """ @property From f4251dd91898a69c22d232f3a35f483a3087aeff Mon Sep 17 00:00:00 2001 From: Kernc Date: Sat, 31 Oct 2020 19:05:22 +0100 Subject: [PATCH 6/7] REF: Make pdoc.Doc.obj point to raw property/descriptor --- pdoc/__init__.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/pdoc/__init__.py b/pdoc/__init__.py index 9ff2d520..4205823d 100644 --- a/pdoc/__init__.py +++ b/pdoc/__init__.py @@ -367,6 +367,14 @@ def _is_descriptor(obj): inspect.ismemberdescriptor(obj)) +def _unwrap_descriptor(obj): + if isinstance(obj, property): + return (getattr(obj, 'fget', False) or + getattr(obj, 'fset', False) or + getattr(obj, 'fdel', obj)) + return getattr(obj, '__get__', obj) + + def _filter_type(type: Type[T], values: Union[Iterable['Doc'], Mapping[str, 'Doc']]) -> List[T]: """ @@ -488,7 +496,7 @@ def source(self) -> str: available, an empty string. """ try: - lines, _ = inspect.getsourcelines(self.obj) + lines, _ = inspect.getsourcelines(_unwrap_descriptor(self.obj)) except (ValueError, TypeError, OSError): return '' return inspect.cleandoc(''.join(['\n'] + lines)) @@ -1002,7 +1010,7 @@ def definition_order_index( (inspect.isclass(obj) or _is_descriptor(obj)) and inspect.getdoc(obj)), cls=self, kind=kind, - obj=getattr(obj, 'fget', getattr(obj, '__get__', None)), + obj=_is_descriptor(obj) and obj or None, instance_var=(_is_descriptor(obj) or name in getattr(self.obj, '__slots__', ()))) @@ -1277,7 +1285,8 @@ def return_annotation(self, *, link=None) -> str: lambda: _get_type_hints(cast(Class, self.cls).obj)[self.name], # global variables lambda: _get_type_hints(not self.cls and self.module.obj)[self.name], - lambda: inspect.signature(self.obj).return_annotation, + # properties + lambda: inspect.signature(_unwrap_descriptor(self.obj)).return_annotation, # Use raw annotation strings in unmatched forward declarations lambda: cast(Class, self.cls).obj.__annotations__[self.name], # Extract annotation from the docstring for C builtin function From b87b43e0998bfb2f533935cef14fe322e0ed7cbe Mon Sep 17 00:00:00 2001 From: Kernc Date: Sat, 22 Jun 2024 02:32:37 +0200 Subject: [PATCH 7/7] ENH: Introduce `Variable.kind: Literal["var","prop"]` --- pdoc/__init__.py | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/pdoc/__init__.py b/pdoc/__init__.py index 4205823d..2f948073 100644 --- a/pdoc/__init__.py +++ b/pdoc/__init__.py @@ -993,23 +993,13 @@ def definition_order_index( self.doc[name] = Function( name, self.module, obj, cls=self) else: - if isinstance(obj, property): - kind = "property" - if obj.fget is not None: - kind += "/get" - if obj.fset is not None: - kind += "/set" - if obj.fdel is not None: - kind += "/del" - else: - kind = "var" self.doc[name] = Variable( name, self.module, docstring=( var_docstrings.get(name) or (inspect.isclass(obj) or _is_descriptor(obj)) and inspect.getdoc(obj)), cls=self, - kind=kind, + kind="prop" if isinstance(obj, property) else "var", obj=_is_descriptor(obj) and obj or None, instance_var=(_is_descriptor(obj) or name in getattr(self.obj, '__slots__', ()))) @@ -1511,8 +1501,8 @@ def __init__(self, name, module, docstring, *, self.kind = kind """ - One of `var`, `property/get/set/del` with one or more of get, set, del, - e.g. property/get/set for a property that can be read and set. + `prop` if variable is a dynamic property (has getter/setter or deleter), + or `var` otherwise. """ @property