Пример #1
0
 def test_source_map_manycur_single(self):
     smap = find_prices.parse_source_map('USD:yahoo/USDCAD '
                                         'CAD:yahoo/CAD=X')
     self.assertEqual(
         {'USD': [PS('beancount.prices.sources.yahoo', 'USDCAD', False)],
          'CAD': [PS('beancount.prices.sources.yahoo', 'CAD=X', False)]},
         self._clean_source_map(smap))
Пример #2
0
 def test_source_map_manycur_single(self):
     smap = find_prices.parse_source_map('USD:google/CURRENCY:GBPUSD '
                                         'CAD:google/CURRENCY:GBPCAD')
     self.assertEqual(
         {'USD': [PS('beancount.prices.sources.google', 'CURRENCY:GBPUSD', False)],
          'CAD': [PS('beancount.prices.sources.google', 'CURRENCY:GBPCAD', False)]},
         self._clean_source_map(smap))
 def test_source_map_onecur_multiple(self):
     smap = find_prices.parse_source_map('USD:financequote/NASDAQ:AAPL,google/NASDAQ:AAPL,yahoo/AAPL')
     self.assertEqual(
         {'USD': [PS('beancount.prices.sources.financequote', 'NASDAQ:AAPL', False),
                  PS('beancount.prices.sources.google', 'NASDAQ:AAPL', False),
                  PS('beancount.prices.sources.yahoo', 'AAPL', False)]},
         self._clean_source_map(smap))
 def test_source_map_inverse(self):
     smap = find_prices.parse_source_map('USD:financequote/^CURRENCY:GBPUSD,google/^CURRENCY:GBPUSD,yahoo/^GBPUSD')
     self.assertEqual(
         {'USD': [PS('beancount.prices.sources.financequote', 'CURRENCY:GBPUSD', True),
                  PS('beancount.prices.sources.google', 'CURRENCY:GBPUSD', True),
                  PS('beancount.prices.sources.yahoo', 'GBPUSD', True)]},
         self._clean_source_map(smap))
Пример #5
0
 def test_source_map_manycur_multiple(self):
     smap = find_prices.parse_source_map('USD:yahoo/GBPUSD,oanda/GBPUSD '
                                         'CAD:yahoo/GBPCAD')
     self.assertEqual(
         {'USD': [PS('beancount.prices.sources.yahoo', 'GBPUSD', False),
                  PS('beancount.prices.sources.oanda', 'GBPUSD', False)],
          'CAD': [PS('beancount.prices.sources.yahoo', 'GBPCAD', False)]},
         self._clean_source_map(smap))
Пример #6
0
 def test_source_map_onecur_multiple(self):
     smap = find_prices.parse_source_map('USD:oanda/USDCAD,yahoo/CAD=X')
     self.assertEqual(
         {
             'USD': [
                 PS('beancount.prices.sources.oanda', 'USDCAD', False),
                 PS('beancount.prices.sources.yahoo', 'CAD=X', False)
             ]
         }, self._clean_source_map(smap))
 def test_source_map_manycur_multiple(self):
     smap = find_prices.parse_source_map('USD:financequote/CURRENCY:GBPUSD,google/CURRENCY:GBPUSD,yahoo/GBPUSD '
                                         'CAD:google/CURRENCY:GBPCAD')
     self.assertEqual(
         {'USD': [PS('beancount.prices.sources.financequote', 'CURRENCY:GBPUSD', False),
                  PS('beancount.prices.sources.google', 'CURRENCY:GBPUSD', False),
                  PS('beancount.prices.sources.yahoo', 'GBPUSD', False)],
          'CAD': [PS('beancount.prices.sources.google', 'CURRENCY:GBPCAD', False)]},
         self._clean_source_map(smap))
Пример #8
0
def process_args():
    """Process the arguments. This also initializes the logging module.

    Returns:
      A tuple of:
        args: The argparse receiver of command-line arguments.
        jobs: A list of DatedPrice job objects.
        entries: A list of all the parsed entries.
    """
    parser = version.ArgumentParser(
        description=beancount.prices.__doc__.splitlines()[0])

    # Input sources or filenames.
    parser.add_argument(
        'sources',
        nargs='+',
        help=('A list of filenames (or source "module/symbol", if -e is '
              'specified) from which to create a list of jobs.'))

    parser.add_argument(
        '-e',
        '--expressions',
        '--expression',
        action='store_true',
        help=('Interpret the arguments as "module/symbol" source strings.'))

    # Regular options.
    parser.add_argument(
        '-v',
        '--verbose',
        action='count',
        help=("Print out progress log. Specify twice for debugging info."))

    parser.add_argument(
        '-d',
        '--date',
        action='store',
        type=date_utils.parse_date_liberally,
        help=("Specify the date for which to fetch the prices."))

    parser.add_argument(
        '-i',
        '--inactive',
        action='store_true',
        help=
        ("Select all commodities from input files, not just the ones active on the date"
         ))

    parser.add_argument(
        '-u',
        '--undeclared',
        action='store',
        help=
        ("Include commodities viewed in the file even without a "
         "corresponding Commodity directive, from this default source. "
         "The currency name itself is used as the lookup symbol in this default source."
         ))

    parser.add_argument(
        '-c',
        '--clobber',
        action='store_true',
        help=
        ("Do not skip prices which are already present in input files; fetch them anyway."
         ))

    parser.add_argument(
        '-a',
        '--all',
        action='store_true',
        help=("A shorthand for --inactive, --undeclared, --clobber."))

    parser.add_argument(
        '-s',
        '--swap-inverted',
        action='store_true',
        help=
        ("For inverted sources, swap currencies instead of inverting the rate. "
         "For example, if fetching the rate for CAD from 'USD:google/^CURRENCY:USDCAD' "
         "results in 1.25, by default we would output \"price CAD  0.8000 USD\". "
         "Using this option we would instead output \" price USD   1.2500 CAD\"."
         ))

    parser.add_argument(
        '-n',
        '--dry-run',
        action='store_true',
        help=
        ("Don't actually fetch the prices, just print the list of the ones to be fetched."
         ))

    # Caching options.
    cache_group = parser.add_argument_group('cache')
    cache_filename = path.join(tempfile.gettempdir(),
                               "{}.cache".format(path.basename(sys.argv[0])))
    cache_group.add_argument(
        '--cache',
        dest='cache_filename',
        action='store',
        default=cache_filename,
        help="Enable the cache and with the given cache name.")
    cache_group.add_argument('--no-cache',
                             dest='cache_filename',
                             action='store_const',
                             const=None,
                             help="Disable the price cache.")

    cache_group.add_argument('--clear-cache',
                             action='store_true',
                             help="Clear the cache prior to startup")

    args = parser.parse_args()

    verbose_levels = {
        None: logging.WARN,
        0: logging.WARN,
        1: logging.INFO,
        2: logging.DEBUG
    }
    logging.basicConfig(level=verbose_levels[args.verbose],
                        format='%(levelname)-8s: %(message)s')

    if args.all:
        args.inactive = args.clobber = True
        args.undeclared = DEFAULT_SOURCE

    # Setup for processing.
    setup_cache(args.cache_filename, args.clear_cache)

    # Get the list of DatedPrice jobs to get from the arguments.
    logging.info("Processing at date: %s", args.date or datetime.date.today())
    jobs = []
    all_entries = []
    dcontext = None
    if args.expressions:
        # Interpret the arguments as price sources.
        for source_str in args.sources:
            psources = []
            try:
                psource_map = find_prices.parse_source_map(source_str)
            except ValueError:
                extra = "; did you provide a filename?" if path.exists(
                    source_str) else ''
                msg = ('Invalid source "{{}}"{}. '.format(extra) +
                       'Supported format is "CCY:module/SYMBOL"')
                parser.error(msg.format(source_str))
            else:
                for currency, psources in psource_map.items():
                    jobs.append(
                        find_prices.DatedPrice(psources[0].symbol, currency,
                                               args.date, psources))
    else:
        # Interpret the arguments as Beancount input filenames.
        for filename in args.sources:
            if not path.exists(filename) or not path.isfile(filename):
                parser.error('File does not exist: "{}"; '
                             'did you mean to use -e?'.format(filename))
                continue
            logging.info('Loading "%s"', filename)
            entries, errors, options_map = loader.load_file(
                filename, log_errors=sys.stderr)
            if dcontext is None:
                dcontext = options_map['dcontext']
            jobs.extend(
                find_prices.get_price_jobs_at_date(entries, args.date,
                                                   args.inactive,
                                                   args.undeclared))
            all_entries.extend(entries)

    return args, jobs, data.sorted(all_entries), dcontext
Пример #9
0
 def test_source_map_onecur_single(self):
     smap = find_prices.parse_source_map('USD:google/NASDAQ:AAPL')
     self.assertEqual(
         {'USD': [PS('beancount.prices.sources.google', 'NASDAQ:AAPL', False)]},
         self._clean_source_map(smap))
Пример #10
0
 def test_source_map_invalid(self):
     for expr in 'USD', 'something else', 'USD:NASDAQ:AAPL':
         with self.assertRaises(ValueError):
             find_prices.parse_source_map(expr)
Пример #11
0
 def test_source_map_inverse(self):
     smap = find_prices.parse_source_map('USD:yahoo/^GBPUSD')
     self.assertEqual(
         {'USD': [PS('beancount.prices.sources.yahoo', 'GBPUSD', True)]},
         self._clean_source_map(smap))
Пример #12
0
 def test_source_map_onecur_single(self):
     smap = find_prices.parse_source_map('USD:yahoo/AAPL')
     self.assertEqual(
         {'USD': [PS('beancount.prices.sources.yahoo', 'AAPL', False)]},
         self._clean_source_map(smap))