def fetch_exchange_rates(): """Retrieve all currency exchange rates. Batch currencies into requests of `SYMBOLS_PER_REQUEST` currencies each. Returns: list: List of `{abbr : n.nn}` dicts of exchange rates (relative to EUR). """ rates = {} futures = [] active = load_active_currencies() syms = [s for s in CURRENCIES.keys() if s in active] if not OPENX_APP_KEY: log.warning('fetching limited set of fiat currency exchange rates: ' 'APP_KEY for openexchangerates.org not set. ' 'Please sign up for a free account here: ' 'https://openexchangerates.org/signup/free') jobs = [(load_xra_rates, (syms, ))] else: jobs = [(load_openx_rates, (syms, ))] syms = [] for s in CRYPTO_CURRENCIES.keys(): if s in CURRENCIES: log.warning( 'ignoring crytopcurrency "%s", as it conflicts with ' 'a fiat currency', s) continue if s in active: syms.append(s) for symbols in grouper(SYMBOLS_PER_REQUEST, syms): jobs.append((load_cryptocurrency_rates, (symbols, ))) # fetch data in a thread pool pool = Pool(2) for job in jobs: futures.append(pool.apply_async(*job)) pool.close() pool.join() for f in futures: for currency, rate in f.get().iteritems(): if is_valid_currency(currency) and is_valid_exchange_rate(rate): rates[currency] = rate log.debug("Currency %s has new rate %s", currency, rate) else: log.warn("Got invalid rate update for currency '%s' to '%s'", currency, rate) return rates
def handle_delimited_query(query): """Process sub-commands. Args: query (str): User query """ # Currencies or decimal places if query.endswith(DELIMITER): # User deleted trailing space run_trigger('config') # subprocess.call(['osascript', '-e', ALFRED_AS]) # return mode, query = [s.strip() for s in query.split(DELIMITER)] if mode == 'currencies': currencies = sorted([(name, symbol) for (symbol, name) in CURRENCIES.items()] + [(name, symbol) for (symbol, name) in CRYPTO_CURRENCIES.items()]) if query: currencies = wf.filter(query, currencies, key=lambda t: ' '.join(t), match_on=MATCH_ALL ^ MATCH_ALLCHARS, min_score=30) else: # Show last update time age = wf.cached_data_age(CURRENCY_CACHE_NAME) if age > 0: # Exchange rates in cache td = timedelta(seconds=age) wf.add_item('Exchange rates updated {}'.format( human_timedelta(td)), icon=ICON_INFO) if not currencies: wf.add_item('No matching currencies', 'Try a different query', icon=ICON_WARNING) for name, symbol in currencies: wf.add_item(u'{} // {}'.format(name, symbol), u'Use `{}` in conversions'.format(symbol), copytext=symbol, valid=False, icon=ICON_CURRENCY) wf.send_feedback()
def fetch_currency_rates(): """Retrieve all currency exchange rates. Batch currencies into requests of `SYMBOLS_PER_REQUEST` currencies each. Returns: list: List of `{abbr : n.nn}` dicts of exchange rates (relative to EUR). """ rates = {} for symbols in grouper(SYMBOLS_PER_REQUEST, CURRENCIES.keys()): symbols = [s for s in symbols if s] d = load_yahoo_rates(symbols) rates.update(d) return rates
def fetch_exchange_rates(): """Retrieve all currency exchange rates. Batch currencies into requests of `SYMBOLS_PER_REQUEST` currencies each. Returns: list: List of `{abbr : n.nn}` dicts of exchange rates (relative to EUR). """ rates = {} futures = [] active = load_active_currencies() syms = [s for s in CURRENCIES.keys() if s in active] # rates.update(load_openx_rates(syms)) jobs = [(load_openx_rates, (syms, ))] syms = [] for s in CRYPTO_CURRENCIES.keys(): if s in CURRENCIES: log.warning( 'ignoring crytopcurrency "%s", as it conflicts with ' 'a fiat currency', s) continue if s in active: syms.append(s) # syms = [s for s in CRYPTO_CURRENCIES.keys() if s in active] for symbols in grouper(SYMBOLS_PER_REQUEST, syms): jobs.append((load_cryptocurrency_rates, (symbols, ))) # fetch data in a thread pool pool = Pool(2) for job in jobs: futures.append(pool.apply_async(*job)) pool.close() pool.join() for f in futures: rates.update(f.get()) return rates
def fetch_exchange_rates(): """Retrieve all currency exchange rates. Batch currencies into requests of `SYMBOLS_PER_REQUEST` currencies each. Returns: list: List of `{abbr : n.nn}` dicts of exchange rates (relative to EUR). """ rates = {} futures = [] active = load_active_currencies() syms = [s for s in CURRENCIES.keys() if s in active] # rates.update(load_openx_rates(syms)) jobs = [(load_openx_rates, (syms,))] syms = [] for s in CRYPTO_CURRENCIES.keys(): if s in CURRENCIES: log.warning('ignoring crytopcurrency "%s", as it conflicts with ' 'a fiat currency', s) continue if s in active: syms.append(s) # syms = [s for s in CRYPTO_CURRENCIES.keys() if s in active] for symbols in grouper(SYMBOLS_PER_REQUEST, syms): jobs.append((load_cryptocurrency_rates, (symbols,))) # fetch data in a thread pool pool = Pool(2) for job in jobs: futures.append(pool.apply_async(*job)) pool.close() pool.join() for f in futures: rates.update(f.get()) return rates
def fetch_exchange_rates(): """Retrieve all currency exchange rates. Batch currencies into requests of `SYMBOLS_PER_REQUEST` currencies each. Returns: list: List of `{abbr : n.nn}` dicts of exchange rates (relative to EUR). """ rates = {} futures = [] active = load_active_currencies() # batch symbols into groups and interleave requests to the # different services yjobs = [] syms = [s for s in CURRENCIES.keys() if s in active] for symbols in grouper(SYMBOLS_PER_REQUEST, syms): yjobs.append((load_yahoo_rates, (symbols,))) cjobs = [] syms = [sym for sym in CRYPTO_CURRENCIES.keys() if sym in active] for symbols in grouper(SYMBOLS_PER_REQUEST, syms): cjobs.append((load_cryptocurrency_rates, (symbols,))) # fetch data in a thread pool pool = Pool(4) for job in interleave(yjobs, cjobs): futures.append(pool.apply_async(*job)) pool.close() pool.join() for f in futures: rates.update(f.get()) return rates
def main(wf): """Run Script Filter. Args: wf (workflow.Workflow): Workflow object. Returns: int: Exit status. """ args = docopt(__doc__, wf.args) log.debug('args : {!r}'.format(args)) query = args.get('<query>') if args.get('--openhelp'): subprocess.call(['open', README_URL]) return 0 if args.get('--openunits'): path = wf.datafile(CUSTOM_DEFINITIONS_FILENAME) if not os.path.exists(path): shutil.copy( wf.workflowfile('{0}.sample'.format( CUSTOM_DEFINITIONS_FILENAME)), path) subprocess.call(['open', path]) return 0 if args.get('--places'): value = int(query) log.debug('Setting `decimal_places` to {!r}'.format(value)) wf.settings['decimal_places'] = value print('Set decimal places to {}'.format(value)) # subprocess.call(['osascript', '-e', ALFRED_AS]) return 0 if not query or not query.strip(): wf.add_item('View Help File', 'Open help file in your browser', valid=True, arg='--openhelp', icon=ICON_HELP) wf.add_item('View Supported Currencies', 'View and search list of supported currencies', autocomplete=' currencies {0} '.format(DELIMITER), icon=ICON_CURRENCY) wf.add_item(('Decimal Places in Results ' '(current : {0})'.format(wf.settings.get( 'decimal_places', DECIMAL_PLACES_DEFAULT))), 'View and search list of supported currencies', autocomplete=' places {0} '.format(DELIMITER), icon=ICON_SETTINGS) wf.add_item('Edit Custom Units', 'Add and edit your own custom units', valid=True, arg='--openunits', icon='icon.png') wf.send_feedback() return 0 else: # Currencies or decimal places if query.endswith(DELIMITER): # User deleted trailing space subprocess.call(['osascript', '-e', ALFRED_AS]) return 0 mode, query = [s.strip() for s in query.split(DELIMITER)] if mode == 'currencies': currencies = sorted([(name, symbol) for (symbol, name) in CURRENCIES.items()]) if query: currencies = wf.filter(query, currencies, key=lambda t: ' '.join(t), match_on=MATCH_ALL ^ MATCH_ALLCHARS, min_score=30) else: # Show last update time age = wf.cached_data_age(CURRENCY_CACHE_NAME) if age > 0: # Exchange rates in cache td = timedelta(seconds=age) wf.add_item('Exchange rates updated {}'.format( human_timedelta(td)), icon=ICON_INFO) if not currencies: wf.add_item('No matching currencies', 'Try a different query', icon=ICON_WARNING) for name, symbol in currencies: wf.add_item('{0} // {1}'.format(name, symbol), 'Use `{0}` in conversions'.format(symbol), icon=ICON_CURRENCY) wf.send_feedback() elif mode == 'places': if query: if not query.isdigit(): wf.add_item('Invalid number : {0}'.format(query), 'Please enter a number', icon=ICON_WARNING) else: wf.add_item('Set decimal places to : {0}'.format(query), 'Hit `ENTER` to save', valid=True, arg='--places {0}'.format(query), icon=ICON_SETTINGS) else: wf.add_item('Enter a number of decimal places', 'Current number is {0}'.format( wf.settings.get('decimal_places', DECIMAL_PLACES_DEFAULT)), icon=ICON_INFO) wf.send_feedback()
def respond_external(action, **kw): exchange_error = 0 exchange_message = '' error_code = '' error_description = '' errors = '' response = {} dom = None data = '' total = '' price = '' currency = '' document = '' order_number = '' order_date = '' print_action(action, 'Respond.External') locale = request.form.get('currentUsedLocalization') or '' wizard = request.form.get('wizardID') or '' try: # ------------------------------------- # Get DOM and XML response from Service # ------------------------------------- exchange_error, exchange_message, dom, data = send(action, request, session, **kw) if demo(): exchange_error, exchange_message, total, currency = _demo_price(action) order_number, order_date = _demo_order(action) elif exchange_error: total = 0.0 elif dom is not None: total = float(getDOMItemValue(dom, 'total') or '0') currency = CURRENCIES.get(getDOMItemValue(dom, 'currency'), gettext('undefined')) error_code = getDOMItemValue(dom, 'errorCode').strip() error_description = getDOMItemValue(dom, 'errorDescription') if action == '207': order = _order(dom) order_number = order.get('number', '') order_date = order.get('date', '') elif data: x = request.form.get('price') total = x and float(x.split()[0])*1.288726 or 0 except: msg = '--> Send error!' print_to(errorlog, [msg, data], request=request) # ---------------------- # Service Exchange Error # ---------------------- if IsDeepDebug: print msg raise #print_to(errorlog, ['>>> Data:', data]) IsValid = data and True or False if exchange_message and exchange_message == exchange_error: exchange_message = '' if error_description and error_description == error_code: error_description = '' # ----------------- # Response is valid # ----------------- if IsValid: errors = getDOMErrors(dom) or '' if IsDeepDebug: print errors if currency in ('undefined', n_a, '') or not total: if not exchange_message: if action == '203' and error_code in ('', '0',): pass else: exchange_message = gettext('Calculation is not performed.') IsValid = False total = IsValid and '%.2f' % total or '' price = IsValid and '%s %s' % (total, currency) or '' if IsDebug: print '--> Total: %s' % price document = order_number and ('# %s %s %s' % (order_number, gettext('at'), order_date)) or '' # ------------------------------------------- # Make parameters and Register response in DB # ------------------------------------------- attrs = { \ 'locale' : locale, 'selected_item' : kw.get('id') or request.form.get('selected_item'), 'title' : request.form.get('title') or '', 'document' : document or action, 'total' : total, 'currency' : currency, 'countryID' : getCountryID(getDOMItemValue(dom, 'countryID'), locale), 'regionID' : getRegionID(getDOMItemValue(dom, 'regionID'), locale), 'userID' : getUserID(getDOMItemValue(dom, 'userID'), locale), 'userName' : getClient(getDOMItemValue(dom, 'userName'), locale), 'wizardID' : wizard, 'wizardName' : request.form.get('wizardName') or '', 'custom_code' : request.form.get('custom_code') or '', 'option_update' : request.form.get('option_update') or '', 'option_cost' : request.form.get('option_cost') or '', 'data' : data, #getDOMTagStrippedValue(dom, 'parameters'), } #print_to(errorlog, ['>>> Total:', total]) if IsValid and action in ('203','204','205','207',): # and dom response = register(action, dom, attrs) if IsDeepDebug: print '>>> DB Response:%s' % response order = action == '205' and response.get('custom_code') or document return { \ 'action' : action, 'op' : '', # -------------- # Service Errors # -------------- 'exchange_error' : exchange_error, 'exchange_message' : exchange_message, 'error_code' : error_code, 'error_description' : error_description, 'errors' : errors, # --- # IDs # --- 'countryID' : getDOMItemValue(dom, 'countryID') or '', 'regionID' : getDOMItemValue(dom, 'regionID') or '', 'userID' : attrs['userID'], # -------------- # Client Details # -------------- 'country_name' : getDOMItemValue(dom, 'countryName') or getCountry(getDOMItemValue(dom, 'countryID'), locale), 'region_name' : getDOMItemValue(dom, 'regionName') or getRegion(getDOMItemValue(dom, 'regionID'), locale), 'client_name' : attrs['userName'], # ---------- # Order Info # ---------- 'document_number' : order_number, 'document_date' : order_date, 'order' : order, # ------- # DB Data # ------- 'total_log_rows' : getLogTotal({'userID' : attrs['userID'], 'wizardID' : wizard}), 'custom_code' : response.get('custom_code', ''), 'next_custom_code' : response.get('next_custom_code', ''), 'option_update' : response.get('option_update', ''), 'option_cost' : response.get('option_cost', ''), 'title' : response.get('title', ''), # ------------------------------ # Results (Price & XML-Response) # ------------------------------ 'price' : price, 'data' : data, }
def respond_internal(action, **kw): exchange_error = 0 exchange_message = '' error_code = '' error_description = '' response = {} dom = None data = '' currency = '' order_number = '' order_date = '' print_action(action, 'Respond.Internal') op = request.form.get('op') or kw.get('op') if IsDebug: print '--> op: [%s]' % op if not op: pass elif op == 'get': # -------------------------------------------------------------- # Generate and Send XML to Service (from WEB-form to JavaScript) # -------------------------------------------------------------- data = getXml(action, request, session) errors = [] elif op == 'set': # ----------------------------------------------- # Receive XML from Service (loaded by JavaScript) # ----------------------------------------------- dom, data = receive(action, request, session, **kw) if demo(): exchange_error, exchange_message, total, currency = _demo_price(action) order_number, order_date = _demo_order(action) else: total = float(getDOMItemValue(dom, 'total')) currency = CURRENCIES.get(getDOMItemValue(dom, 'currency'), gettext('undefined')) error_code = getDOMItemValue(dom, 'errorCode').strip() error_description = getDOMItemValue(dom, 'errorDescription') errors = getDOMErrors(dom) or '' if IsDebug: print '--> Total: %s %s' % (total, currency) total = '%.2f' % total or '' price = '%s %s' % (total, currency) or '' return { \ 'action' : action, 'op' : op, # -------------- # Service Errors # -------------- 'exchange_error' : exchange_error, 'exchange_message' : exchange_message, 'error_code' : error_code, 'error_description' : error_description, 'errors' : errors, # --- # IDs # --- 'countryID' : getDOMItemValue(dom, 'countryID') or '', 'regionID' : getDOMItemValue(dom, 'regionID') or '', 'userID' : getUserID(getDOMItemValue(dom, 'userID')), # -------------- # Client Details # -------------- 'country_name' : getDOMItemValue(dom, 'countryName') or getCountry(getDOMItemValue(dom, 'countryID')), 'region_name' : getDOMItemValue(dom, 'regionName') or getRegion(getDOMItemValue(dom, 'regionID')), 'client_name' : getClient(getDOMItemValue(dom, 'userName')), # ------------------------------ # Results (Price & XML-Response) # ------------------------------ 'price' : price, 'data' : data, }