Skip to content

Commit

Permalink
feat: added methods for working with BioSimulations API
Browse files Browse the repository at this point in the history
  • Loading branch information
jonrkarr committed Dec 20, 2021
1 parent a8aa240 commit 4a2095d
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 32 deletions.
2 changes: 1 addition & 1 deletion biosimulators_utils/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.1.148'
__version__ = '0.1.149'
129 changes: 112 additions & 17 deletions biosimulators_utils/biosimulations/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,22 @@
import simplejson.errors

__all__ = [
'submit_project_to_runbiosimulations',
'run_simulation_project',
'publish_simulation_project',
'get_published_project',
'get_authorization_for_client',
'validate_biosimulations_api_response',
]


def submit_project_to_runbiosimulations(name, filename_or_url,
simulator, simulator_version='latest',
cpus=1, memory=8, max_time=20, env_vars=None,
purpose='other',
email=None,
project_id=None,
config=None):
def run_simulation_project(name, filename_or_url,
simulator, simulator_version='latest',
cpus=1, memory=8, max_time=20, env_vars=None,
purpose='other',
email=None,
project_id=None,
auth=None,
config=None):
""" Submit a simulation project (COMBINE/OMEX archive) to runBioSimulations and, optionally, BioSimulations
Args:
Expand All @@ -39,13 +43,15 @@ def submit_project_to_runbiosimulations(name, filename_or_url,
purpose (:obj:`str`, optional): purpose (``academic`` or ``other``)
email (:obj:`str`, optional): email to receive a notification upon completion of the simulation run
project_id (:obj:`str`, optional): id to publish the run as to BioSimulations
auth (obj:`str`, optional): authorization for the BioSimulations; needed to claim edit the published project in
the future
config (:obj:`Config`, optional): configuration
Returns:
:obj:`str`: runBioSimulations id
"""
config = config or get_config()
endpoint = config.RUNBIOSIMULATIONS_API_ENDPOINT + 'runs'
endpoint = config.BIOSIMULATIONS_API_ENDPOINT + 'runs'
run = {
"name": name,
"simulator": simulator,
Expand All @@ -62,6 +68,11 @@ def submit_project_to_runbiosimulations(name, filename_or_url,

if os.path.isfile(filename_or_url):
with open(filename_or_url, 'rb') as file:
headers = {
"Accept": "application/json",
}
if auth:
headers['Authorization'] = auth
response = requests.post(
endpoint,
data={
Expand All @@ -70,24 +81,108 @@ def submit_project_to_runbiosimulations(name, filename_or_url,
files={
'file': ('project.omex', file, 'application/zip'),
},
headers={
"Accept": "application/json",
}
headers=headers,
)
else:
run['url'] = filename_or_url
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
}
if auth:
headers['Authorization'] = auth
response = requests.post(
endpoint,
json=run,
headers={
"Content-Type": "application/json",
"Accept": "application/json",
}
headers=headers,
)
response.raise_for_status()

validate_biosimulations_api_response(response, 'Run could not be submitted.', RuntimeError)

return response.json()['id']


def publish_simulation_project(run_id, project_id, overwrite=True, auth=None, config=None):
""" Publish a project to BioSimulations
Args:
run_id (:obj:`str`): id of the simulation run to publish
project_id (:obj:`str`): desired id for the published project
auth (obj:`str`, optional): authorization for the BioSimulations; needed to claim edit the published project in
the future
config (:obj:`Config`, optional): configuration
"""
config = config or get_config()
endpoint = config.BIOSIMULATIONS_API_ENDPOINT + 'projects/{}'.format(project_id)

headers = {}
if auth:
headers['Authorization'] = auth

method = requests.post
if overwrite:
project = get_published_project(project_id)
if project:
method = requests.put

response = method(
endpoint,
json={
'id': project_id,
'simulationRun': run_id,
},
headers=headers,
)
validate_biosimulations_api_response(response,
'Project `{}` for run `{}` could not be published.'.format(project_id, run_id),
ValueError)


def get_published_project(project_id, config=None):
""" Publish a project to BioSimulations
Args:
project_id (:obj:`str`): desired id for the published project
config (:obj:`Config`, optional): configuration
Returns:
:obj:`dict`: in schema ``Project`` or :obj:`None` if the project doesn't exist
"""
config = config or get_config()
endpoint = config.BIOSIMULATIONS_API_ENDPOINT + 'projects/{}'.format(project_id)
response = requests.get(endpoint)

if response.status_code == 200:
return response.json()
else:
return None


def get_authorization_for_client(id, secret, config=None):
""" Get the authorization for a client of the BioSimulations API
Args:
id (:obj:`str`): id of the API client
secret (:obj:`str`): secret for API client
config (:obj:`Config`, optional): configuration
Returns:
:obj:`str`: authorization for the client
"""
config = config or get_config()

response = requests.post(config.BIOSIMULATIONS_API_AUTH_ENDPOINT,
json={
'client_id': id,
'client_secret': secret,
'audience': config.BIOSIMULATIONS_API_AUDIENCE,
"grant_type": "client_credentials",
})
response.raise_for_status()
response_data = response.json()
return response_data['token_type'] + ' ' + response_data['access_token']


def validate_biosimulations_api_response(response, failure_introductory_message, exception_type=None):
""" Validate a response from one of BioSimulation's APIs.
Expand Down
24 changes: 18 additions & 6 deletions biosimulators_utils/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
DEFAULT_PLOTS_PATH = 'plots.zip'
DEFAULT_LOG_PATH = 'log.yml'
DEFAULT_BIOSIMULATORS_API_ENDPOINT = 'https://api.biosimulators.org/'
DEFAULT_RUNBIOSIMULATIONS_API_ENDPOINT = 'https://api.biosimulations.org/'
DEFAULT_BIOSIMULATIONS_API_ENDPOINT = 'https://api.biosimulations.org/'
DEFAULT_BIOSIMULATIONS_API_AUTH_ENDPOINT = 'https://auth.biosimulations.org/oauth/token'
DEFAULT_BIOSIMULATIONS_API_AUDIENCE = 'api.biosimulations.org'


class Config(object):
Expand Down Expand Up @@ -58,7 +60,9 @@ class Config(object):
LOG (:obj:`bool`): whether to log the execution of a COMBINE/OMEX archive
LOG_PATH (:obj:`str`): path to save the execution log of a COMBINE/OMEX archive
BIOSIMULATORS_API_ENDPOINT (:obj:`str`): URL for BioSimulators API
RUNBIOSIMULATIONS_API_ENDPOINT (:obj:`str`): URL for runBioSimulations API
BIOSIMULATIONS_API_ENDPOINT (:obj:`str`): URL for runBioSimulations API
BIOSIMULATIONS_API_AUTH_ENDPOINT (:obj:`str`): authorization endpoint for the BioSimulations API
BIOSIMULATIONS_API_AUDIENCE (:obj:`str`): audience for the BioSimulations API
VERBOSE (:obj:`bool`): whether to display the detailed output of the execution of each task
DEBUG (:obj:`bool`): whether to raise exceptions rather than capturing them
"""
Expand Down Expand Up @@ -88,7 +92,9 @@ def __init__(self,
LOG=True,
LOG_PATH=DEFAULT_LOG_PATH,
BIOSIMULATORS_API_ENDPOINT=DEFAULT_BIOSIMULATORS_API_ENDPOINT,
RUNBIOSIMULATIONS_API_ENDPOINT=DEFAULT_RUNBIOSIMULATIONS_API_ENDPOINT,
BIOSIMULATIONS_API_ENDPOINT=DEFAULT_BIOSIMULATIONS_API_ENDPOINT,
BIOSIMULATIONS_API_AUTH_ENDPOINT=DEFAULT_BIOSIMULATIONS_API_AUTH_ENDPOINT,
BIOSIMULATIONS_API_AUDIENCE=DEFAULT_BIOSIMULATIONS_API_AUDIENCE,
VERBOSE=False,
DEBUG=False):
"""
Expand Down Expand Up @@ -121,7 +127,9 @@ def __init__(self,
LOG (:obj:`bool`, optional): whether to log the execution of a COMBINE/OMEX archive
LOG_PATH (:obj:`str`, optional): path to save the execution status of a COMBINE/OMEX archive
BIOSIMULATORS_API_ENDPOINT (:obj:`str`, optional): URL for BioSimulators API
RUNBIOSIMULATIONS_API_ENDPOINT (:obj:`str`, optional): URL for runBioSimulations API
BIOSIMULATIONS_API_ENDPOINT (:obj:`str`, optional): URL for runBioSimulations API
BIOSIMULATIONS_API_AUTH_ENDPOINT (:obj:`str`, optional): authorization endpoint for the BioSimulations API
BIOSIMULATIONS_API_AUDIENCE (:obj:`str`, optional): audience for the BioSimulations API
VERBOSE (:obj:`bool`, optional): whether to display the detailed output of the execution of each task
DEBUG (:obj:`bool`, optional): whether to raise exceptions rather than capturing them
"""
Expand Down Expand Up @@ -149,7 +157,9 @@ def __init__(self,
self.LOG = LOG
self.LOG_PATH = LOG_PATH
self.BIOSIMULATORS_API_ENDPOINT = BIOSIMULATORS_API_ENDPOINT
self.RUNBIOSIMULATIONS_API_ENDPOINT = RUNBIOSIMULATIONS_API_ENDPOINT
self.BIOSIMULATIONS_API_ENDPOINT = BIOSIMULATIONS_API_ENDPOINT
self.BIOSIMULATIONS_API_AUTH_ENDPOINT = BIOSIMULATIONS_API_AUTH_ENDPOINT
self.BIOSIMULATIONS_API_AUDIENCE = BIOSIMULATIONS_API_AUDIENCE
self.VERBOSE = VERBOSE
self.DEBUG = DEBUG

Expand Down Expand Up @@ -201,7 +211,9 @@ def get_config():
LOG=os.environ.get('LOG', '1').lower() in ['1', 'true'],
LOG_PATH=os.environ.get('LOG_PATH', DEFAULT_LOG_PATH),
BIOSIMULATORS_API_ENDPOINT=os.environ.get('BIOSIMULATORS_API_ENDPOINT', DEFAULT_BIOSIMULATORS_API_ENDPOINT),
RUNBIOSIMULATIONS_API_ENDPOINT=os.environ.get('RUNBIOSIMULATIONS_API_ENDPOINT', DEFAULT_RUNBIOSIMULATIONS_API_ENDPOINT),
BIOSIMULATIONS_API_ENDPOINT=os.environ.get('BIOSIMULATIONS_API_ENDPOINT', DEFAULT_BIOSIMULATIONS_API_ENDPOINT),
BIOSIMULATIONS_API_AUTH_ENDPOINT=os.environ.get('BIOSIMULATIONS_API_AUTH_ENDPOINT', DEFAULT_BIOSIMULATIONS_API_AUTH_ENDPOINT),
BIOSIMULATIONS_API_AUDIENCE=os.environ.get('BIOSIMULATIONS_API_AUDIENCE', DEFAULT_BIOSIMULATIONS_API_AUDIENCE),
VERBOSE=os.environ.get('VERBOSE', '1').lower() in ['1', 'true'],
DEBUG=os.environ.get('DEBUG', '0').lower() in ['1', 'true'],
)
Expand Down
4 changes: 2 additions & 2 deletions biosimulators_utils/simulator_registry/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ def get_simulator_version_specs(id):

try:
intro_failure_msg = "The specifications of the versions of `{}` could not be retrieved from the BioSimulators registry.".format(id)
validate_biosimulations_api_response(response, intro_failure_msg)
validate_biosimulations_api_response(response, intro_failure_msg, ValueError)
version_specs = response.json()
except requests.exceptions.HTTPError:
except ValueError:
if response.status_code != 404:
raise
version_specs = []
Expand Down
Loading

0 comments on commit 4a2095d

Please sign in to comment.