From 5212c005b664239c48270896f73fa119b485ba61 Mon Sep 17 00:00:00 2001 From: blais Date: Sun, 30 Apr 2023 15:44:16 -0400 Subject: [PATCH 01/36] (lint) --- .pylintrc | 56 +++++++++------------------ Makefile | 3 ++ beancount/ingest/identify_test.py | 1 - beancount/ingest/regression_pytest.py | 4 +- beancount/parser/booking_full.py | 3 +- beancount/plugins/close_tree.py | 36 ++++++++++------- beancount/prices/sources/coinbase.py | 2 +- beancount/prices/sources/iex.py | 2 +- beancount/prices/sources/quandl.py | 2 +- beancount/prices/sources/tsp.py | 2 +- beancount/prices/sources/yahoo.py | 6 ++- beancount/query/query_env_test.py | 3 +- beancount/reports/report.py | 1 + beancount/tools/treeify.py | 6 +-- beancount/utils/defdict.py | 2 +- 15 files changed, 61 insertions(+), 68 deletions(-) diff --git a/.pylintrc b/.pylintrc index 86fd97315..bd9302a79 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,3 +1,9 @@ +# module-name-hint, method-name-hint, class-name-hint, class-attribute-name-hint, +# inlinevar-name-hint, variable-name-hint, const-name-hint, attr-name-hint, +# argument-name-hint, function-name-hint, no-space-check + + + [MASTER] # Specify a configuration file. @@ -32,11 +38,6 @@ load-plugins=pylint_protobuf # mypackage.mymodule.MyReporterClass. output-format=text -# Put messages in a separate file for each module / package specified on the -# command line instead of printing them on stdout. Reports (if any) will be -# written in a file name "pylint_global.[txt|html]". -files-output=no - # Tells whether to display a full report or only the messages reports=no @@ -86,8 +87,6 @@ disable=locally-disabled, too-many-function-args, unsubscriptable-object, too-many-nested-blocks, - no-self-use, - redefined-variable-type, duplicate-code, too-few-public-methods, too-many-public-methods, @@ -121,7 +120,6 @@ disable=locally-disabled, c-extension-no-member, cyclic-import, isinstance-second-argument-not-valid-type, - bad-continuation, consider-using-f-string, consider-using-with, unspecified-encoding, @@ -130,12 +128,9 @@ disable=locally-disabled, global-variable-not-assigned, useless-suppression, unused-private-member, - use-maxsplit-arg - - -# Notes: -# bad-continuation: Is buggy, see https://github.com/PyCQA/pylint/issues/3512 - + use-maxsplit-arg, + use-dict-literal, + unnecessary-lambda-assignment [VARIABLES] @@ -188,9 +183,6 @@ notes=FIXME,XXX,TODO [BASIC] -# List of builtins function names that should not be used, separated by a comma -bad-functions= - # Good variable names which should always be accepted, separated by a comma good-names=f,i,j,k,ex,Run,_ @@ -208,61 +200,61 @@ include-naming-hint=no module-rgx=(([a-z_][a-z0-9_\-]*)|([A-Z][a-zA-Z0-9]+))$ # Naming hint for module names -module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ +##module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Regular expression matching correct method names method-rgx=[a-z_][a-zA-Z0-9_]{2,72}$ # Naming hint for method names -method-name-hint=[a-z_][a-zA-Z0-9_]{2,64}$ +##method-name-hint=[a-z_][a-zA-Z0-9_]{2,64}$ # Regular expression matching correct class names class-rgx=[A-Z_][a-zA-Z0-9]+$ # Naming hint for class names -class-name-hint=[A-Z_][a-zA-Z0-9]+$ +##class-name-hint=[A-Z_][a-zA-Z0-9]+$ # Regular expression matching correct class attribute names class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{1,30}|(__.*__))$ # Naming hint for class attribute names -class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{1,30}|(__.*__))$ +##class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{1,30}|(__.*__))$ # Regular expression matching correct inline iteration names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Naming hint for inline iteration names -inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ +##inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ # Regular expression matching correct variable names variable-rgx=(_?[a-z_][a-z0-9_]{1,30}|__|mu|no)$ # Naming hint for variable names -variable-name-hint=[a-z_][a-z0-9_]{1,30}$ +##variable-name-hint=[a-z_][a-z0-9_]{1,30}$ # Regular expression matching correct constant names const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Naming hint for constant names -const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ +##const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Regular expression matching correct attribute names attr-rgx=[a-z_][a-z0-9_]{1,30}$ # Naming hint for attribute names -attr-name-hint=[a-z_][a-z0-9_]{1,30}$ +##attr-name-hint=[a-z_][a-z0-9_]{1,30}$ # Regular expression matching correct argument names argument-rgx=(_?[a-z_][a-z0-9_]{1,30}|__|mu)$ # Naming hint for argument names -argument-name-hint=[a-z_][a-z0-9_]{1,30}$ +##argument-name-hint=[a-z_][a-z0-9_]{1,30}$ # Regular expression matching correct function names function-rgx=_?[a-z_][a-zA-Z0-9_]{2,64}$ # Naming hint for function names -function-name-hint=[a-z_][a-zA-Z0-9_]{2,64}$ +##function-name-hint=[a-z_][a-zA-Z0-9_]{2,64}$ # Regular expression which should only match function or class names that do # not require a docstring. @@ -285,9 +277,6 @@ ignore-long-lines=^\s*(# )??$ # else. single-line-if-stmt=no -# List of optional constructs for which whitespace checking is disabled -no-space-check=trailing-comma,dict-separator - # Maximum number of lines in a module max-module-lines=1000 @@ -380,10 +369,3 @@ valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=mcs - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=Exception diff --git a/Makefile b/Makefile index 631ee995f..7ad6fe7db 100755 --- a/Makefile +++ b/Makefile @@ -234,6 +234,9 @@ pylint-only: pyflakes: pyflakes $(LINT_SRCS) +ruff: + ruff beancount examples/ingest/office/importers tools + # Check everything. status check: pylint pyflakes filter-terms missing-tests dep-constraints multi-imports test diff --git a/beancount/ingest/identify_test.py b/beancount/ingest/identify_test.py index b54e5e49b..20ee7cf67 100644 --- a/beancount/ingest/identify_test.py +++ b/beancount/ingest/identify_test.py @@ -3,7 +3,6 @@ from os import path from unittest import mock -import os import re import subprocess import sys diff --git a/beancount/ingest/regression_pytest.py b/beancount/ingest/regression_pytest.py index bb0a8aae4..75ee347a5 100644 --- a/beancount/ingest/regression_pytest.py +++ b/beancount/ingest/regression_pytest.py @@ -44,9 +44,9 @@ class TestImporter(regtest.ImporterTestBase): from os import path import io import os -import pytest import re -import unittest + +import pytest from beancount.ingest import cache from beancount.ingest import extract diff --git a/beancount/parser/booking_full.py b/beancount/parser/booking_full.py index a5926ce29..b6aa1d535 100644 --- a/beancount/parser/booking_full.py +++ b/beancount/parser/booking_full.py @@ -76,7 +76,6 @@ import copy import enum from decimal import Decimal -from typing import Text import uuid from beancount.core.number import MISSING @@ -93,7 +92,7 @@ from beancount.core import interpolate -def unique_label() -> Text: +def unique_label() -> str: "Return a globally unique label for cost entries." return str(uuid.uuid4()) diff --git a/beancount/plugins/close_tree.py b/beancount/plugins/close_tree.py index 7d4d6a4af..f4985e6eb 100644 --- a/beancount/plugins/close_tree.py +++ b/beancount/plugins/close_tree.py @@ -1,12 +1,12 @@ -"""This plugin inserts close directives for all of an account's descendants when an account is -closed. Unopened parent accounts can also be closed. Any explicitly specified close is left -untouched. +"""This plugin inserts close directives for all of an account's descendants when +an account is closed. Unopened parent accounts can also be closed. Any +explicitly specified close is left untouched. For example, given this:: 2017-11-10 open Assets:Brokerage:AAPL 2017-11-10 open Assets:Brokerage:ORNG - 2018-11-10 close Assets:Brokerage ; this account does not necessarily need to be opened + 2018-11-10 close Assets:Brokerage ; this does not necessarily need to be opened the plugin turns it into:: @@ -15,18 +15,18 @@ 2018-11-10 close Assets:Brokerage:AAPL 2018-11-10 close Assets:Brokerage:ORNG -Invoke this plugin _after_ any plugins that generate `open` directives for account trees that you -want to auto close. An example is the `auto_accounts` plugin that ships with Beancount:: +Invoke this plugin _after_ any plugins that generate `open` directives for +account trees that you want to auto close. An example is the `auto_accounts` +plugin that ships with Beancount:: plugin "beancount.plugins.auto_accounts" plugin "beancount.plugins.close_tree" - """ from beancount.core import data from beancount.core.data import Open, Close -__plugins__ = ('close_tree',) +__plugins__ = ("close_tree",) def close_tree(entries, unused_options_map): @@ -37,22 +37,28 @@ def close_tree(entries, unused_options_map): unused_options_map: A parser options dict. Returns: A tuple of entries and errors. - """ + """ new_entries = [] errors = [] - opens = set(e.account for e in entries if isinstance(e, Open)) - closes = set(e.account for e in entries if isinstance(e, Close)) + opens = set(entry.account for entry in entries if isinstance(entry, Open)) + closes = set(entry.account for entry in entries if isinstance(entry, Close)) for entry in entries: - if isinstance(entry, Close): - subaccounts = [a for a in opens if a.startswith(entry.account + ':') and a not in closes] + if isinstance(entry, Close): + subaccounts = [ + account + for account in opens + if account.startswith(entry.account + ":") and account not in closes + ] for subacc in subaccounts: - meta = data.new_metadata('', 0) + meta = data.new_metadata("", 0) close_entry = data.Close(meta, entry.date, subacc) new_entries.append(close_entry) - closes.add(subacc) # So we don't attempt to re-close a grandchild that a child closed + closes.add( + subacc + ) # So we don't attempt to re-close a grandchild that a child closed. if entry.account in opens: new_entries.append(entry) else: diff --git a/beancount/prices/sources/coinbase.py b/beancount/prices/sources/coinbase.py index e8265ff2a..b5a4b06ec 100644 --- a/beancount/prices/sources/coinbase.py +++ b/beancount/prices/sources/coinbase.py @@ -32,7 +32,7 @@ def fetch_quote(ticker, time=None): if time is not None: options['date'] = time.astimezone(tz.tzutc()).date().isoformat() - response = requests.get(url, options) + response = requests.get(url, options, timeout=300) if response.status_code != requests.codes.ok: raise CoinbaseError("Invalid response ({}): {}".format(response.status_code, response.text)) diff --git a/beancount/prices/sources/iex.py b/beancount/prices/sources/iex.py index 0256ebc30..ab67d1b45 100644 --- a/beancount/prices/sources/iex.py +++ b/beancount/prices/sources/iex.py @@ -25,7 +25,7 @@ def fetch_quote(ticker): """Fetch the latest price for the given ticker.""" url = "https://api.iextrading.com/1.0/tops/last?symbols={}".format(ticker.upper()) - response = requests.get(url) + response = requests.get(url, timeout=300) if response.status_code != requests.codes.ok: raise IEXError("Invalid response ({}): {}".format( response.status_code, response.text)) diff --git a/beancount/prices/sources/quandl.py b/beancount/prices/sources/quandl.py index 08b72ff66..ffaf8dcc1 100644 --- a/beancount/prices/sources/quandl.py +++ b/beancount/prices/sources/quandl.py @@ -79,7 +79,7 @@ def fetch_time_series(ticker, time=None): payload['api_key'] = os.environ['QUANDL_API_KEY'] # Fetch and process errors. - response = requests.get(url, params=payload) + response = requests.get(url, params=payload, timeout=300) if response.status_code != requests.codes.ok: raise QuandlError("Invalid response ({}): {}".format(response.status_code, response.text)) diff --git a/beancount/prices/sources/tsp.py b/beancount/prices/sources/tsp.py index bf86121b5..a1aab9589 100644 --- a/beancount/prices/sources/tsp.py +++ b/beancount/prices/sources/tsp.py @@ -131,7 +131,7 @@ def get_historical_price(self, fund, time): 'InvFunds' : '1' } - response = requests.get(url, params=payload) + response = requests.get(url, params=payload, timeout=300) result = parse_response(response) trade_day = list(result.items())[0] prices = trade_day[1] diff --git a/beancount/prices/sources/yahoo.py b/beancount/prices/sources/yahoo.py index f38cec827..d3a22f40d 100644 --- a/beancount/prices/sources/yahoo.py +++ b/beancount/prices/sources/yahoo.py @@ -83,7 +83,8 @@ def get_latest_price(self, ticker): 'exchange': 'NYSE', } payload.update(_DEFAULT_PARAMS) - response = requests.get(url, params=payload, headers={'User-Agent': None}) + response = requests.get(url, params=payload, headers={'User-Agent': None}, + timeout=300) result = parse_response(response) try: price = D(result['regularMarketPrice']) @@ -114,7 +115,8 @@ def get_historical_price(self, ticker, time): 'interval': '1d', } payload.update(_DEFAULT_PARAMS) - response = requests.get(url, params=payload, headers={'User-Agent': None}) + response = requests.get(url, params=payload, headers={'User-Agent': None}, + timeout=300) result = parse_response(response) meta = result['meta'] diff --git a/beancount/query/query_env_test.py b/beancount/query/query_env_test.py index ad2f4fc3d..8c2b8dfd0 100644 --- a/beancount/query/query_env_test.py +++ b/beancount/query/query_env_test.py @@ -261,7 +261,8 @@ def test_Date(self, entries, _, options_map): 'SELECT date(year, month, 1) as m') self.assertEqual([(datetime.date(2016, 11, 1),)], rrows) - with self.assertRaisesRegex(ValueError, "day is out of range for month|day must be in"): + with self.assertRaisesRegex(ValueError, + "day is out of range for month|day must be in"): rtypes, rrows = query.run_query(entries, options_map, 'SELECT date(2020, 2, 32) as m') diff --git a/beancount/reports/report.py b/beancount/reports/report.py index 577337216..ff4b0b4d0 100755 --- a/beancount/reports/report.py +++ b/beancount/reports/report.py @@ -213,6 +213,7 @@ def main(argv=None): return is_check = False + outfile = None if hasattr(args, 'report_class'): # Open output file and guess file format. outfile = open(args.output, 'w') if args.output else sys.stdout diff --git a/beancount/tools/treeify.py b/beancount/tools/treeify.py index e90cc8a93..d12dc41a1 100755 --- a/beancount/tools/treeify.py +++ b/beancount/tools/treeify.py @@ -290,9 +290,9 @@ def _main(): args = parser.parse_args() - if sum([1 if expr else 0 for expr in (args.filenames, - args.loose_accounts, - args.pattern)]) > 1: + if sum(1 if expr else 0 for expr in (args.filenames, + args.loose_accounts, + args.pattern)) > 1: parser.error("Conflicted pattern options") if args.pattern is None: diff --git a/beancount/utils/defdict.py b/beancount/utils/defdict.py index d7d73c9c2..ae8e41352 100644 --- a/beancount/utils/defdict.py +++ b/beancount/utils/defdict.py @@ -43,7 +43,7 @@ def __getitem__(self, key): return value def get(self, key, _=None): - return self.__getitem__(key) + return self.__getitem__(key) # pylint: disable=unnecessary-dunder-call # The next three methods are present in order to support pickling. Note that # because this class is a specialization of dict, and that dict has a From 7901c040414b4f5e595b9f3500abd799418fae07 Mon Sep 17 00:00:00 2001 From: blais Date: Sun, 30 Apr 2023 16:27:13 -0400 Subject: [PATCH 02/36] Added config for ruff --- pyproject.toml | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..a1dcac8a5 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,46 @@ +[tool.ruff] +# Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default. +select = ["E", "F", "PL", "PD"] +ignore = [] + +# Allow autofix for all enabled rules (when `--fix`) is provided. +fixable = ["A", "B", "C", "D", "E", "F", "G", "I", "N", "Q", "S", "T", "W", "ANN", "ARG", "BLE", "COM", "DJ", "DTZ", "EM", "ERA", "EXE", "FBT", "ICN", "INP", "ISC", "NPY", "PD", "PGH", "PIE", "PL", "PT", "PTH", "PYI", "RET", "RSE", "RUF", "SIM", "SLF", "TCH", "TID", "TRY", "UP", "YTT"] +unfixable = [] + +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".hg", + ".mypy_cache", + ".nox", + ".pants.d", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "venv", +] +per-file-ignores = {} + +# Same as Black. +line-length = 92 + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +# Assume Python 3.11. +target-version = "py311" + +[tool.ruff.mccabe] +# Unlike Flake8, default to a complexity level of 10. +max-complexity = 10 From 38c2a3d833ed1308926133c749c94fa7e5f7196d Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 14:02:19 +0200 Subject: [PATCH 03/36] Add Meson build definition This aims at replacing setuptools for building Python packages. This does not build the C++ code as it is not used yet. --- meson.build | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 meson.build diff --git a/meson.build b/meson.build new file mode 100644 index 000000000..3c5f129b4 --- /dev/null +++ b/meson.build @@ -0,0 +1,134 @@ +project('beancount', 'c', version: files('beancount/VERSION')) + +py = import('python').find_installation(pure: false) + +py.install_sources( + ''' + beancount/__init__.py + beancount/api.py + beancount/core/__init__.py + beancount/core/account.py + beancount/core/account_types.py + beancount/core/amount.py + beancount/core/compare.py + beancount/core/convert.py + beancount/core/data.py + beancount/core/display_context.py + beancount/core/distribution.py + beancount/core/flags.py + beancount/core/getters.py + beancount/core/interpolate.py + beancount/core/inventory.py + beancount/core/number.py + beancount/core/position.py + beancount/core/prices.py + beancount/core/realization.py + beancount/loader.py + beancount/ops/__init__.py + beancount/ops/balance.py + beancount/ops/basicops.py + beancount/ops/compress.py + beancount/ops/documents.py + beancount/ops/find_prices.py + beancount/ops/lifetimes.py + beancount/ops/pad.py + beancount/ops/summarize.py + beancount/ops/validation.py + beancount/parser/__init__.py + beancount/parser/booking.py + beancount/parser/booking_full.py + beancount/parser/booking_method.py + beancount/parser/cmptest.py + beancount/parser/context.py + beancount/parser/grammar.py + beancount/parser/hashsrc.py + beancount/parser/lexer.py + beancount/parser/options.py + beancount/parser/parser.py + beancount/parser/printer.py + beancount/parser/version.py + beancount/plugins/__init__.py + beancount/plugins/auto.py + beancount/plugins/auto_accounts.py + beancount/plugins/check_average_cost.py + beancount/plugins/check_closing.py + beancount/plugins/check_commodity.py + beancount/plugins/check_drained.py + beancount/plugins/close_tree.py + beancount/plugins/coherent_cost.py + beancount/plugins/commodity_attr.py + beancount/plugins/currency_accounts.py + beancount/plugins/implicit_prices.py + beancount/plugins/leafonly.py + beancount/plugins/noduplicates.py + beancount/plugins/nounused.py + beancount/plugins/onecommodity.py + beancount/plugins/pedantic.py + beancount/plugins/sellgains.py + beancount/plugins/unique_prices.py + beancount/projects/__init__.py + beancount/projects/export.py + beancount/scripts/__init__.py + beancount/scripts/check.py + beancount/scripts/deps.py + beancount/scripts/directories.py + beancount/scripts/doctor.py + beancount/scripts/example.py + beancount/scripts/format.py + beancount/tools/__init__.py + beancount/tools/treeify.py + beancount/utils/__init__.py + beancount/utils/bisect_key.py + beancount/utils/date_utils.py + beancount/utils/defdict.py + beancount/utils/encryption.py + beancount/utils/file_utils.py + beancount/utils/import_utils.py + beancount/utils/invariants.py + beancount/utils/memo.py + beancount/utils/misc_utils.py + beancount/utils/pager.py + beancount/utils/regexp_utils.py + beancount/utils/snoop.py + beancount/utils/table.py + beancount/utils/test_utils.py + '''.split(), + preserve_path: true, +) + +# these are needed only to be able to run hashsrc.py at run time +py.install_sources( + ''' + beancount/parser/lexer.l + beancount/parser/grammar.y + beancount/parser/decimal.h + beancount/parser/decimal.c + beancount/parser/macros.h + beancount/parser/parser.h + beancount/parser/parser.c + beancount/parser/tokens.h + '''.split(), + preserve_path: true, +) + +parser_source_hash = run_command( + [py, '-c', 'from hashsrc import hash_parser_source_files; print(hash_parser_source_files())'], + env: {'PYTHONPATH': '@0@/beancount/parser/'.format(meson.current_source_dir())}, + capture: true, + check: true, +).stdout().strip() + +py.extension_module( + '_parser', + 'beancount/parser/decimal.c', + 'beancount/parser/lexer.c', + 'beancount/parser/grammar.c', + 'beancount/parser/parser.c', + 'beancount/parser/tokens.c', + c_args: [ + '-DPARSER_SOURCE_HASH="@0@"'.format(parser_source_hash), + '-DBEANCOUNT_VERSION="@0@"'.format(meson.project_version()), + ], + install: true, + subdir: 'beancount/parser', +) From b5b0dbd22b1d3811d41c05e2ecdb8ff5877d331b Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 14:04:47 +0200 Subject: [PATCH 04/36] Switch packaging to use meson-python via pyproject.toml The setuptools based setup.py build definition is not removed but will not be used by default by build tools. --- pyproject.toml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..fd45b9aac --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,32 @@ +[build-system] +build-backend = "mesonpy" +requires = [ + "meson-python >= 0.14.0", + "meson >= 1.2.1", +] + +[project] +name = "beancount" +description = "Command-line Double-Entry Accounting" +readme = "README.rst" +authors = [ + { name = "Martin Blais", email = "blais@furius.ca" }, +] +requires-python = ">=3.7" +classifiers = [] +# entr_points={ +# "console_scripts": [ +# "bean-check = beancount.scripts.check:main", +# "bean-doctor = beancount.scripts.doctor:main", +# "bean-example = beancount.scripts.example:main", +# "bean-format = beancount.scripts.format:main", +# "treeify = beancount.tools.treeify:main", +# ] +# }, +# ] +dependencies = [ + "click", + "pytest", + "python-dateutil", +] +dynamic = ["version"] From 59d4cc2c322bd250d4680b2ef5d2793ccac23b0a Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 14:58:20 +0200 Subject: [PATCH 05/36] Build Python wheels in CI --- .github/workflows/wheels.yaml | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .github/workflows/wheels.yaml diff --git a/.github/workflows/wheels.yaml b/.github/workflows/wheels.yaml new file mode 100644 index 000000000..3b3b24c1a --- /dev/null +++ b/.github/workflows/wheels.yaml @@ -0,0 +1,53 @@ +name: build +on: + push: + pull_request: + workflow_dispatch: + +jobs: + + wheels: + runs-on: ${{ matrix.os }}-latest + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu + - os: macos + - os: windows + architecture: AMD64 + - os: windows + architecture: x86 + steps: + - uses: actions/checkout@v3 + - uses: docker/setup-qemu-action@v2 + with: + platforms: arm64 + if: runner.os == 'Linux' + - uses: bus1/cabuild/action/msdevshell@v1 + with: + architecture: x64 + if: runner.os == 'Windows' && matrix.architecture == 'AMD64' + - uses: bus1/cabuild/action/msdevshell@v1 + with: + architecture: x86 + if: runner.os == 'Windows' && matrix.architecture == 'x86' + - run: pipx run cibuildwheel==2.15.0 + env: + CIBW_SKIP: pp* cp36-* cp37-* *-musllinux* + CIBW_ARCHS_MACOS: x86_64 arm64 + CIBW_ARCHS_LINUX: x86_64 aarch64 + CIBW_ARCHS_WINDOWS: ${{ matrix.architecture }} + - uses: actions/upload-artifact@v3 + with: + path: wheelhouse/*.whl + + sdist: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: python -m pip install build + - run: python -m build --sdist + - uses: actions/upload-artifact@v3 + with: + path: dist/*.tar.gz From 8b1a6fe083cb0752c956dd9f104edbb497af640e Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 15:03:46 +0200 Subject: [PATCH 06/36] Modernize CI job --- .github/workflows/install.yaml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/.github/workflows/install.yaml b/.github/workflows/install.yaml index efba5b918..7f1330a7f 100644 --- a/.github/workflows/install.yaml +++ b/.github/workflows/install.yaml @@ -4,6 +4,20 @@ on: - pull_request jobs: install-from-sources: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + # The oldest supported python version + python-version: 3.7 + - run: python -m pip install . + - run: | + bean-check --help + bean-doctor --help + bean-example --help + bean-format --help + install-from-sources-oldstyle: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -25,8 +39,9 @@ jobs: with: # The oldest supported python version python-version: 3.7 - - run: python setup.py sdist --format zip - - run: pip install dist/beancount-*.zip + - rum: python -m pip install build + - run: python -m build --sdist + - run: python -m pip install dist/beancount-*.zip - run: | bean-check --help bean-doctor --help From cce8b09a4275f0d450557dc9c59a9d75b8f5c55c Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 15:27:19 +0200 Subject: [PATCH 07/36] Modernize CI job running tests --- .github/workflows/linux-ci.yaml | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/workflows/linux-ci.yaml b/.github/workflows/linux-ci.yaml index a60f8d011..856dd9379 100644 --- a/.github/workflows/linux-ci.yaml +++ b/.github/workflows/linux-ci.yaml @@ -8,19 +8,17 @@ jobs: strategy: fail-fast: false matrix: - python: ['3.7', '3.8', '3.9', '3.10', '3.11'] + python: + - '3.7' + - '3.8' + - '3.9' + - '3.10' + - '3.11' steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} - - run: pip install -r requirements/dev.txt - - run: python setup.py build_ext -i - - run: make ctest - env: - LD_LIBRARY_PATH: ${{ env.pythonLocation }}/lib - # The Makefile does not handle older python-config versions. - # These tests are however about the pure C code, thus there is - # little value in running them for different Python version. - if: ${{ matrix.python == '3.9' }} - - run: make test + - run: python -m pip install pytest + - run: python -m pip install . -Cbuilddir=build || cat build/meson-logs/meson-log.txt + - run: python -m pytest beancount From f3413609c76b70a6503be032471478729ccbca5b Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 16:00:59 +0200 Subject: [PATCH 08/36] Fix meson.build --- meson.build | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 3c5f129b4..69742df36 100644 --- a/meson.build +++ b/meson.build @@ -5,6 +5,7 @@ py = import('python').find_installation(pure: false) py.install_sources( ''' beancount/__init__.py + beancount/VERSION beancount/api.py beancount/core/__init__.py beancount/core/account.py @@ -118,6 +119,16 @@ parser_source_hash = run_command( check: true, ).stdout().strip() +add_project_arguments( + '-DPARSER_SOURCE_HASH=@0@'.format(parser_source_hash), + '-DBEANCOUNT_VERSION=@0@'.format(meson.project_version()), + language: 'c', +) + +if host_machine.system() == 'windows' + add_project_arguments('-DYY_NO_UNISTD_H', language: 'c') +endif + py.extension_module( '_parser', 'beancount/parser/decimal.c', @@ -125,10 +136,6 @@ py.extension_module( 'beancount/parser/grammar.c', 'beancount/parser/parser.c', 'beancount/parser/tokens.c', - c_args: [ - '-DPARSER_SOURCE_HASH="@0@"'.format(parser_source_hash), - '-DBEANCOUNT_VERSION="@0@"'.format(meson.project_version()), - ], install: true, subdir: 'beancount/parser', ) From d19fa8e2dcd22b2d5c4656abb40335031b51daa6 Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 17:15:39 +0200 Subject: [PATCH 09/36] Rewrite parser test to do not spawn another interpreter --- beancount/parser/parser_test.py | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/beancount/parser/parser_test.py b/beancount/parser/parser_test.py index 7894f1d74..1758bf61f 100644 --- a/beancount/parser/parser_test.py +++ b/beancount/parser/parser_test.py @@ -97,21 +97,15 @@ def test_parse_file(self): self.assertEqual(1, len(entries)) self.assertEqual(0, len(errors)) - @classmethod - def parse_stdin(cls): - entries, errors, _ = parser.parse_file("-") - assert entries, "Empty entries: {}".format(entries) - assert not errors, "Errors: {}".format(errors) - def test_parse_stdin(self): - env = test_utils.subprocess_env() if 'bazel' not in __file__ else None - code = ('import beancount.parser.parser_test as p; ' - 'p.TestParserInputs.parse_stdin()') - pipe = subprocess.Popen([sys.executable, '-c', code, __file__], - env=env, - stdin=subprocess.PIPE) - output, errors = pipe.communicate(self.INPUT.encode('utf-8')) - self.assertEqual(0, pipe.returncode) + try: + stdin = sys.stdin + sys.stdin = io.TextIOWrapper(io.BytesIO(self.INPUT.encode('utf-8'))) + entries, errors, _ = parser.parse_file("-") + self.assertEqual(1, len(entries)) + self.assertEqual(0, len(errors)) + finally: + sys.stdin = stdin def test_parse_None(self): # None is treated as the empty string... From 7f59dc4b5c973ab8351e5bbeb3ac6e61767ed21d Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 17:18:59 +0200 Subject: [PATCH 10/36] Move encryption test to avoid importing test module --- beancount/loader_test.py | 31 ------------------------------ beancount/utils/encryption_test.py | 31 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/beancount/loader_test.py b/beancount/loader_test.py index d3531d63a..4a3a77000 100644 --- a/beancount/loader_test.py +++ b/beancount/loader_test.py @@ -14,7 +14,6 @@ from beancount import loader from beancount.parser import parser from beancount.utils import test_utils -from beancount.utils import encryption_test TEST_INPUT = """ @@ -362,36 +361,6 @@ def test_load_file_return_include_filenames(self): list(map(path.basename, options_map['include']))) -class TestLoadIncludesEncrypted(encryption_test.TestEncryptedBase): - - def test_include_encrypted(self): - with test_utils.tempdir() as tmpdir: - test_utils.create_temporary_files(tmpdir, { - 'apples.beancount': """ - include "oranges.beancount.asc" - 2014-01-01 open Assets:Apples - """, - 'oranges.beancount': """ - 2014-01-02 open Assets:Oranges - """}) - - # Encrypt the oranges file and remove the unencrypted file. - with open(path.join(tmpdir, 'oranges.beancount')) as infile: - self.encrypt_as_file(infile.read(), - path.join(tmpdir, 'oranges.beancount.asc')) - os.remove(path.join(tmpdir, 'oranges.beancount')) - - # Load the top-level file which includes the encrypted file. - with test_utils.environ('GNUPGHOME', self.ringdir): - entries, errors, options_map = loader.load_file( - path.join(tmpdir, 'apples.beancount')) - - self.assertFalse(errors) - self.assertEqual(2, len(entries)) - self.assertTrue(entries[0].meta['filename'].endswith('/apples.beancount')) - self.assertTrue(entries[1].meta['filename'].endswith('/oranges.beancount.asc')) - - class TestLoadCache(unittest.TestCase): def setUp(self): diff --git a/beancount/utils/encryption_test.py b/beancount/utils/encryption_test.py index 5409ca019..e37198b6d 100644 --- a/beancount/utils/encryption_test.py +++ b/beancount/utils/encryption_test.py @@ -7,6 +7,7 @@ import tempfile from os import path +from beancount import loader from beancount.utils import encryption from beancount.utils import test_utils @@ -165,5 +166,35 @@ def test_is_encrypted_file(self): self.assertTrue(encryption.is_encrypted_file(file.name)) +class TestLoadIncludesEncrypted(TestEncryptedBase): + + def test_include_encrypted(self): + with test_utils.tempdir() as tmpdir: + test_utils.create_temporary_files(tmpdir, { + 'apples.beancount': """ + include "oranges.beancount.asc" + 2014-01-01 open Assets:Apples + """, + 'oranges.beancount': """ + 2014-01-02 open Assets:Oranges + """}) + + # Encrypt the oranges file and remove the unencrypted file. + with open(path.join(tmpdir, 'oranges.beancount')) as infile: + self.encrypt_as_file(infile.read(), + path.join(tmpdir, 'oranges.beancount.asc')) + os.remove(path.join(tmpdir, 'oranges.beancount')) + + # Load the top-level file which includes the encrypted file. + with test_utils.environ('GNUPGHOME', self.ringdir): + entries, errors, options_map = loader.load_file( + path.join(tmpdir, 'apples.beancount')) + + self.assertFalse(errors) + self.assertEqual(2, len(entries)) + self.assertTrue(entries[0].meta['filename'].endswith('/apples.beancount')) + self.assertTrue(entries[1].meta['filename'].endswith('/oranges.beancount.asc')) + + if __name__ == '__main__': unittest.main() From d4a7381dc4f53c4ba5d1d55a22ccb6991506ca1d Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 17:21:58 +0200 Subject: [PATCH 11/36] Do not try to import C++ parser --- beancount/__init__.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/beancount/__init__.py b/beancount/__init__.py index 6e5cb9caa..ba0bbf8ea 100644 --- a/beancount/__init__.py +++ b/beancount/__init__.py @@ -16,16 +16,7 @@ __version__ = version_file.read().strip() -# Import v3 extension module. -import warnings -try: - from beancount.cparser import extmodule - parse = extmodule.parse -except ImportError: - warnings.warn("Unable to import v3 extension module.") - # Expose the public API. del path del sys -del warnings from .api import * # pylint: disable=wildcard-import From 6d08da1625c42f65b9584a7089412bbd41804099 Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 17:22:54 +0200 Subject: [PATCH 12/36] Fix CI test runner --- .github/workflows/linux-ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/linux-ci.yaml b/.github/workflows/linux-ci.yaml index 856dd9379..5515f1825 100644 --- a/.github/workflows/linux-ci.yaml +++ b/.github/workflows/linux-ci.yaml @@ -20,5 +20,5 @@ jobs: with: python-version: ${{ matrix.python }} - run: python -m pip install pytest - - run: python -m pip install . -Cbuilddir=build || cat build/meson-logs/meson-log.txt - - run: python -m pytest beancount + - run: python -m pip install . + - run: pytest --import-mode=importlib beancount From 47ec368eb8ed1ca72dc0e7d11274677657da5b83 Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 17:25:55 +0200 Subject: [PATCH 13/36] Consolidate CI test jobs Build and run tests on macOS in addition to Linux. Build on Windows. Running the tests on Windows would require removing assumptions based on running on an UNIX system from the tests. fixup --- .github/workflows/{linux-ci.yaml => tests.yaml} | 11 ++++++++--- .github/workflows/windows-ci.yaml | 16 ---------------- 2 files changed, 8 insertions(+), 19 deletions(-) rename .github/workflows/{linux-ci.yaml => tests.yaml} (67%) delete mode 100644 .github/workflows/windows-ci.yaml diff --git a/.github/workflows/linux-ci.yaml b/.github/workflows/tests.yaml similarity index 67% rename from .github/workflows/linux-ci.yaml rename to .github/workflows/tests.yaml index 5515f1825..523f78526 100644 --- a/.github/workflows/linux-ci.yaml +++ b/.github/workflows/tests.yaml @@ -1,13 +1,17 @@ -name: linux-ci +name: tests on: - push - pull_request jobs: test: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }}-latest strategy: fail-fast: false matrix: + os: + - ubuntu + - windows + - macos python: - '3.7' - '3.8' @@ -20,5 +24,6 @@ jobs: with: python-version: ${{ matrix.python }} - run: python -m pip install pytest - - run: python -m pip install . + - run: python -m pip install . -Csetup-args=--vsenv - run: pytest --import-mode=importlib beancount + if: runner.os != 'Windows' diff --git a/.github/workflows/windows-ci.yaml b/.github/workflows/windows-ci.yaml deleted file mode 100644 index ef6ad650a..000000000 --- a/.github/workflows/windows-ci.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: windows-ci -on: - - push - - pull_request -jobs: - compile: - runs-on: windows-latest - strategy: - matrix: - python: ['3.7', '3.8', '3.9', '3.10', '3.11'] - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python }} - - run: python setup.py build_ext From f93c2afe7a31ec62d3d7fcc27f8fb5f20e4d33f7 Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 18:05:48 +0200 Subject: [PATCH 14/36] Fix pylint errors --- beancount/loader_test.py | 4 ++-- beancount/parser/parser_test.py | 4 +--- beancount/plugins/close_tree.py | 17 ++++++++++------- tools/benchmark.py | 2 +- tools/update_options.py | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/beancount/loader_test.py b/beancount/loader_test.py index 4a3a77000..3b973b485 100644 --- a/beancount/loader_test.py +++ b/beancount/loader_test.py @@ -506,8 +506,8 @@ def test_load_cache_override_filename_pattern_by_argument(self): def test_load_cache_disable(self): with test_utils.tempdir() as tmp: cache_filename = path.join(tmp, "__{filename}__") - for kwargs in [dict(use_cache=False), - dict(use_cache=False, cache_filename=cache_filename)]: + for kwargs in [{'use_cache': False}, + {'use_cache': False, 'cache_filename': cache_filename}]: loader.initialize(**kwargs) test_utils.create_temporary_files(tmp, { 'apples.beancount': """ diff --git a/beancount/parser/parser_test.py b/beancount/parser/parser_test.py index 1758bf61f..cd20309eb 100644 --- a/beancount/parser/parser_test.py +++ b/beancount/parser/parser_test.py @@ -9,12 +9,10 @@ import tempfile import textwrap import sys -import subprocess from beancount.core.number import D from beancount.core import data from beancount.parser import parser, _parser, lexer, grammar -from beancount.utils import test_utils class TestCompareTestFunctions(unittest.TestCase): @@ -98,8 +96,8 @@ def test_parse_file(self): self.assertEqual(0, len(errors)) def test_parse_stdin(self): + stdin = sys.stdin try: - stdin = sys.stdin sys.stdin = io.TextIOWrapper(io.BytesIO(self.INPUT.encode('utf-8'))) entries, errors, _ = parser.parse_file("-") self.assertEqual(1, len(entries)) diff --git a/beancount/plugins/close_tree.py b/beancount/plugins/close_tree.py index 7d4d6a4af..8f3f86d00 100644 --- a/beancount/plugins/close_tree.py +++ b/beancount/plugins/close_tree.py @@ -1,6 +1,6 @@ -"""This plugin inserts close directives for all of an account's descendants when an account is -closed. Unopened parent accounts can also be closed. Any explicitly specified close is left -untouched. +"""This plugin inserts close directives for all of an account's descendants when an account +is closed. Unopened parent accounts can also be closed. Any explicitly specified close is +left untouched. For example, given this:: @@ -15,8 +15,9 @@ 2018-11-10 close Assets:Brokerage:AAPL 2018-11-10 close Assets:Brokerage:ORNG -Invoke this plugin _after_ any plugins that generate `open` directives for account trees that you -want to auto close. An example is the `auto_accounts` plugin that ships with Beancount:: +Invoke this plugin _after_ any plugins that generate `open` directives for account trees +that you want to auto close. An example is the `auto_accounts` plugin that ships with +Beancount:: plugin "beancount.plugins.auto_accounts" plugin "beancount.plugins.close_tree" @@ -47,12 +48,14 @@ def close_tree(entries, unused_options_map): for entry in entries: if isinstance(entry, Close): - subaccounts = [a for a in opens if a.startswith(entry.account + ':') and a not in closes] + subaccounts = [a for a in opens + if a.startswith(entry.account + ':') and a not in closes] for subacc in subaccounts: meta = data.new_metadata('', 0) close_entry = data.Close(meta, entry.date, subacc) new_entries.append(close_entry) - closes.add(subacc) # So we don't attempt to re-close a grandchild that a child closed + # So we don't attempt to re-close a grandchild that a child closed + closes.add(subacc) if entry.account in opens: new_entries.append(entry) else: diff --git a/tools/benchmark.py b/tools/benchmark.py index 303512618..13efdfb05 100755 --- a/tools/benchmark.py +++ b/tools/benchmark.py @@ -19,7 +19,7 @@ def prevent_run_with_changes(): def benchmark_revision(beancount_file: str, revision: str): """Run the benchmark on a particular revision.""" - args = dict(shell=False, stdout=subprocess.PIPE) + args = {'shell': False, 'stdout': subprocess.PIPE} # Clean up local files. WARNING. subprocess.check_call(["make", "clean"], **args) diff --git a/tools/update_options.py b/tools/update_options.py index 4c80457d8..291c45c30 100755 --- a/tools/update_options.py +++ b/tools/update_options.py @@ -36,7 +36,7 @@ def replace_gdocs_document(http, docid, title, contents): resumable=True) return service.files().update( fileId=docid, - body=dict(name=title), + body={'name': title}, media_body=media).execute() From 02e6128213576df8f501604b5f5b426ad67ac595 Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 18:22:53 +0200 Subject: [PATCH 15/36] Test with Python 3.12 too in CI --- .github/workflows/tests.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 523f78526..7ec98b642 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -18,11 +18,13 @@ jobs: - '3.9' - '3.10' - '3.11' + - '3.12' steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} + allow-prereleases: true - run: python -m pip install pytest - run: python -m pip install . -Csetup-args=--vsenv - run: pytest --import-mode=importlib beancount From 71f656d3879d56989e2234c25fbd3712b6eec59a Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 18:21:52 +0200 Subject: [PATCH 16/36] Fix install CI jobs --- .github/workflows/install.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/install.yaml b/.github/workflows/install.yaml index 7f1330a7f..eea1118a8 100644 --- a/.github/workflows/install.yaml +++ b/.github/workflows/install.yaml @@ -39,9 +39,9 @@ jobs: with: # The oldest supported python version python-version: 3.7 - - rum: python -m pip install build + - run: python -m pip install build - run: python -m build --sdist - - run: python -m pip install dist/beancount-*.zip + - run: python -m pip install dist/beancount-*.tar.gz - run: | bean-check --help bean-doctor --help From 6a5458175e3734ac63a9976a6852997d238346e6 Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 19:04:56 +0200 Subject: [PATCH 17/36] Drop dependency on pytest It is not a runtime dependency. It is used only to run the tests. --- pyproject.toml | 1 - setup.py | 17 +++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index fd45b9aac..eb9028335 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,6 @@ classifiers = [] # ] dependencies = [ "click", - "pytest", "python-dateutil", ] dynamic = ["version"] diff --git a/setup.py b/setup.py index 57cdf0e03..e0b244ece 100755 --- a/setup.py +++ b/setup.py @@ -86,15 +86,6 @@ def get_git_changeset(): install_requires = [ - # Testing support now uses the pytest module. - "pytest", - # - # Command line parsing. - "click", - # - # We use dateutil for timezone database definitions. See this - # article for context: https://assert.cc/posts/dateutil-preferred/ - "python-dateutil", ] # Create a setup. @@ -145,7 +136,13 @@ def get_git_changeset(): extra_compile_args=get_cflags(), ), ], - install_requires=install_requires, + install_requires=[ + # Command line parsing. + "click", + # We use dateutil for timezone database definitions. See this + # article for context: https://assert.cc/posts/dateutil-preferred/ + "python-dateutil", + ], entry_points={ "console_scripts": [ "bean-check = beancount.scripts.check:main", From 6948aa9b77b9d6f24e79ef2130d0559b69cc7372 Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 19:06:02 +0200 Subject: [PATCH 18/36] Complete pyproject.toml --- pyproject.toml | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index eb9028335..2184316dd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,24 +8,36 @@ requires = [ [project] name = "beancount" description = "Command-line Double-Entry Accounting" -readme = "README.rst" +readme = { content-type = "text/x-rst", text = """ +A double-entry accounting system that uses text files as input. + +Beancount defines a simple data format or "language" that lets you +define financial transaction records in a text file, load them in +memory and generate and export a variety of reports, such as balance +sheets or income statements. It also provides a client with an +SQL-like query language to filter and aggregate financial data, and a +web interface which renders those reports to HTML. Finally, it +provides the scaffolding required to automate the conversion of +external data into one's input file in Beancount syntax.""" } authors = [ { name = "Martin Blais", email = "blais@furius.ca" }, ] +license = { text = "GPL-2.0-only" } requires-python = ">=3.7" -classifiers = [] -# entr_points={ -# "console_scripts": [ -# "bean-check = beancount.scripts.check:main", -# "bean-doctor = beancount.scripts.doctor:main", -# "bean-example = beancount.scripts.example:main", -# "bean-format = beancount.scripts.format:main", -# "treeify = beancount.tools.treeify:main", -# ] -# }, -# ] dependencies = [ "click", "python-dateutil", ] dynamic = ["version"] + +[project.scripts] +bean-check = "beancount.scripts.check:main" +bean-doctor = "beancount.scripts.doctor:main" +bean-example = "beancount.scripts.example:main" +bean-format = "beancount.scripts.format:main" +treeify = "beancount.tools.treeify:main" + +[project.urls] +homepage = "https://beancount.github.io/" +documentation = "https://beancount.github.io/docs/" +repository = "https://github.com/beancount/beancount" From d5923d25206b569c678f4bc664468769084dd866 Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 19:58:28 +0200 Subject: [PATCH 19/36] Fix Python 3.12 compatibility I am not completely sure that the UnboundLocalError emitted by Python 3.12 is correct, but eliminating the roundabout way used to access the Balance class makes sense on its own. --- beancount/ops/summarize.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/beancount/ops/summarize.py b/beancount/ops/summarize.py index 219333e58..307a93a9c 100644 --- a/beancount/ops/summarize.py +++ b/beancount/ops/summarize.py @@ -25,7 +25,6 @@ from beancount.core import interpolate from beancount.core import convert from beancount.core import prices -from beancount.ops import balance from beancount.utils import bisect_key from beancount.parser import options @@ -404,7 +403,7 @@ def transfer_balances(entries, date, account_pred, transfer_account): # has been transferred away; they would break. after_entries = [entry for entry in entries[index:] - if not (isinstance(entry, balance.Balance) and + if not (isinstance(entry, data.Balance) and entry.account in transfer_balances)] # Split the new entries in a new list. From e4587b55d9a5431765be24fdfd116ac4fabd6dc7 Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 20:16:50 +0200 Subject: [PATCH 20/36] Remove PKG-INFO from repository --- PKG-INFO | 8 -------- beancount/utils/test_utils.py | 3 +-- 2 files changed, 1 insertion(+), 10 deletions(-) delete mode 100644 PKG-INFO diff --git a/PKG-INFO b/PKG-INFO deleted file mode 100644 index 9fb67c2be..000000000 --- a/PKG-INFO +++ /dev/null @@ -1,8 +0,0 @@ -Description: Command-line Double-Entry Accounting -Official-Homepage: http://furius.ca/beancount -Author: Martin Blais -Author-Email: blais@furius.ca -ChangeLog: http://furius.ca/beancount/CHANGES -Bugs-Reporting: mailto:blais@furius.ca -Download-Snapshots: https://github.com/beancount/beancount -License: GNU GPLv2 only diff --git a/beancount/utils/test_utils.py b/beancount/utils/test_utils.py index f50290ab4..99b027d59 100644 --- a/beancount/utils/test_utils.py +++ b/beancount/utils/test_utils.py @@ -43,8 +43,7 @@ def find_repository_root(filename=None): if match: return match.group(1) - while not all(path.exists(path.join(filename, sigfile)) - for sigfile in ('PKG-INFO', 'COPYING')): + while not path.exists(path.join(filename, 'pyproject.toml')): prev_filename = filename filename = path.dirname(filename) if prev_filename == filename: From efb4f76ed05b7dfeb1ab67acf9f7617316630924 Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Sun, 17 Sep 2023 23:31:53 +0200 Subject: [PATCH 21/36] Add uploading of wheel and sdist to PyPI on pushing a tag Build wheels and sdist only when a tag is pushed. Consolidate the old workflow into the new. --- .github/workflows/pypi-wheel.yaml | 45 ------------------------------- .github/workflows/wheels.yaml | 18 +++++++++++-- 2 files changed, 16 insertions(+), 47 deletions(-) delete mode 100644 .github/workflows/pypi-wheel.yaml diff --git a/.github/workflows/pypi-wheel.yaml b/.github/workflows/pypi-wheel.yaml deleted file mode 100644 index 33025b751..000000000 --- a/.github/workflows/pypi-wheel.yaml +++ /dev/null @@ -1,45 +0,0 @@ -name: upload-wheel -on: - push: - tags: - - '2.[0-9]+.[0-9]+' - workflow_dispatch: - inputs: - tag: - required: true - description: 'Release tag' -jobs: - build-and-upload: - runs-on: ${{ matrix.os }}-latest - strategy: - fail-fast: false - matrix: - python: ['3.7', '3.8', '3.9', '3.10', '3.11'] - os: [windows, macos] - env: - # The newly pushed tag or the tag specified in the workflow dispatch. - TAG: ${{ github.event.push.tag || github.event.inputs.tag }} - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ env.TAG }} - - run: git describe --tags - - run: | - # Check that release tag and package version agree. - import os, sys - tag = os.getenv('TAG') - print(f'git tag: {tag}') - version = open('beancount/VERSION').read().strip() - print(f'package version: {version}') - if tag != version: - sys.exit(1) - shell: python - - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python }} - - run: python -m pip install wheel twine - - run: python setup.py bdist_wheel - - run: twine upload dist/beancount-$TAG-*.whl - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} diff --git a/.github/workflows/wheels.yaml b/.github/workflows/wheels.yaml index 3b3b24c1a..b784bca10 100644 --- a/.github/workflows/wheels.yaml +++ b/.github/workflows/wheels.yaml @@ -1,8 +1,7 @@ name: build on: push: - pull_request: - workflow_dispatch: + tags: '*' jobs: @@ -51,3 +50,18 @@ jobs: - uses: actions/upload-artifact@v3 with: path: dist/*.tar.gz + + upload: + needs: + - wheels + - sdist + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v3 + with: + path: dist + - run: python -m pip install twine + - run: python -m twine upload dist/* + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI }} From fdde5e4455cadd119515f4234cd0073aa5475a8e Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Mon, 18 Sep 2023 09:01:09 +0200 Subject: [PATCH 22/36] Remove unused utility code and clarify dependency on python-dateutil beancount.utils.date_utils.parse_date_liberally() is not used in the codebase. The only user was beanquery, which does not use this function anymore. Clarify the reason for the dependency on python-dateutil. --- beancount/utils/date_utils.py | 20 -------------------- beancount/utils/date_utils_test.py | 18 ------------------ setup.py | 3 +-- 3 files changed, 1 insertion(+), 40 deletions(-) diff --git a/beancount/utils/date_utils.py b/beancount/utils/date_utils.py index f208666a9..0af36c58b 100644 --- a/beancount/utils/date_utils.py +++ b/beancount/utils/date_utils.py @@ -8,8 +8,6 @@ import os import time -import dateutil.parser - def iter_dates(start_date, end_date): """Yield all the dates between 'start_date' and 'end_date'. @@ -27,24 +25,6 @@ def iter_dates(start_date, end_date): date += oneday -def parse_date_liberally(string, parse_kwargs_dict=None): - """Parse arbitrary strings to dates. - - This function is intended to support liberal inputs, so that we can use it - in accepting user-specified dates on command-line scripts. - - Args: - string: A string to parse. - parse_kwargs_dict: Dict of kwargs to pass to dateutil parser. - Returns: - A datetime.date object. - """ - # At the moment, rely on the most excellent dateutil. - if parse_kwargs_dict is None: - parse_kwargs_dict = {} - return dateutil.parser.parse(string, **parse_kwargs_dict).date() - - def render_ofx_date(dtime): """Render a datetime to the OFX format. diff --git a/beancount/utils/date_utils_test.py b/beancount/utils/date_utils_test.py index 07035f46a..df91fd2af 100644 --- a/beancount/utils/date_utils_test.py +++ b/beancount/utils/date_utils_test.py @@ -18,24 +18,6 @@ def test_iter_dates(self): list(date_utils.iter_dates(date1, date2))) self.assertEqual([], list(date_utils.iter_dates(date2, date1))) - def test_parse_date_liberally(self): - const_date = datetime.date(2014, 12, 7) - test_cases = ( - ('12/7/2014',), - ('7-Dec-2014',), - ('7/12/2014', {'parserinfo': dateutil.parser.parserinfo(dayfirst=True)}), - ('12/7', {'default': datetime.datetime(2014, 1, 1)}), - ('7.12.2014', {'dayfirst': True}), - ('14 12 7', {'yearfirst': True}), - ('Transaction of 7th December 2014', {'fuzzy': True}), - ) - for case in test_cases: - if len(case) == 2: - parse_date = date_utils.parse_date_liberally(case[0], case[1]) - else: - parse_date = date_utils.parse_date_liberally(case[0]) - self.assertEqual(const_date, parse_date) - def test_next_month(self): self.assertEqual(datetime.date(2015, 11, 1), date_utils.next_month(datetime.date(2015, 10, 1))) diff --git a/setup.py b/setup.py index e0b244ece..4562f5862 100755 --- a/setup.py +++ b/setup.py @@ -139,8 +139,7 @@ def get_git_changeset(): install_requires=[ # Command line parsing. "click", - # We use dateutil for timezone database definitions. See this - # article for context: https://assert.cc/posts/dateutil-preferred/ + # Used to generate recurring events in beancounr.scripts.example. "python-dateutil", ], entry_points={ From a91c854ea148cda36eb9ea9e8a82f0cc75d40651 Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Mon, 18 Sep 2023 09:23:09 +0200 Subject: [PATCH 23/36] Add versions requirements to pyproject.toml --- beancount/utils/date_utils_test.py | 1 - pyproject.toml | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/beancount/utils/date_utils_test.py b/beancount/utils/date_utils_test.py index df91fd2af..dffe6e3dc 100644 --- a/beancount/utils/date_utils_test.py +++ b/beancount/utils/date_utils_test.py @@ -3,7 +3,6 @@ import unittest import datetime -import dateutil from beancount.utils import date_utils diff --git a/pyproject.toml b/pyproject.toml index 2184316dd..0b9fdde31 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,8 +25,8 @@ authors = [ license = { text = "GPL-2.0-only" } requires-python = ">=3.7" dependencies = [ - "click", - "python-dateutil", + "click >=7.0", + "python-dateutil >=2.6.0", ] dynamic = ["version"] From 5369ad6937f723b78006d0410b9c14b6246d11a0 Mon Sep 17 00:00:00 2001 From: Filip Filmar Date: Tue, 25 Jul 2023 08:08:18 +0000 Subject: [PATCH 24/36] Adds a hermetic setup for python 3.10 This allows downloading and compiling beancount latest without any special python package installation. Hopefully that's something that we want to have. --- WORKSPACE | 45 +++- beancount/scripts/BUILD | 2 + beancount/utils/BUILD | 5 + experiments/v3/pbpb/BUILD | 2 + experiments/v3/protos/BUILD | 4 +- requirements/BUILD.bazel | 22 ++ requirements/dev_lock.txt | 495 ++++++++++++++++++++++++++++++++++++ requirements/tools_lock.txt | 312 +++++++++++++++++++++++ 8 files changed, 883 insertions(+), 4 deletions(-) create mode 100644 requirements/BUILD.bazel create mode 100644 requirements/dev_lock.txt create mode 100644 requirements/tools_lock.txt diff --git a/WORKSPACE b/WORKSPACE index c1cb04564..ea3c6e6b1 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -2,7 +2,7 @@ Note that: -- This is using a local Python runtime, which must be 3.10 +- This is using a hermetic Python runtime, which must be 3.10. - The pip package for 'protobuf' version *must* match that which is in use in this build. - Your version of Bazel installed must match that which is used in the github @@ -11,6 +11,46 @@ Note that: """ workspace(name="beancount") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +rules_python_version = "93f5ea2f01ce7eb870d3ad3943eda5d354cdaac5" + +http_archive( + name = "rules_python", + strip_prefix = "rules_python-{}".format(rules_python_version), + url = "https://github.com/bazelbuild/rules_python/archive/{}.zip".format(rules_python_version), + sha256 = "179541b519e8fd7c8fbfd0d2a2a51835cf7c83bd6a8f0f3fd599a0910d1a0981" +) + +load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains") + +py_repositories() + +python_register_toolchains( + name = "python3_10", + python_version = "3.10", +) + +load("@python3_10//:defs.bzl", "interpreter") + +load("@rules_python//python:pip.bzl", "pip_parse") + +pip_parse( + name = "pypi", + requirements_lock = "//requirements:dev_lock.txt", + python_interpreter_target = interpreter, +) + +load("@pypi//:requirements.bzl", "install_deps") + +install_deps() + +pip_parse( + name = "pypi_tools", + requirements_lock = "//requirements:tools_lock.txt", + python_interpreter_target = interpreter, +) + #------------------------------------------------------------------------------ # Direct dependencies of Beancount. # @@ -20,7 +60,6 @@ workspace(name="beancount") # all the related files. We use maybe_http_archive() throughout. # Allow an external python_configure() definition to be pulled from pybind11_bael. -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "pybind11_bazel", url = "https://github.com/pybind/pybind11_bazel/archive/faf56fb3df11287f26dbc66fdedf60a2fc2c6631.zip", @@ -29,7 +68,7 @@ http_archive( ) # updated = "2022-11-03", load("@pybind11_bazel//:python_configure.bzl", "python_configure") -python_configure(name = "local_config_python") +python_configure(name = "local_config_python", python_interpreter_target = interpreter) bind( name = "python_headers", actual = "@local_config_python//:python_headers", diff --git a/beancount/scripts/BUILD b/beancount/scripts/BUILD index 595530d27..e060c2083 100644 --- a/beancount/scripts/BUILD +++ b/beancount/scripts/BUILD @@ -1,3 +1,4 @@ +load("@pypi//:requirements.bzl", "requirement") package(default_visibility = ["//visibility:public"]) py_test( @@ -125,6 +126,7 @@ py_test( "//beancount/scripts:example", "//beancount/utils:test_utils", "//beancount:plugins_for_tests", + requirement("python-dateutil"), ], ) diff --git a/beancount/utils/BUILD b/beancount/utils/BUILD index 713308322..93579436e 100644 --- a/beancount/utils/BUILD +++ b/beancount/utils/BUILD @@ -1,3 +1,7 @@ +load( + "@pypi//:requirements.bzl", + "requirement", +) package(default_visibility = ["//visibility:public"]) py_library( @@ -22,6 +26,7 @@ py_test( srcs = ["date_utils_test.py"], deps = [ ":date_utils", + requirement("python-dateutil"), ], ) diff --git a/experiments/v3/pbpb/BUILD b/experiments/v3/pbpb/BUILD index cb34e4a7e..3b1d397da 100644 --- a/experiments/v3/pbpb/BUILD +++ b/experiments/v3/pbpb/BUILD @@ -68,4 +68,6 @@ py_test( "@com_google_protobuf//:protobuf_python", #"//beancount/ccore:data_py_proto", ], + # This test does not seem to work, so omit it from //... + tags = [ "manual" ], ) diff --git a/experiments/v3/protos/BUILD b/experiments/v3/protos/BUILD index 3bd42c098..d689f5eba 100644 --- a/experiments/v3/protos/BUILD +++ b/experiments/v3/protos/BUILD @@ -45,7 +45,7 @@ py_extension( "@local_config_python//:python_headers", "@com_google_protobuf//:protobuf", "@com_google_protobuf//:proto_api", - "@com_google_protobuf//:pyext", + #"@com_google_protobuf//:pyext", "@pybind11", ], @@ -60,4 +60,6 @@ py_test( #"//beancount/ccore:data_py_proto", ":expose_protos", ], + # This test does not seem to work, so omit it from //... + tags = [ "manual" ], ) diff --git a/requirements/BUILD.bazel b/requirements/BUILD.bazel new file mode 100644 index 000000000..fcba23b59 --- /dev/null +++ b/requirements/BUILD.bazel @@ -0,0 +1,22 @@ +load( + "@pypi//:requirements.bzl", + "requirement", +) +load("@rules_python//python:pip.bzl", "compile_pip_requirements") + +# bazel run //requirements:dev_req.update +compile_pip_requirements( + name = "dev_req", + extra_args = ["--allow-unsafe"], + requirements_in = "dev.txt", + requirements_txt = "dev_lock.txt", + data = [ "tools.txt", ], +) + +# bazel run //requirements:tools_req.update +compile_pip_requirements( + name = "tools_req", + extra_args = ["--allow-unsafe"], + requirements_in = "tools.txt", + requirements_txt = "tools_lock.txt", +) diff --git a/requirements/dev_lock.txt b/requirements/dev_lock.txt new file mode 100644 index 000000000..64e976356 --- /dev/null +++ b/requirements/dev_lock.txt @@ -0,0 +1,495 @@ +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# bazel run //requirements:dev_req.update +# +astroid==2.15.6 \ + --hash=sha256:389656ca57b6108f939cf5d2f9a2a825a3be50ba9d589670f393236e0a03b91c \ + --hash=sha256:903f024859b7c7687d7a7f3a3f73b17301f8e42dfd9cc9df9d4418172d3e2dbd + # via + # pylint + # pylint-protobuf +cachetools==5.3.1 \ + --hash=sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590 \ + --hash=sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b + # via google-auth +certifi==2023.7.22 \ + --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ + --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 + # via requests +charset-normalizer==3.2.0 \ + --hash=sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96 \ + --hash=sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c \ + --hash=sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710 \ + --hash=sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706 \ + --hash=sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020 \ + --hash=sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252 \ + --hash=sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad \ + --hash=sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329 \ + --hash=sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a \ + --hash=sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f \ + --hash=sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6 \ + --hash=sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4 \ + --hash=sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a \ + --hash=sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46 \ + --hash=sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2 \ + --hash=sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23 \ + --hash=sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace \ + --hash=sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd \ + --hash=sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982 \ + --hash=sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10 \ + --hash=sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2 \ + --hash=sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea \ + --hash=sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09 \ + --hash=sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5 \ + --hash=sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149 \ + --hash=sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489 \ + --hash=sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9 \ + --hash=sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80 \ + --hash=sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592 \ + --hash=sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3 \ + --hash=sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6 \ + --hash=sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed \ + --hash=sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c \ + --hash=sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200 \ + --hash=sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a \ + --hash=sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e \ + --hash=sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d \ + --hash=sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6 \ + --hash=sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623 \ + --hash=sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669 \ + --hash=sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3 \ + --hash=sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa \ + --hash=sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9 \ + --hash=sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2 \ + --hash=sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f \ + --hash=sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1 \ + --hash=sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4 \ + --hash=sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a \ + --hash=sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8 \ + --hash=sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3 \ + --hash=sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029 \ + --hash=sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f \ + --hash=sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959 \ + --hash=sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22 \ + --hash=sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7 \ + --hash=sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952 \ + --hash=sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346 \ + --hash=sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e \ + --hash=sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d \ + --hash=sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299 \ + --hash=sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd \ + --hash=sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a \ + --hash=sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3 \ + --hash=sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037 \ + --hash=sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94 \ + --hash=sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c \ + --hash=sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858 \ + --hash=sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a \ + --hash=sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449 \ + --hash=sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c \ + --hash=sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918 \ + --hash=sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1 \ + --hash=sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c \ + --hash=sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac \ + --hash=sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa + # via requests +click==8.1.6 \ + --hash=sha256:48ee849951919527a045bfe3bf7baa8a959c423134e1a5b98c05c20ba75a1cbd \ + --hash=sha256:fa244bb30b3b5ee2cae3da8f55c9e5e0c0e86093306301fb418eb9dc40fbded5 + # via -r requirements/tools.txt +dill==0.3.7 \ + --hash=sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e \ + --hash=sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03 + # via pylint +exceptiongroup==1.1.2 \ + --hash=sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5 \ + --hash=sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f + # via pytest +google-api-core==2.11.1 \ + --hash=sha256:25d29e05a0058ed5f19c61c0a78b1b53adea4d9364b464d014fbda941f6d1c9a \ + --hash=sha256:d92a5a92dc36dd4f4b9ee4e55528a90e432b059f93aee6ad857f9de8cc7ae94a + # via google-api-python-client +google-api-python-client==2.94.0 \ + --hash=sha256:28b2f0c2c6380a119e2efd7ecd28fa9d313becf37d71f00bfa49332428e071b4 \ + --hash=sha256:4ff598b7b83d5c0c5582927e74947286070b5b21a13e1bb64409fd92e45bfb26 + # via -r requirements/tools.txt +google-auth==2.22.0 \ + --hash=sha256:164cba9af4e6e4e40c3a4f90a1a6c12ee56f14c0b4868d1ca91b32826ab334ce \ + --hash=sha256:d61d1b40897407b574da67da1a833bdc10d5a11642566e506565d1b1a46ba873 + # via + # google-api-core + # google-api-python-client + # google-auth-httplib2 + # google-auth-oauthlib +google-auth-httplib2==0.1.0 \ + --hash=sha256:31e49c36c6b5643b57e82617cb3e021e3e1d2df9da63af67252c02fa9c1f4a10 \ + --hash=sha256:a07c39fd632becacd3f07718dfd6021bf396978f03ad3ce4321d060015cc30ac + # via google-api-python-client +google-auth-oauthlib==1.0.0 \ + --hash=sha256:95880ca704928c300f48194d1770cf5b1462835b6e49db61445a520f793fd5fb \ + --hash=sha256:e375064964820b47221a7e1b7ee1fd77051b6323c3f9e3e19785f78ab67ecfc5 + # via -r requirements/tools.txt +googleapis-common-protos==1.59.1 \ + --hash=sha256:0cbedb6fb68f1c07e18eb4c48256320777707e7d0c55063ae56c15db3224a61e \ + --hash=sha256:b35d530fe825fb4227857bc47ad84c33c809ac96f312e13182bdeaa2abe1178a + # via google-api-core +httplib2==0.22.0 \ + --hash=sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc \ + --hash=sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81 + # via + # -r requirements/tools.txt + # google-api-python-client + # google-auth-httplib2 + # oauth2client +idna==3.4 \ + --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ + --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 + # via requests +iniconfig==2.0.0 \ + --hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \ + --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 + # via pytest +isort==5.12.0 \ + --hash=sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504 \ + --hash=sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6 + # via pylint +lazy-object-proxy==1.9.0 \ + --hash=sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382 \ + --hash=sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82 \ + --hash=sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9 \ + --hash=sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494 \ + --hash=sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46 \ + --hash=sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30 \ + --hash=sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63 \ + --hash=sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4 \ + --hash=sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae \ + --hash=sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be \ + --hash=sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701 \ + --hash=sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd \ + --hash=sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006 \ + --hash=sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a \ + --hash=sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586 \ + --hash=sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8 \ + --hash=sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821 \ + --hash=sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07 \ + --hash=sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b \ + --hash=sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171 \ + --hash=sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b \ + --hash=sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2 \ + --hash=sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7 \ + --hash=sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4 \ + --hash=sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8 \ + --hash=sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e \ + --hash=sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f \ + --hash=sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda \ + --hash=sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4 \ + --hash=sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e \ + --hash=sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671 \ + --hash=sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11 \ + --hash=sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455 \ + --hash=sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734 \ + --hash=sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb \ + --hash=sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59 + # via astroid +lxml==4.9.3 \ + --hash=sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3 \ + --hash=sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d \ + --hash=sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a \ + --hash=sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120 \ + --hash=sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305 \ + --hash=sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287 \ + --hash=sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23 \ + --hash=sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52 \ + --hash=sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f \ + --hash=sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4 \ + --hash=sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584 \ + --hash=sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f \ + --hash=sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693 \ + --hash=sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef \ + --hash=sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5 \ + --hash=sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02 \ + --hash=sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc \ + --hash=sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7 \ + --hash=sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da \ + --hash=sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a \ + --hash=sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40 \ + --hash=sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8 \ + --hash=sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd \ + --hash=sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601 \ + --hash=sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c \ + --hash=sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be \ + --hash=sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2 \ + --hash=sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c \ + --hash=sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129 \ + --hash=sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc \ + --hash=sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2 \ + --hash=sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1 \ + --hash=sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7 \ + --hash=sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d \ + --hash=sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477 \ + --hash=sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d \ + --hash=sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e \ + --hash=sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7 \ + --hash=sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2 \ + --hash=sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574 \ + --hash=sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf \ + --hash=sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b \ + --hash=sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98 \ + --hash=sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12 \ + --hash=sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42 \ + --hash=sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35 \ + --hash=sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d \ + --hash=sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce \ + --hash=sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d \ + --hash=sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f \ + --hash=sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db \ + --hash=sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4 \ + --hash=sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694 \ + --hash=sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac \ + --hash=sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2 \ + --hash=sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7 \ + --hash=sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96 \ + --hash=sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d \ + --hash=sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b \ + --hash=sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a \ + --hash=sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13 \ + --hash=sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340 \ + --hash=sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6 \ + --hash=sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458 \ + --hash=sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c \ + --hash=sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c \ + --hash=sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9 \ + --hash=sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432 \ + --hash=sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991 \ + --hash=sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69 \ + --hash=sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf \ + --hash=sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb \ + --hash=sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b \ + --hash=sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833 \ + --hash=sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76 \ + --hash=sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85 \ + --hash=sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e \ + --hash=sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50 \ + --hash=sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8 \ + --hash=sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4 \ + --hash=sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b \ + --hash=sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5 \ + --hash=sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190 \ + --hash=sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7 \ + --hash=sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa \ + --hash=sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0 \ + --hash=sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9 \ + --hash=sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0 \ + --hash=sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b \ + --hash=sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5 \ + --hash=sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7 \ + --hash=sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4 + # via -r requirements/tools.txt +mccabe==0.7.0 \ + --hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \ + --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e + # via pylint +oauth2client==4.1.3 \ + --hash=sha256:b8a81cc5d60e2d364f0b1b98f958dbd472887acaf1a5b05e21c28c31a2d6d3ac \ + --hash=sha256:d486741e451287f69568a4d26d70d9acd73a2bbfa275746c535b4209891cccc6 + # via -r requirements/tools.txt +oauthlib==3.2.2 \ + --hash=sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca \ + --hash=sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918 + # via requests-oauthlib +packaging==23.1 \ + --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \ + --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f + # via pytest +platformdirs==3.9.1 \ + --hash=sha256:1b42b450ad933e981d56e59f1b97495428c9bd60698baab9f3eb3d00d5822421 \ + --hash=sha256:ad8291ae0ae5072f66c16945166cb11c63394c7a3ad1b1bc9828ca3162da8c2f + # via pylint +pluggy==1.2.0 \ + --hash=sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849 \ + --hash=sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3 + # via pytest +ply==3.11 \ + --hash=sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3 \ + --hash=sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce + # via -r requirements/tools.txt +protobuf==4.23.4 \ + --hash=sha256:0a5759f5696895de8cc913f084e27fd4125e8fb0914bb729a17816a33819f474 \ + --hash=sha256:351cc90f7d10839c480aeb9b870a211e322bf05f6ab3f55fcb2f51331f80a7d2 \ + --hash=sha256:5fea3c64d41ea5ecf5697b83e41d09b9589e6f20b677ab3c48e5f242d9b7897b \ + --hash=sha256:6dd9b9940e3f17077e820b75851126615ee38643c2c5332aa7a359988820c720 \ + --hash=sha256:7b19b6266d92ca6a2a87effa88ecc4af73ebc5cfde194dc737cf8ef23a9a3b12 \ + --hash=sha256:8547bf44fe8cec3c69e3042f5c4fb3e36eb2a7a013bb0a44c018fc1e427aafbd \ + --hash=sha256:9053df6df8e5a76c84339ee4a9f5a2661ceee4a0dab019e8663c50ba324208b0 \ + --hash=sha256:c3e0939433c40796ca4cfc0fac08af50b00eb66a40bbbc5dee711998fb0bbc1e \ + --hash=sha256:ccd9430c0719dce806b93f89c91de7977304729e55377f872a92465d548329a9 \ + --hash=sha256:e1c915778d8ced71e26fcf43c0866d7499891bca14c4368448a82edc61fdbc70 \ + --hash=sha256:e9d0be5bf34b275b9f87ba7407796556abeeba635455d036c7351f7c183ef8ff \ + --hash=sha256:effeac51ab79332d44fba74660d40ae79985901ac21bca408f8dc335a81aa597 \ + --hash=sha256:fee88269a090ada09ca63551bf2f573eb2424035bcf2cb1b121895b01a46594a + # via + # google-api-core + # pylint-protobuf +pyasn1==0.5.0 \ + --hash=sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57 \ + --hash=sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde + # via + # oauth2client + # pyasn1-modules + # rsa +pyasn1-modules==0.3.0 \ + --hash=sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c \ + --hash=sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d + # via + # google-auth + # oauth2client +pylint==2.17.4 \ + --hash=sha256:5dcf1d9e19f41f38e4e85d10f511e5b9c35e1aa74251bf95cdd8cb23584e2db1 \ + --hash=sha256:7a1145fb08c251bdb5cca11739722ce64a63db479283d10ce718b2460e54123c + # via + # -r requirements/dev.txt + # pylint-protobuf +pylint-protobuf==0.20.2 \ + --hash=sha256:41093a32907e95c340a9b7c4938230dff00a27dfdddc8e6d29a89079129c840c \ + --hash=sha256:f86e04cb59fb5b72adda41129145160844ea0b28faada7a2f7a26e6a5f285179 + # via -r requirements/dev.txt +pyparsing==3.1.0 \ + --hash=sha256:d554a96d1a7d3ddaf7183104485bc19fd80543ad6ac5bdb6426719d766fb06c1 \ + --hash=sha256:edb662d6fe322d6e990b1594b5feaeadf806803359e3d4d42f11e295e588f0ea + # via httplib2 +pytest==7.4.0 \ + --hash=sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32 \ + --hash=sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a + # via -r requirements/dev.txt +python-dateutil==2.8.2 \ + --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ + --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 + # via -r requirements/tools.txt +requests==2.31.0 \ + --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \ + --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 + # via + # -r requirements/tools.txt + # google-api-core + # requests-oauthlib +requests-oauthlib==1.3.1 \ + --hash=sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5 \ + --hash=sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a + # via google-auth-oauthlib +rsa==4.9 \ + --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ + --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 + # via + # google-auth + # oauth2client +six==1.16.0 \ + --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ + --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 + # via + # google-auth + # google-auth-httplib2 + # oauth2client + # python-dateutil +tomli==2.0.1 \ + --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ + --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f + # via + # pylint + # pytest +tomlkit==0.11.8 \ + --hash=sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171 \ + --hash=sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3 + # via pylint +typing-extensions==4.7.1 \ + --hash=sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36 \ + --hash=sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2 + # via astroid +uritemplate==4.1.1 \ + --hash=sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0 \ + --hash=sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e + # via google-api-python-client +urllib3==1.26.16 \ + --hash=sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f \ + --hash=sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14 + # via + # google-auth + # requests +wrapt==1.15.0 \ + --hash=sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0 \ + --hash=sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420 \ + --hash=sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a \ + --hash=sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c \ + --hash=sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079 \ + --hash=sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923 \ + --hash=sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f \ + --hash=sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1 \ + --hash=sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8 \ + --hash=sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86 \ + --hash=sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0 \ + --hash=sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364 \ + --hash=sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e \ + --hash=sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c \ + --hash=sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e \ + --hash=sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c \ + --hash=sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727 \ + --hash=sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff \ + --hash=sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e \ + --hash=sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29 \ + --hash=sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7 \ + --hash=sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72 \ + --hash=sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475 \ + --hash=sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a \ + --hash=sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317 \ + --hash=sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2 \ + --hash=sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd \ + --hash=sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640 \ + --hash=sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98 \ + --hash=sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248 \ + --hash=sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e \ + --hash=sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d \ + --hash=sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec \ + --hash=sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1 \ + --hash=sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e \ + --hash=sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9 \ + --hash=sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92 \ + --hash=sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb \ + --hash=sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094 \ + --hash=sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46 \ + --hash=sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29 \ + --hash=sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd \ + --hash=sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705 \ + --hash=sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8 \ + --hash=sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975 \ + --hash=sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb \ + --hash=sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e \ + --hash=sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b \ + --hash=sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418 \ + --hash=sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019 \ + --hash=sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1 \ + --hash=sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba \ + --hash=sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6 \ + --hash=sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2 \ + --hash=sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3 \ + --hash=sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7 \ + --hash=sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752 \ + --hash=sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416 \ + --hash=sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f \ + --hash=sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1 \ + --hash=sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc \ + --hash=sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145 \ + --hash=sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee \ + --hash=sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a \ + --hash=sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7 \ + --hash=sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b \ + --hash=sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653 \ + --hash=sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0 \ + --hash=sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90 \ + --hash=sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29 \ + --hash=sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6 \ + --hash=sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034 \ + --hash=sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09 \ + --hash=sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559 \ + --hash=sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639 + # via astroid diff --git a/requirements/tools_lock.txt b/requirements/tools_lock.txt new file mode 100644 index 000000000..237dec529 --- /dev/null +++ b/requirements/tools_lock.txt @@ -0,0 +1,312 @@ +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# bazel run //requirements:tools_req.update +# +cachetools==5.3.1 \ + --hash=sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590 \ + --hash=sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b + # via google-auth +certifi==2023.7.22 \ + --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ + --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 + # via requests +charset-normalizer==3.2.0 \ + --hash=sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96 \ + --hash=sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c \ + --hash=sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710 \ + --hash=sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706 \ + --hash=sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020 \ + --hash=sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252 \ + --hash=sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad \ + --hash=sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329 \ + --hash=sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a \ + --hash=sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f \ + --hash=sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6 \ + --hash=sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4 \ + --hash=sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a \ + --hash=sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46 \ + --hash=sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2 \ + --hash=sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23 \ + --hash=sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace \ + --hash=sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd \ + --hash=sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982 \ + --hash=sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10 \ + --hash=sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2 \ + --hash=sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea \ + --hash=sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09 \ + --hash=sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5 \ + --hash=sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149 \ + --hash=sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489 \ + --hash=sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9 \ + --hash=sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80 \ + --hash=sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592 \ + --hash=sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3 \ + --hash=sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6 \ + --hash=sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed \ + --hash=sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c \ + --hash=sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200 \ + --hash=sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a \ + --hash=sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e \ + --hash=sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d \ + --hash=sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6 \ + --hash=sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623 \ + --hash=sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669 \ + --hash=sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3 \ + --hash=sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa \ + --hash=sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9 \ + --hash=sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2 \ + --hash=sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f \ + --hash=sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1 \ + --hash=sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4 \ + --hash=sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a \ + --hash=sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8 \ + --hash=sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3 \ + --hash=sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029 \ + --hash=sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f \ + --hash=sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959 \ + --hash=sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22 \ + --hash=sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7 \ + --hash=sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952 \ + --hash=sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346 \ + --hash=sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e \ + --hash=sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d \ + --hash=sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299 \ + --hash=sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd \ + --hash=sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a \ + --hash=sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3 \ + --hash=sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037 \ + --hash=sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94 \ + --hash=sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c \ + --hash=sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858 \ + --hash=sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a \ + --hash=sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449 \ + --hash=sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c \ + --hash=sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918 \ + --hash=sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1 \ + --hash=sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c \ + --hash=sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac \ + --hash=sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa + # via requests +click==8.1.6 \ + --hash=sha256:48ee849951919527a045bfe3bf7baa8a959c423134e1a5b98c05c20ba75a1cbd \ + --hash=sha256:fa244bb30b3b5ee2cae3da8f55c9e5e0c0e86093306301fb418eb9dc40fbded5 + # via -r requirements/tools.txt +google-api-core==2.11.1 \ + --hash=sha256:25d29e05a0058ed5f19c61c0a78b1b53adea4d9364b464d014fbda941f6d1c9a \ + --hash=sha256:d92a5a92dc36dd4f4b9ee4e55528a90e432b059f93aee6ad857f9de8cc7ae94a + # via google-api-python-client +google-api-python-client==2.94.0 \ + --hash=sha256:28b2f0c2c6380a119e2efd7ecd28fa9d313becf37d71f00bfa49332428e071b4 \ + --hash=sha256:4ff598b7b83d5c0c5582927e74947286070b5b21a13e1bb64409fd92e45bfb26 + # via -r requirements/tools.txt +google-auth==2.22.0 \ + --hash=sha256:164cba9af4e6e4e40c3a4f90a1a6c12ee56f14c0b4868d1ca91b32826ab334ce \ + --hash=sha256:d61d1b40897407b574da67da1a833bdc10d5a11642566e506565d1b1a46ba873 + # via + # google-api-core + # google-api-python-client + # google-auth-httplib2 + # google-auth-oauthlib +google-auth-httplib2==0.1.0 \ + --hash=sha256:31e49c36c6b5643b57e82617cb3e021e3e1d2df9da63af67252c02fa9c1f4a10 \ + --hash=sha256:a07c39fd632becacd3f07718dfd6021bf396978f03ad3ce4321d060015cc30ac + # via google-api-python-client +google-auth-oauthlib==1.0.0 \ + --hash=sha256:95880ca704928c300f48194d1770cf5b1462835b6e49db61445a520f793fd5fb \ + --hash=sha256:e375064964820b47221a7e1b7ee1fd77051b6323c3f9e3e19785f78ab67ecfc5 + # via -r requirements/tools.txt +googleapis-common-protos==1.59.1 \ + --hash=sha256:0cbedb6fb68f1c07e18eb4c48256320777707e7d0c55063ae56c15db3224a61e \ + --hash=sha256:b35d530fe825fb4227857bc47ad84c33c809ac96f312e13182bdeaa2abe1178a + # via google-api-core +httplib2==0.22.0 \ + --hash=sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc \ + --hash=sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81 + # via + # -r requirements/tools.txt + # google-api-python-client + # google-auth-httplib2 + # oauth2client +idna==3.4 \ + --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ + --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 + # via requests +lxml==4.9.3 \ + --hash=sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3 \ + --hash=sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d \ + --hash=sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a \ + --hash=sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120 \ + --hash=sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305 \ + --hash=sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287 \ + --hash=sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23 \ + --hash=sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52 \ + --hash=sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f \ + --hash=sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4 \ + --hash=sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584 \ + --hash=sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f \ + --hash=sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693 \ + --hash=sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef \ + --hash=sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5 \ + --hash=sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02 \ + --hash=sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc \ + --hash=sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7 \ + --hash=sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da \ + --hash=sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a \ + --hash=sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40 \ + --hash=sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8 \ + --hash=sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd \ + --hash=sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601 \ + --hash=sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c \ + --hash=sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be \ + --hash=sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2 \ + --hash=sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c \ + --hash=sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129 \ + --hash=sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc \ + --hash=sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2 \ + --hash=sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1 \ + --hash=sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7 \ + --hash=sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d \ + --hash=sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477 \ + --hash=sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d \ + --hash=sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e \ + --hash=sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7 \ + --hash=sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2 \ + --hash=sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574 \ + --hash=sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf \ + --hash=sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b \ + --hash=sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98 \ + --hash=sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12 \ + --hash=sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42 \ + --hash=sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35 \ + --hash=sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d \ + --hash=sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce \ + --hash=sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d \ + --hash=sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f \ + --hash=sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db \ + --hash=sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4 \ + --hash=sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694 \ + --hash=sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac \ + --hash=sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2 \ + --hash=sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7 \ + --hash=sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96 \ + --hash=sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d \ + --hash=sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b \ + --hash=sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a \ + --hash=sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13 \ + --hash=sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340 \ + --hash=sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6 \ + --hash=sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458 \ + --hash=sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c \ + --hash=sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c \ + --hash=sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9 \ + --hash=sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432 \ + --hash=sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991 \ + --hash=sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69 \ + --hash=sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf \ + --hash=sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb \ + --hash=sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b \ + --hash=sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833 \ + --hash=sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76 \ + --hash=sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85 \ + --hash=sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e \ + --hash=sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50 \ + --hash=sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8 \ + --hash=sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4 \ + --hash=sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b \ + --hash=sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5 \ + --hash=sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190 \ + --hash=sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7 \ + --hash=sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa \ + --hash=sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0 \ + --hash=sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9 \ + --hash=sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0 \ + --hash=sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b \ + --hash=sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5 \ + --hash=sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7 \ + --hash=sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4 + # via -r requirements/tools.txt +oauth2client==4.1.3 \ + --hash=sha256:b8a81cc5d60e2d364f0b1b98f958dbd472887acaf1a5b05e21c28c31a2d6d3ac \ + --hash=sha256:d486741e451287f69568a4d26d70d9acd73a2bbfa275746c535b4209891cccc6 + # via -r requirements/tools.txt +oauthlib==3.2.2 \ + --hash=sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca \ + --hash=sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918 + # via requests-oauthlib +ply==3.11 \ + --hash=sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3 \ + --hash=sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce + # via -r requirements/tools.txt +protobuf==4.23.4 \ + --hash=sha256:0a5759f5696895de8cc913f084e27fd4125e8fb0914bb729a17816a33819f474 \ + --hash=sha256:351cc90f7d10839c480aeb9b870a211e322bf05f6ab3f55fcb2f51331f80a7d2 \ + --hash=sha256:5fea3c64d41ea5ecf5697b83e41d09b9589e6f20b677ab3c48e5f242d9b7897b \ + --hash=sha256:6dd9b9940e3f17077e820b75851126615ee38643c2c5332aa7a359988820c720 \ + --hash=sha256:7b19b6266d92ca6a2a87effa88ecc4af73ebc5cfde194dc737cf8ef23a9a3b12 \ + --hash=sha256:8547bf44fe8cec3c69e3042f5c4fb3e36eb2a7a013bb0a44c018fc1e427aafbd \ + --hash=sha256:9053df6df8e5a76c84339ee4a9f5a2661ceee4a0dab019e8663c50ba324208b0 \ + --hash=sha256:c3e0939433c40796ca4cfc0fac08af50b00eb66a40bbbc5dee711998fb0bbc1e \ + --hash=sha256:ccd9430c0719dce806b93f89c91de7977304729e55377f872a92465d548329a9 \ + --hash=sha256:e1c915778d8ced71e26fcf43c0866d7499891bca14c4368448a82edc61fdbc70 \ + --hash=sha256:e9d0be5bf34b275b9f87ba7407796556abeeba635455d036c7351f7c183ef8ff \ + --hash=sha256:effeac51ab79332d44fba74660d40ae79985901ac21bca408f8dc335a81aa597 \ + --hash=sha256:fee88269a090ada09ca63551bf2f573eb2424035bcf2cb1b121895b01a46594a + # via google-api-core +pyasn1==0.5.0 \ + --hash=sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57 \ + --hash=sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde + # via + # oauth2client + # pyasn1-modules + # rsa +pyasn1-modules==0.3.0 \ + --hash=sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c \ + --hash=sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d + # via + # google-auth + # oauth2client +pyparsing==3.1.0 \ + --hash=sha256:d554a96d1a7d3ddaf7183104485bc19fd80543ad6ac5bdb6426719d766fb06c1 \ + --hash=sha256:edb662d6fe322d6e990b1594b5feaeadf806803359e3d4d42f11e295e588f0ea + # via httplib2 +python-dateutil==2.8.2 \ + --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ + --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 + # via -r requirements/tools.txt +requests==2.31.0 \ + --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \ + --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 + # via + # -r requirements/tools.txt + # google-api-core + # requests-oauthlib +requests-oauthlib==1.3.1 \ + --hash=sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5 \ + --hash=sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a + # via google-auth-oauthlib +rsa==4.9 \ + --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ + --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 + # via + # google-auth + # oauth2client +six==1.16.0 \ + --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ + --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 + # via + # google-auth + # google-auth-httplib2 + # oauth2client + # python-dateutil +uritemplate==4.1.1 \ + --hash=sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0 \ + --hash=sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e + # via google-api-python-client +urllib3==1.26.16 \ + --hash=sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f \ + --hash=sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14 + # via + # google-auth + # requests From 1dc1639e3e61e54f6755e54e4ed1ae5e2a76c40c Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Mon, 18 Sep 2023 09:54:10 +0200 Subject: [PATCH 25/36] Use the regex module for Unicode character class aware regular expr --- beancount/core/account.py | 8 +- beancount/parser/grammar.py | 9 +- beancount/scripts/format.py | 14 +- beancount/utils/regexp_utils.py | 862 --------------------------- beancount/utils/regexp_utils_test.py | 32 - meson.build | 1 - pyproject.toml | 1 + requirements/tools.txt | 1 + setup.py | 2 + 9 files changed, 21 insertions(+), 909 deletions(-) delete mode 100644 beancount/utils/regexp_utils.py delete mode 100644 beancount/utils/regexp_utils_test.py diff --git a/beancount/core/account.py b/beancount/core/account.py index 5183fad14..417ec56c6 100644 --- a/beancount/core/account.py +++ b/beancount/core/account.py @@ -12,6 +12,8 @@ from os import path from typing import Any, Callable, Iterable, Iterator, List, Tuple +import regex + from beancount.utils import regexp_utils @@ -29,8 +31,8 @@ # Lu: Uppercase letters. # L: All letters. # Nd: Decimal numbers. -ACC_COMP_TYPE_RE = regexp_utils.re_replace_unicode(r"[\p{Lu}][\p{L}\p{Nd}\-]*") -ACC_COMP_NAME_RE = regexp_utils.re_replace_unicode(r"[\p{Lu}\p{Nd}][\p{L}\p{Nd}\-]*") +ACC_COMP_TYPE_RE = r"[\p{Lu}][\p{L}\p{Nd}\-]*" +ACC_COMP_NAME_RE = r"[\p{Lu}\p{Nd}][\p{L}\p{Nd}\-]*" # Regular expression string that matches a valid account. {5672c7270e1e} ACCOUNT_RE = "(?:{})(?:{}{})+".format(ACC_COMP_TYPE_RE, sep, ACC_COMP_NAME_RE) @@ -51,7 +53,7 @@ def is_valid(string: Account) -> bool: A boolean, true if the string has the form of an account's name. """ return (isinstance(string, str) and - bool(re.match('{}$'.format(ACCOUNT_RE), string))) + bool(regex.match('{}$'.format(ACCOUNT_RE), string))) def join(*components: Tuple[str]) -> Account: diff --git a/beancount/parser/grammar.py b/beancount/parser/grammar.py index fb9695eb0..e31ff9905 100644 --- a/beancount/parser/grammar.py +++ b/beancount/parser/grammar.py @@ -5,12 +5,13 @@ import collections import copy -import re import traceback from os import path from datetime import date from decimal import Decimal +import regex + from beancount.core.number import ZERO from beancount.core.number import MISSING from beancount.core.amount import Amount @@ -91,9 +92,9 @@ def valid_account_regexp(options): # Replace the first term of the account regular expression with the specific # names allowed under the options configuration. This code is kept in sync # with {5672c7270e1e}. - return re.compile("(?:{})(?:{}{})+".format('|'.join(names), - account.sep, - account.ACC_COMP_NAME_RE)) + return regex.compile("(?:{})(?:{}{})+".format('|'.join(names), + account.sep, + account.ACC_COMP_NAME_RE)) # A temporary data structure used during parsing to hold and accumulate the diff --git a/beancount/scripts/format.py b/beancount/scripts/format.py index c7a76dced..f82d15df7 100755 --- a/beancount/scripts/format.py +++ b/beancount/scripts/format.py @@ -3,9 +3,9 @@ import collections import io -import re import click +import regex from beancount.core import amount from beancount.core import account @@ -37,7 +37,7 @@ def align_beancount(contents, prefix_width=None, num_width=None, currency_column # of the stripped prefix and the number. match_pairs = [] for line in contents.splitlines(): - match = re.match( + match = regex.match( rf'(^\d[^";]*?|\s+{account.ACCOUNT_RE})\s+' rf'({PARENTHESIZED_BINARY_OP_RE}|{NUMBER_RE})\s+' rf'((?:{amount.CURRENCY_RE})\b.*)', @@ -101,10 +101,10 @@ def align_beancount(contents, prefix_width=None, num_width=None, currency_column # Ensure that the file before and after have only whitespace differences. # This is a sanity check, to make really sure we never change anything but whitespace, # so it's safe. - # open('/tmp/before', 'w').write(re.sub(r'[ \t]+', ' ', contents)) - # open('/tmp/after', 'w').write(re.sub(r'[ \t]+', ' ', formatted_contents)) - old_stripped = re.sub(r'[ \t\n]+', ' ', contents.rstrip()) - new_stripped = re.sub(r'[ \t\n]+', ' ', formatted_contents.rstrip()) + # open('/tmp/before', 'w').write(regex.sub(r'[ \t]+', ' ', contents)) + # open('/tmp/after', 'w').write(regex.sub(r'[ \t]+', ' ', formatted_contents)) + old_stripped = regex.sub(r'[ \t\n]+', ' ', contents.rstrip()) + new_stripped = regex.sub(r'[ \t\n]+', ' ', formatted_contents.rstrip()) assert (old_stripped == new_stripped), (old_stripped, new_stripped) return formatted_contents @@ -140,7 +140,7 @@ def normalize_indent_whitespace(match_pairs): adjusted with a different whitespace prefix. """ # Compute most frequent account name prefix. - match_posting = re.compile(r'([ \t]+)({}.*)'.format(account.ACCOUNT_RE)).match + match_posting = regex.compile(r'([ \t]+)({}.*)'.format(account.ACCOUNT_RE)).match width = compute_most_frequent( len(match.group(1)) for match in (match_posting(prefix) diff --git a/beancount/utils/regexp_utils.py b/beancount/utils/regexp_utils.py deleted file mode 100644 index d1d185a41..000000000 --- a/beancount/utils/regexp_utils.py +++ /dev/null @@ -1,862 +0,0 @@ -"""Regular expression helpers. -""" -__copyright__ = "Copyright (C) 2018 Martin Blais" -__license__ = "GNU GPLv2" - - -UNICODE_RANGES = { - # Letters. - 'L': (r'\u0041-\u005A' - r'\u0061-\u007A' - r'\u00AA' - r'\u00B5' - r'\u00BA' - r'\u00C0-\u00D6' - r'\u00D8-\u00F6' - r'\u00F8-\u02C1' - r'\u02C6-\u02D1' - r'\u02E0-\u02E4' - r'\u02EC' - r'\u02EE' - r'\u0370-\u0374' - r'\u0376-\u0377' - r'\u037A-\u037D' - r'\u0386' - r'\u0388-\u038A' - r'\u038C' - r'\u038E-\u03A1' - r'\u03A3-\u03F5' - r'\u03F7-\u0481' - r'\u048A-\u0523' - r'\u0531-\u0556' - r'\u0559' - r'\u0561-\u0587' - r'\u05D0-\u05EA' - r'\u05F0-\u05F2' - r'\u0621-\u064A' - r'\u066E-\u066F' - r'\u0671-\u06D3' - r'\u06D5' - r'\u06E5-\u06E6' - r'\u06EE-\u06EF' - r'\u06FA-\u06FC' - r'\u06FF' - r'\u0710' - r'\u0712-\u072F' - r'\u074D-\u07A5' - r'\u07B1' - r'\u07CA-\u07EA' - r'\u07F4-\u07F5' - r'\u07FA' - r'\u0904-\u0939' - r'\u093D' - r'\u0950' - r'\u0958-\u0961' - r'\u0971-\u0972' - r'\u097B-\u097F' - r'\u0985-\u098C' - r'\u098F-\u0990' - r'\u0993-\u09A8' - r'\u09AA-\u09B0' - r'\u09B2' - r'\u09B6-\u09B9' - r'\u09BD' - r'\u09CE' - r'\u09DC-\u09DD' - r'\u09DF-\u09E1' - r'\u09F0-\u09F1' - r'\u0A05-\u0A0A' - r'\u0A0F-\u0A10' - r'\u0A13-\u0A28' - r'\u0A2A-\u0A30' - r'\u0A32-\u0A33' - r'\u0A35-\u0A36' - r'\u0A38-\u0A39' - r'\u0A59-\u0A5C' - r'\u0A5E' - r'\u0A72-\u0A74' - r'\u0A85-\u0A8D' - r'\u0A8F-\u0A91' - r'\u0A93-\u0AA8' - r'\u0AAA-\u0AB0' - r'\u0AB2-\u0AB3' - r'\u0AB5-\u0AB9' - r'\u0ABD' - r'\u0AD0' - r'\u0AE0-\u0AE1' - r'\u0B05-\u0B0C' - r'\u0B0F-\u0B10' - r'\u0B13-\u0B28' - r'\u0B2A-\u0B30' - r'\u0B32-\u0B33' - r'\u0B35-\u0B39' - r'\u0B3D' - r'\u0B5C-\u0B5D' - r'\u0B5F-\u0B61' - r'\u0B71' - r'\u0B83' - r'\u0B85-\u0B8A' - r'\u0B8E-\u0B90' - r'\u0B92-\u0B95' - r'\u0B99-\u0B9A' - r'\u0B9C' - r'\u0B9E-\u0B9F' - r'\u0BA3-\u0BA4' - r'\u0BA8-\u0BAA' - r'\u0BAE-\u0BB9' - r'\u0BD0' - r'\u0C05-\u0C0C' - r'\u0C0E-\u0C10' - r'\u0C12-\u0C28' - r'\u0C2A-\u0C33' - r'\u0C35-\u0C39' - r'\u0C3D' - r'\u0C58-\u0C59' - r'\u0C60-\u0C61' - r'\u0C85-\u0C8C' - r'\u0C8E-\u0C90' - r'\u0C92-\u0CA8' - r'\u0CAA-\u0CB3' - r'\u0CB5-\u0CB9' - r'\u0CBD' - r'\u0CDE' - r'\u0CE0-\u0CE1' - r'\u0D05-\u0D0C' - r'\u0D0E-\u0D10' - r'\u0D12-\u0D28' - r'\u0D2A-\u0D39' - r'\u0D3D' - r'\u0D60-\u0D61' - r'\u0D7A-\u0D7F' - r'\u0D85-\u0D96' - r'\u0D9A-\u0DB1' - r'\u0DB3-\u0DBB' - r'\u0DBD' - r'\u0DC0-\u0DC6' - r'\u0E01-\u0E30' - r'\u0E32-\u0E33' - r'\u0E40-\u0E46' - r'\u0E81-\u0E82' - r'\u0E84' - r'\u0E87-\u0E88' - r'\u0E8A' - r'\u0E8D' - r'\u0E94-\u0E97' - r'\u0E99-\u0E9F' - r'\u0EA1-\u0EA3' - r'\u0EA5' - r'\u0EA7' - r'\u0EAA-\u0EAB' - r'\u0EAD-\u0EB0' - r'\u0EB2-\u0EB3' - r'\u0EBD' - r'\u0EC0-\u0EC4' - r'\u0EC6' - r'\u0EDC-\u0EDD' - r'\u0F00' - r'\u0F40-\u0F47' - r'\u0F49-\u0F6C' - r'\u0F88-\u0F8B' - r'\u1000-\u102A' - r'\u103F' - r'\u1050-\u1055' - r'\u105A-\u105D' - r'\u1061' - r'\u1065-\u1066' - r'\u106E-\u1070' - r'\u1075-\u1081' - r'\u108E' - r'\u10A0-\u10C5' - r'\u10D0-\u10FA' - r'\u10FC' - r'\u1100-\u1159' - r'\u115F-\u11A2' - r'\u11A8-\u11F9' - r'\u1200-\u1248' - r'\u124A-\u124D' - r'\u1250-\u1256' - r'\u1258' - r'\u125A-\u125D' - r'\u1260-\u1288' - r'\u128A-\u128D' - r'\u1290-\u12B0' - r'\u12B2-\u12B5' - r'\u12B8-\u12BE' - r'\u12C0' - r'\u12C2-\u12C5' - r'\u12C8-\u12D6' - r'\u12D8-\u1310' - r'\u1312-\u1315' - r'\u1318-\u135A' - r'\u1380-\u138F' - r'\u13A0-\u13F4' - r'\u1401-\u166C' - r'\u166F-\u1676' - r'\u1681-\u169A' - r'\u16A0-\u16EA' - r'\u16EE-\u16F0' - r'\u1700-\u170C' - r'\u170E-\u1711' - r'\u1720-\u1731' - r'\u1740-\u1751' - r'\u1760-\u176C' - r'\u176E-\u1770' - r'\u1780-\u17B3' - r'\u17D7' - r'\u17DC' - r'\u1820-\u1877' - r'\u1880-\u18A8' - r'\u18AA' - r'\u1900-\u191C' - r'\u1950-\u196D' - r'\u1970-\u1974' - r'\u1980-\u19A9' - r'\u19C1-\u19C7' - r'\u1A00-\u1A16' - r'\u1B05-\u1B33' - r'\u1B45-\u1B4B' - r'\u1B83-\u1BA0' - r'\u1BAE-\u1BAF' - r'\u1C00-\u1C23' - r'\u1C4D-\u1C4F' - r'\u1C5A-\u1C7D' - r'\u1D00-\u1DBF' - r'\u1E00-\u1F15' - r'\u1F18-\u1F1D' - r'\u1F20-\u1F45' - r'\u1F48-\u1F4D' - r'\u1F50-\u1F57' - r'\u1F59' - r'\u1F5B' - r'\u1F5D' - r'\u1F5F-\u1F7D' - r'\u1F80-\u1FB4' - r'\u1FB6-\u1FBC' - r'\u1FBE' - r'\u1FC2-\u1FC4' - r'\u1FC6-\u1FCC' - r'\u1FD0-\u1FD3' - r'\u1FD6-\u1FDB' - r'\u1FE0-\u1FEC' - r'\u1FF2-\u1FF4' - r'\u1FF6-\u1FFC' - r'\u2071' - r'\u207F' - r'\u2090-\u2094' - r'\u2102' - r'\u2107' - r'\u210A-\u2113' - r'\u2115' - r'\u2119-\u211D' - r'\u2124' - r'\u2126' - r'\u2128' - r'\u212A-\u212D' - r'\u212F-\u2139' - r'\u213C-\u213F' - r'\u2145-\u2149' - r'\u214E' - r'\u2160-\u2188' - r'\u2C00-\u2C2E' - r'\u2C30-\u2C5E' - r'\u2C60-\u2C6F' - r'\u2C71-\u2C7D' - r'\u2C80-\u2CE4' - r'\u2D00-\u2D25' - r'\u2D30-\u2D65' - r'\u2D6F' - r'\u2D80-\u2D96' - r'\u2DA0-\u2DA6' - r'\u2DA8-\u2DAE' - r'\u2DB0-\u2DB6' - r'\u2DB8-\u2DBE' - r'\u2DC0-\u2DC6' - r'\u2DC8-\u2DCE' - r'\u2DD0-\u2DD6' - r'\u2DD8-\u2DDE' - r'\u2E2F' - r'\u3005-\u3007' - r'\u3021-\u3029' - r'\u3031-\u3035' - r'\u3038-\u303C' - r'\u3041-\u3096' - r'\u309D-\u309F' - r'\u30A1-\u30FA' - r'\u30FC-\u30FF' - r'\u3105-\u312D' - r'\u3131-\u318E' - r'\u31A0-\u31B7' - r'\u31F0-\u31FF' - r'\u3400' - r'\u4DB5' - r'\u4E00' - r'\u9FC3' - r'\uA000-\uA48C' - r'\uA500-\uA60C' - r'\uA610-\uA61F' - r'\uA62A-\uA62B' - r'\uA640-\uA65F' - r'\uA662-\uA66E' - r'\uA67F-\uA697' - r'\uA717-\uA71F' - r'\uA722-\uA788' - r'\uA78B-\uA78C' - r'\uA7FB-\uA801' - r'\uA803-\uA805' - r'\uA807-\uA80A' - r'\uA80C-\uA822' - r'\uA840-\uA873' - r'\uA882-\uA8B3' - r'\uA90A-\uA925' - r'\uA930-\uA946' - r'\uAA00-\uAA28' - r'\uAA40-\uAA42' - r'\uAA44-\uAA4B' - r'\uAC00' - r'\uD7A3' - r'\uF900-\uFA2D' - r'\uFA30-\uFA6A' - r'\uFA70-\uFAD9' - r'\uFB00-\uFB06' - r'\uFB13-\uFB17' - r'\uFB1D' - r'\uFB1F-\uFB28' - r'\uFB2A-\uFB36' - r'\uFB38-\uFB3C' - r'\uFB3E' - r'\uFB40-\uFB41' - r'\uFB43-\uFB44' - r'\uFB46-\uFBB1' - r'\uFBD3-\uFD3D' - r'\uFD50-\uFD8F' - r'\uFD92-\uFDC7' - r'\uFDF0-\uFDFB' - r'\uFE70-\uFE74' - r'\uFE76-\uFEFC' - r'\uFF21-\uFF3A' - r'\uFF41-\uFF5A' - r'\uFF66-\uFFBE' - r'\uFFC2-\uFFC7' - r'\uFFCA-\uFFCF' - r'\uFFD2-\uFFD7' - r'\uFFDA-\uFFDC'), - - # Uppercase letters. - 'Lu': (r'\u0041-\u005a' - r'\u00c0-\u00d6' - r'\u00d8-\u00de' - r'\u0100' - r'\u0102' - r'\u0104' - r'\u0106' - r'\u0108' - r'\u010a' - r'\u010c' - r'\u010e' - r'\u0110' - r'\u0112' - r'\u0114' - r'\u0116' - r'\u0118' - r'\u011a' - r'\u011c' - r'\u011e' - r'\u0120' - r'\u0122' - r'\u0124' - r'\u0126' - r'\u0128' - r'\u012a' - r'\u012c' - r'\u012e' - r'\u0130' - r'\u0132' - r'\u0134' - r'\u0136' - r'\u0139' - r'\u013b' - r'\u013d' - r'\u013f' - r'\u0141' - r'\u0143' - r'\u0145' - r'\u0147' - r'\u014a' - r'\u014c' - r'\u014e' - r'\u0150' - r'\u0152' - r'\u0154' - r'\u0156' - r'\u0158' - r'\u015a' - r'\u015c' - r'\u015e' - r'\u0160' - r'\u0162' - r'\u0164' - r'\u0166' - r'\u0168' - r'\u016a' - r'\u016c' - r'\u016e' - r'\u0170' - r'\u0172' - r'\u0174' - r'\u0176' - r'\u0178' - r'\u0179' - r'\u017b' - r'\u017d' - r'\u0181' - r'\u0182' - r'\u0184' - r'\u0186' - r'\u0187' - r'\u0189-' - r'\u018b' - r'\u018e-\u0191' - r'\u0193' - r'\u0194' - r'\u0196-' - r'\u0198' - r'\u019c' - r'\u019d' - r'\u019f' - r'\u01a0' - r'\u01a2' - r'\u01a4' - r'\u01a6' - r'\u01a7' - r'\u01a9' - r'\u01ac' - r'\u01ae' - r'\u01af' - r'\u01b1-\u01b3' - r'\u01b5' - r'\u01b7' - r'\u01b8' - r'\u01bc' - r'\u01c4' - r'\u01c7' - r'\u01ca' - r'\u01cd' - r'\u01cf' - r'\u01d1' - r'\u01d3' - r'\u01d5' - r'\u01d7' - r'\u01d9' - r'\u01db' - r'\u01de' - r'\u01e0' - r'\u01e2' - r'\u01e4' - r'\u01e6' - r'\u01e8' - r'\u01ea' - r'\u01ec' - r'\u01ee' - r'\u01f1' - r'\u01f4' - r'\u01f6-\u01f8' - r'\u01fa' - r'\u01fc' - r'\u01fe' - r'\u0200' - r'\u0202' - r'\u0204' - r'\u0206' - r'\u0208' - r'\u020a' - r'\u020c' - r'\u020e' - r'\u0210' - r'\u0212' - r'\u0214' - r'\u0216' - r'\u0218' - r'\u021a' - r'\u021c' - r'\u021e' - r'\u0220' - r'\u0222' - r'\u0224' - r'\u0226' - r'\u0228' - r'\u022a' - r'\u022c' - r'\u022e' - r'\u0230' - r'\u0232' - r'\u023a' - r'\u023b' - r'\u023d' - r'\u023e' - r'\u0241' - r'\u0243-\u0246' - r'\u0248' - r'\u024a' - r'\u024c' - r'\u024e' - r'\u0386' - r'\u0388-\u038a' - r'\u038c' - r'\u038e' - r'\u038f' - r'\u0391-\u03a1' - r'\u03a3-\u03ab' - r'\u03d2-\u03d4' - r'\u03d8' - r'\u03da' - r'\u03dc' - r'\u03de' - r'\u03e0' - r'\u03e2' - r'\u03e4' - r'\u03e6' - r'\u03e8' - r'\u03ea' - r'\u03ec' - r'\u03ee' - r'\u03f4' - r'\u03f7' - r'\u03f9' - r'\u03fa' - r'\u03fd-\u042f' - r'\u0460' - r'\u0462' - r'\u0464' - r'\u0466' - r'\u0468' - r'\u046a' - r'\u046c' - r'\u046e' - r'\u0470' - r'\u0472' - r'\u0474' - r'\u0476' - r'\u0478' - r'\u047a' - r'\u047c' - r'\u047e' - r'\u0480' - r'\u048a' - r'\u048c' - r'\u048e' - r'\u0490' - r'\u0492' - r'\u0494' - r'\u0496' - r'\u0498' - r'\u049a' - r'\u049c' - r'\u049e' - r'\u04a0' - r'\u04a2' - r'\u04a4' - r'\u04a6' - r'\u04a8' - r'\u04aa' - r'\u04ac' - r'\u04ae' - r'\u04b0' - r'\u04b2' - r'\u04b4' - r'\u04b6' - r'\u04b8' - r'\u04ba' - r'\u04bc' - r'\u04be' - r'\u04c0' - r'\u04c1' - r'\u04c3' - r'\u04c5' - r'\u04c7' - r'\u04c9' - r'\u04cb' - r'\u04cd' - r'\u04d0' - r'\u04d2' - r'\u04d4' - r'\u04d6' - r'\u04d8' - r'\u04da' - r'\u04dc' - r'\u04de' - r'\u04e0' - r'\u04e2' - r'\u04e4' - r'\u04e6' - r'\u04e8' - r'\u04ea' - r'\u04ec' - r'\u04ee' - r'\u04f0' - r'\u04f2' - r'\u04f4' - r'\u04f6' - r'\u04f8' - r'\u04fa' - r'\u04fc' - r'\u04fe' - r'\u0500' - r'\u0502' - r'\u0504' - r'\u0506' - r'\u0508' - r'\u050a' - r'\u050c' - r'\u050e' - r'\u0510' - r'\u0512' - r'\u0531-\u0556' - r'\u10a0-\u10c5' - r'\u1e00' - r'\u1e02' - r'\u1e04' - r'\u1e06' - r'\u1e08' - r'\u1e0a' - r'\u1e0c' - r'\u1e0e' - r'\u1e10' - r'\u1e12' - r'\u1e14' - r'\u1e16' - r'\u1e18' - r'\u1e1a' - r'\u1e1c' - r'\u1e1e' - r'\u1e20' - r'\u1e22' - r'\u1e24' - r'\u1e26' - r'\u1e28' - r'\u1e2a' - r'\u1e2c' - r'\u1e2e' - r'\u1e30' - r'\u1e32' - r'\u1e34' - r'\u1e36' - r'\u1e38' - r'\u1e3a' - r'\u1e3c' - r'\u1e3e' - r'\u1e40' - r'\u1e42' - r'\u1e44' - r'\u1e46' - r'\u1e48' - r'\u1e4a' - r'\u1e4c' - r'\u1e4e' - r'\u1e50' - r'\u1e52' - r'\u1e54' - r'\u1e56' - r'\u1e58' - r'\u1e5a' - r'\u1e5c' - r'\u1e5e' - r'\u1e60' - r'\u1e62' - r'\u1e64' - r'\u1e66' - r'\u1e68' - r'\u1e6a' - r'\u1e6c' - r'\u1e6e' - r'\u1e70' - r'\u1e72' - r'\u1e74' - r'\u1e76' - r'\u1e78' - r'\u1e7a' - r'\u1e7c' - r'\u1e7e' - r'\u1e80' - r'\u1e82' - r'\u1e84' - r'\u1e86' - r'\u1e88' - r'\u1e8a' - r'\u1e8c' - r'\u1e8e' - r'\u1e90' - r'\u1e92' - r'\u1e94' - r'\u1ea0' - r'\u1ea2' - r'\u1ea4' - r'\u1ea6' - r'\u1ea8' - r'\u1eaa' - r'\u1eac' - r'\u1eae' - r'\u1eb0' - r'\u1eb2' - r'\u1eb4' - r'\u1eb6' - r'\u1eb8' - r'\u1eba' - r'\u1ebc' - r'\u1ebe' - r'\u1ec0' - r'\u1ec2' - r'\u1ec4' - r'\u1ec6' - r'\u1ec8' - r'\u1eca' - r'\u1ecc' - r'\u1ece' - r'\u1ed0' - r'\u1ed2' - r'\u1ed4' - r'\u1ed6' - r'\u1ed8' - r'\u1eda' - r'\u1edc' - r'\u1ede' - r'\u1ee0' - r'\u1ee2' - r'\u1ee4' - r'\u1ee6' - r'\u1ee8' - r'\u1eea' - r'\u1eec' - r'\u1eee' - r'\u1ef0' - r'\u1ef2' - r'\u1ef4' - r'\u1ef6' - r'\u1ef8' - r'\u1f08-\u1f0f' - r'\u1f18-\u1f1d' - r'\u1f28-\u1f2f' - r'\u1f38-\u1f3f' - r'\u1f48-\u1f4d' - r'\u1f59' - r'\u1f5b' - r'\u1f5d' - r'\u1f5f' - r'\u1f68-\u1f6f' - r'\u1fb8-\u1fbb' - r'\u1fc8-\u1fcb' - r'\u1fd8-\u1fdb' - r'\u1fe8-\u1fec' - r'\u1ff8-\u1ffb' - r'\u2102' - r'\u2107' - r'\u210b-\u210d' - r'\u2110-\u2112' - r'\u2115' - r'\u2119-\u211d' - r'\u2124' - r'\u2126' - r'\u2128' - r'\u212a-\u212d' - r'\u2130-\u2133' - r'\u213e' - r'\u213f' - r'\u2145' - r'\u2183' - r'\u2c00-\u2c2e' - r'\u2c60' - r'\u2c62-\u2c64' - r'\u2c67' - r'\u2c69' - r'\u2c6b' - r'\u2c75' - r'\u2c80' - r'\u2c82' - r'\u2c84' - r'\u2c86' - r'\u2c88' - r'\u2c8a' - r'\u2c8c' - r'\u2c8e' - r'\u2c90' - r'\u2c92' - r'\u2c94' - r'\u2c96' - r'\u2c98' - r'\u2c9a' - r'\u2c9c' - r'\u2c9e' - r'\u2ca0' - r'\u2ca2' - r'\u2ca4' - r'\u2ca6' - r'\u2ca8' - r'\u2caa' - r'\u2cac' - r'\u2cae' - r'\u2cb0' - r'\u2cb2' - r'\u2cb4' - r'\u2cb6' - r'\u2cb8' - r'\u2cba' - r'\u2cbc' - r'\u2cbe' - r'\u2cc0' - r'\u2cc2' - r'\u2cc4' - r'\u2cc6' - r'\u2cc8' - r'\u2cca' - r'\u2ccc' - r'\u2cce' - r'\u2cd0' - r'\u2cd2' - r'\u2cd4' - r'\u2cd6' - r'\u2cd8' - r'\u2cda' - r'\u2cdc' - r'\u2cde' - r'\u2ce0' - r'\u2ce2' - r'\uff21-\uff3a'), - - # Decimal numbers. - 'Nd': (r'\u0030-\u0039' - r'\u0660-\u0669' - r'\u06f0-\u06f9' - r'\u07c0-\u07c9' - r'\u0966-\u096f' - r'\u09e6-\u09ef' - r'\u0a66-\u0a6f' - r'\u0ae6-\u0aef' - r'\u0b66-\u0b6f' - r'\u0be6-\u0bef' - r'\u0c66-\u0c6f' - r'\u0ce6-\u0cef' - r'\u0d66-\u0d6f' - r'\u0e50-\u0e59' - r'\u0ed0-\u0ed9' - r'\u0f20-\u0f29' - r'\u1040-\u1049' - r'\u17e0-\u17e9' - r'\u1810-\u1819' - r'\u1946-\u194f' - r'\u19d0-\u19d9' - r'\u1b50-\u1b59' - r'\uff10-\uff19'), -} - - -def re_replace_unicode(regexp): - """Substitute Unicode Properties in regular expressions with their - corresponding expanded ranges. - - Args: - regexp: A regular expression string. - Returns: - Return the regular expression with Unicode Properties substituted. - """ - for category, rangestr in UNICODE_RANGES.items(): - regexp = regexp.replace(r'\p{' + category + '}', rangestr) - return regexp diff --git a/beancount/utils/regexp_utils_test.py b/beancount/utils/regexp_utils_test.py deleted file mode 100644 index 31cf191dd..000000000 --- a/beancount/utils/regexp_utils_test.py +++ /dev/null @@ -1,32 +0,0 @@ -# coding: utf-8 -__copyright__ = "Copyright (C) 2018 Martin Blais" -__license__ = "GNU GPLv2" - -import re -import unittest - -from beancount.utils import regexp_utils - - -def match(regexp, string): - regexp = regexp_utils.re_replace_unicode(regexp) - return re.match("^{}$".format(regexp), string) - - -class TestRegexpUtils(unittest.TestCase): - - def test_replace_unicode(self): - self.assertTrue(match(r"[\p{L}]+", "Assets")) - self.assertFalse(match(r"[\p{L}]+", "Assets:Checking")) - self.assertFalse(match(r"[\p{L}]+", "Checking0")) - self.assertTrue(match(r"[\p{L} ]+", "Adrián Medraño")) - - self.assertFalse(match(r"[\p{Lu}]+", "Assets")) - self.assertTrue(match(r"[\p{Lu}]+", "ASSETS")) - - self.assertFalse(match(r"[\p{Nd}]+", "Assets")) - self.assertTrue(match(r"[\p{Nd}]+", "78654865347")) - - -if __name__ == '__main__': - unittest.main() diff --git a/meson.build b/meson.build index 69742df36..b7d108a24 100644 --- a/meson.build +++ b/meson.build @@ -89,7 +89,6 @@ py.install_sources( beancount/utils/memo.py beancount/utils/misc_utils.py beancount/utils/pager.py - beancount/utils/regexp_utils.py beancount/utils/snoop.py beancount/utils/table.py beancount/utils/test_utils.py diff --git a/pyproject.toml b/pyproject.toml index 0b9fdde31..eeea397e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ requires-python = ">=3.7" dependencies = [ "click >=7.0", "python-dateutil >=2.6.0", + "regex >=2022.9.13", ] dynamic = ["version"] diff --git a/requirements/tools.txt b/requirements/tools.txt index 80423b19b..f582c8fc7 100644 --- a/requirements/tools.txt +++ b/requirements/tools.txt @@ -6,4 +6,5 @@ lxml>=3.0 oauth2client>=4.0 ply>=3.4 python-dateutil>=2.6.0 +regex>=2022.9.13 requests>=2.0 diff --git a/setup.py b/setup.py index 4562f5862..29317bb98 100755 --- a/setup.py +++ b/setup.py @@ -141,6 +141,8 @@ def get_git_changeset(): "click", # Used to generate recurring events in beancounr.scripts.example. "python-dateutil", + # Unicode character class aware regular expressions. + "regex", ], entry_points={ "console_scripts": [ From 45ccf0a1d82b9bc9b17929634cff442d9cff1018 Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Mon, 18 Sep 2023 10:48:25 +0200 Subject: [PATCH 26/36] Normalize unicode representation of filename before regex matching Fixes #750. --- beancount/core/account.py | 9 +++++++-- beancount/core/account_test.py | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/beancount/core/account.py b/beancount/core/account.py index 417ec56c6..21ec4a56d 100644 --- a/beancount/core/account.py +++ b/beancount/core/account.py @@ -9,13 +9,13 @@ import re import os +import unicodedata + from os import path from typing import Any, Callable, Iterable, Iterator, List, Tuple import regex -from beancount.utils import regexp_utils - # Public type for accounts. Account = str @@ -180,6 +180,11 @@ def walk(root_directory: Account) -> Iterator[Tuple[str, Account, List[str], Lis files.sort() relroot = root[len(root_directory)+1:] account_name = relroot.replace(os.sep, sep) + # The regex module does not handle Unicode characters in decomposed + # form. Python uses the normal form for representing string. However, + # some filesystems use the canonical decomposition form. + # See https://docs.python.org/3/library/unicodedata.html#unicodedata.normalize + account_name = unicodedata.normalize('NFKC', account_name) if is_valid(account_name): yield (root, account_name, dirs, files) diff --git a/beancount/core/account_test.py b/beancount/core/account_test.py index 65406b712..800b37106 100644 --- a/beancount/core/account_test.py +++ b/beancount/core/account_test.py @@ -128,6 +128,7 @@ class TestWalk(test_utils.TmpFilesTestBase): 'root/Assets/US/Bank/Checking/otherdir/2014-06-08.bank-statement.pdf', 'root/Assets/US/Bank/Savings/2014-07-01.savings.pdf', 'root/Liabilities/US/Bank/', # Empty directory. + 'root/Assets/Cäsh/2023-08-18.test.pdf', # Unicode directory name. ] def test_walk(self): @@ -136,6 +137,10 @@ def test_walk(self): for root, account_, dirs, files in account.walk(self.root)] self.assertEqual([ + ('/Assets/Cäsh', 'Assets:Cäsh', + [], + ['2023-08-18.test.pdf']), + ('/Assets/US', 'Assets:US', ['Bank'], []), From 5bf52777ac4197555cf80f5b4b1d4b9cab9091a3 Mon Sep 17 00:00:00 2001 From: Zhong Zheng Date: Tue, 26 Sep 2023 22:15:38 +1000 Subject: [PATCH 27/36] remove merge conflict artefacts --- beancount/plugins/close_tree.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/beancount/plugins/close_tree.py b/beancount/plugins/close_tree.py index bdeca486f..1ac464212 100644 --- a/beancount/plugins/close_tree.py +++ b/beancount/plugins/close_tree.py @@ -1,12 +1,6 @@ -<<<<<<< HEAD """This plugin inserts close directives for all of an account's descendants when an account is closed. Unopened parent accounts can also be closed. Any explicitly specified close is left untouched. -======= -"""This plugin inserts close directives for all of an account's descendants when an account -is closed. Unopened parent accounts can also be closed. Any explicitly specified close is -left untouched. ->>>>>>> github/master For example, given this:: From 345efb1901525b66f1dfaf9f4190a8c3d8eea64d Mon Sep 17 00:00:00 2001 From: Daniele Nicolodi Date: Mon, 2 Oct 2023 09:59:27 +0200 Subject: [PATCH 28/36] parser: Allow single uppercase character flags without quote prefix --- beancount/ops/pad_test.py | 18 +- beancount/ops/summarize_test.py | 86 +- beancount/parser/booking_full_test.py | 14 +- beancount/parser/grammar.c | 1110 +++++++++++++------------ beancount/parser/grammar.h | 63 +- beancount/parser/grammar.y | 41 +- beancount/parser/grammar_test.py | 1 + beancount/parser/lexer.c | 688 +++++++-------- beancount/parser/lexer.h | 8 +- beancount/parser/lexer.l | 21 +- beancount/parser/lexer_test.py | 7 +- beancount/parser/printer.py | 2 - 12 files changed, 1069 insertions(+), 990 deletions(-) diff --git a/beancount/ops/pad_test.py b/beancount/ops/pad_test.py index d38e6d93c..b1da7528f 100644 --- a/beancount/ops/pad_test.py +++ b/beancount/ops/pad_test.py @@ -38,7 +38,7 @@ def test_pad_simple(self, entries, errors, __): 2013-05-01 pad Assets:Checking Equity:Opening-Balances ;; Check this is inserted. - 2013-05-01 'P "(Padding inserted for Balance of 172.45 USD for difference 172.45 USD)" + 2013-05-01 P "(Padding inserted for Balance of 172.45 USD for difference 172.45 USD)" Assets:Checking 172.45 USD Equity:Opening-Balances -172.45 USD @@ -75,7 +75,7 @@ def test_pad_to_zero(self, entries, errors, __): 2013-05-01 pad Assets:Checking Equity:Opening-Balances ;; Check this is inserted. - 2013-05-01 'P "(Padding inserted for Balance of 0.00 USD for difference -234.56 USD)" + 2013-05-01 P "(Padding inserted for Balance of 0.00 USD for difference -234.56 USD)" Assets:Checking -234.56 USD Equity:Opening-Balances 234.56 USD @@ -114,7 +114,7 @@ def test_pad_no_overflow(self, entries, errors, __): 2013-05-01 pad Assets:Checking Equity:Opening-Balances - 2013-05-01 'P "(Padding inserted for Balance of 172.45 USD for difference 172.45 USD)" + 2013-05-01 P "(Padding inserted for Balance of 172.45 USD for difference 172.45 USD)" Assets:Checking 172.45 USD Equity:Opening-Balances -172.45 USD @@ -160,7 +160,7 @@ def test_pad_used_twice_legally(self, entries, errors, __): 2013-05-01 pad Assets:Checking Equity:Opening-Balances - 2013-05-01 'P "(Padding inserted for Balance of 172.45 USD for difference 172.45 USD)" + 2013-05-01 P "(Padding inserted for Balance of 172.45 USD for difference 172.45 USD)" Assets:Checking 172.45 USD Equity:Opening-Balances -172.45 USD @@ -172,7 +172,7 @@ def test_pad_used_twice_legally(self, entries, errors, __): 2013-05-20 pad Assets:Checking Equity:Opening-Balances - 2013-05-20 'P "(Padding inserted for Balance of 200 USD for difference 7.55 USD)" + 2013-05-20 P "(Padding inserted for Balance of 200 USD for difference 7.55 USD)" Assets:Checking 7.55 USD Equity:Opening-Balances -7.55 USD @@ -208,7 +208,7 @@ def test_pad_used_twice_illegally(self, entries, errors, __): 2013-05-20 pad Assets:Checking Equity:Opening-Balances - 2013-05-20 'P "(Padding inserted for Balance of 200 USD for difference 200 USD)" + 2013-05-20 P "(Padding inserted for Balance of 200 USD for difference 200 USD)" Assets:Checking 200 USD Equity:Opening-Balances -200 USD @@ -294,7 +294,7 @@ def test_pad_parents(self, entries, errors, __): 2013-05-20 pad Assets:US Equity:Opening-Balances ;; A single pad that does not include child accounts should be inserted. - 2013-05-20 'P "(Padding inserted for Balance of 100.00 USD for difference 90.00 USD)" + 2013-05-20 P "(Padding inserted for Balance of 100.00 USD for difference 90.00 USD)" Assets:US 90.00 USD Equity:Opening-Balances -90.00 USD @@ -339,11 +339,11 @@ def test_pad_multiple_currencies(self, entries, errors, __): 2013-05-20 pad Assets:Checking Equity:Opening-Balances - 2013-05-20 'P "(Padding inserted for Balance of 5.00 USD for difference 4.00 USD)" + 2013-05-20 P "(Padding inserted for Balance of 5.00 USD for difference 4.00 USD)" Assets:Checking 4.00 USD Equity:Opening-Balances -4.00 USD - 2013-05-20 'P "(Padding inserted for Balance of 3.00 CAD for difference 2.00 CAD)" + 2013-05-20 P "(Padding inserted for Balance of 3.00 CAD for difference 2.00 CAD)" Assets:Checking 2.00 CAD Equity:Opening-Balances -2.00 CAD diff --git a/beancount/ops/summarize_test.py b/beancount/ops/summarize_test.py index d3a16908f..b1a05f825 100644 --- a/beancount/ops/summarize_test.py +++ b/beancount/ops/summarize_test.py @@ -101,19 +101,19 @@ def test_open(self): 2012-01-01 open Assets:US:Checking 2012-01-01 open Assets:CA:Checking - 2012-05-31 'S "Opening balance for 'Assets:CA:Checking' (Summarization)" + 2012-05-31 S "Opening balance for 'Assets:CA:Checking' (Summarization)" Assets:CA:Checking 6,000 CAD Equity:Opening-Balances -6,000 CAD - 2012-05-31 'S "Opening balance for 'Assets:US:Checking' (Summarization)" + 2012-05-31 S "Opening balance for 'Assets:US:Checking' (Summarization)" Assets:US:Checking -18,600 USD Equity:Opening-Balances 18,600 USD - 2012-05-31 'S "Opening balance for 'Equity:Earnings:Previous' (Summarization)" + 2012-05-31 S "Opening balance for 'Equity:Earnings:Previous' (Summarization)" Equity:Earnings:Previous 13,600 USD Equity:Opening-Balances -13,600 USD - 2012-05-31 'S "Opening balance for 'Equity:Conversions:Previous' (Summarization)" + 2012-05-31 S "Opening balance for 'Equity:Conversions:Previous' (Summarization)" Equity:Conversions:Previous 5,000 USD Equity:Opening-Balances -5,000 USD Equity:Conversions:Previous -6,000 CAD @@ -190,7 +190,7 @@ def test_close(self): ;; 2012-09-01 END -------------------------------- - 2012-08-31 'C "Conversion for (-8000 USD, 9750 CAD)" + 2012-08-31 C "Conversion for (-8000 USD, 9750 CAD)" Equity:Conversions:Current 8000 USD @ 0 NOTHING Equity:Conversions:Current -9750 CAD @ 0 NOTHING @@ -252,11 +252,11 @@ def test_clear(self): Expenses:Taxes 3600 USD Assets:US:Checking -13600 USD - 2012-12-31 'T "Transfer balance for 'Expenses:Taxes' (Transfer balance)" + 2012-12-31 T "Transfer balance for 'Expenses:Taxes' (Transfer balance)" Expenses:Taxes -10400 USD Equity:Earnings:Current 10400 USD - 2012-12-31 'T "Transfer balance for 'Income:Salary' (Transfer balance)" + 2012-12-31 T "Transfer balance for 'Income:Salary' (Transfer balance)" Income:Salary -31000 USD Equity:Earnings:Current 31000 USD @@ -299,19 +299,19 @@ def test_open_close_clear(self): 2012-01-01 open Assets:US:Checking 2012-01-01 open Assets:CA:Checking - 2012-05-31 'S "Opening balance for 'Assets:CA:Checking' (Summarization)" + 2012-05-31 S "Opening balance for 'Assets:CA:Checking' (Summarization)" Assets:CA:Checking 6,000 CAD Equity:Opening-Balances -6,000 CAD - 2012-05-31 'S "Opening balance for 'Assets:US:Checking' (Summarization)" + 2012-05-31 S "Opening balance for 'Assets:US:Checking' (Summarization)" Assets:US:Checking -18,600 USD Equity:Opening-Balances 18,600 USD - 2012-05-31 'S "Opening balance for 'Equity:Earnings:Previous' (Summarization)" + 2012-05-31 S "Opening balance for 'Equity:Earnings:Previous' (Summarization)" Equity:Earnings:Previous 13,600 USD Equity:Opening-Balances -13,600 USD - 2012-05-31 'S "Opening balance for 'Equity:Conversions:Previous' (Summarization)" + 2012-05-31 S "Opening balance for 'Equity:Conversions:Previous' (Summarization)" Equity:Conversions:Previous 5,000 USD Equity:Opening-Balances -5,000 USD Equity:Conversions:Previous -6,000 CAD @@ -330,15 +330,15 @@ def test_open_close_clear(self): ;; 2012-09-01 END -------------------------------- - 2012-08-31 'C "Conversion for (-3000 USD, 3750 CAD)" + 2012-08-31 C "Conversion for (-3000 USD, 3750 CAD)" Equity:Conversions:Current 3,000 USD @ 0 NOTHING Equity:Conversions:Current -3,750 CAD @ 0 NOTHING - 2012-12-31 'T "Transfer balance for 'Income:Salary' (Transfer balance)" + 2012-12-31 T "Transfer balance for 'Income:Salary' (Transfer balance)" Income:Salary -11,000 USD Equity:Earnings:Current 11,000 USD - 2012-12-31 'T "Transfer balance for 'Expenses:Taxes' (Transfer balance)" + 2012-12-31 T "Transfer balance for 'Expenses:Taxes' (Transfer balance)" Expenses:Taxes -3,200 USD Equity:Earnings:Current 3,200 USD @@ -414,15 +414,15 @@ def test_clamp(self, entries, errors, options_map): 2012-01-01 open Assets:US:Checking 2012-01-01 open Assets:CA:Checking - 2012-05-31 'S "Opening balance for 'Assets:CA:Checking' (Summarization)" + 2012-05-31 S "Opening balance for 'Assets:CA:Checking' (Summarization)" Assets:CA:Checking 6000.00 CAD Equity:Opening-Balances -6000.00 CAD - 2012-05-31 'S "Opening balance for 'Assets:US:Checking' (Summarization)" + 2012-05-31 S "Opening balance for 'Assets:US:Checking' (Summarization)" Assets:US:Checking -18600.00 USD Equity:Opening-Balances 18600.00 USD - 2012-05-31 'S "Opening balance for 'Equity:Earnings' (Summarization)" + 2012-05-31 S "Opening balance for 'Equity:Earnings' (Summarization)" Equity:Earnings 13600.00 USD Equity:Opening-Balances -13600.00 USD @@ -439,7 +439,7 @@ def test_clamp(self, entries, errors, options_map): ;; 2012-09-01 END -------------------------------- - 2012-08-31 'C "Conversion for (-3000.00 USD, 3750.00 CAD)" + 2012-08-31 C "Conversion for (-3000.00 USD, 3750.00 CAD)" Equity:Conversions 3000.00 USD @ 0 NOTHING Equity:Conversions -3750.00 CAD @ 0 NOTHING @@ -480,15 +480,15 @@ def test_cap(self, entries, errors, options_map): self.assertIncludesEntries(entries, capd_entries) self.assertIncludesEntries(""" - 2014-03-01 'T "Transfer balance for 'Expenses:Taxes' (Transfer balance)" + 2014-03-01 T "Transfer balance for 'Expenses:Taxes' (Transfer balance)" Expenses:Taxes -3500.00 USD Equity:Earnings 3500.00 USD - 2014-03-01 'T "Transfer balance for 'Income:Salary' (Transfer balance)" + 2014-03-01 T "Transfer balance for 'Income:Salary' (Transfer balance)" Income:Salary -10000.00 USD Equity:Earnings 10000.00 USD - 2014-03-01 'C "Conversion for (-5000.00 USD, 6000.00 CAD)" + 2014-03-01 C "Conversion for (-5000.00 USD, 6000.00 CAD)" Equity:Conversions 5000.00 USD @ 0 NOTHING Equity:Conversions -6000.00 CAD @ 0 NOTHING @@ -649,7 +649,7 @@ def test_transfer_balances__middle_assets(self): INPUT_PERIOD), xfer_entries) self.assertIncludesEntries(""" - 2010-12-31 'T "Transfer balance for 'Assets:US:Chase:Checking' (Transfer balance)" + 2010-12-31 T "Transfer balance for 'Assets:US:Chase:Checking' (Transfer balance)" Assets:US:Chase:Checking -2459.98 USD Equity:Transfer 2459.98 USD @@ -665,7 +665,7 @@ def test_transfer_balances__middle_at_cost(self): self.assertIncludesEntries(self.entries, xfer_entries) self.assertIncludesEntries(""" - 2010-12-31 'T "Transfer balance for 'Assets:US:Investing:HOOL' (Transfer balance)" + 2010-12-31 T "Transfer balance for 'Assets:US:Investing:HOOL' (Transfer balance)" Assets:US:Investing:HOOL -5 HOOL {510.00 USD, 2010-12-05} ; -2550.00 USD Equity:Transfer 2550.00 USD ; 2550.00 USD @@ -684,7 +684,7 @@ def test_transfer_balances__end_assets_implicit(self): INPUT_PERIOD), xfer_entries) self.assertIncludesEntries(""" - 2011-02-28 'T "Transfer balance for 'Assets:US:Chase:Checking' (Transfer balance)" + 2011-02-28 T "Transfer balance for 'Assets:US:Chase:Checking' (Transfer balance)" Assets:US:Chase:Checking -8459.98 USD Equity:Transfer 8459.98 USD @@ -699,7 +699,7 @@ def test_transfer_balances__end_assets_explicit(self): self.assertIncludesEntries(self.entries, xfer_entries) self.assertIncludesEntries(""" - 2011-04-01 'T "Transfer balance for 'Assets:US:Chase:Checking' (Transfer balance)" + 2011-04-01 T "Transfer balance for 'Assets:US:Chase:Checking' (Transfer balance)" Assets:US:Chase:Checking -8459.98 USD Equity:Transfer 8459.98 USD @@ -715,23 +715,23 @@ def test_transfer_balances__middle_income(self): self.assertIncludesEntries(self.entries, xfer_entries) self.assertIncludesEntries(""" - 2010-12-31 'T "Transfer balance for 'Expenses:Flights' (Transfer balance)" + 2010-12-31 T "Transfer balance for 'Expenses:Flights' (Transfer balance)" Expenses:Flights -345.23 USD Equity:Transfer 345.23 USD - 2010-12-31 'T "Transfer balance for 'Expenses:Internet' (Transfer balance)" + 2010-12-31 T "Transfer balance for 'Expenses:Internet' (Transfer balance)" Expenses:Internet -80.02 USD Equity:Transfer 80.02 USD - 2010-12-31 'T "Transfer balance for 'Expenses:Restaurant' (Transfer balance)" + 2010-12-31 T "Transfer balance for 'Expenses:Restaurant' (Transfer balance)" Expenses:Restaurant -67.20 USD Equity:Transfer 67.20 USD - 2010-12-31 'T "Transfer balance for 'Expenses:Taxes' (Transfer balance)" + 2010-12-31 T "Transfer balance for 'Expenses:Taxes' (Transfer balance)" Expenses:Taxes -4000.00 USD Equity:Transfer 4000.00 USD - 2010-12-31 'T "Transfer balance for 'Income:US:Employer:Salary' (Transfer balance)" + 2010-12-31 T "Transfer balance for 'Income:US:Employer:Salary' (Transfer balance)" Income:US:Employer:Salary 10000.00 USD Equity:Transfer -10000.00 USD @@ -763,39 +763,39 @@ def test_summarize__complete(self): entry.flag == flags.FLAG_SUMMARIZE)] self.assertEqualEntries(""" - 2010-12-31 'S "Opening balance for 'Assets:CA:BMO:Checking' (Summarization)" + 2010-12-31 S "Opening balance for 'Assets:CA:BMO:Checking' (Summarization)" Assets:CA:BMO:Checking 1000.00 CAD Equity:Opening-Balances -1000.00 CAD - 2010-12-31 'S "Opening balance for 'Assets:US:Chase:Checking' (Summarization)" + 2010-12-31 S "Opening balance for 'Assets:US:Chase:Checking' (Summarization)" Assets:US:Chase:Checking 2459.98 USD Equity:Opening-Balances -2459.98 USD - 2010-12-31 'S "Opening balance for 'Assets:US:Investing:HOOL' (Summarization)" + 2010-12-31 S "Opening balance for 'Assets:US:Investing:HOOL' (Summarization)" Assets:US:Investing:HOOL 5 HOOL {510.00 USD, 2010-12-05} ; 2550.00 USD Equity:Opening-Balances -2550.00 USD ; -2550.00 USD - 2010-12-31 'S "Opening balance for 'Expenses:Flights' (Summarization)" + 2010-12-31 S "Opening balance for 'Expenses:Flights' (Summarization)" Expenses:Flights 345.23 USD Equity:Opening-Balances -345.23 USD - 2010-12-31 'S "Opening balance for 'Expenses:Internet' (Summarization)" + 2010-12-31 S "Opening balance for 'Expenses:Internet' (Summarization)" Expenses:Internet 80.02 USD Equity:Opening-Balances -80.02 USD - 2010-12-31 'S "Opening balance for 'Expenses:Restaurant' (Summarization)" + 2010-12-31 S "Opening balance for 'Expenses:Restaurant' (Summarization)" Expenses:Restaurant 67.20 USD Equity:Opening-Balances -67.20 USD - 2010-12-31 'S "Opening balance for 'Expenses:Taxes' (Summarization)" + 2010-12-31 S "Opening balance for 'Expenses:Taxes' (Summarization)" Expenses:Taxes 4000.00 USD Equity:Opening-Balances -4000.00 USD - 2010-12-31 'S "Opening balance for 'Income:US:Employer:Salary' (Summarization)" + 2010-12-31 S "Opening balance for 'Income:US:Employer:Salary' (Summarization)" Income:US:Employer:Salary -10000.00 USD Equity:Opening-Balances 10000.00 USD - 2010-12-31 'S "Opening balance for 'Liabilities:US:Chase:CreditCard' (Summarization)" + 2010-12-31 S "Opening balance for 'Liabilities:US:Chase:CreditCard' (Summarization)" Liabilities:US:Chase:CreditCard -412.43 USD Equity:Opening-Balances 412.43 USD @@ -901,7 +901,7 @@ def test_conversions__needed_middle(self): self.assertIncludesEntries(self.entries, conversion_entries) self.assertIncludesEntries(""" - 2012-03-02 'C "Conversion for (-800.00 USD, 800.00 CAD)" + 2012-03-02 C "Conversion for (-800.00 USD, 800.00 CAD)" Equity:Conversions 800.00 USD @ 0 NOTHING Equity:Conversions -800.00 CAD @ 0 NOTHING @@ -918,7 +918,7 @@ def test_conversions__with_transactions_at_cost(self): self.assertIncludesEntries(self.entries, conversion_entries) self.assertIncludesEntries(""" - 2012-03-09 'C "Conversion for (-800.00 USD, 200.00 CAD, 60 NT {10 CAD, 2012-03-03})" + 2012-03-09 C "Conversion for (-800.00 USD, 200.00 CAD, 60 NT {10 CAD, 2012-03-03})" Equity:Conversions 800.00 USD @ 0 XFER Equity:Conversions -800.00 CAD @ 0 XFER @@ -936,7 +936,7 @@ def test_conversions__multiple(self): self.assertIncludesEntries(self.entries, conversion_entries) self.assertIncludesEntries(""" - 2012-05-09 'C "Conversion for (-700.00 USD, 100.00 CAD, 60 NT {10 CAD, 2012-03-03})" + 2012-05-09 C "Conversion for (-700.00 USD, 100.00 CAD, 60 NT {10 CAD, 2012-03-03})" Equity:Conversions 700.00 USD @ 0 NOTHING Equity:Conversions -700.00 CAD @ 0 NOTHING @@ -951,7 +951,7 @@ def test_conversions__no_date(self): self.assertIncludesEntries(self.entries, conversion_entries) self.assertIncludesEntries(""" - 2012-05-01 'C "Conversion for (-700.00 USD, 100.00 CAD, 60 NT {10 CAD, 2012-03-03})" + 2012-05-01 C "Conversion for (-700.00 USD, 100.00 CAD, 60 NT {10 CAD, 2012-03-03})" Equity:Conversions 700.00 USD @ 0 NOTHING Equity:Conversions -700.00 CAD @ 0 NOTHING diff --git a/beancount/parser/booking_full_test.py b/beancount/parser/booking_full_test.py index 2256480b8..21fa1ba89 100644 --- a/beancount/parser/booking_full_test.py +++ b/beancount/parser/booking_full_test.py @@ -1402,7 +1402,7 @@ def test_augment__from_empty__at_cost__pos(self, _, __): Assets:Account 1 HOOL {100.00 USD, 2015-10-01} 2015-10-01 * #reduced - 'S Assets:Account 1 HOOL {100.00 USD, 2015-10-01} + S Assets:Account 1 HOOL {100.00 USD, 2015-10-01} """ @book_test(Booking.STRICT) @@ -1415,7 +1415,7 @@ def test_augment__from_empty__at_cost__neg(self, _, __): Assets:Account -1 HOOL {100.00 USD, 2015-10-01} 2015-10-01 * #reduced - 'S Assets:Account -1 HOOL {100.00 USD, 2015-10-01} + S Assets:Account -1 HOOL {100.00 USD, 2015-10-01} """ @book_test(Booking.STRICT) @@ -1446,7 +1446,7 @@ def test_augment__from_empty__incomplete_cost__with_currency(self, entries, __): Assets:Account 1 HOOL {0 USD, 2015-10-01} 2015-10-01 * #reduced - 'S Assets:Account 1 HOOL {USD, 2015-10-01} + S Assets:Account 1 HOOL {USD, 2015-10-01} """ # Further test what would happen if book_reductions() would be called anyhow. entry = find_first_with_tag('apply', entries) @@ -1579,7 +1579,7 @@ def test_reduce__ambiguous__none(self, _, __): Assets:Account -5 HOOL {117.00 USD, 2016-05-02} 2016-05-02 * #reduced - 'S Assets:Account -5 HOOL {117.00 USD, 2016-05-02} + S Assets:Account -5 HOOL {117.00 USD, 2016-05-02} 2016-01-01 * #ex Assets:Account 1 HOOL {115.00 USD, 2016-01-01} @@ -1601,7 +1601,7 @@ def test_reduce__ambiguous__none__from_mixed(self, _, __): Assets:Account -5 HOOL {117.00 USD, 2016-05-02} 2016-05-02 * #reduced - 'S Assets:Account -5 HOOL {117.00 USD, 2016-05-02} + S Assets:Account -5 HOOL {117.00 USD, 2016-05-02} 2016-01-01 * #ex Assets:Account 1 HOOL {115.00 USD, 2016-01-01} @@ -2105,7 +2105,7 @@ def test_ambiguous__FIFO__no_match_against_any_lots(self, _, __): Assets:Account 0 HOOL {} 2015-02-22 * #reduced - 'S Assets:Account 0 HOOL {USD, 2015-02-22} + S Assets:Account 0 HOOL {USD, 2015-02-22} 2015-02-22 * #booked @@ -2262,7 +2262,7 @@ def test_ambiguous__LIFO__no_match_against_any_lots(self, _, __): Assets:Account 0 HOOL {} 2015-02-22 * #reduced - 'S Assets:Account 0 HOOL {USD, 2015-02-22} + S Assets:Account 0 HOOL {USD, 2015-02-22} 2015-02-22 * #booked diff --git a/beancount/parser/grammar.c b/beancount/parser/grammar.c index 211a210ae..73aa4ce11 100644 --- a/beancount/parser/grammar.c +++ b/beancount/parser/grammar.c @@ -197,88 +197,90 @@ enum yysymbol_kind_t YYSYMBOL_LPAREN = 20, /* LPAREN */ YYSYMBOL_RPAREN = 21, /* RPAREN */ YYSYMBOL_FLAG = 22, /* FLAG */ - YYSYMBOL_TXN = 23, /* TXN */ - YYSYMBOL_BALANCE = 24, /* BALANCE */ - YYSYMBOL_OPEN = 25, /* OPEN */ - YYSYMBOL_CLOSE = 26, /* CLOSE */ - YYSYMBOL_COMMODITY = 27, /* COMMODITY */ - YYSYMBOL_PAD = 28, /* PAD */ - YYSYMBOL_EVENT = 29, /* EVENT */ - YYSYMBOL_PRICE = 30, /* PRICE */ - YYSYMBOL_NOTE = 31, /* NOTE */ - YYSYMBOL_DOCUMENT = 32, /* DOCUMENT */ - YYSYMBOL_QUERY = 33, /* QUERY */ - YYSYMBOL_CUSTOM = 34, /* CUSTOM */ - YYSYMBOL_PUSHTAG = 35, /* PUSHTAG */ - YYSYMBOL_POPTAG = 36, /* POPTAG */ - YYSYMBOL_PUSHMETA = 37, /* PUSHMETA */ - YYSYMBOL_POPMETA = 38, /* POPMETA */ - YYSYMBOL_OPTION = 39, /* OPTION */ - YYSYMBOL_INCLUDE = 40, /* INCLUDE */ - YYSYMBOL_PLUGIN = 41, /* PLUGIN */ - YYSYMBOL_NONE = 42, /* NONE */ - YYSYMBOL_BOOL = 43, /* BOOL */ - YYSYMBOL_DATE = 44, /* DATE */ - YYSYMBOL_ACCOUNT = 45, /* ACCOUNT */ - YYSYMBOL_CURRENCY = 46, /* CURRENCY */ - YYSYMBOL_STRING = 47, /* STRING */ - YYSYMBOL_NUMBER = 48, /* NUMBER */ - YYSYMBOL_TAG = 49, /* TAG */ - YYSYMBOL_LINK = 50, /* LINK */ - YYSYMBOL_KEY = 51, /* KEY */ - YYSYMBOL_NEGATIVE = 52, /* NEGATIVE */ - YYSYMBOL_YYACCEPT = 53, /* $accept */ - YYSYMBOL_txn = 54, /* txn */ - YYSYMBOL_eol = 55, /* eol */ - YYSYMBOL_number_expr = 56, /* number_expr */ - YYSYMBOL_txn_strings = 57, /* txn_strings */ - YYSYMBOL_tags_links = 58, /* tags_links */ - YYSYMBOL_transaction = 59, /* transaction */ - YYSYMBOL_optflag = 60, /* optflag */ - YYSYMBOL_price_annotation = 61, /* price_annotation */ - YYSYMBOL_account = 62, /* account */ - YYSYMBOL_posting = 63, /* posting */ - YYSYMBOL_key_value = 64, /* key_value */ - YYSYMBOL_key_value_line = 65, /* key_value_line */ - YYSYMBOL_key_value_value = 66, /* key_value_value */ - YYSYMBOL_posting_or_kv_list = 67, /* posting_or_kv_list */ - YYSYMBOL_key_value_list = 68, /* key_value_list */ - YYSYMBOL_currency_list = 69, /* currency_list */ - YYSYMBOL_pushtag = 70, /* pushtag */ - YYSYMBOL_poptag = 71, /* poptag */ - YYSYMBOL_pushmeta = 72, /* pushmeta */ - YYSYMBOL_popmeta = 73, /* popmeta */ - YYSYMBOL_open = 74, /* open */ - YYSYMBOL_opt_booking = 75, /* opt_booking */ - YYSYMBOL_close = 76, /* close */ - YYSYMBOL_commodity = 77, /* commodity */ - YYSYMBOL_pad = 78, /* pad */ - YYSYMBOL_balance = 79, /* balance */ - YYSYMBOL_amount = 80, /* amount */ - YYSYMBOL_amount_tolerance = 81, /* amount_tolerance */ - YYSYMBOL_maybe_number = 82, /* maybe_number */ - YYSYMBOL_maybe_currency = 83, /* maybe_currency */ - YYSYMBOL_compound_amount = 84, /* compound_amount */ - YYSYMBOL_incomplete_amount = 85, /* incomplete_amount */ - YYSYMBOL_cost_spec = 86, /* cost_spec */ - YYSYMBOL_cost_comp_list = 87, /* cost_comp_list */ - YYSYMBOL_cost_comp = 88, /* cost_comp */ - YYSYMBOL_price = 89, /* price */ - YYSYMBOL_event = 90, /* event */ - YYSYMBOL_query = 91, /* query */ - YYSYMBOL_note = 92, /* note */ - YYSYMBOL_filename = 93, /* filename */ - YYSYMBOL_document = 94, /* document */ - YYSYMBOL_custom_value = 95, /* custom_value */ - YYSYMBOL_custom_value_list = 96, /* custom_value_list */ - YYSYMBOL_custom = 97, /* custom */ - YYSYMBOL_entry = 98, /* entry */ - YYSYMBOL_option = 99, /* option */ - YYSYMBOL_include = 100, /* include */ - YYSYMBOL_plugin = 101, /* plugin */ - YYSYMBOL_directive = 102, /* directive */ - YYSYMBOL_declarations = 103, /* declarations */ - YYSYMBOL_file = 104 /* file */ + YYSYMBOL_CAPITAL = 23, /* CAPITAL */ + YYSYMBOL_TXN = 24, /* TXN */ + YYSYMBOL_BALANCE = 25, /* BALANCE */ + YYSYMBOL_OPEN = 26, /* OPEN */ + YYSYMBOL_CLOSE = 27, /* CLOSE */ + YYSYMBOL_COMMODITY = 28, /* COMMODITY */ + YYSYMBOL_PAD = 29, /* PAD */ + YYSYMBOL_EVENT = 30, /* EVENT */ + YYSYMBOL_PRICE = 31, /* PRICE */ + YYSYMBOL_NOTE = 32, /* NOTE */ + YYSYMBOL_DOCUMENT = 33, /* DOCUMENT */ + YYSYMBOL_QUERY = 34, /* QUERY */ + YYSYMBOL_CUSTOM = 35, /* CUSTOM */ + YYSYMBOL_PUSHTAG = 36, /* PUSHTAG */ + YYSYMBOL_POPTAG = 37, /* POPTAG */ + YYSYMBOL_PUSHMETA = 38, /* PUSHMETA */ + YYSYMBOL_POPMETA = 39, /* POPMETA */ + YYSYMBOL_OPTION = 40, /* OPTION */ + YYSYMBOL_INCLUDE = 41, /* INCLUDE */ + YYSYMBOL_PLUGIN = 42, /* PLUGIN */ + YYSYMBOL_NONE = 43, /* NONE */ + YYSYMBOL_BOOL = 44, /* BOOL */ + YYSYMBOL_DATE = 45, /* DATE */ + YYSYMBOL_ACCOUNT = 46, /* ACCOUNT */ + YYSYMBOL_CURRENCY = 47, /* CURRENCY */ + YYSYMBOL_STRING = 48, /* STRING */ + YYSYMBOL_NUMBER = 49, /* NUMBER */ + YYSYMBOL_TAG = 50, /* TAG */ + YYSYMBOL_LINK = 51, /* LINK */ + YYSYMBOL_KEY = 52, /* KEY */ + YYSYMBOL_NEGATIVE = 53, /* NEGATIVE */ + YYSYMBOL_YYACCEPT = 54, /* $accept */ + YYSYMBOL_txn = 55, /* txn */ + YYSYMBOL_eol = 56, /* eol */ + YYSYMBOL_number_expr = 57, /* number_expr */ + YYSYMBOL_currency = 58, /* currency */ + YYSYMBOL_txn_strings = 59, /* txn_strings */ + YYSYMBOL_tags_links = 60, /* tags_links */ + YYSYMBOL_transaction = 61, /* transaction */ + YYSYMBOL_optflag = 62, /* optflag */ + YYSYMBOL_price_annotation = 63, /* price_annotation */ + YYSYMBOL_account = 64, /* account */ + YYSYMBOL_posting = 65, /* posting */ + YYSYMBOL_key_value = 66, /* key_value */ + YYSYMBOL_key_value_line = 67, /* key_value_line */ + YYSYMBOL_key_value_value = 68, /* key_value_value */ + YYSYMBOL_posting_or_kv_list = 69, /* posting_or_kv_list */ + YYSYMBOL_key_value_list = 70, /* key_value_list */ + YYSYMBOL_currency_list = 71, /* currency_list */ + YYSYMBOL_pushtag = 72, /* pushtag */ + YYSYMBOL_poptag = 73, /* poptag */ + YYSYMBOL_pushmeta = 74, /* pushmeta */ + YYSYMBOL_popmeta = 75, /* popmeta */ + YYSYMBOL_open = 76, /* open */ + YYSYMBOL_opt_booking = 77, /* opt_booking */ + YYSYMBOL_close = 78, /* close */ + YYSYMBOL_commodity = 79, /* commodity */ + YYSYMBOL_pad = 80, /* pad */ + YYSYMBOL_balance = 81, /* balance */ + YYSYMBOL_amount = 82, /* amount */ + YYSYMBOL_amount_tolerance = 83, /* amount_tolerance */ + YYSYMBOL_maybe_number = 84, /* maybe_number */ + YYSYMBOL_maybe_currency = 85, /* maybe_currency */ + YYSYMBOL_compound_amount = 86, /* compound_amount */ + YYSYMBOL_incomplete_amount = 87, /* incomplete_amount */ + YYSYMBOL_cost_spec = 88, /* cost_spec */ + YYSYMBOL_cost_comp_list = 89, /* cost_comp_list */ + YYSYMBOL_cost_comp = 90, /* cost_comp */ + YYSYMBOL_price = 91, /* price */ + YYSYMBOL_event = 92, /* event */ + YYSYMBOL_query = 93, /* query */ + YYSYMBOL_note = 94, /* note */ + YYSYMBOL_filename = 95, /* filename */ + YYSYMBOL_document = 96, /* document */ + YYSYMBOL_custom_value = 97, /* custom_value */ + YYSYMBOL_custom_value_list = 98, /* custom_value_list */ + YYSYMBOL_custom = 99, /* custom */ + YYSYMBOL_entry = 100, /* entry */ + YYSYMBOL_option = 101, /* option */ + YYSYMBOL_include = 102, /* include */ + YYSYMBOL_plugin = 103, /* plugin */ + YYSYMBOL_directive = 104, /* directive */ + YYSYMBOL_declarations = 105, /* declarations */ + YYSYMBOL_file = 106 /* file */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; @@ -609,19 +611,19 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 35 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 269 +#define YYLAST 332 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 53 +#define YYNTOKENS 54 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 52 +#define YYNNTS 53 /* YYNRULES -- Number of rules. */ -#define YYNRULES 131 +#define YYNRULES 135 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 224 +#define YYNSTATES 228 /* YYMAXUTOK -- Last valid token kind. */ -#define YYMAXUTOK 307 +#define YYMAXUTOK 308 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM @@ -665,27 +667,27 @@ static const yytype_int8 yytranslate[] = 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52 + 45, 46, 47, 48, 49, 50, 51, 52, 53 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { - 0, 287, 287, 291, 295, 299, 304, 304, 311, 312, - 317, 322, 327, 332, 337, 341, 347, 352, 357, 365, - 370, 375, 382, 389, 393, 397, 401, 404, 407, 414, - 419, 424, 429, 436, 443, 449, 450, 451, 452, 453, - 454, 455, 456, 457, 458, 465, 470, 474, 479, 484, - 491, 496, 500, 507, 512, 517, 524, 531, 538, 548, - 555, 562, 563, 570, 577, 584, 591, 598, 605, 612, - 620, 621, 628, 629, 636, 641, 646, 654, 661, 666, - 671, 678, 683, 688, 695, 696, 697, 698, 705, 712, - 719, 726, 732, 735, 742, 747, 752, 757, 762, 767, - 778, 783, 790, 797, 798, 799, 800, 801, 802, 803, - 804, 805, 806, 807, 808, 811, 818, 825, 830, 837, - 838, 839, 840, 841, 842, 843, 846, 847, 848, 853, - 871, 879 + 0, 289, 289, 293, 297, 301, 305, 310, 310, 317, + 318, 323, 328, 333, 338, 343, 347, 353, 357, 363, + 368, 373, 381, 386, 391, 398, 405, 409, 413, 417, + 418, 421, 424, 431, 436, 441, 446, 453, 460, 466, + 467, 468, 469, 470, 471, 472, 473, 474, 475, 482, + 487, 491, 496, 501, 508, 513, 517, 524, 529, 534, + 541, 548, 555, 565, 572, 579, 580, 587, 594, 601, + 608, 615, 622, 629, 637, 638, 645, 646, 653, 658, + 663, 671, 678, 683, 688, 695, 700, 705, 712, 713, + 714, 715, 722, 729, 736, 743, 749, 752, 759, 764, + 769, 774, 779, 784, 795, 800, 807, 814, 815, 816, + 817, 818, 819, 820, 821, 822, 823, 824, 825, 828, + 835, 842, 847, 854, 855, 856, 857, 858, 859, 860, + 863, 864, 865, 870, 888, 896 }; #endif @@ -704,14 +706,14 @@ static const char *const yytname[] = "\"end of file\"", "error", "\"invalid token\"", "INDENT", "EOL", "PIPE", "ATAT", "AT", "LCURLCURL", "RCURLCURL", "LCURL", "RCURL", "COMMA", "TILDE", "HASH", "ASTERISK", "SLASH", "COLON", "PLUS", "MINUS", - "LPAREN", "RPAREN", "FLAG", "TXN", "BALANCE", "OPEN", "CLOSE", + "LPAREN", "RPAREN", "FLAG", "CAPITAL", "TXN", "BALANCE", "OPEN", "CLOSE", "COMMODITY", "PAD", "EVENT", "PRICE", "NOTE", "DOCUMENT", "QUERY", "CUSTOM", "PUSHTAG", "POPTAG", "PUSHMETA", "POPMETA", "OPTION", "INCLUDE", "PLUGIN", "NONE", "BOOL", "DATE", "ACCOUNT", "CURRENCY", "STRING", "NUMBER", "TAG", "LINK", "KEY", "NEGATIVE", "$accept", "txn", - "eol", "number_expr", "txn_strings", "tags_links", "transaction", - "optflag", "price_annotation", "account", "posting", "key_value", - "key_value_line", "key_value_value", "posting_or_kv_list", + "eol", "number_expr", "currency", "txn_strings", "tags_links", + "transaction", "optflag", "price_annotation", "account", "posting", + "key_value", "key_value_line", "key_value_value", "posting_or_kv_list", "key_value_list", "currency_list", "pushtag", "poptag", "pushmeta", "popmeta", "open", "opt_booking", "close", "commodity", "pad", "balance", "amount", "amount_tolerance", "maybe_number", "maybe_currency", @@ -728,12 +730,12 @@ yysymbol_name (yysymbol_kind_t yysymbol) } #endif -#define YYPACT_NINF (-104) +#define YYPACT_NINF (-114) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) -#define YYTABLE_NINF (-82) +#define YYTABLE_NINF (-86) #define yytable_value_is_error(Yyn) \ 0 @@ -742,29 +744,29 @@ yysymbol_name (yysymbol_kind_t yysymbol) STATE-NUM. */ static const yytype_int16 yypact[] = { - -104, 126, 48, -104, -104, -104, -28, 9, 16, 18, - 25, 28, 37, 235, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, 85, 85, 70, 85, - 74, 47, 85, 43, -104, -104, -104, -104, 53, 53, - 53, 54, 53, 69, 79, 53, 53, 86, 91, -104, - -104, -104, -104, -104, 196, -104, 85, 85, -104, 85, - -104, -104, 206, 93, 85, 85, 53, 98, 206, 102, - 109, 122, -104, 21, 206, 206, 206, -104, -104, -104, - -104, -104, -104, -104, 113, -104, -104, -104, -104, -104, - -104, 189, 85, -104, -11, -104, -104, 85, 85, 113, - 85, -104, -104, -104, 85, 99, -104, -104, 55, -104, - -104, 212, 206, 206, 206, 206, -104, 206, -104, -104, - 106, -104, 85, 172, 172, -104, -104, -104, 55, 55, - -104, -104, -104, -104, -104, 113, -104, -104, -104, -104, - -104, -104, -104, -104, -104, 105, 105, 202, 172, -104, - -104, 42, -104, 172, 172, 172, -104, -104, 172, 172, - 173, -104, 172, -104, 85, 172, 172, 35, -104, -104, - -104, -104, -104, -104, -104, 55, 53, -104, 88, -104, - 139, 132, -1, -104, -104, 165, 175, 27, -104, -104, - -104, 95, -2, -104, 6, -104, 111, 206, 206, -104, - -104, 206, -104, -104, 153, -104, 85, -104, 85, 136, - -104, -104, -104, -104 + -114, 187, 32, -114, -114, -114, -27, -16, -4, 2, + 10, 21, 27, 297, -114, -114, -114, -114, -114, -114, + -114, -114, -114, -114, -114, -114, -114, -114, -114, -114, + -114, -114, -114, -114, -114, -114, 25, 25, 55, 25, + 80, 52, 25, 9, -114, -114, -114, -114, -114, 65, + 65, 65, 12, 65, 66, 12, 65, 65, 73, 76, + -114, -114, -114, -114, -114, 260, -114, 25, 25, -114, + 25, -114, -114, 0, 12, 25, -114, -114, 25, 65, + 82, 0, 89, 94, 96, -114, 5, 0, 0, 0, + -114, -114, -114, -114, -114, -114, 113, -114, -114, -114, + -114, -114, -114, -114, 234, 25, -114, 4, -114, -114, + 25, 25, 113, 25, -114, -114, -114, 25, 149, -114, + -114, 11, -114, -114, 24, 0, 0, 0, 0, -114, + 0, -114, -114, 12, -114, 25, 110, 110, -114, -114, + -114, 11, 11, -114, -114, -114, -114, -114, 113, -114, + -114, -114, -114, -114, -114, -114, -114, -114, 67, 67, + 113, 110, -114, -114, 8, -114, 110, 110, 110, -114, + -114, 110, 110, 131, -114, 110, -114, 25, 110, 110, + 87, -114, -114, -114, -114, -114, -114, -114, -114, 11, + 65, -114, 162, -114, 155, 12, 56, -114, -114, 194, + 226, 86, -114, -114, -114, 254, 23, -114, 35, -114, + 95, 0, 0, -114, -114, 0, -114, -114, 215, -114, + 25, -114, 25, 12, -114, -114, -114, -114 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -772,51 +774,51 @@ static const yytype_int16 yypact[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 130, 0, 0, 131, 129, 126, 0, 0, 0, 0, - 0, 0, 0, 0, 103, 119, 120, 121, 122, 105, - 106, 112, 107, 104, 111, 110, 113, 109, 108, 114, - 128, 123, 124, 125, 127, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 5, 4, 3, 2, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, - 7, 6, 56, 57, 44, 58, 0, 0, 116, 0, - 117, 28, 0, 53, 0, 0, 0, 0, 0, 0, - 0, 0, 100, 19, 0, 0, 0, 41, 40, 37, - 38, 35, 8, 39, 42, 36, 33, 43, 59, 115, - 118, 0, 0, 54, 62, 50, 50, 0, 0, 0, - 0, 19, 92, 19, 0, 0, 18, 17, 0, 14, - 13, 0, 0, 0, 0, 0, 67, 0, 68, 50, - 0, 61, 0, 63, 64, 50, 50, 50, 0, 0, - 50, 96, 95, 94, 50, 98, 99, 97, 101, 21, - 20, 45, 15, 11, 12, 9, 10, 0, 66, 55, - 50, 0, 52, 65, 89, 88, 50, 50, 90, 102, - 22, 69, 60, 51, 0, 91, 93, 19, 49, 48, - 34, 25, 24, 26, 46, 0, 0, 47, 71, 32, - 70, 73, 80, 72, 77, 71, 71, 0, 87, 85, - 86, 73, 0, 84, 0, 82, 0, 71, 71, 29, - 75, 71, 74, 79, 71, 78, 0, 27, 0, 0, - 83, 31, 30, 76 + 134, 0, 0, 135, 133, 130, 0, 0, 0, 0, + 0, 0, 0, 0, 107, 123, 124, 125, 126, 109, + 110, 116, 111, 108, 115, 114, 117, 113, 112, 118, + 132, 127, 128, 129, 131, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 4, 3, 6, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 19, 8, 7, 60, 61, 48, 62, 0, 0, 120, + 0, 121, 32, 0, 57, 0, 18, 17, 0, 0, + 0, 0, 0, 0, 0, 104, 22, 0, 0, 0, + 45, 44, 41, 39, 9, 43, 46, 42, 40, 37, + 47, 63, 119, 122, 0, 0, 58, 66, 54, 54, + 0, 0, 0, 0, 22, 96, 22, 0, 0, 21, + 20, 0, 15, 14, 0, 0, 0, 0, 0, 71, + 0, 72, 54, 0, 65, 0, 67, 68, 54, 54, + 54, 0, 0, 54, 100, 99, 98, 54, 102, 103, + 101, 105, 24, 23, 49, 16, 12, 13, 10, 11, + 0, 70, 59, 54, 0, 56, 69, 93, 92, 54, + 54, 94, 106, 25, 73, 64, 55, 0, 95, 97, + 22, 53, 52, 38, 28, 27, 29, 30, 50, 0, + 0, 51, 75, 36, 74, 77, 84, 76, 81, 75, + 75, 0, 91, 89, 90, 77, 0, 88, 0, 86, + 0, 75, 75, 33, 79, 75, 78, 83, 75, 82, + 0, 31, 0, 0, 87, 35, 34, 80 }; /* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = +static const yytype_int8 yypgoto[] = { - -104, -104, -37, -61, -104, -103, -104, -104, -20, -36, - -104, 181, 22, -104, -104, -84, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -74, -104, -99, - -10, -104, 8, -104, 2, -15, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, -104 + -114, -114, -37, -10, -48, -114, -113, -114, -114, -66, + -29, -114, 127, -28, -114, -114, -44, -114, -114, -114, + -114, -114, -114, -114, -114, -114, -114, -114, -67, -114, + -77, -57, -114, -42, -114, -49, -64, -114, -114, -114, + -114, -114, -114, -114, -114, -114, -114, -114, -114, -114, + -114, -114, -114 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_uint8 yydefgoto[] = { - 0, 59, 62, 190, 83, 118, 14, 186, 216, 72, - 178, 174, 162, 96, 170, 133, 104, 15, 16, 17, - 18, 19, 132, 20, 21, 22, 23, 97, 102, 191, - 194, 203, 217, 197, 204, 205, 24, 25, 26, 27, - 113, 28, 148, 115, 29, 30, 31, 32, 33, 34, - 1, 2 + 0, 60, 63, 194, 129, 86, 121, 14, 190, 220, + 73, 181, 177, 165, 99, 173, 136, 107, 15, 16, + 17, 18, 19, 135, 20, 21, 22, 23, 100, 105, + 195, 198, 207, 221, 201, 208, 209, 24, 25, 26, + 27, 116, 28, 151, 118, 29, 30, 31, 32, 33, + 34, 1, 2 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -824,131 +826,145 @@ static const yytype_uint8 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { - 63, 130, 65, 94, 110, 68, 70, 195, 138, 196, - 139, 101, 211, 73, 74, 213, 76, 109, 214, 79, - 80, 36, 134, 119, 120, 121, 116, 60, 95, 98, - 99, 61, 100, 207, 208, 60, 131, 105, 106, 61, - 107, 147, 60, 60, 212, 158, 61, 61, 35, 181, - 182, 163, 164, 165, 145, 60, 168, 183, 37, 61, - 169, 153, 154, 155, 156, 129, 157, 38, 117, 40, - 135, 136, 41, 137, 185, 42, 172, 140, 144, 146, - -23, 151, 175, 176, 43, 60, 38, 64, 60, 61, - 69, 66, 61, 38, 67, 160, 202, 202, 71, 60, - 75, 166, 167, 61, 149, 150, 84, 85, 86, -70, - 122, 123, 219, 124, 125, 202, 77, 84, 85, 86, - 122, 123, 215, 214, 173, 78, 3, 4, 122, 123, - 5, 124, 125, 81, 201, 201, 92, 180, 82, 103, - 184, 193, 141, 142, 71, 108, 143, 92, 187, 111, - 188, 189, 159, 201, 122, 123, 112, 124, 125, 126, - 209, 6, 7, 8, 9, 10, 11, 12, 198, 114, - 13, 84, 85, 86, -81, 161, 177, -81, 193, 221, - 198, 222, 223, 84, 85, 86, -81, -81, 218, 39, - 198, 210, 179, 84, 85, 86, 192, 199, 206, 220, - 200, 92, 127, 0, 122, 123, 0, 124, 125, 199, - 0, 0, 200, 92, 84, 85, 86, 122, 123, 199, - 124, 125, 200, 92, 84, 85, 86, 122, 123, 0, - 124, 125, 0, 152, 0, 128, 0, 0, 87, 88, - 89, 71, 90, 91, 92, 93, 0, 0, 171, 44, - 45, 0, 0, 0, 92, 0, 0, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58 + 64, 141, 66, 142, 78, 69, 71, 81, 61, 61, + 119, 61, 62, 62, 113, 62, 133, 97, 87, 88, + 89, 74, 75, 36, 79, 61, 106, 82, 83, 62, + 101, 102, 35, 103, 37, 76, 98, 215, 108, 125, + 126, 109, 127, 128, 217, 155, 76, 218, 38, 94, + 110, 150, 134, 120, 40, 96, 131, 70, 41, 77, + 38, 152, 153, 104, 199, 137, 200, 189, 132, 42, + 77, 112, 65, 138, 139, 43, 140, 122, 123, 124, + 143, 147, 125, 126, 154, 162, 61, 61, 161, 149, + 62, 62, 211, 212, 166, 167, 168, 67, 163, 171, + 68, 184, 185, 172, 169, 170, 219, 218, 148, 186, + 187, 72, 174, 164, 80, 156, 157, 158, 159, 175, + 160, 84, 206, 206, 85, 178, 179, 176, 125, 126, + 111, 127, 128, -26, 180, 39, 76, 114, 223, 38, + 183, 206, 115, 188, 117, 182, 222, 197, 214, 61, + 196, 210, 191, 62, 224, 193, 0, 197, 216, 0, + 77, 192, 61, 0, 213, 0, 62, 87, 88, 89, + 125, 126, 0, 127, 128, 227, 0, 0, 0, 0, + 87, 88, 89, 225, 0, 226, 0, 3, 4, 205, + 205, 5, 0, 144, 145, 72, 0, 146, 94, 0, + 0, 0, 0, -85, 0, 0, -85, 0, 205, 202, + 0, 94, 87, 88, 89, 0, 0, 0, 0, 0, + 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, + 202, 0, 13, 87, 88, 89, 0, -85, -85, 203, + 0, 202, 204, 94, 87, 88, 89, 130, 0, 125, + 126, 0, 127, 128, 0, 0, 0, 76, 0, 0, + 203, 0, 0, 204, 94, 0, 0, 0, -74, 125, + 126, 203, 127, 128, 204, 94, 0, 76, 87, 88, + 89, 77, 0, 76, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 77, 0, 90, 91, 92, 72, 77, 93, 94, + 95, 44, 45, 0, 0, 0, 0, 0, 0, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59 }; static const yytype_int16 yycheck[] = { - 37, 12, 39, 64, 78, 42, 43, 8, 111, 10, - 113, 72, 14, 49, 50, 9, 52, 78, 12, 55, - 56, 49, 106, 84, 85, 86, 5, 0, 64, 66, - 67, 4, 69, 6, 7, 0, 47, 74, 75, 4, - 76, 115, 0, 0, 46, 129, 4, 4, 0, 14, - 15, 135, 136, 137, 115, 0, 140, 22, 49, 4, - 144, 122, 123, 124, 125, 102, 127, 51, 47, 51, - 107, 108, 47, 110, 177, 47, 160, 114, 115, 115, - 45, 118, 166, 167, 47, 0, 51, 17, 0, 4, - 47, 17, 4, 51, 47, 132, 195, 196, 45, 0, - 46, 138, 139, 4, 49, 50, 18, 19, 20, 14, - 15, 16, 211, 18, 19, 214, 47, 18, 19, 20, - 15, 16, 11, 12, 161, 46, 0, 1, 15, 16, - 4, 18, 19, 47, 195, 196, 48, 174, 47, 46, - 177, 46, 43, 44, 45, 47, 47, 48, 185, 47, - 186, 188, 46, 214, 15, 16, 47, 18, 19, 46, - 197, 35, 36, 37, 38, 39, 40, 41, 15, 47, - 44, 18, 19, 20, 9, 3, 3, 12, 46, 216, - 15, 218, 46, 18, 19, 20, 11, 12, 208, 8, - 15, 201, 170, 18, 19, 20, 188, 44, 196, 214, - 47, 48, 13, -1, 15, 16, -1, 18, 19, 44, - -1, -1, 47, 48, 18, 19, 20, 15, 16, 44, - 18, 19, 47, 48, 18, 19, 20, 15, 16, -1, - 18, 19, -1, 21, -1, 46, -1, -1, 42, 43, - 44, 45, 46, 47, 48, 49, -1, -1, 46, 14, - 15, -1, -1, -1, 48, -1, -1, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34 + 37, 114, 39, 116, 52, 42, 43, 55, 0, 0, + 5, 0, 4, 4, 81, 4, 12, 65, 18, 19, + 20, 50, 51, 50, 53, 0, 74, 56, 57, 4, + 67, 68, 0, 70, 50, 23, 65, 14, 75, 15, + 16, 78, 18, 19, 9, 21, 23, 12, 52, 49, + 79, 118, 48, 48, 52, 65, 104, 48, 48, 47, + 52, 50, 51, 73, 8, 109, 10, 180, 105, 48, + 47, 81, 17, 110, 111, 48, 113, 87, 88, 89, + 117, 118, 15, 16, 121, 133, 0, 0, 132, 118, + 4, 4, 6, 7, 138, 139, 140, 17, 135, 143, + 48, 14, 15, 147, 141, 142, 11, 12, 118, 22, + 23, 46, 160, 3, 48, 125, 126, 127, 128, 163, + 130, 48, 199, 200, 48, 169, 170, 164, 15, 16, + 48, 18, 19, 46, 3, 8, 23, 48, 215, 52, + 177, 218, 48, 180, 48, 173, 212, 195, 205, 0, + 192, 200, 189, 4, 218, 192, -1, 205, 206, -1, + 47, 190, 0, -1, 201, -1, 4, 18, 19, 20, + 15, 16, -1, 18, 19, 223, -1, -1, -1, -1, + 18, 19, 20, 220, -1, 222, -1, 0, 1, 199, + 200, 4, -1, 44, 45, 46, -1, 48, 49, -1, + -1, -1, -1, 9, -1, -1, 12, -1, 218, 15, + -1, 49, 18, 19, 20, -1, -1, -1, -1, -1, + -1, -1, -1, 36, 37, 38, 39, 40, 41, 42, + 15, -1, 45, 18, 19, 20, -1, 11, 12, 45, + -1, 15, 48, 49, 18, 19, 20, 13, -1, 15, + 16, -1, 18, 19, -1, -1, -1, 23, -1, -1, + 45, -1, -1, 48, 49, -1, -1, -1, 14, 15, + 16, 45, 18, 19, 48, 49, -1, 23, 18, 19, + 20, 47, -1, 23, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 47, -1, 43, 44, 45, 46, 47, 48, 49, + 50, 14, 15, -1, -1, -1, -1, -1, -1, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_int8 yystos[] = { - 0, 103, 104, 0, 1, 4, 35, 36, 37, 38, - 39, 40, 41, 44, 59, 70, 71, 72, 73, 74, - 76, 77, 78, 79, 89, 90, 91, 92, 94, 97, - 98, 99, 100, 101, 102, 0, 49, 49, 51, 64, - 51, 47, 47, 47, 14, 15, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 54, - 0, 4, 55, 55, 17, 55, 17, 47, 55, 47, - 55, 45, 62, 62, 62, 46, 62, 47, 46, 62, - 62, 47, 47, 57, 18, 19, 20, 42, 43, 44, - 46, 47, 48, 49, 56, 62, 66, 80, 55, 55, - 55, 56, 81, 46, 69, 55, 55, 62, 47, 56, - 80, 47, 47, 93, 47, 96, 5, 47, 58, 56, - 56, 56, 15, 16, 18, 19, 46, 13, 46, 55, - 12, 47, 75, 68, 68, 55, 55, 55, 58, 58, - 55, 43, 44, 47, 55, 56, 62, 80, 95, 49, - 50, 55, 21, 56, 56, 56, 56, 56, 68, 46, - 55, 3, 65, 68, 68, 68, 55, 55, 68, 68, - 67, 46, 68, 55, 64, 68, 68, 3, 63, 65, - 55, 14, 15, 22, 55, 58, 60, 55, 62, 55, - 56, 82, 85, 46, 83, 8, 10, 86, 15, 44, - 47, 56, 82, 84, 87, 88, 87, 6, 7, 55, - 83, 14, 46, 9, 12, 11, 61, 85, 61, 82, - 88, 55, 55, 46 + 0, 105, 106, 0, 1, 4, 36, 37, 38, 39, + 40, 41, 42, 45, 61, 72, 73, 74, 75, 76, + 78, 79, 80, 81, 91, 92, 93, 94, 96, 99, + 100, 101, 102, 103, 104, 0, 50, 50, 52, 66, + 52, 48, 48, 48, 14, 15, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 55, 0, 4, 56, 56, 17, 56, 17, 48, 56, + 48, 56, 46, 64, 64, 64, 23, 47, 58, 64, + 48, 58, 64, 64, 48, 48, 59, 18, 19, 20, + 43, 44, 45, 48, 49, 50, 57, 58, 64, 68, + 82, 56, 56, 56, 57, 83, 58, 71, 56, 56, + 64, 48, 57, 82, 48, 48, 95, 48, 98, 5, + 48, 60, 57, 57, 57, 15, 16, 18, 19, 58, + 13, 58, 56, 12, 48, 77, 70, 70, 56, 56, + 56, 60, 60, 56, 44, 45, 48, 56, 57, 64, + 82, 97, 50, 51, 56, 21, 57, 57, 57, 57, + 57, 70, 58, 56, 3, 67, 70, 70, 70, 56, + 56, 70, 70, 69, 58, 70, 56, 66, 70, 70, + 3, 65, 67, 56, 14, 15, 22, 23, 56, 60, + 62, 56, 64, 56, 57, 84, 87, 58, 85, 8, + 10, 88, 15, 45, 48, 57, 84, 86, 89, 90, + 89, 6, 7, 56, 85, 14, 58, 9, 12, 11, + 63, 87, 63, 84, 90, 56, 56, 58 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { - 0, 53, 54, 54, 54, 54, 55, 55, 56, 56, - 56, 56, 56, 56, 56, 56, 57, 57, 57, 58, - 58, 58, 59, 60, 60, 60, 60, 61, 62, 63, - 63, 63, 63, 64, 65, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, - 68, 68, 68, 69, 69, 69, 70, 71, 72, 73, - 74, 75, 75, 76, 77, 78, 79, 80, 81, 81, - 82, 82, 83, 83, 84, 84, 84, 85, 86, 86, - 86, 87, 87, 87, 88, 88, 88, 88, 89, 90, - 91, 92, 93, 94, 95, 95, 95, 95, 95, 95, - 96, 96, 97, 98, 98, 98, 98, 98, 98, 98, - 98, 98, 98, 98, 98, 99, 100, 101, 101, 102, - 102, 102, 102, 102, 102, 102, 103, 103, 103, 103, - 103, 104 + 0, 54, 55, 55, 55, 55, 55, 56, 56, 57, + 57, 57, 57, 57, 57, 57, 57, 58, 58, 59, + 59, 59, 60, 60, 60, 61, 62, 62, 62, 62, + 62, 63, 64, 65, 65, 65, 65, 66, 67, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 69, + 69, 69, 69, 69, 70, 70, 70, 71, 71, 71, + 72, 73, 74, 75, 76, 77, 77, 78, 79, 80, + 81, 82, 83, 83, 84, 84, 85, 85, 86, 86, + 86, 87, 88, 88, 88, 89, 89, 89, 90, 90, + 90, 90, 91, 92, 93, 94, 95, 96, 97, 97, + 97, 97, 97, 97, 98, 98, 99, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 100, 100, 101, + 102, 103, 103, 104, 104, 104, 104, 104, 104, 104, + 105, 105, 105, 105, 105, 106 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { - 0, 2, 1, 1, 1, 1, 1, 1, 1, 3, - 3, 3, 3, 2, 2, 3, 0, 2, 2, 0, - 2, 2, 6, 0, 1, 1, 1, 1, 1, 6, - 8, 8, 4, 3, 3, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 3, 4, 2, 2, - 0, 3, 2, 0, 1, 3, 3, 3, 3, 4, - 7, 1, 0, 5, 5, 6, 6, 2, 2, 4, - 1, 0, 1, 0, 2, 2, 4, 2, 3, 3, - 0, 0, 1, 3, 1, 1, 1, 1, 6, 6, - 6, 7, 1, 7, 1, 1, 1, 1, 1, 1, - 0, 2, 6, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 4, 3, 3, 4, 1, - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, - 0, 2 + 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 3, 3, 3, 3, 2, 2, 3, 1, 1, 0, + 2, 2, 0, 2, 2, 6, 0, 1, 1, 1, + 1, 1, 1, 6, 8, 8, 4, 3, 3, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 3, 4, 2, 2, 0, 3, 2, 0, 1, 3, + 3, 3, 3, 4, 7, 1, 0, 5, 5, 6, + 6, 2, 2, 4, 1, 0, 1, 0, 2, 2, + 4, 2, 3, 3, 0, 0, 1, 3, 1, 1, + 1, 1, 6, 6, 6, 7, 1, 7, 1, 1, + 1, 1, 1, 1, 0, 2, 6, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, + 3, 3, 4, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 0, 2 }; @@ -1808,374 +1824,398 @@ YYLTYPE yylloc = yyloc_default; switch (yyn) { case 2: /* txn: TXN */ -#line 288 "beancount/parser/grammar.y" +#line 290 "beancount/parser/grammar.y" { (yyval.character) = '*'; } -#line 1816 "beancount/parser/grammar.c" +#line 1832 "beancount/parser/grammar.c" break; case 3: /* txn: FLAG */ -#line 292 "beancount/parser/grammar.y" +#line 294 "beancount/parser/grammar.y" { (yyval.character) = (yyvsp[0].character); } -#line 1824 "beancount/parser/grammar.c" +#line 1840 "beancount/parser/grammar.c" break; case 4: /* txn: ASTERISK */ -#line 296 "beancount/parser/grammar.y" +#line 298 "beancount/parser/grammar.y" { (yyval.character) = '*'; } -#line 1832 "beancount/parser/grammar.c" +#line 1848 "beancount/parser/grammar.c" break; case 5: /* txn: HASH */ -#line 300 "beancount/parser/grammar.y" +#line 302 "beancount/parser/grammar.y" { (yyval.character) = '#'; } -#line 1840 "beancount/parser/grammar.c" +#line 1856 "beancount/parser/grammar.c" + break; + + case 6: /* txn: CAPITAL */ +#line 306 "beancount/parser/grammar.y" + { + (yyval.character) = (yyvsp[0].character); + } +#line 1864 "beancount/parser/grammar.c" break; - case 9: /* number_expr: number_expr PLUS number_expr */ -#line 313 "beancount/parser/grammar.y" + case 10: /* number_expr: number_expr PLUS number_expr */ +#line 319 "beancount/parser/grammar.y" { (yyval.pyobj) = PyNumber_Add((yyvsp[-2].pyobj), (yyvsp[0].pyobj)); DECREF((yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 1849 "beancount/parser/grammar.c" +#line 1873 "beancount/parser/grammar.c" break; - case 10: /* number_expr: number_expr MINUS number_expr */ -#line 318 "beancount/parser/grammar.y" + case 11: /* number_expr: number_expr MINUS number_expr */ +#line 324 "beancount/parser/grammar.y" { (yyval.pyobj) = PyNumber_Subtract((yyvsp[-2].pyobj), (yyvsp[0].pyobj)); DECREF((yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 1858 "beancount/parser/grammar.c" +#line 1882 "beancount/parser/grammar.c" break; - case 11: /* number_expr: number_expr ASTERISK number_expr */ -#line 323 "beancount/parser/grammar.y" + case 12: /* number_expr: number_expr ASTERISK number_expr */ +#line 329 "beancount/parser/grammar.y" { (yyval.pyobj) = PyNumber_Multiply((yyvsp[-2].pyobj), (yyvsp[0].pyobj)); DECREF((yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 1867 "beancount/parser/grammar.c" +#line 1891 "beancount/parser/grammar.c" break; - case 12: /* number_expr: number_expr SLASH number_expr */ -#line 328 "beancount/parser/grammar.y" + case 13: /* number_expr: number_expr SLASH number_expr */ +#line 334 "beancount/parser/grammar.y" { (yyval.pyobj) = PyNumber_TrueDivide((yyvsp[-2].pyobj), (yyvsp[0].pyobj)); DECREF((yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 1876 "beancount/parser/grammar.c" +#line 1900 "beancount/parser/grammar.c" break; - case 13: /* number_expr: MINUS number_expr */ -#line 333 "beancount/parser/grammar.y" + case 14: /* number_expr: MINUS number_expr */ +#line 339 "beancount/parser/grammar.y" { (yyval.pyobj) = PyNumber_Negative((yyvsp[0].pyobj)); DECREF((yyvsp[0].pyobj)); } -#line 1885 "beancount/parser/grammar.c" +#line 1909 "beancount/parser/grammar.c" break; - case 14: /* number_expr: PLUS number_expr */ -#line 338 "beancount/parser/grammar.y" + case 15: /* number_expr: PLUS number_expr */ +#line 344 "beancount/parser/grammar.y" { (yyval.pyobj) = (yyvsp[0].pyobj); } -#line 1893 "beancount/parser/grammar.c" +#line 1917 "beancount/parser/grammar.c" break; - case 15: /* number_expr: LPAREN number_expr RPAREN */ -#line 342 "beancount/parser/grammar.y" + case 16: /* number_expr: LPAREN number_expr RPAREN */ +#line 348 "beancount/parser/grammar.y" { (yyval.pyobj) = (yyvsp[-1].pyobj); } -#line 1901 "beancount/parser/grammar.c" +#line 1925 "beancount/parser/grammar.c" break; - case 16: /* txn_strings: %empty */ -#line 348 "beancount/parser/grammar.y" + case 17: /* currency: CURRENCY */ +#line 354 "beancount/parser/grammar.y" + { + (yyval.pyobj) = (yyvsp[0].pyobj); + } +#line 1933 "beancount/parser/grammar.c" + break; + + case 18: /* currency: CAPITAL */ +#line 358 "beancount/parser/grammar.y" + { + (yyval.pyobj) = PyUnicode_FromStringAndSize(&(yyvsp[0].character), 1); + } +#line 1941 "beancount/parser/grammar.c" + break; + + case 19: /* txn_strings: %empty */ +#line 364 "beancount/parser/grammar.y" { Py_INCREF(Py_None); (yyval.pyobj) = Py_None; } -#line 1910 "beancount/parser/grammar.c" +#line 1950 "beancount/parser/grammar.c" break; - case 17: /* txn_strings: txn_strings STRING */ -#line 353 "beancount/parser/grammar.y" + case 20: /* txn_strings: txn_strings STRING */ +#line 369 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "handle_list", "OO", (yyvsp[-1].pyobj), (yyvsp[0].pyobj)); } -#line 1919 "beancount/parser/grammar.c" +#line 1959 "beancount/parser/grammar.c" break; - case 18: /* txn_strings: txn_strings PIPE */ -#line 358 "beancount/parser/grammar.y" + case 21: /* txn_strings: txn_strings PIPE */ +#line 374 "beancount/parser/grammar.y" { BUILDY(, (yyval.pyobj), "pipe_deprecated_error", ""); (yyval.pyobj) = (yyvsp[-1].pyobj); } -#line 1929 "beancount/parser/grammar.c" +#line 1969 "beancount/parser/grammar.c" break; - case 19: /* tags_links: %empty */ -#line 366 "beancount/parser/grammar.y" + case 22: /* tags_links: %empty */ +#line 382 "beancount/parser/grammar.y" { BUILDY(, (yyval.pyobj), "tag_link_new", ""); } -#line 1938 "beancount/parser/grammar.c" +#line 1978 "beancount/parser/grammar.c" break; - case 20: /* tags_links: tags_links LINK */ -#line 371 "beancount/parser/grammar.y" + case 23: /* tags_links: tags_links LINK */ +#line 387 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "tag_link_LINK", "OO", (yyvsp[-1].pyobj), (yyvsp[0].pyobj)); } -#line 1947 "beancount/parser/grammar.c" +#line 1987 "beancount/parser/grammar.c" break; - case 21: /* tags_links: tags_links TAG */ -#line 376 "beancount/parser/grammar.y" + case 24: /* tags_links: tags_links TAG */ +#line 392 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "tag_link_TAG", "OO", (yyvsp[-1].pyobj), (yyvsp[0].pyobj)); } -#line 1956 "beancount/parser/grammar.c" +#line 1996 "beancount/parser/grammar.c" break; - case 22: /* transaction: DATE txn txn_strings tags_links eol posting_or_kv_list */ -#line 383 "beancount/parser/grammar.y" + case 25: /* transaction: DATE txn txn_strings tags_links eol posting_or_kv_list */ +#line 399 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-5].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "transaction", "ObOOO", (yyvsp[-5].pyobj), (yyvsp[-4].character), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 1965 "beancount/parser/grammar.c" +#line 2005 "beancount/parser/grammar.c" break; - case 23: /* optflag: %empty */ -#line 390 "beancount/parser/grammar.y" + case 26: /* optflag: %empty */ +#line 406 "beancount/parser/grammar.y" { (yyval.character) = '\0'; } -#line 1973 "beancount/parser/grammar.c" +#line 2013 "beancount/parser/grammar.c" break; - case 24: /* optflag: ASTERISK */ -#line 394 "beancount/parser/grammar.y" + case 27: /* optflag: ASTERISK */ +#line 410 "beancount/parser/grammar.y" { (yyval.character) = '*'; } -#line 1981 "beancount/parser/grammar.c" +#line 2021 "beancount/parser/grammar.c" break; - case 25: /* optflag: HASH */ -#line 398 "beancount/parser/grammar.y" + case 28: /* optflag: HASH */ +#line 414 "beancount/parser/grammar.y" { (yyval.character) = '#'; } -#line 1989 "beancount/parser/grammar.c" +#line 2029 "beancount/parser/grammar.c" break; - case 28: /* account: ACCOUNT */ -#line 408 "beancount/parser/grammar.y" + case 32: /* account: ACCOUNT */ +#line 425 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[0].pyobj)), (yyval.pyobj), "account", "O", (yyvsp[0].pyobj)); } -#line 1998 "beancount/parser/grammar.c" +#line 2038 "beancount/parser/grammar.c" break; - case 29: /* posting: INDENT optflag account incomplete_amount cost_spec eol */ -#line 415 "beancount/parser/grammar.y" + case 33: /* posting: INDENT optflag account incomplete_amount cost_spec eol */ +#line 432 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[-1].pyobj)), (yyval.pyobj), "posting", "OOOOOb", (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[-1].pyobj), Py_None, Py_False, (yyvsp[-4].character)); } -#line 2007 "beancount/parser/grammar.c" +#line 2047 "beancount/parser/grammar.c" break; - case 30: /* posting: INDENT optflag account incomplete_amount cost_spec AT price_annotation eol */ -#line 420 "beancount/parser/grammar.y" + case 34: /* posting: INDENT optflag account incomplete_amount cost_spec AT price_annotation eol */ +#line 437 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-5].pyobj), (yyvsp[-4].pyobj), (yyvsp[-3].pyobj), (yyvsp[-1].pyobj)), (yyval.pyobj), "posting", "OOOOOb", (yyvsp[-5].pyobj), (yyvsp[-4].pyobj), (yyvsp[-3].pyobj), (yyvsp[-1].pyobj), Py_False, (yyvsp[-6].character)); } -#line 2016 "beancount/parser/grammar.c" +#line 2056 "beancount/parser/grammar.c" break; - case 31: /* posting: INDENT optflag account incomplete_amount cost_spec ATAT price_annotation eol */ -#line 425 "beancount/parser/grammar.y" + case 35: /* posting: INDENT optflag account incomplete_amount cost_spec ATAT price_annotation eol */ +#line 442 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-5].pyobj), (yyvsp[-4].pyobj), (yyvsp[-3].pyobj), (yyvsp[-1].pyobj)), (yyval.pyobj), "posting", "OOOOOb", (yyvsp[-5].pyobj), (yyvsp[-4].pyobj), (yyvsp[-3].pyobj), (yyvsp[-1].pyobj), Py_True, (yyvsp[-6].character)); } -#line 2025 "beancount/parser/grammar.c" +#line 2065 "beancount/parser/grammar.c" break; - case 32: /* posting: INDENT optflag account eol */ -#line 430 "beancount/parser/grammar.y" + case 36: /* posting: INDENT optflag account eol */ +#line 447 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj)), (yyval.pyobj), "posting", "OOOOOb", (yyvsp[-1].pyobj), MISSING_OBJ, Py_None, Py_None, Py_False, (yyvsp[-2].character)); } -#line 2034 "beancount/parser/grammar.c" +#line 2074 "beancount/parser/grammar.c" break; - case 33: /* key_value: KEY COLON key_value_value */ -#line 437 "beancount/parser/grammar.y" + case 37: /* key_value: KEY COLON key_value_value */ +#line 454 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-2].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "key_value", "OO", (yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 2043 "beancount/parser/grammar.c" +#line 2083 "beancount/parser/grammar.c" break; - case 34: /* key_value_line: INDENT key_value eol */ -#line 444 "beancount/parser/grammar.y" + case 38: /* key_value_line: INDENT key_value eol */ +#line 461 "beancount/parser/grammar.y" { (yyval.pyobj) = (yyvsp[-1].pyobj); } -#line 2051 "beancount/parser/grammar.c" +#line 2091 "beancount/parser/grammar.c" break; - case 44: /* key_value_value: %empty */ -#line 459 "beancount/parser/grammar.y" + case 48: /* key_value_value: %empty */ +#line 476 "beancount/parser/grammar.y" { Py_INCREF(Py_None); (yyval.pyobj) = Py_None; } -#line 2060 "beancount/parser/grammar.c" +#line 2100 "beancount/parser/grammar.c" break; - case 45: /* posting_or_kv_list: %empty */ -#line 466 "beancount/parser/grammar.y" + case 49: /* posting_or_kv_list: %empty */ +#line 483 "beancount/parser/grammar.y" { Py_INCREF(Py_None); (yyval.pyobj) = Py_None; } -#line 2069 "beancount/parser/grammar.c" +#line 2109 "beancount/parser/grammar.c" break; - case 46: /* posting_or_kv_list: posting_or_kv_list INDENT eol */ -#line 471 "beancount/parser/grammar.y" + case 50: /* posting_or_kv_list: posting_or_kv_list INDENT eol */ +#line 488 "beancount/parser/grammar.y" { (yyval.pyobj) = (yyvsp[-2].pyobj); } -#line 2077 "beancount/parser/grammar.c" +#line 2117 "beancount/parser/grammar.c" break; - case 47: /* posting_or_kv_list: posting_or_kv_list INDENT tags_links eol */ -#line 475 "beancount/parser/grammar.y" + case 51: /* posting_or_kv_list: posting_or_kv_list INDENT tags_links eol */ +#line 492 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-3].pyobj), (yyvsp[-1].pyobj)), (yyval.pyobj), "handle_list", "OO", (yyvsp[-3].pyobj), (yyvsp[-1].pyobj)); } -#line 2086 "beancount/parser/grammar.c" +#line 2126 "beancount/parser/grammar.c" break; - case 48: /* posting_or_kv_list: posting_or_kv_list key_value_line */ -#line 480 "beancount/parser/grammar.y" + case 52: /* posting_or_kv_list: posting_or_kv_list key_value_line */ +#line 497 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "handle_list", "OO", (yyvsp[-1].pyobj), (yyvsp[0].pyobj)); } -#line 2095 "beancount/parser/grammar.c" +#line 2135 "beancount/parser/grammar.c" break; - case 49: /* posting_or_kv_list: posting_or_kv_list posting */ -#line 485 "beancount/parser/grammar.y" + case 53: /* posting_or_kv_list: posting_or_kv_list posting */ +#line 502 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "handle_list", "OO", (yyvsp[-1].pyobj), (yyvsp[0].pyobj)); } -#line 2104 "beancount/parser/grammar.c" +#line 2144 "beancount/parser/grammar.c" break; - case 50: /* key_value_list: %empty */ -#line 492 "beancount/parser/grammar.y" + case 54: /* key_value_list: %empty */ +#line 509 "beancount/parser/grammar.y" { Py_INCREF(Py_None); (yyval.pyobj) = Py_None; } -#line 2113 "beancount/parser/grammar.c" +#line 2153 "beancount/parser/grammar.c" break; - case 51: /* key_value_list: key_value_list INDENT eol */ -#line 497 "beancount/parser/grammar.y" + case 55: /* key_value_list: key_value_list INDENT eol */ +#line 514 "beancount/parser/grammar.y" { (yyval.pyobj) = (yyvsp[-2].pyobj); } -#line 2121 "beancount/parser/grammar.c" +#line 2161 "beancount/parser/grammar.c" break; - case 52: /* key_value_list: key_value_list key_value_line */ -#line 501 "beancount/parser/grammar.y" + case 56: /* key_value_list: key_value_list key_value_line */ +#line 518 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "handle_list", "OO", (yyvsp[-1].pyobj), (yyvsp[0].pyobj)); } -#line 2130 "beancount/parser/grammar.c" +#line 2170 "beancount/parser/grammar.c" break; - case 53: /* currency_list: %empty */ -#line 508 "beancount/parser/grammar.y" + case 57: /* currency_list: %empty */ +#line 525 "beancount/parser/grammar.y" { Py_INCREF(Py_None); (yyval.pyobj) = Py_None; } -#line 2139 "beancount/parser/grammar.c" +#line 2179 "beancount/parser/grammar.c" break; - case 54: /* currency_list: CURRENCY */ -#line 513 "beancount/parser/grammar.y" + case 58: /* currency_list: currency */ +#line 530 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[0].pyobj)), (yyval.pyobj), "handle_list", "OO", Py_None, (yyvsp[0].pyobj)); } -#line 2148 "beancount/parser/grammar.c" +#line 2188 "beancount/parser/grammar.c" break; - case 55: /* currency_list: currency_list COMMA CURRENCY */ -#line 518 "beancount/parser/grammar.y" + case 59: /* currency_list: currency_list COMMA currency */ +#line 535 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-2].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "handle_list", "OO", (yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 2157 "beancount/parser/grammar.c" +#line 2197 "beancount/parser/grammar.c" break; - case 56: /* pushtag: PUSHTAG TAG eol */ -#line 525 "beancount/parser/grammar.y" + case 60: /* pushtag: PUSHTAG TAG eol */ +#line 542 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj)), (yyval.pyobj), "pushtag", "O", (yyvsp[-1].pyobj)); } -#line 2166 "beancount/parser/grammar.c" +#line 2206 "beancount/parser/grammar.c" break; - case 57: /* poptag: POPTAG TAG eol */ -#line 532 "beancount/parser/grammar.y" + case 61: /* poptag: POPTAG TAG eol */ +#line 549 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj)), (yyval.pyobj), "poptag", "O", (yyvsp[-1].pyobj)); } -#line 2175 "beancount/parser/grammar.c" +#line 2215 "beancount/parser/grammar.c" break; - case 58: /* pushmeta: PUSHMETA key_value eol */ -#line 539 "beancount/parser/grammar.y" + case 62: /* pushmeta: PUSHMETA key_value eol */ +#line 556 "beancount/parser/grammar.y" { /* Note: key_value is a tuple, Py_BuildValue() won't wrap it up * within a tuple, so expand in the method (it receives two @@ -2183,312 +2223,312 @@ YYLTYPE yylloc = yyloc_default; BUILDY(DECREF((yyvsp[-1].pyobj)), (yyval.pyobj), "pushmeta", "O", (yyvsp[-1].pyobj)); } -#line 2187 "beancount/parser/grammar.c" +#line 2227 "beancount/parser/grammar.c" break; - case 59: /* popmeta: POPMETA KEY COLON eol */ -#line 549 "beancount/parser/grammar.y" + case 63: /* popmeta: POPMETA KEY COLON eol */ +#line 566 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-2].pyobj)), (yyval.pyobj), "popmeta", "O", (yyvsp[-2].pyobj)); } -#line 2196 "beancount/parser/grammar.c" +#line 2236 "beancount/parser/grammar.c" break; - case 60: /* open: DATE OPEN account currency_list opt_booking eol key_value_list */ -#line 556 "beancount/parser/grammar.y" + case 64: /* open: DATE OPEN account currency_list opt_booking eol key_value_list */ +#line 573 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-6].pyobj), (yyvsp[-4].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "open", "OOOOO", (yyvsp[-6].pyobj), (yyvsp[-4].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 2205 "beancount/parser/grammar.c" +#line 2245 "beancount/parser/grammar.c" break; - case 62: /* opt_booking: %empty */ -#line 564 "beancount/parser/grammar.y" + case 66: /* opt_booking: %empty */ +#line 581 "beancount/parser/grammar.y" { Py_INCREF(Py_None); (yyval.pyobj) = Py_None; } -#line 2214 "beancount/parser/grammar.c" +#line 2254 "beancount/parser/grammar.c" break; - case 63: /* close: DATE CLOSE account eol key_value_list */ -#line 571 "beancount/parser/grammar.y" + case 67: /* close: DATE CLOSE account eol key_value_list */ +#line 588 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-4].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "close", "OOO", (yyvsp[-4].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 2223 "beancount/parser/grammar.c" +#line 2263 "beancount/parser/grammar.c" break; - case 64: /* commodity: DATE COMMODITY CURRENCY eol key_value_list */ -#line 578 "beancount/parser/grammar.y" + case 68: /* commodity: DATE COMMODITY currency eol key_value_list */ +#line 595 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-4].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "commodity", "OOO", (yyvsp[-4].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 2232 "beancount/parser/grammar.c" +#line 2272 "beancount/parser/grammar.c" break; - case 65: /* pad: DATE PAD account account eol key_value_list */ -#line 585 "beancount/parser/grammar.y" + case 69: /* pad: DATE PAD account account eol key_value_list */ +#line 602 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-5].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "pad", "OOOO", (yyvsp[-5].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 2241 "beancount/parser/grammar.c" +#line 2281 "beancount/parser/grammar.c" break; - case 66: /* balance: DATE BALANCE account amount_tolerance eol key_value_list */ -#line 592 "beancount/parser/grammar.y" + case 70: /* balance: DATE BALANCE account amount_tolerance eol key_value_list */ +#line 609 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-5].pyobj), (yyvsp[-3].pyobj), (yyvsp[0].pyobj), (yyvsp[-2].pairobj).pyobj1, (yyvsp[-2].pairobj).pyobj2), (yyval.pyobj), "balance", "OOOOO", (yyvsp[-5].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pairobj).pyobj1, (yyvsp[-2].pairobj).pyobj2, (yyvsp[0].pyobj)); } -#line 2250 "beancount/parser/grammar.c" +#line 2290 "beancount/parser/grammar.c" break; - case 67: /* amount: number_expr CURRENCY */ -#line 599 "beancount/parser/grammar.y" + case 71: /* amount: number_expr currency */ +#line 616 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "amount", "OO", (yyvsp[-1].pyobj), (yyvsp[0].pyobj)); } -#line 2259 "beancount/parser/grammar.c" +#line 2299 "beancount/parser/grammar.c" break; - case 68: /* amount_tolerance: number_expr CURRENCY */ -#line 606 "beancount/parser/grammar.y" + case 72: /* amount_tolerance: number_expr currency */ +#line 623 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj), (yyvsp[0].pyobj)), (yyval.pairobj).pyobj1, "amount", "OO", (yyvsp[-1].pyobj), (yyvsp[0].pyobj)); (yyval.pairobj).pyobj2 = Py_None; Py_INCREF(Py_None); } -#line 2270 "beancount/parser/grammar.c" +#line 2310 "beancount/parser/grammar.c" break; - case 69: /* amount_tolerance: number_expr TILDE number_expr CURRENCY */ -#line 613 "beancount/parser/grammar.y" + case 73: /* amount_tolerance: number_expr TILDE number_expr currency */ +#line 630 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-3].pyobj), (yyvsp[0].pyobj)), (yyval.pairobj).pyobj1, "amount", "OO", (yyvsp[-3].pyobj), (yyvsp[0].pyobj)); (yyval.pairobj).pyobj2 = (yyvsp[-1].pyobj); } -#line 2280 "beancount/parser/grammar.c" +#line 2320 "beancount/parser/grammar.c" break; - case 71: /* maybe_number: %empty */ -#line 622 "beancount/parser/grammar.y" + case 75: /* maybe_number: %empty */ +#line 639 "beancount/parser/grammar.y" { Py_INCREF(MISSING_OBJ); (yyval.pyobj) = MISSING_OBJ; } -#line 2289 "beancount/parser/grammar.c" +#line 2329 "beancount/parser/grammar.c" break; - case 73: /* maybe_currency: %empty */ -#line 630 "beancount/parser/grammar.y" + case 77: /* maybe_currency: %empty */ +#line 647 "beancount/parser/grammar.y" { Py_INCREF(MISSING_OBJ); (yyval.pyobj) = MISSING_OBJ; } -#line 2298 "beancount/parser/grammar.c" +#line 2338 "beancount/parser/grammar.c" break; - case 74: /* compound_amount: maybe_number CURRENCY */ -#line 637 "beancount/parser/grammar.y" + case 78: /* compound_amount: maybe_number currency */ +#line 654 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "compound_amount", "OOO", (yyvsp[-1].pyobj), Py_None, (yyvsp[0].pyobj)); } -#line 2307 "beancount/parser/grammar.c" +#line 2347 "beancount/parser/grammar.c" break; - case 75: /* compound_amount: number_expr maybe_currency */ -#line 642 "beancount/parser/grammar.y" + case 79: /* compound_amount: number_expr maybe_currency */ +#line 659 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "compound_amount", "OOO", (yyvsp[-1].pyobj), Py_None, (yyvsp[0].pyobj)); } -#line 2316 "beancount/parser/grammar.c" +#line 2356 "beancount/parser/grammar.c" break; - case 76: /* compound_amount: maybe_number HASH maybe_number CURRENCY */ -#line 647 "beancount/parser/grammar.y" + case 80: /* compound_amount: maybe_number HASH maybe_number currency */ +#line 664 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-3].pyobj), (yyvsp[-1].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "compound_amount", "OOO", (yyvsp[-3].pyobj), (yyvsp[-1].pyobj), (yyvsp[0].pyobj)); ; } -#line 2326 "beancount/parser/grammar.c" +#line 2366 "beancount/parser/grammar.c" break; - case 77: /* incomplete_amount: maybe_number maybe_currency */ -#line 655 "beancount/parser/grammar.y" + case 81: /* incomplete_amount: maybe_number maybe_currency */ +#line 672 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "amount", "OO", (yyvsp[-1].pyobj), (yyvsp[0].pyobj)); } -#line 2335 "beancount/parser/grammar.c" +#line 2375 "beancount/parser/grammar.c" break; - case 78: /* cost_spec: LCURL cost_comp_list RCURL */ -#line 662 "beancount/parser/grammar.y" + case 82: /* cost_spec: LCURL cost_comp_list RCURL */ +#line 679 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj)), (yyval.pyobj), "cost_spec", "OO", (yyvsp[-1].pyobj), Py_False); } -#line 2344 "beancount/parser/grammar.c" +#line 2384 "beancount/parser/grammar.c" break; - case 79: /* cost_spec: LCURLCURL cost_comp_list RCURLCURL */ -#line 667 "beancount/parser/grammar.y" + case 83: /* cost_spec: LCURLCURL cost_comp_list RCURLCURL */ +#line 684 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj)), (yyval.pyobj), "cost_spec", "OO", (yyvsp[-1].pyobj), Py_True); } -#line 2353 "beancount/parser/grammar.c" +#line 2393 "beancount/parser/grammar.c" break; - case 80: /* cost_spec: %empty */ -#line 672 "beancount/parser/grammar.y" + case 84: /* cost_spec: %empty */ +#line 689 "beancount/parser/grammar.y" { Py_INCREF(Py_None); (yyval.pyobj) = Py_None; } -#line 2362 "beancount/parser/grammar.c" +#line 2402 "beancount/parser/grammar.c" break; - case 81: /* cost_comp_list: %empty */ -#line 679 "beancount/parser/grammar.y" + case 85: /* cost_comp_list: %empty */ +#line 696 "beancount/parser/grammar.y" { /* We indicate that there was a cost if there */ (yyval.pyobj) = PyList_New(0); } -#line 2371 "beancount/parser/grammar.c" +#line 2411 "beancount/parser/grammar.c" break; - case 82: /* cost_comp_list: cost_comp */ -#line 684 "beancount/parser/grammar.y" + case 86: /* cost_comp_list: cost_comp */ +#line 701 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[0].pyobj)), (yyval.pyobj), "handle_list", "OO", Py_None, (yyvsp[0].pyobj)); } -#line 2380 "beancount/parser/grammar.c" +#line 2420 "beancount/parser/grammar.c" break; - case 83: /* cost_comp_list: cost_comp_list COMMA cost_comp */ -#line 689 "beancount/parser/grammar.y" + case 87: /* cost_comp_list: cost_comp_list COMMA cost_comp */ +#line 706 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-2].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "handle_list", "OO", (yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 2389 "beancount/parser/grammar.c" +#line 2429 "beancount/parser/grammar.c" break; - case 87: /* cost_comp: ASTERISK */ -#line 699 "beancount/parser/grammar.y" + case 91: /* cost_comp: ASTERISK */ +#line 716 "beancount/parser/grammar.y" { BUILDY(, (yyval.pyobj), "cost_merge", "O", Py_None); } -#line 2398 "beancount/parser/grammar.c" +#line 2438 "beancount/parser/grammar.c" break; - case 88: /* price: DATE PRICE CURRENCY amount eol key_value_list */ -#line 706 "beancount/parser/grammar.y" + case 92: /* price: DATE PRICE currency amount eol key_value_list */ +#line 723 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-5].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "price", "OOOO", (yyvsp[-5].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 2407 "beancount/parser/grammar.c" +#line 2447 "beancount/parser/grammar.c" break; - case 89: /* event: DATE EVENT STRING STRING eol key_value_list */ -#line 713 "beancount/parser/grammar.y" + case 93: /* event: DATE EVENT STRING STRING eol key_value_list */ +#line 730 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-5].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "event", "OOOO", (yyvsp[-5].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 2416 "beancount/parser/grammar.c" +#line 2456 "beancount/parser/grammar.c" break; - case 90: /* query: DATE QUERY STRING STRING eol key_value_list */ -#line 720 "beancount/parser/grammar.y" + case 94: /* query: DATE QUERY STRING STRING eol key_value_list */ +#line 737 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-5].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "query", "OOOO", (yyvsp[-5].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 2425 "beancount/parser/grammar.c" +#line 2465 "beancount/parser/grammar.c" break; - case 91: /* note: DATE NOTE account STRING tags_links eol key_value_list */ -#line 727 "beancount/parser/grammar.y" + case 95: /* note: DATE NOTE account STRING tags_links eol key_value_list */ +#line 744 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-6].pyobj), (yyvsp[-4].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "note", "OOOOO", (yyvsp[-6].pyobj), (yyvsp[-4].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 2434 "beancount/parser/grammar.c" +#line 2474 "beancount/parser/grammar.c" break; - case 93: /* document: DATE DOCUMENT account filename tags_links eol key_value_list */ -#line 736 "beancount/parser/grammar.y" + case 97: /* document: DATE DOCUMENT account filename tags_links eol key_value_list */ +#line 753 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-6].pyobj), (yyvsp[-4].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "document", "OOOOO", (yyvsp[-6].pyobj), (yyvsp[-4].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 2443 "beancount/parser/grammar.c" +#line 2483 "beancount/parser/grammar.c" break; - case 94: /* custom_value: STRING */ -#line 743 "beancount/parser/grammar.y" + case 98: /* custom_value: STRING */ +#line 760 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[0].pyobj)), (yyval.pyobj), "custom_value", "OO", (yyvsp[0].pyobj), Py_None); } -#line 2452 "beancount/parser/grammar.c" +#line 2492 "beancount/parser/grammar.c" break; - case 95: /* custom_value: DATE */ -#line 748 "beancount/parser/grammar.y" + case 99: /* custom_value: DATE */ +#line 765 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[0].pyobj)), (yyval.pyobj), "custom_value", "OO", (yyvsp[0].pyobj), Py_None); } -#line 2461 "beancount/parser/grammar.c" +#line 2501 "beancount/parser/grammar.c" break; - case 96: /* custom_value: BOOL */ -#line 753 "beancount/parser/grammar.y" + case 100: /* custom_value: BOOL */ +#line 770 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[0].pyobj)), (yyval.pyobj), "custom_value", "OO", (yyvsp[0].pyobj), Py_None); } -#line 2470 "beancount/parser/grammar.c" +#line 2510 "beancount/parser/grammar.c" break; - case 97: /* custom_value: amount */ -#line 758 "beancount/parser/grammar.y" + case 101: /* custom_value: amount */ +#line 775 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[0].pyobj)), (yyval.pyobj), "custom_value", "OO", (yyvsp[0].pyobj), Py_None); } -#line 2479 "beancount/parser/grammar.c" +#line 2519 "beancount/parser/grammar.c" break; - case 98: /* custom_value: number_expr */ -#line 763 "beancount/parser/grammar.y" + case 102: /* custom_value: number_expr */ +#line 780 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[0].pyobj)), (yyval.pyobj), "custom_value", "OO", (yyvsp[0].pyobj), Py_None); } -#line 2488 "beancount/parser/grammar.c" +#line 2528 "beancount/parser/grammar.c" break; - case 99: /* custom_value: account */ -#line 768 "beancount/parser/grammar.y" + case 103: /* custom_value: account */ +#line 785 "beancount/parser/grammar.y" { /* Obtain beancount.core.account.TYPE */ PyObject* module = PyImport_ImportModule("beancount.core.account"); @@ -2497,83 +2537,83 @@ YYLTYPE yylloc = yyloc_default; BUILDY(DECREF((yyvsp[0].pyobj), dtype), (yyval.pyobj), "custom_value", "OO", (yyvsp[0].pyobj), dtype); } -#line 2501 "beancount/parser/grammar.c" +#line 2541 "beancount/parser/grammar.c" break; - case 100: /* custom_value_list: %empty */ -#line 779 "beancount/parser/grammar.y" + case 104: /* custom_value_list: %empty */ +#line 796 "beancount/parser/grammar.y" { Py_INCREF(Py_None); (yyval.pyobj) = Py_None; } -#line 2510 "beancount/parser/grammar.c" +#line 2550 "beancount/parser/grammar.c" break; - case 101: /* custom_value_list: custom_value_list custom_value */ -#line 784 "beancount/parser/grammar.y" + case 105: /* custom_value_list: custom_value_list custom_value */ +#line 801 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "handle_list", "OO", (yyvsp[-1].pyobj), (yyvsp[0].pyobj)); } -#line 2519 "beancount/parser/grammar.c" +#line 2559 "beancount/parser/grammar.c" break; - case 102: /* custom: DATE CUSTOM STRING custom_value_list eol key_value_list */ -#line 791 "beancount/parser/grammar.y" + case 106: /* custom: DATE CUSTOM STRING custom_value_list eol key_value_list */ +#line 808 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-5].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "custom", "OOOO", (yyvsp[-5].pyobj), (yyvsp[-3].pyobj), (yyvsp[-2].pyobj), (yyvsp[0].pyobj)); } -#line 2528 "beancount/parser/grammar.c" +#line 2568 "beancount/parser/grammar.c" break; - case 115: /* option: OPTION STRING STRING eol */ -#line 812 "beancount/parser/grammar.y" + case 119: /* option: OPTION STRING STRING eol */ +#line 829 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-2].pyobj), (yyvsp[-1].pyobj)), (yyval.pyobj), "option", "OO", (yyvsp[-2].pyobj), (yyvsp[-1].pyobj)); } -#line 2537 "beancount/parser/grammar.c" +#line 2577 "beancount/parser/grammar.c" break; - case 116: /* include: INCLUDE STRING eol */ -#line 819 "beancount/parser/grammar.y" + case 120: /* include: INCLUDE STRING eol */ +#line 836 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj)), (yyval.pyobj), "include", "O", (yyvsp[-1].pyobj)); } -#line 2546 "beancount/parser/grammar.c" +#line 2586 "beancount/parser/grammar.c" break; - case 117: /* plugin: PLUGIN STRING eol */ -#line 826 "beancount/parser/grammar.y" + case 121: /* plugin: PLUGIN STRING eol */ +#line 843 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj)), (yyval.pyobj), "plugin", "OO", (yyvsp[-1].pyobj), Py_None); } -#line 2555 "beancount/parser/grammar.c" +#line 2595 "beancount/parser/grammar.c" break; - case 118: /* plugin: PLUGIN STRING STRING eol */ -#line 831 "beancount/parser/grammar.y" + case 122: /* plugin: PLUGIN STRING STRING eol */ +#line 848 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-2].pyobj), (yyvsp[-1].pyobj)), (yyval.pyobj), "plugin", "OO", (yyvsp[-2].pyobj), (yyvsp[-1].pyobj)); } -#line 2564 "beancount/parser/grammar.c" +#line 2604 "beancount/parser/grammar.c" break; - case 128: /* declarations: declarations entry */ -#line 849 "beancount/parser/grammar.y" + case 132: /* declarations: declarations entry */ +#line 866 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj), (yyvsp[0].pyobj)), (yyval.pyobj), "handle_list", "OO", (yyvsp[-1].pyobj), (yyvsp[0].pyobj)); } -#line 2573 "beancount/parser/grammar.c" +#line 2613 "beancount/parser/grammar.c" break; - case 129: /* declarations: declarations error */ -#line 854 "beancount/parser/grammar.y" + case 133: /* declarations: declarations error */ +#line 871 "beancount/parser/grammar.y" { /* * Ignore the error and continue reducing ({3d95e55b654e}). @@ -2591,29 +2631,29 @@ YYLTYPE yylloc = yyloc_default; */ (yyval.pyobj) = (yyvsp[-1].pyobj); } -#line 2595 "beancount/parser/grammar.c" +#line 2635 "beancount/parser/grammar.c" break; - case 130: /* declarations: %empty */ -#line 872 "beancount/parser/grammar.y" + case 134: /* declarations: %empty */ +#line 889 "beancount/parser/grammar.y" { Py_INCREF(Py_None); (yyval.pyobj) = Py_None; } -#line 2604 "beancount/parser/grammar.c" +#line 2644 "beancount/parser/grammar.c" break; - case 131: /* file: declarations $end */ -#line 880 "beancount/parser/grammar.y" + case 135: /* file: declarations $end */ +#line 897 "beancount/parser/grammar.y" { BUILDY(DECREF((yyvsp[-1].pyobj)), (yyval.pyobj), "store_result", "O", (yyvsp[-1].pyobj)); } -#line 2613 "beancount/parser/grammar.c" +#line 2653 "beancount/parser/grammar.c" break; -#line 2617 "beancount/parser/grammar.c" +#line 2657 "beancount/parser/grammar.c" default: break; } @@ -2842,7 +2882,7 @@ YYLTYPE yylloc = yyloc_default; return yyresult; } -#line 888 "beancount/parser/grammar.y" +#line 905 "beancount/parser/grammar.y" /* Get a printable version of a token name. */ diff --git a/beancount/parser/grammar.h b/beancount/parser/grammar.h index 89330baf7..11dba129b 100644 --- a/beancount/parser/grammar.h +++ b/beancount/parser/grammar.h @@ -123,36 +123,37 @@ const char* token_to_string(int token); LPAREN = 275, /* LPAREN */ RPAREN = 276, /* RPAREN */ FLAG = 277, /* FLAG */ - TXN = 278, /* TXN */ - BALANCE = 279, /* BALANCE */ - OPEN = 280, /* OPEN */ - CLOSE = 281, /* CLOSE */ - COMMODITY = 282, /* COMMODITY */ - PAD = 283, /* PAD */ - EVENT = 284, /* EVENT */ - PRICE = 285, /* PRICE */ - NOTE = 286, /* NOTE */ - DOCUMENT = 287, /* DOCUMENT */ - QUERY = 288, /* QUERY */ - CUSTOM = 289, /* CUSTOM */ - PUSHTAG = 290, /* PUSHTAG */ - POPTAG = 291, /* POPTAG */ - PUSHMETA = 292, /* PUSHMETA */ - POPMETA = 293, /* POPMETA */ - OPTION = 294, /* OPTION */ - INCLUDE = 295, /* INCLUDE */ - PLUGIN = 296, /* PLUGIN */ - NONE = 297, /* NONE */ - BOOL = 298, /* BOOL */ - DATE = 299, /* DATE */ - ACCOUNT = 300, /* ACCOUNT */ - CURRENCY = 301, /* CURRENCY */ - STRING = 302, /* STRING */ - NUMBER = 303, /* NUMBER */ - TAG = 304, /* TAG */ - LINK = 305, /* LINK */ - KEY = 306, /* KEY */ - NEGATIVE = 307 /* NEGATIVE */ + CAPITAL = 278, /* CAPITAL */ + TXN = 279, /* TXN */ + BALANCE = 280, /* BALANCE */ + OPEN = 281, /* OPEN */ + CLOSE = 282, /* CLOSE */ + COMMODITY = 283, /* COMMODITY */ + PAD = 284, /* PAD */ + EVENT = 285, /* EVENT */ + PRICE = 286, /* PRICE */ + NOTE = 287, /* NOTE */ + DOCUMENT = 288, /* DOCUMENT */ + QUERY = 289, /* QUERY */ + CUSTOM = 290, /* CUSTOM */ + PUSHTAG = 291, /* PUSHTAG */ + POPTAG = 292, /* POPTAG */ + PUSHMETA = 293, /* PUSHMETA */ + POPMETA = 294, /* POPMETA */ + OPTION = 295, /* OPTION */ + INCLUDE = 296, /* INCLUDE */ + PLUGIN = 297, /* PLUGIN */ + NONE = 298, /* NONE */ + BOOL = 299, /* BOOL */ + DATE = 300, /* DATE */ + ACCOUNT = 301, /* ACCOUNT */ + CURRENCY = 302, /* CURRENCY */ + STRING = 303, /* STRING */ + NUMBER = 304, /* NUMBER */ + TAG = 305, /* TAG */ + LINK = 306, /* LINK */ + KEY = 307, /* KEY */ + NEGATIVE = 308 /* NEGATIVE */ }; typedef enum yytokentype yytoken_kind_t; #endif @@ -171,7 +172,7 @@ union YYSTYPE PyObject* pyobj2; } pairobj; -#line 175 "beancount/parser/grammar.h" +#line 176 "beancount/parser/grammar.h" }; typedef union YYSTYPE YYSTYPE; diff --git a/beancount/parser/grammar.y b/beancount/parser/grammar.y index d61044510..b780377a5 100644 --- a/beancount/parser/grammar.y +++ b/beancount/parser/grammar.y @@ -182,6 +182,7 @@ void yyerror(YYLTYPE* loc, yyscan_t scanner, PyObject* builder, char const* mess %token LPAREN /* ( */ %token RPAREN /* ) */ %token FLAG /* Valid characters for flags */ +%token CAPITAL /* Valid characters for flags */ %token TXN /* 'txn' keyword */ %token BALANCE /* 'balance' keyword */ %token OPEN /* 'open' keyword */ @@ -215,6 +216,7 @@ void yyerror(YYLTYPE* loc, yyscan_t scanner, PyObject* builder, char const* mess /* Types for non-terminal symbols. */ %type txn %type optflag +%type currency %type account %type transaction %type posting @@ -275,7 +277,7 @@ void yyerror(YYLTYPE* loc, yyscan_t scanner, PyObject* builder, char const* mess %start file /* We have some number of expected shift/reduce conflicts at 'eol'. */ -%expect 7 +%expect 8 /*--------------------------------------------------------------------------------*/ @@ -300,6 +302,10 @@ txn: { $$ = '#'; } + | CAPITAL + { + $$ = $1; + } eol: EOL | YYEOF @@ -343,6 +349,16 @@ number_expr: $$ = $2; } +currency: + CURRENCY + { + $$ = $1; + } + | CAPITAL + { + $$ = PyUnicode_FromStringAndSize(&$1, 1); + } + txn_strings: %empty { @@ -399,6 +415,7 @@ optflag: $$ = '#'; } | FLAG + | CAPITAL price_annotation: incomplete_amount @@ -449,7 +466,7 @@ key_value_value: STRING | account | DATE - | CURRENCY + | currency | TAG | BOOL | NONE @@ -509,12 +526,12 @@ currency_list: Py_INCREF(Py_None); $$ = Py_None; } - | CURRENCY + | currency { BUILDY(DECREF($1), $$, "handle_list", "OO", Py_None, $1); } - | currency_list COMMA CURRENCY + | currency_list COMMA currency { BUILDY(DECREF($1, $3), $$, "handle_list", "OO", $1, $3); @@ -574,7 +591,7 @@ close: } commodity: - DATE COMMODITY CURRENCY eol key_value_list + DATE COMMODITY currency eol key_value_list { BUILDY(DECREF($1, $3, $5), $$, "commodity", "OOO", $1, $3, $5); @@ -595,21 +612,21 @@ balance: } amount: - number_expr CURRENCY + number_expr currency { BUILDY(DECREF($1, $2), $$, "amount", "OO", $1, $2); } amount_tolerance: - number_expr CURRENCY + number_expr currency { BUILDY(DECREF($1, $2), $$.pyobj1, "amount", "OO", $1, $2); $$.pyobj2 = Py_None; Py_INCREF(Py_None); } - | number_expr TILDE number_expr CURRENCY + | number_expr TILDE number_expr currency { BUILDY(DECREF($1, $4), $$.pyobj1, "amount", "OO", $1, $4); @@ -625,7 +642,7 @@ maybe_number: } maybe_currency: - CURRENCY + currency | %empty { Py_INCREF(MISSING_OBJ); @@ -633,7 +650,7 @@ maybe_currency: } compound_amount: - maybe_number CURRENCY + maybe_number currency { BUILDY(DECREF($1, $2), $$, "compound_amount", "OOO", $1, Py_None, $2); @@ -643,7 +660,7 @@ compound_amount: BUILDY(DECREF($1, $2), $$, "compound_amount", "OOO", $1, Py_None, $2); } - | maybe_number HASH maybe_number CURRENCY + | maybe_number HASH maybe_number currency { BUILDY(DECREF($1, $3, $4), $$, "compound_amount", "OOO", $1, $3, $4); @@ -702,7 +719,7 @@ cost_comp: } price: - DATE PRICE CURRENCY amount eol key_value_list + DATE PRICE currency amount eol key_value_list { BUILDY(DECREF($1, $3, $4, $6), $$, "price", "OOOO", $1, $3, $4, $6); diff --git a/beancount/parser/grammar_test.py b/beancount/parser/grammar_test.py index 42f4f6cc0..ce7d57592 100644 --- a/beancount/parser/grammar_test.py +++ b/beancount/parser/grammar_test.py @@ -1234,6 +1234,7 @@ def test_parse_currencies(self, entries, errors, _): 2014-01-19 open Assets:Period DJ.EURO 2014-01-19 open Assets:Apostrophe DJ'EURO 2014-01-19 open Assets:Numbers EURO123 + 2014-01-19 open Assets:Short V """ self.assertFalse(errors) diff --git a/beancount/parser/lexer.c b/beancount/parser/lexer.c index f2cd96127..935f413d4 100644 --- a/beancount/parser/lexer.c +++ b/beancount/parser/lexer.c @@ -1,4 +1,4 @@ -#line 2 "beancount/parser/lexer.c" +#line 1 "beancount/parser/lexer.c" #define PY_SSIZE_T_CLEAN #include @@ -54,7 +54,7 @@ yyscan_t yylex_free(yyscan_t scanner); void yylex_initialize(PyObject* file, PyObject* filename, int lineno, PyObject* missing_obj, yyscan_t scanner); -#line 58 "beancount/parser/lexer.c" +#line 57 "beancount/parser/lexer.c" #define YY_INT_ALIGNED short int @@ -445,38 +445,38 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static const flex_int16_t yy_accept[274] = +static const flex_int16_t yy_accept[273] = { 0, 0, 0, 0, 0, 59, 59, 61, 57, 3, 1, - 27, 57, 24, 57, 22, 23, 25, 19, 17, 20, - 21, 51, 26, 4, 12, 57, 57, 57, 57, 57, + 27, 57, 24, 22, 23, 25, 19, 17, 20, 21, + 51, 26, 4, 12, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, - 57, 15, 10, 16, 18, 57, 57, 57, 57, 57, - 57, 57, 57, 3, 27, 24, 25, 26, 58, 60, - 59, 3, 0, 50, 0, 52, 28, 0, 9, 0, - 51, 51, 4, 11, 0, 0, 8, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, - 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, - 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, - 56, 55, 52, 55, 58, 59, 0, 9, 9, 51, - 51, 51, 8, 49, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, - 8, 8, 54, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 34, 0, 0, 0, 0, 0, 29, - 0, 0, 0, 51, 49, 0, 0, 0, 0, 0, + 15, 10, 16, 18, 57, 57, 57, 57, 57, 57, + 57, 57, 3, 27, 24, 25, 26, 58, 60, 59, + 3, 0, 50, 0, 52, 0, 9, 0, 51, 51, + 4, 11, 28, 0, 0, 8, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 8, 8, 8, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 8, 7, 5, 0, 0, 0, 0, - - 0, 0, 0, 39, 31, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 6, 0, 32, 0, - 0, 0, 35, 0, 0, 0, 0, 0, 38, 0, - 0, 36, 0, 0, 0, 0, 49, 0, 0, 37, - 0, 0, 45, 46, 0, 42, 0, 0, 0, 49, - 30, 0, 0, 47, 44, 0, 41, 48, 0, 40, - 43, 33, 0 + + 0, 0, 0, 0, 0, 0, 0, 13, 14, 0, + 0, 0, 0, 0, 0, 0, 0, 2, 3, 56, + 55, 52, 55, 58, 59, 0, 9, 9, 51, 51, + 51, 8, 49, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, + 8, 54, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 34, 0, 0, 0, 0, 0, 29, 0, + 0, 0, 51, 49, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 7, 5, 0, 0, 0, 0, 0, + + 0, 0, 39, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 6, 0, 32, 0, 0, + 0, 35, 0, 0, 0, 0, 0, 38, 0, 0, + 36, 0, 0, 0, 0, 49, 0, 0, 37, 0, + 0, 45, 46, 0, 42, 0, 0, 0, 49, 30, + 0, 0, 47, 44, 0, 41, 48, 0, 40, 43, + 33, 0 } ; static const YY_CHAR yy_ec[256] = @@ -522,180 +522,182 @@ static const YY_CHAR yy_meta[71] = 1, 1, 8, 8, 8, 8, 8, 8, 8, 8 } ; -static const flex_int16_t yy_base[290] = +static const flex_int16_t yy_base[289] = { 0, - 0, 69, 75, 79, 819, 817, 819, 824, 71, 824, - 824, 66, 0, 77, 824, 824, 824, 824, 824, 824, - 76, 79, 824, 0, 796, 102, 794, 780, 782, 0, - 0, 764, 43, 742, 734, 733, 722, 711, 130, 701, - 698, 695, 824, 689, 824, 51, 674, 98, 54, 101, - 60, 123, 672, 173, 0, 185, 0, 0, 0, 824, - 0, 176, 102, 824, 728, 0, 824, 248, 252, 244, - 708, 255, 0, 824, 263, 0, 0, 280, 343, 213, - 628, 222, 198, 226, 218, 229, 629, 663, 662, 656, - 0, 666, 274, 275, 276, 277, 280, 281, 282, 67, - - 304, 293, 307, 294, 295, 306, 296, 308, 824, 824, - 0, 271, 278, 301, 317, 320, 323, 326, 824, 350, - 824, 824, 0, 824, 0, 0, 381, 0, 0, 377, - 666, 384, 392, 373, 342, 620, 348, 268, 351, 274, - 355, 621, 358, 361, 366, 369, 372, 384, 387, 652, - 653, 654, 824, 417, 406, 432, 434, 435, 436, 437, - 439, 441, 440, 658, 443, 444, 357, 448, 356, 657, - 403, 407, 410, 477, 442, 413, 611, 436, 418, 439, - 441, 453, 612, 456, 459, 462, 465, 468, 471, 474, - 477, 480, 483, 648, 0, 0, 528, 466, 529, 530, - - 533, 531, 532, 652, 650, 534, 536, 541, 535, 543, - 539, 537, 0, 650, 549, 510, 525, 533, 536, 539, - 542, 545, 548, 551, 554, 0, 0, 538, 648, 599, - 600, 550, 646, 601, 602, 603, 540, 549, 645, 604, - 605, 643, 610, 568, 571, 589, 0, 607, 616, 642, - 617, 619, 641, 637, 622, 542, 623, 625, 306, 0, - 297, 628, 634, 258, 246, 635, 170, 164, 636, 156, - 116, 70, 824, 691, 701, 711, 717, 724, 733, 739, - 745, 755, 765, 775, 785, 795, 802, 808, 813 + 0, 69, 75, 79, 811, 810, 804, 850, 71, 850, + 850, 66, 0, 850, 850, 850, 850, 850, 850, 76, + 79, 850, 0, 774, 108, 763, 749, 751, 0, 0, + 743, 43, 727, 709, 713, 711, 704, 69, 664, 661, + 658, 850, 655, 850, 38, 650, 44, 41, 104, 46, + 107, 651, 115, 0, 178, 0, 0, 0, 850, 0, + 247, 82, 850, 706, 0, 242, 246, 107, 691, 249, + 0, 850, 850, 257, 125, 137, 274, 343, 207, 645, + 216, 192, 220, 212, 223, 646, 284, 286, 290, 0, + 686, 276, 287, 288, 297, 289, 290, 294, 298, 336, + + 292, 296, 67, 308, 303, 317, 316, 850, 850, 0, + 262, 317, 320, 323, 328, 331, 334, 850, 395, 850, + 850, 0, 850, 0, 0, 390, 0, 0, 393, 686, + 396, 404, 382, 341, 640, 354, 257, 360, 301, 364, + 641, 367, 370, 373, 378, 381, 393, 396, 457, 459, + 463, 850, 318, 309, 426, 418, 445, 446, 313, 449, + 450, 454, 682, 453, 455, 456, 457, 368, 680, 416, + 419, 428, 487, 464, 447, 635, 450, 453, 455, 457, + 460, 636, 463, 475, 478, 481, 484, 487, 490, 493, + 496, 499, 560, 562, 564, 550, 551, 552, 553, 556, + + 554, 555, 676, 675, 557, 559, 558, 560, 564, 562, + 561, 0, 674, 571, 530, 548, 557, 560, 563, 566, + 569, 572, 575, 578, 0, 609, 579, 672, 623, 624, + 625, 671, 627, 626, 628, 563, 465, 669, 629, 631, + 668, 634, 592, 595, 614, 0, 640, 641, 666, 643, + 644, 663, 586, 651, 575, 648, 652, 509, 0, 476, + 654, 659, 357, 295, 661, 252, 241, 662, 237, 163, + 152, 850, 717, 727, 737, 743, 750, 759, 765, 771, + 781, 791, 801, 811, 821, 828, 834, 839 } ; -static const flex_int16_t yy_def[290] = +static const flex_int16_t yy_def[289] = { 0, - 273, 1, 274, 274, 275, 275, 273, 273, 273, 273, - 273, 276, 277, 273, 273, 273, 273, 273, 273, 273, - 278, 273, 273, 279, 273, 273, 26, 26, 26, 280, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 282, 283, 273, 284, 284, 285, 273, - 286, 273, 276, 273, 276, 277, 273, 278, 287, 273, - 273, 273, 279, 273, 288, 26, 26, 273, 26, 273, - 273, 273, 273, 273, 273, 273, 273, 26, 26, 26, - 280, 281, 281, 281, 281, 281, 281, 281, 281, 281, - - 281, 281, 281, 281, 281, 281, 281, 281, 273, 273, - 79, 273, 273, 273, 273, 273, 273, 273, 273, 282, - 273, 273, 277, 273, 285, 286, 287, 127, 127, 273, - 273, 273, 288, 289, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 26, - 26, 26, 273, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 273, 273, 273, 273, 289, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 26, 26, 26, 281, 281, 281, 281, - - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 79, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 79, 26, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 273, 273, 273, 273, 175, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 273, 175, - 281, 281, 281, 281, 281, 281, 281, 273, 281, 281, - 281, 281, 0, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273 + 272, 1, 273, 273, 274, 274, 272, 272, 272, 272, + 272, 275, 276, 272, 272, 272, 272, 272, 272, 277, + 272, 272, 278, 272, 272, 25, 25, 25, 279, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 281, 282, 272, 283, 283, 284, 272, 285, + 272, 275, 272, 275, 276, 277, 286, 272, 272, 272, + 278, 272, 272, 287, 25, 25, 272, 25, 272, 272, + 272, 272, 272, 272, 272, 272, 25, 25, 25, 279, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + + 280, 280, 280, 280, 280, 280, 280, 272, 272, 78, + 272, 272, 272, 272, 272, 272, 272, 272, 281, 272, + 272, 276, 272, 284, 285, 286, 126, 126, 272, 272, + 272, 287, 288, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 25, 25, + 25, 272, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 272, + 272, 272, 272, 288, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 25, 25, 25, 280, 280, 280, 280, 280, + + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 78, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 78, 25, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 272, 272, 272, 272, 174, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 272, 174, 280, + 280, 280, 280, 280, 280, 280, 272, 280, 280, 280, + 280, 0, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272 } ; -static const flex_int16_t yy_nxt[895] = +static const flex_int16_t yy_nxt[921] = { 0, - 8, 9, 10, 9, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 8, 21, 22, 23, 24, 25, - 26, 26, 26, 27, 26, 28, 26, 26, 29, 26, - 8, 30, 8, 31, 32, 33, 34, 35, 31, 31, - 31, 36, 31, 31, 37, 38, 39, 40, 31, 31, - 41, 31, 31, 31, 31, 42, 43, 44, 45, 8, - 8, 8, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 64, 62, 55, 62, 56, 60, 60, 60, 57, - 60, 60, 60, 68, 153, 94, 58, 153, 95, 68, - 68, 70, 68, 71, 96, 72, 65, 67, 67, 67, - - 67, 67, 67, 67, 67, 67, 67, 64, 68, 75, - 111, 111, 111, 114, 114, 76, 75, 161, 77, 78, - 116, 116, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 65, 153, 75, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 113, 113, 113, - 115, 115, 115, 102, 80, 81, 82, 83, 84, 85, - 86, 87, 103, 153, 120, 104, 62, 62, 105, 62, - 268, 106, 117, 117, 117, 122, 122, 153, 122, 122, - 122, 122, 122, 122, 122, 122, 122, 122, 123, 123, - - 123, 123, 122, 122, 122, 123, 123, 123, 123, 123, - 123, 123, 123, 123, 123, 122, 122, 123, 123, 123, - 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, - 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, - 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, - 122, 122, 122, 122, 122, 68, 70, 145, 145, 127, - 130, 68, 68, 153, 68, 127, 127, 70, 128, 71, - 75, 132, 79, 79, 79, 153, 75, 75, 147, 147, - 68, 144, 144, 144, 127, 146, 146, 146, 148, 148, - 148, 153, 153, 153, 153, 75, 134, 153, 153, 153, - - 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, - 153, 153, 153, 153, 153, 158, 154, 160, 159, 156, - 155, 153, 268, 153, 153, 153, 157, 186, 186, 164, - 111, 111, 111, 169, 188, 188, 167, 111, 111, 111, - 166, 162, 135, 136, 137, 138, 139, 140, 141, 142, - 273, 120, 170, 62, 163, 168, 79, 273, 165, 79, - 111, 111, 111, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 153, 153, 273, 111, 111, 111, 171, - 171, 171, 172, 172, 172, 173, 173, 173, 127, 70, - 78, 71, 210, 130, 127, 127, 70, 128, 71, 75, - - 174, 134, 134, 134, 212, 75, 75, 185, 185, 185, - 187, 187, 187, 127, 189, 189, 189, 79, 79, 79, - 79, 79, 79, 153, 75, 79, 79, 79, 79, 79, - 79, 191, 191, 191, 153, 176, 177, 178, 179, 180, - 181, 182, 183, 192, 192, 192, 193, 193, 193, 153, - 197, 153, 153, 153, 153, 198, 153, 153, 153, 78, - 153, 153, 213, 213, 213, 153, 213, 213, 213, 213, - 213, 213, 175, 175, 175, 199, 204, 218, 218, 203, - 202, 206, 207, 153, 200, 205, 201, 208, 211, 70, - 214, 71, 214, 215, 209, 217, 217, 217, 219, 219, - - 219, 220, 220, 229, 176, 177, 178, 179, 180, 181, - 182, 183, 221, 221, 221, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 223, 223, 223, - 224, 224, 224, 225, 225, 225, 226, 226, 226, 226, - 226, 226, 226, 226, 226, 153, 153, 153, 153, 153, - 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, - 153, 70, 214, 71, 214, 215, 153, 153, 238, 175, - 175, 175, 228, 248, 230, 231, 232, 236, 237, 235, - 239, 233, 240, 234, 175, 175, 175, 251, 256, 241, - 255, 242, 175, 175, 175, 175, 175, 175, 244, 244, - - 244, 245, 245, 245, 246, 246, 246, 247, 247, 247, - 247, 247, 247, 247, 247, 247, 153, 153, 153, 153, - 153, 153, 153, 259, 153, 259, 243, 260, 260, 260, - 260, 260, 260, 153, 153, 249, 153, 252, 258, 153, - 153, 257, 153, 250, 261, 153, 253, 254, 260, 260, - 260, 153, 153, 153, 153, 265, 264, 262, 153, 153, - 153, 263, 153, 153, 267, 153, 243, 153, 271, 153, - 227, 222, 216, 266, 153, 153, 196, 195, 269, 194, - 190, 184, 131, 153, 270, 152, 151, 150, 149, 143, - 272, 59, 59, 59, 59, 59, 59, 59, 59, 59, - - 59, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 63, 63, 63, 63, 63, 63, 63, 63, 63, - 63, 66, 66, 66, 131, 66, 66, 69, 69, 69, - 273, 118, 69, 73, 73, 112, 73, 73, 73, 73, - 73, 73, 73, 91, 91, 91, 110, 91, 91, 92, - 109, 108, 107, 92, 92, 119, 119, 101, 119, 119, - 119, 119, 119, 119, 119, 121, 121, 100, 121, 121, - 121, 121, 121, 121, 121, 124, 124, 99, 124, 124, - 124, 124, 124, 124, 124, 125, 98, 97, 125, 125, - 125, 125, 125, 125, 125, 126, 126, 93, 126, 126, - - 126, 126, 126, 126, 126, 129, 129, 129, 90, 89, - 129, 133, 133, 133, 88, 74, 133, 175, 273, 60, - 175, 60, 175, 7, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273 + 8, 9, 10, 9, 11, 12, 13, 8, 14, 15, + 16, 17, 18, 19, 8, 20, 21, 22, 23, 24, + 25, 25, 25, 26, 25, 27, 25, 25, 28, 25, + 8, 29, 8, 30, 31, 32, 33, 34, 30, 30, + 30, 35, 30, 30, 36, 37, 38, 39, 30, 30, + 40, 30, 30, 30, 30, 41, 42, 43, 44, 8, + 8, 8, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 63, 61, 54, 61, 55, 59, 59, 59, 56, + 59, 59, 59, 66, 152, 93, 57, 63, 94, 66, + 66, 68, 66, 69, 95, 70, 64, 110, 110, 110, + + 113, 113, 101, 112, 112, 112, 115, 115, 66, 73, + 73, 102, 64, 165, 103, 74, 119, 104, 61, 68, + 105, 75, 74, 129, 76, 77, 272, 272, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 272, 272, + 74, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 114, 114, 114, 116, 116, 116, 152, + 79, 80, 81, 82, 83, 84, 85, 86, 121, 121, + 152, 121, 121, 121, 121, 121, 121, 121, 121, 121, + 121, 122, 122, 122, 122, 121, 121, 121, 122, 122, + 122, 122, 122, 122, 122, 122, 122, 122, 121, 121, + 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, + 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, + 122, 122, 122, 121, 121, 121, 121, 121, 121, 121, + 121, 121, 121, 121, 121, 121, 121, 121, 61, 66, + 61, 144, 144, 126, 152, 66, 66, 267, 66, 126, + 126, 68, 127, 69, 74, 131, 78, 78, 78, 152, + 74, 74, 146, 146, 66, 143, 143, 143, 126, 145, + 145, 145, 147, 147, 147, 272, 272, 272, 272, 74, + 133, 272, 272, 152, 133, 133, 133, 133, 133, 133, + + 133, 133, 133, 133, 152, 152, 152, 152, 149, 152, + 150, 152, 152, 152, 152, 152, 185, 185, 153, 151, + 152, 110, 110, 110, 157, 152, 152, 158, 163, 159, + 152, 155, 154, 152, 152, 152, 134, 135, 136, 137, + 138, 139, 140, 141, 272, 272, 156, 164, 160, 166, + 272, 196, 167, 152, 168, 202, 78, 272, 197, 78, + 169, 187, 187, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 161, 152, 272, 110, 110, 110, 110, + 110, 110, 110, 110, 110, 152, 162, 170, 170, 170, + 171, 171, 171, 172, 172, 172, 119, 126, 61, 77, + + 133, 133, 133, 126, 126, 68, 127, 69, 68, 129, + 69, 74, 173, 184, 184, 184, 211, 74, 74, 186, + 186, 186, 126, 188, 188, 188, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 152, 74, 78, 78, 78, + 190, 190, 190, 152, 175, 176, 177, 178, 179, 180, + 181, 182, 191, 191, 191, 192, 192, 192, 272, 272, + 272, 272, 152, 152, 272, 272, 152, 152, 199, 198, + 152, 152, 152, 152, 152, 212, 212, 212, 212, 212, + 212, 77, 152, 194, 193, 195, 203, 212, 212, 212, + 201, 209, 206, 152, 204, 205, 200, 210, 207, 68, + + 213, 69, 213, 214, 255, 208, 174, 174, 174, 216, + 216, 216, 217, 217, 218, 218, 218, 219, 219, 220, + 220, 220, 133, 133, 133, 267, 175, 176, 177, 178, + 179, 180, 181, 182, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 222, 222, 222, 223, 223, 223, 224, + 224, 224, 225, 225, 225, 225, 225, 225, 225, 225, + 225, 272, 272, 272, 272, 272, 272, 152, 152, 152, + 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, + 152, 152, 226, 68, 213, 69, 213, 214, 228, 174, + 174, 174, 152, 237, 227, 236, 152, 229, 230, 231, + + 235, 238, 234, 152, 232, 239, 233, 174, 174, 174, + 272, 272, 240, 254, 247, 241, 174, 174, 174, 174, + 174, 174, 243, 243, 243, 244, 244, 244, 245, 245, + 245, 246, 246, 246, 246, 246, 246, 246, 246, 246, + 152, 152, 152, 152, 152, 152, 152, 258, 152, 258, + 242, 259, 259, 259, 259, 259, 259, 152, 152, 248, + 152, 152, 250, 251, 257, 152, 256, 249, 152, 152, + 252, 152, 253, 259, 259, 259, 152, 260, 152, 152, + 152, 263, 261, 152, 264, 152, 152, 262, 152, 152, + 242, 266, 152, 152, 270, 221, 215, 152, 265, 152, + + 189, 183, 130, 152, 268, 148, 142, 130, 272, 269, + 117, 111, 109, 108, 107, 106, 271, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 65, 65, 65, + 100, 65, 65, 67, 67, 67, 99, 98, 67, 71, + 71, 97, 71, 71, 71, 71, 71, 71, 71, 90, + 90, 90, 96, 90, 90, 91, 92, 89, 88, 91, + 91, 118, 118, 87, 118, 118, 118, 118, 118, 118, + 118, 120, 120, 72, 120, 120, 120, 120, 120, 120, + + 120, 123, 123, 272, 123, 123, 123, 123, 123, 123, + 123, 124, 59, 59, 124, 124, 124, 124, 124, 124, + 124, 125, 125, 272, 125, 125, 125, 125, 125, 125, + 125, 128, 128, 128, 272, 272, 128, 132, 132, 132, + 272, 272, 132, 174, 272, 272, 174, 272, 174, 7, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272 } ; -static const flex_int16_t yy_chk[895] = +static const flex_int16_t yy_chk[921] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -705,104 +707,106 @@ static const flex_int16_t yy_chk[895] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 12, 9, 2, 9, 2, 3, 3, 3, 2, - 4, 4, 4, 21, 100, 33, 2, 272, 33, 21, - 21, 22, 21, 22, 33, 22, 12, 14, 14, 14, - - 14, 14, 14, 14, 14, 14, 14, 63, 21, 26, - 46, 46, 46, 49, 49, 26, 26, 100, 26, 26, - 51, 51, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 63, 271, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 48, 48, 48, - 50, 50, 50, 39, 26, 26, 26, 26, 26, 26, - 26, 26, 39, 270, 54, 39, 54, 62, 39, 62, - 268, 39, 52, 52, 52, 56, 56, 267, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 68, 70, 83, 83, 69, - 70, 68, 68, 265, 68, 69, 69, 72, 69, 72, - 75, 72, 80, 80, 80, 264, 75, 75, 85, 85, - 68, 82, 82, 82, 69, 84, 84, 84, 86, 86, - 86, 93, 94, 95, 96, 75, 78, 97, 98, 99, - - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 102, 104, 105, 107, 261, 97, 93, 99, 98, 95, - 94, 101, 259, 106, 103, 108, 96, 138, 138, 102, - 112, 112, 112, 107, 140, 140, 105, 113, 113, 113, - 104, 101, 78, 78, 78, 78, 78, 78, 78, 78, - 79, 120, 108, 120, 101, 106, 79, 79, 103, 79, - 114, 114, 114, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 169, 167, 79, 115, 115, 115, 116, - 116, 116, 117, 117, 117, 118, 118, 118, 127, 130, - 134, 130, 167, 130, 127, 127, 132, 127, 132, 133, - - 132, 135, 135, 135, 169, 133, 133, 137, 137, 137, - 139, 139, 139, 127, 141, 141, 141, 143, 143, 143, - 144, 144, 144, 155, 133, 145, 145, 145, 146, 146, - 146, 147, 147, 147, 154, 134, 134, 134, 134, 134, - 134, 134, 134, 148, 148, 148, 149, 149, 149, 156, - 154, 157, 158, 159, 160, 155, 161, 163, 162, 175, - 165, 166, 171, 171, 171, 168, 172, 172, 172, 173, - 173, 173, 176, 176, 176, 156, 161, 179, 179, 160, - 159, 163, 165, 198, 157, 162, 158, 166, 168, 174, - 174, 174, 174, 174, 166, 178, 178, 178, 180, 180, - - 180, 181, 181, 198, 175, 175, 175, 175, 175, 175, - 175, 175, 182, 182, 182, 184, 184, 184, 185, 185, - 185, 186, 186, 186, 187, 187, 187, 188, 188, 188, - 189, 189, 189, 190, 190, 190, 191, 191, 191, 192, - 192, 192, 193, 193, 193, 197, 199, 200, 202, 203, - 201, 206, 209, 207, 212, 228, 211, 237, 208, 256, - 210, 215, 215, 215, 215, 215, 238, 232, 209, 216, - 216, 216, 197, 228, 199, 200, 201, 207, 208, 206, - 210, 202, 211, 203, 217, 217, 217, 232, 238, 211, - 237, 212, 218, 218, 218, 219, 219, 219, 220, 220, - - 220, 221, 221, 221, 222, 222, 222, 223, 223, 223, - 224, 224, 224, 225, 225, 225, 230, 231, 234, 235, - 236, 240, 241, 243, 248, 243, 243, 244, 244, 244, - 245, 245, 245, 249, 251, 230, 252, 234, 241, 255, - 257, 240, 258, 231, 248, 262, 235, 236, 246, 246, - 246, 263, 266, 269, 254, 255, 252, 249, 253, 250, - 242, 251, 239, 233, 258, 229, 214, 205, 266, 204, - 194, 183, 177, 257, 170, 164, 152, 151, 262, 150, - 142, 136, 131, 92, 263, 90, 89, 88, 87, 81, - 269, 274, 274, 274, 274, 274, 274, 274, 274, 274, - - 274, 275, 275, 275, 275, 275, 275, 275, 275, 275, - 275, 276, 276, 276, 276, 276, 276, 276, 276, 276, - 276, 277, 277, 277, 71, 277, 277, 278, 278, 278, - 65, 53, 278, 279, 279, 47, 279, 279, 279, 279, - 279, 279, 279, 280, 280, 280, 44, 280, 280, 281, - 42, 41, 40, 281, 281, 282, 282, 38, 282, 282, - 282, 282, 282, 282, 282, 283, 283, 37, 283, 283, - 283, 283, 283, 283, 283, 284, 284, 36, 284, 284, - 284, 284, 284, 284, 284, 285, 35, 34, 285, 285, - 285, 285, 285, 285, 285, 286, 286, 32, 286, 286, - - 286, 286, 286, 286, 286, 287, 287, 287, 29, 28, - 287, 288, 288, 288, 27, 25, 288, 289, 7, 6, - 289, 5, 289, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273 - + 4, 4, 4, 20, 103, 32, 2, 62, 32, 20, + 20, 21, 20, 21, 32, 21, 12, 45, 45, 45, + + 48, 48, 38, 47, 47, 47, 50, 50, 20, 25, + 25, 38, 62, 103, 38, 25, 53, 38, 53, 68, + 38, 25, 25, 68, 25, 25, 75, 75, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 76, 76, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 49, 49, 49, 51, 51, 51, 271, + 25, 25, 25, 25, 25, 25, 25, 25, 55, 55, + 270, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 61, 66, + 61, 82, 82, 67, 269, 66, 66, 267, 66, 67, + 67, 70, 67, 70, 74, 70, 79, 79, 79, 266, + 74, 74, 84, 84, 66, 81, 81, 81, 67, 83, + 83, 83, 85, 85, 85, 87, 87, 88, 88, 74, + 77, 89, 89, 92, 77, 77, 77, 77, 77, 77, + + 77, 77, 77, 77, 93, 94, 96, 97, 87, 101, + 88, 98, 264, 102, 95, 99, 137, 137, 92, 89, + 105, 111, 111, 111, 96, 104, 154, 97, 101, 98, + 159, 94, 93, 107, 106, 153, 77, 77, 77, 77, + 77, 77, 77, 77, 78, 78, 95, 102, 99, 104, + 78, 153, 105, 100, 106, 159, 78, 78, 154, 78, + 107, 139, 139, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 100, 263, 78, 112, 112, 112, 113, + 113, 113, 114, 114, 114, 168, 100, 115, 115, 115, + 116, 116, 116, 117, 117, 117, 119, 126, 119, 133, + + 134, 134, 134, 126, 126, 129, 126, 129, 131, 129, + 131, 132, 131, 136, 136, 136, 168, 132, 132, 138, + 138, 138, 126, 140, 140, 140, 142, 142, 142, 143, + 143, 143, 144, 144, 144, 156, 132, 145, 145, 145, + 146, 146, 146, 155, 133, 133, 133, 133, 133, 133, + 133, 133, 147, 147, 147, 148, 148, 148, 149, 149, + 150, 150, 157, 158, 151, 151, 160, 161, 156, 155, + 164, 162, 165, 166, 167, 170, 170, 170, 171, 171, + 171, 174, 237, 150, 149, 151, 160, 172, 172, 172, + 158, 166, 164, 260, 161, 162, 157, 167, 165, 173, + + 173, 173, 173, 173, 237, 165, 175, 175, 175, 177, + 177, 177, 178, 178, 179, 179, 179, 180, 180, 181, + 181, 181, 183, 183, 183, 258, 174, 174, 174, 174, + 174, 174, 174, 174, 184, 184, 184, 185, 185, 185, + 186, 186, 186, 187, 187, 187, 188, 188, 188, 189, + 189, 189, 190, 190, 190, 191, 191, 191, 192, 192, + 192, 193, 193, 194, 194, 195, 195, 196, 197, 198, + 199, 201, 202, 200, 205, 207, 206, 208, 211, 210, + 236, 209, 193, 214, 214, 214, 214, 214, 197, 215, + 215, 215, 255, 208, 196, 207, 227, 198, 199, 200, + + 206, 209, 205, 253, 201, 210, 202, 216, 216, 216, + 226, 226, 210, 236, 227, 211, 217, 217, 217, 218, + 218, 218, 219, 219, 219, 220, 220, 220, 221, 221, + 221, 222, 222, 222, 223, 223, 223, 224, 224, 224, + 229, 230, 231, 234, 233, 235, 239, 242, 240, 242, + 242, 243, 243, 243, 244, 244, 244, 247, 248, 229, + 250, 251, 231, 233, 240, 256, 239, 230, 254, 257, + 234, 261, 235, 245, 245, 245, 262, 247, 265, 268, + 252, 251, 248, 249, 254, 241, 238, 250, 232, 228, + 213, 257, 204, 203, 265, 182, 176, 169, 256, 163, + + 141, 135, 130, 91, 261, 86, 80, 69, 64, 262, + 52, 46, 43, 41, 40, 39, 268, 273, 273, 273, + 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, + 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, + 37, 276, 276, 277, 277, 277, 36, 35, 277, 278, + 278, 34, 278, 278, 278, 278, 278, 278, 278, 279, + 279, 279, 33, 279, 279, 280, 31, 28, 27, 280, + 280, 281, 281, 26, 281, 281, 281, 281, 281, 281, + 281, 282, 282, 24, 282, 282, 282, 282, 282, 282, + + 282, 283, 283, 7, 283, 283, 283, 283, 283, 283, + 283, 284, 6, 5, 284, 284, 284, 284, 284, 284, + 284, 285, 285, 0, 285, 285, 285, 285, 285, 285, + 285, 286, 286, 286, 0, 0, 286, 287, 287, 287, + 0, 0, 287, 288, 0, 0, 288, 0, 288, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272 } ; /* Table of booleans, true if rule could match eol. */ static const flex_int32_t yy_rule_can_match_eol[61] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; @@ -862,12 +866,12 @@ int pyfile_read_into(PyObject *file, char *buf, size_t max_size); yycolumn += yyleng; \ } -#line 866 "beancount/parser/lexer.c" +#line 869 "beancount/parser/lexer.c" #line 133 "beancount/parser/lexer.l" /* Characters that may be used as flags. Single-character letters may also be * used as flags, but must be prefixed by a quote, as in "'P' for "P". */ -#line 871 "beancount/parser/lexer.c" +#line 874 "beancount/parser/lexer.c" #define INITIAL 0 #define INVALID 1 @@ -1158,7 +1162,7 @@ YY_DECL /* Newlines matter. */ -#line 1162 "beancount/parser/lexer.c" +#line 1165 "beancount/parser/lexer.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -1186,13 +1190,13 @@ YY_DECL while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 274 ) + if ( yy_current_state >= 273 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } - while ( yy_current_state != 273 ); + while ( yy_current_state != 272 ); yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; @@ -1287,10 +1291,10 @@ YY_RULE_SETUP * underscore (_), dash (-), or quote ('). * The pattern has to be kept in sync with beancount.core.amount.CURRENCY_RE. * - * In Beancount v3 (C++ version), a single character (e.g. "V" for Visa) is a - * valid currency. v2 uses the GNU flex scanner which does not have the - * lookahead capability required to make this possible but the v3 C++ scanner - * uses Genivia's RE-Flex which supports a lookahead and it will. + * Upper case letters are both valid currencies and valid flags. To + * kepe the lexer simple, these are lexed as their own token, see the + * rule for CAPITAL below. They are interpreted ad a flag or as a + * currency in the grammar. * * Example currencies: * "AAPL" (stock) @@ -1422,114 +1426,126 @@ YY_RULE_SETUP return FLAG; } YY_BREAK +/* The whitespace lookahead is not necessary to correctly parse valid + * ledgers, but it enables the lexer to throw an error sooner on + * invalid input. For example, without the lookahead, an invalid + * account name like "Assets:invalid" is tokenized into CAPITAL + * ('A'), KEY ('ssets:'), erorr ('invalid'). With the lookahead the + * lexer errors out immediately. The first form would be anyhow + * rejected by the grammar, but the latter seems preferable. */ case 28: +/* rule 28 can match eol */ +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ +YY_LINENO_REWIND_TO(yy_bp + 1); +yyg->yy_c_buf_p = yy_cp = yy_bp + 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 234 "beancount/parser/lexer.l" +#line 241 "beancount/parser/lexer.l" { - yylval->character = yytext[1]; - return FLAG; + yylval->character = yytext[0]; + return CAPITAL; } YY_BREAK /* Keywords. */ case 29: YY_RULE_SETUP -#line 240 "beancount/parser/lexer.l" +#line 247 "beancount/parser/lexer.l" { return TXN; } YY_BREAK case 30: YY_RULE_SETUP -#line 241 "beancount/parser/lexer.l" +#line 248 "beancount/parser/lexer.l" { return BALANCE; } YY_BREAK case 31: YY_RULE_SETUP -#line 242 "beancount/parser/lexer.l" +#line 249 "beancount/parser/lexer.l" { return OPEN; } YY_BREAK case 32: YY_RULE_SETUP -#line 243 "beancount/parser/lexer.l" +#line 250 "beancount/parser/lexer.l" { return CLOSE; } YY_BREAK case 33: YY_RULE_SETUP -#line 244 "beancount/parser/lexer.l" +#line 251 "beancount/parser/lexer.l" { return COMMODITY; } YY_BREAK case 34: YY_RULE_SETUP -#line 245 "beancount/parser/lexer.l" +#line 252 "beancount/parser/lexer.l" { return PAD; } YY_BREAK case 35: YY_RULE_SETUP -#line 246 "beancount/parser/lexer.l" +#line 253 "beancount/parser/lexer.l" { return EVENT; } YY_BREAK case 36: YY_RULE_SETUP -#line 247 "beancount/parser/lexer.l" +#line 254 "beancount/parser/lexer.l" { return QUERY; } YY_BREAK case 37: YY_RULE_SETUP -#line 248 "beancount/parser/lexer.l" +#line 255 "beancount/parser/lexer.l" { return CUSTOM; } YY_BREAK case 38: YY_RULE_SETUP -#line 249 "beancount/parser/lexer.l" +#line 256 "beancount/parser/lexer.l" { return PRICE; } YY_BREAK case 39: YY_RULE_SETUP -#line 250 "beancount/parser/lexer.l" +#line 257 "beancount/parser/lexer.l" { return NOTE; } YY_BREAK case 40: YY_RULE_SETUP -#line 251 "beancount/parser/lexer.l" +#line 258 "beancount/parser/lexer.l" { return DOCUMENT; } YY_BREAK case 41: YY_RULE_SETUP -#line 252 "beancount/parser/lexer.l" +#line 259 "beancount/parser/lexer.l" { return PUSHTAG; } YY_BREAK case 42: YY_RULE_SETUP -#line 253 "beancount/parser/lexer.l" +#line 260 "beancount/parser/lexer.l" { return POPTAG; } YY_BREAK case 43: YY_RULE_SETUP -#line 254 "beancount/parser/lexer.l" +#line 261 "beancount/parser/lexer.l" { return PUSHMETA; } YY_BREAK case 44: YY_RULE_SETUP -#line 255 "beancount/parser/lexer.l" +#line 262 "beancount/parser/lexer.l" { return POPMETA; } YY_BREAK case 45: YY_RULE_SETUP -#line 256 "beancount/parser/lexer.l" +#line 263 "beancount/parser/lexer.l" { return OPTION; } YY_BREAK case 46: YY_RULE_SETUP -#line 257 "beancount/parser/lexer.l" +#line 264 "beancount/parser/lexer.l" { return PLUGIN; } YY_BREAK case 47: YY_RULE_SETUP -#line 258 "beancount/parser/lexer.l" +#line 265 "beancount/parser/lexer.l" { return INCLUDE; } YY_BREAK /* Dates. */ case 48: YY_RULE_SETUP -#line 261 "beancount/parser/lexer.l" +#line 268 "beancount/parser/lexer.l" { return TOKEN(DATE, yytext); } @@ -1537,7 +1553,7 @@ YY_RULE_SETUP /* Account names. */ case 49: YY_RULE_SETUP -#line 266 "beancount/parser/lexer.l" +#line 273 "beancount/parser/lexer.l" { return TOKEN(ACCOUNT, yytext); } @@ -1546,7 +1562,7 @@ YY_RULE_SETUP case 50: /* rule 50 can match eol */ YY_RULE_SETUP -#line 271 "beancount/parser/lexer.l" +#line 278 "beancount/parser/lexer.l" { return TOKEN(STRING, yytext + 1, yyleng - 2); } @@ -1554,7 +1570,7 @@ YY_RULE_SETUP /* Numbers. */ case 51: YY_RULE_SETUP -#line 276 "beancount/parser/lexer.l" +#line 283 "beancount/parser/lexer.l" { return TOKEN(NUMBER, yytext); } @@ -1562,7 +1578,7 @@ YY_RULE_SETUP /* Tags. */ case 52: YY_RULE_SETUP -#line 281 "beancount/parser/lexer.l" +#line 288 "beancount/parser/lexer.l" { return TOKEN(TAG, yytext + 1, yyleng - 1); } @@ -1570,7 +1586,7 @@ YY_RULE_SETUP /* Links. */ case 53: YY_RULE_SETUP -#line 286 "beancount/parser/lexer.l" +#line 293 "beancount/parser/lexer.l" { return TOKEN(LINK, yytext + 1, yyleng - 1); } @@ -1581,7 +1597,7 @@ case 54: yyg->yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 291 "beancount/parser/lexer.l" +#line 298 "beancount/parser/lexer.l" { return TOKEN(KEY, yytext, yyleng); } @@ -1594,7 +1610,7 @@ case 55: yyg->yy_c_buf_p = yy_cp = yy_bp + 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 298 "beancount/parser/lexer.l" +#line 305 "beancount/parser/lexer.l" { BEGIN(IGNORE); } YY_BREAK case 56: @@ -1602,13 +1618,13 @@ case 56: yyg->yy_c_buf_p = yy_cp = yy_bp + 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP -#line 299 "beancount/parser/lexer.l" +#line 306 "beancount/parser/lexer.l" { BEGIN(IGNORE); } YY_BREAK /* Default rule. {bf253a29a820} */ case 57: YY_RULE_SETUP -#line 302 "beancount/parser/lexer.l" +#line 309 "beancount/parser/lexer.l" { unput(*yytext); BEGIN(INVALID); @@ -1617,7 +1633,7 @@ YY_RULE_SETUP case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(INVALID): case YY_STATE_EOF(IGNORE): -#line 307 "beancount/parser/lexer.l" +#line 314 "beancount/parser/lexer.l" { /* Ensure location data is populated. */ YY_USER_ACTION; @@ -1627,7 +1643,7 @@ case YY_STATE_EOF(IGNORE): /* Ivalid input: skip over to to the next whitespace character. */ case 58: YY_RULE_SETUP -#line 314 "beancount/parser/lexer.l" +#line 321 "beancount/parser/lexer.l" { PyObject* input = PyUnicode_Decode(yytext, yyleng, "utf-8", "backslashreplace"); build_lexer_error(yylloc, builder, "Invalid token: '%U'", input); @@ -1638,17 +1654,17 @@ YY_RULE_SETUP /* Ignore input till the newline. */ case 59: YY_RULE_SETUP -#line 321 "beancount/parser/lexer.l" +#line 328 "beancount/parser/lexer.l" { BEGIN(INITIAL); } YY_BREAK case 60: YY_RULE_SETUP -#line 325 "beancount/parser/lexer.l" +#line 332 "beancount/parser/lexer.l" ECHO; YY_BREAK -#line 1652 "beancount/parser/lexer.c" +#line 1667 "beancount/parser/lexer.c" case YY_END_OF_BUFFER: { @@ -1947,7 +1963,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 274 ) + if ( yy_current_state >= 273 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; @@ -1976,11 +1992,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 274 ) + if ( yy_current_state >= 273 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - yy_is_jam = (yy_current_state == 273); + yy_is_jam = (yy_current_state == 272); (void)yyg; return yy_is_jam ? 0 : yy_current_state; @@ -2853,7 +2869,7 @@ void yyfree (void * ptr , yyscan_t yyscanner) #define YYTABLES_NAME "yytables" -#line 325 "beancount/parser/lexer.l" +#line 332 "beancount/parser/lexer.l" yyscan_t yylex_new(void) diff --git a/beancount/parser/lexer.h b/beancount/parser/lexer.h index 64baeeee8..e905f0020 100644 --- a/beancount/parser/lexer.h +++ b/beancount/parser/lexer.h @@ -2,7 +2,7 @@ #define yyHEADER_H 1 #define yyIN_HEADER 1 -#line 6 "beancount/parser/lexer.h" +#line 5 "beancount/parser/lexer.h" #define PY_SSIZE_T_CLEAN #include @@ -58,7 +58,7 @@ yyscan_t yylex_free(yyscan_t scanner); void yylex_initialize(PyObject* file, PyObject* filename, int lineno, PyObject* missing_obj, yyscan_t scanner); -#line 62 "beancount/parser/lexer.h" +#line 61 "beancount/parser/lexer.h" #define YY_INT_ALIGNED short int @@ -572,9 +572,9 @@ extern int yylex \ #undef yyTABLES_NAME #endif -#line 325 "beancount/parser/lexer.l" +#line 332 "beancount/parser/lexer.l" -#line 579 "beancount/parser/lexer.h" +#line 578 "beancount/parser/lexer.h" #undef yyIN_HEADER #endif /* yyHEADER_H */ diff --git a/beancount/parser/lexer.l b/beancount/parser/lexer.l index 333707007..9d2c6ddca 100644 --- a/beancount/parser/lexer.l +++ b/beancount/parser/lexer.l @@ -173,10 +173,10 @@ NULL { * underscore (_), dash (-), or quote ('). * The pattern has to be kept in sync with beancount.core.amount.CURRENCY_RE. * - * In Beancount v3 (C++ version), a single character (e.g. "V" for Visa) is a - * valid currency. v2 uses the GNU flex scanner which does not have the - * lookahead capability required to make this possible but the v3 C++ scanner - * uses Genivia's RE-Flex which supports a lookahead and it will. + * Upper case letters are both valid currencies and valid flags. To + * kepe the lexer simple, these are lexed as their own token, see the + * rule for CAPITAL below. They are interpreted ad a flag or as a + * currency in the grammar. * * Example currencies: * "AAPL" (stock) @@ -230,9 +230,16 @@ NULL { yylval->character = yytext[0]; return FLAG; } -'[A-Z] { - yylval->character = yytext[1]; - return FLAG; + /* The whitespace lookahead is not necessary to correctly parse valid + * ledgers, but it enables the lexer to throw an error sooner on + * invalid input. For example, without the lookahead, an invalid + * account name like "Assets:invalid" is tokenized into CAPITAL + * ('A'), KEY ('ssets:'), erorr ('invalid'). With the lookahead the + * lexer errors out immediately. The first form would be anyhow + * rejected by the grammar, but the latter seems preferable. */ +[A-Z]/[ \t\n] { + yylval->character = yytext[0]; + return CAPITAL; } /* Keywords. */ diff --git a/beancount/parser/lexer_test.py b/beancount/parser/lexer_test.py index daea59f4a..e442bae69 100644 --- a/beancount/parser/lexer_test.py +++ b/beancount/parser/lexer_test.py @@ -67,7 +67,7 @@ def test_lex_iter(self, tokens, errors): #sometag123 ^sometag123 somekey: - % # 'V 'C + % # V C """ self.assertEqual([ ('DATE', 1, b'2013-05-18', datetime.date(2013, 5, 18)), @@ -87,9 +87,8 @@ def test_lex_iter(self, tokens, errors): ('CURRENCY', 5, b'TEST-D', 'TEST-D'), ('CURRENCY', 5, b'TEST-3', 'TEST-3'), ('CURRENCY', 5, b'NT.TO', 'NT.TO'), - # TODO(blais): Not supported in flex parser. - ('error', 5, b'V', None), - ('error', 5, b'P', None), + ('CAPITAL', 5, b'V', None), + ('CAPITAL', 5, b'P', None), ('CURRENCY', 5, b'V12', 'V12'), ('EOL', 6, b'\n', None), ('CURRENCY', 6, b'/NQH21', '/NQH21'), diff --git a/beancount/parser/printer.py b/beancount/parser/printer.py index d7a26abc3..d36471e06 100644 --- a/beancount/parser/printer.py +++ b/beancount/parser/printer.py @@ -368,8 +368,6 @@ def render_flag(inflag: Optional[str]) -> str: """Render a flag, which can be None, a symbol of a character to a string.""" if not inflag: return '' - if re.match(r"[A-Z]$", inflag): - return "'{}".format(inflag) return inflag From 6bf1f19eda060aa179cecfec9ac1414532fb93de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Oct 2023 01:12:44 +0000 Subject: [PATCH 29/36] Bump urllib3 from 1.26.16 to 1.26.18 in /requirements Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.26.16 to 1.26.18. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/1.26.16...1.26.18) --- updated-dependencies: - dependency-name: urllib3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements/dev_lock.txt | 6 +++--- requirements/tools_lock.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/requirements/dev_lock.txt b/requirements/dev_lock.txt index 64e976356..9c611ec3c 100644 --- a/requirements/dev_lock.txt +++ b/requirements/dev_lock.txt @@ -410,9 +410,9 @@ uritemplate==4.1.1 \ --hash=sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0 \ --hash=sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e # via google-api-python-client -urllib3==1.26.16 \ - --hash=sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f \ - --hash=sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14 +urllib3==1.26.18 \ + --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \ + --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0 # via # google-auth # requests diff --git a/requirements/tools_lock.txt b/requirements/tools_lock.txt index 237dec529..9552787ea 100644 --- a/requirements/tools_lock.txt +++ b/requirements/tools_lock.txt @@ -304,9 +304,9 @@ uritemplate==4.1.1 \ --hash=sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0 \ --hash=sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e # via google-api-python-client -urllib3==1.26.16 \ - --hash=sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f \ - --hash=sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14 +urllib3==1.26.18 \ + --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \ + --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0 # via # google-auth # requests From 8c99bf0c8b254275d23058d4cd703c98c373f67e Mon Sep 17 00:00:00 2001 From: anonymous <29055749+idiomaticrefactoring@users.noreply.github.com> Date: Tue, 19 Dec 2023 14:06:23 +1100 Subject: [PATCH 30/36] Update framedocs.py refactor with With statement to open file --- experiments/docs/framedocs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/experiments/docs/framedocs.py b/experiments/docs/framedocs.py index eddbb3e98..426436ceb 100755 --- a/experiments/docs/framedocs.py +++ b/experiments/docs/framedocs.py @@ -65,7 +65,8 @@ def parse_htaccess(filename): documents = collections.defaultdict(list) redirects = [] - for line in open(filename): + with open(filename) as f: + for line in f: match = re.match(r'RedirectMatch /doc/(.+?)\$\s+(.+)$', line) if match: name, url = match.groups() From 6955c49445bedb749d56136a1c995011cd74ef58 Mon Sep 17 00:00:00 2001 From: blais Date: Sun, 31 Dec 2023 21:40:02 -0500 Subject: [PATCH 31/36] Misc notes and missing exposed functions from API. --- beancount/api.py | 7 +++++++ beancount/scripts/deps.py | 1 + experiments/docs_json/convert_docs_json_to_markdown.py | 1 + experiments/docs_rst/download_docs.py | 1 + experiments/docs_rst/old/docs.py | 1 + tools/update_options.py | 1 + 6 files changed, 12 insertions(+) diff --git a/beancount/api.py b/beancount/api.py index e47cc3427..82b629732 100644 --- a/beancount/api.py +++ b/beancount/api.py @@ -20,6 +20,7 @@ from .core.flags import * # pylint: disable=wildcard-import +# TODO(blais): We should return a namedtuple of all the contents, not the lists. from .loader import load_file, load_encrypted_file, load_doc from .core.data import ( @@ -28,6 +29,8 @@ Flag, Meta, Booking, + Posting, + Directive, Directives, Options, new_metadata, @@ -78,3 +81,7 @@ from .core.prices import PriceMap, build_price_map, get_price, get_latest_price from .parser.options import get_account_types + +from .parser.printer import print_entry +from .parser.printer import print_entries +from .parser.printer import format_entry diff --git a/beancount/scripts/deps.py b/beancount/scripts/deps.py index d317470e7..ad82c8a82 100644 --- a/beancount/scripts/deps.py +++ b/beancount/scripts/deps.py @@ -47,6 +47,7 @@ def check_dependencies(): check_import('ply', module_name='ply.yacc', min_version='3.4'), # Optionally required to upload data to Google Drive. + # TODO(blais, 2023-11-18): oauth2client is deprecated. check_import('googleapiclient'), check_import('oauth2client'), check_import('httplib2'), diff --git a/experiments/docs_json/convert_docs_json_to_markdown.py b/experiments/docs_json/convert_docs_json_to_markdown.py index ad7d4f3fa..1cc626f90 100755 --- a/experiments/docs_json/convert_docs_json_to_markdown.py +++ b/experiments/docs_json/convert_docs_json_to_markdown.py @@ -29,6 +29,7 @@ import apiclient.errors from apiclient import discovery import httplib2 +# TODO(blais, 2023-11-18): oauth2client is deprecated. from oauth2client import service_account diff --git a/experiments/docs_rst/download_docs.py b/experiments/docs_rst/download_docs.py index 0713adf83..9906d979d 100755 --- a/experiments/docs_rst/download_docs.py +++ b/experiments/docs_rst/download_docs.py @@ -32,6 +32,7 @@ import apiclient.errors from apiclient import discovery import httplib2 +# TODO(blais, 2023-11-18): oauth2client is deprecated. from oauth2client import service_account diff --git a/experiments/docs_rst/old/docs.py b/experiments/docs_rst/old/docs.py index 3582c715b..e0b59a9ad 100755 --- a/experiments/docs_rst/old/docs.py +++ b/experiments/docs_rst/old/docs.py @@ -14,6 +14,7 @@ from os import path import httplib2 +# TODO(blais, 2023-11-18): oauth2client is deprecated. from oauth2client import service_account diff --git a/tools/update_options.py b/tools/update_options.py index 291c45c30..f6b16062a 100755 --- a/tools/update_options.py +++ b/tools/update_options.py @@ -15,6 +15,7 @@ from apiclient import discovery import httplib2 from apiclient.http import MediaInMemoryUpload # pylint: disable=import-error +# TODO(blais, 2023-11-18): oauth2client is deprecated. from oauth2client import service_account from beancount.parser import options From 60f1c40fd287e44a59a2948424ca8bde545c3926 Mon Sep 17 00:00:00 2001 From: Soham Shanbhag Date: Sat, 6 Jan 2024 18:50:12 +0900 Subject: [PATCH 32/36] Correct order of beancount.ops.pad in loader The present language syntax specifies the following for the pad directive: > A padding directive automatically inserts a transaction that will make the subsequent balance assertion succeed, if it is needed However, the present padding behaviour does not satisfy this. This issue has been raised in the google groups at https://groups.google.com/g/beancount/c/d4AaX1HqXwI. This commit adds a test to the padding test already present in the repository showing this behaviour. The added test uses a tempfile so I'm not sure if cleanup is needed, however it is similar to the tempfile used in loader_test.py. This commit also adds the proposed change to loader.py which should correct the behaviour. With the proposed tests, all the tests pass. Should fix #742, but the forecast plugin is no longer in the repository. --- beancount/loader.py | 2 +- beancount/ops/pad_test.py | 66 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/beancount/loader.py b/beancount/loader.py index a4b1ec35f..01ccbba61 100644 --- a/beancount/loader.py +++ b/beancount/loader.py @@ -42,7 +42,6 @@ # List of default plugins to run. PLUGINS_PRE = [ - ("beancount.ops.pad", None), ("beancount.ops.documents", None), ] @@ -54,6 +53,7 @@ PLUGINS_AUTO = [] PLUGINS_POST = [ + ("beancount.ops.pad", None), ("beancount.ops.balance", None), ] diff --git a/beancount/ops/pad_test.py b/beancount/ops/pad_test.py index b1da7528f..ada070c74 100644 --- a/beancount/ops/pad_test.py +++ b/beancount/ops/pad_test.py @@ -3,6 +3,9 @@ import datetime import unittest +import tempfile +from os import path +import textwrap from beancount.core.amount import A from beancount.core import inventory @@ -13,7 +16,6 @@ from beancount.parser import cmptest from beancount import loader - class TestPadding(cmptest.TestCase): @loader.load_doc() @@ -570,6 +572,68 @@ def test_pad_issue362(self, entries, errors, __): # self.assertRegex(errors[0].message, "Balance failed") # self.assertEqual(datetime.date(2015, 9, 15), errors[0].entry.date) + def test_pad_plugin_modify(self): + with tempfile.TemporaryDirectory() as tmpdir: + ledger_fn = path.join(tmpdir, 'my.beancount') + with open(ledger_fn, 'w') as ledger_file: + ledger_file.write(textwrap.dedent(""" + option "insert_pythonpath" "True" + plugin "plugin_temp" + + 2020-01-01 open Equity:Opening-Balances + 2020-01-01 open Assets:Checking + 2020-01-01 open Assets:Cash + + 2023-02-01 * "Add 20$" + Assets:Checking 20.0 USD + Assets:Cash -20.0 USD + + 2023-03-01 pad Assets:Checking Equity:Opening-Balances + 2023-03-02 balance Assets:Checking 100.0 USD + """)) + + plugin_fn = path.join(tmpdir, 'plugin_temp.py') + with open(plugin_fn, 'w') as plugin_file: + plugin_file.write(textwrap.dedent(""" + from beancount.core import data + + __plugins__ = ('plugin_temp',) + + def plugin_temp(entries, unused_options_map): + new_entries = list( + e._replace(narration=e.narration + " - Duplicate") + for e in data.filter_txns(entries) + if e.flag == '*' + ) + return new_entries + entries, [] + """)) + entries, errors, options_map = loader.load_file(ledger_fn) + + self.assertFalse(errors) + self.assertEqualEntries(""" + option "insert_pythonpath" "True" + plugin "plugin_temp" + + 2020-01-01 open Equity:Opening-Balances + 2020-01-01 open Assets:Checking + 2020-01-01 open Assets:Cash + + 2023-02-01 * "Add 20$ - Duplicate" + Assets:Checking 20.0 USD + Assets:Cash -20.0 USD + + 2023-02-01 * "Add 20$" + Assets:Checking 20.0 USD + Assets:Cash -20.0 USD + + 2023-03-01 pad Assets:Checking Equity:Opening-Balances + + 2023-03-01 P "(Padding inserted for Balance of 100.0 USD for difference 60.0 USD)" + Assets:Checking 60.0 USD + Equity:Opening-Balances -60.0 USD + + 2023-03-02 balance Assets:Checking 100.0 USD + """, entries) if __name__ == '__main__': unittest.main() From 0260d8d8fe844e6a7a65308dd2c7ae093c8c87ad Mon Sep 17 00:00:00 2001 From: blais Date: Sun, 14 Jan 2024 15:21:14 -0500 Subject: [PATCH 33/36] Updated pylint configuration for pylint 3.0.3. --- .pylintrc | 762 +++++++++++++++++++++++++++++++++------ beancount/parser/lexer.c | 12 +- beancount/parser/lexer.h | 6 +- 3 files changed, 656 insertions(+), 124 deletions(-) diff --git a/.pylintrc b/.pylintrc index 5b118d86d..ed6a3be78 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,154 +1,686 @@ -# module-name-hint, method-name-hint, class-name-hint, class-attribute-name-hint, -# inlinevar-name-hint, variable-name-hint, const-name-hint, attr-name-hint, -# argument-name-hint, function-name-hint, no-space-check +[MAIN] +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no +# Clear in-memory caches upon conclusion of linting. Useful if running pylint +# in a server-like mode. +clear-cache-post-run=no -[MASTER] -ignore= - BUILD +# Load and enable all available extensions. Use --list-extensions to see a list +# all available extensions. +#enable-all-extensions= + +# In error mode, messages with a category besides ERROR or FATAL are +# suppressed, and no reports are done by default. Error mode is compatible with +# disabling specific errors. +#errors-only= + +# Always return a 0 (non-error) status code, even if lint errors are found. +# This is primarily useful in continuous integration scripts. +#exit-zero= + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. +extension-pkg-allow-list= + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. (This is an alternative name to extension-pkg-allow-list +# for backward compatibility.) +extension-pkg-whitelist= + +# Return non-zero exit code if any of these messages/categories are detected, +# even if score is above --fail-under value. Syntax same as enable. Messages +# specified are enabled, while categories only check already-enabled messages. +fail-on= + +# Specify a score threshold under which the program will exit with error. +fail-under=10 + +# Interpret the stdin as a python script, whose filename needs to be passed as +# the module_or_package argument. +#from-stdin= + +# Files or directories to be skipped. They should be base names, not paths. +ignore=BUILD + +# Add files or directories matching the regular expressions patterns to the +# ignore-list. The regex matches against paths and can be in Posix or Windows +# format. Because '\\' represents the directory delimiter on Windows systems, +# it can't be used as an escape character. +ignore-paths= + +# Files or directories matching the regular expression patterns are skipped. +# The regex matches against base names, not paths. The default value ignores +# Emacs file locks +ignore-patterns=^\.# + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis). It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the +# number of processors available to use, and will cap the count on Windows to +# avoid hangs. +jobs=1 + +# Control the amount of potential inferred values when inferring a single +# object. This can help the performance when dealing with large functions or +# complex, nested conditions. +limit-inference-results=100 + +# List of plugins (as comma separated values of python module names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. persistent=yes -load-plugins=pylint_protobuf -[REPORTS] -output-format=text +# Minimum Python version to use for version dependent checks. Will default to +# the version used to run pylint. +py-version=3.11 + +# Discover python modules and packages in the file system subtree. +recursive=no + +# Add paths to the list of the source roots. Supports globbing patterns. The +# source root is an absolute path or a path relative to the current working +# directory used to determine a package namespace for modules located under the +# source root. +source-roots= + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages. +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + +# In verbose mode, extra non-checker-related info will be displayed. +#verbose= + + +[BASIC] + +# Naming style matching correct argument names. +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style. If left empty, argument names will be checked with the set +# naming style. +argument-rgx=(_?[a-z_][a-z0-9_]{1,30}|__|mu)$ + +# Naming style matching correct attribute names. +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style. If left empty, attribute names will be checked with the set naming +# style. +attr-rgx=[a-z_][a-z0-9_]{1,30}$ + +# Bad variable names which should always be refused, separated by a comma. +bad-names=foo, + bar, + baz, + toto, + tutu, + tata + +# Bad variable names regexes, separated by a comma. If names match any regex, +# they will always be refused +bad-names-rgxs= + +# Naming style matching correct class attribute names. +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style. If left empty, class attribute names will be checked +# with the set naming style. +#class-attribute-rgx= + +# Naming style matching correct class constant names. +class-const-naming-style=UPPER_CASE + +# Regular expression matching correct class constant names. Overrides class- +# const-naming-style. If left empty, class constant names will be checked with +# the set naming style. +#class-const-rgx= + +# Naming style matching correct class names. +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming- +# style. If left empty, class names will be checked with the set naming style. +#class-rgx= + +# Naming style matching correct constant names. +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style. If left empty, constant names will be checked with the set naming +# style. +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names. +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style. If left empty, function names will be checked with the set +# naming style. +function-rgx=_?[a-z_][a-zA-Z0-9_]{2,64}$ + +# Good variable names which should always be accepted, separated by a comma. +good-names=i, + j, + k, + f, + ex, + Run, + _ + +# Good variable names regexes, separated by a comma. If names match any regex, +# they will always be accepted +good-names-rgxs= + +# Include a hint for the correct naming format with invalid-name. +include-naming-hint=no + +# Naming style matching correct inline iteration names. +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style. If left empty, inline iteration names will be checked +# with the set naming style. +#inlinevar-rgx= + +# Naming style matching correct method names. +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style. If left empty, method names will be checked with the set naming style. +method-rgx=[a-z_][a-zA-Z0-9_]{2,72}$ + +# Naming style matching correct module names. +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style. If left empty, module names will be checked with the set naming style. +module-rgx=(([a-z_][a-z0-9_\-]*)|([A-Z][a-zA-Z0-9]+))$ + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +# These decorators are taken in consideration only for invalid-name. +property-classes=abc.abstractproperty + +# Regular expression matching correct type alias names. If left empty, type +# alias names will be checked with the set naming style. +#typealias-rgx= + +# Regular expression matching correct type variable names. If left empty, type +# variable names will be checked with the set naming style. +#typevar-rgx= + +# Naming style matching correct variable names. +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style. If left empty, variable names will be checked with the set +# naming style. +variable-rgx=(_?[a-z_][a-z0-9_]{1,30}|__|mu|no)$ + + +[CLASSES] + +# Warn about protected attribute access inside special methods +check-protected-access-in-special-methods=no + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp, + asyncSetUp, + __post_init__ + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict,_fields,_replace,_source,_make,os._exit + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[DESIGN] + +# List of regular expressions of class ancestor names to ignore when counting +# public methods (see R0903) +exclude-too-few-public-methods= + +# List of qualified class names to ignore when counting class parents (see +# R0901) +ignored-parents= + +# Maximum number of arguments for function / method. +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in an if statement (see R0916). +max-bool-expr=5 + +# Maximum number of branch for function / method body. +max-branches=12 + +# Maximum number of locals for function / method body. +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body. +max-returns=6 + +# Maximum number of statements in function / method body. +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when caught. +overgeneral-exceptions=builtins.BaseException,builtins.Exception + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=92 + +# Maximum number of lines in a module. +max-module-lines=1000 + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[IMPORTS] + +# List of modules that can be imported at any level, not just the top level +# one. +allow-any-import-level= + +# Allow explicit reexports by alias from a package __init__. +allow-reexport-from-package=no + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Deprecated modules which should not be used, separated by a comma. +deprecated-modules= + +# Output a graph (.gv or any supported image format) of external dependencies +# to the given file (report RP0402 must not be disabled). +ext-import-graph= + +# Output a graph (.gv or any supported image format) of all (i.e. internal and +# external) dependencies to the given file (report RP0402 must not be +# disabled). +import-graph= + +# Output a graph (.gv or any supported image format) of internal dependencies +# to the given file (report RP0402 must not be disabled). +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + +# Couples of modules and preferred modules, separated by a comma. +preferred-modules= + + +[LOGGING] + +# The type of string formatting that logging methods do. `old` means using % +# formatting, `new` is for `{}` formatting. +logging-format-style=old + +# Logging modules to check that the string format arguments are in logging +# function parameter format. +logging-modules=logging -# Tells whether to display a full report or only the messages -reports=no [MESSAGES CONTROL] -enable=all +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, +# UNDEFINED. +confidence=HIGH, + CONTROL_FLOW, + INFERENCE, + INFERENCE_FAILURE, + UNDEFINED # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if +# file where it should appear only once). You can also use "--disable=all" to +# disable everything first and then re-enable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable=locally-disabled, + suppressed-message, + missing-docstring, + too-many-lines, + multiple-statements, + superfluous-parens, + ungrouped-imports, + wrong-import-position, + no-self-argument, + no-member, + no-value-for-parameter, + too-many-function-args, + unsubscriptable-object, + too-many-nested-blocks, + duplicate-code, + too-few-public-methods, + too-many-public-methods, + too-many-branches, + too-many-arguments, + too-many-locals, + too-many-statements, + attribute-defined-outside-init, + protected-access, + arguments-differ, + abstract-method, + fixme, + global-variable-undefined, + global-statement, + unused-variable, + unused-argument, + redefined-outer-name, + redefined-builtin, + undefined-loop-variable, + broad-except, + logging-format-interpolation, + anomalous-backslash-in-string, + len-as-condition, + no-else-return, + invalid-unary-operand-type, + no-name-in-module, + inconsistent-return-statements, + not-callable, + stop-iteration-return, + assignment-from-no-return, + c-extension-no-member, + cyclic-import, + isinstance-second-argument-not-valid-type, + inherit-non-class, + consider-using-f-string, + consider-using-with, + unspecified-encoding, + arguments-renamed, + consider-using-dict-items, + global-variable-not-assigned, + useless-suppression, + unused-private-member, + use-maxsplit-arg, + unnecessary-lambda-assignment, + use-dict-literal -# I like most of these... reenable one by one. -disable=locally-disabled, - suppressed-message, - missing-docstring, - too-many-lines, - multiple-statements, - superfluous-parens, - ungrouped-imports, - wrong-import-position, - no-self-argument, - no-member, - no-value-for-parameter, - too-many-function-args, - unsubscriptable-object, - too-many-nested-blocks, - duplicate-code, - too-few-public-methods, - too-many-public-methods, - too-many-branches, - too-many-arguments, - too-many-locals, - too-many-statements, - attribute-defined-outside-init, - protected-access, - arguments-differ, - abstract-method, - fixme, - global-variable-undefined, - global-statement, - unused-variable, - unused-argument, - redefined-outer-name, - redefined-builtin, - undefined-loop-variable, - broad-except, - logging-format-interpolation, - anomalous-backslash-in-string, - len-as-condition, - no-else-return, - invalid-unary-operand-type, - no-name-in-module, - inconsistent-return-statements, - not-callable, - stop-iteration-return, - assignment-from-no-return, - c-extension-no-member, - cyclic-import, - isinstance-second-argument-not-valid-type, - inherit-non-class, - consider-using-f-string, - consider-using-with, - unspecified-encoding, - arguments-renamed, - consider-using-dict-items, - global-variable-not-assigned, - useless-suppression, - unused-private-member, - use-maxsplit-arg, - unnecessary-lambda-assignment, - use-dict-literal, -[VARIABLES] +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable= -# Tells whether we should check for unused import in __init__ files. -init-import=no -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=_$|dummy +[METHOD_ARGS] -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= +# List of qualified names (i.e., library.method) which require a timeout +# parameter e.g. 'requests.api.get,requests.api.post' +timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request -[TYPECHECK] +[MISCELLANEOUS] -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + +# Regular expression of note tags to take in consideration. +notes-rgx= + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=sys.exit,argparse.parse_error + + +[REPORTS] + +# Python expression which should return a score less than or equal to 10. You +# have access to the variables 'fatal', 'error', 'warning', 'refactor', +# 'convention', and 'info' which contain the number of messages in each +# category, as well as 'statement' which is the total number of statements +# analyzed. This score is used by the global evaluation report (RP0004). +evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details. +msg-template= + +# Set the output format. Available formats are: text, parseable, colorized, +# json2 (improved json format), json (old json format) and msvs (visual +# studio). You can also give a reporter class, e.g. +# mypackage.mymodule.MyReporterClass. +#output-format= + +# Tells whether to display a full report or only the messages. +reports=no + +# Activate the evaluation score. +score=yes -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis -ignored-modules= -# List of classes names for which member attributes should not be checked -# (useful for classes with attributes dynamically set). -ignored-classes= +[SIMILARITIES] + +# Comments are removed from the similarity computation +ignore-comments=yes + +# Docstrings are removed from the similarity computation +ignore-docstrings=yes + +# Imports are removed from the similarity computation +ignore-imports=yes + +# Signatures are removed from the similarity computation +ignore-signatures=yes + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes. +max-spelling-suggestions=4 + +# Spelling dictionary name. No available dictionaries : You need to install +# both the python package and the system dependency for enchant to work. +spelling-dict= + +# List of comma separated words that should be considered directives if they +# appear at the beginning of a comment and should not be checked. +spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains the private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to the private dictionary (see the +# --spelling-private-dict-file option) instead of raising a message. +spelling-store-unknown-words=no + + +[STRING] + +# This flag controls whether inconsistent-quotes generates a warning when the +# character used as a quote delimiter is used inconsistently within a module. +check-quote-consistency=no + +# This flag controls whether the implicit-str-concat should generate a warning +# on implicit string concatenation in sequences defined over several lines. +check-str-concat-over-line-jumps=no + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager # List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E0201 when accessed. Python regular +# system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. -#generated-members=REQUEST,acl_users,aq_parent generated-members= +# Tells whether to warn about missing members when the owner of the attribute +# is inferred to be None. +ignore-none=yes -[LOGGING] +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging +# List of symbolic message names to ignore for Mixin members. +ignored-checks-for-mixins=no-member, + not-async-context-manager, + not-context-manager, + attribute-defined-outside-init +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace -[MISCELLANEOUS] +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes -# List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 -[BASIC] -good-names=f,i,j,k,ex,_ -argument-rgx=(_?[a-z_][a-z0-9_]{1,30}|__|mu)$ -attr-rgx=[a-z_][a-z0-9_]{1,30}$ -function-rgx=_?[a-z_][a-zA-Z0-9_]{2,64}$ -method-rgx=[a-z_][a-zA-Z0-9_]{2,72}$ -module-rgx=(([a-z_][a-z0-9_\-]*)|([A-Z][a-zA-Z0-9]+))$ -variable-rgx=(_?[a-z_][a-z0-9_]{1,30}|__|mu|no)$ +# Regex pattern to define which classes are considered mixins. +mixin-class-rgx=.*[Mm]ixin -[FORMAT] -max-line-length=92 +# List of decorators that change the signature of a decorated function. +signature-mutators= + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid defining new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of names allowed to shadow builtins +allowed-redefined-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, + _cb + +# A regular expression matching the name of dummy variables (i.e. expected to +# not be used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io diff --git a/beancount/parser/lexer.c b/beancount/parser/lexer.c index 935f413d4..3aa90806f 100644 --- a/beancount/parser/lexer.c +++ b/beancount/parser/lexer.c @@ -1,4 +1,4 @@ -#line 1 "beancount/parser/lexer.c" +#line 2 "beancount/parser/lexer.c" #define PY_SSIZE_T_CLEAN #include @@ -54,7 +54,7 @@ yyscan_t yylex_free(yyscan_t scanner); void yylex_initialize(PyObject* file, PyObject* filename, int lineno, PyObject* missing_obj, yyscan_t scanner); -#line 57 "beancount/parser/lexer.c" +#line 58 "beancount/parser/lexer.c" #define YY_INT_ALIGNED short int @@ -866,12 +866,12 @@ int pyfile_read_into(PyObject *file, char *buf, size_t max_size); yycolumn += yyleng; \ } -#line 869 "beancount/parser/lexer.c" +#line 870 "beancount/parser/lexer.c" #line 133 "beancount/parser/lexer.l" /* Characters that may be used as flags. Single-character letters may also be * used as flags, but must be prefixed by a quote, as in "'P' for "P". */ -#line 874 "beancount/parser/lexer.c" +#line 875 "beancount/parser/lexer.c" #define INITIAL 0 #define INVALID 1 @@ -1162,7 +1162,7 @@ YY_DECL /* Newlines matter. */ -#line 1165 "beancount/parser/lexer.c" +#line 1166 "beancount/parser/lexer.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -1664,7 +1664,7 @@ YY_RULE_SETUP #line 332 "beancount/parser/lexer.l" ECHO; YY_BREAK -#line 1667 "beancount/parser/lexer.c" +#line 1668 "beancount/parser/lexer.c" case YY_END_OF_BUFFER: { diff --git a/beancount/parser/lexer.h b/beancount/parser/lexer.h index e905f0020..e8828961a 100644 --- a/beancount/parser/lexer.h +++ b/beancount/parser/lexer.h @@ -2,7 +2,7 @@ #define yyHEADER_H 1 #define yyIN_HEADER 1 -#line 5 "beancount/parser/lexer.h" +#line 6 "beancount/parser/lexer.h" #define PY_SSIZE_T_CLEAN #include @@ -58,7 +58,7 @@ yyscan_t yylex_free(yyscan_t scanner); void yylex_initialize(PyObject* file, PyObject* filename, int lineno, PyObject* missing_obj, yyscan_t scanner); -#line 61 "beancount/parser/lexer.h" +#line 62 "beancount/parser/lexer.h" #define YY_INT_ALIGNED short int @@ -575,6 +575,6 @@ extern int yylex \ #line 332 "beancount/parser/lexer.l" -#line 578 "beancount/parser/lexer.h" +#line 579 "beancount/parser/lexer.h" #undef yyIN_HEADER #endif /* yyHEADER_H */ From a5ce3382c95d0e273aad5de1753def6256fb7a3d Mon Sep 17 00:00:00 2001 From: bobobo1618 Date: Sun, 18 Feb 2024 12:17:18 +0100 Subject: [PATCH 34/36] Fix build breakage --- bazel/repositories.bzl | 2 +- beancount/core/BUILD | 3 --- beancount/utils/BUILD | 11 ----------- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl index 95305632e..fd0cb709c 100644 --- a/bazel/repositories.bzl +++ b/bazel/repositories.bzl @@ -67,7 +67,7 @@ def _cppbase_dependencies(): name = "com_google_absl", url = "https://github.com/abseil/abseil-cpp/archive/refs/heads/lts_2022_06_23.tar.gz", strip_prefix = "abseil-cpp-lts_2022_06_23", - sha256 = "5acf752f4c9a6b4d935e73581ebc86c21722d72bc054b1cc8949a55ae179bc59", + sha256 = "9c32fdb4a7d8c38f74145aa0d9d33ca639822022968732143fcd2cc5aee86701", updated = "2022-09-06", ) diff --git a/beancount/core/BUILD b/beancount/core/BUILD index f1231436a..5afd7ae9e 100644 --- a/beancount/core/BUILD +++ b/beancount/core/BUILD @@ -22,9 +22,6 @@ package(default_visibility = [ py_library( name = "account", srcs = ["account.py"], - deps = [ - "//beancount/utils:regexp_utils", - ], ) py_test( diff --git a/beancount/utils/BUILD b/beancount/utils/BUILD index 93579436e..be25a57ee 100644 --- a/beancount/utils/BUILD +++ b/beancount/utils/BUILD @@ -139,17 +139,6 @@ py_test( ], ) -py_library( - name = "regexp_utils", - srcs = ["regexp_utils.py"], -) - -py_test( - name = "regexp_utils_test", - srcs = ["regexp_utils_test.py"], - deps = [":regexp_utils"], -) - py_library( name = "snoop", srcs = ["snoop.py"], From d2d1e536c82281933b7bfc9cf3137f3698dcf4dc Mon Sep 17 00:00:00 2001 From: Ev2geny Date: Sun, 10 Mar 2024 10:43:21 +0100 Subject: [PATCH 35/36] Optional write_source parameter is added to the printer.print_entry and printer.print_entries functions to be able to add source file and line number in a format interpretable as a message location for Emacs, VSCode --- beancount/parser/printer.py | 59 ++++++++-- beancount/parser/printer_test.py | 186 +++++++++++++++++++++++++++++-- 2 files changed, 226 insertions(+), 19 deletions(-) diff --git a/beancount/parser/printer.py b/beancount/parser/printer.py index d36471e06..e56f24bbe 100644 --- a/beancount/parser/printer.py +++ b/beancount/parser/printer.py @@ -105,7 +105,7 @@ class EntryPrinter: # pylint: disable=invalid-name def __init__(self, dcontext=None, render_weight=False, min_width_account=None, - prefix=None, stringify_invalid_types=False): + prefix=None, stringify_invalid_types=False, write_source=False): self.dcontext = dcontext or display_context.DEFAULT_DISPLAY_CONTEXT self.dformat = self.dcontext.build(precision=display_context.Precision.MOST_COMMON) self.dformat_max = self.dcontext.build(precision=display_context.Precision.MAXIMUM) @@ -113,6 +113,7 @@ def __init__(self, dcontext=None, render_weight=False, min_width_account=None, self.min_width_account = min_width_account self.prefix = prefix or ' ' self.stringify_invalid_types = stringify_invalid_types + self.write_source = write_source def __call__(self, obj): """Render a directive. @@ -123,6 +124,10 @@ def __call__(self, obj): A string, the rendered directive. """ oss = io.StringIO() + + # We write optional entry source for every entry type, hence writing it here + self.write_entry_source(obj.meta, oss, prefix="") + method = getattr(self, obj.__class__.__name__) method(obj, oss) return oss.getvalue() @@ -164,6 +169,25 @@ def write_metadata(self, meta, oss, prefix=None): if value_str is not None: oss.write("{}{}: {}\n".format(prefix, key, value_str)) + def write_entry_source(self, meta, oss, prefix=None): + """Write source file and line number in a format interpretable as a message + location for Emacs, VSCode or other editors. As this is for + "debugging" purposes, this information will be commented out by a + semicolon. + + Args: + meta: A dict that contains the metadata for this directive. + oss: A file object to write to. + prefix: User-specific prefix for custom indentation + """ + if not self.write_source: + return + + if prefix is None: + prefix = self.prefix + + oss.write('{}; source: {}\n'.format(prefix, render_source(meta))) + def Transaction(self, entry, oss): # Compute the string for the payee and narration line. strings = [] @@ -371,20 +395,28 @@ def render_flag(inflag: Optional[str]) -> str: return inflag -def format_entry(entry, dcontext=None, render_weights=False, prefix=None): +def format_entry(entry, dcontext=None, render_weights=False, prefix=None, + write_source=False): """Format an entry into a string in the same input syntax the parser accepts. Args: entry: An entry instance. dcontext: An instance of DisplayContext used to format the numbers. render_weights: A boolean, true to render the weights for debugging. + write_source: If true a source file and line number will be written for + each entry in a format interpretable as a message location for Emacs, + VSCode or other editors. As this is for + "debugging" purposes, this information will be commented out by a + semicolon. Returns: A string, the formatted entry. """ - return EntryPrinter(dcontext, render_weights, prefix=prefix)(entry) + return EntryPrinter(dcontext, render_weights, prefix=prefix, + write_source=write_source)(entry) -def print_entry(entry, dcontext=None, render_weights=False, file=None): +def print_entry(entry, dcontext=None, render_weights=False, file=None, + write_source=False): """A convenience function that prints a single entry to a file. Args: @@ -392,20 +424,26 @@ def print_entry(entry, dcontext=None, render_weights=False, file=None): dcontext: An instance of DisplayContext used to format the numbers. render_weights: A boolean, true to render the weights for debugging. file: An optional file object to write the entries to. + write_source: If true a source file and line number will be written for + each entry in a format interpretable as a message location for Emacs, + VSCode or other editors. This is usefull for "debugging" peurposes, + especially in a multi-file setup """ # TODO(blais): DO remove this now, it's a huge annoyance not to be able to # print in-between other statements. output = file or (codecs.getwriter("utf-8")(sys.stdout.buffer) if hasattr(sys.stdout, 'buffer') else sys.stdout) - output.write(format_entry(entry, dcontext, render_weights)) + output.write(format_entry(entry, dcontext, render_weights, + write_source=write_source)) output.write('\n') # TODO(blais): Change this to a function which accepts the same optional # arguments as the printer object. Isolate the spacer/segmentation algorithm to # its own function. -def print_entries(entries, dcontext=None, render_weights=False, file=None, prefix=None): +def print_entries(entries, dcontext=None, render_weights=False, file=None, prefix=None, + write_source=False): """A convenience function that prints a list of entries to a file. Args: @@ -413,6 +451,11 @@ def print_entries(entries, dcontext=None, render_weights=False, file=None, prefi dcontext: An instance of DisplayContext used to format the numbers. render_weights: A boolean, true to render the weights for debugging. file: An optional file object to write the entries to. + prefix: User-specific prefix for custom indentation (for Fava). + write_source: If true a source file and line number will be written for + each entry in a format interpretable as a message location for Emacs, + VSCode or other editors. This is usefull for "debugging" peurposes, + especially in a multi-file setup """ assert isinstance(entries, list), "Entries is not a list: {}".format(entries) output = file or (codecs.getwriter("utf-8")(sys.stdout.buffer) @@ -422,13 +465,13 @@ def print_entries(entries, dcontext=None, render_weights=False, file=None, prefi if prefix: output.write(prefix) previous_type = type(entries[0]) if entries else None - eprinter = EntryPrinter(dcontext, render_weights) + eprinter = EntryPrinter(dcontext, render_weights, write_source=write_source) for entry in entries: # Insert a newline between transactions and between blocks of directives # of the same type. entry_type = type(entry) if (entry_type in (data.Transaction, data.Commodity) or - entry_type is not previous_type): + entry_type is not previous_type or write_source): output.write('\n') previous_type = entry_type diff --git a/beancount/parser/printer_test.py b/beancount/parser/printer_test.py index d2ce8cbf7..3fb1f2b35 100644 --- a/beancount/parser/printer_test.py +++ b/beancount/parser/printer_test.py @@ -2,10 +2,12 @@ __license__ = "GNU GPLv2" import io +import os from datetime import date import unittest import re import textwrap +import tempfile from beancount.parser import printer from beancount.parser import cmptest @@ -70,6 +72,122 @@ def assertRoundTrip(self, entries1, errors1): # Compare the two output texts. self.assertEqual(oss2.getvalue(), oss1.getvalue()) + def assertRoundTripViaRealFile(self, entries1, errors1, + test_write_source=True): + """ + The same as assertRoundTrip, but the 1st time saves ledger in string + format to a real file as an opposite to io.StringIO(). + This ensures, that when parsed back from file, entries will contain file + name and line number metadata. + + Args: + test_write_source - if True, will test funtionality write_source, + which activates printing of the source file and line number for + every transaction + """ + self.assertFalse(errors1) + + # Not using context manager to make this test compatible with Windows + # Contex manager can be used as of python 3.12 + # see https://github.com/python/cpython/issues/58451 + # https://github.com/beancount/beancount/issues/222 + oss1 = tempfile.NamedTemporaryFile('w', suffix='.beancount', + delete=False) + + oss1.write('option "plugin_processing_mode" "raw"\n') + printer.print_entries(entries1, file=oss1) + + oss1.close() + + with open(oss1.name, "r") as file: + oss1_value = file.read() + + # entries2 will contain information about filename and line number in + # metadata + entries2, errors, __ = loader.load_file(oss1.name) + + self.assertEqualEntries(entries1, entries2) + self.assertFalse(errors) + + oss2 = io.StringIO() + oss2.write('option "plugin_processing_mode" "raw"\n') + + # converting entries2 to string now also with the commented out source + # information + printer.print_entries(entries2, file=oss2, write_source=test_write_source) + oss2_value = oss2.getvalue() + entries3, errors, __ = loader.load_string(oss2_value) + + # testing, that qnt of '; source' subscrings is equal to qnt of + # entries + if test_write_source: + self.assertEqual(oss2_value.count("; source"), len(entries3)) + + self.assertEqualEntries(entries1, entries3) + self.assertFalse(errors) + + if test_write_source: + self.assertNotEqual(oss2_value, oss1_value) + else: + self.assertEqual(oss2.getvalue(), oss1_value) + + # Finally deleting temporary file + os.unlink(oss1.name) + + def test_write_source(self): + """ + Targeted testing of the write_source, functionality which activates + printing of the source file and line number for every transaction in + a commented out form + """ + ORIGINAL_LEDGER = textwrap.dedent("""\ + 2014-01-01 open Assets:Account1 + 2014-01-01 open Assets:Cash + + 2014-06-08 * + Assets:Account1 111.00 BEAN + Assets:Cash -111.00 BEAN + """) + + # note:this multistring contains some training white spaces + EXPECTED_OUTPUT_LEDGER_TEMPL = textwrap.dedent(""" + ; source: __path_to_file__:1: + 2014-01-01 open Assets:Account1 + + ; source: __path_to_file__:2: + 2014-01-01 open Assets:Cash + + ; source: __path_to_file__:4: + 2014-06-08 * + Assets:Account1 111.00 BEAN + Assets:Cash -111.00 BEAN + """) + + + # Not using context manager to make this test compatible with Windows + # Contex manager can be used as of python 3.12 + # see https://github.com/python/cpython/issues/58451 + # https://github.com/beancount/beancount/issues/222 + oss1 = tempfile.NamedTemporaryFile('w', suffix='.beancount', + delete=False) + oss1.write(ORIGINAL_LEDGER) + oss1.close() + # entries2 will contain the file name and line number in metadata + entries2, errors, __ = loader.load_file(oss1.name) + self.assertFalse(errors) + + expected_output_ledger = EXPECTED_OUTPUT_LEDGER_TEMPL.replace( + '__path_to_file__',oss1.name) + + # Print out those reparsed and parse them back in. + oss2 = io.StringIO() + # Getting original ledger but with the source location information + printer.print_entries(entries2, file=oss2, write_source=True) + + self.maxDiff=1000 + self.assertEqual(expected_output_ledger, oss2.getvalue()) + + @loader.load_doc() def test_Transaction(self, entries, errors, __): """ @@ -123,7 +241,12 @@ def test_Transaction(self, entries, errors, __): 2014-06-20 custom "budget" Assets:Account2 "balance < 200.00 USD" 200.00 10.00 USD """ - self.assertRoundTrip(entries, errors) + with self.subTest("RoundTrip test via StringIO"): + self.assertRoundTrip(entries, errors) + + #TODO: This test fails on Windows for the entry with escaped symbols + with self.subTest("RoundTrip test via real file"): + self.assertRoundTripViaRealFile(entries, errors) @loader.load_doc() def test_Balance(self, entries, errors, __): @@ -131,7 +254,11 @@ def test_Balance(self, entries, errors, __): 2014-06-01 open Assets:Account1 2014-06-08 balance Assets:Account1 0.00 USD """ - self.assertRoundTrip(entries, errors) + with self.subTest("RoundTrip test via StringIO"): + self.assertRoundTrip(entries, errors) + + with self.subTest("RoundTrip test via real file"): + self.assertRoundTripViaRealFile(entries, errors) @loader.load_doc() def test_BalanceTolerance(self, entries, errors, __): @@ -145,7 +272,11 @@ def test_BalanceTolerance(self, entries, errors, __): 2014-06-04 balance Assets:Account1 200.00 ~0.05 USD """ - self.assertRoundTrip(entries, errors) + with self.subTest("RoundTrip test via StringIO"): + self.assertRoundTrip(entries, errors) + + with self.subTest("RoundTrip test via real file"): + self.assertRoundTripViaRealFile(entries, errors) @loader.load_doc() def test_Note(self, entries, errors, __): @@ -153,7 +284,11 @@ def test_Note(self, entries, errors, __): 2014-06-01 open Assets:Account1 2014-06-08 note Assets:Account1 "Note" """ - self.assertRoundTrip(entries, errors) + with self.subTest("RoundTrip test via StringIO"): + self.assertRoundTrip(entries, errors) + + with self.subTest("RoundTrip test via real file"): + self.assertRoundTripViaRealFile(entries, errors) @loader.load_doc() def test_Document(self, entries, errors, __): @@ -167,14 +302,22 @@ def test_Document(self, entries, errors, __): 2014-06-08 document Assets:Account1 "path/to/document2.csv" #tag1 2014-06-08 document Assets:Account1 "path/to/document2.csv" ^link1 """ - self.assertRoundTrip(entries, errors) + with self.subTest("RoundTrip test via StringIO"): + self.assertRoundTrip(entries, errors) + + with self.subTest("RoundTrip test via real file"): + self.assertRoundTripViaRealFile(entries, errors) @loader.load_doc() def test_Query(self, entries, errors, __): """ 2014-06-08 query "cash" "SELECT sum(position) WHERE currency = 'USD'" """ - self.assertRoundTrip(entries, errors) + with self.subTest("RoundTrip test via StringIO"): + self.assertRoundTrip(entries, errors) + + with self.subTest("RoundTrip test via real file"): + self.assertRoundTripViaRealFile(entries, errors) @loader.load_doc() def test_Pad(self, entries, errors, __): @@ -184,7 +327,11 @@ def test_Pad(self, entries, errors, __): 2014-06-08 pad Assets:Account1 Assets:Account2 2014-10-01 balance Assets:Account1 1 USD """ - self.assertRoundTrip(entries, errors) + with self.subTest("RoundTrip test via StringIO"): + self.assertRoundTrip(entries, errors) + + with self.subTest("RoundTrip test via real file"): + self.assertRoundTripViaRealFile(entries, errors) @loader.load_doc() def test_Open(self, entries, errors, __): @@ -194,7 +341,11 @@ def test_Open(self, entries, errors, __): 2014-06-08 open Assets:Account3 USD,CAD,EUR 2014-06-08 open Assets:Account4 HOOL "NONE" """ - self.assertRoundTrip(entries, errors) + with self.subTest("RoundTrip test via StringIO"): + self.assertRoundTrip(entries, errors) + + with self.subTest("RoundTrip test via real file"): + self.assertRoundTripViaRealFile(entries, errors) @loader.load_doc() def test_Close(self, entries, errors, __): @@ -202,7 +353,11 @@ def test_Close(self, entries, errors, __): 2014-01-01 open Assets:Account1 2014-06-08 close Assets:Account1 """ - self.assertRoundTrip(entries, errors) + with self.subTest("RoundTrip test via StringIO"): + self.assertRoundTrip(entries, errors) + + with self.subTest("RoundTrip test via real file"): + self.assertRoundTripViaRealFile(entries, errors) @loader.load_doc() def test_Price(self, entries, errors, __): @@ -210,7 +365,11 @@ def test_Price(self, entries, errors, __): 2014-06-08 price BEAN 53.24 USD 2014-06-08 price USD 1.09 CAD """ - self.assertRoundTrip(entries, errors) + with self.subTest("RoundTrip test via StringIO"): + self.assertRoundTrip(entries, errors) + + with self.subTest("RoundTrip test via real file"): + self.assertRoundTripViaRealFile(entries, errors) @loader.load_doc() def test_Event(self, entries, errors, __): @@ -218,7 +377,11 @@ def test_Event(self, entries, errors, __): 2014-06-08 event "location" "New York, NY, USA" 2014-06-08 event "employer" "Four Square" """ - self.assertRoundTrip(entries, errors) + with self.subTest("RoundTrip test via StringIO"): + self.assertRoundTrip(entries, errors) + + with self.subTest("RoundTrip test via real file"): + self.assertRoundTripViaRealFile(entries, errors) def test_metadata(self): meta = data.new_metadata('beancount/core/testing.beancount', 12345) @@ -228,6 +391,7 @@ def test_metadata(self): self.assertEqual(' something: "a\\"\\\\c"\n', oss.getvalue()) + def characterize_spaces(text): """Classify each line to a particular type. From 558d0b1ce02af238ca81342aa635b386e74be23c Mon Sep 17 00:00:00 2001 From: William Davies <36384318+william-davies@users.noreply.github.com> Date: Mon, 1 Apr 2024 16:03:37 +0100 Subject: [PATCH 36/36] docs: fix module docstring I think `In a sense, this is the inverse of "pedantic." This is useful when doing some types of quick and dirty tests.` was copied from the `beancount.plugins.auto` docstring --- beancount/plugins/pedantic.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/beancount/plugins/pedantic.py b/beancount/plugins/pedantic.py index 69bb1f596..cce6b0a5e 100644 --- a/beancount/plugins/pedantic.py +++ b/beancount/plugins/pedantic.py @@ -1,7 +1,4 @@ -"""A plugin of plugins which triggers are all the pedantic plugins. - -In a sense, this is the inverse of "pedantic." This is useful when doing some -types of quick and dirty tests. +"""A plugin of plugins which triggers all the pedantic plugins. """ __copyright__ = "Copyright (C) 2017 Martin Blais" __license__ = "GNU GPLv2"