Skip to content

Commit

Permalink
Merge branch 'master' into 22.7.x
Browse files Browse the repository at this point in the history
  • Loading branch information
tristanlatr committed Jul 15, 2022
2 parents 64bd190 + bd37a2f commit 1c24fa1
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 5 deletions.
10 changes: 8 additions & 2 deletions pydoctor/extensions/deprecate.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,10 @@ def deprecatedToUsefulText(ctx:model.Documentable, name:str, deprecated:ast.Call

bound_args = astutils.bind_args(_deprecated_signature, deprecated)
_version_call = bound_args.arguments['version']

# Also support using incremental from twisted.python.versions: https://github.com/twisted/twisted/blob/twisted-22.4.0/src/twisted/python/versions.py
if not isinstance(_version_call, ast.Call) or \
astbuilder.node2fullname(_version_call.func, ctx) != "incremental.Version":
astbuilder.node2fullname(_version_call.func, ctx) not in ("incremental.Version", "twisted.python.versions.Version"):
raise ValueError("Invalid call to twisted.python.deprecate.deprecated(), first argument should be a call to incremental.Version()")

version = versionToUsefulObject(_version_call)
Expand All @@ -135,8 +137,12 @@ def validate_identifier(_text:str) -> bool:

if not validate_identifier(_package):
raise ValueError(f"Invalid package name: {_package!r}")

if replacement is not None and not validate_identifier(replacement):
raise ValueError(f"Invalid replacement name: {replacement!r}")
# The replacement is not an identifier, so don't even try to resolve it.
# By adding extras backtics, we make the replacement a literal text.
replacement = replacement.replace('\n', ' ')
replacement = f"`{replacement}`"

if replacement is not None:
text = _deprecation_text_with_replacement_template.format(
Expand Down
27 changes: 24 additions & 3 deletions pydoctor/test/test_twisted_python_deprecate.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ def foo():
@deprecate.deprecated(incremental.Version('Twisted', 16, 0, 0))
def _bar():
'should appear'
@deprecated(Version('Twisted', 14, 2, 3), replacement='stuff')
from twisted.python.versions import Version as AliasVersion
@deprecated(AliasVersion('Twisted', 14, 2, 3), replacement='stuff')
class Baz:
@deprecatedProperty(Version('Twisted', 'NEXT', 0, 0), replacement='faam')
@deprecatedProperty(AliasVersion('Twisted', 'NEXT', 0, 0), replacement='faam')
@property
def foom(self):
...
Expand Down Expand Up @@ -82,6 +83,27 @@ class stuff: ...
name='foom', package='Twisted', version=r'NEXT', replacement='faam'
), class_html_text, re.DOTALL), class_html_text

@twisted_deprecated_systemcls_param
def test_twisted_python_deprecate_arbitrary_text(capsys: CapSys, systemcls: Type[model.System]) -> None:
"""
The deprecated object replacement can be given as a free form text as well, it does not have to be an identifier or an object.
"""
system = systemcls()
system.options.verbosity = -1

mod = fromText(
"""
from twisted.python.deprecate import deprecated
from incremental import Version
@deprecated(Version('Twisted', 15, 0, 0), replacement='just use something else')
def foo(): ...
""", system=system, modname='mod')

mod_html = test_templatewriter.getHTMLOf(mod)

assert not capsys.readouterr().out
assert 'just use something else' in mod_html

@twisted_deprecated_systemcls_param
def test_twisted_python_deprecate_security(capsys: CapSys, systemcls: Type[model.System]) -> None:
system = systemcls()
Expand All @@ -100,7 +122,6 @@ def _bar(): ...
mod_html = test_templatewriter.getHTMLOf(mod)

assert capsys.readouterr().out == '''mod:4: Invalid package name: 'Twisted\\n.. raw:: html\\n\\n <script>alert(1)</script>'
mod:6: Invalid replacement name: '\\n.. raw:: html\\n\\n <script>alert(1)</script>'
''', capsys.readouterr().out
assert '<script>alert(1)</script>' not in mod_html

Expand Down

0 comments on commit 1c24fa1

Please sign in to comment.