Skip to content

Adds missing bits #1960

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions qiita_db/artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,57 @@ def types():
qdb.sql_connection.TRN.add(sql)
return qdb.sql_connection.TRN.execute_fetchindex()

@staticmethod
def create_type(name, description, can_be_submitted_to_ebi,
can_be_submitted_to_vamps, filepath_types):
"""Creates a new artifact type in the system

Parameters
----------
name : str
The artifact type name
description : str
The artifact type description
can_be_submitted_to_ebi : bool
Whether the artifact type can be submitted to EBI or not
can_be_submitted_to_vamps : bool
Whether the artifact type can be submitted to VAMPS or not
filepath_types : list of (str, bool)
The list filepath types that the new artifact type supports, and
if they're required or not in an artifact instance of this type

Raises
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the only type of unacceptable artifact a duplicate one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is creating a new artifact type (not a new artifact) and I couldn't think in any other case where a new type is unacceptable.

------
qiita_db.exceptions.QiitaDBDuplicateError
If an artifact type with the same name already exists
"""
with qdb.sql_connection.TRN:
sql = """SELECT EXISTS(
SELECT *
FROM qiita.artifact_type
WHERE artifact_type=%s)"""
qdb.sql_connection.TRN.add(sql, [name])
if qdb.sql_connection.TRN.execute_fetchlast():
raise qdb.exceptions.QiitaDBDuplicateError(
'artifact type', 'name: %s' % name)
sql = """INSERT INTO qiita.artifact_type
(artifact_type, description, can_be_submitted_to_ebi,
can_be_submitted_to_vamps)
VALUES (%s, %s, %s, %s)
RETURNING artifact_type_id"""
qdb.sql_connection.TRN.add(
sql, [name, description, can_be_submitted_to_ebi,
can_be_submitted_to_vamps])
at_id = qdb.sql_connection.TRN.execute_fetchlast()
sql = """INSERT INTO qiita.artifact_type_filepath_type
(artifact_type_id, filepath_type_id, required)
VALUES (%s, %s, %s)"""
sql_args = [
[at_id, qdb.util.convert_to_id(fpt, 'filepath_type'), req]
for fpt, req in filepath_types]
qdb.sql_connection.TRN.add(sql, sql_args, many=True)
qdb.sql_connection.TRN.execute()

@classmethod
def copy(cls, artifact, prep_template):
"""Creates a copy of `artifact` and attaches it to `prep_template`
Expand Down
39 changes: 39 additions & 0 deletions qiita_db/handlers/artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,42 @@ def post(self):
filepaths, artifact_type, name=name, prep_template=prep_template)

self.write({'artifact': a.id})


class ArtifactTypeHandler(OauthBaseHandler):
@authenticate_oauth
def post(self):
"""Creates a new artifact type

Parameters
----------
name : str
The artifact type name
description : str
The artifact type description
can_be_submitted_to_ebi : bool
Whether the artifact type can be submitted to EBI or not
can_be_submitted_to_vamps : bool
Whether the artifact type can be submitted to VAMPS or not
filepath_types : list of (str, bool)
The list filepath types that the new artifact type supports, and
if they're required or not in an artifact instance of this type

Raises
------
HTTPError
If the artifact type already exists, with error code 400
"""
a_type = self.get_argument('type_name')
a_desc = self.get_argument('description')
ebi = self.get_argument('can_be_submitted_to_ebi')
vamps = self.get_argument('can_be_submitted_to_vamps')
fp_types = loads(self.get_argument('filepath_types'))

try:
qdb.artifact.Artifact.create_type(a_type, a_desc, ebi, vamps,
fp_types)
except qdb.exceptions.QiitaDBDuplicateError as e:
raise HTTPError(400, str(e))

self.finish()
46 changes: 42 additions & 4 deletions qiita_db/handlers/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
# -----------------------------------------------------------------------------

from json import loads
from glob import glob
from os.path import join

from tornado.web import HTTPError

from .oauth2 import OauthBaseHandler, authenticate_oauth
from qiita_core.qiita_settings import qiita_config
import qiita_db as qdb


Expand Down Expand Up @@ -97,17 +100,20 @@ def post(self, name, version):
cmd_desc = self.get_argument('description')
req_params = loads(self.get_argument('required_parameters'))
opt_params = loads(self.get_argument('optional_parameters'))
outputs = self.get_argument('outputs', None)
if outputs:
outputs = loads(outputs)
dflt_param_set = loads(self.get_argument('default_parameter_sets'))

parameters = req_params
parameters.update(opt_params)

cmd = qdb.software.Command.create(
plugin, cmd_name, cmd_desc, parameters)
plugin, cmd_name, cmd_desc, parameters, outputs)

# params = opt_params
for name, vals in dflt_param_set.items():
qdb.software.DefaultParameters.create(name, cmd, **vals)
if dflt_param_set is not None:
for name, vals in dflt_param_set.items():
qdb.software.DefaultParameters.create(name, cmd, **vals)

self.finish()

Expand Down Expand Up @@ -184,3 +190,35 @@ def get(self, plugin_name, plugin_version, cmd_name):
'default_parameter_sets': {
p.name: p.values for p in cmd.default_parameter_sets}}
self.write(response)


class CommandActivateHandler(OauthBaseHandler):
@authenticate_oauth
def post(self, plugin_name, plugin_version, cmd_name):
"""Activates the command

Parameters
----------
plugin_name : str
The plugin name
plugin_version : str
The plugin version
cmd_name : str
The command name
"""
with qdb.sql_connection.TRN:
cmd = _get_command(plugin_name, plugin_version, cmd_name)
cmd.activate()

self.finish()


class ReloadPluginAPItestHandler(OauthBaseHandler):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is missing a test, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this method idempotent? if not, should it be?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same question regarding CommandActivateHandler

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is idempotent as long as the files in qiita_config.plugin_dir do not change.
CommandActivateHandler is idempotent.

@authenticate_oauth
def post(self):
"""Reloads the plugins"""
conf_files = glob(join(qiita_config.plugin_dir, "*.conf"))
for fp in conf_files:
s = qdb.software.Software.from_file(fp, update=True)
s.activate()
self.finish()
9 changes: 5 additions & 4 deletions qiita_db/handlers/processing_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,14 @@ class ProcessingJobAPItestHandler(OauthBaseHandler):
@authenticate_oauth
def post(self):
user = self.get_argument('user', 'test@foo.bar')
cmd = self.get_argument('command')
s_name, s_version, cmd_name = loads(self.get_argument('command'))
params_dict = self.get_argument('parameters')
status = self.get_argument('status', None)

params = qdb.software.Parameters.load(
qdb.software.Command(cmd),
json_str=params_dict)
cmd = qdb.software.Software.from_name_and_version(
s_name, s_version).get_command(cmd_name)

params = qdb.software.Parameters.load(cmd, json_str=params_dict)

job = qdb.processing_job.ProcessingJob.create(
qdb.user.User(user), params)
Expand Down
23 changes: 23 additions & 0 deletions qiita_db/handlers/tests/test_artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,5 +191,28 @@ def test_post_error(self):
obs.body)


class ArtifactTypeHandlerTests(OauthTestingBase):
def test_post_no_header(self):
obs = self.post('/qiita_db/artifacts/types/', data={})
self.assertEqual(obs.code, 400)

def test_post(self):
data = {'type_name': 'new_type',
'description': 'some_description',
'can_be_submitted_to_ebi': False,
'can_be_submitted_to_vamps': False,
'filepath_types': dumps([("log", False),
("raw_forward_seqs", True)])}
obs = self.post('/qiita_db/artifacts/types/', headers=self.header,
data=data)
self.assertEqual(obs.code, 200)
self.assertIn(['new_type', 'some_description'],
qdb.artifact.Artifact.types())

obs = self.post('/qiita_db/artifacts/types/', headers=self.header,
data=data)
self.assertEqual(obs.code, 400)
self.assertIn('already exists', obs.body)

if __name__ == '__main__':
main()
33 changes: 33 additions & 0 deletions qiita_db/handlers/tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def test_post(self):
'optional_parameters': dumps({'param1': ['string', ''],
'param2': ['float', '1.5'],
'param3': ['boolean', 'True']}),
'outputs': dumps({'out1': 'BIOM'}),
'default_parameter_sets': dumps(
{'dflt1': {'param1': 'test',
'param2': '2.4',
Expand Down Expand Up @@ -164,5 +165,37 @@ def test_get(self):
self.assertEqual(loads(obs.body), exp)


class CommandActivateHandlerTests(OauthTestingBase):
def test_post_command_does_not_exist(self):
obs = self.post('/qiita_db/plugins/QIIME/1.9.1/commands/'
'UNKNOWN/activate/',
headers=self.header, data={})
self.assertEqual(obs.code, 404)

def test_post_no_header(self):
obs = self.post('/qiita_db/plugins/QIIME/1.9.1/commands/'
'Split%20libraries/activate/', data={})
self.assertEqual(obs.code, 400)

def test_post(self):
qdb.software.Software.deactivate_all()
self.assertFalse(qdb.software.Command(2).active)
obs = self.post('/qiita_db/plugins/QIIME/1.9.1/commands/'
'Split%20libraries/activate/', headers=self.header,
data={})
self.assertEqual(obs.code, 200)
self.assertTrue(qdb.software.Command(2).active)


class ReloadPluginAPItestHandlerTests(OauthTestingBase):
def test_post_no_header(self):
obs = self.post('/apitest/reload_plugins/', data={})
self.assertEqual(obs.code, 400)

def test_post(self):
obs = self.post('/apitest/reload_plugins/', headers=self.header,
data={})
self.assertEqual(obs.code, 200)

if __name__ == '__main__':
main()
4 changes: 2 additions & 2 deletions qiita_db/handlers/tests/test_processing_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ class ProcessingJobAPItestHandlerTests(OauthTestingBase):
def test_post_processing_job(self):
data = {
'user': 'demo@microbio.me',
'command': 3,
'command': dumps(['QIIME', '1.9.1', 'Pick closed-reference OTUs']),
'parameters': dumps({"reference": 1,
"sortmerna_e_value": 1,
"sortmerna_max_pos": 10000,
Expand All @@ -225,7 +225,7 @@ def test_post_processing_job(self):
def test_post_processing_job_status(self):
data = {
'user': 'demo@microbio.me',
'command': 3,
'command': dumps(['QIIME', '1.9.1', 'Pick closed-reference OTUs']),
'status': 'running',
'parameters': dumps({"reference": 1,
"sortmerna_e_value": 1,
Expand Down
45 changes: 43 additions & 2 deletions qiita_db/software.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def exists(cls, software, name):
return qdb.sql_connection.TRN.execute_fetchlast()

@classmethod
def create(cls, software, name, description, parameters):
def create(cls, software, name, description, parameters, outputs=None):
r"""Creates a new command in the system

The supported types for the parameters are:
Expand Down Expand Up @@ -175,6 +175,9 @@ def create(cls, software, name, description, parameters):
format is: {parameter_name: (parameter_type, default)},
where parameter_name, parameter_type and default are strings. If
default is None.
outputs : dict, optional
The description of the outputs that this command generated. The
format is: {output_name: artifact_type}

Returns
-------
Expand Down Expand Up @@ -216,7 +219,7 @@ def create(cls, software, name, description, parameters):
ptype, dflt = vals
# Check that the type is one of the supported types
supported_types = ['string', 'integer', 'float', 'reference',
'boolean']
'boolean', 'prep_template']
if ptype not in supported_types and not ptype.startswith(
('choice', 'artifact')):
supported_types.extend(['choice', 'artifact'])
Expand Down Expand Up @@ -281,6 +284,17 @@ def create(cls, software, name, description, parameters):
for at in atypes]
qdb.sql_connection.TRN.add(sql_type, sql_params, many=True)

# Add the outputs to the command
if outputs:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just want to confirm that now there are no tests without output. I think is fine due to how it work but want to double check it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

sql = """INSERT INTO qiita.command_output
(name, command_id, artifact_type_id)
VALUES (%s, %s, %s)"""
sql_args = [
[pname, c_id, qdb.util.convert_to_id(at, 'artifact_type')]
for pname, at in outputs.items()]
qdb.sql_connection.TRN.add(sql, sql_args, many=True)
qdb.sql_connection.TRN.execute()

return cls(c_id)

@property
Expand Down Expand Up @@ -425,6 +439,31 @@ def outputs(self):
qdb.sql_connection.TRN.add(sql, [self.id])
return qdb.sql_connection.TRN.execute_fetchindex()

@property
def active(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't have an actual tests, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested it through the function test_activate so it is implicitly tested.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

K

"""Returns if the command is active or not

Returns
-------
bool
Whether the command is active or not
"""
with qdb.sql_connection.TRN:
sql = """SELECT active
FROM qiita.software_command
WHERE command_id = %s"""
qdb.sql_connection.TRN.add(sql, [self.id])
return qdb.sql_connection.TRN.execute_fetchlast()

def activate(self):
"""Activates the command"""
with qdb.sql_connection.TRN:
sql = """UPDATE qiita.software_command
SET active = %s
WHERE command_id = %s"""
qdb.sql_connection.TRN.add(sql, [True, self.id])
return qdb.sql_connection.TRN.execute()


class Software(qdb.base.QiitaObject):
r"""A software package available in the system
Expand Down Expand Up @@ -456,6 +495,8 @@ def deactivate_all(cls):
with qdb.sql_connection.TRN:
sql = "UPDATE qiita.software SET active = False"
qdb.sql_connection.TRN.add(sql)
sql = "UPDATE qiita.software_command SET active = False"
qdb.sql_connection.TRN.add(sql)
qdb.sql_connection.TRN.execute()

@classmethod
Expand Down
Loading