There's no fget/fset/fdel for those and we also can't __doc__ them.
return [out]
-def extract_property_doc(state: State, path: List[str], property):
+def extract_property_doc(state: State, parent, path: List[str], property):
assert inspect.isdatadescriptor(property)
out = Empty()
out.name = path[-1]
out.id = state.config['ID_FORMATTER'](EntryType.PROPERTY, path[-1:])
+
+ # If this is a slot, there won't be any fget / fset / fdel. Assume they're
+ # gettable and settable (couldn't find any way to make them *inspectably*
+ # readonly, all solutions involved throwing from __setattr__()) and
+ # deletable as well (calling del on it seems to simply remove any
+ # previously set value). Unfortunately we can't get any docstring for these
+ # either.
+ # TODO: any better way to detect that those are slots?
+ if property.__class__.__name__ == 'member_descriptor' and property.__class__.__module__ == 'builtins':
+ out.is_gettable = True
+ out.is_settable = True
+ out.is_deletable = True
+ # TODO: external summary for properties
+ out.summary = ''
+ out.has_details = False
+
+ # First try to get fully dereferenced type hints (with strings
+ # converted to actual annotations). If that fails (e.g. because a type
+ # doesn't exist), we'll take the non-dereferenced annotations instead.
+ type_hints = get_type_hints_or_nothing(state, path, parent)
+
+ if out.name in type_hints:
+ out.type = extract_annotation(state, path, type_hints[out.name])
+ elif hasattr(parent, '__annotations__') and out.name in parent.__annotations__:
+ out.type = extract_annotation(state, path, parent.__annotations__[out.name])
+ else:
+ out.type = None
+
+ return out
+
# TODO: external summary for properties
out.is_gettable = property.fget is not None
if property.fget or (property.fset and property.__doc__):
else:
page.methods += [function]
elif member_entry.type == EntryType.PROPERTY:
- page.properties += [extract_property_doc(state, subpath, member_entry.object)]
+ page.properties += [extract_property_doc(state, class_, subpath, member_entry.object)]
elif member_entry.type == EntryType.DATA:
page.data += [extract_data_doc(state, class_, subpath, member_entry.object)]
else: # pragma: no cover
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>inspect_annotations.FooSlots | My Python Project</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Python Project</a>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>
+ <span class="m-breadcrumb"><a href="inspect_annotations.html">inspect_annotations</a>.<wbr/></span>FooSlots <span class="m-thin">class</span>
+ </h1>
+ <p>A class with slots</p>
+ <div class="m-block m-default">
+ <h3>Contents</h3>
+ <ul>
+ <li>
+ Reference
+ <ul>
+ <li><a href="#properties">Properties</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ <section id="properties">
+ <h2><a href="#properties">Properties</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <a href="#annotated" class="m-doc-self" id="annotated">annotated</a>: typing.List[str] <span class="m-label m-flat m-success">get set del</span>
+ </dt>
+ <dd></dd>
+ <dt>
+ <a href="#unannotated" class="m-doc-self" id="unannotated">unannotated</a> <span class="m-label m-flat m-success">get set del</span>
+ </dt>
+ <dd></dd>
+ </dl>
+ </section>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
<dl class="m-doc">
<dt>class <a href="inspect_annotations.Foo.html" class="m-doc">Foo</a></dt>
<dd>A class with properties</dd>
+ <dt>class <a href="inspect_annotations.FooSlots.html" class="m-doc">FooSlots</a></dt>
+ <dd>A class with slots</dd>
</dl>
</section>
<section id="functions">
"""A property with a type annotation"""
pass
+class FooSlots:
+ """A class with slots"""
+
+ __slots__ = ['unannotated', 'annotated']
+
+ annotated: List[str]
+
def annotation(param: List[int], another: bool, third: str = "hello") -> float:
"""An annotated function"""
pass
<li>class <a href="inspect_string.Foo.Subclass.html" class="m-doc">Subclass</a> <span class="m-doc">A subclass of Foo</span></li>
</ul>
</li>
+ <li>class <a href="inspect_string.FooSlots.html" class="m-doc">FooSlots</a> <span class="m-doc">A class with slots. Can't have docstrings for these.</span></li>
<li>class <a href="inspect_string.Specials.html" class="m-doc">Specials</a> <span class="m-doc">Special class members</span></li>
</ul>
</li>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>inspect_string.FooSlots | My Python Project</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Python Project</a>
+ <div class="m-col-t-4 m-hide-m m-text-right m-nopadr">
+ <a id="m-navbar-show" href="#navigation" title="Show navigation"></a>
+ <a id="m-navbar-hide" href="#" title="Hide navigation"></a>
+ </div>
+ <div id="m-navbar-collapse" class="m-col-t-12 m-show-m m-col-m-none m-right-m">
+ <div class="m-row">
+ <ol class="m-col-t-12 m-col-m-none">
+ <li><a href="modules.html">Modules</a></li>
+ <li><a href="classes.html">Classes</a></li>
+ </ol>
+ </div>
+ </div>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>
+ <span class="m-breadcrumb"><a href="inspect_string.html">inspect_string</a>.<wbr/></span>FooSlots <span class="m-thin">class</span>
+ </h1>
+ <p>A class with slots. Can't have docstrings for these.</p>
+ <div class="m-block m-default">
+ <h3>Contents</h3>
+ <ul>
+ <li>
+ Reference
+ <ul>
+ <li><a href="#properties">Properties</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ <section id="properties">
+ <h2><a href="#properties">Properties</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <a href="#first" class="m-doc-self" id="first">first</a> <span class="m-label m-flat m-success">get set del</span>
+ </dt>
+ <dd></dd>
+ <dt>
+ <a href="#second" class="m-doc-self" id="second">second</a> <span class="m-label m-flat m-success">get set del</span>
+ </dt>
+ <dd></dd>
+ </dl>
+ </section>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
<dl class="m-doc">
<dt>class <a href="inspect_string.Foo.html" class="m-doc">Foo</a></dt>
<dd>The foo class</dd>
+ <dt>class <a href="inspect_string.FooSlots.html" class="m-doc">FooSlots</a></dt>
+ <dd>A class with slots. Can't have docstrings for these.</dd>
<dt>class <a href="inspect_string.Specials.html" class="m-doc">Specials</a></dt>
<dd>Special class members</dd>
</dl>
"""A private property"""
pass
+class FooSlots:
+ """A class with slots. Can't have docstrings for these."""
+
+ __slots__ = ['first', 'second']
+
class Specials:
"""Special class members"""
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>inspect_type_links.second.FooSlots | My Python Project</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Python Project</a>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>
+ <span class="m-breadcrumb"><a href="inspect_type_links.html">inspect_type_links</a>.<wbr/></span><span class="m-breadcrumb"><a href="inspect_type_links.second.html">second</a>.<wbr/></span>FooSlots <span class="m-thin">class</span>
+ </h1>
+ <p>A slot class</p>
+ <div class="m-block m-default">
+ <h3>Contents</h3>
+ <ul>
+ <li>
+ Reference
+ <ul>
+ <li><a href="#properties">Properties</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ <section id="properties">
+ <h2><a href="#properties">Properties</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <a href="#type_slot" class="m-doc-self" id="type_slot">type_slot</a>: <a href="inspect_type_links.second.html#Enum" class="m-doc">Enum</a> <span class="m-label m-flat m-success">get set del</span>
+ </dt>
+ <dd></dd>
+ <dt>
+ <a href="#type_slot_string_nested" class="m-doc-self" id="type_slot_string_nested">type_slot_string_nested</a>: typing.Tuple[<a href="inspect_type_links.second.Foo.html" class="m-doc">Foo</a>, typing.List[<a href="inspect_type_links.second.html#Enum" class="m-doc">Enum</a>], typing.Any] <span class="m-label m-flat m-success">get set del</span>
+ </dt>
+ <dd></dd>
+ </dl>
+ </section>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>inspect_type_links.second.FooSlotsInvalid | My Python Project</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Python Project</a>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>
+ <span class="m-breadcrumb"><a href="inspect_type_links.html">inspect_type_links</a>.<wbr/></span><span class="m-breadcrumb"><a href="inspect_type_links.second.html">second</a>.<wbr/></span>FooSlotsInvalid <span class="m-thin">class</span>
+ </h1>
+ <p>A slot class with an invalid annotation. Has to be separate because otherwise it would invalidate all other slot annotations in FooSlots as well.</p>
+ <div class="m-block m-default">
+ <h3>Contents</h3>
+ <ul>
+ <li>
+ Reference
+ <ul>
+ <li><a href="#properties">Properties</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ <section id="properties">
+ <h2><a href="#properties">Properties</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <a href="#type_slot_string_invalid" class="m-doc-self" id="type_slot_string_invalid">type_slot_string_invalid</a>: typing.List[FooBar] <span class="m-label m-flat m-success">get set del</span>
+ </dt>
+ <dd></dd>
+ </dl>
+ </section>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
<dl class="m-doc">
<dt>class <a href="inspect_type_links.second.Foo.html" class="m-doc">Foo</a></dt>
<dd>A class in the second module</dd>
+ <dt>class <a href="inspect_type_links.second.FooSlots.html" class="m-doc">FooSlots</a></dt>
+ <dd>A slot class</dd>
+ <dt>class <a href="inspect_type_links.second.FooSlotsInvalid.html" class="m-doc">FooSlotsInvalid</a></dt>
+ <dd>A slot class with an invalid annotation. Has to be separate because otherwise it would invalidate all other slot annotations in FooSlots as well.</dd>
</dl>
</section>
<section id="enums">
# other data annotations from being retrieved
TYPE_DATA_STRING_INVALID: 'Foo.Bar' = 3
+class FooSlots:
+ """A slot class"""
+
+ __slots__ = ['type_slot', 'type_slot_string_nested']
+
+ type_slot: Enum
+ type_slot_string_nested: 'Tuple[Foo, List[Enum], Any]'
+
+class FooSlotsInvalid:
+ """A slot class with an invalid annotation. Has to be separate because otherwise it would invalidate all other slot annotations in FooSlots as well."""
+
+ __slots__ = ['type_slot_string_invalid']
+
+ type_slot_string_invalid: List['FooBar']
+
def type_string(a: 'Foo'):
"""A function with string type annotation"""
self.assertEqual(*self.actual_expected_contents('inspect_string.html'))
self.assertEqual(*self.actual_expected_contents('inspect_string.another_module.html'))
self.assertEqual(*self.actual_expected_contents('inspect_string.Foo.html'))
+ self.assertEqual(*self.actual_expected_contents('inspect_string.FooSlots.html'))
self.assertEqual(*self.actual_expected_contents('inspect_string.Specials.html'))
self.assertEqual(*self.actual_expected_contents('classes.html'))
self.assertEqual(*self.actual_expected_contents('inspect_string.html', '../inspect_string/inspect_string.html'))
self.assertEqual(*self.actual_expected_contents('inspect_string.another_module.html', '../inspect_string/inspect_string.another_module.html'))
self.assertEqual(*self.actual_expected_contents('inspect_string.Foo.html', '../inspect_string/inspect_string.Foo.html'))
+ self.assertEqual(*self.actual_expected_contents('inspect_string.FooSlots.html', '../inspect_string/inspect_string.FooSlots.html'))
self.assertEqual(*self.actual_expected_contents('inspect_string.Specials.html', '../inspect_string/inspect_string.Specials.html'))
self.assertEqual(*self.actual_expected_contents('classes.html', '../inspect_string/classes.html'))
self.run_python()
self.assertEqual(*self.actual_expected_contents('inspect_annotations.html'))
self.assertEqual(*self.actual_expected_contents('inspect_annotations.Foo.html'))
+ self.assertEqual(*self.actual_expected_contents('inspect_annotations.FooSlots.html'))
@unittest.skipUnless(LooseVersion(sys.version) >= LooseVersion('3.7'),
"signature with / for pow() is not present in 3.6")
self.assertEqual(*self.actual_expected_contents('inspect_type_links.second.html'))
self.assertEqual(*self.actual_expected_contents('inspect_type_links.second.Foo.html'))
+ self.assertEqual(*self.actual_expected_contents('inspect_type_links.second.FooSlots.html'))
+ self.assertEqual(*self.actual_expected_contents('inspect_type_links.second.FooSlotsInvalid.html'))