-
Notifications
You must be signed in to change notification settings - Fork 1
Remove fetching from GitHub release assets #62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
7f7a684
bf2b5b3
1441cff
1b21fe5
1f67188
49b0248
a80d45f
8920efd
e5f9164
75b5c1d
fdb6c28
405889b
31a520e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,19 +1,16 @@ | ||
| import json | ||
| import os | ||
| import pathlib | ||
| import shutil | ||
| import urllib.request | ||
|
|
||
| import platformdirs | ||
| import pytest | ||
| from pytest_socket import SocketBlockedError, disable_socket | ||
|
|
||
| import openff.nagl_models._dynamic_fetch | ||
| from openff.nagl_models import __file__ as root | ||
| from openff.nagl_models._dynamic_fetch import ( | ||
| get_model, | ||
| HashComparisonFailedException, | ||
| UnableToParseDOIException, | ||
| BadFileSuffixError, | ||
| ) | ||
|
|
||
|
|
||
|
|
@@ -29,41 +26,6 @@ def mocked_urlretrieve(url, filename): | |
| return new, None | ||
|
|
||
|
|
||
| def mocked_get_release_metadata(): | ||
| # can regenerate this file with | ||
| # $ wget https://api.github.com/repos/openforcefield/openff-nagl-models/releases | ||
| return json.loads( | ||
| open(pathlib.Path(root).parent / "tests/data/releases.json").read() | ||
| ) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "known_model", | ||
| [ | ||
| "openff-gnn-am1bcc-0.0.1-alpha.1.pt", | ||
| "openff-gnn-am1bcc-0.1.0-rc.1.pt", | ||
| "openff-gnn-am1bcc-0.1.0-rc.2.pt", | ||
| "openff-gnn-am1bcc-0.1.0-rc.3.pt", | ||
| ], | ||
| ) | ||
| def test_get_known_models(monkeypatch, known_model): | ||
| with monkeypatch.context() as m: | ||
| m.setattr( | ||
| urllib.request, | ||
| "urlretrieve", | ||
| mocked_urlretrieve, | ||
| ) | ||
| m.setattr( | ||
| openff.nagl_models._dynamic_fetch, | ||
| "get_release_metadata", | ||
| mocked_get_release_metadata, | ||
| ) | ||
|
|
||
| assert get_model(known_model).endswith(known_model) | ||
|
|
||
| assert "OPENFF_NAGL_MODELS" in get_model(known_model) | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def hide_cache(): | ||
| cache_dir = platformdirs.user_cache_path() / "OPENFF_NAGL_MODELS" | ||
|
|
@@ -83,60 +45,94 @@ def hide_cache(): | |
| shutil.move(alt_dir, cache_dir) | ||
|
|
||
|
|
||
| def test_access_internet_with_empty_cache(hide_cache): | ||
| cache_path = platformdirs.user_cache_path() / "OPENFF_NAGL_MODELS" | ||
| def test_zenodo_fetching_and_caching(hide_cache): | ||
| """ | ||
| All of the tests that rely on remote fetching into the cache | ||
| and checking whether something is in the cache need to be run in | ||
| serial, otherwise they'll interfere with each other, so they're | ||
| all consolidated into this one test. | ||
| """ | ||
|
|
||
| # This test uses a Zenodo sandbox DOI (10.5072 prefix) and the corresponding | ||
| # SHA256 hash of the test file "my_favorite_model.pt" (which is a copy of | ||
| # openff-gnn-am1bcc-0.1.0-rc.3.pt) uploaded to that sandbox record | ||
|
|
||
| from pytest_socket import SocketBlockedError, disable_socket, enable_socket | ||
|
|
||
| disable_socket() | ||
|
|
||
| # would be nice to test the FileNotFoundError, but much more difficult to get that | ||
| # particular network failure vs. checking that the network is accessed at all | ||
| # Ensure that the cache is hidden, | ||
| with pytest.raises(FileNotFoundError): | ||
|
|
||
| get_model( | ||
| "my_favorite_model.pt", | ||
| ) | ||
|
|
||
| # Ensure that trying to fetch a | ||
| # model fails due to lack of internet access | ||
| with pytest.raises( | ||
| SocketBlockedError, | ||
| ): | ||
| get_model.cache_clear() | ||
| get_model( | ||
| "my_favorite_model.pt", | ||
| doi="10.5072/zenodo.278300", | ||
| file_hash="127eb0b9512f22546f8b455582bcd85b2521866d32b86d231fee26d4771b1d81", | ||
| ) | ||
|
|
||
| get_model("openff-gnn-am1bcc-0.1.0-rc.3.pt") | ||
| # Ensure that the file can actually be fetched | ||
| enable_socket() | ||
| get_model( | ||
| "my_favorite_model.pt", | ||
| doi="10.5072/zenodo.278300", | ||
| ) | ||
|
|
||
| # Ensure that, once fetched, the file can be gotten without accessing the internet. | ||
| disable_socket() | ||
| # Ensure that cached files can be accessed when no optional arguments are provided | ||
| get_model( | ||
| "my_favorite_model.pt", | ||
| ) | ||
|
Comment on lines
+88
to
+90
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we be extra explicit about where the file is and isn't?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added! |
||
|
|
||
| def test_file_exists_in_cache_without_internet(monkeypatch): | ||
| # since tests can run in different orders, make sure the file exists already | ||
| with monkeypatch.context() as m: | ||
| m.setattr( | ||
| urllib.request, | ||
| "urlretrieve", | ||
| mocked_urlretrieve, | ||
| ) | ||
| m.setattr( | ||
| openff.nagl_models._dynamic_fetch, | ||
| "get_release_metadata", | ||
| mocked_get_release_metadata, | ||
| ) | ||
| # Ensure that cached files can be accessed when only doi is provided | ||
|
j-wags marked this conversation as resolved.
Outdated
|
||
| get_model( | ||
| "my_favorite_model.pt", | ||
| doi="10.5072/zenodo.278300", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (not blocking) I can't figure out a good way (or reason to) test this, but I was a little surprised that an incorrect (but correctly-formatted) DOI could be passed here and it might not necessarily match the contents on Zenodo
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I somewhat addressed this in a spec clarification openforcefield/standards@2b6ef83 |
||
| ) | ||
|
|
||
| assert get_model("openff-gnn-am1bcc-0.1.0-rc.3.pt") | ||
| # Ensure that cached files can be accessed when all optional arguments are provided | ||
| get_model( | ||
| "my_favorite_model.pt", | ||
| doi="10.5072/zenodo.278300", | ||
| file_hash="127eb0b9512f22546f8b455582bcd85b2521866d32b86d231fee26d4771b1d81", | ||
| ) | ||
|
|
||
| disable_socket() | ||
| # Ensure that cached files can be accessed when only hash is provided | ||
| get_model( | ||
| "my_favorite_model.pt", | ||
| file_hash="127eb0b9512f22546f8b455582bcd85b2521866d32b86d231fee26d4771b1d81", | ||
| ) | ||
|
|
||
| # Ensure that cached files raise hash comparison errors | ||
| with pytest.raises(HashComparisonFailedException): | ||
| get_model( | ||
| "my_favorite_model.pt", | ||
| doi="10.5072/zenodo.278300", | ||
| file_hash="wrong_hash", | ||
| ) | ||
|
|
||
| get_model("openff-gnn-am1bcc-0.1.0-rc.3.pt") | ||
|
|
||
|
|
||
| def test_error_on_missing_file(monkeypatch): | ||
| with ( | ||
| pytest.raises( | ||
| # | ||
| def test_error_on_missing_file(): | ||
| with pytest.raises( | ||
| FileNotFoundError, | ||
| match="Could not find asset with name 'FOOBAR", | ||
| ), | ||
| monkeypatch.context() as m, | ||
| ): | ||
| m.setattr( | ||
| urllib.request, | ||
| "urlretrieve", | ||
| mocked_urlretrieve, | ||
| ) | ||
| m.setattr( | ||
| openff.nagl_models._dynamic_fetch, | ||
| "get_release_metadata", | ||
| mocked_get_release_metadata, | ||
| ) | ||
| match="Could not find asset with name 'FOOBAR"): | ||
| get_model("FOOBAR.pt") | ||
|
|
||
| def test_error_on_bad_file_suffix(): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this behavior should not reach out to the internet, it would be nice to have this test run with and without the socket turned off. Same with |
||
| with pytest.raises( | ||
| BadFileSuffixError, | ||
| match="NAGLToolkitWrapper does not recognize file path extension"): | ||
|
|
||
| get_model("FOOBAR.txt") | ||
|
|
||
|
|
@@ -150,69 +146,22 @@ def test_error_on_missing_file(monkeypatch): | |
| "openff-gnn-am1bcc-0.1.0-rc.3.pt", | ||
| ], | ||
| ) | ||
| def test_all_models_loadable(model, monkeypatch): | ||
| def test_all_models_loadable(model): | ||
| pytest.importorskip("openff.nagl") | ||
|
|
||
| from openff.nagl.nn._models import GNNModel | ||
|
|
||
| with monkeypatch.context() as m: | ||
| m.setattr( | ||
| urllib.request, | ||
| "urlretrieve", | ||
| mocked_urlretrieve, | ||
| ) | ||
| m.setattr( | ||
| openff.nagl_models._dynamic_fetch, | ||
| "get_release_metadata", | ||
| mocked_get_release_metadata, | ||
| ) | ||
|
|
||
| GNNModel.load(get_model(model), eval_mode=True) | ||
|
|
||
|
|
||
| def test_get_model_by_doi_and_hash(hide_cache): | ||
| # This test uses a Zenodo sandbox DOI (10.5072 prefix) and the corresponding | ||
| # SHA256 hash of the test file uploaded to that sandbox record | ||
| get_model( | ||
| "my_favorite_model.pt", | ||
| doi="10.5072/zenodo.278300", | ||
| file_hash="127eb0b9512f22546f8b455582bcd85b2521866d32b86d231fee26d4771b1d81", | ||
| ) | ||
|
|
||
|
|
||
| def test_get_model_by_doi_no_hash(hide_cache): | ||
| get_model("my_favorite_model.pt", doi="10.5072/zenodo.278300") | ||
|
|
||
|
|
||
| def test_get_model_hash_comparison_fails(): | ||
| with pytest.raises(HashComparisonFailedException): | ||
| get_model( | ||
| "my_favorite_model.pt", | ||
| doi="10.5072/zenodo.278300", | ||
| file_hash="wrong_hash", | ||
| ) | ||
| GNNModel.load(get_model(model), eval_mode=True) | ||
|
|
||
|
|
||
| def test_user_provided_hash_conflicts_with_known_hash(): | ||
| with pytest.raises(HashComparisonFailedException): | ||
| get_model("openff-gnn-am1bcc-0.1.0-rc.3.pt", file_hash="wrong_hash") | ||
|
|
||
|
|
||
| def test_malformed_doi(monkeypatch, hide_cache): | ||
| with monkeypatch.context() as m: | ||
| m.setattr( | ||
| urllib.request, | ||
| "urlretrieve", | ||
| mocked_urlretrieve, | ||
| ) | ||
| m.setattr( | ||
| openff.nagl_models._dynamic_fetch, | ||
| "get_release_metadata", | ||
| mocked_get_release_metadata, | ||
| ) | ||
|
|
||
| with pytest.raises(UnableToParseDOIException): | ||
| get_model("my_favorite_model.pt", doi="zenodo.278300") | ||
| def test_malformed_doi(): | ||
| with pytest.raises(UnableToParseDOIException): | ||
| get_model("nonexistent.pt", doi="zenodo.278300") | ||
|
|
||
|
|
||
| def test_no_matching_file_at_doi(): | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.