# Licensed under a 3-clause BSD style license - see LICENSE.rst import importlib import secrets import sys from textwrap import dedent import pytest from astropy.utils.parsing import lex, yacc, _TAB_HEADER def _docstring_canary(): """Docstring that's here just to check for -OO.""" @pytest.mark.skipif(not _docstring_canary.__doc__, reason="Test cannot be run with -OO") def test_generate_parser(tmp_path, monkeypatch): # Write Python code into the temporary directory, so that the # generated tables will also go into the temporary directory. # We use a unique suffix so that the test can be run multiple times # without weirdness due to module caching. suffix = secrets.token_hex(16) lexer_file = tmp_path / f'test_parsing_lexer_{suffix}.py' lexer_file.write_text(dedent(fr""" from astropy.utils.parsing import lex def make_lexer(): tokens = ('NUMBER', 'PLUS') t_PLUS = r'\+' def t_NUMBER(t): r'\d+' t.value = int(t.value) return t return lex('test_parsing_lextab_{suffix}', 'test_parsing_lexer_{suffix}') """)) parser_file = tmp_path / f'test_parsing_parser_{suffix}.py' parser_file.write_text(dedent(fr""" from astropy.utils.parsing import yacc def make_parser(): tokens = ('NUMBER', 'PLUS') def p_expression_number(p): 'expression : NUMBER' p[0] = p[1] def p_expression_plus(p): 'expression : expression PLUS NUMBER' p[0] = p[1] + p[3] return yacc('test_parsing_parsetab_{suffix}', 'test_parsing_parser_{suffix}') """)) monkeypatch.syspath_prepend(tmp_path) lexer_mod = importlib.import_module(f'test_parsing_lexer_{suffix}') lexer = lexer_mod.make_lexer() parser_mod = importlib.import_module(f'test_parsing_parser_{suffix}') parser = parser_mod.make_parser() result = parser.parse('1+2+3', lexer=lexer) assert result == 6 lextab = (tmp_path / f'test_parsing_lextab_{suffix}.py').read_text() assert lextab.startswith(_TAB_HEADER.format(package=f'test_parsing_lexer_{suffix}')) parsetab = (tmp_path / f'test_parsing_parsetab_{suffix}.py').read_text() assert parsetab.startswith(_TAB_HEADER.format(package=f'test_parsing_parser_{suffix}'))