<commit_before>"""
Dummy client runner

This module implements a stand-alone launcher for stress-testing
an Evennia game. It will launch any number of fake clients. These
clients will log into the server and start doing random operations.
Customizing and weighing these operations differently depends on
which type of game is tested. The module contains a testing module
for plain Evennia.

Please note that you shouldn't run this on a production server!
Launch the program without any arguments or options to see a
full step-by-step setup help.

Basically (for testing default Evennia):

 - Use an empty/testing database.
 - set PERMISSION_PLAYERS_DEFAULT = "Builders"
 - start server, eventually with profiling active
 - launch this client runner

If you want to customize the runner's client actions
(because you changed the cmdset or needs to better
match your use cases or add more actions), you can
change which actions by adding a path to

   DUMMYRUNNER_ACTIONS_MODULE = <path.to.your.module>

in your settings. See utils.dummyrunner_actions.py
for instructions on how to define this module.

"""

import os, sys, time, random
from optparse import OptionParser
from twisted.conch import telnet
from twisted.internet import reactor, protocol
# from twisted.application import internet, service
# from twisted.web import client
from twisted.internet.task import LoopingCall

# Tack on the root evennia directory to the python path and initialize django settings
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from django.core.management import setup_environ
from game import settings
setup_environ(settings)

from django.conf import settings
from src.utils import utils

HELPTEXT = """
DO NOT RUN THIS ON A PRODUCTION SERVER! USE A CLEAN/TESTING DATABASE!

This stand-alone program launches dummy telnet clients against a
running Evennia server. The idea is to mimic real players logging in
and repeatedly doing resource-heavy commands so as to stress test the
game. It uses the default command set to log in and issue commands, so
if that was customized, some of the functionality will not be tested
(it will not fail, the commands will just not be recognized).  The
running clients will create new objects and rooms all over the place
as part of their running, so using a clean/testing database is
strongly recommended.

Setup:
  1) setup a fresh/clean database (if using sqlite, just safe-copy
     away your real evennia.db3 file and create a new one with
     manage.py)
  2) in game/settings.py, add

        PERMISSION_PLAYER_DEFAULT="Builders"

  3a) Start Evennia like normal.
  3b) If you want profiling, start Evennia like this instead:

        python runner.py -S start

     this will start Evennia under cProfiler with output server.prof.
  4) run this dummy runner:

        python dummyclients.py <nr_of_clients> [timestep] [port]

     Default is to connect one client to port 4000, using a 5 second
     timestep.  Increase the number of clients and shorten the
     timestep (minimum is 1s) to further stress the game.

     You can stop the dummy runner with Ctrl-C.

  5) Log on and determine if game remains responsive despite the
     heavier load. Note that if you do profiling, there is an
     additional overhead from the profiler too!
  6) If you use profiling, let the game run long enough to gather
     data, then stop the server. You can inspect the server.prof file
     from a python prompt (see Python's manual on cProfiler).

"""
# number of clients to launch if no input is given on command line
DEFAULT_NCLIENTS = 1
# time between each 'tick', in seconds, if not set on command
# line. All launched clients will be called upon to possibly do an
# action with this frequency.
DEFAULT_TIMESTEP = 5
# Port to use, if not specified on command line
DEFAULT_PORT = settings.TELNET_PORTS[0]
# chance of an action happening, per timestep. This helps to
# spread out usage randomly, like it would be in reality.
CHANCE_OF_ACTION = 0.1

#------------------------------------------------------------
# Helper functions
#------------------------------------------------------------

def idcounter():
    "generates subsequent id numbers"
    idcount = 0
    while True:
        idcount += 1
        yield idcount
OID = idcounter()
CID = idcounter()

def makeiter(obj):
    "makes everything iterable"
    if not hasattr(obj, '__iter__'):
        return [obj]
    return obj

#------------------------------------------------------------
# Client classes
#------------------------------------------------------------

class DummyClient(telnet.StatefulTelnetProtocol):
    """
    Handles connection to a running Evennia server,
    mimicking a real player by sending commands on
    a timer.
    """

    def connectionMade(self):

        # public properties
        self.cid = CID.next()
        self.istep = 0
        self.exits = [] # exit names created
        self.objs = [] # obj names created

        self._actions = self.factory.actions
        self._echo_brief = self.factory.verbose == 1
        self._echo_all = self.factory.verbose == 2
        #print " ** client %i connected." % self.cid

        reactor.addSystemEventTrigger('before', 'shutdown', self.logout)

        # start client tick
        d = LoopingCall(self.step)
        d.start(self.factory.timestep, now=True).addErrback(self.error)

    def dataReceived(self, data):
        "Echo incoming data to stdout"
        if self._echo_all:
            print data

    def connectionLost(self, reason):
        "loosing the connection"
        #print " ** client %i lost connection." % self.cid

    def error(self, err):
        "error callback"
        print err

    def counter(self):
        "produces a unique id, also between clients"
        return OID.next()

    def logout(self):
        "Causes the client to log out of the server. Triggered by ctrl-c signal."
        cmd, report = self._actions[1](self)
        print "client %i %s (%s actions)" % (self.cid, report, self.istep)
        self.sendLine(cmd)

    def step(self):
        """
        Perform a step. This is called repeatedly by the runner
        and causes the client to issue commands to the server.
        This holds all "intelligence" of the dummy client.
        """
        if random.random() > CHANCE_OF_ACTION:
            return
        if self.istep == 0:
            cfunc = self._actions[0]
        else: # random selection using cumulative probabilities
            rand = random.random()
            cfunc = [func for cprob, func in self._actions[2] if cprob >= rand][0]
        # launch the action (don't hide tracebacks)
        cmd, report = cfunc(self)
        # handle the result
        cmd = "\n".join(makeiter(cmd))
        if self.istep == 0 or self._echo_brief or self._echo_all:
            print "client %i %s" % (self.cid, report)
        self.sendLine(cmd)
        self.istep += 1 # only steps up if an action is taken

class DummyFactory(protocol.ClientFactory):
    protocol = DummyClient

    def __init__(self, actions, timestep, verbose):
        "Setup the factory base (shared by all clients)"
        self.actions = actions
        self.timestep = timestep
        self.verbose = verbose

#------------------------------------------------------------
# Access method:
# Starts clients and connects them to a running server.
#------------------------------------------------------------

def start_all_dummy_clients(actions, nclients=1, timestep=5, telnet_port=4000, verbose=0):

    # validating and preparing the action tuple

    # make sure the probabilities add up to 1
    pratio = 1.0 / sum(tup[0] for tup in actions[2:])
    flogin, flogout, probs, cfuncs = actions[0], actions[1], [tup[0] * pratio for tup in actions[2:]], [tup[1] for tup in actions[2:]]
    # create cumulative probabilies for the random actions
    cprobs = [sum(v for i,v in enumerate(probs) if i<=k) for k in range(len(probs))]
    # rebuild a new, optimized action structure
    actions = (flogin, flogout, zip(cprobs, cfuncs))

    # setting up all clients (they are automatically started)
    factory = DummyFactory(actions, timestep, verbose)
    for i in range(nclients):
        reactor.connectTCP("localhost", telnet_port, factory)
    # start reactor
    reactor.run()

#------------------------------------------------------------
# Command line interface
#------------------------------------------------------------

if __name__ == '__main__':

    # parsing command line with default vals
    parser = OptionParser(usage="%prog [options] <nclients> [timestep, [port]]",
                          description="This program requires some preparations to run properly. Start it without any arguments or options for full help.")
    parser.add_option('-v', '--verbose', action='store_const', const=1, dest='verbose',
                      default=0,help="echo brief description of what clients do every timestep.")
    parser.add_option('-V', '--very-verbose', action='store_const',const=2, dest='verbose',
                      default=0,help="echo all client returns to stdout (hint: use only with nclients=1!)")

    options, args = parser.parse_args()

    nargs = len(args)
    nclients = DEFAULT_NCLIENTS
    timestep = DEFAULT_TIMESTEP
    port = DEFAULT_PORT
    try:
        if not args : raise Exception
        if nargs > 0: nclients = max(1, int(args[0]))
        if nargs > 1: timestep = max(1, int(args[1]))
        if nargs > 2: port = int(args[2])
    except Exception:
        print HELPTEXT
        sys.exit()

    # import the ACTION tuple from a given module
    try:
        action_modpath = settings.DUMMYRUNNER_ACTIONS_MODULE
    except AttributeError:
        # use default
        action_modpath = "src.utils.dummyrunner_actions"
    actions = utils.mod_import(action_modpath, "ACTIONS")

    print "Connecting %i dummy client(s) to port %i using a %i second timestep ... " % (nclients, port, timestep)
    t0 = time.time()
    start_all_dummy_clients(actions, nclients, timestep, port,
                       verbose=options.verbose)
    ttot = time.time() - t0
    print "... dummy client runner finished after %i seconds." % ttot
<commit_msg>Fixed critical typo in instructions for dummyrunner.<commit_after>"""
Dummy client runner

This module implements a stand-alone launcher for stress-testing
an Evennia game. It will launch any number of fake clients. These
clients will log into the server and start doing random operations.
Customizing and weighing these operations differently depends on
which type of game is tested. The module contains a testing module
for plain Evennia.

Please note that you shouldn't run this on a production server!
Launch the program without any arguments or options to see a
full step-by-step setup help.

Basically (for testing default Evennia):

 - Use an empty/testing database.
 - set PERMISSION_PLAYER_DEFAULT = "Builders"
 - start server, eventually with profiling active
 - launch this client runner

If you want to customize the runner's client actions
(because you changed the cmdset or needs to better
match your use cases or add more actions), you can
change which actions by adding a path to

   DUMMYRUNNER_ACTIONS_MODULE = <path.to.your.module>

in your settings. See utils.dummyrunner_actions.py
for instructions on how to define this module.

"""

import os, sys, time, random
from optparse import OptionParser
from twisted.conch import telnet
from twisted.internet import reactor, protocol
# from twisted.application import internet, service
# from twisted.web import client
from twisted.internet.task import LoopingCall

# Tack on the root evennia directory to the python path and initialize django settings
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from django.core.management import setup_environ
from game import settings
setup_environ(settings)

from django.conf import settings
from src.utils import utils

HELPTEXT = """
DO NOT RUN THIS ON A PRODUCTION SERVER! USE A CLEAN/TESTING DATABASE!

This stand-alone program launches dummy telnet clients against a
running Evennia server. The idea is to mimic real players logging in
and repeatedly doing resource-heavy commands so as to stress test the
game. It uses the default command set to log in and issue commands, so
if that was customized, some of the functionality will not be tested
(it will not fail, the commands will just not be recognized).  The
running clients will create new objects and rooms all over the place
as part of their running, so using a clean/testing database is
strongly recommended.

Setup:
  1) setup a fresh/clean database (if using sqlite, just safe-copy
     away your real evennia.db3 file and create a new one with
     manage.py)
  2) in game/settings.py, add

        PERMISSION_PLAYER_DEFAULT="Builders"

  3a) Start Evennia like normal.
  3b) If you want profiling, start Evennia like this instead:

        python runner.py -S start

     this will start Evennia under cProfiler with output server.prof.
  4) run this dummy runner:

        python dummyclients.py <nr_of_clients> [timestep] [port]

     Default is to connect one client to port 4000, using a 5 second
     timestep.  Increase the number of clients and shorten the
     timestep (minimum is 1s) to further stress the game.

     You can stop the dummy runner with Ctrl-C.

  5) Log on and determine if game remains responsive despite the
     heavier load. Note that if you do profiling, there is an
     additional overhead from the profiler too!
  6) If you use profiling, let the game run long enough to gather
     data, then stop the server. You can inspect the server.prof file
     from a python prompt (see Python's manual on cProfiler).

"""
# number of clients to launch if no input is given on command line
DEFAULT_NCLIENTS = 1
# time between each 'tick', in seconds, if not set on command
# line. All launched clients will be called upon to possibly do an
# action with this frequency.
DEFAULT_TIMESTEP = 5
# Port to use, if not specified on command line
DEFAULT_PORT = settings.TELNET_PORTS[0]
# chance of an action happening, per timestep. This helps to
# spread out usage randomly, like it would be in reality.
CHANCE_OF_ACTION = 0.1

#------------------------------------------------------------
# Helper functions
#------------------------------------------------------------

def idcounter():
    "generates subsequent id numbers"
    idcount = 0
    while True:
        idcount += 1
        yield idcount
OID = idcounter()
CID = idcounter()

def makeiter(obj):
    "makes everything iterable"
    if not hasattr(obj, '__iter__'):
        return [obj]
    return obj

#------------------------------------------------------------
# Client classes
#------------------------------------------------------------

class DummyClient(telnet.StatefulTelnetProtocol):
    """
    Handles connection to a running Evennia server,
    mimicking a real player by sending commands on
    a timer.
    """

    def connectionMade(self):

        # public properties
        self.cid = CID.next()
        self.istep = 0
        self.exits = [] # exit names created
        self.objs = [] # obj names created

        self._actions = self.factory.actions
        self._echo_brief = self.factory.verbose == 1
        self._echo_all = self.factory.verbose == 2
        #print " ** client %i connected." % self.cid

        reactor.addSystemEventTrigger('before', 'shutdown', self.logout)

        # start client tick
        d = LoopingCall(self.step)
        d.start(self.factory.timestep, now=True).addErrback(self.error)

    def dataReceived(self, data):
        "Echo incoming data to stdout"
        if self._echo_all:
            print data

    def connectionLost(self, reason):
        "loosing the connection"
        #print " ** client %i lost connection." % self.cid

    def error(self, err):
        "error callback"
        print err

    def counter(self):
        "produces a unique id, also between clients"
        return OID.next()

    def logout(self):
        "Causes the client to log out of the server. Triggered by ctrl-c signal."
        cmd, report = self._actions[1](self)
        print "client %i %s (%s actions)" % (self.cid, report, self.istep)
        self.sendLine(cmd)

    def step(self):
        """
        Perform a step. This is called repeatedly by the runner
        and causes the client to issue commands to the server.
        This holds all "intelligence" of the dummy client.
        """
        if random.random() > CHANCE_OF_ACTION:
            return
        if self.istep == 0:
            cfunc = self._actions[0]
        else: # random selection using cumulative probabilities
            rand = random.random()
            cfunc = [func for cprob, func in self._actions[2] if cprob >= rand][0]
        # launch the action (don't hide tracebacks)
        cmd, report = cfunc(self)
        # handle the result
        cmd = "\n".join(makeiter(cmd))
        if self.istep == 0 or self._echo_brief or self._echo_all:
            print "client %i %s" % (self.cid, report)
        self.sendLine(cmd)
        self.istep += 1 # only steps up if an action is taken

class DummyFactory(protocol.ClientFactory):
    protocol = DummyClient

    def __init__(self, actions, timestep, verbose):
        "Setup the factory base (shared by all clients)"
        self.actions = actions
        self.timestep = timestep
        self.verbose = verbose

#------------------------------------------------------------
# Access method:
# Starts clients and connects them to a running server.
#------------------------------------------------------------

def start_all_dummy_clients(actions, nclients=1, timestep=5, telnet_port=4000, verbose=0):

    # validating and preparing the action tuple

    # make sure the probabilities add up to 1
    pratio = 1.0 / sum(tup[0] for tup in actions[2:])
    flogin, flogout, probs, cfuncs = actions[0], actions[1], [tup[0] * pratio for tup in actions[2:]], [tup[1] for tup in actions[2:]]
    # create cumulative probabilies for the random actions
    cprobs = [sum(v for i,v in enumerate(probs) if i<=k) for k in range(len(probs))]
    # rebuild a new, optimized action structure
    actions = (flogin, flogout, zip(cprobs, cfuncs))

    # setting up all clients (they are automatically started)
    factory = DummyFactory(actions, timestep, verbose)
    for i in range(nclients):
        reactor.connectTCP("localhost", telnet_port, factory)
    # start reactor
    reactor.run()

#------------------------------------------------------------
# Command line interface
#------------------------------------------------------------

if __name__ == '__main__':

    # parsing command line with default vals
    parser = OptionParser(usage="%prog [options] <nclients> [timestep, [port]]",
                          description="This program requires some preparations to run properly. Start it without any arguments or options for full help.")
    parser.add_option('-v', '--verbose', action='store_const', const=1, dest='verbose',
                      default=0,help="echo brief description of what clients do every timestep.")
    parser.add_option('-V', '--very-verbose', action='store_const',const=2, dest='verbose',
                      default=0,help="echo all client returns to stdout (hint: use only with nclients=1!)")

    options, args = parser.parse_args()

    nargs = len(args)
    nclients = DEFAULT_NCLIENTS
    timestep = DEFAULT_TIMESTEP
    port = DEFAULT_PORT
    try:
        if not args : raise Exception
        if nargs > 0: nclients = max(1, int(args[0]))
        if nargs > 1: timestep = max(1, int(args[1]))
        if nargs > 2: port = int(args[2])
    except Exception:
        print HELPTEXT
        sys.exit()

    # import the ACTION tuple from a given module
    try:
        action_modpath = settings.DUMMYRUNNER_ACTIONS_MODULE
    except AttributeError:
        # use default
        action_modpath = "src.utils.dummyrunner_actions"
    actions = utils.mod_import(action_modpath, "ACTIONS")

    print "Connecting %i dummy client(s) to port %i using a %i second timestep ... " % (nclients, port, timestep)
    t0 = time.time()
    start_all_dummy_clients(actions, nclients, timestep, port,
                       verbose=options.verbose)
    ttot = time.time() - t0
    print "... dummy client runner finished after %i seconds." % ttot
<|endoftext|>


<commit_before>#!/usr/bin/env python
"""
Commandline tool for neoepitope protein fasta generation from annotated variant vcf.

usage: variants2proteins.py [-h]
                               [-v VCF] [-t {VEP,ANNOVAR,SNPEFF}] [-p PROTEINS]
                               [-r REFERENCE] [-fINDEL] [-fFS] [-fSNP] -o
                               OUTPUT

optional arguments:
  -h, --help            show this help message and exit
  -v VCF, --vcf VCF     Path to the vcf input file
  -t {VEP,ANNOVAR,SNPEFF}, --type {VEP,ANNOVAR,SNPEFF}
                        Type of annotation tool used (Variant Effect
                        Predictor, ANNOVAR exonic gene annotation, SnpEff)
  -p PROTEINS, --proteins PROTEINS
                        Path to the protein ID input file (in HGNC-ID)
  -r REFERENCE, --reference REFERENCE
                        The reference genome used for varinat annotation and
                        calling.
  -fINDEL, --filterINDEL
                        Filter insertions and deletions (including
                        frameshifts)
  -fFS, --filterFSINDEL
                        Filter frameshift INDELs
  -fSNP, --filterSNP    Filter SNPs
  -o OUTPUT, --output OUTPUT
                        Path to the output file

"""
import time
import sys
import argparse
import logging

from Fred2.Core import Protein, Peptide, Allele, MutationSyntax, Variant
from Fred2.Core.Variant import VariationType
from Fred2.IO import read_lines, MartsAdapter, read_annovar_exonic
from Fred2.EpitopePrediction import EpitopePredictorFactory
from Fred2.Core import generate_peptides_from_proteins, generate_peptides_from_variants, generate_transcripts_from_variants, generate_proteins_from_transcripts
from Fred2.IO.ADBAdapter import EIdentifierTypes, EAdapterFields
from Fred2.IO.FileReader import read_vcf

MARTDBURL = {"GRCH37": "http://grch37.ensembl.org/biomart/martservice?query=",
             "GRCH38": "http://www.ensembl.org/biomart/martservice?query="} # is corrently set to GRCh38

def read_variant_effect_predictor(file, gene_filter=None):
    """
    Reads a VCF (v4.1) file generatede by variant effect predictor and generates variant objects

    :param str file: Path to vcf file
    :param list gene_filter: List of proteins (in HGNC) of inerrest. Variants are filter according to this list
    :return: list(Variant) - a list of Fred2.Core.Variant objects
    """
    vars = []
    def get_type(ref, alt):
        """
            returns the variant type
        """
        if len(ref)==1 and len(alt)==1:
            return VariationType.SNP
        if len(ref)>0 and len(alt)==0:
            if len(ref)%3 == 0:
                return VariationType.DEL
            else:
                return VariationType.FSDEL
        if len(ref) == 0 and len(alt)>0:
            if len(alt)% 3 == 0:
                return VariationType.INS
            else:
                return VariationType.FSINS
        return VariationType.UNKNOWN

    coding_types = set(["3_prime_UTR_variant", "5_prime_UTR_variant", "start_lost", "stop_gained",
        "frameshift_variant", "start_lost", "inframe_insertion", "inframe_deletion", "missense_variant",
        "protein_altering_variant", "splice_region_variant", "incomplete_terminal_codon_variant", "stop_retained_variant",
        "synonymous_variant", "coding_sequence_variant"])

    with open(file, "r") as f:
        for i,l in enumerate(f):

            #skip comments
            if l.startswith("#") or l.strip() == "":
                continue

            chrom, gene_pos,var_id,ref,alt,_,filter_flag,info= l.strip().split("\t")[:8]
            coding = {}
            isSynonymous = False

            for co in info.split(","):
                #skip additional info fields without annotation
                try:
                    #Allele|Consequence|IMPACT|SYMBOL|Gene|Feature_type|Feature|BIOTYPE|EXON|INTRON|HGVSc|HGVSp|cDNA_position|CDS_position|Protein_position|Amino_acids|Codons|Existing_variation|DISTANCE|STRAND|FLAGS|SYMBOL_SOURCE|HGNC_ID|TSL|APPRIS|SIFT|PolyPhen|AF|AFR_AF|AMR_AF|EAS_AF|EUR_AF|SAS_AF|AA_AF|EA_AF|gnomAD_AF|gnomAD_AFR_AF|gnomAD_AMR_AF|gnomAD_ASJ_AF|gnomAD_EAS_AF|gnomAD_FIN_AF|gnomAD_NFE_AF|gnomAD_OTH_AF|gnomAD_SAS_AF|CLIN_SIG|SOMATIC|PHENO|PUBMED|MOTIF_NAME|MOTIF_POS|HIGH_INF_POS|MOTIF_SCORE_CHANGE">
                    _,var_type,_,gene,_,transcript_type,transcript_id,_,_,_,_,_,_,transcript_pos,prot_pos,aa_mutation = co.strip().split("|")[:16]
                    HGNC_ID=co.strip().split("|")[22]
                except ValueError:
                    logging.warning("INFO field in different format in line: {}, skipping...".format(str(i)))
                    continue

                #pass every other feature type except Transcript (RegulatoryFeature, MotifFeature.)
                #pass genes that are uninterresting for us
                if transcript_type != "Transcript" or (HGNC_ID not in gene_filter and gene_filter):
                    continue

                #pass all intronic and other mutations that do not directly influence the protein sequence
                if any(t in coding_types for t in var_type.split("&")):
                    #generate mutation syntax

                    #positioning in Fred2 is 0-based!!!
                    if transcript_pos != "" and '?' not in transcript_pos:
                        coding[transcript_id] = MutationSyntax(transcript_id, int(transcript_pos.split("-")[0])-1, -1 if prot_pos  == "" else int(prot_pos.split("-")[0])-1, co, "", geneID=HGNC_ID)

                #is variant synonymous?
                isSynonymous = any(t == "synonymous_variant" for t in var_type.split("&"))
            if coding:
                vars.append(Variant(var_id, get_type(ref, alt), chrom, int(gene_pos), ref.upper(), alt.upper(), coding, False, isSynonymous))
    return vars

def main():

    model = argparse.ArgumentParser(description='Neoepitope protein fasta generation from variant vcf')

    model.add_argument(
        '-v', '--vcf',
        type=str,
        default=None,
        help='Path to the vcf input file'
        )

    model.add_argument(
        '-t', '--type',
        type=str,
        choices=["VEP", "ANNOVAR", "SNPEFF"],
        default="VEP",
        help='Type of annotation tool used (Variant Effect Predictor, ANNOVAR exonic gene annotation, SnpEff)'
        )

    model.add_argument(
        '-p','--proteins',
        type=str,
        default=None,
        help='Path to the protein ID input file (in HGNC-ID)'
        )

    model.add_argument(
        '-r' ,'--reference',
        type=str,
        default='GRCh38',
        help='The reference genome used for varinat annotation and calling.'
        )

    model.add_argument(
        '-fINDEL' ,'--filterINDEL',
        action="store_true",
        help='Filter insertions and deletions (including frameshifts)'
        )

    model.add_argument(
        '-fFS' ,'--filterFSINDEL',
        action="store_true",
        help='Filter frameshift INDELs'
        )

    model.add_argument(
        '-fSNP' ,'--filterSNP',
        action="store_true",
        help='Filter SNPs'
        )

    model.add_argument(
        '-o','--output',
        type=str,
        required=True,
        help='Path to the output file'
        )

    args = model.parse_args()

    martDB = MartsAdapter(biomart=MARTDBURL[args.reference.upper()])

    if args.vcf is None:
        sys.stderr.write("At least a vcf file or a protein id file has to be provided.\n")
        return -1

    # if vcf file is given: generate variants and filter them if HGNC IDs ar given
    if args.vcf is not None:
        protein_ids = []
        if args.proteins is not None:
            with open(args.proteins, "r") as f:
                for l in f:
                    l = l.strip()
                    if l != "":
                        protein_ids.append(l)

        if args.type == "VEP":
            variants = read_variant_effect_predictor(args.vcf, gene_filter=protein_ids)

        elif args.type == "SNPEFF":
            variants = read_vcf(args.vcf)[0]

        else:
            variants = read_annovar_exonic(args.vcf, gene_filter=protein_ids)

        if args.filterSNP:
            variants = filter(lambda x: x.type != VariationType.SNP, variants)

        if args.filterINDEL:
            variants = filter(lambda x: x.type not in [VariationType.INS,
                                                       VariationType.DEL,
                                                       VariationType.FSDEL,
                                                       VariationType.FSINS], variants)

        if args.filterFSINDEL:
            variants = filter(lambda x: x.type not in [VariationType.FSDEL, VariationType.FSINS], variants)

        if not variants:
            sys.stderr.write("No variants left after filtering. Please refine your filtering criteria.\n")
            return -1

        #generate transcripts
        transcripts = generate_transcripts_from_variants(variants, martDB, EIdentifierTypes.ENSEMBL)

        #generate proteins
        proteins = generate_proteins_from_transcripts(transcripts)

        print proteins

        #write fasta file
        with open(args.output, "w") as f:
            for p in proteins:
                f.write('>' + str(p.transcript_id) + '|' + str(p.vars) + '_var_' + '\n')
                f.write(str(p)+ '\n')

    else:
        sys.stderr.write("At least a vcf file or a protein id file has to be provided.\n")
        return -1

    return 0

if __name__ == "__main__":
    sys.exit(main())

<commit_msg>fix code<commit_after>#!/usr/bin/env python
"""
Commandline tool for neoepitope protein fasta generation from annotated variant vcf.

usage: variants2proteins.py [-h]
                               [-v VCF] [-t {VEP,ANNOVAR,SNPEFF}] [-p PROTEINS]
                               [-r REFERENCE] [-fINDEL] [-fFS] [-fSNP] -o
                               OUTPUT

optional arguments:
  -h, --help            show this help message and exit
  -v VCF, --vcf VCF     Path to the vcf input file
  -t {VEP,ANNOVAR,SNPEFF}, --type {VEP,ANNOVAR,SNPEFF}
                        Type of annotation tool used (Variant Effect
                        Predictor, ANNOVAR exonic gene annotation, SnpEff)
  -p PROTEINS, --proteins PROTEINS
                        Path to the protein ID input file (in HGNC-ID)
  -r REFERENCE, --reference REFERENCE
                        The reference genome used for varinat annotation and
                        calling.
  -fINDEL, --filterINDEL
                        Filter insertions and deletions (including
                        frameshifts)
  -fFS, --filterFSINDEL
                        Filter frameshift INDELs
  -fSNP, --filterSNP    Filter SNPs
  -o OUTPUT, --output OUTPUT
                        Path to the output file

"""
import time
import sys
import argparse
import logging

from Fred2.Core import Protein, Peptide, Allele, MutationSyntax, Variant
from Fred2.Core.Variant import VariationType
from Fred2.IO import read_lines, MartsAdapter, read_annovar_exonic
from Fred2.EpitopePrediction import EpitopePredictorFactory
from Fred2.Core import generate_peptides_from_proteins, generate_peptides_from_variants, generate_transcripts_from_variants, generate_proteins_from_transcripts
from Fred2.IO.ADBAdapter import EIdentifierTypes, EAdapterFields
from Fred2.IO.FileReader import read_vcf

MARTDBURL = {"GRCH37": "http://grch37.ensembl.org/biomart/martservice?query=",
             "GRCH38": "http://www.ensembl.org/biomart/martservice?query="} # is corrently set to GRCh38

def read_variant_effect_predictor(file, gene_filter=None):
    """
    Reads a VCF (v4.1) file generatede by variant effect predictor and generates variant objects

    :param str file: Path to vcf file
    :param list gene_filter: List of proteins (in HGNC) of inerrest. Variants are filter according to this list
    :return: list(Variant) - a list of Fred2.Core.Variant objects
    """
    vars = []
    def get_type(ref, alt):
        """
            returns the variant type
        """
        if len(ref)==1 and len(alt)==1:
            return VariationType.SNP
        if len(ref)>0 and len(alt)==0:
            if len(ref)%3 == 0:
                return VariationType.DEL
            else:
                return VariationType.FSDEL
        if len(ref) == 0 and len(alt)>0:
            if len(alt)% 3 == 0:
                return VariationType.INS
            else:
                return VariationType.FSINS
        return VariationType.UNKNOWN

    coding_types = set(["3_prime_UTR_variant", "5_prime_UTR_variant", "start_lost", "stop_gained",
        "frameshift_variant", "start_lost", "inframe_insertion", "inframe_deletion", "missense_variant",
        "protein_altering_variant", "splice_region_variant", "incomplete_terminal_codon_variant", "stop_retained_variant",
        "synonymous_variant", "coding_sequence_variant"])

    with open(file, "r") as f:
        for i,l in enumerate(f):

            #skip comments
            if l.startswith("#") or l.strip() == "":
                continue

            chrom, gene_pos,var_id,ref,alt,_,filter_flag,info= l.strip().split("\t")[:8]
            coding = {}
            isSynonymous = False

            for co in info.split(","):
                #skip additional info fields without annotation
                try:
                    #Allele|Consequence|IMPACT|SYMBOL|Gene|Feature_type|Feature|BIOTYPE|EXON|INTRON|HGVSc|HGVSp|cDNA_position|CDS_position|Protein_position|Amino_acids|Codons|Existing_variation|DISTANCE|STRAND|FLAGS|SYMBOL_SOURCE|HGNC_ID|TSL|APPRIS|SIFT|PolyPhen|AF|AFR_AF|AMR_AF|EAS_AF|EUR_AF|SAS_AF|AA_AF|EA_AF|gnomAD_AF|gnomAD_AFR_AF|gnomAD_AMR_AF|gnomAD_ASJ_AF|gnomAD_EAS_AF|gnomAD_FIN_AF|gnomAD_NFE_AF|gnomAD_OTH_AF|gnomAD_SAS_AF|CLIN_SIG|SOMATIC|PHENO|PUBMED|MOTIF_NAME|MOTIF_POS|HIGH_INF_POS|MOTIF_SCORE_CHANGE">
                    _,var_type,_,gene,_,transcript_type,transcript_id,_,_,_,_,_,_,transcript_pos,prot_pos,aa_mutation = co.strip().split("|")[:16]
                    HGNC_ID=co.strip().split("|")[22]
                except ValueError:
                    logging.warning("INFO field in different format in line: {}, skipping...".format(str(i)))
                    continue

                #pass every other feature type except Transcript (RegulatoryFeature, MotifFeature.)
                #pass genes that are uninterresting for us
                if transcript_type != "Transcript" or (HGNC_ID not in gene_filter and gene_filter):
                    continue

                #pass all intronic and other mutations that do not directly influence the protein sequence
                if any(t in coding_types for t in var_type.split("&")):
                    #generate mutation syntax

                    #positioning in Fred2 is 0-based!!!
                    if transcript_pos != "" and '?' not in transcript_pos:
                        coding[transcript_id] = MutationSyntax(transcript_id, int(transcript_pos.split("-")[0])-1, -1 if prot_pos  == "" else int(prot_pos.split("-")[0])-1, co, "", geneID=HGNC_ID)

                #is variant synonymous?
                isSynonymous = any(t == "synonymous_variant" for t in var_type.split("&"))
            if coding:
                vars.append(Variant(var_id, get_type(ref, alt), chrom, int(gene_pos), ref.upper(), alt.upper(), coding, False, isSynonymous))
    return vars

def main():

    model = argparse.ArgumentParser(description='Neoepitope protein fasta generation from variant vcf')

    model.add_argument(
        '-v', '--vcf',
        type=str,
        default=None,
        help='Path to the vcf input file'
        )

    model.add_argument(
        '-t', '--type',
        type=str,
        choices=["VEP", "ANNOVAR", "SNPEFF"],
        default="VEP",
        help='Type of annotation tool used (Variant Effect Predictor, ANNOVAR exonic gene annotation, SnpEff)'
        )

    model.add_argument(
        '-p','--proteins',
        type=str,
        default=None,
        help='Path to the protein ID input file (in HGNC-ID)'
        )

    model.add_argument(
        '-r' ,'--reference',
        type=str,
        default='GRCh38',
        help='The reference genome used for varinat annotation and calling.'
        )

    model.add_argument(
        '-fINDEL' ,'--filterINDEL',
        action="store_true",
        help='Filter insertions and deletions (including frameshifts)'
        )

    model.add_argument(
        '-fFS' ,'--filterFSINDEL',
        action="store_true",
        help='Filter frameshift INDELs'
        )

    model.add_argument(
        '-fSNP' ,'--filterSNP',
        action="store_true",
        help='Filter SNPs'
        )

    model.add_argument(
        '-o','--output',
        type=str,
        required=True,
        help='Path to the output file'
        )

    args = model.parse_args()

    martDB = MartsAdapter(biomart=MARTDBURL[args.reference.upper()])

    if args.vcf is None:
        sys.stderr.write("At least a vcf file or a protein id file has to be provided.\n")
        return -1

    # if vcf file is given: generate variants and filter them if HGNC IDs ar given
    if args.vcf is not None:
        protein_ids = []
        if args.proteins is not None:
            with open(args.proteins, "r") as f:
                for l in f:
                    l = l.strip()
                    if l != "":
                        protein_ids.append(l)

        if args.type == "VEP":
            variants = read_variant_effect_predictor(args.vcf, gene_filter=protein_ids)

        elif args.type == "SNPEFF":
            variants = read_vcf(args.vcf)[0]

        else:
            variants = read_annovar_exonic(args.vcf, gene_filter=protein_ids)

        if args.filterSNP:
            variants = filter(lambda x: x.type != VariationType.SNP, variants)

        if args.filterINDEL:
            variants = filter(lambda x: x.type not in [VariationType.INS,
                                                       VariationType.DEL,
                                                       VariationType.FSDEL,
                                                       VariationType.FSINS], variants)

        if args.filterFSINDEL:
            variants = filter(lambda x: x.type not in [VariationType.FSDEL, VariationType.FSINS], variants)

        if not variants:
            sys.stderr.write("No variants left after filtering. Please refine your filtering criteria.\n")
            return -1

        variants = filter(lambda x: x.type != VariationType.UNKNOWN, variants)

        #generate transcripts
        transcripts = generate_transcripts_from_variants(variants, martDB, EIdentifierTypes.ENSEMBL)

        #generate proteins
        proteins = generate_proteins_from_transcripts(transcripts)

        print proteins

        #write fasta file
        with open(args.output, "w") as f:
            for p in proteins:
                f.write('>' + str(p.transcript_id) + '|' + str(p.vars) + '_var_' + '\n')
                f.write(str(p)+ '\n')

    else:
        sys.stderr.write("At least a vcf file or a protein id file has to be provided.\n")
        return -1

    return 0

if __name__ == "__main__":
    sys.exit(main())

<|endoftext|>


<commit_before>import logging
from django.conf import settings
from django.contrib import messages
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.http import HttpResponseRedirect
from django.template.loader import render_to_string
from django.utils.encoding import smart_unicode
from django.contrib.auth.models import AnonymousUser

assert 'django.contrib.auth' in settings.INSTALLED_APPS
assert 'django.contrib.sessions' in settings.INSTALLED_APPS
assert 'viewas' in settings.INSTALLED_APPS

if hasattr(settings, 'AUTH_USER_MODEL'):
    from django.contrib.auth import get_user_model

    User = get_user_model()
else:
    from django.contrib.auth.models import User

# tilda (192) as default key
VIEWAS_TOGGLE_KEY = getattr(settings, 'VIEWAS_TOGGLE_KEY', 192)

_HTML_TYPES = ('text/html', 'application/xhtml+xml')

def replace_insensitive(string, target, replacement):
    """
    Similar to string.replace() but is case insensitive
    Code borrowed from: http://forums.devshed.com/python-programming-11/case-insensitive-string-replace-490921.html
    """
    no_case = string.lower()
    index = no_case.rfind(target.lower())
    if index >= 0:
        return string[:index] + replacement + string[index + len(target):]
    # no results so return the original string
    return string

class BaseMiddleware(object):
    def can_run(self, request):
        if not hasattr(request, 'user'):
            return False
        user = getattr(request, 'actual_user', request.user)
        return user.is_superuser

class ViewAsHookMiddleware(BaseMiddleware):
    """
    Authenticates a superuser as another user assuming a session variable is present.
    """
    logger = logging.getLogger('viewas')

    def get_user(self, username):
        selector = User.USERNAME_FIELD + '__iexact'
        query = {selector: username}
        try:
            return User.objects.get(**query)
        except ObjectDoesNotExist:
            # try to look up by email
            if '@' in username:
                try:
                    return User.objects.get(email__iexact=username)
                except (MultipleObjectsReturned, ObjectDoesNotExist):
                    return None
        return None

    def login_as(self, request, username):
        if request.user.get_username().lower() == username.lower():
            return

        if username == '':
            if 'login_as' in request.session:
                del request.session['login_as']
            return

        self.logger.info(
            'User %r forced a login as %r at %s',
            request.user.get_username(), username, request.get_full_path(),
            extra={'request': request})

        user = self.get_user(username)
        if user:
            request.user = user
            request.session['login_as'] = request.user.get_username()
        else:
            messages.warning(request, "Did not find a user matching '%s'" % (username,))
            if 'login_as' in request.session:
                del request.session['login_as']

    def process_request(self, request):
        if not self.can_run(request):
            return

        request.actual_user = request.user

        if 'login_as' in request.POST:
            self.login_as(request, request.POST['login_as'])
            return HttpResponseRedirect(request.get_full_path())

        elif 'login_as' in request.session:
            self.login_as(request, request.session['login_as'])

class ViewAsRenderMiddleware(BaseMiddleware):
    tag = u''

    def process_response(self, request, response):
        if not self.can_run(request):
            return response

        if ('gzip' not in response.get('Content-Encoding', '') and
                response.get('Content-Type', '').split(';')[0] in _HTML_TYPES):
            response.content = replace_insensitive(
                smart_unicode(response.content),
                self.tag,
                smart_unicode(self.render(request) + self.tag))
            if response.get('Content-Length', None):
                response['Content-Length'] = len(response.content)
        return response

    def render(self, request):
        if not isinstance(request.user, AnonymousUser):
            request.user.username = request.user.get_username()
        if hasattr(request, 'actual_user'):
            request.actual_user.username = request.actual_user.get_username()
        return render_to_string('viewas/header.html', {
            'VIEWAS_TOGGLE_KEY': VIEWAS_TOGGLE_KEY,
            'request': request,
        })

class ViewAsMiddleware(ViewAsHookMiddleware, ViewAsRenderMiddleware):
    pass
<commit_msg>smart_string changed to smart_text for python3<commit_after>import logging
from django.conf import settings
from django.contrib import messages
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.http import HttpResponseRedirect
from django.template.loader import render_to_string
from django.utils.encoding import smart_text
from django.contrib.auth.models import AnonymousUser

assert 'django.contrib.auth' in settings.INSTALLED_APPS
assert 'django.contrib.sessions' in settings.INSTALLED_APPS
assert 'viewas' in settings.INSTALLED_APPS

if hasattr(settings, 'AUTH_USER_MODEL'):
    from django.contrib.auth import get_user_model

    User = get_user_model()
else:
    from django.contrib.auth.models import User

# tilda (192) as default key
VIEWAS_TOGGLE_KEY = getattr(settings, 'VIEWAS_TOGGLE_KEY', 192)

_HTML_TYPES = ('text/html', 'application/xhtml+xml')

def replace_insensitive(string, target, replacement):
    """
    Similar to string.replace() but is case insensitive
    Code borrowed from: http://forums.devshed.com/python-programming-11/case-insensitive-string-replace-490921.html
    """
    no_case = string.lower()
    index = no_case.rfind(target.lower())
    if index >= 0:
        return string[:index] + replacement + string[index + len(target):]
    # no results so return the original string
    return string

class BaseMiddleware(object):
    def can_run(self, request):
        if not hasattr(request, 'user'):
            return False
        user = getattr(request, 'actual_user', request.user)
        return user.is_superuser

class ViewAsHookMiddleware(BaseMiddleware):
    """
    Authenticates a superuser as another user assuming a session variable is present.
    """
    logger = logging.getLogger('viewas')

    def get_user(self, username):
        selector = User.USERNAME_FIELD + '__iexact'
        query = {selector: username}
        try:
            return User.objects.get(**query)
        except ObjectDoesNotExist:
            # try to look up by email
            if '@' in username:
                try:
                    return User.objects.get(email__iexact=username)
                except (MultipleObjectsReturned, ObjectDoesNotExist):
                    return None
        return None

    def login_as(self, request, username):
        if request.user.get_username().lower() == username.lower():
            return

        if username == '':
            if 'login_as' in request.session:
                del request.session['login_as']
            return

        self.logger.info(
            'User %r forced a login as %r at %s',
            request.user.get_username(), username, request.get_full_path(),
            extra={'request': request})

        user = self.get_user(username)
        if user:
            request.user = user
            request.session['login_as'] = request.user.get_username()
        else:
            messages.warning(request, "Did not find a user matching '%s'" % (username,))
            if 'login_as' in request.session:
                del request.session['login_as']

    def process_request(self, request):
        if not self.can_run(request):
            return

        request.actual_user = request.user

        if 'login_as' in request.POST:
            self.login_as(request, request.POST['login_as'])
            return HttpResponseRedirect(request.get_full_path())

        elif 'login_as' in request.session:
            self.login_as(request, request.session['login_as'])

class ViewAsRenderMiddleware(BaseMiddleware):
    tag = u''

    def process_response(self, request, response):
        if not self.can_run(request):
            return response

        if ('gzip' not in response.get('Content-Encoding', '') and
                response.get('Content-Type', '').split(';')[0] in _HTML_TYPES):
            response.content = replace_insensitive(
                smart_text(response.content),
                self.tag,
                smart_text(self.render(request) + self.tag))
            if response.get('Content-Length', None):
                response['Content-Length'] = len(response.content)
        return response

    def render(self, request):
        if not isinstance(request.user, AnonymousUser):
            request.user.username = request.user.get_username()
        if hasattr(request, 'actual_user'):
            request.actual_user.username = request.actual_user.get_username()
        return render_to_string('viewas/header.html', {
            'VIEWAS_TOGGLE_KEY': VIEWAS_TOGGLE_KEY,
            'request': request,
        })

class ViewAsMiddleware(ViewAsHookMiddleware, ViewAsRenderMiddleware):
    pass
<|endoftext|>


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

# Copyright 2016 - 2018: Stefano Mazzucco <stefano AT curso DOT re>

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#   http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import division

from itertools import chain

try:
    from functools import reduce
except ImportError:  # pragma: no cover
    pass

__version__ = '1.0.0'
__all__ = ['QuadTree']

class QuadTree(object):
    def __init__(self, bbox, max_items=10, max_depth=10):
        """Initialize a quadtree.

        :param bbox: bounding box, 4-iterable containing the bottom-left and
                     top right coordinates (easting, northing).
                     E.g. [0, 0, 10, 10]
        :param max_items: the maximum number of items that can be
                          held in the bounding box before the
                          quadtree splits it into four smaller ones
                          (children quadtrees)
        :param max_depth: the maximum depth of the quadtree. Once this
                          value is reached, the instance will split no
                          more and all elements will be stored in the
                          lowest level quadrant

        """
        _validate_bbox(bbox)
        self.max_items = max_items
        self.max_depth = int(max_depth) if max_depth >= 0 else 0
        self.bbox = bbox
        self.contents = []
        self.children = ()

    def insert(self, element):
        """Insert an element in the quadtree. If the
        element's coordinates are not within the quadtree's
        bounding box, the insertion will fail.

        Note that an element with coordinates x, y is
        considered to be inside the bounding box if
        x0 <= x < x1 and y0 <= y < y1.

        :param element: 3-iterable, the first item
                        is the element's "value"
                        while the second and third
                        are the easting and northing
                        respectively.

        :returns: True or False depending on whether
                  the insertion succeeded.

        """
        if not _inside(element, self.bbox):
            return False
        if self.children:
            for child in self.children:
                result = child.insert(element)
                if result:
                    self.contents = []
                    return result
        self.contents.append(element)
        if len(self.contents) > self.max_items and self.max_depth > 0:
            self._split()
        return True

    def _split(self):
        x0, y0, x1, y1 = self.bbox
        xm = (x1 - x0) / 2
        ym = (y1 - y0) / 2

        sw = x0, y0, x0 + xm, y0 + ym
        se = x0 + xm, y0, x1, y0 + ym
        ne = x0 + xm, y0 + ym, x1, y1
        nw = x0, y0 + ym, x0 + xm, y1
        self.children = (QuadTree(sw, self.max_items, self.max_depth - 1),
                         QuadTree(se, self.max_items, self.max_depth - 1),
                         QuadTree(ne, self.max_items, self.max_depth - 1),
                         QuadTree(nw, self.max_items, self.max_depth - 1))

        while self.contents:
            element = self.contents.pop()
            for child in self.children:
                if child.insert(element):
                    break

    def intersect(self, bbox):
        """Return a list of elements of the quadtree
        that intersect the given bounding box.

        :param bbox: 4-iterable containing the bottom-left and
                     top right coordinates (easting, northing).
                     E.g. [0, 0, 10, 10]

        :returns: a set of intersecting elements (may be empty)

        """
        if not self._intersects_bbox(bbox):
            return set()
        if self.children:
            return reduce(
                lambda x, y: x.union(y),
                (c.intersect(bbox) for c in self.children),
                set())
        return set(element for element in self.contents
                   if _inside(element, bbox))

    def _intersects_bbox(self, bbox):
        x0, y0, x1, y1 = self.bbox
        xi0, yi0, xi1, yi1 = bbox

        vertical_intersect = not (yi0 >= y1 or yi1 < y0)
        horizontal_intersect = not (xi0 >= x1 or xi1 < x0)

        return vertical_intersect and horizontal_intersect

    def __repr__(self):
        return '{}({}, {}, {})'.format(
            self.__class__.__name__,
            self.bbox,
            self.max_items,
            self.max_depth)

    def __contains__(self, element):
        return (element in self.contents or
                any(element in qt for qt in self.children))

    def __iter__(self):
        if self.contents:
            return (element for element in self.contents)
        else:
            return chain.from_iterable(self.children)

    def __len__(self):
        if self.contents:
            return len(self.contents)
        else:
            return sum(len(child) for child in self.children)

    def __getitem__(self, key):
        """Will return the first element containing whose
        value equals key.
        """
        if self.children:
            item = None
            for child in self.children:
                try:
                    item = child[key]
                    break
                except KeyError:
                    continue
            if item is None:
                raise KeyError(key)
            return item
        items = [el for el in self.contents if el[0] == key]
        if not items:
            raise KeyError(key)
        return items[0]

def _inside(element, bbox):
    """Test whether an element is inside a bounding box.

    :param element: 3-iterable, the first item
                    is the element's "value"
                    while the second and third
                    are the easting and northing
                    respectively.

    :param bbox: 4-iterable containing the bottom-left and
                 top right coordinates (easting, northing).
                 E.g. [0, 0, 10, 10]

    """
    x0, y0, x1, y1 = bbox
    _, x, y = element
    return x0 <= x < x1 and y0 <= y < y1

def _validate_bbox(bbox):
    x0, y0, x1, y1 = bbox
    x_ok = x0 < x1
    y_ok = y0 < y1
    if not x_ok and not y_ok:
        raise ValueError(
            'Invalid bounding box: {}'.format(bbox))
<commit_msg>Bump version 1.0.0 -> 1.1.0<commit_after># -*- coding: utf-8 -*-

# Copyright 2016 - 2018: Stefano Mazzucco <stefano AT curso DOT re>

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#   http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import division

from itertools import chain

try:
    from functools import reduce
except ImportError:  # pragma: no cover
    pass

__version__ = '1.1.0'
__all__ = ['QuadTree']

class QuadTree(object):
    def __init__(self, bbox, max_items=10, max_depth=10):
        """Initialize a quadtree.

        :param bbox: bounding box, 4-iterable containing the bottom-left and
                     top right coordinates (easting, northing).
                     E.g. [0, 0, 10, 10]
        :param max_items: the maximum number of items that can be
                          held in the bounding box before the
                          quadtree splits it into four smaller ones
                          (children quadtrees)
        :param max_depth: the maximum depth of the quadtree. Once this
                          value is reached, the instance will split no
                          more and all elements will be stored in the
                          lowest level quadrant

        """
        _validate_bbox(bbox)
        self.max_items = max_items
        self.max_depth = int(max_depth) if max_depth >= 0 else 0
        self.bbox = bbox
        self.contents = []
        self.children = ()

    def insert(self, element):
        """Insert an element in the quadtree. If the
        element's coordinates are not within the quadtree's
        bounding box, the insertion will fail.

        Note that an element with coordinates x, y is
        considered to be inside the bounding box if
        x0 <= x < x1 and y0 <= y < y1.

        :param element: 3-iterable, the first item
                        is the element's "value"
                        while the second and third
                        are the easting and northing
                        respectively.

        :returns: True or False depending on whether
                  the insertion succeeded.

        """
        if not _inside(element, self.bbox):
            return False
        if self.children:
            for child in self.children:
                result = child.insert(element)
                if result:
                    self.contents = []
                    return result
        self.contents.append(element)
        if len(self.contents) > self.max_items and self.max_depth > 0:
            self._split()
        return True

    def _split(self):
        x0, y0, x1, y1 = self.bbox
        xm = (x1 - x0) / 2
        ym = (y1 - y0) / 2

        sw = x0, y0, x0 + xm, y0 + ym
        se = x0 + xm, y0, x1, y0 + ym
        ne = x0 + xm, y0 + ym, x1, y1
        nw = x0, y0 + ym, x0 + xm, y1
        self.children = (QuadTree(sw, self.max_items, self.max_depth - 1),
                         QuadTree(se, self.max_items, self.max_depth - 1),
                         QuadTree(ne, self.max_items, self.max_depth - 1),
                         QuadTree(nw, self.max_items, self.max_depth - 1))

        while self.contents:
            element = self.contents.pop()
            for child in self.children:
                if child.insert(element):
                    break

    def intersect(self, bbox):
        """Return a list of elements of the quadtree
        that intersect the given bounding box.

        :param bbox: 4-iterable containing the bottom-left and
                     top right coordinates (easting, northing).
                     E.g. [0, 0, 10, 10]

        :returns: a set of intersecting elements (may be empty)

        """
        if not self._intersects_bbox(bbox):
            return set()
        if self.children:
            return reduce(
                lambda x, y: x.union(y),
                (c.intersect(bbox) for c in self.children),
                set())
        return set(element for element in self.contents
                   if _inside(element, bbox))

    def _intersects_bbox(self, bbox):
        x0, y0, x1, y1 = self.bbox
        xi0, yi0, xi1, yi1 = bbox

        vertical_intersect = not (yi0 >= y1 or yi1 < y0)
        horizontal_intersect = not (xi0 >= x1 or xi1 < x0)

        return vertical_intersect and horizontal_intersect

    def __repr__(self):
        return '{}({}, {}, {})'.format(
            self.__class__.__name__,
            self.bbox,
            self.max_items,
            self.max_depth)

    def __contains__(self, element):
        return (element in self.contents or
                any(element in qt for qt in self.children))

    def __iter__(self):
        if self.contents:
            return (element for element in self.contents)
        else:
            return chain.from_iterable(self.children)

    def __len__(self):
        if self.contents:
            return len(self.contents)
        else:
            return sum(len(child) for child in self.children)

    def __getitem__(self, key):
        """Will return the first element containing whose
        value equals key.
        """
        if self.children:
            item = None
            for child in self.children:
                try:
                    item = child[key]
                    break
                except KeyError:
                    continue
            if item is None:
                raise KeyError(key)
            return item
        items = [el for el in self.contents if el[0] == key]
        if not items:
            raise KeyError(key)
        return items[0]

def _inside(element, bbox):
    """Test whether an element is inside a bounding box.

    :param element: 3-iterable, the first item
                    is the element's "value"
                    while the second and third
                    are the easting and northing
                    respectively.

    :param bbox: 4-iterable containing the bottom-left and
                 top right coordinates (easting, northing).
                 E.g. [0, 0, 10, 10]

    """
    x0, y0, x1, y1 = bbox
    _, x, y = element
    return x0 <= x < x1 and y0 <= y < y1

def _validate_bbox(bbox):
    x0, y0, x1, y1 = bbox
    x_ok = x0 < x1
    y_ok = y0 < y1
    if not x_ok and not y_ok:
        raise ValueError(
            'Invalid bounding box: {}'.format(bbox))
<|endoftext|>


<commit_before>import os, sys, select, subprocess

args = ['mode2', '-d', '/dev/lirc0']
p1 = subprocess.Popen(args, stdout=subprocess.PIPE)
p2 = subprocess.Popen(args, stdout=subprocess.PIPE)

space_list = []
pulse_list = []
try:
    while True:
        rlist, wlist, xlist = select.select([p1.stdout, p2.stdout], [], [])
        for stdout in rlist:
            output = os.read(stdout.fileno(), 1024).decode('utf-8')

            if output:
                # sys.stdout.write(output)
                # sys.stdout.write('indicator: ' + output)
                o = output.split()
                if len(o) == 4:
                    for wave, length in zip(o[::2], o[1::2]):
                        if wave == 'space':
                            space_list.append(int(length))
                        elif wave == 'pulse':
                            pulse_list.append(int(length))

                    if len(space_list) == 36 and len(pulse_list) == 36:
                        pass

except KeyboardInterrupt:
    print('Exist Now....')
    sys.exit(0)<commit_msg>add relay to read_irr function<commit_after>import os, sys, select, subprocess
from relay import RelayLED

def read_irr():
    args = ['mode2', '-d', '/dev/lirc0']
    p1 = subprocess.Popen(args, stdout=subprocess.PIPE)
    p2 = subprocess.Popen(args, stdout=subprocess.PIPE)

    space_list = []
    pulse_list = []
    led = RelayLED()
    try:
        while True:
            rlist, wlist, xlist = select.select([p1.stdout, p2.stdout], [], [])
            for stdout in rlist:
                output = os.read(stdout.fileno(), 1024).decode('utf-8')

                if output:
                    # sys.stdout.write(output)
                    # sys.stdout.write('indicator: ' + output)
                    o = output.split()
                    if len(o) == 4:
                        for wave, length in zip(o[::2], o[1::2]):
                            if wave == 'space':
                                space_list.append(int(length))
                            elif wave == 'pulse':
                                pulse_list.append(int(length))

                        if len(space_list) == 36 and len(pulse_list) == 36:
                            led.toggle()

    except KeyboardInterrupt:
        print('Exist Now....')
        sys.exit(0)<|endoftext|>


<commit_before>"""
xbox_score_client.py

Reads joystick data from the xbox controller and converts it into score packets

@author: Allen Li
"""

import lcm
import argparse
import forseti2 as fs2
import settings
import util

SLEEP_TIME = 0.1
# packet format
PF = fs2.xbox_joystick_state

#Button configurations
BUTTON_GAME_PIECE_ENTER = [PF.A]
BUTTON_PERMANENT_GOAL_SCORE = [PF.B]
BUTTON_DISPENSER_BALLS_ENTER_FIELD = [PF.X]

BUTTON_BONUS_SET_BLUE = [PF.LB]
BUTTON_BONUS_SET_GOLD = [PF.RB]
AXIS_BONUS_SET_BLUE = [] # TODO
AXIS_BONUS_SET_GOLD = [] # TODO
BUTTON_BONUS_TOGGLE = [PF.A]

def describe_button(b):
    mapping = {
        PF.A : "A",
        PF.B : "B",
        PF.X : "X",
        PF.Y : "Y",
        PF.LB : "Left Button",
        PF.RB : "Right Button",
        PF.BACK : "Back",
        PF.START : "Start",
        PF.GUIDE : "Guide",
        PF.LSTICK : "Left stick press",
        PF.RSTICK : "Right stick press",
    }
    try:
        return ", ".join(describe_button(bb) for bb in b)
    except TypeError:
        if b in mapping:
            return mapping[b]
        else:
            return "Unknown"

class ScoreClient(object):

    def __init__(self, joystick_channel='default'):
        self.lc = lcm.LCM(settings.LCM_URI)
        self.subscription = self.lc.subscribe("xbox/state/{}/0".format(joystick_channel),
                                              self.handle_xbox)
        self.seq = util.LCMSequence(self.lc, fs2.score_delta, "score/delta")
        self.buttons = [0 for _ in xrange(11)]

    def update(self, i, b):
        print "RUNNING BASE ScoreClient"

    def process_message(self, msg):
        for i, b in enumerate(msg.buttons):
            if self.buttons[i] != b:
                self.buttons[i] = b
                self.update(i, b)

    def handle_xbox(self, channel, data):
        self.process_message(PF.decode(data))

    def handle(self):
        self.lc.handle()

    def update_alliance(self, alliance, i, b):
        if b != 1:
            # respond only on the down press
            return

        assert(alliance in [fs2.score_delta.BLUE, fs2.score_delta.GOLD])
        if alliance == fs2.score_delta.BLUE:
            if i in BUTTON_GAME_PIECE_ENTER:
                self.seq.publish(gold_normal_points=settings.GAME_PIECE_VALUE)
            elif i in BUTTON_PERMANENT_GOAL_SCORE:
                self.seq.publish(blue_permanent_points=settings.PERMANENT_GOAL_VALUE)
            elif i in BUTTON_DISPENSER_BALLS_ENTER_FIELD:
                self.seq.publish(gold_normal_points=settings.BALL_VALUE_PER_DISPENSER)
        else:
            if i in BUTTON_GAME_PIECE_ENTER:
                self.seq.publish(blue_normal_points=settings.GAME_PIECE_VALUE)
            elif i in BUTTON_PERMANENT_GOAL_SCORE:
                self.seq.publish(gold_permanent_points=settings.PERMANENT_GOAL_VALUE)
            elif i in BUTTON_DISPENSER_BALLS_ENTER_FIELD:
                self.seq.publish(blue_normal_points=settings.BALL_VALUE_PER_DISPENSER)

    def update_bonus(self, i, b):
        if b != 1:
            # respond only on the down press
            return

        if i in BUTTON_BONUS_SET_BLUE:
            self.seq.publish(bonus_possession=fs2.score_delta.BLUE)
        elif i in BUTTON_BONUS_SET_GOLD:
            self.seq.publish(bonus_possession=fs2.score_delta.GOLD)
        elif i in BUTTON_BONUS_TOGGLE:
            self.seq.publish(bonus_possession=fs2.score_delta.TOGGLE,
                             bonus_points=settings.BONUS_INCREMENT)

    def print_mapping_alliance(self, alliance):
        assert(alliance in [fs2.score_delta.BLUE, fs2.score_delta.GOLD])
        color = "Blue" if alliance == fs2.score_delta.BLUE else "Gold"

        print "Button mapping"
        print "--------------"
        print "    Game piece enters {} side of the field: {}".format(
            color,
            "".join(describe_button(BUTTON_GAME_PIECE_ENTER)))
        print "    {} alliance scores permanent goal: {}".format(
            color,
            "".join(describe_button(BUTTON_PERMANENT_GOAL_SCORE)))
        print "    Dispenser fully releases on {} side of the field: {}".format(
            color,
            "".join(describe_button(BUTTON_DISPENSER_BALLS_ENTER_FIELD)))

    def print_mapping_bonus(self):
        print "Button mapping"
        print "--------------"
        print "    Bonus ball initially enters the Blue side of the field:", describe_button(BUTTON_BONUS_SET_BLUE)
        print "    Bonus ball initially enters the Gold side of the field:", describe_button(BUTTON_BONUS_SET_GOLD)
        print "    Toggle bonus ball side, increment score:", describe_button(BUTTON_BONUS_TOGGLE)

class BlueScoreClient(ScoreClient):
    def update(self, i, b):
        self.update_alliance(fs2.score_delta.BLUE, i, b)

    def print_mapping(self):
        self.print_mapping_alliance(fs2.score_delta.BLUE)

class GoldScoreClient(ScoreClient):
    def update(self, i, b):
        self.update_alliance(fs2.score_delta.GOLD, i, b)

    def print_mapping(self):
        self.print_mapping_alliance(fs2.score_delta.GOLD)

class BonusScoreClient(ScoreClient):
    def update(self, i, b):
        self.update_bonus(i, b)

    def print_mapping(self):
        self.print_mapping_bonus()

class DebugScoreClient(ScoreClient):
    """
    Score client for debugging purposes.

    Penalties and resets would normally be done using the judge interface, but
    this provides an alternative for debugging purposes
    """

    button_actions = {
        PF.X : ("increment blue points", dict(blue_normal_points=settings.GAME_PIECE_VALUE)),
        PF.Y : ("increment gold points", dict(gold_normal_points=settings.GAME_PIECE_VALUE)),
        PF.A : ("increment blue permanent points", dict(blue_permanent_points=settings.PERMANENT_GOAL_VALUE)),
        PF.B : ("increment gold permanent points", dict(gold_permanent_points=settings.PERMANENT_GOAL_VALUE)),
        PF.BACK : ("blue bonus ball", dict(bonus_possession=fs2.score_delta.BLUE)),
        PF.START : ("gold bonus ball", dict(bonus_possession=fs2.score_delta.GOLD)),
        PF.GUIDE : ("change bonus ball posession, increment score", dict(
            bonus_possession=fs2.score_delta.TOGGLE,
            bonus_points=settings.BONUS_INCREMENT)),
        PF.LB : ("blue penalty", dict(blue_penalty=settings.PENALTY_REGULAR)),
        PF.RB : ("gold penalty", dict(gold_penalty=settings.PENALTY_REGULAR)),
        PF.RSTICK : ("RESET", dict(action_reset=True)),
    }

    def update(self, i, b):
        if b != 1:
            # respond only on the down press
            return

        if i in self.button_actions:
            self.seq.publish(**self.button_actions[i][1])

    def print_mapping(self):
        print "Button mapping"
        print "--------------"

        for k, v in self.button_actions.items():
            print "{:>20}: {}".format(describe_button(k), v[0])

def main():
    parser = argparse.ArgumentParser(description="Receives joystick values and outputs score changes")
    parser.add_argument('--type', required=True, type=str, choices=['blue', 'gold', 'bonus', 'debug'], action='store')
    parser.add_argument('--joystick', default=0, help="Joystick channel name")
    args = parser.parse_args()
    if args.type == 'blue':
        sclient = BlueScoreClient(joystick_channel=args.joystick)
    elif args.type == 'gold':
        sclient = GoldScoreClient(joystick_channel=args.joystick)
    elif args.type == 'bonus':
        sclient = BonusScoreClient(joystick_channel=args.joystick)
    elif args.type == 'debug':
        sclient = DebugScoreClient(joystick_channel=args.joystick)

    print "Initialized ScoreClient..."
    sclient.print_mapping()
    try:
        while True:
            sclient.handle()
    except KeyboardInterrupt:
        pass

if __name__ == '__main__':
    main()
<commit_msg>Fix scoring system<commit_after>"""
xbox_score_client.py

Reads joystick data from the xbox controller and converts it into score packets

@author: Allen Li
"""

import lcm
import argparse
import forseti2 as fs2
import settings
import util

SLEEP_TIME = 0.1
# packet format
PF = fs2.xbox_joystick_state

#Button configurations
BUTTON_GAME_PIECE_ENTER = [PF.A]
BUTTON_PERMANENT_GOAL_SCORE = [PF.B]
BUTTON_DISPENSER_BALLS_ENTER_FIELD = [PF.X]

BUTTON_BONUS_SET_BLUE = [PF.LB]
BUTTON_BONUS_SET_GOLD = [PF.RB]
AXIS_BONUS_SET_BLUE = [] # TODO
AXIS_BONUS_SET_GOLD = [] # TODO
BUTTON_BONUS_TOGGLE = [PF.A]

def describe_button(b):
    mapping = {
        PF.A : "A",
        PF.B : "B",
        PF.X : "X",
        PF.Y : "Y",
        PF.LB : "Left Button",
        PF.RB : "Right Button",
        PF.BACK : "Back",
        PF.START : "Start",
        PF.GUIDE : "Guide",
        PF.LSTICK : "Left stick press",
        PF.RSTICK : "Right stick press",
    }
    try:
        return ", ".join(describe_button(bb) for bb in b)
    except TypeError:
        if b in mapping:
            return mapping[b]
        else:
            return "Unknown"

class ScoreClient(object):

    def __init__(self, joystick_channel='default'):
        self.lc = lcm.LCM(settings.LCM_URI)
        self.subscription = self.lc.subscribe("xbox/state/{}/0".format(joystick_channel),
                                              self.handle_xbox)
        self.seq = util.LCMSequence(self.lc, fs2.score_delta, "score/delta")
        self.buttons = [0 for _ in xrange(11)]

    def update(self, i, b):
        print "RUNNING BASE ScoreClient"

    def process_message(self, msg):
        for i, b in enumerate(msg.buttons):
            if self.buttons[i] != b:
                self.buttons[i] = b
                self.update(i, b)

    def handle_xbox(self, channel, data):
        self.process_message(PF.decode(data))

    def handle(self):
        self.lc.handle()

    def update_alliance(self, alliance, i, b):
        if b != 1:
            # respond only on the down press
            return

        assert(alliance in [fs2.score_delta.BLUE, fs2.score_delta.GOLD])
        if alliance == fs2.score_delta.BLUE:
            if i in BUTTON_GAME_PIECE_ENTER:
                self.seq.publish(
                    blue_normal_points=-settings.GAME_PIECE_VALUE,
                    gold_normal_points=settings.GAME_PIECE_VALUE
                    )
            elif i in BUTTON_PERMANENT_GOAL_SCORE:
                self.seq.publish(
                    gold_normal_points=-settings.GAME_PIECE_VALUE,
                    blue_permanent_points=settings.PERMANENT_GOAL_VALUE
                    )
            elif i in BUTTON_DISPENSER_BALLS_ENTER_FIELD:
                self.seq.publish(gold_normal_points=settings.BALL_VALUE_PER_DISPENSER)
        else:
            if i in BUTTON_GAME_PIECE_ENTER:
                self.seq.publish(
                    blue_normal_points=settings.GAME_PIECE_VALUE,
                    gold_normal_points=-settings.GAME_PIECE_VALUE
                    )
            elif i in BUTTON_PERMANENT_GOAL_SCORE:
                self.seq.publish(
                    gold_permanent_points=settings.PERMANENT_GOAL_VALUE,
                    blue_normal_points=-settings.GAME_PIECE_VALUE
                    )
            elif i in BUTTON_DISPENSER_BALLS_ENTER_FIELD:
                self.seq.publish(blue_normal_points=settings.BALL_VALUE_PER_DISPENSER)

    def update_bonus(self, i, b):
        if b != 1:
            # respond only on the down press
            return

        if i in BUTTON_BONUS_SET_BLUE:
            self.seq.publish(bonus_possession=fs2.score_delta.BLUE)
        elif i in BUTTON_BONUS_SET_GOLD:
            self.seq.publish(bonus_possession=fs2.score_delta.GOLD)
        elif i in BUTTON_BONUS_TOGGLE:
            self.seq.publish(bonus_possession=fs2.score_delta.TOGGLE,
                             bonus_points=settings.BONUS_INCREMENT)

    def print_mapping_alliance(self, alliance):
        assert(alliance in [fs2.score_delta.BLUE, fs2.score_delta.GOLD])
        color = "Blue" if alliance == fs2.score_delta.BLUE else "Gold"

        print "Button mapping"
        print "--------------"
        print "    Game piece enters {} side of the field: {}".format(
            color,
            "".join(describe_button(BUTTON_GAME_PIECE_ENTER)))
        print "    {} alliance scores permanent goal: {}".format(
            color,
            "".join(describe_button(BUTTON_PERMANENT_GOAL_SCORE)))
        print "    Dispenser fully releases on {} side of the field: {}".format(
            color,
            "".join(describe_button(BUTTON_DISPENSER_BALLS_ENTER_FIELD)))

    def print_mapping_bonus(self):
        print "Button mapping"
        print "--------------"
        print "    Bonus ball initially enters the Blue side of the field:", describe_button(BUTTON_BONUS_SET_BLUE)
        print "    Bonus ball initially enters the Gold side of the field:", describe_button(BUTTON_BONUS_SET_GOLD)
        print "    Toggle bonus ball side, increment score:", describe_button(BUTTON_BONUS_TOGGLE)

class BlueScoreClient(ScoreClient):
    def update(self, i, b):
        self.update_alliance(fs2.score_delta.BLUE, i, b)

    def print_mapping(self):
        self.print_mapping_alliance(fs2.score_delta.BLUE)

class GoldScoreClient(ScoreClient):
    def update(self, i, b):
        self.update_alliance(fs2.score_delta.GOLD, i, b)

    def print_mapping(self):
        self.print_mapping_alliance(fs2.score_delta.GOLD)

class BonusScoreClient(ScoreClient):
    def update(self, i, b):
        self.update_bonus(i, b)

    def print_mapping(self):
        self.print_mapping_bonus()

class DebugScoreClient(ScoreClient):
    """
    Score client for debugging purposes.

    Penalties and resets would normally be done using the judge interface, but
    this provides an alternative for debugging purposes
    """

    button_actions = {
        PF.X : ("increment blue points", dict(blue_normal_points=settings.GAME_PIECE_VALUE)),
        PF.Y : ("increment gold points", dict(gold_normal_points=settings.GAME_PIECE_VALUE)),
        PF.A : ("increment blue permanent points", dict(blue_permanent_points=settings.PERMANENT_GOAL_VALUE)),
        PF.B : ("increment gold permanent points", dict(gold_permanent_points=settings.PERMANENT_GOAL_VALUE)),
        PF.BACK : ("blue bonus ball", dict(bonus_possession=fs2.score_delta.BLUE)),
        PF.START : ("gold bonus ball", dict(bonus_possession=fs2.score_delta.GOLD)),
        PF.GUIDE : ("change bonus ball posession, increment score", dict(
            bonus_possession=fs2.score_delta.TOGGLE,
            bonus_points=settings.BONUS_INCREMENT)),
        PF.LB : ("blue penalty", dict(blue_penalty=settings.PENALTY_REGULAR)),
        PF.RB : ("gold penalty", dict(gold_penalty=settings.PENALTY_REGULAR)),
        PF.RSTICK : ("RESET", dict(action_reset=True)),
    }

    def update(self, i, b):
        if b != 1:
            # respond only on the down press
            return

        if i in self.button_actions:
            self.seq.publish(**self.button_actions[i][1])

    def print_mapping(self):
        print "Button mapping"
        print "--------------"

        for k, v in self.button_actions.items():
            print "{:>20}: {}".format(describe_button(k), v[0])

def main():
    parser = argparse.ArgumentParser(description="Receives joystick values and outputs score changes")
    parser.add_argument('--type', required=True, type=str, choices=['blue', 'gold', 'bonus', 'debug'], action='store')
    parser.add_argument('--joystick', default=0, help="Joystick channel name")
    args = parser.parse_args()
    if args.type == 'blue':
        sclient = BlueScoreClient(joystick_channel=args.joystick)
    elif args.type == 'gold':
        sclient = GoldScoreClient(joystick_channel=args.joystick)
    elif args.type == 'bonus':
        sclient = BonusScoreClient(joystick_channel=args.joystick)
    elif args.type == 'debug':
        sclient = DebugScoreClient(joystick_channel=args.joystick)

    print "Initialized ScoreClient..."
    sclient.print_mapping()
    try:
        while True:
            sclient.handle()
    except KeyboardInterrupt:
        pass

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