diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..80111fe --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,22 @@ +name: Test + +on: + workflow_dispatch: + push: + branches: + - main + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.9' + cache: 'pip' + - run: pip install -r dev.txt + - run: black --check . + - run: pylint doxygentoasciidoc + - run: pytest diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..f6628c8 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,8 @@ +[MESSAGES CONTROL] +disable=missing-module-docstring,missing-function-docstring,missing-class-docstring,too-many-lines + +[FORMAT] +good-names=id + +[MASTER] +ignore=tests diff --git a/README.md b/README.md index 7182187..7a30882 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,29 @@ Allowed args: `-c`: process a node other than `doxygenindex` The following attributes from the XML will be preserved in the generated asciidoc: role, tag, type. + +## Development + +Install the development dependencies: + +```console +$ pip install -r dev.txt +``` + +Run the test suite: + +```console +$ pytest +``` + +Ensure code is formatted consistently: + +```console +$ black --check . +``` + +Ensure code passes linting: + +```console +$ pylint doxygentoasciidoc +``` diff --git a/cli.py b/cli.py index f151d29..67a6a54 100644 --- a/cli.py +++ b/cli.py @@ -1,7 +1,6 @@ import os import sys import argparse -import yaml from bs4 import BeautifulSoup from .nodes import Node, DoxygenindexNode @@ -10,9 +9,19 @@ def main(): """Convert the given Doxygen index.xml to AsciiDoc and output the result.""" parser = argparse.ArgumentParser() - parser.add_argument("-f", "--file", help="The path of the file to convert", default=None) - parser.add_argument("-o", "--output", help="The path of the output file", default=None) - parser.add_argument("-c", "--child", help="Is NOT the root index file", default=False, action='store_true') + parser.add_argument( + "-f", "--file", help="The path of the file to convert", default=None + ) + parser.add_argument( + "-o", "--output", help="The path of the output file", default=None + ) + parser.add_argument( + "-c", + "--child", + help="Is NOT the root index file", + default=False, + action="store_true", + ) args = parser.parse_args() filename = args.file output_filename = args.output diff --git a/dev.txt b/dev.txt new file mode 100644 index 0000000..84b19d8 --- /dev/null +++ b/dev.txt @@ -0,0 +1,4 @@ +-r requirements.txt +pytest +pylint +black diff --git a/helpers.py b/helpers.py index 073eddb..e0ca580 100644 --- a/helpers.py +++ b/helpers.py @@ -22,16 +22,16 @@ def title(text, level, attributes=None): """Return text formatted as a title with the given level.""" if level > 5: if attributes is not None: - if re.search(r'([,\s]role=)', attributes) is not None: - attributes = re.sub(r'([,\s]role=)(.*?[,\s]?$)', "\\1h6 \\2", attributes) + if re.search(r"([,\s]role=)", attributes) is not None: + attributes = re.sub( + r"([,\s]role=)(.*?[,\s]?$)", "\\1h6 \\2", attributes + ) else: attributes += ",role=h6" return f"[{attributes}]\n*{escape_text(text)}*" - else: - return f"[.h6]\n*{escape_text(text)}*" + return f"[.h6]\n*{escape_text(text)}*" marker = "=" * (level + 1) if attributes is not None: return f"[{attributes}]\n{marker} {escape_text(text)}" - else: - return f"{marker} {escape_text(text)}" + return f"{marker} {escape_text(text)}" diff --git a/nodes.py b/nodes.py index 9d1e208..14b8a0e 100644 --- a/nodes.py +++ b/nodes.py @@ -163,8 +163,10 @@ def children(self, selector=None, **kwargs): for position, child in enumerate(children) ] - def attributes(self, skip=[], **kwargs): + def attributes(self, skip=None): """Return an asciidoc string of any attributes specified, plus the node id.""" + if skip is None: + skip = [] preserved_attributes = ["role", "tag", "type"] atts = [] if self.node.get("id", None) is not None and "id" not in skip: @@ -395,6 +397,7 @@ def to_asciidoc_row(self, depth=0): class GroupNode(Node): def to_asciidoc(self, **kwargs): + # pylint: disable=too-many-locals,too-many-branches output = [self.__output_title(**kwargs)] briefdescription = self.__output_briefdescription(**kwargs) if briefdescription: @@ -990,7 +993,8 @@ def to_asciidoc(self, **kwargs): ) else: output.append( - f"[.memname]`#define {escape_text(name)}{escape_text(argsstring)} {escape_text(initializer).rstrip()}`" + f"[.memname]`#define {escape_text(name)}{escape_text(argsstring)} " + f"{escape_text(initializer).rstrip()}`" ) else: output.append( @@ -1063,7 +1067,8 @@ def to_asciidoc(self, **kwargs): for memberdef in self.children("memberdef", kind="typedef"): type_ = memberdef.child("type").to_asciidoc(**kwargs) typedef = [ - f"`typedef {type_} <<{memberdef.id},{escape_text(memberdef.text('name'))}>>{escape_text(memberdef.text('argsstring'))}`::" + f"`typedef {type_} <<{memberdef.id},{escape_text(memberdef.text('name'))}>>" + f"{escape_text(memberdef.text('argsstring'))}`::" ] briefdescription = memberdef.child("briefdescription").to_asciidoc(**kwargs) if briefdescription: @@ -1148,7 +1153,8 @@ def to_asciidoc(self, **kwargs): else: argsstring = "" macro = [ - f"* `#define <<{memberdef.id},{escape_text(memberdef.text('name'))}>>{escape_text(argsstring)}" + f"* `#define <<{memberdef.id},{escape_text(memberdef.text('name'))}>>" + f"{escape_text(argsstring)}" ] if memberdef.text("initializer"): initializer = memberdef.child("initializer").to_asciidoc( diff --git a/tests/test_copyright_node.py b/tests/test_copyright_node.py index ef7571b..1636c45 100644 --- a/tests/test_copyright_node.py +++ b/tests/test_copyright_node.py @@ -5,6 +5,8 @@ def test_copyright_node(tmp_path): xml = """""" - asciidoc = CopyrightNode(BeautifulSoup(xml, "xml").copy, xmldir=tmp_path).to_asciidoc() + asciidoc = CopyrightNode( + BeautifulSoup(xml, "xml").copy, xmldir=tmp_path + ).to_asciidoc() assert asciidoc == "©" diff --git a/tests/test_heading_node.py b/tests/test_heading_node.py index 69082f4..6487b1b 100644 --- a/tests/test_heading_node.py +++ b/tests/test_heading_node.py @@ -5,6 +5,8 @@ def test_heading_node(tmp_path): xml = """Examples Index""" - asciidoc = HeadingNode(BeautifulSoup(xml, "xml").title, xmldir=tmp_path).to_asciidoc() + asciidoc = HeadingNode( + BeautifulSoup(xml, "xml").title, xmldir=tmp_path + ).to_asciidoc() assert asciidoc == "=== Examples Index" diff --git a/tests/test_none_node.py b/tests/test_none_node.py index c4f1d34..a23fafc 100644 --- a/tests/test_none_node.py +++ b/tests/test_none_node.py @@ -5,6 +5,8 @@ def test_none_node(tmp_path): xml = """examples_page""" - asciidoc = NoneNode(BeautifulSoup(xml, "xml").compoundname, xmldir=tmp_path).to_asciidoc() + asciidoc = NoneNode( + BeautifulSoup(xml, "xml").compoundname, xmldir=tmp_path + ).to_asciidoc() assert asciidoc == "" diff --git a/tests/test_sect_node.py b/tests/test_sect_node.py index 8ec40fa..d892330 100644 --- a/tests/test_sect_node.py +++ b/tests/test_sect_node.py @@ -33,7 +33,9 @@ def test_compounddef_kind_page_is_processed_as_sect(tmp_path): """ - asciidoc = Node(BeautifulSoup(xml, "xml").compounddef, xmldir=tmp_path).to_asciidoc() + asciidoc = Node( + BeautifulSoup(xml, "xml").compounddef, xmldir=tmp_path + ).to_asciidoc() assert asciidoc == dedent( """\