Skip to content

Commit 1961159

Browse files
committed
REF: Avoid using _BLACKLISTED_DUMMY 🤡
Closes #309
1 parent 1bb95b4 commit 1961159

File tree

2 files changed

+59
-39
lines changed

2 files changed

+59
-39
lines changed

pdoc/__init__.py

+44-32
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,6 @@
6666
tpl_lookup.directories.insert(0, path.join(os.getenv("XDG_CONFIG_HOME", ''), "pdoc"))
6767

6868

69-
# A surrogate so that the check in Module._link_inheritance()
70-
# "__pdoc__-overriden key {!r} does not exist" can pick the object up
71-
# (and not warn).
72-
# If you know how to keep the warning, but skip the object creation
73-
# altogether, please make it happen!
74-
class _BLACKLISTED_DUMMY:
75-
pass
76-
77-
7869
class Context(dict):
7970
"""
8071
The context object that maps all documented identifiers
@@ -89,6 +80,13 @@ class Context(dict):
8980
"""
9081
__pdoc__['Context.__init__'] = False
9182

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

9391
_global_context = Context()
9492

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

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

677677
# Populate self.doc with this module's public members
678+
public_objs = []
678679
if hasattr(self.obj, '__all__'):
679-
public_objs = []
680680
for name in self.obj.__all__:
681681
try:
682682
obj = getattr(self.obj, name)
@@ -691,20 +691,25 @@ def is_from_this_module(obj):
691691
mod = inspect.getmodule(inspect.unwrap(obj))
692692
return mod is None or mod.__name__ == self.obj.__name__
693693

694-
public_objs = [(name, (_BLACKLISTED_DUMMY
695-
if _is_blacklisted(name, self) else
696-
inspect.unwrap(obj)))
697-
for name, obj in inspect.getmembers(self.obj)
698-
if ((_is_public(name) or _is_whitelisted(name, self)) and
699-
(_is_blacklisted(name, self) or # skips unwrapping that follows
700-
is_from_this_module(obj) or name in var_docstrings))]
694+
for name, obj in inspect.getmembers(self.obj):
695+
if ((_is_public(name) or
696+
_is_whitelisted(name, self)) and
697+
(_is_blacklisted(name, self) or # skips unwrapping that follows
698+
is_from_this_module(obj) or
699+
name in var_docstrings)):
700+
701+
if _is_blacklisted(name, self):
702+
self._context.blacklisted.add(f'{self.refname}.{name}')
703+
continue
704+
705+
obj = inspect.unwrap(obj)
706+
public_objs.append((name, obj))
707+
701708
index = list(self.obj.__dict__).index
702709
public_objs.sort(key=lambda i: index(i[0]))
703710

704711
for name, obj in public_objs:
705-
if obj is _BLACKLISTED_DUMMY:
706-
self.doc[name] = Variable(name, self, 'dummy', obj=obj)
707-
elif _is_function(obj):
712+
if _is_function(obj):
708713
self.doc[name] = Function(name, self, obj)
709714
elif inspect.isclass(obj):
710715
self.doc[name] = Class(name, self, obj)
@@ -819,7 +824,9 @@ def _link_inheritance(self):
819824
continue
820825

821826
if (not name.endswith('.__init__') and
822-
name not in self.doc and refname not in self._context):
827+
name not in self.doc and
828+
refname not in self._context and
829+
refname not in self._context.blacklisted):
823830
warn(f'__pdoc__-overriden key {name!r} does not exist '
824831
f'in module {self.name!r}')
825832

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

1021-
public_objs = [(_name, (_BLACKLISTED_DUMMY
1022-
if _is_blacklisted(_name, self) else
1023-
inspect.unwrap(obj)))
1024-
for _name, obj in _getmembers_all(self.obj)
1025-
# Filter only *own* members. The rest are inherited
1026-
# in Class._fill_inheritance()
1027-
if (_name in self.obj.__dict__ or _name in annotations)
1028-
and (_is_public(_name) or _is_whitelisted(_name, self))]
1028+
public_objs = []
1029+
for _name, obj in _getmembers_all(self.obj):
1030+
# Filter only *own* members. The rest are inherited
1031+
# in Class._fill_inheritance()
1032+
if ((_name in self.obj.__dict__ or
1033+
_name in annotations) and
1034+
(_is_public(_name) or
1035+
_is_whitelisted(_name, self))):
1036+
1037+
if _is_blacklisted(_name, self):
1038+
self.module._context.blacklisted.add(f'{self.refname}.{_name}')
1039+
continue
1040+
1041+
obj = inspect.unwrap(obj)
1042+
public_objs.append((_name, obj))
10291043

10301044
def definition_order_index(
10311045
name,
@@ -1046,9 +1060,7 @@ def definition_order_index(
10461060

10471061
# Convert the public Python objects to documentation objects.
10481062
for name, obj in public_objs:
1049-
if obj is _BLACKLISTED_DUMMY:
1050-
self.doc[name] = Variable(name, self.module, 'dummy', obj=obj, cls=self)
1051-
elif _is_function(obj):
1063+
if _is_function(obj):
10521064
self.doc[name] = Function(
10531065
name, self.module, obj, cls=self)
10541066
else:

pdoc/test/__init__.py

+15-7
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ def test_html_identifier(self):
232232
with run_html(EXAMPLE_MODULE + package, filter='A',
233233
config='show_source_code=False'):
234234
self._check_files(['A'], ['CONST', 'B docstring'])
235-
self.assertIn('__pdoc__', cm.warning.args[0])
235+
self.assertIn('Code reference `example_pkg.B`', cm.warning.args[0])
236236

237237
def test_html_ref_links(self):
238238
with run_html(EXAMPLE_MODULE, config='show_source_code=False'):
@@ -589,12 +589,14 @@ def test_qualname(self):
589589
def test__pdoc__dict(self):
590590
module = pdoc.import_module(EXAMPLE_MODULE)
591591
with patch.object(module, '__pdoc__', {'B': False}):
592+
pdoc.reset()
592593
mod = pdoc.Module(module)
593594
pdoc.link_inheritance()
594595
self.assertIn('A', mod.doc)
595596
self.assertNotIn('B', mod.doc)
596597

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

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

613+
# Ensure "overridden key doesn't exist" warning is raised
614+
with patch.object(module, '__pdoc__', {'xxx': False}):
615+
pdoc.reset()
616+
mod = pdoc.Module(module)
617+
with self.assertWarns(UserWarning) as cm:
618+
pdoc.link_inheritance()
619+
self.assertIn("'xxx' does not exist", cm.warning.args[0])
620+
610621
# GH-99: https://github.com/pdoc3/pdoc/issues/99
611622
module = pdoc.import_module(EXAMPLE_MODULE + '._exclude_dir')
612623
with patch.object(module, '__pdoc__', {'downloaded_modules': False}, create=True):
624+
pdoc.reset()
613625
mod = pdoc.Module(module)
614626
# GH-206: https://github.com/pdoc3/pdoc/issues/206
615627
with warnings.catch_warnings(record=True) as cm:
@@ -792,10 +804,6 @@ def test_link_inheritance(self):
792804
pdoc.link_inheritance()
793805
self.assertFalse(w)
794806

795-
mod._is_inheritance_linked = False
796-
with self.assertWarns(UserWarning):
797-
pdoc.link_inheritance()
798-
799807
# Test inheritance across modules
800808
pdoc.reset()
801809
mod = pdoc.Module(EXAMPLE_MODULE + '._test_linking')
@@ -810,7 +818,7 @@ def test_link_inheritance(self):
810818
self.assertNotEqual(b.inherits, a)
811819

812820
def test_context(self):
813-
context = {}
821+
context = pdoc.Context()
814822
pdoc.Module(pdoc, context=context)
815823
self.assertIn('pdoc', context)
816824
self.assertIn('pdoc.cli', context)
@@ -916,7 +924,7 @@ def f(a: typing.Callable):
916924
self.assertEqual(pdoc.Function('slice', mod, slice).params(), ['start', 'stop', 'step'])
917925

918926
class get_sample(repeat):
919-
""" get_sample(self: pdoc.int, pos: int) -> Tuple[int, float] """
927+
""" get_sample(self: int, pos: int) -> Tuple[int, float] """
920928
self.assertEqual(pdoc.Function('get_sample', mod, get_sample).params(annotate=True),
921929
['self:\xa0int', 'pos:\xa0int'])
922930
self.assertEqual(pdoc.Function('get_sample', mod, get_sample).return_annotation(),

0 commit comments

Comments
 (0)