def setUp(self): fetch_cached = mock.patch( 'beancount.prices.price.fetch_cached_price').start() fetch_cached.return_value = source.SourcePrice( D('125.00'), datetime.datetime(2015, 11, 22, 16, 0, 0), 'JPY') self.dprice = find_prices.DatedPrice('JPY', 'USD', datetime.date(2015, 11, 22), None) self.addCleanup(mock.patch.stopall)
def test_expressions(self): with test_utils.capture('stderr'): args, jobs, _, __ = test_utils.run_with_args( price.process_args, ['--no-cache', '-e', 'USD:yahoo/AAPL']) self.assertEqual([ find_prices.DatedPrice( 'AAPL', 'USD', None, [find_prices.PriceSource(yahoo, 'AAPL', False)]) ], jobs)
def test_fetch_price__naive_time_no_timeozne(self, fetch_cached): fetch_cached.return_value = SourcePrice( D('125.00'), datetime.datetime(2015, 11, 22, 16, 0, 0), 'JPY') dprice = find_prices.DatedPrice('JPY', 'USD', datetime.date(2015, 11, 22), None) with self.assertRaises(ValueError): price.fetch_price( dprice._replace( sources=[find_prices.PriceSource(yahoo, 'USDJPY', False)]), False)
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