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))
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))
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))
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))
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
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))
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)
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))
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))