<commit_before>#!/usr/bin/env python
from optparse import OptionParser
import collections
import functools
import pdb
import sys

import numpy as np
import pandas as pd
import zarr

from google.cloud import bigquery

import dash
import dash.dependencies as dd
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dt
import plotly.graph_objs as go

'''
basenji_fetch_app.py

Run a Dash app to enable SAD queries.
'''

################################################################################
# main
################################################################################
def main():
    usage = 'usage: %prog [options] <sad_zarr_file>'
    parser = OptionParser(usage)
    # parser.add_option('--ld', dest='ld_query', default=False, action='store_true')
    (options,args) = parser.parse_args()

    if len(args) != 1:
        parser.error('Must provide SAD zarr')
    else:
        sad_zarr_file = args[0]

    #############################################
    # precursors

    sad_zarr_in = zarr.open_group(sad_zarr_file, 'r')

    # hash SNP ids to indexes
    snps = np.array(sad_zarr_in['snp'])
    snp_indexes = {}
    for i, snp_id in enumerate(snps):
        snp_indexes[snp_id] = i

    # easy access to target information
    target_ids = np.array(sad_zarr_in['target_ids'])
    target_labels = np.array(sad_zarr_in['target_labels'])

    # read SAD percentile indexes into memory
    sad_pct = np.array(sad_zarr_in['SAD_pct'])

    # initialize BigQuery client
    client = bigquery.Client('seqnn-170614')

    #############################################
    # layout

    app = dash.Dash()
    app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})

    app.layout = html.Div([
        html.Div([
            html.H1('Basenji SNP activity difference'),

            dcc.Markdown('Instructions...'),

            html.Div([
                html.Label('Datasets'),
                dcc.Dropdown(
                    id='dataset',
                    options=[
                        {'label':'CAGE', 'value':'CAGE'},
                        {'label':'DNase', 'value':'DNASE'},
                        {'label':'H3K4me3', 'value':'HISTONE:H3K4me3'},
                        {'label':'All', 'value':'All'}
                    ],
                    value='CAGE'
                )
            ], style={'width': '250', 'display': 'inline-block'}),

            html.Div([
                html.Label('Population'),
                dcc.Dropdown(
                    id='population',
                    options=[
                        {'label':'-', 'value':'-'},
                        {'label':'1kG African', 'value':'AFR'},
                        {'label':'1kG American', 'value':'AMR'},
                        {'label':'1kG East Asian', 'value':'EAS'},
                        {'label':'1kG European', 'value':'EUR'},
                        {'label':'1kG South Asian', 'value':'SAS'}
                    ],
                    value='-'
                )
            ], style={'width': '250', 'display': 'inline-block'}),

            html.Div([
                html.Label('SNP ID'),
                dcc.Input(id='snp_id', value='rs2157719', type='text'),
                html.Button(id='snp_submit', n_clicks=0, children='Submit')
            ], style={'display': 'inline-block', 'float': 'right'})

        ], style={
            'borderBottom': 'thin lightgrey solid',
            'backgroundColor': 'rgb(250, 250, 250)',
            'padding': '10px 5px'
        }),

        dcc.Graph(id='assoc_plot'),

        html.Div([
            dt.DataTable(
                id='table',
                rows=[],
                columns=['SNP', 'Association', 'Score', 'ScoreQ', 'R2', 'Experiment', 'Description'],
                column_widths=[150, 125, 125, 125, 125, 200],
                editable=False,
                filterable=True,
                sortable=True,
                resizable=True,
                sortColumn='Association',
                row_selectable=True,
                selected_row_indices=[],
                max_rows_in_viewport=20
            )
        ])
    ])

    #############################################
    # callback helpers

    @memoized
    def query_ld(snp_id, population):
        bq_path = 'genomics-public-data.linkage_disequilibrium_1000G_phase_3'

        # construct query
        query = 'SELECT tname, corr'
        query += ' FROM `%s.super_pop_%s`' % (bq_path,population)
        query += ' WHERE qname = "%s"' % snp_id

        # run query
        print('Running a BigQuery!', file=sys.stderr)
        query_results = client.query(query)

        return query_results

    @memoized
    def read_sad(snp_i):
        print('Reading SAD!', file=sys.stderr)

        # read SAD
        snp_sad = sad_zarr_in['SAD'][snp_i,:].astype('float64')

        # compute percentile indexes
        snp_sadq = []
        for ti in range(len(snp_sad)):
            snp_sadq.append(int(np.searchsorted(sad_pct[ti], snp_sad[ti])))

        return snp_sad, snp_sadq

    def snp_rows(snp_id, dataset, ld_r2=1.):
        rows = []

        percentiles = np.around(sad_zarr_in['percentiles'], 3)
        percentiles = np.append(percentiles, percentiles[-1])

        # search for SNP
        if snp_id in snp_indexes:
            snp_i = snp_indexes[snp_id]

            # SAD
            snp_sad, snp_sadq = read_sad(snp_i)

            # round floats
            snp_sad = np.around(snp_sad,4)
            snp_assoc = np.around(snp_sad*ld_r2, 4)
            ld_r2_round = np.around(ld_r2, 4)

            # extract target scores and info
            for ti, tid in enumerate(target_ids):
                if dataset == 'All' or target_labels[ti].startswith(dataset):
                    rows.append({
                        'SNP': snp_id,
                        'Association': snp_assoc[ti],
                        'Score': snp_sad[ti],
                        'ScoreQ': percentiles[snp_sadq[ti]],
                        'R2': ld_r2_round,
                        'Experiment': tid,
                        'Description': target_labels[ti]})

        return rows

    def make_data_mask(dataset):
        dataset_mask = []
        for ti, tid in enumerate(target_ids):
            if dataset == 'All':
                dataset_mask.append(True)
            else:
                dataset_mask.append(target_labels[ti].startswith(dataset))
        return np.array(dataset_mask, dtype='bool')

    def snp_scores(snp_id, dataset, ld_r2=1.):
        dataset_mask = make_data_mask(dataset)

        scores = np.zeros(dataset_mask.sum(), dtype='float64')

        # search for SNP
        if snp_id in snp_indexes:
            snp_i = snp_indexes[snp_id]

            # read SAD
            snp_sad, _ = read_sad(snp_i)

            # filter datasets
            snp_sad = snp_sad[dataset_mask]

            # add
            scores += snp_sad*ld_r2

        return scores

    #############################################
    # callbacks

    @app.callback(
        dd.Output('table', 'rows'),
        [dd.Input('snp_submit', 'n_clicks')],
        [
            dd.State('snp_id','value'),
            dd.State('dataset','value'),
            dd.State('population','value')
        ]
    )
    def update_table(n_clicks, snp_id, dataset, population):
        print('Tabling')

        # add snp_id rows
        rows = snp_rows(snp_id, dataset)

        if population != '-':
            query_results = query_ld(snp_id, population)

            for ld_snp, ld_corr in query_results:
                rows += snp_rows(ld_snp, dataset, ld_corr)

        return rows

    @app.callback(
        dd.Output('assoc_plot', 'figure'),
        [dd.Input('snp_submit', 'n_clicks')],
        [
            dd.State('snp_id','value'),
            dd.State('dataset','value'),
            dd.State('population','value')
        ]
    )
    def update_plot(n_clicks, snp_id, dataset, population):
        print('Plotting')

        target_mask = make_data_mask(dataset)

        # add snp_id rows
        query_scores = snp_scores(snp_id, dataset)

        if population != '-':
            query_results = query_ld(snp_id, population)

            for ld_snp, ld_corr in query_results:
                query_scores += snp_scores(ld_snp, dataset, ld_corr)

        # sort
        sorted_indexes = np.argsort(query_scores)

        # range
        ymax = np.abs(query_scores).max()
        ymax *= 1.2

        return {
            'data': [go.Scatter(
                x=np.arange(len(query_scores)),
                y=query_scores[sorted_indexes],
                text=target_ids[target_mask][sorted_indexes],
                mode='markers'
            )],
            'layout': {
                'height': 400,
                'margin': {'l': 20, 'b': 30, 'r': 10, 't': 10},
                'yaxis': {'range': [-ymax,ymax]},
                'xaxis': {'range': [-1,1+len(query_scores)]}
            }
        }

    #############################################
    # run

    app.scripts.config.serve_locally = True
    app.run_server(debug=True)

class memoized(object):
    '''Decorator. Caches a function's return value each time it is called.
    If called later with the same arguments, the cached value is returned
    (not reevaluated).
    '''
    def __init__(self, func):
        self.func = func
        self.cache = {}
    def __call__(self, *args):
        if not isinstance(args, collections.Hashable):
            # uncacheable. a list, for instance.
            # better to not cache than blow up.
            return self.func(*args)
        if args in self.cache:
            return self.cache[args]
        else:
            value = self.func(*args)
            self.cache[args] = value
            return value
    def __repr__(self):
        '''Return the function's docstring.'''
        return self.func.__doc__
    def __get__(self, obj, objtype):
        '''Support instance methods.'''
        return functools.partial(self.__call__, obj)

################################################################################
# __main__
################################################################################
if __name__ == '__main__':
    main()
<commit_msg>comments and verbose ifs<commit_after>#!/usr/bin/env python
from optparse import OptionParser
import collections
import functools
import pdb
import sys

import numpy as np
import pandas as pd
import zarr

from google.cloud import bigquery

import dash
import dash.dependencies as dd
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dt
import plotly.graph_objs as go

'''
basenji_fetch_app.py

Run a Dash app to enable SAD queries.
'''

################################################################################
# main
################################################################################
def main():
    usage = 'usage: %prog [options] <sad_zarr_file>'
    parser = OptionParser(usage)
    parser.add_option('-c', dest='chrom_zarrs', defaut=False, action='store_true', help='Zarr files split by chromosome [Default: %default]')
    parser.add_option('--ld', dest='ld_query', default=False, action='store_true')
    (options,args) = parser.parse_args()

    if len(args) != 1:
        parser.error('Must provide SAD zarr')
    else:
        sad_zarr_file = args[0]

    #############################################
    # precursors

    sad_zarr_in = zarr.open_group(sad_zarr_file, 'r')

    # hash SNP ids to indexes
    snps = np.array(sad_zarr_in['snp'])
    snp_indexes = {}
    for i, snp_id in enumerate(snps):
        snp_indexes[snp_id] = i

    # easy access to target information
    target_ids = np.array(sad_zarr_in['target_ids'])
    target_labels = np.array(sad_zarr_in['target_labels'])

    # read SAD percentile indexes into memory
    sad_pct = np.array(sad_zarr_in['SAD_pct'])

    # initialize BigQuery client
    client = bigquery.Client('seqnn-170614')

    #############################################
    # layout

    app = dash.Dash()
    app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})

    app.layout = html.Div([
        html.Div([
            html.H1('Basenji SNP activity difference'),

            dcc.Markdown('Instructions...'),

            html.Div([
                html.Label('Datasets'),
                dcc.Dropdown(
                    id='dataset',
                    options=[
                        {'label':'CAGE', 'value':'CAGE'},
                        {'label':'DNase', 'value':'DNASE'},
                        {'label':'H3K4me3', 'value':'HISTONE:H3K4me3'},
                        {'label':'All', 'value':'All'}
                    ],
                    value='CAGE'
                )
            ], style={'width': '250', 'display': 'inline-block'}),

            html.Div([
                html.Label('Population'),
                dcc.Dropdown(
                    id='population',
                    options=[
                        {'label':'-', 'value':'-'},
                        {'label':'1kG African', 'value':'AFR'},
                        {'label':'1kG American', 'value':'AMR'},
                        {'label':'1kG East Asian', 'value':'EAS'},
                        {'label':'1kG European', 'value':'EUR'},
                        {'label':'1kG South Asian', 'value':'SAS'}
                    ],
                    value='-'
                )
            ], style={'width': '250', 'display': 'inline-block'}),

            html.Div([
                html.Label('SNP ID'),
                dcc.Input(id='snp_id', value='rs2157719', type='text'),
                html.Button(id='snp_submit', n_clicks=0, children='Submit')
            ], style={'display': 'inline-block', 'float': 'right'})

        ], style={
            'borderBottom': 'thin lightgrey solid',
            'backgroundColor': 'rgb(250, 250, 250)',
            'padding': '10px 5px'
        }),

        dcc.Graph(id='assoc_plot'),

        html.Div([
            dt.DataTable(
                id='table',
                rows=[],
                columns=['SNP', 'Association', 'Score', 'ScoreQ', 'R2', 'Experiment', 'Description'],
                column_widths=[150, 125, 125, 125, 125, 200],
                editable=False,
                filterable=True,
                sortable=True,
                resizable=True,
                sortColumn='Association',
                row_selectable=True,
                selected_row_indices=[],
                max_rows_in_viewport=20
            )
        ])
    ])

    #############################################
    # callback helpers

    @memoized
    def query_ld(snp_id, population):
        """Query Google Genomics 1000 Genomes LD table for the given SNP."""
        bq_path = 'genomics-public-data.linkage_disequilibrium_1000G_phase_3'

        # construct query
        query = 'SELECT tname, corr'
        query += ' FROM `%s.super_pop_%s`' % (bq_path,population)
        query += ' WHERE qname = "%s"' % snp_id

        # run query
        print('Running a BigQuery!', file=sys.stderr)
        query_results = client.query(query)

        return query_results

    @memoized
    def read_sad(snp_i, verbose=True):
        """Read SAD scores from Zarr for the given SNP index."""
        if verbose:
            print('Reading SAD!', file=sys.stderr)

        # read SAD
        snp_sad = sad_zarr_in['SAD'][snp_i,:].astype('float64')

        # compute percentile indexes
        snp_sadq = []
        for ti in range(len(snp_sad)):
            snp_sadq.append(int(np.searchsorted(sad_pct[ti], snp_sad[ti])))

        return snp_sad, snp_sadq

    def snp_rows(snp_id, dataset, ld_r2=1.):
        """Construct table rows for the given SNP id and its LD set
           in the given dataset."""
        rows = []

        percentiles = np.around(sad_zarr_in['percentiles'], 3)
        percentiles = np.append(percentiles, percentiles[-1])

        # search for SNP
        if snp_id in snp_indexes:
            snp_i = snp_indexes[snp_id]

            # SAD
            snp_sad, snp_sadq = read_sad(snp_i)

            # round floats
            snp_sad = np.around(snp_sad,4)
            snp_assoc = np.around(snp_sad*ld_r2, 4)
            ld_r2_round = np.around(ld_r2, 4)

            # extract target scores and info
            for ti, tid in enumerate(target_ids):
                if dataset == 'All' or target_labels[ti].startswith(dataset):
                    rows.append({
                        'SNP': snp_id,
                        'Association': snp_assoc[ti],
                        'Score': snp_sad[ti],
                        'ScoreQ': percentiles[snp_sadq[ti]],
                        'R2': ld_r2_round,
                        'Experiment': tid,
                        'Description': target_labels[ti]})

        return rows

    def make_data_mask(dataset):
        """Make a mask across targets for the given dataset."""
        dataset_mask = []
        for ti, tid in enumerate(target_ids):
            if dataset == 'All':
                dataset_mask.append(True)
            else:
                dataset_mask.append(target_labels[ti].startswith(dataset))
        return np.array(dataset_mask, dtype='bool')

    def snp_scores(snp_id, dataset, ld_r2=1.):
        """Compute an array of scores for this SNP
           in the specified dataset."""

        dataset_mask = make_data_mask(dataset)

        scores = np.zeros(dataset_mask.sum(), dtype='float64')

        # search for SNP
        if snp_id in snp_indexes:
            snp_i = snp_indexes[snp_id]

            # read SAD
            snp_sad, _ = read_sad(snp_i)

            # filter datasets
            snp_sad = snp_sad[dataset_mask]

            # add
            scores += snp_sad*ld_r2

        return scores

    #############################################
    # callbacks

    @app.callback(
        dd.Output('table', 'rows'),
        [dd.Input('snp_submit', 'n_clicks')],
        [
            dd.State('snp_id','value'),
            dd.State('dataset','value'),
            dd.State('population','value')
        ]
    )
    def update_table(n_clicks, snp_id, dataset, population, verbose=True):
        """Update the table with a new parameter set."""
        if verbose:
            print('Tabling')

        # add snp_id rows
        rows = snp_rows(snp_id, dataset)

        if population != '-':
            query_results = query_ld(snp_id, population)

            for ld_snp, ld_corr in query_results:
                rows += snp_rows(ld_snp, dataset, ld_corr)

        return rows

    @app.callback(
        dd.Output('assoc_plot', 'figure'),
        [dd.Input('snp_submit', 'n_clicks')],
        [
            dd.State('snp_id','value'),
            dd.State('dataset','value'),
            dd.State('population','value')
        ]
    )
    def update_plot(n_clicks, snp_id, dataset, population, verbose=True):
        if verbose:
            print('Plotting')

        target_mask = make_data_mask(dataset)

        # add snp_id rows
        query_scores = snp_scores(snp_id, dataset)

        if population != '-':
            query_results = query_ld(snp_id, population)

            for ld_snp, ld_corr in query_results:
                query_scores += snp_scores(ld_snp, dataset, ld_corr)

        # sort
        sorted_indexes = np.argsort(query_scores)

        # range
        ymax = np.abs(query_scores).max()
        ymax *= 1.2

        return {
            'data': [go.Scatter(
                x=np.arange(len(query_scores)),
                y=query_scores[sorted_indexes],
                text=target_ids[target_mask][sorted_indexes],
                mode='markers'
            )],
            'layout': {
                'height': 400,
                'margin': {'l': 20, 'b': 30, 'r': 10, 't': 10},
                'yaxis': {'range': [-ymax,ymax]},
                'xaxis': {'range': [-1,1+len(query_scores)]}
            }
        }

    #############################################
    # run

    app.scripts.config.serve_locally = True
    app.run_server(debug=True)

class memoized(object):
    '''Decorator. Caches a function's return value each time it is called.
    If called later with the same arguments, the cached value is returned
    (not reevaluated).
    '''
    def __init__(self, func):
        self.func = func
        self.cache = {}
    def __call__(self, *args):
        if not isinstance(args, collections.Hashable):
            # uncacheable. a list, for instance.
            # better to not cache than blow up.
            return self.func(*args)
        if args in self.cache:
            return self.cache[args]
        else:
            value = self.func(*args)
            self.cache[args] = value
            return value
    def __repr__(self):
        '''Return the function's docstring.'''
        return self.func.__doc__
    def __get__(self, obj, objtype):
        '''Support instance methods.'''
        return functools.partial(self.__call__, obj)

################################################################################
# __main__
################################################################################
if __name__ == '__main__':
    main()
<|endoftext|>


<commit_before>'''
LeoADCA
Little Leonardo Accelerometer Data Calibration Application

This app will launch an window in your default broweser to visually identify
the times at which various axis of the lleo tag have been placed into +/-g
orientations.

Enter the start and end times of these orientation periods, then click 'save'
to write those to a calibration YAML file (cal.yaml) in the data directory
'''

def timestamp_to_epoch(timestamps):
    '''Convert collection of timestamps to epoch time (nanoseconds)'''
    import pandas
    import numpy

    indexes = pandas.DatetimeIndex(timestamps)
    epochs  = indexes.astype(numpy.int64)

    return epochs

def epoch_to_timestamp(epoch):
    '''Convert a single epoch date to a pandas timestamp'''
    import pandas

    return pandas.to_datetime(epoch, unit='ns')

def date_string_nano(timestamp):
    '''Convert pandas timestamp to string format with nanosecond precision'''
    from datetime import datetime

    dt = epoch_to_timestamp(timestamp).to_datetime()
    s = dt.strftime('%Y-%m-%d %H:%M:%S')
    s += '.{:.5}'.format(str(timestamp)[-9:])

    return s

# TODO get rid of data_df from passed params
def plot_triaxial(data_df, height, width, tools):
    '''Plot pandas dataframe containing an x, y, and z column'''
    import bokeh.plotting

    p = bokeh.plotting.figure(plot_height=height, plot_width=width, title='',
                              toolbar_sticky=False, tools=tools, webgl=True)

    # Static plot of accelerometry data
    x_line = p.line(y='x', x='date', color='#1b9e77', legend='x', source=source)
    y_line = p.line(y='y', x='date', color='#d95f02', legend='y', source=source)
    z_line = p.line(y='z', x='date', color='#7570b3', legend='z', source=source)

    lines = [x_line, y_line, z_line]

    return p, lines

def select_data(acc, acc_slider):
    '''Get data selection from plot controls'''

    slider_dt = epoch_to_timestamp(acc_slider.value)

    data = acc[(acc['datetimes'] == slider_dt)]

    return data

def update(attrname, old, new):
    '''Update plots from selected data'''
    import numpy

    data_selected = select_data(acc, acc_slider)

    vline.set(location=acc_slider.value)

    for i in range(len(lines)):
        lines[i].visible = i in param_checkbox.active

    #source.data['timestep'][0] = acc_slider.value

        # The following can be used to filter/update data,
        # but the amount of data makes this very cpu heavy

        #timesteps = list(data_df['datetime'])
        #x = list(data_df['acc_x']),
        #y = list(data_df['acc_y']),
        #z = list(data_df['acc_z']),

    return None

def save_times():
    '''Save index from bokeh textinput'''
    import os

    from pylleo.pylleo import lleocal
    from pylleo.pylleo import yamlutils

    cal_yaml_path = os.path.join(data_path, 'cal.yaml')

    param = (param_select.value).lower().replace('-','_')
    bound = bound_select.value
    start = int(start_input.value)
    end   = int(end_input.value)

    t_now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    print(t_now, 'UPDATE CAL TIMES: {}, {}'.format(param, bound))

    cal_dict = lleocal.load(cal_yaml_path)
    cal_dict = lleocal.update(acc, cal_dict, param, bound, start, end)
    yamlutils.write_yaml(cal_dict, cal_yaml_path)

    return None

def save_poly():
    '''Perform polyfit once bounds selected'''
    import datetime

    from pylleo.pylleo import lleocal
    from pylleo.pylleo import yamlutils

    # TODO perhaps put check for bounds and message here
    cal_yaml_path = os.path.join(data_path, 'cal.yaml')
    cal_dict = lleocal.load(cal_yaml_path)

    param = (param_select.value).lower().replace('-','_')

    try:
        t_now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        print(t_now, 'SAVE POLY: {}'.format(param))

        lower, upper = lleocal.get_cal_data(acc, cal_dict, param)
        poly = list(lleocal.fit1d(lower, upper))
        poly = [float(str(i)) for i in poly]
        print(type(poly), len(poly), poly)

        cal_dict[param]['poly'] = poly
        yamlutils.write_yaml(cal_dict, cal_yaml_path)
    except:
        pass

    return None

# save state to calibration field
import os
import numpy
import sys
import subprocess

#from bokeh.layouts import layout
from bokeh.layouts import widgetbox
from bokeh.models import WidgetBox, HBox
from bokeh.models import Span, Label
from bokeh.models import PanTool, WheelZoomTool, BoxZoomTool, HoverTool
from bokeh.models import ColumnDataSource
#from bokeh.models.widgets import Tabs, Panel
from bokeh.models.widgets import Button
from bokeh.models.widgets import CheckboxButtonGroup
from bokeh.models.widgets import Slider, Select, TextInput
from bokeh.io import curdoc

from pylleo.pylleo import lleoio

# DATA
#------------------------------------------------------------------------------

# Setup Accelerometer data
args = sys.argv
sample_f = int(args[1])
data_path = args[2]

# TODO handle lleo mag, and other tags...
param_strs = ['Acceleration-X', 'Acceleration-Y', 'Acceleration-Z', 'Depth',
              'Propeller', 'Temperature']

meta = lleoio.read_meta(data_path, param_strs, n_header=10)
acc, depth, prop, temp = lleoio.read_data(meta, data_path, n_header=10,
                                          sample_f=sample_f)

# TODO make data output similar to dtag, remove this
# A = acc[acc.keys()[1:]].values.astype(float)

# Timestamps in epoch time and strings to nanosecond
dates = timestamp_to_epoch(acc['datetimes'])
#dates_str = [date_string_nano(d) for d in dates]

# Create Column Data Source that will be used by the plot
source = ColumnDataSource(data=dict(x    = list(acc['acceleration_x'].values),
                                    y    = list(acc['acceleration_y'].values),
                                    z    = list(acc['acceleration_z'].values),
                                    date = list(dates),))

# Input
#------------------------------------------------------------------------------

# TODO use callback with BoxSelectTool to get indices rather than TextInput
# http://stackoverflow.com/a/34175864/943773

# Create Input controls
t_min = min(dates)
t_max = max(dates)
acc_slider = Slider(title='Timestep', start=t_min, end=t_max, value=t_min, step=1)

# TODO generalize this for plotting the lines too
param_checkbox = CheckboxButtonGroup(labels=["x", "y", "z"], active=[0, 1, 2])

param_select = Select(title="Calibrate Param:", value=param_strs[0],
                      options=param_strs)

bound_select = Select(title="Bound:", value='lower',
                      options=['lower', 'upper'])

# User input start end times, save to cal
start_input = TextInput(value='0', title='start:')
end_input = TextInput(value='0', title='end:')

button_save = Button(label='Save Times', button_type='success')
button_save.on_click(save_times)

button_poly = Button(label='Perform Polyfit', button_type='success')
button_poly.on_click(save_poly)

controls = [acc_slider, param_checkbox, param_select, bound_select,
            start_input, end_input, button_save, button_poly]

# Plotting
#------------------------------------------------------------------------------

# Axis labels
axis_map = {'Time': 't',
            'Acceleration': 'acc',}

x_axis = Select(title='X Axis', options=sorted(axis_map.keys()), value='Time')
y_axis = Select(title='Y Axis', options=sorted(axis_map.keys()), value='Acceleration')

hover = HoverTool(tooltips=[('index', '$index'),
                            ('acc', '$y'),
                            ('time', '@date'),
                            ])

#'pan,wheel_zoom,box_zoom,reset,hover'
tools = [PanTool(), WheelZoomTool(), BoxZoomTool(), hover]
p, lines = plot_triaxial(acc, 300, 800, tools)

# Add line for current video time
vline = Span(location=0, dimension='height', line_color='red', line_width=3)
p.renderers.extend([vline,])

# Rendering
#------------------------------------------------------------------------------

for control in controls:
    control.on_change('value', update)

inputs = HBox(widgetbox(*controls), width=800)

# initial load of the data
update(None, None, None)

#TODO update to widget, hbox depreciated
curdoc().add_root(HBox(p, inputs, width=1100))
<commit_msg>working, fixed poly save, print statements<commit_after>'''
LeoADCA
Little Leonardo Accelerometer Data Calibration Application

This app will launch an window in your default broweser to visually identify
the times at which various axis of the lleo tag have been placed into +/-g
orientations.

Enter the start and end times of these orientation periods, then click 'save'
to write those to a calibration YAML file (cal.yaml) in the data directory
'''

def timestamp_to_epoch(timestamps):
    '''Convert collection of timestamps to epoch time (nanoseconds)'''
    import pandas
    import numpy

    indexes = pandas.DatetimeIndex(timestamps)
    epochs  = indexes.astype(numpy.int64)

    return epochs

def epoch_to_timestamp(epoch):
    '''Convert a single epoch date to a pandas timestamp'''
    import pandas

    return pandas.to_datetime(epoch, unit='ns')

def date_string_nano(timestamp):
    '''Convert pandas timestamp to string format with nanosecond precision'''
    from datetime import datetime

    dt = epoch_to_timestamp(timestamp).to_datetime()
    s = dt.strftime('%Y-%m-%d %H:%M:%S')
    s += '.{:.5}'.format(str(timestamp)[-9:])

    return s

# TODO get rid of data_df from passed params
def plot_triaxial(data_df, height, width, tools):
    '''Plot pandas dataframe containing an x, y, and z column'''
    import bokeh.plotting

    p = bokeh.plotting.figure(plot_height=height, plot_width=width, title='',
                              toolbar_sticky=False, tools=tools, webgl=True)

    # Static plot of accelerometry data
    x_line = p.line(y='x', x='date', color='#1b9e77', legend='x', source=source)
    y_line = p.line(y='y', x='date', color='#d95f02', legend='y', source=source)
    z_line = p.line(y='z', x='date', color='#7570b3', legend='z', source=source)

    lines = [x_line, y_line, z_line]

    return p, lines

def select_data(acc, acc_slider):
    '''Get data selection from plot controls'''

    slider_dt = epoch_to_timestamp(acc_slider.value)

    data = acc[(acc['datetimes'] == slider_dt)]

    return data

def update(attrname, old, new):
    '''Update plots from selected data'''
    import numpy

    data_selected = select_data(acc, acc_slider)

    vline.set(location=acc_slider.value)

    for i in range(len(lines)):
        lines[i].visible = i in param_checkbox.active

    #source.data['timestep'][0] = acc_slider.value

        # The following can be used to filter/update data,
        # but the amount of data makes this very cpu heavy

        #timesteps = list(data_df['datetime'])
        #x = list(data_df['acc_x']),
        #y = list(data_df['acc_y']),
        #z = list(data_df['acc_z']),

    return None

def save_times():
    '''Save index from bokeh textinput'''
    import datetime
    import os

    from pylleo.pylleo import lleocal
    from pylleo.pylleo import yamlutils

    cal_yaml_path = os.path.join(data_path, 'cal.yaml')

    param = (param_select.value).lower().replace('-','_')
    bound = bound_select.value
    start = int(start_input.value)
    end   = int(end_input.value)

    t_now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    print(t_now, 'UPDATE CAL TIMES: {}, {}'.format(param, bound))

    cal_dict = lleocal.load(cal_yaml_path)
    cal_dict = lleocal.update(acc, cal_dict, param, bound, start, end)
    yamlutils.write_yaml(cal_dict, cal_yaml_path)

    return None

def save_poly():
    '''Perform polyfit once bounds selected'''
    import datetime

    from pylleo.pylleo import lleocal
    from pylleo.pylleo import yamlutils

    # TODO perhaps put check for bounds and message here
    cal_yaml_path = os.path.join(data_path, 'cal.yaml')
    cal_dict = lleocal.load(cal_yaml_path)

    param = (param_select.value).lower().replace('-','_')

    try:
        t_now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        print(t_now, 'SAVE POLY: {}'.format(param))

        lower, upper = lleocal.get_cal_data(acc, cal_dict, param)
        poly = list(lleocal.fit1d(lower, upper))
        poly = [float(str(i)) for i in poly]

        cal_dict[param]['poly'] = poly
        yamlutils.write_yaml(cal_dict, cal_yaml_path)
    except:
        pass

    return None

# save state to calibration field
import os
import numpy
import sys
import subprocess

#from bokeh.layouts import layout
from bokeh.layouts import widgetbox
from bokeh.models import WidgetBox, HBox
from bokeh.models import Span, Label
from bokeh.models import PanTool, WheelZoomTool, BoxZoomTool, HoverTool
from bokeh.models import ColumnDataSource
#from bokeh.models.widgets import Tabs, Panel
from bokeh.models.widgets import Button
from bokeh.models.widgets import CheckboxButtonGroup
from bokeh.models.widgets import Slider, Select, TextInput
from bokeh.io import curdoc

from pylleo.pylleo import lleoio

# DATA
#------------------------------------------------------------------------------

# Setup Accelerometer data
args = sys.argv
sample_f = int(args[1])
data_path = args[2]

# TODO handle lleo mag, and other tags...
param_strs = ['Acceleration-X', 'Acceleration-Y', 'Acceleration-Z', 'Depth',
              'Propeller', 'Temperature']

meta = lleoio.read_meta(data_path, param_strs, n_header=10)
acc, depth, prop, temp = lleoio.read_data(meta, data_path, n_header=10,
                                          sample_f=sample_f)

# TODO make data output similar to dtag, remove this
# A = acc[acc.keys()[1:]].values.astype(float)

# Timestamps in epoch time and strings to nanosecond
dates = timestamp_to_epoch(acc['datetimes'])
#dates_str = [date_string_nano(d) for d in dates]

# Create Column Data Source that will be used by the plot
source = ColumnDataSource(data=dict(x    = list(acc['acceleration_x'].values),
                                    y    = list(acc['acceleration_y'].values),
                                    z    = list(acc['acceleration_z'].values),
                                    date = list(dates),))

# Input
#------------------------------------------------------------------------------

# TODO use callback with BoxSelectTool to get indices rather than TextInput
# http://stackoverflow.com/a/34175864/943773

# Create Input controls
t_min = min(dates)
t_max = max(dates)
acc_slider = Slider(title='Timestep', start=t_min, end=t_max, value=t_min, step=1)

# TODO generalize this for plotting the lines too
param_checkbox = CheckboxButtonGroup(labels=["x", "y", "z"], active=[0, 1, 2])

param_select = Select(title="Calibrate Param:", value=param_strs[0],
                      options=param_strs)

bound_select = Select(title="Bound:", value='lower',
                      options=['lower', 'upper'])

# User input start end times, save to cal
start_input = TextInput(value='0', title='start:')
end_input = TextInput(value='0', title='end:')

button_save = Button(label='Save Times', button_type='success')
button_save.on_click(save_times)

button_poly = Button(label='Perform Polyfit', button_type='success')
button_poly.on_click(save_poly)

controls = [acc_slider, param_checkbox, param_select, bound_select,
            start_input, end_input, button_save, button_poly]

# Plotting
#------------------------------------------------------------------------------

# Axis labels
axis_map = {'Time': 't',
            'Acceleration': 'acc',}

x_axis = Select(title='X Axis', options=sorted(axis_map.keys()), value='Time')
y_axis = Select(title='Y Axis', options=sorted(axis_map.keys()), value='Acceleration')

hover = HoverTool(tooltips=[('index', '$index'),
                            ('acc', '$y'),
                            ('time', '@date'),
                            ])

#'pan,wheel_zoom,box_zoom,reset,hover'
tools = [PanTool(), WheelZoomTool(), BoxZoomTool(), hover]
p, lines = plot_triaxial(acc, 300, 800, tools)

# Add line for current video time
vline = Span(location=0, dimension='height', line_color='red', line_width=3)
p.renderers.extend([vline,])

# Rendering
#------------------------------------------------------------------------------

for control in controls:
    control.on_change('value', update)

inputs = HBox(widgetbox(*controls), width=800)

# initial load of the data
update(None, None, None)

#TODO update to widget, hbox depreciated
curdoc().add_root(HBox(p, inputs, width=1100))
<|endoftext|>


<commit_before>row = '.^^^.^.^^^^^..^^^..^..^..^^..^.^.^.^^.^^....^.^...^.^^.^^.^^..^^..^.^..^^^.^^...^...^^....^^.^^^^^^^'
row_count = 400000

def next_row(row):
    result = ''
    row = '.' + row + '.'
    for i in range(1, len(row) - 1):
        trap = row[i - 1] == row[i] != row[i + 1] or \
               row[i + 1] == row[i] != row[i - 1]
        result += '^' if trap else '.'
    return result

count = 0
for _ in range(row_count):
    count += row.count('.')
    row = next_row(row)

print(count)
<commit_msg>Speed up day 18<commit_after>row = '.^^^.^.^^^^^..^^^..^..^..^^..^.^.^.^^.^^....^.^...^.^^.^^.^^..^^..^.^..^^^.^^...^...^^....^^.^^^^^^^'
row = list(map(lambda c: c == '^', row))
row_count = 400000

def next_row(row):
    result = [False] * len(row)
    row = [False] + row + [False]
    for i in range(len(row) - 2):
        result[i] = row[i] != row[i + 2]
    return result

count = 0
for _ in range(row_count):
    count += row.count(False)
    row = next_row(row)
print(count)
<|endoftext|>


<commit_before>#Advent of Code December 21
#Written by icydoge - icydoge AT gmail dot com

import itertools

weapons = [["Dagger", 8, 4], ["Shortsword", 10, 5], ["Warhammer", 25, 6], ["Longsword", 40, 7], ["Greataxe", 74, 8]]
armors = [["No Armor", 0, 0], ["Leather", 13, 1], ["Chainmail", 31, 2], ["Splintmail", 53, 3], ["Bandedmail", 75, 4], ["Platemail", 102, 5]]
rings = [["Empty Ring Slot 1", 0, 0, 0], ["Empty Ring Slot 2", 0, 0, 0], ["Damage +1", 25, 1, 0], ["Damage +2", 50, 2, 0], ["Damage +1", 100, 3, 0], ["Defense +1", 20, 0, 1], ["Defense +2", 40, 0, 2], ["Defense +3", 80, 0, 3]]

def get_damage(attacker_damage, defender_armor):

    damage = attacker_damage - defender_armor

    if damage < 1:
        damage = 1

    return damage

with open('inputs/rpg.txt') as f:
    content = f.read().splitlines()

boss_HP = int(content[0].split(' ')[2])
boss_damage = int(content[1].split(' ')[1])
boss_armor = int(content[2].split(' ')[1])

player_HP = 100
solutions = []
non_solutions = []

for weapon in weapons:
    for armor in armors:
        for ring_set in list(itertools.combinations(rings, 2)):
            player_damage = weapon[2] + sum([x[2] for x in ring_set])
            player_armor = armor[2] + sum([x[3] for x in ring_set])
            gold_expense = weapon[1] + armor[1] + sum([x[1] for x in ring_set])

            #Seems easy enough to formulate as a MMORPG player...
            if (float(player_HP) / get_damage(boss_damage, player_armor)) >= (float(boss_HP) / get_damage(player_damage, boss_armor)):
                solutions.append([weapon, armor, ring_set, gold_expense])

            else:
                non_solutions.append([weapon, armor, ring_set, gold_expense])

part_one_solution = min([x[3] for x in solutions])
print "Least amount of gold spent to kill the boss (Part One):", part_one_solution

part_two_solution = max([x[3] for x in non_solutions])
print "Most amount of gold to spend without killing the boss (Part Two):", part_two_solution
<commit_msg>Correct a rounding error and a text description error<commit_after>#Advent of Code December 21
#Written by icydoge - icydoge AT gmail dot com

import itertools
import math

weapons = [["Dagger", 8, 4], ["Shortsword", 10, 5], ["Warhammer", 25, 6], ["Longsword", 40, 7], ["Greataxe", 74, 8]]
armors = [["No Armor", 0, 0], ["Leather", 13, 1], ["Chainmail", 31, 2], ["Splintmail", 53, 3], ["Bandedmail", 75, 4], ["Platemail", 102, 5]]
rings = [["Empty Ring Slot 1", 0, 0, 0], ["Empty Ring Slot 2", 0, 0, 0], ["Damage +1", 25, 1, 0], ["Damage +2", 50, 2, 0], ["Damage +3", 100, 3, 0], ["Defense +1", 20, 0, 1], ["Defense +2", 40, 0, 2], ["Defense +3", 80, 0, 3]]

def get_damage(attacker_damage, defender_armor):

    damage = attacker_damage - defender_armor

    if damage < 1:
        damage = 1

    return damage

with open('inputs/rpg.txt') as f:
    content = f.read().splitlines()

boss_HP = int(content[0].split(' ')[2])
boss_damage = int(content[1].split(' ')[1])
boss_armor = int(content[2].split(' ')[1])

player_HP = 100
solutions = []
non_solutions = []

for weapon in weapons:
    for armor in armors:
        for ring_set in list(itertools.combinations(rings, 2)):
            player_damage = weapon[2] + sum([x[2] for x in ring_set])
            player_armor = armor[2] + sum([x[3] for x in ring_set])
            gold_expense = weapon[1] + armor[1] + sum([x[1] for x in ring_set])

            #Seems easy enough to formulate as a MMORPG player...
            if (math.ceil(float(player_HP) / float(get_damage(boss_damage, player_armor)))) >= (math.ceil(float(boss_HP) / float(get_damage(player_damage, boss_armor)))):
                solutions.append([weapon, armor, ring_set, gold_expense])

            else:
                non_solutions.append([weapon, armor, ring_set, gold_expense])

part_one_solution = min([x[3] for x in solutions])
print "Least amount of gold spent to kill the boss (Part One):", part_one_solution

part_two_solution = max([x[3] for x in non_solutions])
print "Most amount of gold to spend without killing the boss (Part Two):", part_two_solution
<|endoftext|>


<commit_before># !/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import csv
import sys
import math
import re
from dateutil.parser import parse
from collections import defaultdict

csv_modif = csv.reader(open(sys.argv[1]))
date_now = ""
if len(sys.argv) > 1:
	date_now = sys.argv[2]

header = next(csv_modif)
csv_output = csv.writer(open("data/turnover.csv", 'w'))
newheaders = header[1:42] + ["entree", "sortie", "nombredejours"]
csv_output.writerow(newheaders)
collab = defaultdict(dict)

def writecollab(unecollab):
	parsed_entree = parse(unecollab["entree"])
	nbdejours = ""
	#Gestion de la fin de mandat
	if unecollab["raw_data"][23]:
		unecollab["sortie"] = unecollab["raw_data"][23] + " 12:00:00 +0200"
	elif date_now:
		unecollab["raw_data"][23] = re.sub(r' .*', '', date_now)
	if unecollab["sortie"] == "" and date_now:
		unecollab["sortie"] = date_now
	if unecollab["sortie"] != "":
		parsed_sortie = parse(unecollab["sortie"])
		nbdejours = parsed_sortie - parsed_entree
		nbdejours = str(math.floor(nbdejours.total_seconds()/60/60/24))
	newline = unecollab["raw_data"] + [unecollab["entree"], unecollab["sortie"], nbdejours]
	csv_output.writerow(newline)

couple_contrats = defaultdict(list)

def validcollab(couple):
	couple_contrats[couple].append(collab[couple])

for modif in csv_modif:
	modif[1] = modif[14]
	parlementaire = modif[1]
	collaborateur = modif[5]
	couple = (parlementaire, collaborateur)
	rawdata = modif[1:42]

	if couple not in collab:
		collab[couple]["raw_data"] = rawdata
		collab[couple]["entree"] = ""
		collab[couple]["sortie"] = ""

	if modif[0] == "AJOUT":
		if collab[couple]["entree"] != "":
			print("ERROR: Réembauche d'un collab déjà en poste")
			print(modif)
		collab[couple]["entree"] = modif[12]

	elif modif[0] == "SUPPRESSION":
		if collab[couple]["sortie"] != "":
			print("ERROR: Fin d'un contrat jamais commencé")
			print(modif)
		if collab[couple]["entree"] == "":
			print("ERROR: Collaborateur embauché à la législature précédente")
			print(modif)
			collab[couple]["entree"] = "2017-06-21 00:00:00 +0200"
		collab[couple]["sortie"] = modif[12]

		# À chaque fin de contrat, l'information est versée dans un .csv de façon à s'assurer que
		# les données ne soient pas écrasée en cas de réembauche du collab par le même parlementaire
		validcollab(couple)
		collab.pop(couple, None)

for couple in collab:
	validcollab(couple)

for couple in couple_contrats:
	if len(couple_contrats[couple]) > 1:
		for i  in range(len(couple_contrats[couple]) - 1, 0, -1):
			datediff = parse(couple_contrats[couple][i]["entree"]) - parse(couple_contrats[couple][i-1]["sortie"])
			if (datediff.total_seconds()/60/60/24 < 7):
				couple_contrats[couple][i-1]["sortie"] = couple_contrats[couple][i]["sortie"]
				couple_contrats[couple][i]["deleted"] = True
for couple in couple_contrats:
	for collaboration in couple_contrats[couple]:
		if "deleted" not in collaboration:
			writecollab(collaboration)
<commit_msg>si collab de retour dans 3 mois, merge lower on collab<commit_after># !/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import csv
import sys
import math
import re
from dateutil.parser import parse
from collections import defaultdict

csv_modif = csv.reader(open(sys.argv[1]))
date_now = ""
if len(sys.argv) > 1:
	date_now = sys.argv[2]

header = next(csv_modif)
csv_output = csv.writer(open("data/turnover.csv", 'w'))
newheaders = header[1:42] + ["entree", "sortie", "nombredejours"]
csv_output.writerow(newheaders)
collab = defaultdict(dict)

def writecollab(unecollab):
	parsed_entree = parse(unecollab["entree"])
	nbdejours = ""
	#Gestion de la fin de mandat
	if unecollab["raw_data"][23]:
		unecollab["sortie"] = unecollab["raw_data"][23] + " 12:00:00 +0200"
	elif date_now:
		unecollab["raw_data"][23] = re.sub(r' .*', '', date_now)
	if unecollab["sortie"] == "" and date_now:
		unecollab["sortie"] = date_now
	if unecollab["sortie"] != "":
		parsed_sortie = parse(unecollab["sortie"])
		nbdejours = parsed_sortie - parsed_entree
		nbdejours = str(math.floor(nbdejours.total_seconds()/60/60/24))
	newline = unecollab["raw_data"] + [unecollab["entree"], unecollab["sortie"], nbdejours]
	csv_output.writerow(newline)

couple_contrats = defaultdict(list)

def validcollab(couple):
	couple_contrats[couple].append(collab[couple])

for modif in csv_modif:
	modif[1] = modif[14]
	parlementaire = modif[1]
	collaborateur = modif[5].lower()
	couple = (parlementaire, collaborateur)
	rawdata = modif[1:42]

	if couple not in collab:
		collab[couple]["raw_data"] = rawdata
		collab[couple]["entree"] = ""
		collab[couple]["sortie"] = ""

	if modif[0] == "AJOUT":
		if collab[couple]["entree"] != "":
			print("ERROR: Réembauche d'un collab déjà en poste")
			print(modif)
		collab[couple]["entree"] = modif[12]

	elif modif[0] == "SUPPRESSION":
		if collab[couple]["sortie"] != "":
			print("ERROR: Fin d'un contrat jamais commencé")
			print(modif)
		if collab[couple]["entree"] == "":
			print("ERROR: Collaborateur embauché à la législature précédente")
			print(modif)
			collab[couple]["entree"] = "2017-06-21 00:00:00 +0200"
		collab[couple]["sortie"] = modif[12]

		# À chaque fin de contrat, l'information est versée dans un .csv de façon à s'assurer que
		# les données ne soient pas écrasée en cas de réembauche du collab par le même parlementaire
		validcollab(couple)
		collab.pop(couple, None)

for couple in collab:
	validcollab(couple)

for couple in couple_contrats:
	if len(couple_contrats[couple]) > 1:
		for i  in range(len(couple_contrats[couple]) - 1, 0, -1):
			datediff = parse(couple_contrats[couple][i]["entree"]) - parse(couple_contrats[couple][i-1]["sortie"])
			if (datediff.total_seconds()/60/60/24 < 120):
				couple_contrats[couple][i-1]["sortie"] = couple_contrats[couple][i]["sortie"]
				couple_contrats[couple][i]["deleted"] = True
for couple in couple_contrats:
	for collaboration in couple_contrats[couple]:
		if "deleted" not in collaboration:
			writecollab(collaboration)
<|endoftext|>


<commit_before>"""
Convert a genbank file to sequences
"""

import sys
import argparse
from roblib import genbank_to_faa, genbank_to_fna, genbank_to_orfs, genbank_to_ptt, genbank_to_functions, genbank_seqio
from roblib import genbank
from Bio import SeqIO

__author__ = 'Rob Edwards'
__copyright__ = 'Copyright 2020, Rob Edwards'
__credits__ = ['Rob Edwards']
__license__ = 'MIT'
__maintainer__ = 'Rob Edwards'
__email__ = 'raedwards@gmail.com'

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description=" ")
    parser.add_argument('-g', '--genbank', help='genbank file', required=True)
    parser.add_argument('-c', '--complex', help='complex identifier line', action='store_true')
    parser.add_argument('-a', '--aminoacids', help="output file for the amino acid sequences (.faa will be appended)")
    parser.add_argument('-n', '--nucleotide', help='output file for nucleotide sequence (.fna will be appended)')
    parser.add_argument('-p', '--ptt', help='output file for the ptt protein table')
    parser.add_argument('-o', '--orfs', help='output file for orfs (.orfs will be appended)')
    parser.add_argument('-f', '--functions', help='output file for two column table of [protein id, function]')
    parser.add_argument('--phage_finder', help='make a phage finder file')
    parser.add_argument('--separate',  action='store_true',
                        help='separate output into different files (with no other options just output gbk).')
    parser.add_argument('-v', help='verbose output', action='store_true')
    args = parser.parse_args()

    did = False
    if args.nucleotide:
        if args.separate:
            lastid = None
            out = None
            for sid, seq in genbank_to_fna(args.genbank):
                if sid != lastid:
                    if out:
                        out.close()
                    out = open(f"{args.nucleotide}.{sid}.fna", 'w')
                    lastid = sid
                out.write(f">{sid}\n{seq}\n")
            if out:
                out.close()
        else:
            with open(f"{args.nucleotide}.fna", 'w') as out:
                for sid, seq in genbank_to_fna(args.genbank):
                    out.write(f">{sid}\n{seq}\n")
        did = True

    if args.aminoacids:
        if args.separate:
            lastid = None
            out = None
            for seqid, sid, seq in genbank_to_faa(args.genbank, args.complex, args.v):
                if seqid != lastid:
                    if out:
                        out.close()
                    out = open(f"{args.aminoacids}.{seqid}.faa", 'w')
                    lastid = seqid
                out.write(f">{sid}\n{seq}\n")
            if out:
                out.close()
        else:
            with open(f"{args.aminoacids}.faa", 'w') as out:
                for seqid, sid, seq in genbank_to_faa(args.genbank, args.complex, args.v):
                    out.write(f">{sid}\n{seq}\n")
        did = True

    if args.orfs:
        if args.separate:
            lastid = None
            out = None
            for seqid, sid, seq in genbank_to_orfs(args.genbank, args.complex, args.v):
                if seqid != lastid:
                    if out:
                        out.close()
                    out = open(f"{args.orfs}.{seqid}.orfs", 'w')
                    lastid = seqid
                out.write(f">{sid}\n{seq}\n")
            if out:
                out.close()
        else:
            with open(f"{args.orfs}.orfs", 'w') as out:
                for seqid, sid, seq in genbank_to_orfs(args.genbank, args.complex, args.v):
                    out.write(f">{sid}\n{seq}\n")
        did = True

    if args.ptt:
        r = genbank_to_ptt(args.genbank, False, args.v)
        with open(args.ptt, 'w') as out:
            for l in r:
                out.write("\t".join(map(str, l)))
                out.write("\n")
        did = True

    if args.functions:
        with open(args.functions, 'w') as out:
            for pid, prod in genbank_to_functions(args.genbank, args.v):
                out.write(f"{pid}\t{prod}\n")
        did = True

    if args.phage_finder:
        with open(args.phage_finder, 'w') as out:
            for tple in genbank.genbank_to_phage_finder(args.genbank, args.v):
                out.write("\t".join(map(str, tple)) + "\n")
        did = True

    if not did and args.separate:
        lastid = None
        out = None
        for seq in genbank_seqio(args.genbank):
            out = open(f"{seq.id}.gbk", 'w')
            SeqIO.write(seq, out, 'genbank')
            out.close()
        did = True

    if not did:
        sys.stderr.write("Please provide either a -n, -a, -o, -p, -f output file! (or all)\n")
<commit_msg>Choose one or more sequences<commit_after>"""
Convert a genbank file to sequences
"""

import sys
import argparse
from roblib import genbank_to_faa, genbank_to_fna, genbank_to_orfs, genbank_to_ptt, genbank_to_functions, genbank_seqio
from roblib import genbank
from Bio import SeqIO

__author__ = 'Rob Edwards'
__copyright__ = 'Copyright 2020, Rob Edwards'
__credits__ = ['Rob Edwards']
__license__ = 'MIT'
__maintainer__ = 'Rob Edwards'
__email__ = 'raedwards@gmail.com'

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description=" ")
    parser.add_argument('-g', '--genbank', help='genbank file', required=True)
    parser.add_argument('-c', '--complex', help='complex identifier line', action='store_true')
    parser.add_argument('-a', '--aminoacids', help="output file for the amino acid sequences (.faa will be appended)")
    parser.add_argument('-n', '--nucleotide', help='output file for nucleotide sequence (.fna will be appended)')
    parser.add_argument('-p', '--ptt', help='output file for the ptt protein table')
    parser.add_argument('-o', '--orfs', help='output file for orfs (.orfs will be appended)')
    parser.add_argument('-f', '--functions', help='output file for two column table of [protein id, function]')
    parser.add_argument('-i', '--seqid', help='Only output these sequence ID(s) [multiple -i allowed]',
                        action='append')
    parser.add_argument('--phage_finder', help='make a phage finder file')
    parser.add_argument('--separate',  action='store_true',
                        help='separate output into different files (with no other options just output gbk).')
    parser.add_argument('-v', help='verbose output', action='store_true')
    args = parser.parse_args()

    if args.i and not args.separate:
        sys.stderr.write("-i was provided, so requiring to separate files (--separate assumed)\n")
        args.separate = True

    did = False
    if args.nucleotide:
        if args.separate:
            lastid = None
            out = None
            for sid, seq in genbank_to_fna(args.genbank):
                if args.i and sid not in args.i:
                    if args.v:
                        sys.stderr.write(f"Skipped {sid} not provided in -i options\n")
                    continue
                if sid != lastid:
                    if out:
                        out.close()
                    out = open(f"{args.nucleotide}.{sid}.fna", 'w')
                    lastid = sid
                out.write(f">{sid}\n{seq}\n")
            if out:
                out.close()
        else:
            with open(f"{args.nucleotide}.fna", 'w') as out:
                for sid, seq in genbank_to_fna(args.genbank):
                    out.write(f">{sid}\n{seq}\n")
        did = True

    if args.aminoacids:
        if args.separate:
            lastid = None
            out = None
            for seqid, sid, seq in genbank_to_faa(args.genbank, args.complex, args.v):
                if args.i and sid not in args.i:
                    if args.v:
                        sys.stderr.write(f"Skipped {seqid} not provided in -i options\n")
                    continue
                if seqid != lastid:
                    if out:
                        out.close()
                    out = open(f"{args.aminoacids}.{seqid}.faa", 'w')
                    lastid = seqid
                out.write(f">{sid}\n{seq}\n")
            if out:
                out.close()
        else:
            with open(f"{args.aminoacids}.faa", 'w') as out:
                for seqid, sid, seq in genbank_to_faa(args.genbank, args.complex, args.v):
                    out.write(f">{sid}\n{seq}\n")
        did = True

    if args.orfs:
        if args.separate:
            lastid = None
            out = None
            for seqid, sid, seq in genbank_to_orfs(args.genbank, args.complex, args.v):
                if args.i and sid not in args.i:
                    if args.v:
                        sys.stderr.write(f"Skipped {seqid} not provided in -i options\n")
                    continue
                if seqid != lastid:
                    if out:
                        out.close()
                    out = open(f"{args.orfs}.{seqid}.orfs", 'w')
                    lastid = seqid
                out.write(f">{sid}\n{seq}\n")
            if out:
                out.close()
        else:
            with open(f"{args.orfs}.orfs", 'w') as out:
                for seqid, sid, seq in genbank_to_orfs(args.genbank, args.complex, args.v):
                    out.write(f">{sid}\n{seq}\n")
        did = True

    if args.ptt:
        r = genbank_to_ptt(args.genbank, False, args.v)
        with open(args.ptt, 'w') as out:
            for l in r:
                out.write("\t".join(map(str, l)))
                out.write("\n")
        did = True

    if args.functions:
        with open(args.functions, 'w') as out:
            for pid, prod in genbank_to_functions(args.genbank, args.v):
                out.write(f"{pid}\t{prod}\n")
        did = True

    if args.phage_finder:
        with open(args.phage_finder, 'w') as out:
            for tple in genbank.genbank_to_phage_finder(args.genbank, args.v):
                out.write("\t".join(map(str, tple)) + "\n")
        did = True

    if not did and args.separate:
        lastid = None
        out = None
        for seq in genbank_seqio(args.genbank):
            if args.i and seq.id not in args.i:
                if args.v:
                    sys.stderr.write(f"Skipped {seq.id} not provided in -i options\n")
                continue
            out = open(f"{seq.id}.gbk", 'w')
            SeqIO.write(seq, out, 'genbank')
            out.close()
        did = True

    if not did:
        sys.stderr.write("Please provide either a -n, -a, -o, -p, -f output file! (or all)\n")
<|endoftext|>


<commit_before>import os
import glob
import re
import gzip
import json
import subprocess

FUDGE_FACTOR = 81 #

def read_file(filepath, binary = False):
    if binary:
        output_handle = open(filepath, 'rb')
    elif filepath.endswith('.gz'):
        output_handle = gzip.open(filepath, 'r')
    else:
        output_handle = open(filepath, 'r')
    contents = output_handle.read()
    output_handle.close()
    return contents

def write_file(filepath, contents, ftype = 'w'):
    output_handle = open(filepath, ftype)
    output_handle.write(contents)
    output_handle.close()

def Popen(outdir, args):
    subp = subprocess.Popen([str(arg) for arg in args], stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=outdir, env={'SPARKSXDIR' : '/netapp/home/klabqb3backrub/tools/sparks-x'})
    output = subp.communicate()
    return output[0], output[1], subp.returncode # 0 is stdout, 1 is stderr

def rewrite_score_file(old_filepath, backup_filepath, new_filepath, mapping, nmerage, num_fragments):
    print('')
    lines = read_file(old_filepath).split('\n')

    must_zip_output = old_filepath.endswith('.gz')
    new_lines = []
    for l in lines:
        if l.startswith('#') or not(l.strip()):
            new_lines.append(l)
        else:
            tokens = l.split()
            assert(len(tokens) == 14)
            assert(l[:11].strip().isdigit())
            assert(l[11] == ' ')
            residue_id = int(l[:11])
            assert(mapping.get(str(residue_id)))
            new_lines.append('%s%s' % (str(mapping[str(residue_id)] + FUDGE_FACTOR).rjust(11), l[11:]))
            assert(len(new_lines[-1]) == len(l))

    colortext.message('Rewriting fragments score file for %d-mers with %d fragments...' % (nmerage, num_fragments))
    os.rename(old_filepath, backup_filepath)
    write_file(new_filepath, '\n'.join(new_lines))
    colortext.message(must_zip_output)
    if os.path.exists(new_filepath + '.gz'):
        os.remove(new_filepath + '.gz')
    if must_zip_output:
        stdout, stderr, errorcode = Popen(os.path.split(new_filepath)[0], ['gzip', os.path.split(new_filepath)[1]])
        assert(errorcode == 0)

def rewrite_fragments_file(old_filepath, backup_filepath, new_filepath, mapping, nmerage, num_fragments):
    print('')
    lines = read_file(old_filepath).split('\n')

    must_zip_output = old_filepath.endswith('.gz')
    new_lines = []
    for l in lines:
        if l.startswith('position:'):
            assert(l.find('neighbors:') != -1)
            assert(l.find('neighbors:') != -1)
            tokens = l.split()
            assert(len(tokens) == 4)
            assert(l[9:22].strip().isdigit())
            assert(l[22] == ' ')
            residue_id = int(l[9:22])
            assert(mapping.get(str(residue_id)))
            new_lines.append('position:%s%s' % (str(mapping[str(residue_id)] + FUDGE_FACTOR).rjust(13), l[22:]))
            assert(len(new_lines[-1]) == len(l))
        else:
            new_lines.append(l)

    colortext.message('Rewriting fragments file for %d-mers with %d fragments...' % (nmerage, num_fragments))
    os.rename(old_filepath, backup_filepath)
    write_file(new_filepath, '\n'.join(new_lines))
    colortext.message(must_zip_output)
    if os.path.exists(new_filepath + '.gz'):
        os.remove(new_filepath + '.gz')
    if must_zip_output:
        stdout, stderr, errorcode = Popen(os.path.split(new_filepath)[0], ['gzip', os.path.split(new_filepath)[1]])
        assert(errorcode == 0)

if __name__ == '__main__':
    import sys
    sys.path.insert(0, '../../../..')
    import colortext
    if os.path.exists('segment_map.json'):
        mapping = json.loads(open('segment_map.json').read())
        print(mapping)
        print('')
        for d in os.listdir('.'):
            if os.path.isdir(d):
                for f in sorted(glob.glob(os.path.join(d, "*mers")) + glob.glob(os.path.join(d, "*mers.gz"))):
                    if f.find('backup') != -1 or f.find('rewrite') != -1:
                        continue
                    mtchs = re.match('(.*?frags)[.](\d+)[.]score[.](\d+)[.](\d+)mers[.]?(gz)?', f)
                    if mtchs:
                        print(f)
                        assert(mtchs.group(2) == mtchs.group(4))
                        nmerage = int(mtchs.group(2))
                        num_fragments = int(mtchs.group(2))
                        old_filepath = mtchs.group(0)
                        # Kale wanted to change the filename for the scores so that it is easier to distinguish between score and fragments files using glob

                        backup_filepath = '%s.%s.%sbackup.score.%s' % (mtchs.group(1), mtchs.group(3), mtchs.group(4), mtchs.group(5))
                        new_filepath = ('%s.%s.%smers.rewrite.score.%s' % (mtchs.group(1), mtchs.group(3), mtchs.group(4), mtchs.group(5))).replace('.gz', '')
                        rewrite_score_file(old_filepath, backup_filepath, new_filepath, mapping, nmerage, num_fragments)
                    else:
                        mtchs = re.match('(.*)[.](\d+)[.](\d+)mers[.]?(gz)?', f)
                        if mtchs:
                            print(f)
                            nmerage = int(mtchs.group(2))
                            num_fragments = int(mtchs.group(3))
                            old_filepath = mtchs.group(0)
                            backup_filepath= '%s.%s.%sbackup.%s' % (mtchs.group(1), mtchs.group(2), mtchs.group(3), mtchs.group(4))
                            new_filepath= ('%s.%s.%sbackup.rewrite.%s' % (mtchs.group(1), mtchs.group(2), mtchs.group(3), mtchs.group(4))).replace('.gz', '')
                            rewrite_fragments_file(old_filepath, backup_filepath, new_filepath, mapping, nmerage, num_fragments)

#2silA_frags.3.score.200.3mers.gz

        import sys
        sys.exit(0)

        for dirpath, dirnames, filenames in os.walk('.'):
            print(1)
            print(dirpath, dirnames, filenames)
        a='''
            frags.9.score.200.9mers

            for f in glob.glob(os.path.join(scratch_path, "*mers")) + [os.path.join(scratch_path, 'ss_blast')]:
                pass

/2silA_frags.9.score.200.9mers.gz

position:            1 neighbors:          200
position:            9 neighbors:          200

 3fm3 A   220 G L -147.838  140.069  162.241   19.330  -15.590   29.710
 3fm3 A   221 I L -106.823  125.308 -168.239   16.930  -16.440   32.500

EKSVVFKGNTIVGSGSGGTTKYFRIPAMTSKG

9-mers

#query_pos  vall_pos  pdbid c ss  ProfileScoreL1 SecondarySimilarity SolventAccessibility RamaScore Phi Psi ProfileScoreStructL1  TOTAL  FRAG_ID
          1        136  1gen A E           0.59                0.17                 0.14      0.00   0.07   0.36                 0.56    3.500   3743772
          1         57  3m4w A E           0.66                0.16                 0.10      0.01   0.11   0.34                 0.56    3.535    343056
...
         24

3-mers
#query_pos  vall_pos  pdbid c ss  ProfileScoreL1 SecondarySimilarity SolventAccessibility RamaScore Phi Psi ProfileScoreStructL1  TOTAL  FRAG_ID
          1        220  3fm3 A L           0.49                0.28                 0.13      0.00   0.03   0.08                 0.52    1.768   2266884
          1        390  2acx A L           0.39                0.36                 0.13      0.00   0.02   0.03                 0.60    1.786   3077962
...
         30        138  2a9d A L           0.38                0.16                 0.15      0.00   0.11   0.11                 0.50    1.880   1324419

whitespace important?
index specifies *left* index of segment

'''
<commit_msg>Fixing some stdout.<commit_after>import os
import glob
import re
import gzip
import json
import subprocess

FUDGE_FACTOR = 81 # !!!

def read_file(filepath, binary = False):
    if binary:
        output_handle = open(filepath, 'rb')
    elif filepath.endswith('.gz'):
        output_handle = gzip.open(filepath, 'r')
    else:
        output_handle = open(filepath, 'r')
    contents = output_handle.read()
    output_handle.close()
    return contents

def write_file(filepath, contents, ftype = 'w'):
    output_handle = open(filepath, ftype)
    output_handle.write(contents)
    output_handle.close()

def Popen(outdir, args):
    subp = subprocess.Popen([str(arg) for arg in args], stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=outdir, env={'SPARKSXDIR' : '/netapp/home/klabqb3backrub/tools/sparks-x'})
    output = subp.communicate()
    return output[0], output[1], subp.returncode # 0 is stdout, 1 is stderr

def rewrite_score_file(old_filepath, backup_filepath, new_filepath, mapping, nmerage, num_fragments):
    print('')
    lines = read_file(old_filepath).split('\n')

    must_zip_output = old_filepath.endswith('.gz')
    new_lines = []
    for l in lines:
        if l.startswith('#') or not(l.strip()):
            new_lines.append(l)
        else:
            tokens = l.split()
            assert(len(tokens) == 14)
            assert(l[:11].strip().isdigit())
            assert(l[11] == ' ')
            residue_id = int(l[:11])
            assert(mapping.get(str(residue_id)))
            new_lines.append('%s%s' % (str(mapping[str(residue_id)] + FUDGE_FACTOR).rjust(11), l[11:]))
            assert(len(new_lines[-1]) == len(l))

    colortext.message('Rewriting fragments score file for %d-mers with %d fragments...' % (nmerage, num_fragments))
    os.rename(old_filepath, backup_filepath)
    write_file(new_filepath, '\n'.join(new_lines))
    colortext.message(must_zip_output)
    if os.path.exists(new_filepath + '.gz'):
        os.remove(new_filepath + '.gz')
    if must_zip_output:
        stdout, stderr, errorcode = Popen(os.path.split(new_filepath)[0], ['gzip', os.path.split(new_filepath)[1]])
        assert(errorcode == 0)

def rewrite_fragments_file(old_filepath, backup_filepath, new_filepath, mapping, nmerage, num_fragments):
    print('')
    lines = read_file(old_filepath).split('\n')

    must_zip_output = old_filepath.endswith('.gz')
    new_lines = []
    for l in lines:
        if l.startswith('position:'):
            assert(l.find('neighbors:') != -1)
            assert(l.find('neighbors:') != -1)
            tokens = l.split()
            assert(len(tokens) == 4)
            assert(l[9:22].strip().isdigit())
            assert(l[22] == ' ')
            residue_id = int(l[9:22])
            assert(mapping.get(str(residue_id)))
            new_lines.append('position:%s%s' % (str(mapping[str(residue_id)] + FUDGE_FACTOR).rjust(13), l[22:]))
            assert(len(new_lines[-1]) == len(l))
        else:
            new_lines.append(l)

    colortext.message('Rewriting fragments file for %d-mers with %d fragments...' % (nmerage, num_fragments))
    os.rename(old_filepath, backup_filepath)
    write_file(new_filepath, '\n'.join(new_lines))
    colortext.message(must_zip_output)
    if os.path.exists(new_filepath + '.gz'):
        os.remove(new_filepath + '.gz')
    if must_zip_output:
        stdout, stderr, errorcode = Popen(os.path.split(new_filepath)[0], ['gzip', os.path.split(new_filepath)[1]])
        assert(errorcode == 0)

if __name__ == '__main__':
    import sys
    sys.path.insert(0, '../../../..')
    import colortext
    if os.path.exists('segment_map.json'):
        mapping = json.loads(open('segment_map.json').read())
        print(mapping)
        print('')
        for d in os.listdir('.'):
            if os.path.isdir(d):
                for f in sorted(glob.glob(os.path.join(d, "*mers")) + glob.glob(os.path.join(d, "*mers.gz"))):
                    if f.find('backup') != -1 or f.find('rewrite') != -1:
                        continue
                    mtchs = re.match('(.*?frags)[.](\d+)[.]score[.](\d+)[.](\d+)mers[.]?(gz)?', f)
                    if mtchs:
                        assert(mtchs.group(2) == mtchs.group(4))
                        nmerage = int(mtchs.group(2))
                        num_fragments = int(mtchs.group(3))
                        old_filepath = mtchs.group(0)
                        # Kale wanted to change the filename for the scores so that it is easier to distinguish between score and fragments files using glob

                        backup_filepath = '%s.%s.%sbackup.score.%s' % (mtchs.group(1), mtchs.group(3), mtchs.group(4), mtchs.group(5))
                        new_filepath = ('%s.%s.%smers.rewrite.score.%s' % (mtchs.group(1), mtchs.group(3), mtchs.group(4), mtchs.group(5))).replace('.gz', '')
                        rewrite_score_file(old_filepath, backup_filepath, new_filepath, mapping, nmerage, num_fragments)
                    else:
                        mtchs = re.match('(.*)[.](\d+)[.](\d+)mers[.]?(gz)?', f)
                        if mtchs:
                            nmerage = int(mtchs.group(3))
                            num_fragments = int(mtchs.group(2))
                            old_filepath = mtchs.group(0)
                            backup_filepath= '%s.%s.%sbackup.%s' % (mtchs.group(1), mtchs.group(2), mtchs.group(3), mtchs.group(4))
                            new_filepath= ('%s.%s.%sbackup.rewrite.%s' % (mtchs.group(1), mtchs.group(2), mtchs.group(3), mtchs.group(4))).replace('.gz', '')
                            rewrite_fragments_file(old_filepath, backup_filepath, new_filepath, mapping, nmerage, num_fragments)

<|endoftext|>


<commit_before>from __future__ import unicode_literals

import logging
import os

import tornado.ioloop
import tornado.web

from . import helper
from . import korrekturtools

class NetsecHandler(helper.RequestHandlerWithAuth):
    def render(self, template, data):
        htmlPath = self.application.config("html_path")
        super(NetsecHandler, self).render(
            os.path.join("..", htmlPath, "%s.html" % template),
            **data)

class TableHandler(NetsecHandler):
    def get(self):
        abgaben = []
        attachmentPath = self.application.config("attachment_path")
        if os.path.exists(attachmentPath):
            for entry in os.listdir(attachmentPath):
                if entry[0] != ".":
                    abgaben.append({
                        "name": entry.lower(),
                        "status": korrekturtools.readStatus(self.config, entry.lower())
                        })
        else:
            logging.error("Specified attachment path ('%s') does not exist." % attachmentPath)

        self.render('table', {'reihen': abgaben})

class ZipHandler(NetsecHandler):
    def get(self):
        requestedFile = self.request.uri.replace("/zips/", "/zips").replace("/zips", "")

        if len(requestedFile) == 0:
            self.set_status(404)
            self.write("Zurück zur Übersicht")
            self.finish()
            return

        self.write(requestedFile)

class StatusHandler(NetsecHandler):
    def get(self):
        uri = self.request.uri.replace("/status/", "")
        if uri.count("/") == 1:
            student, status = uri.split("/")
        else:
            student = uri
            status = ""
        if status:
            korrekturtools.writeStatus(self.config, student, status)
        else:
            self.write(korrekturtools.readStatus(self.config, student))

class DetailHandler(NetsecHandler):
    def get(self):
        uri = self.request.uri.split("/")
        uri = uri[2:] # remove empty element and "detail"
        print(uri)
        return
        files = []
        attachmentPath = self.application.config("attachment_path")
        if os.path.exists(attachmentPath):
            for entry in os.listdir(os.path.join(attachmentPath, "a")):
                if entry[0] != ".":
                    files.append({
                        "name": entry.lower(),
                        "status": korrekturtools.readStatus(self.config, entry.lower())
                        })
        else:
            logging.error("Specified attachment path ('%s') does not exist." % attachmentPath)

        self.render('detail', {'files': {'name': files, 'size': size }})

class KorrekturApp(tornado.web.Application):
    realm = 'netsec Uebungsabgabesystem'

    def __init__(self, config, handlers):
        super(KorrekturApp, self).__init__(handlers)
        for handler in handlers:
            handler[1].config = config
        self.config = config

    @property
    def users(self):
        return self.config('korrektoren')

def mainloop(config):
    application = KorrekturApp(config, [
        (r"/", TableHandler),
        (r"/zips/.*", ZipHandler),
        (r"/status/.*", StatusHandler),
        (r"/detail/.*", DetailHandler),
    ])

    port = config('httpd.port')
    application.listen(port)
    logging.debug("Web server started on port %i.", port)
    tornado.ioloop.IOLoop.instance().start()
<commit_msg>flake8 suggestions about indentation<commit_after>from __future__ import unicode_literals

import logging
import os

import tornado.ioloop
import tornado.web

from . import helper
from . import korrekturtools

class NetsecHandler(helper.RequestHandlerWithAuth):
    def render(self, template, data):
        htmlPath = self.application.config("html_path")
        super(NetsecHandler, self).render(
            os.path.join("..", htmlPath, "%s.html" % template),
            **data)

class TableHandler(NetsecHandler):
    def get(self):
        abgaben = []
        attachmentPath = self.application.config("attachment_path")
        if os.path.exists(attachmentPath):
            for entry in os.listdir(attachmentPath):
                if entry[0] != ".":
                    abgaben.append({
                        "name": entry.lower(),
                        "status": korrekturtools.readStatus(self.config, entry.lower())
                        })
        else:
            logging.error("Specified attachment path ('%s') does not exist." % attachmentPath)

        self.render('table', {'reihen': abgaben})

class ZipHandler(NetsecHandler):
    def get(self):
        requestedFile = self.request.uri.replace("/zips/", "/zips").replace("/zips", "")

        if len(requestedFile) == 0:
            self.set_status(404)
            self.write("Zurück zur Übersicht")
            self.finish()
            return

        self.write(requestedFile)

class StatusHandler(NetsecHandler):
    def get(self):
        uri = self.request.uri.replace("/status/", "")
        if uri.count("/") == 1:
            student, status = uri.split("/")
        else:
            student = uri
            status = ""
        if status:
            korrekturtools.writeStatus(self.config, student, status)
        else:
            self.write(korrekturtools.readStatus(self.config, student))

class DetailHandler(NetsecHandler):
    def get(self):
        uri = self.request.uri.split("/")
        uri = uri[2:]  # remove empty element and "detail"
        print(uri)
        return
        files = []
        attachmentPath = self.application.config("attachment_path")
        if os.path.exists(attachmentPath):
            for entry in os.listdir(os.path.join(attachmentPath, "a")):
                if entry[0] != ".":
                    files.append({
                        "name": entry.lower(),
                        "status": korrekturtools.readStatus(self.config, entry.lower())
                        })
        else:
            logging.error("Specified attachment path ('%s') does not exist." % attachmentPath)

        self.render('detail', {'files': {'name': files, 'size': size}})

class KorrekturApp(tornado.web.Application):
    realm = 'netsec Uebungsabgabesystem'

    def __init__(self, config, handlers):
        super(KorrekturApp, self).__init__(handlers)
        for handler in handlers:
            handler[1].config = config
        self.config = config

    @property
    def users(self):
        return self.config('korrektoren')

def mainloop(config):
    application = KorrekturApp(config, [
        (r"/", TableHandler),
        (r"/zips/.*", ZipHandler),
        (r"/status/.*", StatusHandler),
        (r"/detail/.*", DetailHandler),
    ])

    port = config('httpd.port')
    application.listen(port)
    logging.debug("Web server started on port %i.", port)
    tornado.ioloop.IOLoop.instance().start()
<|endoftext|>