1# Licensed under a 3-clause BSD style license - see LICENSE.rst 2 3import importlib 4import secrets 5import sys 6from textwrap import dedent 7 8import pytest 9 10from astropy.utils.parsing import lex, yacc, _TAB_HEADER 11 12 13def _docstring_canary(): 14 """Docstring that's here just to check for -OO.""" 15 16 17@pytest.mark.skipif(not _docstring_canary.__doc__, reason="Test cannot be run with -OO") 18def test_generate_parser(tmp_path, monkeypatch): 19 # Write Python code into the temporary directory, so that the 20 # generated tables will also go into the temporary directory. 21 # We use a unique suffix so that the test can be run multiple times 22 # without weirdness due to module caching. 23 suffix = secrets.token_hex(16) 24 lexer_file = tmp_path / f'test_parsing_lexer_{suffix}.py' 25 lexer_file.write_text(dedent(fr""" 26 from astropy.utils.parsing import lex 27 28 def make_lexer(): 29 tokens = ('NUMBER', 'PLUS') 30 t_PLUS = r'\+' 31 32 def t_NUMBER(t): 33 r'\d+' 34 t.value = int(t.value) 35 return t 36 37 return lex('test_parsing_lextab_{suffix}', 'test_parsing_lexer_{suffix}') 38 """)) 39 parser_file = tmp_path / f'test_parsing_parser_{suffix}.py' 40 parser_file.write_text(dedent(fr""" 41 from astropy.utils.parsing import yacc 42 43 def make_parser(): 44 tokens = ('NUMBER', 'PLUS') 45 46 def p_expression_number(p): 47 'expression : NUMBER' 48 p[0] = p[1] 49 50 def p_expression_plus(p): 51 'expression : expression PLUS NUMBER' 52 p[0] = p[1] + p[3] 53 54 return yacc('test_parsing_parsetab_{suffix}', 'test_parsing_parser_{suffix}') 55 """)) 56 57 monkeypatch.syspath_prepend(tmp_path) 58 59 lexer_mod = importlib.import_module(f'test_parsing_lexer_{suffix}') 60 lexer = lexer_mod.make_lexer() 61 parser_mod = importlib.import_module(f'test_parsing_parser_{suffix}') 62 parser = parser_mod.make_parser() 63 result = parser.parse('1+2+3', lexer=lexer) 64 assert result == 6 65 66 lextab = (tmp_path / f'test_parsing_lextab_{suffix}.py').read_text() 67 assert lextab.startswith(_TAB_HEADER.format(package=f'test_parsing_lexer_{suffix}')) 68 parsetab = (tmp_path / f'test_parsing_parsetab_{suffix}.py').read_text() 69 assert parsetab.startswith(_TAB_HEADER.format(package=f'test_parsing_parser_{suffix}')) 70