""" This module contains routines to talk with NOMAD. They are only
slightly modified routines provided by the NOMAD guys.
"""
from ase2sprkkr.common.decorators import add_to_signature, cached_class_property
from functools import wraps
[docs]
def with_token(func):
@add_to_signature(func)
@wraps(func)
def func_with_token(self, token:str=None, *args, **kwargs):
token = token or self.token
if not token:
raise ValueError("Nomad authentication token not set")
func(*args, **kwargs, token=token)
return func_with_token
[docs]
class NomadApi():
default_api_url='https://nomad-lab.eu/prod/v1/api/v1/'
@cached_class_property
def requests():
""" Loading requests lasts for ages """
import requests
return requests
[docs]
def __init__(self, nomad_url=None):
self.url = nomad_url or self.default_api_url
self.token = None
[docs]
def get_authentication_token(self, username, password, expires=None):
'''Get the token for accessing your NOMAD unpublished uploads remotely'''
try:
response = self.requests.get(
self.url + 'auth/token', params=dict(username=username, password=password), timeout=10)
token = response.json().get('access_token')
if token:
if expires:
response = self.requests.get(
self.url + 'auth/token', params=dict(token=token, username=username, password=password, expires=expires), timeout=10)
token = response.json().get('access_token')
if token:
return token
raise ValueError('Nomad response is missing token: \n' + str(response.json()))
except Exception:
raise RuntimeError('Something went wrong trying to get Nomad authentication token')
[docs]
@with_token
def create_dataset(self, dataset_name, token=None):
'''Create a dataset to group a series of NOMAD entries'''
try:
response = self.requests.post(
self.url + 'datasets/',
headers={'Authorization': f'Bearer {token}', 'Accept': 'application/json'},
json={"dataset_name": dataset_name},
timeout=10
)
dataset_id = response.json().get('dataset_id')
if dataset_id:
return dataset_id
raise ValueError('Nomad response is missing dataset_id:\n ' + str(response.json()))
except Exception as e:
raise RuntimeError('Something went wrong trying to create a Nomad dataset') from e
[docs]
@with_token
def upload(self, upload_file, token=None):
'''Upload a single file for NOMAD upload, e.g., zip format'''
def upload():
try:
response = self.requests.post(
self.url + 'uploads',
headers={'Authorization': f'Bearer {token}', 'Accept': 'application/json'},
data=f, timeout=30)
upload_id = response.json().get('upload_id')
if upload_id:
return upload_id
raise ValueError('Nomad response is missing upload_id:\n ' + str(response.json()))
except Exception as e:
raise RuntimeError('Something went wrong uploading to NOMAD') from e
if isinstance(upload_file, str):
with open(upload_file, 'rb') as f:
upload()
else:
upload()
[docs]
@with_token
def check_upload_status(self, upload_id, token=None):
'''
# upload success => returns 'Process publish_upload completed successfully'
# publish success => 'Process publish_upload completed successfully'
'''
try:
response = self.requests.get(
self.url + 'uploads/' + upload_id,
headers={'Authorization': f'Bearer {token}'}, timeout=30)
status_message = response.json().get('data').get('last_status_message')
if status_message:
return status_message
raise ValueError('Nomad response is missing status_message: \n' + str(response.json()))
except Exception as e:
raise RuntimeError('Something went wrong trying to check the status of upload' + upload_id) from e
# upload gets deleted from the upload staging area once published...or in this case something went wrong
[docs]
def publish_upload(self, upload_id, token=None):
'''Publish an upload'''
try:
response = self.requests.post(
self.url + 'uploads/' + upload_id + '/action/publish',
headers={'Authorization': f'Bearer {token}', 'Accept': 'application/json'},
timeout=30)
return response
except Exception as e:
raise RuntimeError('Something went wrong trying to publish upload: ' + upload_id) from e