def merge_config(args: argparse.Namespace, config: configparser.ConfigParser) -> ArgType: """ Merge CLI args > user config > library config > OFX Home > defaults """ # All ArgumentParser args that have a value set _args = {k: v for k, v in vars(args).items() if v is not None} server = _args["server"] user_cfg = read_config(config, server) merged = ChainMap(_args, user_cfg, DEFAULTS) ofxhome_id = merged["ofxhome"] if ofxhome_id: lookup = ofxhome.lookup(ofxhome_id) if lookup is not None: # Insert OFX Home lookup ahead of DEFAULTS but after # user configs and library configs merged.maps.insert(-1, {"url": lookup.url, "org": lookup.org, "fid": lookup.fid, "brokerid": lookup.brokerid}) if not merged["url"]: msg = "Unknown server '{}'; please configure 'url' or 'ofxhome'" raise ValueError(msg.format(server)) return merged
def scan_profiles(start: int, stop: int, timeout: Optional[float] = None ) -> Dict[str, Tuple[ScanResult, ScanResult, Mapping[str, bool]]]: """ Scan OFX Home's list of FIs for working connection configs. """ results = {} institutions = ofxhome.list_institutions() for ofxhome_id in list(institutions.keys())[start:stop]: lookup = ofxhome.lookup(ofxhome_id) if lookup is None\ or ofxhome.ofx_invalid(lookup)\ or ofxhome.ssl_invalid(lookup): continue working = _scan_profile(url=lookup.url, org=lookup.org, fid=lookup.fid, timeout=timeout) if working: results[ofxhome_id] = working return results
def test(self): mock_xml = BytesIO(b"""<?xml version="1.0" encoding="utf-8"?> <institution id="424"> <name>American Express Card</name> <fid>3101</fid> <org>AMEX</org> <url>https://online.americanexpress.com/myca/ofxdl/desktop/desktopDownload.do?request_type=nl_ofxdownload</url> <ofxfail>0</ofxfail> <sslfail>0</sslfail> <lastofxvalidation>2019-04-29 23:08:45</lastofxvalidation> <lastsslvalidation>2019-04-29 23:08:44</lastsslvalidation> <profile finame="American Express" addr1="777 American Expressway" city="Fort Lauderdale" state="Fla." postalcode="33337-0001" country="USA" csphone="1-800-AXP-7500 (1-800-297-7500)" url="https://online.americanexpress.com/myca/ofxdl/desktop/desktopDownload.do?request_type=nl_ofxdownload" signonmsgset="true" bankmsgset="true" creditcardmsgset="true"/> </institution> """) with patch("urllib.request.urlopen") as mock_urlopen: mock_urlopen.return_value = mock_xml lookup = ofxhome.lookup("424") self.assertIsInstance(lookup, ofxhome.OFXServer) self.assertEqual(lookup.id, "424") self.assertEqual(lookup.name, "American Express Card") self.assertEqual(lookup.fid, "3101") self.assertEqual(lookup.org, "AMEX") self.assertEqual( lookup.url, "https://online.americanexpress.com/myca/ofxdl/desktop/desktopDownload.do?request_type=nl_ofxdownload", ) self.assertEqual(lookup.ofxfail, False) self.assertEqual(lookup.sslfail, False) self.assertEqual(lookup.lastofxvalidation, datetime(2019, 4, 29, 23, 8, 45)) self.assertEqual(lookup.lastsslvalidation, datetime(2019, 4, 29, 23, 8, 44)) self.assertEqual( lookup.profile, { "finame": "American Express", "addr1": "777 American Expressway", "city": "Fort Lauderdale", "state": "Fla.", "postalcode": "33337-0001", "country": "USA", "csphone": "1-800-AXP-7500 (1-800-297-7500)", "url": "https://online.americanexpress.com/myca/ofxdl/desktop/desktopDownload.do?request_type=nl_ofxdownload", "signonmsgset": True, "bankmsgset": True, "creditcardmsgset": True, }, )
def main(): fis: Mapping[str, str] = ofxhome.list_institutions() for ofxhome_id in fis.keys(): print("Scanning {}".format(ofxhome_id)) lookup: Optional[ofxhome.OFXServer] = ofxhome.lookup(ofxhome_id) if lookup is None or lookup.url is None: continue url = lookup.url org = lookup.org fid = lookup.fid lookup_name = saxutils.unescape(lookup.name) srvr_nick = known_servers.get(ofxhome_id, lookup_name) ofxhome_id = lookup.id assert ofxhome_id names = LibraryConfig["NAMES"] if ofxhome_id not in names: names[ofxhome_id] = lookup_name if ofxhome.ofx_invalid(lookup) or ofxhome.ssl_invalid(lookup): blank_fmt = {"versions": [], "formats": {}} scan_results = (blank_fmt, blank_fmt, {}) else: scan_results: ofxget.ScanResults = ofxget._scan_profile( url=url, org=org, fid=fid, timeout=10.0 ) v1, v2, _ = scan_results if (not v2["versions"]) and (not v1["versions"]): # If no OFX response, blank the server config LibraryConfig[srvr_nick] = {"ofxhome": ofxhome_id} continue format = ofxget._best_scan_format(scan_results) looked_up_data = { "ofxhome": ofxhome_id, "url": url, "org": org, "fid": fid, "brokerid": lookup.brokerid, } args = ChainMap({"server": srvr_nick}, looked_up_data, format) write_config(args)
def merge_config(config, args): """ Merge default FI configs with user configs from oftools.cfg and CLI args """ server = args.server if server not in config.fi_index: raise ValueError("Unknown FI '{}' not in {}".format( server, str(config.fi_index))) # List of nonempty argparse args set from command line overrides = [k for k, v in vars(args).items() if v] for cfg, value in config.items(server, raw=True): # argparse settings override configparser settings if cfg in overrides: continue if cfg in ( "checking", "savings", "moneymrkt", "creditline", "creditcard", "investment", ): # Allow sequences of acct nos values = [v.strip() for v in value.split(",")] arg = getattr(args, cfg) assert isinstance(arg, list) arg.extend(values) else: # Coerce config to bool, if applicable arg = getattr(args, cfg, None) if type(arg) is bool: value = config.getboolean(server, cfg) setattr(args, cfg, value) # Fall back to OFX Home, if possible url = getattr(args, "url", None) if url is None and "ofxhome_id" in config[server]: lookup = ofxhome.lookup(config[server]["ofxhome_id"]) args.url = lookup.url for cfg in "fid", "org", "brokerid": if getattr(args, cfg, None) is None: value = getattr(lookup, cfg) setattr(args, cfg, value) return args
def merge_from_ofxhome(args: ArgsType): ofxhome_id = args["ofxhome"] if ofxhome_id: logger.info(f"Looking up OFX Home API for id#{ofxhome_id}") lookup = ofxhome.lookup(ofxhome_id) if lookup: logger.debug(f"OFX Home lookup found {lookup}") # Insert OFX Home lookup ahead of DEFAULTS but after # CLI args and user configss args.maps.insert( -1, { "url": lookup.url, "org": lookup.org, "fid": lookup.fid, "brokerid": lookup.brokerid, }, )
def test(self): mock_xml = BytesIO( b"""<?xml version="1.0" encoding="utf-8"?> <institution id="424"> <name>American Express Card</name> <fid>3101</fid> <org>AMEX</org> <url>https://online.americanexpress.com/myca/ofxdl/desktop/desktopDownload.do?request_type=nl_ofxdownload</url> <ofxfail>0</ofxfail> <sslfail>0</sslfail> <lastofxvalidation>2019-04-29 23:08:45</lastofxvalidation> <lastsslvalidation>2019-04-29 23:08:44</lastsslvalidation> <profile finame="American Express" addr1="777 American Expressway" city="Fort Lauderdale" state="Fla." postalcode="33337-0001" country="USA" csphone="1-800-AXP-7500 (1-800-297-7500)" url="https://online.americanexpress.com/myca/ofxdl/desktop/desktopDownload.do?request_type=nl_ofxdownload" signonmsgset="true" bankmsgset="true" creditcardmsgset="true"/> </institution> """) with patch("urllib.request.urlopen") as mock_urlopen: mock_urlopen.return_value = mock_xml lookup = ofxhome.lookup("424") self.assertIsInstance(lookup, ofxhome.OFXServer) self.assertEqual(lookup.id, "424") self.assertEqual(lookup.name, "American Express Card") self.assertEqual(lookup.fid, "3101") self.assertEqual(lookup.org, "AMEX") self.assertEqual(lookup.url, "https://online.americanexpress.com/myca/ofxdl/desktop/desktopDownload.do?request_type=nl_ofxdownload") self.assertEqual(lookup.ofxfail, False) self.assertEqual(lookup.sslfail, False) self.assertEqual(lookup.lastofxvalidation, datetime(2019, 4, 29, 23, 8, 45)) self.assertEqual(lookup.lastsslvalidation, datetime(2019, 4, 29, 23, 8, 44)) self.assertEqual(lookup.profile, {"finame": "American Express", "addr1": "777 American Expressway", "city": "Fort Lauderdale", "state": "Fla.", "postalcode": "33337-0001", "country": "USA", "csphone": "1-800-AXP-7500 (1-800-297-7500)", "url": "https://online.americanexpress.com/myca/ofxdl/desktop/desktopDownload.do?request_type=nl_ofxdownload", "signonmsgset": True, "bankmsgset": True, "creditcardmsgset": True})
def scan_profiles(start, stop, timeout=None): """ Scan OFX Home's list of FIs for working connection configs. """ results = {} institutions = ofxhome.list_institutions() for institution in institutions[start:stop]: ofxhome_id = int(institution.get("id")) lookup = ofxhome.lookup(ofxhome_id) if lookup is None or ofxhome.ofx_invalid( lookup) or ofxhome.ssl_invalid(lookup): continue working = scan_profile(url=lookup.url, org=lookup.org, fid=lookup.fid, timeout=timeout) if working: results[ofxhome_id] = working return results