def test_initialize_local_options(self, options: Options): options.password = "******" options.timeout = 1337 d = Downloader(options) assert d._options is not options assert str(d._options) == str(options) assert str(d._options) != str(opt) options.password = "******" assert d._options.password == "foo"
def test_write_new_section(self, options: Options, config_backup): options.timeout = 42 options.write("https://foo.bar") new_opt = Options.from_config("https://foo.bar") assert options is not new_opt for k, v in options.__dict__.items(): if k == "url": assert v == options.url assert new_opt.url == "https://foo.bar" elif k == "cache": assert type(new_opt.cache) == type(options.cache) # noqa: E721 else: assert getattr(new_opt, k) == v
def _get_server_version(options: Options) -> str: """Try and get the server version.""" import re def callback(fp: BytesIO) -> str: """Parse the version.""" return re.findall(r"\d+\.\d+.\d+", fp.getvalue().decode("utf-8"), flags=re.IGNORECASE)[0] try: if not options.autoload: raise ValueError( "Autoloading is disabled. You can enable it by setting " "`omnipath.options.autoload = True`.") with Options.from_options( options, num_retries=0, timeout=0.1, cache=None, progress_bar=False, chunk_size=1024, ) as opt: return Downloader(opt).maybe_download( Endpoint.ABOUT.s, callback, params={Key.FORMAT.s: Format.TEXT.s}, cache=False, is_final=False, ) except Exception as e: logging.debug(f"Unable to get server version. Reason: `{e}`") return UNKNOWN_SERVER_VERSION
def test_from_config_no_file(self, config_backup): if Path(Options.config_path).exists(): remove(Options.config_path) new_opt = Options.from_config() for k, v in DEFAULT_OPTIONS.__dict__.items(): if hasattr(new_opt, k) and not k.startswith("_"): assert getattr(new_opt, k) == v
def test_from_options_new_values(self, options: Options): new_opt = Options.from_options(options, autoload=not options.autoload, num_retries=0) for k, v in options.__dict__.items(): if k not in ("autoload", "num_retries"): assert getattr(new_opt, k) == v assert new_opt.autoload != options.autoload assert new_opt.num_retries == 0
def test_get_server_version(self, options: Options, requests_mock): url = urljoin(options.url, Endpoint.ABOUT.s) options.autoload = True requests_mock.register_uri( "GET", f"{url}?format=text", content=bytes("foo bar baz\nversion: 42.1337.00", encoding="utf-8"), ) version = _get_server_version(options) assert requests_mock.called_once assert version == "42.1337.00"
def test_get_server_version_no_autoload(self, options: Options, requests_mock, caplog): url = urljoin(options.url, Endpoint.ABOUT.s) options.autoload = False requests_mock.register_uri("GET", f"{url}?format=text", text="foobarbaz") with caplog.at_level(logging.DEBUG): version = _get_server_version(options) assert not requests_mock.called_once assert ("Unable to get server version. Reason: `Autoload is disabled.`" in caplog.text) assert version == UNKNOWN_SERVER_VERSION
def test_get_server_version_not_decodable(self, options: Options, requests_mock, caplog): url = urljoin(options.url, Endpoint.ABOUT.s) options.autoload = True requests_mock.register_uri("GET", f"{url}?format=text", content=bytes("foobarbaz", encoding="utf-8")) with caplog.at_level(logging.DEBUG): version = _get_server_version(options) assert requests_mock.called_once assert ( "Unable to get server version. Reason: `list index out of range`" in caplog.text) assert version == UNKNOWN_SERVER_VERSION
def test_write_config(self, options: Options, config_backup): options.timeout = 1337 options.license = License.COMMERCIAL options.password = "******" options.write() new_opt = Options.from_config() for k, v in options.__dict__.items(): if k == "cache": assert type(new_opt.cache) == type(options.cache) # noqa: E721 elif k == "password": # don't store the password in the file assert getattr(new_opt, k) is None elif k not in ("timeout", "license"): assert getattr(new_opt, k) == v assert new_opt.timeout == 1337 assert new_opt.license == License.COMMERCIAL
def test_invalid_chunk_size(self, options: Options): with pytest.raises(ValueError): options.chunk_size = 0
def test_invalid_timeout(self, options: Options): with pytest.raises(ValueError): options.timeout = 0
def test_from_options(self, options: Options): new_opt = Options.from_options(options) for k, v in options.__dict__.items(): assert getattr(new_opt, k) == v
def test_valid_license(self, options: Options, license: License): options.license = license.value assert isinstance(options.license, License) assert options.license == license
def test_write_new_section_not_url(self, options: Options, config_backup): with pytest.raises(ValueError, match=r"Invalid URL: `foobar`."): options.write("foobar")
def test_invalid_url_type(self, options: Options): with pytest.raises(TypeError): options.url = 42
def test_from_options_invalid_type(self): with pytest.raises(TypeError): Options.from_options("foo")
def test_url_localhost(self, options: Options): options.url = "https://localhost" assert options.url == "https://localhost"
def test_invalid_url(self, options: Options): with pytest.raises(ValueError): options.url = "foo"
def test_password(self, options: Options, pwd: Optional[str]): options.password = pwd assert options.password == pwd
def test_invalid_license(self, options: Options): with pytest.raises(ValueError): options.license = "foo"
def test_invalid_cache_type(self, options: Options): with pytest.raises(TypeError): options.cache = 42
def test_invalid_password_type(self, options: Options): with pytest.raises(TypeError): options.password = 42
def test_from_config_section_is_not_url(self): with pytest.raises(NoSectionError, match=r"No section: 'http://foo.bar'"): Options.from_config("http://foo.bar")
def test_invalid_num_retries(self, options: Options): with pytest.raises(ValueError): options.num_retries = -1
def __new__(cls, clsname, superclasses, attributedict): # noqa: D102 from omnipath import options endpoint = attributedict.pop("__endpoint__", clsname.lower().replace("validator", "")) use_default = True old_members = list(attributedict._member_names) old_values = cls._remove_old_members(attributedict) if endpoint is None: if len(old_members): raise ValueError( "If `__endpoint__` is `None`, no members must be specified." ) elif options.autoload: use_default = False with Options.from_options( options, num_retries=0, timeout=0.1, cache=None, progress_bar=False, chunk_size=2048, ) as opt: try: logging.debug( "Attempting to construct classes from the server") res = Downloader(opt).maybe_download( urljoin(urljoin(opt.url, f"{Key.QUERIES.s}/"), endpoint), callback=json.load, params={Key.FORMAT.s: Format.JSON.s}, ) if len({str(k).upper() for k in res.keys()}) != len(res): raise RuntimeError( f"After upper casing, key will not be unique: `{list(res.keys())}`." ) for k, value in res.items(): if (isinstance(value, str) and "no such query available" in value): raise RuntimeError( f"Invalid endpoint: `{endpoint}`.") key = str(k).upper() if value is None: attributedict[key] = cls.Validator(param=k) elif isinstance(value, Sequence): attributedict[key] = cls.Validator( param=k, haystack={str(v) for v in value}) else: attributedict[key] = cls.Validator(param=k) except Exception as e: logging.debug( f"Unable to construct classes from the server. Reason: `{e}`" ) use_default = True if use_default: if endpoint is not None: logging.debug(f"Using predefined class: `{clsname}`." + ( "" if options.autoload else " Consider specifying `omnipath.options.autoload = True`")) _ = cls._remove_old_members(attributedict) for k, v in zip(old_members, old_values): attributedict[k] = cls.Validator(param=k, doc=v) return super().__new__(cls, clsname, superclasses, attributedict)
def options() -> "Options": opt = Options.from_config() opt.cache = None opt.progress_bar = False return opt