Source code for readmetester._main

"""
readmetester
============
"""
import typing as _t
from itertools import zip_longest as _zip_longest
from pathlib import Path as _Path

from . import _assert
from ._core import CatchStdout as _CatchStdout
from ._core import Code as _Code
from ._core import Command as _Command
from ._core import Holder as _Holder
from ._core import Parser as _Parser
from ._core import Readme as _Readme
from ._core import exec_status as _exec_status


def _process(lines: _t.List[_Code], holder: _Holder) -> None:
    """Populate items to their allocated ``list`` object.

    First split data by documented commands and documented command
    output.

        * Within the command section collect the header with ``total``
          and collect the  results from executed commands with ``total``
          and ``actual``.

        * Collect all non-command documentation as command output as
          this process is guaranteed to only run within a code-block.

    :param lines: Lines from README file.
    :param holder: Holding object.
    """
    command = _Command()
    for line in lines:

        # any lines beginning with ``>>> `` or ``... `` are considered
        # commands
        if line.iscode():
            holder.total.append_command(line)
            command.append(line)

            # if command ends with a colon it is a statement with a
            # continuation
            # append the continuation to execute as one command
            if command.ready():
                with _CatchStdout() as stdout:
                    command.exec()

                value = stdout.getparts()
                if value is not None:
                    holder.catch_output(value)

        elif not line.iscodebreak():

            # remove quotes from documented `str` output
            holder.expected.append(line.dequote())


[docs]def main(path: _t.Optional[_t.Union[str, _Path]] = None) -> None: """Parse README from commandline argument. Initialize ``Holder`` to contain expected, actual, and total values. Enumerate over parsed ``Readme`` and populate the three containers. 1. Expected ``list`` from the README file directly 2. Actual from the actual command output 3. Total with a combination of both plus code-block headings Run assertions on the actual and expected commands and print output from the total ``list``. Clear and initialize base key-values on each iteration. If no errors are raised then print that the README is a success and there are no errors in testing. :param path: Path to README. :raises OutputDocumentError: Raise if the expected ``list`` contains nothing even though command output was captured. """ if path is None: parser = _Parser() path = parser.file holder = _Holder() _assert.syntax(path) readme = _Readme() readme.load(path) _assert.code_blocks(readme) if _exec_status.in_exec: print("recursive exec not implemented") else: for count, element in enumerate(readme, 1): code_block = f"code-block {count}" holder.total.append_header(code_block) _process(element, holder) for position, _ in enumerate( _zip_longest(holder.actual, holder.expected) ): actual, expected = holder.getpair(position) _assert.actual_expected(actual, expected, code_block) _assert.equality(actual, expected, code_block) holder.display()