Skip to content
This repository was archived by the owner on May 5, 2020. It is now read-only.
Open
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
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ ignore-comments=yes
ignore-docstrings=yes

# Ignore imports when computing similarities.
ignore-imports=no
ignore-imports=yes


[TYPECHECK]
Expand Down
6 changes: 6 additions & 0 deletions metagenscope_cli/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
"""MetaGenScope CLI."""

import click
import click_log

from metagenscope_cli.extensions import logger

from .auth_cli import register, login, status
from .get_cli import get
from .run_cli import run
from .upload_cli import upload


click_log.basic_config(logger)


@click.group()
def main():
"""Use to interact with the MetaGenScope web platform."""
Expand Down
26 changes: 17 additions & 9 deletions metagenscope_cli/cli/auth_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,37 @@

import os
import click
import click_log
from requests.exceptions import HTTPError

from metagenscope_cli.extensions import logger
from metagenscope_cli.network.authenticator import Authenticator
from metagenscope_cli.config import config

from .utils import add_authorization


def handle_auth_request(request_generator):
def handle_auth_request(request_generator, save_token_silently):
"""Perform common authentication request functions."""
try:
jwt_token = request_generator()
click.echo(f'JWT Token: {jwt_token}')
logger.info(f'JWT Token: {jwt_token}')

if click.confirm('Store token for future use (overwrites existing)?'):
save_message = 'Store token for future use (overwrites existing)?'
if save_token_silently or click.confirm(save_message):
config.set_token(jwt_token)
except HTTPError as http_error:
click.echo(f'There was an error with registration: {http_error}', err=True)
logger.error(f'There was an error with registration: {http_error}')


@click.command()
@click_log.simple_verbosity_option(logger)
@click.option('-h', '--host', default=None)
@click.option('-y', '--save-token-silently', default=False)
@click.argument('username')
@click.argument('user_email')
@click.argument('password')
def register(host, username, user_email, password):
def register(host, save_token_silently, username, user_email, password):
"""Register as a new MetaGenScope user."""
if host is None:
host = os.environ['MGS_HOST']
Expand All @@ -37,14 +42,16 @@ def request_generator():
"""Generate registration auth request."""
return authenticator.register(username, user_email, password)

handle_auth_request(request_generator)
handle_auth_request(request_generator, save_token_silently)


@click.command()
@click_log.simple_verbosity_option(logger)
@click.option('-h', '--host', default=None)
@click.option('-y', '--save-token-silently', default=False)
@click.argument('user_email')
@click.argument('password')
def login(host, user_email, password):
def login(host, save_token_silently, user_email, password):
"""Authenticate as an existing MetaGenScope user."""
if host is None:
host = os.environ['MGS_HOST']
Expand All @@ -54,12 +61,13 @@ def request_generator():
"""Generate registration auth request."""
return authenticator.login(user_email, password)

handle_auth_request(request_generator)
handle_auth_request(request_generator, save_token_silently)


@click.command()
@click_log.simple_verbosity_option(logger)
@add_authorization()
def status(uploader):
"""Get user status."""
response = uploader.knex.get('/api/v1/auth/status')
click.echo(response)
logger.info(response)
7 changes: 6 additions & 1 deletion metagenscope_cli/cli/get_cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
"""CLI to get data from a MetaGenScope Server."""

import click
import click_log

from metagenscope_cli.extensions import logger

from .utils import add_authorization

Expand All @@ -19,10 +22,11 @@ def uuids():

def report_uuid(name, uuid):
"""Report a uuid to the user."""
click.echo(f'{name}\t{uuid}')
logger.info(f'{name}\t{uuid}')


@uuids.command(name='samples')
@click_log.simple_verbosity_option(logger)
@add_authorization()
@click.argument('sample_names', nargs=-1)
def sample_uuids(uploader, sample_names):
Expand All @@ -34,6 +38,7 @@ def sample_uuids(uploader, sample_names):


@uuids.command(name='groups')
@click_log.simple_verbosity_option(logger)
@add_authorization()
@click.argument('sample_group_names', nargs=-1)
def sample_group_uuids(uploader, sample_group_names):
Expand Down
12 changes: 8 additions & 4 deletions metagenscope_cli/cli/run_cli.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
"""CLI to run commands on MGS server."""

from sys import stderr
import click
import click_log

from metagenscope_cli.extensions import logger

from .utils import add_authorization

Expand All @@ -19,21 +21,23 @@ def middleware():


@middleware.command(name='group')
@click_log.simple_verbosity_option(logger)
@add_authorization()
@click.argument('group_uuid')
def group_middleware(uploader, group_uuid):
"""Run middleware for a group."""
response = uploader.knex.post(f'/api/v1/sample_groups/{group_uuid}/middleware', {})
click.echo(response)
logger.info(response)


@middleware.command(name='sample')
@click_log.simple_verbosity_option(logger)
@add_authorization()
@click.argument('sample_name')
def sample_middleware(uploader, sample_name):
"""Run middleware for a sample."""
response = uploader.knex.get(f'/api/v1/samples/getid/{sample_name}')
sample_uuid = response['data']['sample_uuid']
print(f'{sample_name} :: {sample_uuid}', file=stderr)
logger.info(f'{sample_name} :: {sample_uuid}')
response = uploader.knex.post(f'/api/v1/samples/{sample_uuid}/middleware', {})
click.echo(response)
logger.info(response)
10 changes: 7 additions & 3 deletions metagenscope_cli/cli/upload_cli.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""CLI to upload data to a MetaGenScope Server."""

from sys import stderr
import click
import click_log

from metagenscope_cli.extensions import logger
from metagenscope_cli.sample_sources.data_super_source import DataSuperSource
from metagenscope_cli.sample_sources.file_source import FileSource

Expand All @@ -16,6 +17,7 @@ def upload():


@upload.command()
@click_log.simple_verbosity_option(logger)
@add_authorization()
@click.argument('metadata_csv')
@click.argument('sample_names', nargs=-1)
Expand All @@ -29,12 +31,13 @@ def metadata(uploader, metadata_csv, sample_names):
}
try:
response = uploader.knex.post('/api/v1/samples/metadata', payload)
click.echo(response)
logger.info(response)
except Exception: # pylint:disable=broad-except
print(f'[upload-metadata-error] {sample_name}', file=stderr)
logger.error(f'[upload-metadata-error] {sample_name}')


@upload.command()
@click_log.simple_verbosity_option(logger)
@add_authorization()
@click.option('-g', '--group', default=None)
@click.option('--group-name', default=None)
Expand All @@ -47,6 +50,7 @@ def datasuper(uploader, group, group_name):


@upload.command()
@click_log.simple_verbosity_option(logger)
@add_authorization()
@click.option('-g', '--group', default=None)
@click.argument('result_files', nargs=-1)
Expand Down
29 changes: 14 additions & 15 deletions metagenscope_cli/cli/utils.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
"""Utilities for MetaGenScope CLI."""

import os
from sys import stderr
from datetime import datetime
from functools import wraps

import click
from requests.exceptions import HTTPError

from metagenscope_cli.extensions import logger
from metagenscope_cli.network import Knex, Uploader
from metagenscope_cli.network.token_auth import TokenAuth
from metagenscope_cli.tools.parse_metadata import parse_metadata_from_csv
Expand All @@ -22,10 +22,10 @@ def parse_metadata(filename, sample_names):

def warn_missing_auth():
"""Warn user of missing authentication."""
click.echo('No authenication means provided!', err=True)
click.echo('You must provide an authentication means either by passing '
'--auth-token or by persisting a login token to your local '
'MetaGenScope configuration file (see metagenscope login help).')
logger.error('No authenication means provided!')
logger.error('You must provide an authentication means either by passing '
'--auth-token or by persisting a login token to your local '
'MetaGenScope configuration file (see metagenscope login help).')


def batch_upload(uploader, samples, group_uuid=None, upload_group_name=None):
Expand All @@ -35,29 +35,28 @@ def batch_upload(uploader, samples, group_uuid=None, upload_group_name=None):
if upload_group_name is None:
upload_group_name = f'upload_group_{current_time}'
group_uuid = uploader.create_sample_group(upload_group_name)
click.echo(f'group created: <name: \'{upload_group_name}\' UUID: \'{group_uuid}\'>')
logger.info(f'group created: <name: \'{upload_group_name}\' UUID: \'{group_uuid}\'>')

try:
results = uploader.upload_all_results(group_uuid, samples)
except HTTPError as error:
click.echo('Could not create Sample', err=True)
click.echo(error, err=True)
logger.error('Could not create Sample')
logger.error(error)

if results:
click.echo('Upload results:')
logger.info('Upload results:')
for result in results:
sample_uuid = result['sample_uuid']
sample_name = result['sample_name']
result_type = result['result_type']

if result['type'] == 'error':
exception = result['exception']
click.secho(f' - {sample_name} ({sample_uuid}): {result_type}',
fg='red', err=True)
click.secho(f' {exception}', fg='red', err=True)
logger.error(f' - {sample_name} ({sample_uuid}): {result_type}')
logger.error(f' {exception}')
else:
click.secho(f' - {sample_name} ({sample_uuid}): {result_type}', fg='green')
click.echo(f'group info: <name: \'{upload_group_name}\' UUID: \'{group_uuid}\'>')
logger.info(f' - {sample_name} ({sample_uuid}): {result_type}')
logger.info(f'group info: <name: \'{upload_group_name}\' UUID: \'{group_uuid}\'>')


def add_authorization():
Expand All @@ -78,7 +77,7 @@ def wrapper(host, auth_token, *args, **kwargs):
try:
host = os.environ['MGS_HOST']
except KeyError:
print('No host. Exiting', file=stderr)
logger.error('No host. Exiting')
exit(1)

knex = Knex(token_auth=auth, host=host)
Expand Down
6 changes: 6 additions & 0 deletions metagenscope_cli/extensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""Extensions for python-metagenscope."""

import logging


logger = logging.getLogger(__name__) # pylint:disable=invalid-name
5 changes: 3 additions & 2 deletions metagenscope_cli/network/knex.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""Knex wraps MetaGenScope requests requiring authentication."""

from sys import stderr
import requests

from metagenscope_cli.constants import DEFAULT_HOST
from metagenscope_cli.extensions import logger


class Knex(object):
Expand Down Expand Up @@ -31,7 +32,7 @@ def post(self, endpoint, payload):
else:
response = requests.post(url, headers=self.headers, auth=self.auth)
if response.status_code >= 400:
print(response.content, file=stderr)
logger.error(response.content)
response.raise_for_status()
return response.json()

Expand Down
9 changes: 5 additions & 4 deletions metagenscope_cli/network/uploader.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

from datetime import datetime
from concurrent.futures import ThreadPoolExecutor
from sys import stderr

from requests.exceptions import HTTPError

from metagenscope_cli.extensions import logger


class Uploader:
"""Uploader class handles uploading samples to a server."""
Expand Down Expand Up @@ -51,8 +52,8 @@ def try_upload():
"""Attempt an upload, return the result."""
date_now = datetime.now()
try:
print(f'[uploader {date_now}] uploading {sample_name} :: {result_type}',
file=stderr)
message = f'[uploader {date_now}] uploading {sample_name} :: {result_type}'
logger.info(message)
self.upload_sample_result(sample_uuid, result_type, data, dryrun=dryrun)
except Exception as exception: # pylint:disable=broad-except
result['type'] = 'error'
Expand All @@ -65,7 +66,7 @@ def upload_all_results(self, group_uuid, samples, dryrun=True):
executor = ThreadPoolExecutor(max_workers=5)
results = []
for sample_name, tool_results in samples.items():
print(f'[uploader {datetime.now()}] creating sample {sample_name}', file=stderr)
logger.info(f'[uploader {datetime.now()}] creating sample {sample_name}')
sample_uuid = self.create_sample(sample_name, group_uuid)
futures = []
for tool_result in tool_results:
Expand Down
6 changes: 3 additions & 3 deletions metagenscope_cli/sample_sources/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Sources for sample data."""

from sys import stderr
from metagenscope_cli.extensions import logger
from metagenscope_cli.tools.parsers import parse, UnparsableError


Expand Down Expand Up @@ -35,10 +35,10 @@ def get_sample_payloads(self):
try:
data = parse(result_type, files_dict)
except UnparsableError:
print(f'[parse-error] could not parse {result_type}', file=stderr)
logger.error(f'[parse-error] could not parse {result_type}')
continue
except KeyError:
print(f'[key-error] {sample_name} :: {result_type}', file=stderr)
logger.error(f'[key-error] {sample_name} :: {result_type}')

result_payload = {
'result_type': result_type,
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

dependencies = [
'click',
'click-log==0.2.1',
'requests',
'configparser',
'pandas',
Expand Down