def parse_file(file, report_filename=None, report_firstline=1, encoding=None, **kw): """Parse a beancount input file and return Ledger with the list of transactions and tree of accounts. Args: file: file object or path to the file to be parsed. kw: a dict of keywords to be applied to the C parser. Returns: A tuple of ( list of entries parsed in the file, list of errors that were encountered during parsing, and a dict of the option values that were parsed from the file.) """ if encoding is not None and codecs.lookup(encoding).name != 'utf-8': raise ValueError('Only UTF-8 encoded files are supported.') with contextlib.ExitStack() as ctx: if file == '-': file = sys.stdin.buffer # It would be more appropriate here to check for io.RawIOBase but # that does not work for io.BytesIO despite it implementing the # readinto() method. elif not isinstance(file, io.IOBase): file = ctx.enter_context(open(file, 'rb')) builder = grammar.Builder() parser = _parser.Parser(builder) parser.parse(file, filename=report_filename, lineno=report_firstline, **kw) return builder.finalize()
def test_parser_parse(self): # Do not use a string to avoid issues due to string interning. name = object() self.assertEqual(sys.getrefcount(name), 2) f = io.BytesIO(b"") f.name = name self.assertEqual(sys.getrefcount(f.name), 3) builder = grammar.Builder() parser = _parser.Parser(builder) parser.parse(f) # The Parser object keeps a reference to the input file. self.assertEqual(sys.getrefcount(f), 3) # There are references to the file name from the Parser object # and from the the parsing results. In the case of an empty # input file from the options dictionary stored in the builder. self.assertEqual(sys.getrefcount(name), 5) builder.options = {} self.assertEqual(sys.getrefcount(name), 4) del parser # Once the Parser object is gone we should have just the local # reference to the file object and two references to name. self.assertEqual(sys.getrefcount(name), 3) self.assertEqual(sys.getrefcount(f), 2)
def parse_file(file, report_filename=None, report_firstline=1, **kw): """Parse a beancount input file and return Ledger with the list of transactions and tree of accounts. Args: file: file object or path to the file to be parsed. kw: a dict of keywords to be applied to the C parser. Returns: A tuple of ( list of entries parsed in the file, list of errors that were encountered during parsing, and a dict of the option values that were parsed from the file.) """ close_file = None if file == '-': close_file = file = sys.stdin.buffer # It would be more appropriate here to check for io.RawIOBase but # that does not work for io.BytesIO despite it implementing the # readinto() method. elif not isinstance(file, io.IOBase): close_file = file = open(file, 'rb') builder = grammar.Builder() parser = _parser.Parser(builder) parser.parse(file, filename=report_filename, lineno=report_firstline, **kw) if close_file: close_file.close() return builder.finalize()
def test_parse_string(self): # TODO(blais): Remove, this is temporary, for testing locally. filename = os.getenv("L") assert filename builder = grammar.Builder() out = extmodule.parse(builder, filename) print(out)
def parse_string(string, **kw): """Parse a beancount input file and return Ledger with the list of transactions and tree of accounts. Args: string: a str, the contents to be parsed instead of a file's. **kw: See parse.c. This function parses out 'dedent' which removes whitespace from the front of the text (default is False). Return: Same as the output of parse_file(). """ if kw.pop('dedent', None): string = textwrap.dedent(string) builder = grammar.Builder(None) _parser.parse_string(string, builder, **kw) builder.options['filename'] = '<string>' return builder.finalize()
def parse_file(filename, **kw): """Parse a beancount input file and return Ledger with the list of transactions and tree of accounts. Args: filename: the name of the file to be parsed. kw: a dict of keywords to be applied to the C parser. Returns: A tuple of ( list of entries parsed in the file, list of errors that were encountered during parsing, and a dict of the option values that were parsed from the file.) """ abs_filename = path.abspath(filename) if filename else None builder = grammar.Builder(abs_filename) _parser.parse_file(filename, builder, **kw) return builder.finalize()
def parse_string(string, report_filename=None, **kw): """Parse a beancount input file and return Ledger with the list of transactions and tree of accounts. Args: string: A string, the contents to be parsed instead of a file's. report_filename: A string, the source filename from which this string has been extracted, if any. This is stored in the metadata of the parsed entries. **kw: See parse.c. This function parses out 'dedent' which removes whitespace from the front of the text (default is False). Return: Same as the output of parse_file(). """ if kw.pop('dedent', None): string = textwrap.dedent(string) builder = grammar.Builder(report_filename or '<string>') _parser.parse_string(string, builder, report_filename=report_filename, **kw) return builder.finalize()
def test_parse_lineno(self): f = io.BytesIO(b"2020-07-30 open Assets:Test") builder = grammar.Builder() parser = _parser.Parser(builder) parser.parse(f, lineno=42) self.assertEqual(builder.entries[0].meta['lineno'], 42)