Skip to content

Commit

Permalink
REF: Avoid using _BLACKLISTED_DUMMY 馃ぁ
Browse files Browse the repository at this point in the history
Closes #309
  • Loading branch information
kernc committed Aug 3, 2021
1 parent 1bb95b4 commit 1961159
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 39 deletions.
76 changes: 44 additions & 32 deletions pdoc/__init__.py
Expand Up @@ -66,15 +66,6 @@
tpl_lookup.directories.insert(0, path.join(os.getenv("XDG_CONFIG_HOME", ''), "pdoc"))


# A surrogate so that the check in Module._link_inheritance()
# "__pdoc__-overriden key {!r} does not exist" can pick the object up
# (and not warn).
# If you know how to keep the warning, but skip the object creation
# altogether, please make it happen!
class _BLACKLISTED_DUMMY:
pass


class Context(dict):
"""
The context object that maps all documented identifiers
Expand All @@ -89,6 +80,13 @@ class Context(dict):
"""
__pdoc__['Context.__init__'] = False

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# A surrogate so that the check in Module._link_inheritance()
# "__pdoc__-overriden key {!r} does not exist" can see the object
# (and not warn).
self.blacklisted = getattr(args[0], 'blacklisted', set()) if args else set()


_global_context = Context()

Expand Down Expand Up @@ -658,6 +656,8 @@ def __init__(self, module: Union[ModuleType, str], *, docfilter: Callable[[Doc],
A lookup table for ALL doc objects of all modules that share this context,
mainly used in `Module.find_ident()`.
"""
assert isinstance(self._context, Context), \
'pdoc.Module(context=) should be a pdoc.Context instance'

self.supermodule = supermodule
"""
Expand All @@ -675,8 +675,8 @@ def __init__(self, module: Union[ModuleType, str], *, docfilter: Callable[[Doc],
var_docstrings, _ = _pep224_docstrings(self)

# Populate self.doc with this module's public members
public_objs = []
if hasattr(self.obj, '__all__'):
public_objs = []
for name in self.obj.__all__:
try:
obj = getattr(self.obj, name)
Expand All @@ -691,20 +691,25 @@ def is_from_this_module(obj):
mod = inspect.getmodule(inspect.unwrap(obj))
return mod is None or mod.__name__ == self.obj.__name__

public_objs = [(name, (_BLACKLISTED_DUMMY
if _is_blacklisted(name, self) else
inspect.unwrap(obj)))
for name, obj in inspect.getmembers(self.obj)
if ((_is_public(name) or _is_whitelisted(name, self)) and
(_is_blacklisted(name, self) or # skips unwrapping that follows
is_from_this_module(obj) or name in var_docstrings))]
for name, obj in inspect.getmembers(self.obj):
if ((_is_public(name) or
_is_whitelisted(name, self)) and
(_is_blacklisted(name, self) or # skips unwrapping that follows
is_from_this_module(obj) or
name in var_docstrings)):

if _is_blacklisted(name, self):
self._context.blacklisted.add(f'{self.refname}.{name}')
continue

obj = inspect.unwrap(obj)
public_objs.append((name, obj))

index = list(self.obj.__dict__).index
public_objs.sort(key=lambda i: index(i[0]))

for name, obj in public_objs:
if obj is _BLACKLISTED_DUMMY:
self.doc[name] = Variable(name, self, 'dummy', obj=obj)
elif _is_function(obj):
if _is_function(obj):
self.doc[name] = Function(name, self, obj)
elif inspect.isclass(obj):
self.doc[name] = Class(name, self, obj)
Expand Down Expand Up @@ -819,7 +824,9 @@ def _link_inheritance(self):
continue

if (not name.endswith('.__init__') and
name not in self.doc and refname not in self._context):
name not in self.doc and
refname not in self._context and
refname not in self._context.blacklisted):
warn(f'__pdoc__-overriden key {name!r} does not exist '
f'in module {self.name!r}')

Expand Down Expand Up @@ -1018,14 +1025,21 @@ def __init__(self, name: str, module: Module, obj, *, docstring: str = None):
# Use only own, non-inherited annotations (the rest will be inherited)
annotations = getattr(self.obj, '__annotations__', {})

public_objs = [(_name, (_BLACKLISTED_DUMMY
if _is_blacklisted(_name, self) else
inspect.unwrap(obj)))
for _name, obj in _getmembers_all(self.obj)
# Filter only *own* members. The rest are inherited
# in Class._fill_inheritance()
if (_name in self.obj.__dict__ or _name in annotations)
and (_is_public(_name) or _is_whitelisted(_name, self))]
public_objs = []
for _name, obj in _getmembers_all(self.obj):
# Filter only *own* members. The rest are inherited
# in Class._fill_inheritance()
if ((_name in self.obj.__dict__ or
_name in annotations) and
(_is_public(_name) or
_is_whitelisted(_name, self))):

if _is_blacklisted(_name, self):
self.module._context.blacklisted.add(f'{self.refname}.{_name}')
continue

obj = inspect.unwrap(obj)
public_objs.append((_name, obj))

def definition_order_index(
name,
Expand All @@ -1046,9 +1060,7 @@ def definition_order_index(

# Convert the public Python objects to documentation objects.
for name, obj in public_objs:
if obj is _BLACKLISTED_DUMMY:
self.doc[name] = Variable(name, self.module, 'dummy', obj=obj, cls=self)
elif _is_function(obj):
if _is_function(obj):
self.doc[name] = Function(
name, self.module, obj, cls=self)
else:
Expand Down
22 changes: 15 additions & 7 deletions pdoc/test/__init__.py
Expand Up @@ -232,7 +232,7 @@ def test_html_identifier(self):
with run_html(EXAMPLE_MODULE + package, filter='A',
config='show_source_code=False'):
self._check_files(['A'], ['CONST', 'B docstring'])
self.assertIn('__pdoc__', cm.warning.args[0])
self.assertIn('Code reference `example_pkg.B`', cm.warning.args[0])

def test_html_ref_links(self):
with run_html(EXAMPLE_MODULE, config='show_source_code=False'):
Expand Down Expand Up @@ -589,12 +589,14 @@ def test_qualname(self):
def test__pdoc__dict(self):
module = pdoc.import_module(EXAMPLE_MODULE)
with patch.object(module, '__pdoc__', {'B': False}):
pdoc.reset()
mod = pdoc.Module(module)
pdoc.link_inheritance()
self.assertIn('A', mod.doc)
self.assertNotIn('B', mod.doc)

with patch.object(module, '__pdoc__', {'B.f': False}):
pdoc.reset()
mod = pdoc.Module(module)
pdoc.link_inheritance()
self.assertIn('B', mod.doc)
Expand All @@ -603,13 +605,23 @@ def test__pdoc__dict(self):

# GH-125: https://github.com/pdoc3/pdoc/issues/125
with patch.object(module, '__pdoc__', {'B.inherited': False}):
pdoc.reset()
mod = pdoc.Module(module)
pdoc.link_inheritance()
self.assertNotIn('inherited', mod.doc['B'].doc)

# Ensure "overridden key doesn't exist" warning is raised
with patch.object(module, '__pdoc__', {'xxx': False}):
pdoc.reset()
mod = pdoc.Module(module)
with self.assertWarns(UserWarning) as cm:
pdoc.link_inheritance()
self.assertIn("'xxx' does not exist", cm.warning.args[0])

# GH-99: https://github.com/pdoc3/pdoc/issues/99
module = pdoc.import_module(EXAMPLE_MODULE + '._exclude_dir')
with patch.object(module, '__pdoc__', {'downloaded_modules': False}, create=True):
pdoc.reset()
mod = pdoc.Module(module)
# GH-206: https://github.com/pdoc3/pdoc/issues/206
with warnings.catch_warnings(record=True) as cm:
Expand Down Expand Up @@ -792,10 +804,6 @@ def test_link_inheritance(self):
pdoc.link_inheritance()
self.assertFalse(w)

mod._is_inheritance_linked = False
with self.assertWarns(UserWarning):
pdoc.link_inheritance()

# Test inheritance across modules
pdoc.reset()
mod = pdoc.Module(EXAMPLE_MODULE + '._test_linking')
Expand All @@ -810,7 +818,7 @@ def test_link_inheritance(self):
self.assertNotEqual(b.inherits, a)

def test_context(self):
context = {}
context = pdoc.Context()
pdoc.Module(pdoc, context=context)
self.assertIn('pdoc', context)
self.assertIn('pdoc.cli', context)
Expand Down Expand Up @@ -916,7 +924,7 @@ def f(a: typing.Callable):
self.assertEqual(pdoc.Function('slice', mod, slice).params(), ['start', 'stop', 'step'])

class get_sample(repeat):
""" get_sample(self: pdoc.int, pos: int) -> Tuple[int, float] """
""" get_sample(self: int, pos: int) -> Tuple[int, float] """
self.assertEqual(pdoc.Function('get_sample', mod, get_sample).params(annotate=True),
['self:\xa0int', 'pos:\xa0int'])
self.assertEqual(pdoc.Function('get_sample', mod, get_sample).return_annotation(),
Expand Down

0 comments on commit 1961159

Please sign in to comment.