def test_only_lines_matching_line_matcher_SHOULD_be_replaced(self): # ARRANGE # pattern = r'PA[A-Z]*N' string_matching_pattern = 'PATTERN' string_not_matching_pattern = '<not matched by pattern>' string_matched_by_line_selector = '<MATCHED BY LINE MATCHER>' string_not_matched_by_line_selector = '<not matched by line matcher>' replacement_str = 'REPLACEMENT' sf = StringFormatter({ 'matches_pattern': string_matching_pattern, 'replacement_str': replacement_str, 'not_pattern': string_not_matching_pattern, 'lm_match': string_matched_by_line_selector, 'lm_no_match': string_not_matched_by_line_selector, }) input_lines__tmpl = [ '{matches_pattern} {lm_no_match}', '{matches_pattern} {lm_match}', '{not_pattern} {lm_no_match}', '{not_pattern} {lm_match}', ] output_lines__tmpl = [ '{matches_pattern} {lm_no_match}', '{replacement_str} {lm_match}', '{not_pattern} {lm_no_match}', '{not_pattern} {lm_match}', ] input_lines = [sf.format(line) for line in input_lines__tmpl] output_lines = [sf.format(line) for line in output_lines__tmpl] lines_selector = LineMatcherSymbolContext.of_primitive( 'LINES_SELECTOR_MATCHER', line_matchers.LineMatcherThatMatchesContentsSubString( string_matched_by_line_selector), ) # ACT & ASSERT # self._check( pattern, replacement_str, lines_selector, input_lines, output_lines, )
def plain_symbol_name_is_reserved_word(self, primitive_name: str) -> str: formatter = StringFormatter({ 'reserved_word': formatting.misc_name_with_formatting(misc_texts.RESERVED_WORD_NAME), 'syntax_element': self._grammar.concept.syntax_element.name, 'actual': formatting.keyword(primitive_name), }) lines = [formatter.format(self._RESERVED_WORD__HEADER), '', formatter.format(self._RESERVED_WORD__LIST_HEADER), ''] lines += [ self._INDENT + formatting.keyword(reserved_word) for reserved_word in sorted(self._grammar.custom_reserved_words) ] return '\n'.join(lines)
def cases_for(primitive_expr: str, the_operator: str) -> List[NameAndValue[str]]: sf = StringFormatter({ 'primitive_expr': primitive_expr, 'operator': the_operator, 'non_expr': ast.NOT_A_PRIMITIVE_EXPR_NAME_AND_NOT_A_VALID_SYMBOL_NAME, }) return [ NameAndValue( 'operator not followed by expression', sf.format('{primitive_expr} {operator}'), ), NameAndValue( 'operator followed by non-expression', sf.format('{primitive_expr} {operator} {non_expr}'), ), NameAndValue( 'operator followed by non-expression/two operators', sf.format('{primitive_expr} {operator} {primitive_expr} {operator} {non_expr}'), ), NameAndValue( '( at start of expr: missing )', sf.format('( {primitive_expr} {operator} {primitive_expr} '), ), NameAndValue( '( in middle of expr: missing )', sf.format('( {primitive_expr} {operator} ( {primitive_expr} '), ), ]
def cases_for_symbol_syntax( symbol_reference: NameAndValue[str]) -> List[SourceCase]: sf = StringFormatter({ 'symbol_name': symbol_reference.value, 'space_after': space_after, 'token_after': token_after, }) def source(template: str) -> str: return sf.format(template) def name(case: str) -> str: return 'symbol_syntax={} / {}'.format(symbol_reference.name, case)
def cases_for_operator(the_prefix_operator: str) -> List[SourceCase]: sf = StringFormatter({ 'op': the_prefix_operator, 'primitive_expr': primitive_expr_src, 'space_after': space_after, 'token_after': token_after, }) return [ SourceCase('first line is only primitive expr', sf.format('{op} {primitive_expr}'), SourceExpectation.is_at_end_of_line(1)), SourceCase( 'first line is primitive expr with space around', sf.format(' {op} {primitive_expr}{space_after}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=space_after[1:])), SourceCase( 'expression is followed by non-expression', sf.format('{op} {primitive_expr} {token_after}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=token_after)), SourceCase( '( op primitive )', sf.format('( {op} {primitive_expr} )'), SourceExpectation.is_at_end_of_line(1), ), SourceCase( 'op ( primitive )', sf.format('{op} ( {primitive_expr} )'), SourceExpectation.is_at_end_of_line(1), ), SourceCase( 'no source after operator, but expr on following line', sf.format('{op}\n{primitive_expr}'), SourceExpectation.is_at_end_of_line(2), ), ]
return _dir_error(path, '{PATH} exists, but is not {directory:a}') except NotADirectoryError: return _dir_error(path, 'Clash with existing file') return None def _dir_error(path: DescribedPath, header_tmpl: str) -> TextRenderer: return path_err_msgs.line_header__primitive( _DIR_ERROR_FORMATTER.format(header_tmpl), path.describer, ) _DIR_ERROR_FORMATTER = StringFormatter({ 'PATH': syntax_elements.PATH_SYNTAX_ELEMENT.singular_name, 'directory': file_types.DIRECTORY, }) ERR = TypeVar('ERR') def _create_file(file_path: pathlib.Path, ensure_parent_path_is_existing_dir: Callable[[], Optional[ERR]], error_renderer: Callable[[str], ERR], operation_on_open_file: Callable[[TextIO], None], ) -> Optional[ERR]: """ :return: None iff success. Otherwise an error message. """ try: file_path.lstat()
def __init__(self, format_map: Optional[Mapping[str, Any]] = None): self._string_formatter = StringFormatter(format_map)
class TextParser: def __init__(self, format_map: Optional[Mapping[str, Any]] = None): self._string_formatter = StringFormatter(format_map) def format( self, template: str, extra: Optional[Mapping[str, Any]] = None, ) -> str: """ Formats the given string using the format map given in the constructor. """ return self._string_formatter.format(template, extra) def text( self, s: str, extra: Optional[Mapping[str, Any]] = None, ) -> docs.StringText: return docs.string_text(self.format(s, extra)) def para( self, s: str, extra: Optional[Mapping[str, Any]] = None, ) -> docs.ParagraphItem: return docs.para(self.format(s, extra)) def paras( self, s: str, extra: Optional[Mapping[str, Any]] = None, ) -> List[ParagraphItem]: return docs.paras(self.format(s, extra)) def fap( self, s: str, extra: Optional[Mapping[str, Any]] = None, ) -> List[ParagraphItem]: """ 1. Text replacements according to `format_map` given to the constructor. 2. parse result """ return split_and_parse(self.format(s, extra)) def fnap( self, s: str, extra: Optional[Mapping[str, Any]] = None, ) -> List[ParagraphItem]: """ 1. Text replacements according to `format_map` given to the constructor. 2. normalize lines 3. parse result """ return normalize_and_parse(self.format(s, extra)) def fnap__fun( self, s: str, extra: Optional[Mapping[str, Any]] = None, ) -> Callable[[], List[ParagraphItem]]: """A variant of fnap.""" def ret_val() -> List[ParagraphItem]: return normalize_and_parse(self.format(s, extra)) return ret_val def paragraph_items( self, s: str, extra: Optional[Mapping[str, Any]] = None, ) -> List[ParagraphItem]: return self.fnap(self.format(s, extra)) def section(self, header_or_text, paragraphs_text: str, extra: Optional[Mapping[str, Any]] = None) -> docs.Section: """ :param header_or_text: If a `str` it is formatted using `self.format`. :param paragraphs_text: Parsed using `self.fnap`. """ header = header_or_text if not isinstance(header_or_text, docs.Text): header = docs.text(self.format(header_or_text, extra)) return docs.section(header, self.fnap(paragraphs_text, extra)) def section_contents( self, paragraphs_text: str, extra: Optional[Mapping[str, Any]] = None, ) -> docs.SectionContents: """ :param paragraphs_text: Parsed using `self.fnap`. """ return docs.section_contents(self.fnap(paragraphs_text, extra))
_SET_SPEC_ARGUMENT_2_SPEC = { defs.PHASE_SPEC__ACT: frozenset((_impl.Phase.ACT,)), defs.PHASE_SPEC__NON_ACT: frozenset((_impl.Phase.NON_ACT,)), } _ALL_PHASES = frozenset(_impl.Phase) def parts_parser(phase_is_after_act: bool): return PartsParserFromEmbryoParser(EmbryoParser(phase_is_after_act), MainStepResultTranslatorForUnconditionalSuccess()) class _MissingUnsetKeywordOrVarNameErrorMessage(token_stream_parser.ErrorMessageGenerator): def message(self) -> str: return _SF.format('Expecting {unset_keyword} or {var_name}') class _VarNameErrorMessage(token_stream_parser.ErrorMessageGenerator): def message(self) -> str: return _SF.format('Expecting {var_name}') _MISSING_UNSET_KEYWORD_OR_VAR_NAME_ERROR_MESSAGE = _MissingUnsetKeywordOrVarNameErrorMessage() _MISSING_VAR_NAME_ERROR_MESSAGE = _VarNameErrorMessage() _SF = StringFormatter({ 'unset_keyword': defs.UNSET_IDENTIFIER, 'var_name': defs.VAR_NAME_ELEMENT, })
def source_cases_for_expressions(primitive_expr: str, operator: str) -> List[SourceCase]: sf = StringFormatter({ 'primitive_expr': primitive_expr, 'operator': operator, 'quoted_operator': surrounded_by_soft_quotes(operator_source), 'space_after': ' ', 'quoted_string': surrounded_by_hard_quotes('quoted string'), }) def source(template: str) -> str: return sf.format(template) return [ SourceCase( 'first line is just infix op expr', source('{primitive_expr} {operator} {primitive_expr}'), SourceExpectation.is_at_end_of_line(1) ), SourceCase( 'first line is infix op expr, followed by space', source('{primitive_expr} {operator} {primitive_expr}{space_after}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=sf.format('{space_after}')[1:]) ), SourceCase( 'infix op expr followed by non-operator', source('{primitive_expr} {operator} {primitive_expr} {quoted_string}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=sf.format('{quoted_string}')) ), SourceCase( 'infix op expr followed by primitive expression', source('{primitive_expr} {operator} {primitive_expr} {primitive_expr}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=sf.format('{primitive_expr}')) ), SourceCase( 'infix op expr followed by quoted operator', source('{primitive_expr} {operator} {primitive_expr} {quoted_operator}'), SourceExpectation.source_is_not_at_end( current_line_number=1, remaining_part_of_current_line=sf.format('{quoted_operator}')) ), SourceCase( 'first line is just infix op expr: inside ()', source('( {primitive_expr} {operator} {primitive_expr} )'), SourceExpectation.is_at_end_of_line(1) ), SourceCase( 'first primitive expr inside ()', source('( {primitive_expr} ) {operator} {primitive_expr}'), SourceExpectation.is_at_end_of_line(1) ), SourceCase( 'second primitive expr inside ()', source('{primitive_expr} {operator} ( {primitive_expr} )'), SourceExpectation.is_at_end_of_line(1) ), SourceCase( 'second expr on following line', source('{primitive_expr} {operator}\n{primitive_expr}'), SourceExpectation.is_at_end_of_line(2) ), ]
'{BEGIN_BRACE} fn1 fn2 {END_BRACE}'), NameAndValue('first line ok, multiple file names on second line', '{BEGIN_BRACE} file-name\n' 'fn1 fn2\n' '{END_BRACE}'), ] for must_be_on_current_line in [False, True]: for case in cases: with self.subTest( source_case=case.name, must_be_on_current_line=must_be_on_current_line): source = _SF.format(case.value) self._expect_parse_exception(source, must_be_on_current_line) _SF = StringFormatter({ 'BEGIN_BRACE': syntax.LITERAL_BEGIN, 'END_BRACE': syntax.LITERAL_END, 'FILE_MATCHER_SEPARATOR': syntax.FILE_MATCHER_SEPARATOR, 'FILE_NAME': 'a-file-name', 'FILE_MATCHER': 'file_matcher_symbol', 'INVALID_FILE_MATCHER': NOT_A_VALID_SYMBOL_NAME_NOR_PRIMITIVE_GRAMMAR_ELEMENT_NAME, })
from exactly_lib.util.str_.formatter import StringFormatter from exactly_lib_test.test_resources.test_utils import NIE from exactly_lib_test.util.test_resources.quoting import surrounded_by_hard_quotes SINGLE_TOKEN_NAME = 'single_token_dir_name' MULTI_LINE_NAME = 'a\nname\nthat\nspans\nmultiple\nlines\n' SF = StringFormatter({ 'single_token_name': SINGLE_TOKEN_NAME, 'quoted_multi_line_name': surrounded_by_hard_quotes(MULTI_LINE_NAME), }) SOURCE_LAYOUT_CASES = [ NIE( 'all arguments on first line', input_value=SF.format('{single_token_name}'), expected_value=SINGLE_TOKEN_NAME, ), NIE( 'path argument on following line', input_value=SF.format('\n {single_token_name}'), expected_value=SINGLE_TOKEN_NAME, ), NIE( 'multi line path argument on following line', input_value=SF.format('\n {quoted_multi_line_name}'), expected_value=MULTI_LINE_NAME, ), ]
return _EXIT_CODE_LINE_PREFIX + str(exit_code) def _actual_exit_code_and_stderr_block( exit_code: int, stderr_contents: str) -> Renderer[MajorBlock]: def exit_code_block() -> Renderer[MinorBlock]: return blocks.MinorBlockOfSingleLineObject( line_objects.PreFormattedString(_actual_exit_code_line(exit_code))) minor_blocks = [ exit_code_block(), ] if stderr_contents: minor_blocks.append(stderr_contents_block(stderr_contents)) return comp_rend.MajorBlockR(combinators.SequenceR(minor_blocks)) _STRING_FORMATTER = StringFormatter({ 'exit_code': misc_texts.EXIT_CODE, 'program': types.PROGRAM_TYPE_INFO.name, }) _NON_ZERO_EXIT_CODE_HEADER = _STRING_FORMATTER.format( 'Non-zero {exit_code} from {program}') _UNABLE_TO_EXECUTE_HEADER = _STRING_FORMATTER.format( 'Unable to execute {program}') _EXIT_CODE_LINE_PREFIX = misc_texts.EXIT_CODE_TITLE + ': '