Path: blob/main/singlestoredb/docstring/tests/test_rest.py
469 views
"""Tests for ReST-style docstring routines."""1import typing as T23import pytest45from singlestoredb.docstring.common import ParseError6from singlestoredb.docstring.common import RenderingStyle7from singlestoredb.docstring.rest import compose8from singlestoredb.docstring.rest import parse91011@pytest.mark.parametrize(12'source, expected',13[14pytest.param(None, None, id='No __doc__'),15('', None),16('\n', None),17('Short description', 'Short description'),18('\nShort description\n', 'Short description'),19('\n Short description\n', 'Short description'),20],21)22def test_short_description(23source: T.Optional[str], expected: T.Optional[str],24) -> None:25"""Test parsing short description."""26docstring = parse(source)27assert docstring.short_description == expected28assert docstring.description == expected29assert docstring.long_description is None30assert not docstring.meta313233@pytest.mark.parametrize(34'source, expected_short_desc, expected_long_desc, expected_blank',35[36(37'Short description\n\nLong description',38'Short description',39'Long description',40True,41),42(43"""44Short description4546Long description47""",48'Short description',49'Long description',50True,51),52(53"""54Short description5556Long description57Second line58""",59'Short description',60'Long description\nSecond line',61True,62),63(64'Short description\nLong description',65'Short description',66'Long description',67False,68),69(70"""71Short description72Long description73""",74'Short description',75'Long description',76False,77),78(79'\nShort description\nLong description\n',80'Short description',81'Long description',82False,83),84(85"""86Short description87Long description88Second line89""",90'Short description',91'Long description\nSecond line',92False,93),94],95)96def test_long_description(97source: str,98expected_short_desc: str,99expected_long_desc: str,100expected_blank: bool,101) -> None:102"""Test parsing long description."""103docstring = parse(source)104assert docstring.short_description == expected_short_desc105assert docstring.long_description == expected_long_desc106assert docstring.blank_after_short_description == expected_blank107assert not docstring.meta108109110@pytest.mark.parametrize(111'source, expected_short_desc, expected_long_desc, '112'expected_blank_short_desc, expected_blank_long_desc, '113'expected_full_desc',114[115(116"""117Short description118:meta: asd119""",120'Short description',121None,122False,123False,124'Short description',125),126(127"""128Short description129Long description130:meta: asd131""",132'Short description',133'Long description',134False,135False,136'Short description\nLong description',137),138(139"""140Short description141First line142Second line143:meta: asd144""",145'Short description',146'First line\n Second line',147False,148False,149'Short description\nFirst line\n Second line',150),151(152"""153Short description154155First line156Second line157:meta: asd158""",159'Short description',160'First line\n Second line',161True,162False,163'Short description\n\nFirst line\n Second line',164),165(166"""167Short description168169First line170Second line171172:meta: asd173""",174'Short description',175'First line\n Second line',176True,177True,178'Short description\n\nFirst line\n Second line',179),180(181"""182:meta: asd183""",184None,185None,186False,187False,188None,189),190],191)192def test_meta_newlines(193source: str,194expected_short_desc: T.Optional[str],195expected_long_desc: T.Optional[str],196expected_blank_short_desc: bool,197expected_blank_long_desc: bool,198expected_full_desc: T.Optional[str],199) -> None:200"""Test parsing newlines around description sections."""201docstring = parse(source)202assert docstring.short_description == expected_short_desc203assert docstring.long_description == expected_long_desc204assert docstring.blank_after_short_description == expected_blank_short_desc205assert docstring.blank_after_long_description == expected_blank_long_desc206assert docstring.description == expected_full_desc207assert len(docstring.meta) == 1208209210def test_meta_with_multiline_description() -> None:211"""Test parsing multiline meta documentation."""212docstring = parse(213"""214Short description215216:meta: asd217121822193220""",221)222assert docstring.short_description == 'Short description'223assert len(docstring.meta) == 1224assert docstring.meta[0].args == ['meta']225assert docstring.meta[0].description == 'asd\n1\n 2\n3'226227228def test_multiple_meta() -> None:229"""Test parsing multiple meta."""230docstring = parse(231"""232Short description233234:meta1: asd235123622373238:meta2: herp239:meta3: derp240""",241)242assert docstring.short_description == 'Short description'243assert len(docstring.meta) == 3244assert docstring.meta[0].args == ['meta1']245assert docstring.meta[0].description == 'asd\n1\n 2\n3'246assert docstring.meta[1].args == ['meta2']247assert docstring.meta[1].description == 'herp'248assert docstring.meta[2].args == ['meta3']249assert docstring.meta[2].description == 'derp'250251252def test_meta_with_args() -> None:253"""Test parsing meta with additional arguments."""254docstring = parse(255"""256Short description257258:meta ene due rabe: asd259""",260)261assert docstring.short_description == 'Short description'262assert len(docstring.meta) == 1263assert docstring.meta[0].args == ['meta', 'ene', 'due', 'rabe']264assert docstring.meta[0].description == 'asd'265266267def test_params() -> None:268"""Test parsing params."""269docstring = parse('Short description')270assert len(docstring.params) == 0271272docstring = parse(273"""274Short description275276:param name: description 1277:param int priority: description 2278:param str? sender: description 3279:param str? message: description 4, defaults to 'hello'280:param str? multiline: long description 5,281defaults to 'bye'282""",283)284assert len(docstring.params) == 5285assert docstring.params[0].arg_name == 'name'286assert docstring.params[0].type_name is None287assert docstring.params[0].description == 'description 1'288assert docstring.params[0].default is None289assert not docstring.params[0].is_optional290assert docstring.params[1].arg_name == 'priority'291assert docstring.params[1].type_name == 'int'292assert docstring.params[1].description == 'description 2'293assert not docstring.params[1].is_optional294assert docstring.params[1].default is None295assert docstring.params[2].arg_name == 'sender'296assert docstring.params[2].type_name == 'str'297assert docstring.params[2].description == 'description 3'298assert docstring.params[2].is_optional299assert docstring.params[2].default is None300assert docstring.params[3].arg_name == 'message'301assert docstring.params[3].type_name == 'str'302assert (303docstring.params[3].description == "description 4, defaults to 'hello'"304)305assert docstring.params[3].is_optional306assert docstring.params[3].default == "'hello'"307assert docstring.params[4].arg_name == 'multiline'308assert docstring.params[4].type_name == 'str'309assert (310docstring.params[4].description311== "long description 5,\ndefaults to 'bye'"312)313assert docstring.params[4].is_optional314assert docstring.params[4].default == "'bye'"315316docstring = parse(317"""318Short description319320:param a: description a321:type a: int322:param int b: description b323""",324)325assert len(docstring.params) == 2326assert docstring.params[0].arg_name == 'a'327assert docstring.params[0].type_name == 'int'328assert docstring.params[0].description == 'description a'329assert docstring.params[0].default is None330assert not docstring.params[0].is_optional331332333def test_returns() -> None:334"""Test parsing returns."""335docstring = parse(336"""337Short description338""",339)340assert docstring.returns is None341assert docstring.many_returns is not None342assert len(docstring.many_returns) == 0343344docstring = parse(345"""346Short description347:returns: description348""",349)350assert docstring.returns is not None351assert docstring.returns.type_name is None352assert docstring.returns.description == 'description'353assert not docstring.returns.is_generator354assert docstring.many_returns == [docstring.returns]355356docstring = parse(357"""358Short description359:returns int: description360""",361)362assert docstring.returns is not None363assert docstring.returns.type_name == 'int'364assert docstring.returns.description == 'description'365assert not docstring.returns.is_generator366assert docstring.many_returns == [docstring.returns]367368docstring = parse(369"""370Short description371:returns: description372:rtype: int373""",374)375assert docstring.returns is not None376assert docstring.returns.type_name == 'int'377assert docstring.returns.description == 'description'378assert not docstring.returns.is_generator379assert docstring.many_returns == [docstring.returns]380381382def test_yields() -> None:383"""Test parsing yields."""384docstring = parse(385"""386Short description387""",388)389assert docstring.returns is None390assert docstring.many_returns is not None391assert len(docstring.many_returns) == 0392393docstring = parse(394"""395Short description396:yields: description397""",398)399assert docstring.returns is not None400assert docstring.returns.type_name is None401assert docstring.returns.description == 'description'402assert docstring.returns.is_generator403assert docstring.many_returns is not None404assert len(docstring.many_returns) == 1405assert docstring.many_returns[0] == docstring.returns406407docstring = parse(408"""409Short description410:yields int: description411""",412)413assert docstring.returns is not None414assert docstring.returns.type_name == 'int'415assert docstring.returns.description == 'description'416assert docstring.returns.is_generator417assert docstring.many_returns is not None418assert len(docstring.many_returns) == 1419assert docstring.many_returns[0] == docstring.returns420421422def test_raises() -> None:423"""Test parsing raises."""424docstring = parse(425"""426Short description427""",428)429assert len(docstring.raises) == 0430431docstring = parse(432"""433Short description434:raises: description435""",436)437assert len(docstring.raises) == 1438assert docstring.raises[0].type_name is None439assert docstring.raises[0].description == 'description'440441docstring = parse(442"""443Short description444:raises ValueError: description445""",446)447assert len(docstring.raises) == 1448assert docstring.raises[0].type_name == 'ValueError'449assert docstring.raises[0].description == 'description'450451452def test_broken_meta() -> None:453"""Test parsing broken meta."""454with pytest.raises(ParseError):455parse(':')456457with pytest.raises(ParseError):458parse(':param herp derp')459460with pytest.raises(ParseError):461parse(':param: invalid')462463with pytest.raises(ParseError):464parse(':param with too many args: desc')465466# these should not raise any errors467parse(':sthstrange: desc')468469470def test_deprecation() -> None:471"""Test parsing deprecation notes."""472docstring = parse(':deprecation: 1.1.0 this function will be removed')473assert docstring.deprecation is not None474assert docstring.deprecation.version == '1.1.0'475assert docstring.deprecation.description == 'this function will be removed'476477docstring = parse(':deprecation: this function will be removed')478assert docstring.deprecation is not None479assert docstring.deprecation.version is None480assert docstring.deprecation.description == 'this function will be removed'481482483@pytest.mark.parametrize(484'rendering_style, expected',485[486(487RenderingStyle.COMPACT,488'Short description.\n'489'\n'490'Long description.\n'491'\n'492':param int foo: a description\n'493':param int bar: another description\n'494':returns float: a return',495),496(497RenderingStyle.CLEAN,498'Short description.\n'499'\n'500'Long description.\n'501'\n'502':param int foo: a description\n'503':param int bar: another description\n'504':returns float: a return',505),506(507RenderingStyle.EXPANDED,508'Short description.\n'509'\n'510'Long description.\n'511'\n'512':param foo:\n'513' a description\n'514':type foo: int\n'515':param bar:\n'516' another description\n'517':type bar: int\n'518':returns:\n'519' a return\n'520':rtype: float',521),522],523)524def test_compose(rendering_style: RenderingStyle, expected: str) -> None:525"""Test compose"""526527docstring = parse(528"""529Short description.530531Long description.532533:param int foo: a description534:param int bar: another description535:return float: a return536""",537)538assert compose(docstring, rendering_style=rendering_style) == expected539540541def test_short_rtype() -> None:542"""Test abbreviated docstring with only return type information."""543string = 'Short description.\n\n:rtype: float'544docstring = parse(string)545rendering_style = RenderingStyle.EXPANDED546assert compose(docstring, rendering_style=rendering_style) == string547548549