Swift: add docstring parsing

This commit is contained in:
Paolo Tranquilli
2022-10-18 12:53:33 +02:00
parent 73f977c98c
commit f41fd81965
3 changed files with 169 additions and 0 deletions

View File

@@ -2,6 +2,7 @@ from typing import Callable as _Callable, Union as _Union
from functools import singledispatch as _singledispatch
from swift.codegen.lib import schema as _schema
import inspect as _inspect
from dataclasses import dataclass as _dataclass
class _ChildModifier(_schema.PropertyModifier):
@@ -11,6 +12,14 @@ class _ChildModifier(_schema.PropertyModifier):
prop.is_child = True
@_dataclass
class _DescModifier(_schema.PropertyModifier):
description: str
def modify(self, prop: _schema.Property):
prop.doc = _schema.split_doc(self.description)
def include(source: str):
# add to `includes` variable in calling context
_inspect.currentframe().f_back.f_locals.setdefault(
@@ -97,6 +106,7 @@ optional = _TypeModifier(_Optionalizer())
list = _TypeModifier(_Listifier())
child = _ChildModifier()
desc = _DescModifier
qltest = _Namespace(
skip=_Pragma("qltest_skip"),

View File

@@ -1,5 +1,6 @@
""" schema.yml format representation """
import pathlib
import re
import types
import typing
from dataclasses import dataclass, field
@@ -35,6 +36,8 @@ class Property:
type: Optional[str] = None
is_child: bool = False
pragmas: List[str] = field(default_factory=list)
doc_name: Optional[str] = None
doc: List[str] = field(default_factory=list)
@property
def is_single(self) -> bool:
@@ -76,6 +79,7 @@ class Class:
group: str = ""
pragmas: List[str] = field(default_factory=list)
ipa: Optional[IpaInfo] = None
doc: List[str] = field(default_factory=list)
@property
def final(self):
@@ -154,6 +158,27 @@ class PropertyModifier:
raise NotImplementedError
def split_doc(doc):
# implementation inspired from https://peps.python.org/pep-0257/
if not doc:
return []
lines = doc.splitlines()
# Determine minimum indentation (first line doesn't count):
strippedlines = (line.lstrip() for line in lines[1:])
indents = [len(line) - len(stripped) for line, stripped in zip(lines[1:], strippedlines) if stripped]
# Remove indentation (first line is special):
trimmed = [lines[0].strip()]
if indents:
indent = min(indents)
trimmed.extend(line[indent:].rstrip() for line in lines[1:])
# Strip off trailing and leading blank lines:
while trimmed and not trimmed[-1]:
trimmed.pop()
while trimmed and not trimmed[0]:
trimmed.pop(0)
return trimmed
@dataclass
class _PropertyNamer(PropertyModifier):
name: str
@@ -181,6 +206,7 @@ def _get_class(cls: type) -> Class:
a | _PropertyNamer(n)
for n, a in cls.__dict__.get("__annotations__", {}).items()
],
doc=split_doc(cls.__doc__),
)

View File

@@ -141,6 +141,7 @@ def test_no_mixed_groups_in_bases():
class D(B, C):
pass
#
@@ -409,5 +410,137 @@ def test_ipa_class_on_dangling():
pass
def test_class_docstring():
@schema.load
class data:
class A:
"""Very important class."""
assert data.classes == {
'A': schema.Class('A', doc=["Very important class."])
}
def test_property_docstring():
@schema.load
class data:
class A:
x: int | defs.desc("very important property.")
assert data.classes == {
'A': schema.Class('A', properties=[schema.SingleProperty('x', 'int', doc=["very important property."])])
}
def test_class_docstring_newline():
@schema.load
class data:
class A:
"""Very important
class."""
assert data.classes == {
'A': schema.Class('A', doc=["Very important", "class."])
}
def test_property_docstring_newline():
@schema.load
class data:
class A:
x: int | defs.desc("""very important
property.""")
assert data.classes == {
'A': schema.Class('A', properties=[schema.SingleProperty('x', 'int', doc=["very important", "property."])])
}
def test_class_docstring_stripped():
@schema.load
class data:
class A:
"""
Very important class.
"""
assert data.classes == {
'A': schema.Class('A', doc=["Very important class."])
}
def test_property_docstring_stripped():
@schema.load
class data:
class A:
x: int | defs.desc("""
very important property.
""")
assert data.classes == {
'A': schema.Class('A', properties=[schema.SingleProperty('x', 'int', doc=["very important property."])])
}
def test_class_docstring_split():
@schema.load
class data:
class A:
"""Very important class.
As said, very important."""
assert data.classes == {
'A': schema.Class('A', doc=["Very important class.", "", "As said, very important."])
}
def test_property_docstring_split():
@schema.load
class data:
class A:
x: int | defs.desc("""very important property.
Very very important.""")
assert data.classes == {
'A': schema.Class('A', properties=[
schema.SingleProperty('x', 'int', doc=["very important property.", "", "Very very important."])])
}
def test_class_docstring_indent():
@schema.load
class data:
class A:
"""
Very important class.
As said, very important.
"""
assert data.classes == {
'A': schema.Class('A', doc=["Very important class.", " As said, very important."])
}
def test_property_docstring_indent():
@schema.load
class data:
class A:
x: int | defs.desc("""
very important property.
Very very important.
""")
assert data.classes == {
'A': schema.Class('A', properties=[
schema.SingleProperty('x', 'int', doc=["very important property.", " Very very important."])])
}
if __name__ == '__main__':
sys.exit(pytest.main([__file__] + sys.argv[1:]))