Skip to content

Python Parser

Bases: Parser

A parser for Python modules that contain axioms.

>>> parser = PythonParser()
>>> theory = parser.parse(Path("tests/theorems/mortals.py"))
>>> assert isinstance(theory, Theory)
>>> theory.name
'mortals'
Source code in src/typedlogic/parsers/pyparser/python_parser.py
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
class PythonParser(Parser):
    """
    A parser for Python modules that contain axioms.

        >>> parser = PythonParser()
        >>> theory = parser.parse(Path("tests/theorems/mortals.py"))
        >>> assert isinstance(theory, Theory)
        >>> theory.name
        'mortals'
    """

    def transform(self, source: ModuleType, **kwargs) -> Theory:
        """
        Transform a Python module into a Theory

        :param source:
        :param kwargs:
        :return:
        """
        return translate_module_to_theory(source)

    def parse(self, source: Union[Path, str, TextIO, ModuleType], file_name: Optional[str] = None, **kwargs) -> Theory:
        if isinstance(source, ModuleType):
            return translate_module_to_theory(source)
        if self.auto_validate:
            errs = self.validate(source)
            if errs:
                raise ValueError(f"Validation errors: {errs}")
        if isinstance(source, Path):
            with source.open() as f:
                return self.parse(f, file_name=str(source), **kwargs)
        if isinstance(source, str):
            module = compile_python(source, name=None, package_path=file_name)
            sgs = get_module_sentence_groups(source)
            pds = get_module_predicate_definitions(module)
            # get the python module name
            return Theory(
                name=module.__name__,
                predicate_definitions=list(pds.values()),
                sentence_groups=sgs,
                source_module_name=module.__name__,
            )
        if isinstance(source, (TextIOWrapper, TextIO)):
            lines = "\n".join(source.readlines())
            return self.parse(lines, file_name=file_name, **kwargs)
        raise ValueError(f"Unsupported source type: {type(source)}")

    def validate_iter(
        self, source: Union[Path, str, TextIO, ModuleType], file_name: Optional[str] = None, **kwargs
    ) -> Iterator[ValidationMessage]:
        """
        Validate a Python module

        Note that mypy is assumed to be installed

        :param source:
        :param file_name:
        :param kwargs:
        :return:
        """
        from mypy import api

        result: Optional[Tuple] = None
        if isinstance(source, str):
            with tempfile.NamedTemporaryFile(mode="w+t", delete=False) as temp_file:
                temp_file.write(source)
                result = api.run([temp_file.name])
        if isinstance(source, Path):
            result = api.run([str(source)])
        if result is None:
            raise ValueError(f"Unsupported source type: {type(source)}")
        stdout, stderr, exit_code = result
        if exit_code == 0:
            return
        lines = stderr.splitlines() + stdout.splitlines()
        if not lines:
            raise ValueError(f"No output from mypy; ret={exit_code}; stdout={stdout}; stderr={stderr}")
        for line in lines:
            yield ValidationMessage(line)

transform(source, **kwargs)

Transform a Python module into a Theory

Parameters:

Name Type Description Default
source ModuleType
required
kwargs
{}

Returns:

Type Description
Theory
Source code in src/typedlogic/parsers/pyparser/python_parser.py
68
69
70
71
72
73
74
75
76
def transform(self, source: ModuleType, **kwargs) -> Theory:
    """
    Transform a Python module into a Theory

    :param source:
    :param kwargs:
    :return:
    """
    return translate_module_to_theory(source)

validate_iter(source, file_name=None, **kwargs)

Validate a Python module

Note that mypy is assumed to be installed

Parameters:

Name Type Description Default
source Union[Path, str, TextIO, ModuleType]
required
file_name Optional[str]
None
kwargs
{}

Returns:

Type Description
Iterator[ValidationMessage]
Source code in src/typedlogic/parsers/pyparser/python_parser.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
def validate_iter(
    self, source: Union[Path, str, TextIO, ModuleType], file_name: Optional[str] = None, **kwargs
) -> Iterator[ValidationMessage]:
    """
    Validate a Python module

    Note that mypy is assumed to be installed

    :param source:
    :param file_name:
    :param kwargs:
    :return:
    """
    from mypy import api

    result: Optional[Tuple] = None
    if isinstance(source, str):
        with tempfile.NamedTemporaryFile(mode="w+t", delete=False) as temp_file:
            temp_file.write(source)
            result = api.run([temp_file.name])
    if isinstance(source, Path):
        result = api.run([str(source)])
    if result is None:
        raise ValueError(f"Unsupported source type: {type(source)}")
    stdout, stderr, exit_code = result
    if exit_code == 0:
        return
    lines = stderr.splitlines() + stdout.splitlines()
    if not lines:
        raise ValueError(f"No output from mypy; ret={exit_code}; stdout={stdout}; stderr={stderr}")
    for line in lines:
        yield ValidationMessage(line)