Repository: fair-workflows/nanopub

Issue:
Catch FileNotFoundError if profile is not setup yet
We do not check for FileNotFoundErrors here: (but they are raised if user did not setup profile)
https://github.com/fair-workflows/nanopub/blob/5a142abae96fc48cd5255cb5781aab6f3f670bc6/nanopub/profile.py#L78

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dd98edd..f973eec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,7 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Not released]
 
+### Changed
+* Improved error message by pointing to documentation instead of Readme upon ProfileErrors
+
 ### Fixed
+* Catch FileNotFoundError when profile.yml does not exist, raise ProfileError with useful messageinstead.
 * Fixed broken link to documentation in README.md
 
 ### Added
diff --git a/nanopub/java_wrapper.py b/nanopub/java_wrapper.py
index fc121b7..c9adfd0 100644
--- a/nanopub/java_wrapper.py
+++ b/nanopub/java_wrapper.py
@@ -7,6 +7,8 @@ import requests
 
 from nanopub.definitions import PKG_FILEPATH
 
+from nanopub.profile import PROFILE_INSTRUCTIONS_MESSAGE
+
 # Location of nanopub tool (currently shipped along with the lib)
 NANOPUB_SCRIPT = str(PKG_FILEPATH / 'np')
 NANOPUB_TEST_SERVER = 'http://test-server.nanopubs.lod.labs.vu.nl/'
@@ -32,8 +34,8 @@ class JavaWrapper:
         rsa_key_messages = ['FileNotFoundException', 'id_rsa']
         stderr = result.stderr.decode('utf8')
         if all(m in stderr for m in rsa_key_messages):
-            raise RuntimeError('RSA key appears to be missing, see the instructions for making RSA'
-                               'keys in the setup section of the README')
+            raise RuntimeError('Nanopub RSA key appears to be missing,\n'
+                               + PROFILE_INSTRUCTIONS_MESSAGE)
         elif result.returncode != 0:
             raise RuntimeError(f'Error in nanopub java application: {stderr}')
 
diff --git a/nanopub/profile.py b/nanopub/profile.py
index 97f91e9..5126d89 100644
--- a/nanopub/profile.py
+++ b/nanopub/profile.py
@@ -6,6 +6,11 @@ import yatiml
 
 from nanopub.definitions import PROFILE_PATH
 
+PROFILE_INSTRUCTIONS_MESSAGE = '''
+    Follow these instructions to correctly setup your nanopub profile:
+    https://nanopub.readthedocs.io/en/latest/getting-started/setup.html#setup-your-profile
+'''
+
 
 class ProfileError(RuntimeError):
     """
@@ -56,9 +61,9 @@ def get_public_key() -> str:
         with open(get_profile().public_key, 'r') as f:
             return f.read()
     except FileNotFoundError:
-        raise ProfileError(f'Public key file {get_profile().public_key} not found.\n'
-                           'Maybe your profile was not set up yet or not set up correctly. '
-                           'To set up your profile see the instructions in Readme.md')
+        raise ProfileError(f'Public key file {get_profile().public_key} for nanopub not found.\n'
+                           f'Maybe your nanopub profile was not set up yet or not set up '
+                           f'correctly. \n{PROFILE_INSTRUCTIONS_MESSAGE}')
 
 
 @lru_cache()
@@ -75,9 +80,9 @@ def get_profile() -> Profile:
     """
     try:
         return _load_profile(PROFILE_PATH)
-    except yatiml.RecognitionError as e:
-        msg = (f'{e}\nYour profile has not been set up yet, or is not set up correctly. To set'
-               f' up your profile, see the instructions in README.md.')
+    except (yatiml.RecognitionError, FileNotFoundError) as e:
+        msg = (f'{e}\nYour nanopub profile has not been set up yet, or is not set up correctly.\n'
+               f'{PROFILE_INSTRUCTIONS_MESSAGE}')
         raise ProfileError(msg)
 
 


Test patch:
diff --git a/tests/test_profile.py b/tests/test_profile.py
index 571f58c..2bfc62f 100644
--- a/tests/test_profile.py
+++ b/tests/test_profile.py
@@ -38,6 +38,15 @@ def test_fail_loading_incomplete_profile(tmpdir):
             profile.get_profile()
 
 
+def test_profile_file_not_found(tmpdir):
+    test_file = Path(tmpdir / 'profile.yml')
+    with mock.patch('nanopub.profile.PROFILE_PATH', test_file):
+        profile.get_profile.cache_clear()
+
+        with pytest.raises(profile.ProfileError):
+            profile.get_profile()
+
+
 def test_store_profile(tmpdir):
     test_file = Path(tmpdir / 'profile.yml')