<commit_before>import multiprocessing
import threading
import logging

logger = logging.getLogger('pywebview')

class Event:
    def __init__(self):
        self._items = []
        self._event = threading.Event()

    def _initialize(self, is_multiprocessing):
        if is_multiprocessing:
            self._event = multiprocessing.Event()

    def set(self, *args, **kwargs):
        for func in self._items:
            try:
                func(*args, **kwargs)
            except Exception as e:
                logger.exception(e)

        self._event.set()

    def is_set(self):
        return self._event.is_set()

    def wait(self, timeout=0):
        return self._event.wait(timeout)

    def clear(self):
        return self._event.clear()

    def __add__(self, item):
        self._items.append(item)
        return self

    def __sub__(self, item):
        self._items.remove(item)
        return self

    def __iadd__(self, item):
        self._items.append(item)
        return self

    def __isub__(self, item):
        self._items.remove(item)
        return self
<commit_msg>Fix loaded event race condition<commit_after>import multiprocessing
import threading
import logging

logger = logging.getLogger('pywebview')

class Event:
    def __init__(self):
        self._items = []
        self._event = threading.Event()

    def _initialize(self, is_multiprocessing):
        if is_multiprocessing:
            self._event = multiprocessing.Event()

    def set(self, *args, **kwargs):
        def execute():
            for func in self._items:
                try:
                    func(*args, **kwargs)
                except Exception as e:
                    logger.exception(e)

        self._event.set()

        if len(self._items):
            t = threading.Thread(target=execute)
            t.start()

    def is_set(self):
        return self._event.is_set()

    def wait(self, timeout=0):
        return self._event.wait(timeout)

    def clear(self):
        return self._event.clear()

    def __add__(self, item):
        self._items.append(item)
        return self

    def __sub__(self, item):
        self._items.remove(item)
        return self

    def __iadd__(self, item):
        self._items.append(item)
        return self

    def __isub__(self, item):
        self._items.remove(item)
        return self
<|endoftext|>


<commit_before>#! /usr/bin/python

import os
SCRIPT_PATH = os.path.dirname(os.path.realpath(__file__))

import sys
sys.path.append(SCRIPT_PATH + '/../src/')

import subprocess
import multiprocessing

import basicdefines
from dataspec import *

ASSEMBLER_URL = 'http://sourceforge.net/projects/wgs-assembler/files/wgs-assembler/wgs-8.3/wgs-8.3rc2-Linux_amd64.tar.bz2'
ASSEMBLER_PATH = os.path.join(basicdefines.ASSEMBLERS_PATH_ROOT_ABS, 'wgs-8.3rc2')
ZIP_FILE = 'wgs-8.3rc2-Linux_amd64.tar.bz2'
ZIP_PATH = os.path.join(basicdefines.ASSEMBLERS_PATH_ROOT_ABS, ZIP_FILE)
ASSEMBLER_BIN = os.path.join(ASSEMBLER_PATH,'Linux-amd64/bin/runCA')
ASSEMBLER_ECBIN = os.path.join(ASSEMBLER_PATH,'Linux-amd64/bin/PBcR')
ASSEMBLER_NAME = 'PBcR'
ASSEMBLER_RESULTS = 'out/9-terminator/asm.ctg.fasta'
CREATE_OUTPUT_FOLDER = True

PACBIO_SPEC = os.path.join(ASSEMBLER_PATH, 'wgs_pacbio.spec')
OXFORD_SPEC = os.path.join(ASSEMBLER_PATH, 'wgs_oxford.spec')

DO_ERROR_CORRECTION = True

# Run parameters
P_LENGTH = 500
P_PARTITIONS = 200

# DRY_RUN = True;
DRY_RUN = False;

### Logs messages to STDERR and an output log file if provided (opened elsewhere).
def log(message, fp_log):
    timestamp = strftime("%Y/%m/%d %H:%M:%S", gmtime());

    sys.stderr.write('[%s wrapper %s] %s\n' % (ASSEMBLER_NAME, timestamp, message))
    sys.stderr.flush();
    if (fp_log != None):
        fp_log.write('[%s wrapper %s] %s\n' % (ASSEMBLER_NAME, timestamp, message))
        fp_log.flush();

def execute_command(command, fp_log, dry_run=True):
    if (dry_run == True):
        # sys.stderr.write('Warning: dry_run == True\n');
#        sys.stderr.write('[%s wrapper] Executing (dryrun): "%s"\n' % (ASSEMBLER_NAME, command));
        log('Executing (dryrun): "%s".' % (command), fp_log);
    if (dry_run == False):
        # sys.stderr.write('[%s wrapper] Executing: "%s"\n' % (ASSEMBLER_NAME, command));
        log('Executing: "%s".' % (command), fp_log);
        subprocess.call(command, shell=True);
    # sys.stderr.write('\n');
    log('\n', fp_log);

def measure_command(measure_file):
    if (MODULE_BASICDEFINES == True):
        return basicdefines.measure_command(measure_file);
    else:
        sys.stderr.write('ERROR: Cgmemtime tool not found! Exiting.\n');
        exit(1);
        # return '/usr/bin/time --format "Command line: %%C\\nReal time: %%e s\\nCPU time: -1.0 s\\nUser time: %%U s\\nSystem time: %%S s\\nMaximum RSS: %%M kB\\nExit status: %%x" --quiet -o %s ' % measure_file;

def peek(fp, num_chars):
    data = fp.read(num_chars);
    if len(data) == 0:
        return '';
    fp.seek(num_chars * -1, 1);
    return data;

# Returns a single read from the given FASTA/FASTQ file.
# Parameter header contains only the header of the read.
# Parameter lines contains all lines of the read, which include:
# - header
# - seq
# - '+' if FASTQ
# - quals if FASTQ
# Parameter lines is an array of strings, each for one component.
# Please note that multiline FASTA/FASTQ entries (e.g. sequence line)
# will be truncated into one single line.
def get_single_read(fp):
    lines = [];

    line = fp.readline();
    header = line.rstrip();
    header_leading_char = '';
    if (len(header) > 0):
        sequence_separator = header[0];
        header_leading_char = header[0];
        header = header[1:];            # Strip the '>' or '@' sign from the beginning.
    else:
        return ['', []];

    next_char = peek(fp, 1);

    line_string = '';
    lines.append(header_leading_char + header);

    num_lines = 1;
    #while len(next_char) > 0 and next_char != sequence_separator or (next_char == '@' and num_lines < 4):
    while (len(next_char) > 0 and (next_char != sequence_separator or (next_char == '@' and num_lines < 4))):
        line = fp.readline();
        if (line.rstrip() == '+' or line.rstrip() == ('+' + header)):
        #if (line.rstrip()[0] == '+'):
            lines.append(line_string);
            lines.append(line.rstrip());
            line_string = '';
        else:
            line_string += line.rstrip();
        next_char = peek(fp, 1);
        num_lines += 1;

    lines.append(line_string);

    return [header, lines];

##############################################################
##############################################################
##############################################################

# Function 'run' should provide a standard interface for running a mapper. Given input parameters, it should run the
# alignment process, and convert any custom output results to the SAM format. Function should return a string with the
# path to the output file.
#    reads_file            Path to a FASTA/FASTQ file containing reads.
#    reference_file        Path to a reference genome FASTA file.
#    machine_name        A symbolic name to specify a set of parameters for a specific sequencing platform.
#    output_path            Folder to which the output will be placed to. Filename will be automatically generated according to the name of the mapper being run.
#    output_suffix        A custom suffix that can be added to the output filename.
# def run(reads_file, reference_file, machine_name, output_path, output_suffix=''):
def run(datasets, output_path):
    ##################################################################################
    ### Sanity check for input datasets.
    ##################################################################################
    machine_name = None
    reads_file = None;
    for dataset in datasets:
        if (machine_name != None and dataset.type != machine_name):
            sys.stderr.write('ERROR: %s is not a hybrid assembler, but datasets from disparate technologies are specified! Exiting.\n');
            exit(1);
        machine_name = dataset.type;
        reads_file = dataset.reads_path;
    if (machine_name == None):
        sys.stderr.write('ERROR: Input datasets not specified correctly! Exiting.\n');
        exit(1);

    if (len(datasets) > 1):
        sys.stderr.write('ERROR: More than one input dataset specified. Only one is expected. Exiting.\n');
        exit(1);

    ##################################################################################
    ### Simple variable definitions.
    ##################################################################################
    ### Reference for running a local job instead of using an SGE cluster:
    ### http://seqanswers.com/forums/showthread.php?t=50937
    num_threads = multiprocessing.cpu_count() / 2;
    output_path = os.path.abspath(output_path);

    ##################################################################################
    ### Backup old assembly results, and create the new output folder.
    ##################################################################################
    if (os.path.exists(output_path)):
        timestamp = strftime("%Y_%m_%d-%H_%M_%S", gmtime());
        os.rename(output_path, '%s.bak_%s' % (output_path, timestamp));
    if (not os.path.exists(output_path)):
        log('Creating a directory on path "%s".' % (output_path), None);
        os.makedirs(output_path);

    ##################################################################################
    ### Prepare a log file.
    ##################################################################################
    log_file = '%s/wrapper_log.txt' % (output_path);
    try:
        fp_log = open(log_file, 'a');
    except Exception, e:
        log('ERROR: Could not open file "%s" for writing! Using only STDERR for logging.' % (log_file), None);
        fp_log = None;

    ##################################################################################
    ### Start the important work.
    ##################################################################################
    used_bin = ''
    if DO_ERROR_CORRECTION:
        used_bin = ASSEMBLER_ECBIN
    else:
        used_bin = ASSEMBLER_BIN
    memtime_path = os.path.join(output_path, ASSEMBLER_NAME + '.memtime')

    spec_file = ''
    if machine_name == 'pacbio':
        spec_file = PACBIO_SPEC
        command = 'cd %s; %s %s -pbCNS -length 500 -partitions 200 -l %s -s %s -fastq %s ' % (output_path, measure_command(memtime_path), used_bin, ASSEMBLER_NAME, spec_file, reads_file)
        execute_command(command, fp_log, dry_run=DRY_RUN);
    elif machine_name == 'nanopore':
        spec_file = OXFORD_SPEC
        command = 'cd %s; %s %s -length 500 -partitions 200 -l %s -s %s -fastq %s ' % (output_path, easure_command(memtime_path), used_bin, ASSEMBLER_NAME, spec_file, reads_file)
        execute_command(command, fp_log, dry_run=DRY_RUN);
    elif machine_name == 'illumina':
        log('\nMachine name "%s" not implemented for %s.\n' % (machine_name, ASSEMBLER_NAME));
        log('Skipping ....\n', fp_log)
        return;
    else:
        log('\nMachine name "%s" not implemented for %s.\n' % (machine_name, ASSEMBLER_NAME));
        log('Skipping ....\n', fp_log)
        return;

    if (fp_log != None):
        fp_log.close();

# A placeholder for a function that runs quast on assembly results
# This is the same for all wrappers at the moment and is done in the main program
def run_quast():
    pass

# A function that gets the results of cgmemtime for a wrapper
# Since some aligners are run multiple times and create multiple measurements
# this is specific for each wrapper
# Returns relevant real time, user time and maximum memory reserved
def get_memtime():
    pass

# This is a standard interface for setting up an assembler. It should assume that the assembler
# is not present localy, but needs to be retrieved, unpacked, compiled and set-up, without requireing
# root privileges.
def download_and_install():
    if os.path.exists(ASSEMBLER_BIN):
        sys.stderr.write('[%s wrapper] Bin found at %s. Skipping installation ...\n' % (ASSEMBLER_NAME, ASSEMBLER_BIN))
    else:
        sys.stderr.write('[%s wrapper] Started installation of %s.\n' % (ASSEMBLER_NAME, ASSEMBLER_NAME))

        if not os.path.exists(ZIP_PATH):
            sys.stderr.write('[%s wrapper] Downloading tar.bz2...\n' % (ASSEMBLER_NAME))
            command = 'cd %s; wget %s' % (basicdefines.ASSEMBLERS_PATH_ROOT_ABS, ASSEMBLER_URL)
            sys.stderr.write('[%s wrapper] %s\n' % (ASSEMBLER_NAME, command))
            subprocess.call(command, shell='True')

        # Decompress
        command = 'cd %s; tar -xvjf %s' % (basicdefines.ASSEMBLERS_PATH_ROOT_ABS, ZIP_FILE)
        sys.stderr.write('[%s wrapper] %s\n' % (ASSEMBLER_NAME, command))
        subprocess.call(command, shell='True')

        # make
        # WGS/Celera comes as precompiled binaries
        # Doesn't require make

# def verbose_usage_and_exit():
#     sys.stderr.write('Usage:\n')
#     sys.stderr.write('\t%s mode [<reads_file> <reference_file> <machine_name> <output_path> [<output_suffix>]]\n' % sys.argv[0])
#     sys.stderr.write('\n')
#     sys.stderr.write('\t- mode - either "run" or "install". Is "install" other parameters can be ommitted.\n')

#     exit(0)

# if __name__ == "__main__":
#     if (len(sys.argv) < 2 or len(sys.argv) > 7):
#         verbose_usage_and_exit()

#     if (sys.argv[1] == 'install'):
#         download_and_install()
#         exit(0)

#     elif (sys.argv[1] == 'run'):
#         if (len(sys.argv) < 6):
#             verbose_usage_and_exit()

#         reads_file = sys.argv[2]
#         reference_file = sys.argv[3]
#         machine_name = sys.argv[4]
#         output_path = sys.argv[5]
#         output_suffix = ''

#         if (len(sys.argv) == 7):
#             output_suffix = sys.argv[6]
#         run(reads_file, reference_file, machine_name, output_path, output_suffix)

#     else:
#         verbose_usage_and_exit()

def verbose_usage_and_exit():
    sys.stderr.write('Usage:\n')
    # sys.stderr.write('\t%s mode [<reads_file1>,<reads_file2>,...,<reads_fileN> <machine_name> <output_path>]\n' % sys.argv[0])
    sys.stderr.write('\t%s mode [<output_path> dataset1 [dataset2 ...]]\n' % sys.argv[0])
    sys.stderr.write('\n')
    sys.stderr.write('\t- mode - either "run" or "install". If "install" other parameters can be omitted.\n')
    sys.stderr.write('\t- dataset - specification of a dataset in the form: reads_type,<reads_path>[<reads_path_b,frag_len,frag_stddev] .\n');
    sys.stderr.write('\t            Reads_type can be nanopore/pacbio/single/paired/mate. If reads_type == "paired" or "mate", last three parameters can be omitted".\n');
    sys.stderr.write('\t            If reads_type == "paired" or "mate", other end of the pair needs to be in another file provided by reads_path_b.\n');
    sys.stderr.write('\n');

    sys.stderr.write('Example:\n');
    sys.stderr.write('\t%s run results/%s nanopore,datasets/reads.fastq\n' % (os.path.basename(sys.argv[0]), ASSEMBLER_NAME));
    sys.stderr.write('\n');

    exit(0)

if __name__ == "__main__":
    if (len(sys.argv) < 2 or len(sys.argv) > 7):
        verbose_usage_and_exit()

    if (sys.argv[1] == 'install'):
        download_and_install()
        exit(0)

    elif (sys.argv[1] == 'run'):
        if (len(sys.argv) < 4):
            verbose_usage_and_exit()

        output_path = sys.argv[2]
        datasets = [];
        for arg in sys.argv[3:]:
            dataset = Dataset(arg);
            datasets.append(dataset);
        run(datasets, output_path);

    else:
        verbose_usage_and_exit()
<commit_msg>Working on unifying the command line for all the wrappers, and to make the run functions more systematic.<commit_after>#! /usr/bin/python

import os
SCRIPT_PATH = os.path.dirname(os.path.realpath(__file__))

import sys
sys.path.append(SCRIPT_PATH + '/../src/')

import subprocess
import multiprocessing
from time import gmtime, strftime

import basicdefines
from dataspec import *

ASSEMBLER_URL = 'http://sourceforge.net/projects/wgs-assembler/files/wgs-assembler/wgs-8.3/wgs-8.3rc2-Linux_amd64.tar.bz2'
ASSEMBLER_PATH = os.path.join(basicdefines.ASSEMBLERS_PATH_ROOT_ABS, 'wgs-8.3rc2')
ZIP_FILE = 'wgs-8.3rc2-Linux_amd64.tar.bz2'
ZIP_PATH = os.path.join(basicdefines.ASSEMBLERS_PATH_ROOT_ABS, ZIP_FILE)
ASSEMBLER_BIN = os.path.join(ASSEMBLER_PATH,'Linux-amd64/bin/runCA')
ASSEMBLER_ECBIN = os.path.join(ASSEMBLER_PATH,'Linux-amd64/bin/PBcR')
ASSEMBLER_NAME = 'PBcR'
ASSEMBLER_RESULTS = 'out/9-terminator/asm.ctg.fasta'
CREATE_OUTPUT_FOLDER = True

PACBIO_SPEC = os.path.join(ASSEMBLER_PATH, 'wgs_pacbio.spec')
OXFORD_SPEC = os.path.join(ASSEMBLER_PATH, 'wgs_oxford.spec')

DO_ERROR_CORRECTION = True

# Run parameters
P_LENGTH = 500
P_PARTITIONS = 200

# DRY_RUN = True;
DRY_RUN = False;

### Logs messages to STDERR and an output log file if provided (opened elsewhere).
def log(message, fp_log):
    timestamp = strftime("%Y/%m/%d %H:%M:%S", gmtime());

    sys.stderr.write('[%s wrapper %s] %s\n' % (ASSEMBLER_NAME, timestamp, message))
    sys.stderr.flush();
    if (fp_log != None):
        fp_log.write('[%s wrapper %s] %s\n' % (ASSEMBLER_NAME, timestamp, message))
        fp_log.flush();

def execute_command(command, fp_log, dry_run=True):
    if (dry_run == True):
        # sys.stderr.write('Warning: dry_run == True\n');
#        sys.stderr.write('[%s wrapper] Executing (dryrun): "%s"\n' % (ASSEMBLER_NAME, command));
        log('Executing (dryrun): "%s".' % (command), fp_log);
    if (dry_run == False):
        # sys.stderr.write('[%s wrapper] Executing: "%s"\n' % (ASSEMBLER_NAME, command));
        log('Executing: "%s".' % (command), fp_log);
        subprocess.call(command, shell=True);
    # sys.stderr.write('\n');
    log('\n', fp_log);

def measure_command(measure_file):
    if (MODULE_BASICDEFINES == True):
        return basicdefines.measure_command(measure_file);
    else:
        sys.stderr.write('ERROR: Cgmemtime tool not found! Exiting.\n');
        exit(1);
        # return '/usr/bin/time --format "Command line: %%C\\nReal time: %%e s\\nCPU time: -1.0 s\\nUser time: %%U s\\nSystem time: %%S s\\nMaximum RSS: %%M kB\\nExit status: %%x" --quiet -o %s ' % measure_file;

def peek(fp, num_chars):
    data = fp.read(num_chars);
    if len(data) == 0:
        return '';
    fp.seek(num_chars * -1, 1);
    return data;

# Returns a single read from the given FASTA/FASTQ file.
# Parameter header contains only the header of the read.
# Parameter lines contains all lines of the read, which include:
# - header
# - seq
# - '+' if FASTQ
# - quals if FASTQ
# Parameter lines is an array of strings, each for one component.
# Please note that multiline FASTA/FASTQ entries (e.g. sequence line)
# will be truncated into one single line.
def get_single_read(fp):
    lines = [];

    line = fp.readline();
    header = line.rstrip();
    header_leading_char = '';
    if (len(header) > 0):
        sequence_separator = header[0];
        header_leading_char = header[0];
        header = header[1:];            # Strip the '>' or '@' sign from the beginning.
    else:
        return ['', []];

    next_char = peek(fp, 1);

    line_string = '';
    lines.append(header_leading_char + header);

    num_lines = 1;
    #while len(next_char) > 0 and next_char != sequence_separator or (next_char == '@' and num_lines < 4):
    while (len(next_char) > 0 and (next_char != sequence_separator or (next_char == '@' and num_lines < 4))):
        line = fp.readline();
        if (line.rstrip() == '+' or line.rstrip() == ('+' + header)):
        #if (line.rstrip()[0] == '+'):
            lines.append(line_string);
            lines.append(line.rstrip());
            line_string = '';
        else:
            line_string += line.rstrip();
        next_char = peek(fp, 1);
        num_lines += 1;

    lines.append(line_string);

    return [header, lines];

##############################################################
##############################################################
##############################################################

# Function 'run' should provide a standard interface for running a mapper. Given input parameters, it should run the
# alignment process, and convert any custom output results to the SAM format. Function should return a string with the
# path to the output file.
#    reads_file            Path to a FASTA/FASTQ file containing reads.
#    reference_file        Path to a reference genome FASTA file.
#    machine_name        A symbolic name to specify a set of parameters for a specific sequencing platform.
#    output_path            Folder to which the output will be placed to. Filename will be automatically generated according to the name of the mapper being run.
#    output_suffix        A custom suffix that can be added to the output filename.
# def run(reads_file, reference_file, machine_name, output_path, output_suffix=''):
def run(datasets, output_path):
    ##################################################################################
    ### Sanity check for input datasets.
    ##################################################################################
    machine_name = None
    reads_file = None;
    for dataset in datasets:
        if (machine_name != None and dataset.type != machine_name):
            sys.stderr.write('ERROR: %s is not a hybrid assembler, but datasets from disparate technologies are specified! Exiting.\n');
            exit(1);
        machine_name = dataset.type;
        reads_file = dataset.reads_path;
    if (machine_name == None):
        sys.stderr.write('ERROR: Input datasets not specified correctly! Exiting.\n');
        exit(1);

    if (len(datasets) > 1):
        sys.stderr.write('ERROR: More than one input dataset specified. Only one is expected. Exiting.\n');
        exit(1);

    ##################################################################################
    ### Simple variable definitions.
    ##################################################################################
    ### Reference for running a local job instead of using an SGE cluster:
    ### http://seqanswers.com/forums/showthread.php?t=50937
    num_threads = multiprocessing.cpu_count() / 2;
    output_path = os.path.abspath(output_path);

    ##################################################################################
    ### Backup old assembly results, and create the new output folder.
    ##################################################################################
    if (os.path.exists(output_path)):
        timestamp = strftime("%Y_%m_%d-%H_%M_%S", gmtime());
        os.rename(output_path, '%s.bak_%s' % (output_path, timestamp));
    if (not os.path.exists(output_path)):
        log('Creating a directory on path "%s".' % (output_path), None);
        os.makedirs(output_path);

    ##################################################################################
    ### Prepare a log file.
    ##################################################################################
    log_file = '%s/wrapper_log.txt' % (output_path);
    try:
        fp_log = open(log_file, 'a');
    except Exception, e:
        log('ERROR: Could not open file "%s" for writing! Using only STDERR for logging.' % (log_file), None);
        fp_log = None;

    ##################################################################################
    ### Start the important work.
    ##################################################################################
    used_bin = ''
    if DO_ERROR_CORRECTION:
        used_bin = ASSEMBLER_ECBIN
    else:
        used_bin = ASSEMBLER_BIN
    memtime_path = os.path.join(output_path, ASSEMBLER_NAME + '.memtime')

    spec_file = ''
    if machine_name == 'pacbio':
        spec_file = PACBIO_SPEC
        command = 'cd %s; %s %s -pbCNS -length 500 -partitions 200 -l %s -s %s -fastq %s ' % (output_path, measure_command(memtime_path), used_bin, ASSEMBLER_NAME, spec_file, reads_file)
        execute_command(command, fp_log, dry_run=DRY_RUN);
    elif machine_name == 'nanopore':
        spec_file = OXFORD_SPEC
        command = 'cd %s; %s %s -length 500 -partitions 200 -l %s -s %s -fastq %s ' % (output_path, easure_command(memtime_path), used_bin, ASSEMBLER_NAME, spec_file, reads_file)
        execute_command(command, fp_log, dry_run=DRY_RUN);
    elif machine_name == 'illumina':
        log('\nMachine name "%s" not implemented for %s.\n' % (machine_name, ASSEMBLER_NAME));
        log('Skipping ....\n', fp_log)
        return;
    else:
        log('\nMachine name "%s" not implemented for %s.\n' % (machine_name, ASSEMBLER_NAME));
        log('Skipping ....\n', fp_log)
        return;

    if (fp_log != None):
        fp_log.close();

# A placeholder for a function that runs quast on assembly results
# This is the same for all wrappers at the moment and is done in the main program
def run_quast():
    pass

# A function that gets the results of cgmemtime for a wrapper
# Since some aligners are run multiple times and create multiple measurements
# this is specific for each wrapper
# Returns relevant real time, user time and maximum memory reserved
def get_memtime():
    pass

# This is a standard interface for setting up an assembler. It should assume that the assembler
# is not present localy, but needs to be retrieved, unpacked, compiled and set-up, without requireing
# root privileges.
def download_and_install():
    if os.path.exists(ASSEMBLER_BIN):
        sys.stderr.write('[%s wrapper] Bin found at %s. Skipping installation ...\n' % (ASSEMBLER_NAME, ASSEMBLER_BIN))
    else:
        sys.stderr.write('[%s wrapper] Started installation of %s.\n' % (ASSEMBLER_NAME, ASSEMBLER_NAME))

        if not os.path.exists(ZIP_PATH):
            sys.stderr.write('[%s wrapper] Downloading tar.bz2...\n' % (ASSEMBLER_NAME))
            command = 'cd %s; wget %s' % (basicdefines.ASSEMBLERS_PATH_ROOT_ABS, ASSEMBLER_URL)
            sys.stderr.write('[%s wrapper] %s\n' % (ASSEMBLER_NAME, command))
            subprocess.call(command, shell='True')

        # Decompress
        command = 'cd %s; tar -xvjf %s' % (basicdefines.ASSEMBLERS_PATH_ROOT_ABS, ZIP_FILE)
        sys.stderr.write('[%s wrapper] %s\n' % (ASSEMBLER_NAME, command))
        subprocess.call(command, shell='True')

        # make
        # WGS/Celera comes as precompiled binaries
        # Doesn't require make

# def verbose_usage_and_exit():
#     sys.stderr.write('Usage:\n')
#     sys.stderr.write('\t%s mode [<reads_file> <reference_file> <machine_name> <output_path> [<output_suffix>]]\n' % sys.argv[0])
#     sys.stderr.write('\n')
#     sys.stderr.write('\t- mode - either "run" or "install". Is "install" other parameters can be ommitted.\n')

#     exit(0)

# if __name__ == "__main__":
#     if (len(sys.argv) < 2 or len(sys.argv) > 7):
#         verbose_usage_and_exit()

#     if (sys.argv[1] == 'install'):
#         download_and_install()
#         exit(0)

#     elif (sys.argv[1] == 'run'):
#         if (len(sys.argv) < 6):
#             verbose_usage_and_exit()

#         reads_file = sys.argv[2]
#         reference_file = sys.argv[3]
#         machine_name = sys.argv[4]
#         output_path = sys.argv[5]
#         output_suffix = ''

#         if (len(sys.argv) == 7):
#             output_suffix = sys.argv[6]
#         run(reads_file, reference_file, machine_name, output_path, output_suffix)

#     else:
#         verbose_usage_and_exit()

def verbose_usage_and_exit():
    sys.stderr.write('Usage:\n')
    # sys.stderr.write('\t%s mode [<reads_file1>,<reads_file2>,...,<reads_fileN> <machine_name> <output_path>]\n' % sys.argv[0])
    sys.stderr.write('\t%s mode [<output_path> dataset1 [dataset2 ...]]\n' % sys.argv[0])
    sys.stderr.write('\n')
    sys.stderr.write('\t- mode - either "run" or "install". If "install" other parameters can be omitted.\n')
    sys.stderr.write('\t- dataset - specification of a dataset in the form: reads_type,<reads_path>[<reads_path_b,frag_len,frag_stddev] .\n');
    sys.stderr.write('\t            Reads_type can be nanopore/pacbio/single/paired/mate. If reads_type == "paired" or "mate", last three parameters can be omitted".\n');
    sys.stderr.write('\t            If reads_type == "paired" or "mate", other end of the pair needs to be in another file provided by reads_path_b.\n');
    sys.stderr.write('\n');

    sys.stderr.write('Example:\n');
    sys.stderr.write('\t%s run results/%s nanopore,datasets/reads.fastq\n' % (os.path.basename(sys.argv[0]), ASSEMBLER_NAME));
    sys.stderr.write('\n');

    exit(0)

if __name__ == "__main__":
    if (len(sys.argv) < 2 or len(sys.argv) > 7):
        verbose_usage_and_exit()

    if (sys.argv[1] == 'install'):
        download_and_install()
        exit(0)

    elif (sys.argv[1] == 'run'):
        if (len(sys.argv) < 4):
            verbose_usage_and_exit()

        output_path = sys.argv[2]
        datasets = [];
        for arg in sys.argv[3:]:
            dataset = Dataset(arg);
            datasets.append(dataset);
        run(datasets, output_path);

    else:
        verbose_usage_and_exit()
<|endoftext|>


<commit_before>'''Build an admin interface for pages and page-related things
'''
import functools
import urlparse

from django import http
from django.conf import settings
from django.conf.urls import defaults as urls
from django.contrib import admin
from django.core import exceptions, urlresolvers
from django.db import transaction
from django.views.decorators import csrf
from django.utils import decorators, encoding, functional, html, safestring
from django.utils.translation import ugettext as _

import forms
import models

csrf_protect_m = decorators.method_decorator(csrf.csrf_protect)

def back_redirect(request):
    '''Generate response to redirect ro previous page
    '''
    if 'HTTP_REFERER' in request.META:
        url = urlparse.urljoin(request.META['HTTP_REFERER'],
                               request.META['QUERY_STRING'])
    else:
        url = '/admin/'
    return http.HttpResponseRedirect(url)

class ActivityMixin(admin.ModelAdmin):
    '''Mixin
    '''
    def do_change_active(obj):
        '''Change delete status
        '''
        is_active = obj.is_active
        icon = is_active and 'icon-yes.gif' or 'icon-no.gif'
        action = is_active and 'deactivate' or 'activate'
        msg = is_active and 'Restore file' or 'Delete file'
        return safestring.mark_safe('''

            ''' % (msg, obj.pk, action, msg, settings.STATIC_URL, icon))
    do_change_active.allow_tags = True
    do_change_active.short_description = _('is active')
    do_change_active = staticmethod(do_change_active)

    def change_active(self, request, object_id, is_active):
        '''Change document deleted state
        '''
        obj = self.get_object(request, object_id)
        if obj.is_active != is_active:
            obj.is_active = is_active
            obj.save()
        return back_redirect(request)

    def get_urls(self):
        """Get urls for make object active/inactive
        """
        def wrap(view):
            '''Wrap object with permissions checking
            '''
            def wrapper(*args, **kwargs):
                '''View wrapper
                '''
                return self.admin_site.admin_view(view)(*args, **kwargs)
            return functools.update_wrapper(wrapper, view)

        info = self.model._meta.app_label, self.model._meta.module_name
        urlpatterns = urls.patterns('',
            urls.url(r'^(.+)/activate/$', wrap(self.change_active),
                     {'is_active': True}, name='%s_%s_change' % info, ),
            urls.url(r'^(.+)/deactivate/$', wrap(self.change_active),
                     {'is_active': False}, name='%s_%s_change' % info, ),
        )
        return urlpatterns + super(ActivityMixin, self).get_urls()

class LanguageAdmin(admin.ModelAdmin):
    '''Class represents admin interface for language model
    '''
    model = models.Language
    list_display = ('name', 'raw_code', )

admin.site.register(models.Language, LanguageAdmin)

class LayoutAdmin(admin.ModelAdmin):
    '''Admin iterface for layouts list
    '''
    model = models.Layout
    list_display = ('name', 'template', 'is_default', 'is_active', )
    fields = ('name', 'template', 'is_default', 'is_active', )

admin.site.register(models.Layout, LayoutAdmin)

class PageAdmin(admin.ModelAdmin):
    '''Class represents admin interface for page model
    '''
    model = models.Page
    add_form_template = 'admin/page_change_form.html'
    change_form_template = 'admin/page_change_form.html'
    search_fields = ('translations__header', 'translations__title',
                     'translations__alias', )
    list_filter = ('translations__layout', )
    list_display = ('title', 'alias', 'layout', )

    def title(self, obj):
        '''Get title
        '''
        return unicode(obj)
    title.short_description = _('title')

    def alias(self, obj):
        '''Get alias
        '''
        return obj.get_translation().alias
    alias.short_description = _('alias')

    def layout(self, obj):
        '''Get layout
        '''
        return obj.get_translation().layout
    layout.short_description = _('layout')

    def get_urls(self):
        '''Get urls accessible in admin interface
        '''
        def wrap(view):
            def wrapper(*args, **kwargs):
                return self.admin_site.admin_view(view)(*args, **kwargs)
            return functools.update_wrapper(wrapper, view)

        info = self.model._meta.app_label, self.model._meta.module_name

        return urls.patterns('',
            urls.url('^get_layout_form/(?P<page_id>\w+)/(?P<layout_id>\w+)/' +
                     '(?P<lang_code>\w+)$',
                     wrap(self.layout_view),
                     name='%s_%s_get_layout_form' % info),
            urls.url('^get_layout_form/(?P<layout_id>\w+)/(?P<lang_code>\w+)$',
                     wrap(self.layout_view),
                     name='%s_%s_get_layout_form' % info),
        ) + super(PageAdmin, self).get_urls()

    def get_placeholders(self, template_name):
        '''Get a list of placeholders for layout
        '''
        aliases = settings.PAGES_TEMPLATES_PLACEHOLDERS.get(template_name, ())
        return [models.Placeholder.objects.get_or_create(alias=alias)[0]
                for alias in aliases]

    def render_layout_form(self, language, layout, page):
        '''
        '''
        from django.template import loader
        if page:
            def get_instance(place):
                return models.PageArticle.objects.get_or_create(layout=layout,
                                                    page=page, place=place)[0]
        else:
            get_instance = lambda __: None

        formset = [forms.PageContentForm(None, layout=layout, place=place,
                                         instance=get_instance(place),
                                         language=language)
                   for place in self.get_placeholders(layout.template)]
        return loader.render_to_string('admin/includes/content_form.html',
                                       {'formset': formset})

    @csrf_protect_m
    def layout_view(self, request, page_id=None, layout_id=None,
                    lang_code=None):
        '''Get a lyout
        '''
        # Select language
        lang_code = lang_code or settings.LANGUAGE_CODE
        lang = models.Language.objects.get(code=lang_code)
        # Select layout
        layout_manager = models.Layout.objects
        layout = (layout_manager.get(id=layout_id) if layout_id
                  else self.default_layout)
        # Select page
        if page_id:
            page = models.PageTranslation.objects.get(page_id=page_id,
                                                      language=lang)
        else:
            page = None

        return http.HttpResponse(self.render_layout_form(lang, layout, page))

    @functional.cached_property
    def default_layout(self):
        '''Get default layout
        '''
        return models.Layout.objects.get_default()

    def validate_forms(self, forms):
        '''Validate a list of forms
        '''
        return functools.reduce(lambda valid, form: form.is_valid() and valid,
                                forms, True)

    def validate_inlines(self, translations):
        '''Validate a list forms for contents
        '''
        return functools.reduce(
                lambda valid, transl:
                        self.validate_forms(transl.content_forms) and valid,
                translations, True)

    def get_translation_forms(self, data=None, page=None):
        '''Get a list of forms for different languages
        '''
        if page:
            get_instance = lambda lang: models.PageTranslation.objects.get(
                                                    page=page, language=lang)
        else:
            get_instance = lambda __: None
        return [forms.PageTranslationForm(data, language=language,
                                instance=get_instance(language), page=page,
                                initial={'is_active': True,
                                         'layout__id': self.default_layout.id})
                for language in models.Language.objects.all()]

    def get_layout_forms(self, translations, data=None, page=None):
        '''Get layout forms
        '''
        if page:
            def get_instance(transl, place, layout):
                page_translation = models.PageTranslation.objects.get(
                                        page=page, language=transl.language)
                return models.PageArticle.objects.get_or_create(layout=layout,
                                        page=page_translation, place=place)[0]
        else:
            get_instance = lambda __, ___, ____: None
        for translation in translations:
            layout = translation.layout or self.default_layout
            translation.content_forms = [
                forms.PageContentForm(data, layout=layout, place=placeholder,
                    instance=get_instance(translation, placeholder, layout),
                    language=translation.language)
                for placeholder in self.get_placeholders(layout.template)]

    def save_data(self, request, new_object, form, translations):
        '''Save model and translations with whole data
        '''
        self.save_model(request, new_object, form, True)
        for translation in translations:
            tranls_obj = translation.save(page=new_object)
            for content in translation.content_forms:
                content.save(page=tranls_obj)

    @csrf_protect_m
    @transaction.commit_on_success
    def add_view(self, request, form_url='', extra_context=None):
        '''The 'add' admin view for this model.
        '''
        model = self.model
        opts = model._meta

        if not self.has_add_permission(request):
            raise exceptions.PermissionDenied

        ModelForm = self.get_form(request)
        if request.method == 'POST':
            # Trying to create new post
            form = ModelForm(request.POST, request.FILES)
            if form.is_valid():
                new_object = self.save_form(request, form, change=False)
                form_validated = True
            else:
                form_validated = False
                new_object = self.model()
            # Validate additional data
            translations = self.get_translation_forms(request.POST)
            transl_valid = self.validate_forms(translations)
            self.get_layout_forms(translations, request.POST)
            inlines_valid = self.validate_inlines(translations)
            # If data valid can save results
            if form_validated and transl_valid and inlines_valid:
                self.log_addition(request, new_object)
                self.save_data(request, new_object, form, translations)
                return self.response_add(request, new_object)
        else:
            # Prepare the dict of initial data from the request.
            initial = dict(request.GET.items())
            for k in initial:
                try:
                    field = opts.get_field(k)
                except models.FieldDoesNotExist:
                    continue
                if isinstance(field, models.ManyToManyField):
                    initial[k] = initial[k].split(",")
            form = ModelForm(initial=initial)
            # Prepare translations
            translations = self.get_translation_forms()
            self.get_layout_forms(translations)
        # Create an admin form
        adminForm = admin.helpers.AdminForm(form,
                                        list(self.get_fieldsets(request)),
                                        self.get_prepopulated_fields(request),
                                        self.get_readonly_fields(request),
                                        model_admin=self)
        media = self.media + adminForm.media

        context = {
            'title': _('Add %s') % encoding.force_unicode(opts.verbose_name),
            'adminform': adminForm,
            'is_popup': "_popup" in request.REQUEST,
            'show_delete': False,
            'media': media,
            'errors': admin.helpers.AdminErrorList(form, []),
            'app_label': opts.app_label,
            'translations': translations
        }
        context.update(extra_context or {})
        return self.render_change_form(request, context, form_url=form_url,
                                       add=True)

    @csrf_protect_m
    @transaction.commit_on_success
    def change_view(self, request, object_id, form_url='', extra_context=None):
        "The 'change' admin view for this model."
        model = self.model
        opts = model._meta

        obj = self.get_object(request, admin.util.unquote(object_id))

        if not self.has_change_permission(request, obj):
            raise exceptions.PermissionDenied

        if obj is None:
            raise exceptions.Http404(
                _('%(name)s object with primary key %(key)r does not exist.') %
                           {'name': encoding.force_unicode(opts.verbose_name),
                            'key': html.escape(object_id)})

        if request.method == 'POST' and "_saveasnew" in request.POST:
            url = urlresolvers.reverse('admin:%s_%s_add' %
                                       (opts.app_label, opts.module_name),
                                       current_app=self.admin_site.name)
            return self.add_view(request, form_url=url)

        ModelForm = self.get_form(request, obj)
        if request.method == 'POST':
            # Validate save form
            form = ModelForm(request.POST, request.FILES, instance=obj)

            if form.is_valid():
                form_validated = True
                new_object = self.save_form(request, form, change=True)
            else:
                form_validated = False
                new_object = obj
            # Validate translations, conten
            translations = self.get_translation_forms(request.POST, obj)
            transl_valid = self.validate_forms(translations)
            self.get_layout_forms(translations, request.POST, obj)
            inlines_valid = self.validate_inlines(translations)
            # If all valid real save
            if form_validated and transl_valid and inlines_valid:
                self.save_data(request, new_object, form, translations)
                change_message = self.construct_change_message(request, form,
                                                               [])
                self.log_change(request, new_object, change_message)
                return self.response_change(request, new_object)
        else:
            # Create new form
            form = ModelForm(instance=obj)
            translations = self.get_translation_forms(page=obj)
            self.get_layout_forms(translations, None, obj)

        adminForm = admin.helpers.AdminForm(form,
                                    self.get_fieldsets(request, obj),
                                    self.get_prepopulated_fields(request, obj),
                                    self.get_readonly_fields(request, obj),
                                    model_admin=self)
        media = self.media + adminForm.media

        context = {
            'title': _('Change %s') %
                     encoding.force_unicode(opts.verbose_name),
            'adminform': adminForm,
            'object_id': object_id,
            'original': obj,
            'is_popup': "_popup" in request.REQUEST,
            'media': media,
            'errors': admin.helpers.AdminErrorList(form, []),
            'app_label': opts.app_label,
            'translations': translations
        }
        context.update(extra_context or {})
        return self.render_change_form(request, context, change=True, obj=obj,
                                       form_url=form_url)

admin.site.register(models.Page, PageAdmin)

class MenuAdmin(ActivityMixin):
    '''Admin interface for menus
    '''
    model = models.Menu
    form = forms.MenuForm
    list_display = ('name', 'alias', ActivityMixin.do_change_active, )

    def save_related(self, request, form, formsets, change):
        """Given the ``HttpRequest``, the parent ``ModelForm`` instance, the
        list of inline formsets and a boolean value based on whether the
        parent is being added or changed, save the related objects to the
        database. Note that at this point save_form() and save_model() have
        already been called.
        """
        for formset in formsets:
            self.save_formset(request, form, formset, change=change)

admin.site.register(models.Menu, MenuAdmin)
admin.site.register(models.MenuItem)
<commit_msg>Fix urls import in admin<commit_after>'''Build an admin interface for pages and page-related things
'''
import functools
import urlparse

from django import http
from django.conf import settings
try:
    from django.conf.urls import defaults as urls
except:
    from django.conf import urls
from django.contrib import admin
from django.core import exceptions, urlresolvers
from django.db import transaction
from django.views.decorators import csrf
from django.utils import decorators, encoding, functional, html, safestring
from django.utils.translation import ugettext as _

import forms
import models

csrf_protect_m = decorators.method_decorator(csrf.csrf_protect)

def back_redirect(request):
    '''Generate response to redirect ro previous page
    '''
    if 'HTTP_REFERER' in request.META:
        url = urlparse.urljoin(request.META['HTTP_REFERER'],
                               request.META['QUERY_STRING'])
    else:
        url = '/admin/'
    return http.HttpResponseRedirect(url)

class ActivityMixin(admin.ModelAdmin):
    '''Mixin
    '''
    def do_change_active(obj):
        '''Change delete status
        '''
        is_active = obj.is_active
        icon = is_active and 'icon-yes.gif' or 'icon-no.gif'
        action = is_active and 'deactivate' or 'activate'
        msg = is_active and 'Restore file' or 'Delete file'
        return safestring.mark_safe('''

            ''' % (msg, obj.pk, action, msg, settings.STATIC_URL, icon))
    do_change_active.allow_tags = True
    do_change_active.short_description = _('is active')
    do_change_active = staticmethod(do_change_active)

    def change_active(self, request, object_id, is_active):
        '''Change document deleted state
        '''
        obj = self.get_object(request, object_id)
        if obj.is_active != is_active:
            obj.is_active = is_active
            obj.save()
        return back_redirect(request)

    def get_urls(self):
        """Get urls for make object active/inactive
        """
        def wrap(view):
            '''Wrap object with permissions checking
            '''
            def wrapper(*args, **kwargs):
                '''View wrapper
                '''
                return self.admin_site.admin_view(view)(*args, **kwargs)
            return functools.update_wrapper(wrapper, view)

        info = self.model._meta.app_label, self.model._meta.module_name
        urlpatterns = urls.patterns('',
            urls.url(r'^(.+)/activate/$', wrap(self.change_active),
                     {'is_active': True}, name='%s_%s_change' % info, ),
            urls.url(r'^(.+)/deactivate/$', wrap(self.change_active),
                     {'is_active': False}, name='%s_%s_change' % info, ),
        )
        return urlpatterns + super(ActivityMixin, self).get_urls()

class LanguageAdmin(admin.ModelAdmin):
    '''Class represents admin interface for language model
    '''
    model = models.Language
    list_display = ('name', 'raw_code', )

admin.site.register(models.Language, LanguageAdmin)

class LayoutAdmin(admin.ModelAdmin):
    '''Admin iterface for layouts list
    '''
    model = models.Layout
    list_display = ('name', 'template', 'is_default', 'is_active', )
    fields = ('name', 'template', 'is_default', 'is_active', )

admin.site.register(models.Layout, LayoutAdmin)

class PageAdmin(admin.ModelAdmin):
    '''Class represents admin interface for page model
    '''
    model = models.Page
    add_form_template = 'admin/page_change_form.html'
    change_form_template = 'admin/page_change_form.html'
    search_fields = ('translations__header', 'translations__title',
                     'translations__alias', )
    list_filter = ('translations__layout', )
    list_display = ('title', 'alias', 'layout', )

    def title(self, obj):
        '''Get title
        '''
        return unicode(obj)
    title.short_description = _('title')

    def alias(self, obj):
        '''Get alias
        '''
        return obj.get_translation().alias
    alias.short_description = _('alias')

    def layout(self, obj):
        '''Get layout
        '''
        return obj.get_translation().layout
    layout.short_description = _('layout')

    def get_urls(self):
        '''Get urls accessible in admin interface
        '''
        def wrap(view):
            def wrapper(*args, **kwargs):
                return self.admin_site.admin_view(view)(*args, **kwargs)
            return functools.update_wrapper(wrapper, view)

        info = self.model._meta.app_label, self.model._meta.module_name

        return urls.patterns('',
            urls.url('^get_layout_form/(?P<page_id>\w+)/(?P<layout_id>\w+)/' +
                     '(?P<lang_code>\w+)$',
                     wrap(self.layout_view),
                     name='%s_%s_get_layout_form' % info),
            urls.url('^get_layout_form/(?P<layout_id>\w+)/(?P<lang_code>\w+)$',
                     wrap(self.layout_view),
                     name='%s_%s_get_layout_form' % info),
        ) + super(PageAdmin, self).get_urls()

    def get_placeholders(self, template_name):
        '''Get a list of placeholders for layout
        '''
        aliases = settings.PAGES_TEMPLATES_PLACEHOLDERS.get(template_name, ())
        return [models.Placeholder.objects.get_or_create(alias=alias)[0]
                for alias in aliases]

    def render_layout_form(self, language, layout, page):
        '''
        '''
        from django.template import loader
        if page:
            def get_instance(place):
                return models.PageArticle.objects.get_or_create(layout=layout,
                                                    page=page, place=place)[0]
        else:
            get_instance = lambda __: None

        formset = [forms.PageContentForm(None, layout=layout, place=place,
                                         instance=get_instance(place),
                                         language=language)
                   for place in self.get_placeholders(layout.template)]
        return loader.render_to_string('admin/includes/content_form.html',
                                       {'formset': formset})

    @csrf_protect_m
    def layout_view(self, request, page_id=None, layout_id=None,
                    lang_code=None):
        '''Get a lyout
        '''
        # Select language
        lang_code = lang_code or settings.LANGUAGE_CODE
        lang = models.Language.objects.get(code=lang_code)
        # Select layout
        layout_manager = models.Layout.objects
        layout = (layout_manager.get(id=layout_id) if layout_id
                  else self.default_layout)
        # Select page
        if page_id:
            page = models.PageTranslation.objects.get(page_id=page_id,
                                                      language=lang)
        else:
            page = None

        return http.HttpResponse(self.render_layout_form(lang, layout, page))

    @functional.cached_property
    def default_layout(self):
        '''Get default layout
        '''
        return models.Layout.objects.get_default()

    def validate_forms(self, forms):
        '''Validate a list of forms
        '''
        return functools.reduce(lambda valid, form: form.is_valid() and valid,
                                forms, True)

    def validate_inlines(self, translations):
        '''Validate a list forms for contents
        '''
        return functools.reduce(
                lambda valid, transl:
                        self.validate_forms(transl.content_forms) and valid,
                translations, True)

    def get_translation_forms(self, data=None, page=None):
        '''Get a list of forms for different languages
        '''
        if page:
            get_instance = lambda lang: models.PageTranslation.objects.get(
                                                    page=page, language=lang)
        else:
            get_instance = lambda __: None
        return [forms.PageTranslationForm(data, language=language,
                                instance=get_instance(language), page=page,
                                initial={'is_active': True,
                                         'layout__id': self.default_layout.id})
                for language in models.Language.objects.all()]

    def get_layout_forms(self, translations, data=None, page=None):
        '''Get layout forms
        '''
        if page:
            def get_instance(transl, place, layout):
                page_translation = models.PageTranslation.objects.get(
                                        page=page, language=transl.language)
                return models.PageArticle.objects.get_or_create(layout=layout,
                                        page=page_translation, place=place)[0]
        else:
            get_instance = lambda __, ___, ____: None
        for translation in translations:
            layout = translation.layout or self.default_layout
            translation.content_forms = [
                forms.PageContentForm(data, layout=layout, place=placeholder,
                    instance=get_instance(translation, placeholder, layout),
                    language=translation.language)
                for placeholder in self.get_placeholders(layout.template)]

    def save_data(self, request, new_object, form, translations):
        '''Save model and translations with whole data
        '''
        self.save_model(request, new_object, form, True)
        for translation in translations:
            tranls_obj = translation.save(page=new_object)
            for content in translation.content_forms:
                content.save(page=tranls_obj)

    @csrf_protect_m
    @transaction.commit_on_success
    def add_view(self, request, form_url='', extra_context=None):
        '''The 'add' admin view for this model.
        '''
        model = self.model
        opts = model._meta

        if not self.has_add_permission(request):
            raise exceptions.PermissionDenied

        ModelForm = self.get_form(request)
        if request.method == 'POST':
            # Trying to create new post
            form = ModelForm(request.POST, request.FILES)
            if form.is_valid():
                new_object = self.save_form(request, form, change=False)
                form_validated = True
            else:
                form_validated = False
                new_object = self.model()
            # Validate additional data
            translations = self.get_translation_forms(request.POST)
            transl_valid = self.validate_forms(translations)
            self.get_layout_forms(translations, request.POST)
            inlines_valid = self.validate_inlines(translations)
            # If data valid can save results
            if form_validated and transl_valid and inlines_valid:
                self.log_addition(request, new_object)
                self.save_data(request, new_object, form, translations)
                return self.response_add(request, new_object)
        else:
            # Prepare the dict of initial data from the request.
            initial = dict(request.GET.items())
            for k in initial:
                try:
                    field = opts.get_field(k)
                except models.FieldDoesNotExist:
                    continue
                if isinstance(field, models.ManyToManyField):
                    initial[k] = initial[k].split(",")
            form = ModelForm(initial=initial)
            # Prepare translations
            translations = self.get_translation_forms()
            self.get_layout_forms(translations)
        # Create an admin form
        adminForm = admin.helpers.AdminForm(form,
                                        list(self.get_fieldsets(request)),
                                        self.get_prepopulated_fields(request),
                                        self.get_readonly_fields(request),
                                        model_admin=self)
        media = self.media + adminForm.media

        context = {
            'title': _('Add %s') % encoding.force_unicode(opts.verbose_name),
            'adminform': adminForm,
            'is_popup': "_popup" in request.REQUEST,
            'show_delete': False,
            'media': media,
            'errors': admin.helpers.AdminErrorList(form, []),
            'app_label': opts.app_label,
            'translations': translations
        }
        context.update(extra_context or {})
        return self.render_change_form(request, context, form_url=form_url,
                                       add=True)

    @csrf_protect_m
    @transaction.commit_on_success
    def change_view(self, request, object_id, form_url='', extra_context=None):
        "The 'change' admin view for this model."
        model = self.model
        opts = model._meta

        obj = self.get_object(request, admin.util.unquote(object_id))

        if not self.has_change_permission(request, obj):
            raise exceptions.PermissionDenied

        if obj is None:
            raise exceptions.Http404(
                _('%(name)s object with primary key %(key)r does not exist.') %
                           {'name': encoding.force_unicode(opts.verbose_name),
                            'key': html.escape(object_id)})

        if request.method == 'POST' and "_saveasnew" in request.POST:
            url = urlresolvers.reverse('admin:%s_%s_add' %
                                       (opts.app_label, opts.module_name),
                                       current_app=self.admin_site.name)
            return self.add_view(request, form_url=url)

        ModelForm = self.get_form(request, obj)
        if request.method == 'POST':
            # Validate save form
            form = ModelForm(request.POST, request.FILES, instance=obj)

            if form.is_valid():
                form_validated = True
                new_object = self.save_form(request, form, change=True)
            else:
                form_validated = False
                new_object = obj
            # Validate translations, conten
            translations = self.get_translation_forms(request.POST, obj)
            transl_valid = self.validate_forms(translations)
            self.get_layout_forms(translations, request.POST, obj)
            inlines_valid = self.validate_inlines(translations)
            # If all valid real save
            if form_validated and transl_valid and inlines_valid:
                self.save_data(request, new_object, form, translations)
                change_message = self.construct_change_message(request, form,
                                                               [])
                self.log_change(request, new_object, change_message)
                return self.response_change(request, new_object)
        else:
            # Create new form
            form = ModelForm(instance=obj)
            translations = self.get_translation_forms(page=obj)
            self.get_layout_forms(translations, None, obj)

        adminForm = admin.helpers.AdminForm(form,
                                    self.get_fieldsets(request, obj),
                                    self.get_prepopulated_fields(request, obj),
                                    self.get_readonly_fields(request, obj),
                                    model_admin=self)
        media = self.media + adminForm.media

        context = {
            'title': _('Change %s') %
                     encoding.force_unicode(opts.verbose_name),
            'adminform': adminForm,
            'object_id': object_id,
            'original': obj,
            'is_popup': "_popup" in request.REQUEST,
            'media': media,
            'errors': admin.helpers.AdminErrorList(form, []),
            'app_label': opts.app_label,
            'translations': translations
        }
        context.update(extra_context or {})
        return self.render_change_form(request, context, change=True, obj=obj,
                                       form_url=form_url)

admin.site.register(models.Page, PageAdmin)

class MenuAdmin(ActivityMixin):
    '''Admin interface for menus
    '''
    model = models.Menu
    form = forms.MenuForm
    list_display = ('name', 'alias', ActivityMixin.do_change_active, )

    def save_related(self, request, form, formsets, change):
        """Given the ``HttpRequest``, the parent ``ModelForm`` instance, the
        list of inline formsets and a boolean value based on whether the
        parent is being added or changed, save the related objects to the
        database. Note that at this point save_form() and save_model() have
        already been called.
        """
        for formset in formsets:
            self.save_formset(request, form, formset, change=change)

admin.site.register(models.Menu, MenuAdmin)
admin.site.register(models.MenuItem)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

# ***************************************************************************
# *                                                                         *
# *   Copyright (c) 2017 sliptonic <shopinthewoods@gmail.com>               *
# *                                                                         *
# *   This program is free software; you can redistribute it and/or modify  *
# *   it under the terms of the GNU Lesser General Public License (LGPL)    *
# *   as published by the Free Software Foundation; either version 2 of     *
# *   the License, or (at your option) any later version.                   *
# *   for detail see the LICENCE text file.                                 *
# *                                                                         *
# *   This program is distributed in the hope that it will be useful,       *
# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
# *   GNU Library General Public License for more details.                  *
# *                                                                         *
# *   You should have received a copy of the GNU Library General Public     *
# *   License along with this program; if not, write to the Free Software   *
# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
# *   USA                                                                   *
# *                                                                         *
# ***************************************************************************

import FreeCAD
import PathScripts.PathAreaOp as PathAreaOp
import PathScripts.PathLog as PathLog
import PathScripts.PathOp as PathOp

from PySide import QtCore

__title__ = "Base Path Profile Operation"
__author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
__doc__ = "Base class and implementation for Path profile operations."

if False:
    PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
    PathLog.trackModule(PathLog.thisModule())
else:
    PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())

# Qt tanslation handling
def translate(context, text, disambig=None):
    return QtCore.QCoreApplication.translate(context, text, disambig)

class ObjectProfile(PathAreaOp.ObjectOp):
    '''Base class for proxy objects of all profile operations.'''

    def initAreaOp(self, obj):
        '''initAreaOp(obj) ... creates all profile specific properties.
        Do not overwrite.'''
        # Profile Properties
        obj.addProperty("App::PropertyEnumeration", "Side", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Side of edge that tool should cut"))
        obj.Side = ['Outside', 'Inside']  # side of profile that cutter is on in relation to direction of profile
        obj.addProperty("App::PropertyEnumeration", "Direction", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW"))
        obj.Direction = ['CW', 'CCW']  # this is the direction that the profile runs
        obj.addProperty("App::PropertyBool", "UseComp", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "make True, if using Cutter Radius Compensation"))

        obj.addProperty("App::PropertyDistance", "OffsetExtra", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Extra value to stay away from final profile- good for roughing toolpath"))
        obj.addProperty("App::PropertyEnumeration", "JoinType", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Controls how tool moves around corners. Default=Round"))
        obj.JoinType = ['Round', 'Square', 'Miter']  # this is the direction that the Profile runs
        obj.addProperty("App::PropertyFloat", "MiterLimit", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Maximum distance before a miter join is truncated"))
        obj.setEditorMode('MiterLimit', 2)

    def areaOpOnChanged(self, obj, prop):
        '''areaOpOnChanged(obj, prop) ... updates Side and MiterLimit visibility depending on changed properties.
        Do not overwrite.'''
        if prop == "UseComp":
            if not obj.UseComp:
                obj.setEditorMode('Side', 2)
            else:
                obj.setEditorMode('Side', 0)

        if prop == 'JoinType':
            if obj.JoinType == 'Miter':
                obj.setEditorMode('MiterLimit', 0)
            else:
                obj.setEditorMode('MiterLimit', 2)

    def areaOpAreaParams(self, obj, isHole):
        '''areaOpAreaParams(obj, isHole) ... returns dictionary with area parameters.
        Do not overwrite.'''
        params = {}
        params['Fill'] = 0
        params['Coplanar'] = 0
        params['SectionCount'] = -1

        offset = 0.0
        if obj.UseComp:
            offset = self.radius + obj.OffsetExtra.Value
        if obj.Side == 'Inside':
            offset = 0 - offset
        if isHole:
            offset = 0 - offset
        params['Offset'] = offset

        jointype = ['Round', 'Square', 'Miter']
        params['JoinType'] = jointype.index(obj.JoinType)

        if obj.JoinType == 'Miter':
            params['MiterLimit'] = obj.MiterLimit

        return params

    def areaOpPathParams(self, obj, isHole):
        '''areaOpPathParams(obj, isHole) ... returns dictionary with path parameters.
        Do not overwrite.'''
        params = {}

        # Reverse the direction for holes
        if isHole:
            direction = "CW" if obj.Direction == "CCW" else "CCW"
        else:
            direction = obj.Direction

        if direction == 'CCW':
            params['orientation'] = 0
        else:
            params['orientation'] = 1

        return params

    def areaOpUseProjection(self, obj):
        '''areaOpUseProjection(obj) ... returns True'''
        return True

    def areaOpSetDefaultValues(self, obj):
        '''areaOpSetDefaultValues(obj) ... sets default values.
        Do not overwrite.'''
        obj.Side = "Outside"
        obj.OffsetExtra = 0.0
        obj.Direction = "CW"
        obj.UseComp = True
        obj.JoinType = "Round"
        obj.MiterLimit = 0.1

<commit_msg>fixes #3284<commit_after># -*- coding: utf-8 -*-

# ***************************************************************************
# *                                                                         *
# *   Copyright (c) 2017 sliptonic <shopinthewoods@gmail.com>               *
# *                                                                         *
# *   This program is free software; you can redistribute it and/or modify  *
# *   it under the terms of the GNU Lesser General Public License (LGPL)    *
# *   as published by the Free Software Foundation; either version 2 of     *
# *   the License, or (at your option) any later version.                   *
# *   for detail see the LICENCE text file.                                 *
# *                                                                         *
# *   This program is distributed in the hope that it will be useful,       *
# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
# *   GNU Library General Public License for more details.                  *
# *                                                                         *
# *   You should have received a copy of the GNU Library General Public     *
# *   License along with this program; if not, write to the Free Software   *
# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
# *   USA                                                                   *
# *                                                                         *
# ***************************************************************************

import FreeCAD
import PathScripts.PathAreaOp as PathAreaOp
import PathScripts.PathLog as PathLog
import PathScripts.PathOp as PathOp

from PySide import QtCore

__title__ = "Base Path Profile Operation"
__author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
__doc__ = "Base class and implementation for Path profile operations."

if False:
    PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
    PathLog.trackModule(PathLog.thisModule())
else:
    PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())

# Qt tanslation handling
def translate(context, text, disambig=None):
    return QtCore.QCoreApplication.translate(context, text, disambig)

class ObjectProfile(PathAreaOp.ObjectOp):
    '''Base class for proxy objects of all profile operations.'''

    def initAreaOp(self, obj):
        '''initAreaOp(obj) ... creates all profile specific properties.
        Do not overwrite.'''
        # Profile Properties
        obj.addProperty("App::PropertyEnumeration", "Side", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Side of edge that tool should cut"))
        obj.Side = ['Outside', 'Inside']  # side of profile that cutter is on in relation to direction of profile
        obj.addProperty("App::PropertyEnumeration", "Direction", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "The direction that the toolpath should go around the part ClockWise CW or CounterClockWise CCW"))
        obj.Direction = ['CW', 'CCW']  # this is the direction that the profile runs
        obj.addProperty("App::PropertyBool", "UseComp", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "make True, if using Cutter Radius Compensation"))

        obj.addProperty("App::PropertyDistance", "OffsetExtra", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Extra value to stay away from final profile- good for roughing toolpath"))
        obj.addProperty("App::PropertyEnumeration", "JoinType", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Controls how tool moves around corners. Default=Round"))
        obj.JoinType = ['Round', 'Square', 'Miter']  # this is the direction that the Profile runs
        obj.addProperty("App::PropertyFloat", "MiterLimit", "Profile", QtCore.QT_TRANSLATE_NOOP("App::Property", "Maximum distance before a miter join is truncated"))
        obj.setEditorMode('MiterLimit', 2)

    def areaOpOnChanged(self, obj, prop):
        '''areaOpOnChanged(obj, prop) ... updates Side and MiterLimit visibility depending on changed properties.
        Do not overwrite.'''
        if prop == "UseComp":
            if not obj.UseComp:
                obj.setEditorMode('Side', 2)
            else:
                obj.setEditorMode('Side', 0)

        if prop == 'JoinType':
            if obj.JoinType == 'Miter':
                obj.setEditorMode('MiterLimit', 0)
            else:
                obj.setEditorMode('MiterLimit', 2)

    def areaOpAreaParams(self, obj, isHole):
        '''areaOpAreaParams(obj, isHole) ... returns dictionary with area parameters.
        Do not overwrite.'''
        params = {}
        params['Fill'] = 0
        params['Coplanar'] = 0
        params['SectionCount'] = -1

        offset = 0.0
        if obj.UseComp:
            offset = self.radius + obj.OffsetExtra.Value
        if obj.Side == 'Inside':
            offset = 0 - offset
        if isHole:
            offset = 0 - offset
        params['Offset'] = offset

        jointype = ['Round', 'Square', 'Miter']
        params['JoinType'] = jointype.index(obj.JoinType)

        if obj.JoinType == 'Miter':
            params['MiterLimit'] = obj.MiterLimit

        return params

    def areaOpPathParams(self, obj, isHole):
        '''areaOpPathParams(obj, isHole) ... returns dictionary with path parameters.
        Do not overwrite.'''
        params = {}

        # Reverse the direction for holes
        if isHole:
            direction = "CW" if obj.Direction == "CCW" else "CCW"
        else:
            direction = obj.Direction

        if direction == 'CCW':
            params['orientation'] = 0
        else:
            params['orientation'] = 1
        if not obj.UseComp:
            if direction == 'CCW':
                params['orientation'] = 1
            else:
                params['orientation'] = 0

        return params

    def areaOpUseProjection(self, obj):
        '''areaOpUseProjection(obj) ... returns True'''
        return True

    def areaOpSetDefaultValues(self, obj):
        '''areaOpSetDefaultValues(obj) ... sets default values.
        Do not overwrite.'''
        obj.Side = "Outside"
        obj.OffsetExtra = 0.0
        obj.Direction = "CW"
        obj.UseComp = True
        obj.JoinType = "Round"
        obj.MiterLimit = 0.1

<|endoftext|>