Skip to content

Commit

Permalink
Merge branch 'master' into 22.5.x
Browse files Browse the repository at this point in the history
  • Loading branch information
tristanlatr committed Apr 25, 2022
2 parents f8f96c8 + 8d256e9 commit 56b21d3
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 10 deletions.
19 changes: 9 additions & 10 deletions pydoctor/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -667,10 +667,10 @@ def __init__(self, options: Optional['Options'] = None):
self.buildtime = datetime.datetime.now()
self.intersphinx = SphinxInventory(logger=self.msg)

# since privacy handling now uses fnmatch, we cache results so we don't re-run matches all the time.
# it's ok to cache privacy class results since the potential renames (with reparenting) happends before we begin to
# generate HTML, which is when we call Documentable.PrivacyClass.
self._privacyClassCache: Dict[int, PrivacyClass] = {}
# Since privacy handling now uses fnmatch, we cache results so we don't re-run matches all the time.
# We use the fullName of the objets as the dict key in order to bind a full name to a privacy, not an object to a privacy.
# this way, we are sure the objects' privacy stay true even if we reparent them manually.
self._privacyClassCache: Dict[str, PrivacyClass] = {}


@property
Expand Down Expand Up @@ -790,8 +790,8 @@ def objectsOfType(self, cls: Type[T]) -> Iterator[T]:
yield o

def privacyClass(self, ob: Documentable) -> PrivacyClass:
ob_id = id(ob)
cached_privacy = self._privacyClassCache.get(ob_id)
ob_fullName = ob.fullName()
cached_privacy = self._privacyClassCache.get(ob_fullName)
if cached_privacy is not None:
return cached_privacy

Expand All @@ -807,21 +807,20 @@ def privacyClass(self, ob: Documentable) -> PrivacyClass:

# Precedence order: CLI arguments order
# Check exact matches first, then qnmatch
fullName = ob.fullName()
_found_exact_match = False
for priv, match in reversed(self.options.privacy):
if fullName == match:
if ob_fullName == match:
privacy = priv
_found_exact_match = True
break
if not _found_exact_match:
for priv, match in reversed(self.options.privacy):
if qnmatch.qnmatch(fullName, match):
if qnmatch.qnmatch(ob_fullName, match):
privacy = priv
break

# Store in cache
self._privacyClassCache[ob_id] = privacy
self._privacyClassCache[ob_fullName] = privacy
return privacy

def addObject(self, obj: Documentable) -> None:
Expand Down
28 changes: 28 additions & 0 deletions pydoctor/test/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,3 +443,31 @@ class test3:
assert allobjs['m.tests.test1'].privacyClass == model.PrivacyClass.HIDDEN
assert allobjs['m.tests.test2'].privacyClass == model.PrivacyClass.HIDDEN
assert allobjs['m.tests.test3'].privacyClass == model.PrivacyClass.HIDDEN

def test_privacy_reparented() -> None:
"""
Test that the privacy of an object changes if
the name of the object changes (with reparenting).
"""

system = model.System()

mod_private = fromText('''
class _MyClass:
pass
''', modname='private', system=system)

mod_export = fromText(
'from private import _MyClass # not needed for the test to pass',
modname='public', system=system)

base = mod_private.contents['_MyClass']
assert base.privacyClass == model.PrivacyClass.PRIVATE

# Manually reparent MyClass
base.reparent(mod_export, 'MyClass')
assert base.fullName() == 'public.MyClass'
assert '_MyClass' not in mod_private.contents
assert mod_export.resolveName("MyClass") == base

assert base.privacyClass == model.PrivacyClass.PUBLIC

0 comments on commit 56b21d3

Please sign in to comment.