def test_get_price_jobs__inactive(self, entries, _, __): """ 2000-01-10 open Assets:US:Invest:QQQ 2000-01-10 open Assets:US:Invest:VEA 2000-01-10 open Assets:US:Invest:Margin 2014-01-01 commodity QQQ price: "USD:google/NASDAQ:QQQ" 2014-01-01 commodity VEA price: "USD:google/NASDAQ:VEA" 2014-02-06 * Assets:US:Invest:QQQ 100 QQQ {86.23 USD} Assets:US:Invest:VEA 200 VEA {43.22 USD} Assets:US:Invest:Margin 2014-08-07 * Assets:US:Invest:QQQ -100 QQQ {86.23 USD} @ 91.23 USD Assets:US:Invest:Margin """ jobs = find_prices.get_price_jobs_at_date(entries, None, False, False) self.assertEqual({('VEA', 'USD')}, {(job.base, job.quote) for job in jobs}) jobs = find_prices.get_price_jobs_at_date(entries, None, True, False) self.assertEqual({('VEA', 'USD'), ('QQQ', 'USD')}, {(job.base, job.quote) for job in jobs})
def test_get_price_jobs__date(self, entries, _, __): """ 2000-01-10 open Assets:US:Invest:QQQ 2000-01-10 open Assets:US:Invest:VEA 2000-01-10 open Assets:US:Invest:Margin 2014-01-01 commodity QQQ price: "USD:yahoo/NASDAQ:QQQ" 2014-01-01 commodity VEA price: "USD:yahoo/NASDAQ:VEA" 2014-02-06 * Assets:US:Invest:QQQ 100 QQQ {86.23 USD} Assets:US:Invest:VEA 200 VEA {43.22 USD} Assets:US:Invest:Margin 2014-08-07 * Assets:US:Invest:QQQ -100 QQQ {86.23 USD} @ 91.23 USD Assets:US:Invest:Margin 2015-01-15 * Assets:US:Invest:QQQ 10 QQQ {92.32 USD} Assets:US:Invest:VEA -200 VEA {43.22 USD} @ 41.01 USD Assets:US:Invest:Margin """ jobs = find_prices.get_price_jobs_at_date(entries, datetime.date(2014, 1, 1), False, None) self.assertEqual(set(), {(job.base, job.quote) for job in jobs}) jobs = find_prices.get_price_jobs_at_date(entries, datetime.date(2014, 6, 1), False, None) self.assertEqual({('QQQ', 'USD'), ('VEA', 'USD')}, {(job.base, job.quote) for job in jobs}) jobs = find_prices.get_price_jobs_at_date(entries, datetime.date(2014, 10, 1), False, None) self.assertEqual({('VEA', 'USD')}, {(job.base, job.quote) for job in jobs}) jobs = find_prices.get_price_jobs_at_date(entries, None, False, None) self.assertEqual({('QQQ', 'USD')}, {(job.base, job.quote) for job in jobs})
def test_get_price_jobs__undeclared(self, entries, _, __): """ 2000-01-10 open Assets:US:Invest:QQQ 2000-01-10 open Assets:US:Invest:VEA 2000-01-10 open Assets:US:Invest:Margin 2014-01-01 commodity QQQ price: "USD:yahoo/NASDAQ:QQQ" 2014-02-06 * Assets:US:Invest:QQQ 100 QQQ {86.23 USD} Assets:US:Invest:VEA 200 VEA {43.22 USD} Assets:US:Invest:Margin """ jobs = find_prices.get_price_jobs_at_date(entries, None, False, None) self.assertEqual({('QQQ', 'USD')}, {(job.base, job.quote) for job in jobs}) jobs = find_prices.get_price_jobs_at_date(entries, None, False, 'yahoo') self.assertEqual({('QQQ', 'USD'), ('VEA', 'USD')}, {(job.base, job.quote) for job in jobs})
def test_get_price_jobs__default_source(self, entries, _, __): """ 2000-01-10 open Assets:US:Invest:QQQ 2000-01-10 open Assets:US:Invest:Margin 2014-01-01 commodity QQQ price: "NASDAQ:QQQ" 2014-02-06 * Assets:US:Invest:QQQ 100 QQQ {86.23 USD} Assets:US:Invest:Margin """ jobs = find_prices.get_price_jobs_at_date(entries, None, False, 'yahoo') self.assertEqual(1, len(jobs[0].sources)) self.assertIsInstance(jobs[0].sources[0], find_prices.PriceSource)
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