<commit_before>from __future__ import absolute_import

import linecache
import os
import re
import tokenize
import weakref
from functools import partial
from threading import current_thread

from fields import Fields

from .const import SITE_PACKAGES_PATHS
from .const import SYS_PREFIX_PATHS
from .util import cached_property

try:
    from threading import main_thread
except ImportError:
    from threading import _shutdown
    get_main_thread = weakref.ref(
        _shutdown.__self__ if hasattr(_shutdown, '__self__') else _shutdown.im_self)
    del _shutdown
else:
    get_main_thread = weakref.ref(main_thread())

__all__ = 'Event',

STARTSWITH_TYPES = list, tuple, set
CYTHON_SUFFIX_RE = re.compile(r'([.]cpython-[0-9]+.+)?[.](so|pyd)$', re.IGNORECASE)
LEADING_WHITESPACE_RE = re.compile('(^[ \t]*)(?:[^ \t\n])', re.MULTILINE)

class Event(Fields.kind.function.module.filename):
    """
    Event wrapper for ``frame, kind, arg`` (the arguments the settrace function gets). This objects is passed to your
    custom functions or predicates.

    Provides few convenience properties.

    .. warning::

        Users do not instantiate this directly.
    """
    frame = None
    kind = None
    arg = None
    tracer = None
    threadid = None
    threadname = None

    def __init__(self, frame, kind, arg, tracer):
        self.frame = frame
        self.kind = kind
        self.arg = arg
        self.tracer = tracer

    @cached_property
    def threadid(self):
        """
        Current thread ident. If current thread is main thread then it returns ``None``.
        """
        current = self.thread.ident
        main = get_main_thread()
        if main is None:
            return current
        else:
            return current if current != main.ident else None

    @cached_property
    def threadname(self):
        """
        Current thread name.
        """
        return self.thread.name

    @cached_property
    def thread(self):
        """
        Current thread object.
        """
        return current_thread()

    @cached_property
    def locals(self):
        """
        A dict with local variables.
        """
        return self.frame.f_locals

    @cached_property
    def globals(self):
        """
        A dict with global variables.
        """
        return self.frame.f_globals

    @cached_property
    def function(self):
        """
        A string with function name.
        """
        return self.code.co_name

    @cached_property
    def module(self):
        """
        A string with module name (eg: ``"foo.bar"``).
        """
        module = self.frame.f_globals.get('__name__', '')
        if module is None:
            module = ''

        return module

    @cached_property
    def filename(self, exists=os.path.exists, cython_suffix_re=CYTHON_SUFFIX_RE):
        """
        A string with absolute path to file.
        """
        filename = self.frame.f_globals.get('__file__', '')

        print filename
        if filename is None:
            filename = ''

        if filename.endswith(('.pyc', '.pyo')):
            filename = filename[:-1]
        elif filename.endswith('$py.class'):  # Jython
            filename = filename[:-9] + ".py"
        elif filename.endswith(('.so', '.pyd')):
            print 'cy:', filename
            basename = cython_suffix_re.sub('', filename)
            for ext in ('.pyx', '.py'):
                cyfilename = basename + ext
                print 'cy-:', filename
                if exists(cyfilename):
                    print 'cy:', cyfilename
                    filename = cyfilename
                    break
        return filename

    @cached_property
    def lineno(self):
        """
        An integer with line number in file.
        """
        return self.frame.f_lineno

    @cached_property
    def code(self):
        """
        A code object (not a string).
        """
        return self.frame.f_code

    @cached_property
    def stdlib(self):
        """
        A boolean flag. ``True`` if frame is in stdlib.
        """
        if self.filename.startswith(SITE_PACKAGES_PATHS):
            # if it's in site-packages then its definitely not stdlib
            return False
        elif self.filename.startswith(SYS_PREFIX_PATHS):
            return True
        else:
            return False

    @cached_property
    def fullsource(self):
        """
        A string with the sourcecode for the current statement (from ``linecache`` - failures are ignored).

        May include multiple lines if it's a class/function definition (will include decorators).
        """
        try:
            return self._raw_fullsource
        except Exception as exc:
            return "??? NO SOURCE: {!r}".format(exc)

    @cached_property
    def source(self, getline=linecache.getline):
        """
        A string with the sourcecode for the current line (from ``linecache`` - failures are ignored).

        Fast but sometimes incomplete.
        """
        try:
            return getline(self.filename, self.lineno)
        except Exception as exc:
            return "??? NO SOURCE: {!r}".format(exc)

    @cached_property
    def _raw_fullsource(self,
                        getlines=linecache.getlines,
                        getline=linecache.getline,
                        generate_tokens=tokenize.generate_tokens):
        if self.kind == 'call' and self.code.co_name != "<module>":
            lines = []
            try:
                for _, token, _, _, line in generate_tokens(partial(
                    next,
                    yield_lines(self.filename, self.lineno - 1, lines.append)
                )):
                    if token in ("def", "class", "lambda"):
                        return ''.join(lines)
            except tokenize.TokenError:
                pass

        return getline(self.filename, self.lineno)

    __getitem__ = object.__getattribute__

def yield_lines(filename, start, collector,
                limit=10,
                getlines=linecache.getlines,
                leading_whitespace_re=LEADING_WHITESPACE_RE):
    dedent = None
    amount = 0
    for line in getlines(filename)[start:start + limit]:
        if dedent is None:
            dedent = leading_whitespace_re.findall(line)
            dedent = dedent[0] if dedent else ""
            amount = len(dedent)
        elif not line.startswith(dedent):
            break
        collector(line)
        yield line[amount:]
<commit_msg>Ooops.<commit_after>from __future__ import absolute_import

import linecache
import os
import re
import tokenize
import weakref
from functools import partial
from threading import current_thread

from fields import Fields

from .const import SITE_PACKAGES_PATHS
from .const import SYS_PREFIX_PATHS
from .util import cached_property

try:
    from threading import main_thread
except ImportError:
    from threading import _shutdown
    get_main_thread = weakref.ref(
        _shutdown.__self__ if hasattr(_shutdown, '__self__') else _shutdown.im_self)
    del _shutdown
else:
    get_main_thread = weakref.ref(main_thread())

__all__ = 'Event',

STARTSWITH_TYPES = list, tuple, set
CYTHON_SUFFIX_RE = re.compile(r'([.]cpython-[0-9]+.+)?[.](so|pyd)$', re.IGNORECASE)
LEADING_WHITESPACE_RE = re.compile('(^[ \t]*)(?:[^ \t\n])', re.MULTILINE)

class Event(Fields.kind.function.module.filename):
    """
    Event wrapper for ``frame, kind, arg`` (the arguments the settrace function gets). This objects is passed to your
    custom functions or predicates.

    Provides few convenience properties.

    .. warning::

        Users do not instantiate this directly.
    """
    frame = None
    kind = None
    arg = None
    tracer = None
    threadid = None
    threadname = None

    def __init__(self, frame, kind, arg, tracer):
        self.frame = frame
        self.kind = kind
        self.arg = arg
        self.tracer = tracer

    @cached_property
    def threadid(self):
        """
        Current thread ident. If current thread is main thread then it returns ``None``.
        """
        current = self.thread.ident
        main = get_main_thread()
        if main is None:
            return current
        else:
            return current if current != main.ident else None

    @cached_property
    def threadname(self):
        """
        Current thread name.
        """
        return self.thread.name

    @cached_property
    def thread(self):
        """
        Current thread object.
        """
        return current_thread()

    @cached_property
    def locals(self):
        """
        A dict with local variables.
        """
        return self.frame.f_locals

    @cached_property
    def globals(self):
        """
        A dict with global variables.
        """
        return self.frame.f_globals

    @cached_property
    def function(self):
        """
        A string with function name.
        """
        return self.code.co_name

    @cached_property
    def module(self):
        """
        A string with module name (eg: ``"foo.bar"``).
        """
        module = self.frame.f_globals.get('__name__', '')
        if module is None:
            module = ''

        return module

    @cached_property
    def filename(self, exists=os.path.exists, cython_suffix_re=CYTHON_SUFFIX_RE):
        """
        A string with absolute path to file.
        """
        filename = self.frame.f_globals.get('__file__', '')
        if filename is None:
            filename = ''

        if filename.endswith(('.pyc', '.pyo')):
            filename = filename[:-1]
        elif filename.endswith('$py.class'):  # Jython
            filename = filename[:-9] + ".py"
        elif filename.endswith(('.so', '.pyd')):
            basename = cython_suffix_re.sub('', filename)
            for ext in ('.pyx', '.py'):
                cyfilename = basename + ext
                if exists(cyfilename):
                    filename = cyfilename
                    break
        return filename

    @cached_property
    def lineno(self):
        """
        An integer with line number in file.
        """
        return self.frame.f_lineno

    @cached_property
    def code(self):
        """
        A code object (not a string).
        """
        return self.frame.f_code

    @cached_property
    def stdlib(self):
        """
        A boolean flag. ``True`` if frame is in stdlib.
        """
        if self.filename.startswith(SITE_PACKAGES_PATHS):
            # if it's in site-packages then its definitely not stdlib
            return False
        elif self.filename.startswith(SYS_PREFIX_PATHS):
            return True
        else:
            return False

    @cached_property
    def fullsource(self):
        """
        A string with the sourcecode for the current statement (from ``linecache`` - failures are ignored).

        May include multiple lines if it's a class/function definition (will include decorators).
        """
        try:
            return self._raw_fullsource
        except Exception as exc:
            return "??? NO SOURCE: {!r}".format(exc)

    @cached_property
    def source(self, getline=linecache.getline):
        """
        A string with the sourcecode for the current line (from ``linecache`` - failures are ignored).

        Fast but sometimes incomplete.
        """
        try:
            return getline(self.filename, self.lineno)
        except Exception as exc:
            return "??? NO SOURCE: {!r}".format(exc)

    @cached_property
    def _raw_fullsource(self,
                        getlines=linecache.getlines,
                        getline=linecache.getline,
                        generate_tokens=tokenize.generate_tokens):
        if self.kind == 'call' and self.code.co_name != "<module>":
            lines = []
            try:
                for _, token, _, _, line in generate_tokens(partial(
                    next,
                    yield_lines(self.filename, self.lineno - 1, lines.append)
                )):
                    if token in ("def", "class", "lambda"):
                        return ''.join(lines)
            except tokenize.TokenError:
                pass

        return getline(self.filename, self.lineno)

    __getitem__ = object.__getattribute__

def yield_lines(filename, start, collector,
                limit=10,
                getlines=linecache.getlines,
                leading_whitespace_re=LEADING_WHITESPACE_RE):
    dedent = None
    amount = 0
    for line in getlines(filename)[start:start + limit]:
        if dedent is None:
            dedent = leading_whitespace_re.findall(line)
            dedent = dedent[0] if dedent else ""
            amount = len(dedent)
        elif not line.startswith(dedent):
            break
        collector(line)
        yield line[amount:]
<|endoftext|>


<commit_before>import prpy.planning, threading, openravepy, numpy

class MockPlanner(prpy.planning.BasePlanner):
    def __init__(self, delay=False):
        prpy.planning.BasePlanner.__init__(self)
        self.num_calls = 0
        self.delay = delay
        self.start_condition = threading.Condition()
        self.done_condition = threading.Condition()
        self.running = False

    def wait_for_start(self):
        if self.delay:
            with self.start_condition:
                while not self.running:
                    self.start_condition.wait()

    def finish(self):
        with self.done_condition:
            self.done_condition.notify_all()

    def _PlanGeneric(self, delegate_method, *args, **kw_args):
        # Notify other threads that the planner has started.
        with self.start_condition:
            self.num_calls += 1
            self.running = True
            self.start_condition.notify_all()

        # Optionally wait before returning
        if self.delay:
            with self.done_condition:
                self.done_condition.wait()

        # Compute the return value and return.
        try:
            return delegate_method(*args, **kw_args)
        finally:
            with self.start_condition:
                self.running = False

class SuccessPlanner(MockPlanner):
    def __init__(self, template_traj, delay=False):
        MockPlanner.__init__(self, delay=delay)

        with self.env:
            # Clone the template trajectory into the planning environment.
            self.traj = openravepy.RaveCreateTrajectory(self.env, template_traj.GetXMLId())
            self.traj.Clone(template_traj, 0)

    @prpy.planning.PlanningMethod
    def PlanTest(self, robot):
        def Success_impl(robot):
            cspec = robot.GetActiveConfigurationSpecification()
            traj = openravepy.RaveCreateTrajectory(self.env, 'GenericTrajectory')
            traj.Init(cspec)
            traj.Insert(0, numpy.zeros(cspec.GetDOF()))
            traj.Insert(1, numpy.ones(cspec.GetDOF()))
            return traj

        return self._PlanGeneric(Success_impl, robot)

class FailPlanner(MockPlanner):
    @prpy.planning.PlanningMethod
    def PlanTest(self, robot):
        def Failure_impl(robot):
            raise prpy.planning.PlanningError('FailPlanner')

        return self._PlanGeneric(Failure_impl, robot)
<commit_msg>Updated unit tests for namespace changes.<commit_after>import prpy.planning, threading, openravepy, numpy
from prpy.planning.base import BasePlanner, PlanningMethod

class MockPlanner(BasePlanner):
    def __init__(self, delay=False):
        BasePlanner.__init__(self)
        self.num_calls = 0
        self.delay = delay
        self.start_condition = threading.Condition()
        self.done_condition = threading.Condition()
        self.running = False

    def wait_for_start(self):
        if self.delay:
            with self.start_condition:
                while not self.running:
                    self.start_condition.wait()

    def finish(self):
        with self.done_condition:
            self.done_condition.notify_all()

    def _PlanGeneric(self, delegate_method, *args, **kw_args):
        # Notify other threads that the planner has started.
        with self.start_condition:
            self.num_calls += 1
            self.running = True
            self.start_condition.notify_all()

        # Optionally wait before returning
        if self.delay:
            with self.done_condition:
                self.done_condition.wait()

        # Compute the return value and return.
        try:
            return delegate_method(*args, **kw_args)
        finally:
            with self.start_condition:
                self.running = False

class SuccessPlanner(MockPlanner):
    def __init__(self, template_traj, delay=False):
        MockPlanner.__init__(self, delay=delay)

        with self.env:
            # Clone the template trajectory into the planning environment.
            self.traj = openravepy.RaveCreateTrajectory(self.env, template_traj.GetXMLId())
            self.traj.Clone(template_traj, 0)

    @PlanningMethod
    def PlanTest(self, robot):
        def Success_impl(robot):
            cspec = robot.GetActiveConfigurationSpecification()
            traj = openravepy.RaveCreateTrajectory(self.env, 'GenericTrajectory')
            traj.Init(cspec)
            traj.Insert(0, numpy.zeros(cspec.GetDOF()))
            traj.Insert(1, numpy.ones(cspec.GetDOF()))
            return traj

        return self._PlanGeneric(Success_impl, robot)

class FailPlanner(MockPlanner):
    @PlanningMethod
    def PlanTest(self, robot):
        def Failure_impl(robot):
            raise prpy.planning.PlanningError('FailPlanner')

        return self._PlanGeneric(Failure_impl, robot)
<|endoftext|>


<commit_before>
from nosebase import *

class Seq_Test(object):
    'save seq db and interval to pygr.Data shelve'
    tempDirClass = TempPygrData
    def setup(self,**kwargs):
        tmp = self.tempDirClass(**kwargs)
        self.tempdir = tmp
        self.filename = tmp.copyFile('sp_hbb1')
        from pygr import seqdb
        sp = seqdb.BlastDB(self.filename)
        sp.__doc__ = 'little swissprot'
        hbb = sp['HBB1_TORMA']
        import pygr.Data
        pygr.Data.Bio.Seq.sp = sp
        ival= hbb[10:35]
        ival.__doc__ = 'fragment'
        pygr.Data.Bio.Seq.frag = ival
    def match_test(self):
        pygrData = self.tempdir.force_reload()
        frag = pygrData.Bio.Seq.frag()
        correct = pygrData.Bio.Seq.sp()['HBB1_TORMA'][10:35]
        assert frag == correct, 'seq ival should match'
        assert frag.__doc__ == 'fragment', 'docstring should match'
    def dir_test(self):
        pygrData = self.tempdir.force_reload()
        l = pygrData.dir('Bio')
        assert l == ['Bio.Seq.frag','Bio.Seq.sp']

class Seq_SQL_Test(Seq_Test):
    'save same data to MySQL server'
    tempDirClass = TempPygrDataMySQL
    mysqlArgs = {}
    @skip_errors(ImportError)
    def setup(self):
        import MySQLdb
        try:
            Seq_Test.setup(self,**self.mysqlArgs)
        except MySQLdb.MySQLError:
            raise ImportError

class Seq_SQL2_Test(Seq_SQL_Test):
    'test arg passing mechanism to save to a specific database'
    mysqlArgs = dict(args=' lldb.mbi.ucla.edu')
<commit_msg>added test of PygrDataTextFile storage<commit_after>
from nosebase import *

class Seq_Test(object):
    'save seq db and interval to pygr.Data shelve'
    tempDirClass = TempPygrData
    def setup(self,**kwargs):
        tmp = self.tempDirClass(**kwargs)
        self.tempdir = tmp
        self.filename = tmp.copyFile('sp_hbb1')
        from pygr import seqdb
        sp = seqdb.BlastDB(self.filename)
        sp.__doc__ = 'little swissprot'
        hbb = sp['HBB1_TORMA']
        import pygr.Data
        pygr.Data.Bio.Seq.sp = sp
        ival= hbb[10:35]
        ival.__doc__ = 'fragment'
        pygr.Data.Bio.Seq.frag = ival
    def match_test(self):
        pygrData = self.tempdir.force_reload()
        frag = pygrData.Bio.Seq.frag()
        correct = pygrData.Bio.Seq.sp()['HBB1_TORMA'][10:35]
        assert frag == correct, 'seq ival should match'
        assert frag.__doc__ == 'fragment', 'docstring should match'
        store = PygrDataTextFile('results/seqdb1.pickle')
        saved = store['hbb1 fragment']
        assert frag == saved, 'seq ival should matched stored result'
    def dir_test(self):
        pygrData = self.tempdir.force_reload()
        l = pygrData.dir('Bio')
        assert l == ['Bio.Seq.frag','Bio.Seq.sp']

class Seq_SQL_Test(Seq_Test):
    'save same data to MySQL server'
    tempDirClass = TempPygrDataMySQL
    mysqlArgs = {}
    @skip_errors(ImportError)
    def setup(self):
        import MySQLdb
        try:
            Seq_Test.setup(self,**self.mysqlArgs)
        except MySQLdb.MySQLError:
            raise ImportError

class Seq_SQL2_Test(Seq_SQL_Test):
    'test arg passing mechanism to save to a specific database'
    mysqlArgs = dict(args=' lldb.mbi.ucla.edu')
<|endoftext|>


<commit_before>from django.contrib.contenttypes import fields as contenttypes
from django.db import models
from django.db.models import Q
from core.text import slugify

class Tag(models.Model):
    name = models.CharField(max_length=255)
    slug = models.SlugField(unique=True)

    def __str__(self):
        return self.name

    @classmethod
    def slugify(cls, name):
        return slugify(None, None, name, dodging=False)

class Tagged(models.Model):
    tag = models.ForeignKey('Tag', related_name='tagged')

    tagged = contenttypes.GenericForeignKey('tagged_type', 'tagged_id')
    tagged_id = models.PositiveIntegerField()
    tagged_type = models.ForeignKey('contenttypes.ContentType')

    @classmethod
    def get_tagged_query(cls, tag, model):
        content_type = contenttypes.ContentType.objects.get_for_model(model)
        tagged_objects = Tagged.objects.filter(tagged_type=content_type, tag=tag)
        model_ids = list(map(lambda tagged: tagged.tagged_id, tagged_objects))
        return Q(pk__in=model_ids)

    class Meta:
        ordering = ('tag__name',)
<commit_msg>implement repr for Tagged entity<commit_after>from django.contrib.contenttypes import fields as contenttypes
from django.db import models
from django.db.models import Q
from core.text import slugify

class Tag(models.Model):
    name = models.CharField(max_length=255)
    slug = models.SlugField(unique=True)

    def __str__(self):
        return self.name

    @classmethod
    def slugify(cls, name):
        return slugify(None, None, name, dodging=False)

class Tagged(models.Model):
    tag = models.ForeignKey('Tag', related_name='tagged')

    tagged = contenttypes.GenericForeignKey('tagged_type', 'tagged_id')
    tagged_id = models.PositiveIntegerField()
    tagged_type = models.ForeignKey('contenttypes.ContentType')

    @classmethod
    def get_tagged_query(cls, tag, model):
        content_type = contenttypes.ContentType.objects.get_for_model(model)
        tagged_objects = Tagged.objects.filter(tagged_type=content_type, tag=tag)
        model_ids = list(map(lambda tagged: tagged.tagged_id, tagged_objects))
        return Q(pk__in=model_ids)

    def __repr__(self):
        return "%s was tagged with '%s'" % (str(self.tagged), str(self.tag))

    class Meta:
        ordering = ('tag__name',)
<|endoftext|>


<commit_before>#!/usr/bin/env python
#

# Description
"""
Utilities for plotting SEDs and Castro plots

Many parts of this code are taken from dsphs/like/lnlfn.py by
  Matthew Wood <mdwood@slac.stanford.edu>
  Alex Drlica-Wagner <kadrlica@slac.stanford.edu>
"""

import numpy as np
import matplotlib.pyplot as plt
import matplotlib

NORM_LABEL = [r'Flux Normalization [a.u.]',
              r'E dN/dE [ph $cm^{-2} s^{-1}$]',
              r'$E^2$ dN/dE [MeV $cm^{-2} s^{-1}]$',
              r'$n_{\rm pred}$ [ph]',
              r'dN/dE [ph $cm^{-2} s^{-1} MeV^{-1}$]',
              r'E dN/dE [MeV $cm^{-2} s^{-1} MeV^{-1}$]']

def plotNLL_v_Flux(nll,nstep=25,xlims=None):
    """ Plot the (negative) log-likelihood as a function of normalization

    nll   : a LnLFN object
    nstep : Number of steps to plot
    xlims : x-axis limits, if None, take tem from the nll object

    returns fig,ax, which are matplotlib figure and axes objects
    """
    if xlims is None:
        xmin = nll.interp.xmin
        xmax = nll.interp.xmax
    else:
        xmin = xlims[0]
        xmax = xlims[1]
    y1 = nll.interp(xmin)
    y2 = nll.interp(xmax)

    ymin = min(y1,y2)
    ymax = max(y1,y2,0.5)

    xvals = np.linspace(xmin,xmax,nstep)
    yvals = nll.interp(xvals)

    fig = plt.figure()
    ax = fig.add_subplot(111)

    ax.set_xlim((xmin,xmax))
    ax.set_ylim((ymin,ymax))

    ax.set_xlabel(NORM_LABEL[nll.fluxType])
    ax.set_ylabel(r'$\Delta \log\mathcal{L}$')
    ax.plot(xvals,yvals)
    return fig,ax

def plotCastro(castroData,ylims,nstep=25,zlims=None):
    """ Make a color plot (castro plot) of the (negative) log-likelihood as a function of
    energy and flux normalization

    castroData : A CastroData object, with the log-likelihood v. normalization for each energy bin
    ylims      : y-axis limits
    nstep      : Number of y-axis steps to plot for each energy bin
    zlims      : z-axis limits

    returns fig,ax,im which are matplotlib figure, axes and image objects
    """
    xmin = castroData.specData.log_ebins[0]
    xmax = castroData.specData.log_ebins[-1]
    ymin = ylims[0]
    ymax = ylims[1]
    if zlims is None:
        zmin = -10.
        zmax = 0.
    else:
        zmin = zlims[0]
        zmax = zlims[1]

    fig = plt.figure()
    ax = fig.add_subplot(111)

    ax.set_yscale('log')
    ax.set_xlim((xmin,xmax))
    ax.set_ylim((ymin,ymax))

    ax.set_xlabel("log(Energy/GeV)")
    ax.set_ylabel(NORM_LABEL[castroData.fluxType])

    normVals = np.logspace(np.log10(ymin),np.log10(ymax),nstep)
    ztmp = []
    for i in range(castroData.specData.nE):
        ztmp.append(castroData[i].interp(normVals))
        pass
    ztmp = np.asarray(ztmp).T
    ztmp = np.where(ztmp<zmin,np.nan,ztmp)
    im = ax.imshow(ztmp, extent=[xmin,xmax,ymin,ymax],
                   origin='lower', aspect='auto',interpolation='nearest',
                   vmin=zmin, vmax=zmax,cmap=matplotlib.cm.jet_r)

    limits = castroData.getLimits(0.05)
    ebin_centers = (castroData.specData.ebins[0:-1]+castroData.specData.ebins[1:])/2.
    ax.errorbar(ebin_centers,limits)

    return fig,ax,im

def plotSED(castroData,ylims,TS_thresh=4.0,errSigma=1.0,specVals=[]):
    """ Make a color plot (castro plot) of the (negative) log-likelihood as a function of
    energy and flux normalization

    castroData : A CastroData object, with the log-likelihood v. normalization for each energy bin
    ylims      : y-axis limits
    TS_thresh  : TS value above with to plot a point, rather than an upper limit
    errSigma   : Number of sigma to use for error bars
    specVals   : List of spectra to add to plot
    returns fig,ax which are matplotlib figure and axes objects
    """
    xmin = castroData.specData.ebins[0]
    xmax = castroData.specData.ebins[-1]
    ymin = ylims[0]
    ymax = ylims[1]

    fig = plt.figure()
    ax = fig.add_subplot(111)

    ax.set_xscale('log')
    ax.set_yscale('log')
    ax.set_xlim((xmin,xmax))
    ax.set_ylim((ymin,ymax))

    ax.set_xlabel("Energy [GeV]")
    ax.set_ylabel(NORM_LABEL[castroData.fluxType])

    ts_vals = castroData.ts_vals()
    mles = castroData.mles()

    has_point = ts_vals > TS_thresh
    has_limit = ~has_point
    ul_vals = castroData.getLimits(0.05)

    err_pos = castroData.getLimits(0.32) - mles
    err_neg = mles - castroData.getLimits(0.32,upper=False)

    yerr_points = (err_neg[has_point],err_pos[has_point])
    xerrs = ( castroData.specData.evals - castroData.specData.ebins[0:-1],
              castroData.specData.ebins[1:] - castroData.specData.evals )

    yerr_limits = (0.5*ul_vals[has_limit],np.zeros((has_limit.sum())))

    ax.errorbar(castroData.specData.evals[has_point],mles[has_point],
                yerr=yerr_points,fmt='o')

    ax.errorbar(castroData.specData.evals[has_limit],ul_vals[has_limit],
                yerr=yerr_limits, lw=1, color='red', ls='none', zorder=1, uplims=True)

    ax.errorbar(castroData.specData.evals[has_limit], ul_vals[has_limit], xerr=(xerrs[0][has_limit],xerrs[1][has_limit]),
                lw=1.35, ls='none', color='red', zorder=2, capsize=0)

    for spec in specVals:
        ax.loglog(castro.specData.evals,spec)
        pass

    return fig,ax

if __name__ == "__main__":

    from fermipy import sed
    from fermipy import roi_model
    import sys

    if len(sys.argv) == 1:
        flux_type = 0
    elif sys.argv[1] == "norm":
        flux_type = 0
    elif sys.argv[1] == "flux":
        flux_type = 1
    elif sys.argv[1] == "eflux":
        flux_type = 2
    elif sys.argv[1] == "npred":
        flux_type = 3
    elif sys.argv[1] == "d_flux":
        flux_type = 4
    elif sys.argv[1] == "d_eflux":
        flux_type = 5
    else:
        print "Didn't reconginize flux type %s, choose from norm | flux | eflux | npred"%sys.argv[1]

    if flux_type == 0:
        xlims = (0.,1.)
        ylims = (1e-5,1e-1)
    elif flux_type == 1:
        xlims = (0.,1.)
        ylims = (1e-13,1e-9)
    elif flux_type == 2:
        xlims = (0.,1.)
        ylims = (1e-8,1e-4)
    elif flux_type == 3:
        xlims = (0.,1.)
        ylims = (1e-1,1e3)
    elif flux_type == 4:
        xlims = (0.,1.)
        ylims = (1e-18,1e-11)
    elif flux_type == 5:
        xlims = (0.,1.)
        ylims = (1e-13,1e-9)

    tscube = sed.TSCube.create_from_fits("tscube_test.fits",flux_type)
    peaks = tscube.find_and_refine_peaks(10.0,1.0,use_cumul=True)

    max_ts = tscube.tsmap.counts.max()
    (castro,test_dict) = tscube.test_spectra_of_peak(peaks[0])

    nll = castro[2]
    fig,ax = plotNLL_v_Flux(nll)

    fig2,ax2,im2 = plotCastro(castro,ylims=ylims,nstep=100)

    spec_pl = test_dict["PowerLaw"]["Spectrum"]
    spec_lp = test_dict["LogParabola"]["Spectrum"]
    spec_pc = test_dict["PLExpCutoff"]["Spectrum"]

    fig3,ax3 = plotSED(castro,ylims=ylims,TS_thresh=4.0,specVals=[spec_pl])

    result_pl = test_dict["PowerLaw"]["Result"]
    result_lp = test_dict["LogParabola"]["Result"]
    result_pc = test_dict["PLExpCutoff"]["Result"]
    ts_pl = test_dict["PowerLaw"]["TS"]
    ts_lp = test_dict["LogParabola"]["TS"]
    ts_pc = test_dict["PLExpCutoff"]["TS"]

    print "TS for PL index = 2:  %.1f"%max_ts
    print "Cumulative TS:        %.1f"%castro.ts_vals().sum()
    print "TS for PL index free: %.1f (Index = %.2f)"%(ts_pl,result_pl[1])
    print "TS for LogParabola:   %.1f (Index = %.2f, Beta = %.2f)"%(ts_lp,result_lp[1],result_lp[2])
    print "TS for PLExpCutoff:   %.1f (Index = %.2f, E_c = %.2f)"%(ts_pc,result_pc[1],result_pc[2])

<commit_msg>adjusted fermipy/sed_plotting.py to new sed format<commit_after>#!/usr/bin/env python
#

# Description
"""
Utilities for plotting SEDs and Castro plots

Many parts of this code are taken from dsphs/like/lnlfn.py by
  Matthew Wood <mdwood@slac.stanford.edu>
  Alex Drlica-Wagner <kadrlica@slac.stanford.edu>
"""

import numpy as np
import matplotlib.pyplot as plt
import matplotlib

NORM_LABEL = {'NORM':r'Flux Normalization [a.u.]',
              'FLUX':r'E dN/dE [ph $cm^{-2} s^{-1}$]',
              'EFLUX':r'$E^2$ dN/dE [MeV $cm^{-2} s^{-1}]$',
              'NPRED':r'$n_{\rm pred}$ [ph]',
              'DFDE':r'dN/dE [ph $cm^{-2} s^{-1} MeV^{-1}$]',
              'EDFDE':r'E dN/dE [MeV $cm^{-2} s^{-1} MeV^{-1}$]'}

def plotNLL_v_Flux(nll,fluxType,nstep=25,xlims=None):
    """ Plot the (negative) log-likelihood as a function of normalization

    nll   : a LnLFN object
    nstep : Number of steps to plot
    xlims : x-axis limits, if None, take tem from the nll object

    returns fig,ax, which are matplotlib figure and axes objects
    """
    if xlims is None:
        xmin = nll.interp.xmin
        xmax = nll.interp.xmax
    else:
        xmin = xlims[0]
        xmax = xlims[1]
    y1 = nll.interp(xmin)
    y2 = nll.interp(xmax)

    ymin = min(y1,y2,0.0)
    ymax = max(y1,y2,0.5)

    xvals = np.linspace(xmin,xmax,nstep)
    yvals = nll.interp(xvals)

    fig = plt.figure()
    ax = fig.add_subplot(111)

    ax.set_xlim((xmin,xmax))
    ax.set_ylim((ymin,ymax))

    ax.set_xlabel(NORM_LABEL[fluxType])
    ax.set_ylabel(r'$\Delta \log\mathcal{L}$')
    ax.plot(xvals,yvals)
    return fig,ax

def plotCastro(castroData,ylims,nstep=25,zlims=None):
    """ Make a color plot (castro plot) of the (negative) log-likelihood as a function of
    energy and flux normalization

    castroData : A CastroData object, with the log-likelihood v. normalization for each energy bin
    ylims      : y-axis limits
    nstep      : Number of y-axis steps to plot for each energy bin
    zlims      : z-axis limits

    returns fig,ax,im which are matplotlib figure, axes and image objects
    """
    xmin = castroData.specData.log_ebins[0]
    xmax = castroData.specData.log_ebins[-1]
    ymin = ylims[0]
    ymax = ylims[1]
    if zlims is None:
        zmin = 0
        zmax = 10.
    else:
        zmin = zlims[0]
        zmax = zlims[1]

    fig = plt.figure()
    ax = fig.add_subplot(111)

    ax.set_yscale('log')
    ax.set_xlim((xmin,xmax))
    ax.set_ylim((ymin,ymax))

    ax.set_xlabel("log(Energy/GeV)")
    ax.set_ylabel(NORM_LABEL[castroData.norm_type])

    normVals = np.logspace(np.log10(ymin),np.log10(ymax),nstep)
    ztmp = []
    for i in range(castroData.specData.nE):
        ztmp.append(castroData[i].interp(normVals))
        pass
    ztmp = np.asarray(ztmp).T
    ztmp = np.where(ztmp<zmin,np.nan,ztmp)
    im = ax.imshow(ztmp, extent=[xmin,xmax,ymin,ymax],
                   origin='lower', aspect='auto',interpolation='nearest',
                   vmin=zmin, vmax=zmax,cmap=matplotlib.cm.jet_r)

    limits = castroData.getLimits(0.05)
    ebin_centers = (castroData.specData.ebins[0:-1]+castroData.specData.ebins[1:])/2.
    ax.errorbar(ebin_centers,limits)

    return fig,ax,im,ztmp

def plotSED(castroData,ylims,TS_thresh=4.0,errSigma=1.0,specVals=[]):
    """ Make a color plot (castro plot) of the (negative) log-likelihood as a function of
    energy and flux normalization

    castroData : A CastroData object, with the log-likelihood v. normalization for each energy bin
    ylims      : y-axis limits
    TS_thresh  : TS value above with to plot a point, rather than an upper limit
    errSigma   : Number of sigma to use for error bars
    specVals   : List of spectra to add to plot
    returns fig,ax which are matplotlib figure and axes objects
    """
    xmin = castroData.specData.ebins[0]
    xmax = castroData.specData.ebins[-1]
    ymin = ylims[0]
    ymax = ylims[1]

    fig = plt.figure()
    ax = fig.add_subplot(111)

    ax.set_xscale('log')
    ax.set_yscale('log')
    ax.set_xlim((xmin,xmax))
    ax.set_ylim((ymin,ymax))

    ax.set_xlabel("Energy [GeV]")
    ax.set_ylabel(NORM_LABEL[castroData.norm_type])

    ts_vals = castroData.ts_vals()
    mles = castroData.mles()

    has_point = ts_vals > TS_thresh
    has_limit = ~has_point
    ul_vals = castroData.getLimits(0.05)

    err_pos = castroData.getLimits(0.32) - mles
    err_neg = mles - castroData.getLimits(0.32,upper=False)

    yerr_points = (err_neg[has_point],err_pos[has_point])
    xerrs = ( castroData.specData.evals - castroData.specData.ebins[0:-1],
              castroData.specData.ebins[1:] - castroData.specData.evals )

    yerr_limits = (0.5*ul_vals[has_limit],np.zeros((has_limit.sum())))

    ax.errorbar(castroData.specData.evals[has_point],mles[has_point],
                yerr=yerr_points,fmt='o')

    ax.errorbar(castroData.specData.evals[has_limit],ul_vals[has_limit],
                yerr=yerr_limits, lw=1, color='red', ls='none', zorder=1, uplims=True)

    ax.errorbar(castroData.specData.evals[has_limit], ul_vals[has_limit], xerr=(xerrs[0][has_limit],xerrs[1][has_limit]),
                lw=1.35, ls='none', color='red', zorder=2, capsize=0)

    for spec in specVals:
        ax.loglog(castro.specData.evals,spec)
        pass

    return fig,ax

if __name__ == "__main__":

    from fermipy import sed
    from fermipy import roi_model
    import sys

    if len(sys.argv) == 1:
        flux_type = "FLUX"
    else:
        flux_type = sys.argv[1]

    if flux_type == 'NORM':
        xlims = (0.,1.)
        flux_lims = (1e-5,1e-1)
    elif flux_type == "FLUX":
        xlims = (0.,1.)
        flux_lims = (1e-13,1e-9)
    elif flux_type == "EFLUX":
        xlims = (0.,1.)
        flux_lims = (1e-8,1e-4)
    elif flux_type == "NPRED":
        xlims = (0.,1.)
        flux_lims = (1e-1,1e3)
    elif flux_type == "DFDE":
        xlims = (0.,1.)
        flux_lims = (1e-18,1e-11)
    elif flux_type == "EDFDE":
        xlims = (0.,1.)
        flux_lims = (1e-13,1e-9)
    else:
        print ("Didn't reconginize flux type %s, choose from NORM | FLUX | EFLUX | NPRED | DFDE | EDFDE"%sys.argv[1])
        sys.exit()

    tscube = sed.TSCube.create_from_fits("tscube_test.fits",flux_type)
    resultDict = tscube.find_sources(10.0,1.0,use_cumul=False,
                                     output_peaks=True,
                                     output_specInfo=True,
                                     output_srcs=True)

    peaks = resultDict["Peaks"]

    max_ts = tscube.tsmap.counts.max()
    (castro,test_dict) = tscube.test_spectra_of_peak(peaks[0])

    nll = castro[2]
    fig,ax = plotNLL_v_Flux(nll,flux_type)

    fig2,ax2,im2,ztmp2 = plotCastro(castro,ylims=flux_lims,nstep=100)

    spec_pl = test_dict["PowerLaw"]["Spectrum"]
    spec_lp = test_dict["LogParabola"]["Spectrum"]
    spec_pc = test_dict["PLExpCutoff"]["Spectrum"]

    fig3,ax3 = plotSED(castro,ylims=flux_lims,TS_thresh=2.0,specVals=[spec_pl])

    result_pl = test_dict["PowerLaw"]["Result"]
    result_lp = test_dict["LogParabola"]["Result"]
    result_pc = test_dict["PLExpCutoff"]["Result"]
    ts_pl = test_dict["PowerLaw"]["TS"]
    ts_lp = test_dict["LogParabola"]["TS"]
    ts_pc = test_dict["PLExpCutoff"]["TS"]

    print "TS for PL index = 2:  %.1f"%max_ts
    print "Cumulative TS:        %.1f"%castro.ts_vals().sum()
    print "TS for PL index free: %.1f (Index = %.2f)"%(ts_pl,result_pl[1])
    print "TS for LogParabola:   %.1f (Index = %.2f, Beta = %.2f)"%(ts_lp,result_lp[1],result_lp[2])
    print "TS for PLExpCutoff:   %.1f (Index = %.2f, E_c = %.2f)"%(ts_pc,result_pc[1],result_pc[2])

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from __future__ import unicode_literals

import os
import re
import socket

from .tools import exec_cmd, hex2dotted, minimal_logger

Log = minimal_logger(__name__)

#: These will always be present for each device (even if they are None)
DEVICE_PROPERTY_DEFAULTS = {
    'inet': None,
    'inet4': 'LIST',
    'ether': None,
    'inet6': 'LIST',  # Because lists are mutable
    'netmask': None,
    'netmasks': 'LIST',
    'broadcast': None,
    'broadcasts': 'LIST',
    'prefixlens': 'LIST',
}

class Parser(object):
    """
    Main parser class interface
    """
    def __init__(self, ifconfig=None):
        self._interfaces = {}
        self.ifconfig_data = ifconfig
        self.parse(self.ifconfig_data)

    def add_device(self, device_name):
        if device_name in self._interfaces:
            raise RuntimeError("Device {} already added".format(device_name))
        self._interfaces[device_name] = {}
        for key, value in DEVICE_PROPERTY_DEFAULTS.items():
            if value == "LIST":
                self._interfaces[device_name][key] = []
            else:
                self._interfaces[device_name][key] = value

    def parse(self, ifconfig=None):  # noqa: max-complexity=12
        """
        Parse ifconfig output into self._interfaces.
        Optional Arguments:
            ifconfig
                The data (stdout) from the ifconfig command.  Default is to
                call exec_cmd(self.get_command()).
        """
        if not ifconfig:
            ifconfig, errors, return_code = exec_cmd(self.get_command())
            if return_code:
                Log.error(errors)
                raise ValueError("Non-zero return code, reporting error-code '{}'".format(errors))
        self.ifconfig_data = ifconfig
        cur = None
        patterns = self.get_patterns()
        for line in self.ifconfig_data.splitlines():
            for pattern in patterns:
                m = re.match(pattern, line)
                if not m:
                    continue
                groupdict = m.groupdict()
                # Special treatment to trigger which interface we're
                # setting for if 'device' is in the line.  Presumably the
                # device of the interface is within the first line of the
                # device block.
                if 'device' in groupdict:
                    cur = groupdict['device']
                    self.add_device(cur)
                elif cur is None:
                    raise RuntimeError(
                        "Got results that don't belong to a device"
                    )

                for k, v in groupdict.items():
                    if k in self._interfaces[cur]:
                        if self._interfaces[cur][k] is None:
                            self._interfaces[cur][k] = v
                        elif hasattr(self._interfaces[cur][k], 'append'):
                            self._interfaces[cur][k].append(v)
                        elif self._interfaces[cur][k] == v:
                            # Silently ignore if the it's the same value as last. Example: Multiple
                            # inet4 addresses, result in multiple netmasks. Cardinality mismatch
                            continue
                        else:
                            raise RuntimeError(
                                "Tried to add {}={} multiple times to {}, it was already: {}".format(
                                    k,
                                    v,
                                    cur,
                                    self._interfaces[cur][k]
                                )
                            )
                    else:
                        self._interfaces[cur][k] = v

        # Copy the first 'inet4' ip address to 'inet' for backwards compatibility
        for device, device_dict in self._interfaces.items():
            if len(device_dict['inet4']) > 0:
                device_dict['inet'] = device_dict['inet4'][0]

        # Copy the first 'netmasks' mask to 'netmask' for backwards compatibility
        for device, device_dict in self._interfaces.items():
            if len(device_dict['netmasks']) > 0:
                device_dict['netmask'] = device_dict['netmasks'][0]

        # Copy the first 'broadcast' ip address to 'broadcast' for backwards compatibility
        for device, device_dict in self._interfaces.items():
            if len(device_dict['broadcasts']) > 0:
                device_dict['broadcast'] = device_dict['broadcasts'][0]

        # fix it up
        self._interfaces = self.alter(self._interfaces)

    def alter(self, interfaces):
        """
        Used to provide the ability to alter the interfaces dictionary before
        it is returned from self.parse().
        Required Arguments:
            interfaces
                The interfaces dictionary.
        Returns: interfaces dict
        """
        # fixup some things
        for device, device_dict in interfaces.items():
            if len(device_dict['inet4']) > 0:
                device_dict['inet'] = device_dict['inet4'][0]
            if 'inet' in device_dict and not device_dict['inet'] is None:
                try:
                    host = socket.gethostbyaddr(device_dict['inet'])[0]
                    interfaces[device]['hostname'] = host
                except (socket.herror, socket.gaierror):
                    interfaces[device]['hostname'] = None

            # To be sure that hex values and similar are always consistent, we
            # return everything in lowercase. For instance, Windows writes
            # MACs in upper-case.
            for key, device_item in device_dict.items():
                if hasattr(device_item, 'lower'):
                    interfaces[device][key] = device_dict[key].lower()

        return interfaces

    @classmethod
    def get_command(cls):
        raise NotImplementedError()

    @classmethod
    def get_patterns(cls):
        raise NotImplementedError()

    @property
    def interfaces(self):
        raise NotImplementedError()

    @property
    def default_interface(self):
        raise NotImplementedError()

class NullParser(Parser):
    """
    Doesn't do anything, useful to maintain internal interfaces in case we
    don't want to do anything (because we haven't determined the OS)
    """

    def __init__(self, ifconfig=None):
        self._interfaces = {}
        self.ifconfig_data = ifconfig

    def parse(self, ifconfig=None):
        raise NotImplementedError()

    @property
    def interfaces(self):
        return []

    @property
    def default_interface(self):
        return None

class WindowsParser(Parser):

    @classmethod
    def get_command(cls):
        return 'ipconfig /all'

    @classmethod
    def get_patterns(cls):
        return [
            r"^(?P<device>\w.+):",
            r"^   Physical Address. . . . . . . . . : (?P<ether>[ABCDEFabcdef\d-]+)",
            r"^   IPv4 Address. . . . . . . . . . . : (?P<inet4>[^\s\(]+)",
            r"^   IPv6 Address. . . . . . . . . . . : (?P<inet6>[ABCDEFabcdef\d\:\%]+)",
            r"^\s+Default Gateway . . . . . . . . . : (?P<default_gateway>[^\s\(]+)",
        ]

    @property
    def interfaces(self):
        """
        Returns the full interfaces dictionary.
        """
        return self._interfaces

    def alter(self, interfaces):
        interfaces = Parser.alter(self, interfaces)
        # fixup some things
        for device, device_dict in interfaces.items():
            if 'ether' in device_dict and interfaces[device]['ether']:
                interfaces[device]['ether'] = device_dict['ether'].replace('-', ':')
        return interfaces

    @property
    def default_interface(self):
        """
        Returns the default interface device.
        """
        for _ifn, interface in self.interfaces.items():
            gateway = interface.get('default_gateway', '').strip()
            if gateway and gateway != '::' and not gateway.startswith('127'):
                return interface

class UnixParser(Parser):

    @classmethod
    def get_command(cls):
        ifconfig_cmd = 'ifconfig'
        for path in ['/sbin', '/usr/sbin', '/bin', '/usr/bin']:
            if os.path.exists(os.path.join(path, ifconfig_cmd)):
                ifconfig_cmd = os.path.join(path, ifconfig_cmd)
                break
        ifconfig_cmd = ifconfig_cmd + " -a"
        return ifconfig_cmd

    @classmethod
    def get_patterns(cls):
        return [
            r'(?P<device>^[-a-zA-Z0-9:\.]+): flags=(?P<flags>.*) mtu (?P<mtu>\d+)',
            r'.*inet\s+(?P<inet4>[\d\.]+)((\s+netmask\s)|\/)(?P<netmasks>[\w.]+)(\s+(brd|broadcast)\s(?P<broadcasts>[^\s]*))?.*',
            r'.*inet6\s+(?P<inet6>[\d\:abcdef]+)(%\w+)?((\s+prefixlen\s+)|\/)(?P<prefixlens>\d+)',
            r'.*ether (?P<ether>[^\s]*).*',
        ]

    @property
    def interfaces(self):
        """
        Returns the full interfaces dictionary.
        """
        return self._interfaces

    def _default_interface(self, route_output=None):
        """
        :param route_output: For mocking actual output
        """
        if not route_output:
            out, __, __ = exec_cmd('/sbin/route -n')
            lines = out.splitlines()
        else:
            lines = route_output.split("\n")

        for line in lines[2:]:
            line = line.split()
            if '0.0.0.0' in line and \
               'UG' in line:
                iface = line[-1]
                return self.interfaces.get(iface, None)

    @property
    def default_interface(self):
        """
        Returns the default interface device.
        """
        return self._default_interface()

class LinuxParser(UnixParser):
    """
    A parser for certain ifconfig versions.
    """

    @classmethod
    def get_patterns(cls):
        return super(LinuxParser, cls).get_patterns() + [
            r'(?P<device>^[a-zA-Z0-9:_\-\.]+)(.*)Link encap:(.*).*',
            r'(.*)Link encap:(.*)(HWaddr )(?P<ether>[^\s]*).*',
            r'.*(inet addr:\s*)(?P<inet4>[^\s]+)\s+Bcast:(?P<broadcast>[^\s]*)\s+Mask:(?P<netmask>[^\s]*).*',
            r'.*(inet6 addr:\s*)(?P<inet6>[^\s\/]+)\/(?P<prefixlen>\d+)',
            r'.*(MTU:\s*)(?P<mtu>\d+)',
            r'.*(P-t-P:)(?P<ptp>[^\s]*).*',
            r'.*(RX bytes:)(?P<rxbytes>\d+).*',
            r'.*(TX bytes:)(?P<txbytes>\d+).*',
        ]

    def alter(self, interfaces):
        return interfaces

class UnixIPParser(UnixParser):
    """
    Because ifconfig is getting deprecated, we can use ip address instead
    """

    @classmethod
    def get_command(cls):
        ifconfig_cmd = 'ip'
        for path in ['/sbin', '/usr/sbin', '/bin', '/usr/bin']:
            if os.path.exists(os.path.join(path, ifconfig_cmd)):
                ifconfig_cmd = os.path.join(path, ifconfig_cmd)
                break
        ifconfig_cmd = ifconfig_cmd + " address show"
        return ifconfig_cmd

    @classmethod
    def get_patterns(cls):
        return [
            r'\s*[0-9]+:\s+(?P<device>[^@:]+)[^:]*:(?P<flags>.*) mtu (?P<mtu>\d+)',
            r'.*(inet\s)(?P<inet4>[\d\.]+)',
            r'.*(inet6 )(?P<inet6>[^/]*).*',
            r'.*(ether )(?P<ether>[^\s]*).*',
            r'.*inet\s.*(brd )(?P<broadcast>[^\s]*).*',
            r'.*(inet )[^/]+(?P<netmask>[/][0-9]+).*',
        ]

    def _default_interface(self, route_output=None):
        """
        :param route_output: For mocking actual output
        """
        if not route_output:
            out, __, __ = exec_cmd('/sbin/ip route')
            lines = out.splitlines()
        else:
            lines = route_output.split("\n")

        for line in lines:
            line = line.split()
            if 'default' in line:
                iface = line[4]
                return self.interfaces.get(iface, None)

    @property
    def default_interface(self):
        """
        Returns the default interface device.
        """
        return self._default_interface()

    def alter(self, interfaces):
        return interfaces

class MacOSXParser(UnixParser):

    @classmethod
    def get_patterns(cls):
        return super(MacOSXParser, cls).get_patterns() + [
            r'.*(status: )(?P<status>[^\s]*).*',
            r'.*(media: )(?P<media>.*)',
        ]

    def alter(self, interfaces):
        interfaces = super(MacOSXParser, self).alter(interfaces)
        # fix up netmask address for mac
        for device, device_dict in interfaces.items():
            if device_dict['netmask'] is not None:
                interfaces[device]['netmask'] = hex2dotted(device_dict['netmask'])
            if device_dict['netmasks'] is not None:
                interfaces[device]['netmasks'] = [hex2dotted(mask) for mask in device_dict['netmasks']]
        return interfaces

    def _default_interface(self, route_output=None):
        """
        :param route_output: For mocking actual output
        """
        if not route_output:
            out, __, __ = exec_cmd('/usr/sbin/netstat -rn -f inet')
            lines = out.splitlines()
        else:
            lines = route_output.split("\n")

        for line in lines:
            line = line.split()
            if 'default' in line:
                iface = line[-1]
                return self.interfaces.get(iface, None)

    @property
    def default_interface(self):
        """
        Returns the default interface device.
        """
        return self._default_interface()
<commit_msg>Change not ... is ... -> ... is not .... to be more pythonic<commit_after># -*- coding: utf-8 -*-
from __future__ import unicode_literals

import os
import re
import socket

from .tools import exec_cmd, hex2dotted, minimal_logger

Log = minimal_logger(__name__)

#: These will always be present for each device (even if they are None)
DEVICE_PROPERTY_DEFAULTS = {
    'inet': None,
    'inet4': 'LIST',
    'ether': None,
    'inet6': 'LIST',  # Because lists are mutable
    'netmask': None,
    'netmasks': 'LIST',
    'broadcast': None,
    'broadcasts': 'LIST',
    'prefixlens': 'LIST',
}

class Parser(object):
    """
    Main parser class interface
    """
    def __init__(self, ifconfig=None):
        self._interfaces = {}
        self.ifconfig_data = ifconfig
        self.parse(self.ifconfig_data)

    def add_device(self, device_name):
        if device_name in self._interfaces:
            raise RuntimeError("Device {} already added".format(device_name))
        self._interfaces[device_name] = {}
        for key, value in DEVICE_PROPERTY_DEFAULTS.items():
            if value == "LIST":
                self._interfaces[device_name][key] = []
            else:
                self._interfaces[device_name][key] = value

    def parse(self, ifconfig=None):  # noqa: max-complexity=12
        """
        Parse ifconfig output into self._interfaces.
        Optional Arguments:
            ifconfig
                The data (stdout) from the ifconfig command.  Default is to
                call exec_cmd(self.get_command()).
        """
        if not ifconfig:
            ifconfig, errors, return_code = exec_cmd(self.get_command())
            if return_code:
                Log.error(errors)
                raise ValueError("Non-zero return code, reporting error-code '{}'".format(errors))
        self.ifconfig_data = ifconfig
        cur = None
        patterns = self.get_patterns()
        for line in self.ifconfig_data.splitlines():
            for pattern in patterns:
                m = re.match(pattern, line)
                if not m:
                    continue
                groupdict = m.groupdict()
                # Special treatment to trigger which interface we're
                # setting for if 'device' is in the line.  Presumably the
                # device of the interface is within the first line of the
                # device block.
                if 'device' in groupdict:
                    cur = groupdict['device']
                    self.add_device(cur)
                elif cur is None:
                    raise RuntimeError(
                        "Got results that don't belong to a device"
                    )

                for k, v in groupdict.items():
                    if k in self._interfaces[cur]:
                        if self._interfaces[cur][k] is None:
                            self._interfaces[cur][k] = v
                        elif hasattr(self._interfaces[cur][k], 'append'):
                            self._interfaces[cur][k].append(v)
                        elif self._interfaces[cur][k] == v:
                            # Silently ignore if the it's the same value as last. Example: Multiple
                            # inet4 addresses, result in multiple netmasks. Cardinality mismatch
                            continue
                        else:
                            raise RuntimeError(
                                "Tried to add {}={} multiple times to {}, it was already: {}".format(
                                    k,
                                    v,
                                    cur,
                                    self._interfaces[cur][k]
                                )
                            )
                    else:
                        self._interfaces[cur][k] = v

        # Copy the first 'inet4' ip address to 'inet' for backwards compatibility
        for device, device_dict in self._interfaces.items():
            if len(device_dict['inet4']) > 0:
                device_dict['inet'] = device_dict['inet4'][0]

        # Copy the first 'netmasks' mask to 'netmask' for backwards compatibility
        for device, device_dict in self._interfaces.items():
            if len(device_dict['netmasks']) > 0:
                device_dict['netmask'] = device_dict['netmasks'][0]

        # Copy the first 'broadcast' ip address to 'broadcast' for backwards compatibility
        for device, device_dict in self._interfaces.items():
            if len(device_dict['broadcasts']) > 0:
                device_dict['broadcast'] = device_dict['broadcasts'][0]

        # fix it up
        self._interfaces = self.alter(self._interfaces)

    def alter(self, interfaces):
        """
        Used to provide the ability to alter the interfaces dictionary before
        it is returned from self.parse().
        Required Arguments:
            interfaces
                The interfaces dictionary.
        Returns: interfaces dict
        """
        # fixup some things
        for device, device_dict in interfaces.items():
            if len(device_dict['inet4']) > 0:
                device_dict['inet'] = device_dict['inet4'][0]
            if 'inet' in device_dict and device_dict['inet'] is not None:
                try:
                    host = socket.gethostbyaddr(device_dict['inet'])[0]
                    interfaces[device]['hostname'] = host
                except (socket.herror, socket.gaierror):
                    interfaces[device]['hostname'] = None

            # To be sure that hex values and similar are always consistent, we
            # return everything in lowercase. For instance, Windows writes
            # MACs in upper-case.
            for key, device_item in device_dict.items():
                if hasattr(device_item, 'lower'):
                    interfaces[device][key] = device_dict[key].lower()

        return interfaces

    @classmethod
    def get_command(cls):
        raise NotImplementedError()

    @classmethod
    def get_patterns(cls):
        raise NotImplementedError()

    @property
    def interfaces(self):
        raise NotImplementedError()

    @property
    def default_interface(self):
        raise NotImplementedError()

class NullParser(Parser):
    """
    Doesn't do anything, useful to maintain internal interfaces in case we
    don't want to do anything (because we haven't determined the OS)
    """

    def __init__(self, ifconfig=None):
        self._interfaces = {}
        self.ifconfig_data = ifconfig

    def parse(self, ifconfig=None):
        raise NotImplementedError()

    @property
    def interfaces(self):
        return []

    @property
    def default_interface(self):
        return None

class WindowsParser(Parser):

    @classmethod
    def get_command(cls):
        return 'ipconfig /all'

    @classmethod
    def get_patterns(cls):
        return [
            r"^(?P<device>\w.+):",
            r"^   Physical Address. . . . . . . . . : (?P<ether>[ABCDEFabcdef\d-]+)",
            r"^   IPv4 Address. . . . . . . . . . . : (?P<inet4>[^\s\(]+)",
            r"^   IPv6 Address. . . . . . . . . . . : (?P<inet6>[ABCDEFabcdef\d\:\%]+)",
            r"^\s+Default Gateway . . . . . . . . . : (?P<default_gateway>[^\s\(]+)",
        ]

    @property
    def interfaces(self):
        """
        Returns the full interfaces dictionary.
        """
        return self._interfaces

    def alter(self, interfaces):
        interfaces = Parser.alter(self, interfaces)
        # fixup some things
        for device, device_dict in interfaces.items():
            if 'ether' in device_dict and interfaces[device]['ether']:
                interfaces[device]['ether'] = device_dict['ether'].replace('-', ':')
        return interfaces

    @property
    def default_interface(self):
        """
        Returns the default interface device.
        """
        for _ifn, interface in self.interfaces.items():
            gateway = interface.get('default_gateway', '').strip()
            if gateway and gateway != '::' and not gateway.startswith('127'):
                return interface

class UnixParser(Parser):

    @classmethod
    def get_command(cls):
        ifconfig_cmd = 'ifconfig'
        for path in ['/sbin', '/usr/sbin', '/bin', '/usr/bin']:
            if os.path.exists(os.path.join(path, ifconfig_cmd)):
                ifconfig_cmd = os.path.join(path, ifconfig_cmd)
                break
        ifconfig_cmd = ifconfig_cmd + " -a"
        return ifconfig_cmd

    @classmethod
    def get_patterns(cls):
        return [
            r'(?P<device>^[-a-zA-Z0-9:\.]+): flags=(?P<flags>.*) mtu (?P<mtu>\d+)',
            r'.*inet\s+(?P<inet4>[\d\.]+)((\s+netmask\s)|\/)(?P<netmasks>[\w.]+)(\s+(brd|broadcast)\s(?P<broadcasts>[^\s]*))?.*',
            r'.*inet6\s+(?P<inet6>[\d\:abcdef]+)(%\w+)?((\s+prefixlen\s+)|\/)(?P<prefixlens>\d+)',
            r'.*ether (?P<ether>[^\s]*).*',
        ]

    @property
    def interfaces(self):
        """
        Returns the full interfaces dictionary.
        """
        return self._interfaces

    def _default_interface(self, route_output=None):
        """
        :param route_output: For mocking actual output
        """
        if not route_output:
            out, __, __ = exec_cmd('/sbin/route -n')
            lines = out.splitlines()
        else:
            lines = route_output.split("\n")

        for line in lines[2:]:
            line = line.split()
            if '0.0.0.0' in line and \
               'UG' in line:
                iface = line[-1]
                return self.interfaces.get(iface, None)

    @property
    def default_interface(self):
        """
        Returns the default interface device.
        """
        return self._default_interface()

class LinuxParser(UnixParser):
    """
    A parser for certain ifconfig versions.
    """

    @classmethod
    def get_patterns(cls):
        return super(LinuxParser, cls).get_patterns() + [
            r'(?P<device>^[a-zA-Z0-9:_\-\.]+)(.*)Link encap:(.*).*',
            r'(.*)Link encap:(.*)(HWaddr )(?P<ether>[^\s]*).*',
            r'.*(inet addr:\s*)(?P<inet4>[^\s]+)\s+Bcast:(?P<broadcast>[^\s]*)\s+Mask:(?P<netmask>[^\s]*).*',
            r'.*(inet6 addr:\s*)(?P<inet6>[^\s\/]+)\/(?P<prefixlen>\d+)',
            r'.*(MTU:\s*)(?P<mtu>\d+)',
            r'.*(P-t-P:)(?P<ptp>[^\s]*).*',
            r'.*(RX bytes:)(?P<rxbytes>\d+).*',
            r'.*(TX bytes:)(?P<txbytes>\d+).*',
        ]

    def alter(self, interfaces):
        return interfaces

class UnixIPParser(UnixParser):
    """
    Because ifconfig is getting deprecated, we can use ip address instead
    """

    @classmethod
    def get_command(cls):
        ifconfig_cmd = 'ip'
        for path in ['/sbin', '/usr/sbin', '/bin', '/usr/bin']:
            if os.path.exists(os.path.join(path, ifconfig_cmd)):
                ifconfig_cmd = os.path.join(path, ifconfig_cmd)
                break
        ifconfig_cmd = ifconfig_cmd + " address show"
        return ifconfig_cmd

    @classmethod
    def get_patterns(cls):
        return [
            r'\s*[0-9]+:\s+(?P<device>[^@:]+)[^:]*:(?P<flags>.*) mtu (?P<mtu>\d+)',
            r'.*(inet\s)(?P<inet4>[\d\.]+)',
            r'.*(inet6 )(?P<inet6>[^/]*).*',
            r'.*(ether )(?P<ether>[^\s]*).*',
            r'.*inet\s.*(brd )(?P<broadcast>[^\s]*).*',
            r'.*(inet )[^/]+(?P<netmask>[/][0-9]+).*',
        ]

    def _default_interface(self, route_output=None):
        """
        :param route_output: For mocking actual output
        """
        if not route_output:
            out, __, __ = exec_cmd('/sbin/ip route')
            lines = out.splitlines()
        else:
            lines = route_output.split("\n")

        for line in lines:
            line = line.split()
            if 'default' in line:
                iface = line[4]
                return self.interfaces.get(iface, None)

    @property
    def default_interface(self):
        """
        Returns the default interface device.
        """
        return self._default_interface()

    def alter(self, interfaces):
        return interfaces

class MacOSXParser(UnixParser):

    @classmethod
    def get_patterns(cls):
        return super(MacOSXParser, cls).get_patterns() + [
            r'.*(status: )(?P<status>[^\s]*).*',
            r'.*(media: )(?P<media>.*)',
        ]

    def alter(self, interfaces):
        interfaces = super(MacOSXParser, self).alter(interfaces)
        # fix up netmask address for mac
        for device, device_dict in interfaces.items():
            if device_dict['netmask'] is not None:
                interfaces[device]['netmask'] = hex2dotted(device_dict['netmask'])
            if device_dict['netmasks'] is not None:
                interfaces[device]['netmasks'] = [hex2dotted(mask) for mask in device_dict['netmasks']]
        return interfaces

    def _default_interface(self, route_output=None):
        """
        :param route_output: For mocking actual output
        """
        if not route_output:
            out, __, __ = exec_cmd('/usr/sbin/netstat -rn -f inet')
            lines = out.splitlines()
        else:
            lines = route_output.split("\n")

        for line in lines:
            line = line.split()
            if 'default' in line:
                iface = line[-1]
                return self.interfaces.get(iface, None)

    @property
    def default_interface(self):
        """
        Returns the default interface device.
        """
        return self._default_interface()
<|endoftext|>


<commit_before># mode: run

def test_single_arg(a):
    """
    >>> test_single_arg(1)
    1
    >>> test_single_arg()                # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_single_arg(1,2)             # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_single_arg(**{})            # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_single_arg(*(), **{})       # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    """
    return a

def test_two_args(a,b):
    """
    >>> test_two_args(1,2)
    (1, 2)
    >>> test_two_args()              # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_two_args(1)             # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_two_args(1,2,3)         # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_two_args(**{})          # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_two_args(1, **{})       # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_two_args(*(), **{})     # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    """
    return a,b
<commit_msg>extended test case<commit_after># mode: run
# tags: kwargs, argument unpacking

# This test validates the error handling in the different specialised
# code paths of the argument unpacking code.  The have-kwargs and
# no-kwargs branches take different paths, so we always test with and
# without a keyword dict (even if it's empty).

def test_single_arg(a):
    """
    >>> test_single_arg(1)
    1
    >>> test_single_arg(1, **{})
    1
    >>> test_single_arg()                  # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_single_arg(1,2)               # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_single_arg(1,2, **{})         # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_single_arg(**{})              # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_single_arg(*(), **{})         # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_single_arg(**{'b':2})         # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_single_arg(**{'a':1, 'b':2})  # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    """
    return a

def test_two_args(a,b):
    """
    >>> test_two_args(1,2)
    (1, 2)
    >>> test_two_args(1,2, **{})
    (1, 2)
    >>> test_two_args(1,**{'b':2})
    (1, 2)
    >>> test_two_args(**{'a':1, 'b':2})
    (1, 2)
    >>> test_two_args()                 # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_two_args(1)                # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_two_args(1, **{})          # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_two_args(1,2,3)            # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_two_args(1,2,3, **{})      # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_two_args(**{})             # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_two_args(*(), **{})        # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_two_args(**{'a':1})        # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> test_two_args(**{'a':1, 'b':2, 'c':3})  # doctest: +ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    """
    return a,b
<|endoftext|>


<commit_before>import os
import subprocess
import json

from nose.tools import istest, assert_equal, assert_raises

from whack.sources import PackageSourceFetcher, PackageSourceNotFound, PackageSource
from whack.tempdir import create_temporary_dir
from whack.files import read_file, write_file, write_files, plain_file

@istest
def can_fetch_package_source_from_source_control():
    with create_temporary_dir() as package_source_dir:
        write_files(package_source_dir, [
            plain_file("whack/whack.json", json.dumps({})),
            plain_file("whack/name", "Bob"),
        ])
        _convert_to_git_repo(package_source_dir)

        source_fetcher = PackageSourceFetcher()
        repo_uri = "git+file://{0}".format(package_source_dir)
        with source_fetcher.fetch(repo_uri) as package_source:
            with create_temporary_dir() as target_dir:
                package_source.write_to(target_dir)
                assert_equal(
                    "Bob",
                    read_file(os.path.join(target_dir, "whack/name"))
                )

@istest
def can_fetch_package_source_from_local_path():
    with create_temporary_dir() as package_source_dir:
        write_files(package_source_dir, [
            plain_file("whack/whack.json", json.dumps({})),
            plain_file("whack/name", "Bob"),
        ])

        source_fetcher = PackageSourceFetcher()
        with source_fetcher.fetch(package_source_dir) as package_source:
            with create_temporary_dir() as target_dir:
                package_source.write_to(target_dir)
                assert_equal(
                    "Bob",
                    read_file(os.path.join(target_dir, "whack/name"))
                )

@istest
def error_is_raised_if_package_source_cannot_be_found():
    source_fetcher = PackageSourceFetcher()
    assert_raises(PackageSourceNotFound, lambda: source_fetcher.fetch("nginx"))

@istest
def name_is_stored_in_whack_json():
    with create_temporary_dir() as package_source_dir:
        write_files(package_source_dir, [
            plain_file("whack/whack.json", json.dumps({"name": "nginx"})),
        ])
        package_source = PackageSource(package_source_dir)
        assert_equal("nginx", package_source.name())

@istest
def name_of_package_source_is_non_if_not_specified_in_whack_json():
    with create_temporary_dir() as package_source_dir:
        write_files(package_source_dir, [
            plain_file("whack/whack.json", json.dumps({})),
        ])
        package_source = PackageSource(package_source_dir)
        assert_equal(None, package_source.name())

@istest
def name_of_package_source_is_non_if_whack_json_does_not_exist():
    with create_temporary_dir() as package_source_dir:
        package_source = PackageSource(package_source_dir)
        assert_equal(None, package_source.name())

def _convert_to_git_repo(cwd):
    def _git(command):
        subprocess.check_call(["git"] + command, cwd=cwd)
    _git(["init"])
    _git(["add", "."])
    _git(["commit", "-m", "Initial commit"])
<commit_msg>Remove duplication in tests<commit_after>import os
import subprocess
import json

from nose.tools import istest, assert_equal, assert_raises

from whack.sources import PackageSourceFetcher, PackageSourceNotFound, PackageSource
from whack.tempdir import create_temporary_dir
from whack.files import read_file, write_file, write_files, plain_file

@istest
def can_fetch_package_source_from_source_control():
    def put_package_source_into_source_control(package_source_dir):
        _convert_to_git_repo(package_source_dir)
        return "git+file://{0}".format(package_source_dir)

    _assert_package_source_can_be_written_to_target_dir(
        put_package_source_into_source_control
    )

@istest
def can_fetch_package_source_from_local_path():
    _assert_package_source_can_be_written_to_target_dir(
        lambda package_source_dir: package_source_dir
    )

def _assert_package_source_can_be_written_to_target_dir(source_filter):
    with create_temporary_dir() as package_source_dir:
        write_files(package_source_dir, [
            plain_file("whack/whack.json", json.dumps({})),
            plain_file("whack/name", "Bob"),
        ])

        package_source_name = source_filter(package_source_dir)

        source_fetcher = PackageSourceFetcher()
        with source_fetcher.fetch(package_source_name) as package_source:
            with create_temporary_dir() as target_dir:
                package_source.write_to(target_dir)
                assert_equal(
                    "Bob",
                    read_file(os.path.join(target_dir, "whack/name"))
                )

@istest
def error_is_raised_if_package_source_cannot_be_found():
    source_fetcher = PackageSourceFetcher()
    assert_raises(PackageSourceNotFound, lambda: source_fetcher.fetch("nginx"))

@istest
def name_is_stored_in_whack_json():
    with create_temporary_dir() as package_source_dir:
        write_files(package_source_dir, [
            plain_file("whack/whack.json", json.dumps({"name": "nginx"})),
        ])
        package_source = PackageSource(package_source_dir)
        assert_equal("nginx", package_source.name())

@istest
def name_of_package_source_is_non_if_not_specified_in_whack_json():
    with create_temporary_dir() as package_source_dir:
        write_files(package_source_dir, [
            plain_file("whack/whack.json", json.dumps({})),
        ])
        package_source = PackageSource(package_source_dir)
        assert_equal(None, package_source.name())

@istest
def name_of_package_source_is_non_if_whack_json_does_not_exist():
    with create_temporary_dir() as package_source_dir:
        package_source = PackageSource(package_source_dir)
        assert_equal(None, package_source.name())

def _convert_to_git_repo(cwd):
    def _git(command):
        subprocess.check_call(["git"] + command, cwd=cwd)
    _git(["init"])
    _git(["add", "."])
    _git(["commit", "-m", "Initial commit"])
<|endoftext|>


<commit_before>"""Mission evaluation."""

import itertools
import logging
from auvsi_suas.models.mission_judge_feedback import MissionJudgeFeedback
from auvsi_suas.models.odlc import Odlc
from auvsi_suas.models.odlc import OdlcEvaluator
from auvsi_suas.models.takeoff_or_landing_event import TakeoffOrLandingEvent
from auvsi_suas.models.uas_telemetry import UasTelemetry
from auvsi_suas.proto import interop_admin_api_pb2
from auvsi_suas.proto import interop_api_pb2
from django.contrib.auth.models import User

logger = logging.getLogger(__name__)

# The time between interop telemetry posts that's a prereq for other tasks.
INTEROP_TELEM_THRESHOLD_TIME_SEC = 1.0

# Weight of timeline points for mission time.
MISSION_TIME_WEIGHT = 0.8
# Weight of timeline points for not taking a timeout.
TIMEOUT_WEIGHT = 0.2
# Minimum amount of flight time without losing points.
FLIGHT_TIME_MIN_SEC = 20 * 60
# Maximum amount of flight time allowed.
FLIGHT_TIME_MAX_SEC = 30 * 60
# Maximum amount of post process time allowed.
PROCESS_TIME_MAX_SEC = 10 * 60
# Mission time points lost due for every second over max time.
MISSION_TIME_PENALTY_FROM_SEC = 0.03
# Weighting of flight time relative to post process time.
FLIGHT_TO_PROCESS_TIME_WEIGHT = 5.0

# Ratio of points lost per takeover.
AUTONOMOUS_FLIGHT_TAKEOVER = 0.10
# Ratio of points lost per out of bounds.
BOUND_PENALTY = 0.1
SAFETY_BOUND_PENALTY = 1.0
# Ratio of points lost for TFOA and crash.
TFOA_PENALTY = 0.25
CRASH_PENALTY = 0.35
# Weight of flight points to all autonomous flight.
AUTONOMOUS_FLIGHT_FLIGHT_WEIGHT = 0.4
# Weight of capture points to all autonomous flight.
WAYPOINT_CAPTURE_WEIGHT = 0.1
# Weight of accuracy points to all autonomous flight.
WAYPOINT_ACCURACY_WEIGHT = 0.5

# Weight of air drop points for accuracy.
AIR_DROP_ACCURACY_WEIGHT = 0.5
# Weight of air drop points for UGV driving to location.
AIR_DROP_DRIVE_WEIGHT = 0.5
# Air drop to point ratio.
AIR_DROP_DISTANCE_POINT_RATIO = {
    interop_admin_api_pb2.MissionJudgeFeedback.INSUFFICIENT_ACCURACY: 0,
    interop_admin_api_pb2.MissionJudgeFeedback.WITHIN_05_FT: 1,
    interop_admin_api_pb2.MissionJudgeFeedback.WITHIN_25_FT: 0.5,
    interop_admin_api_pb2.MissionJudgeFeedback.WITHIN_75_FT: 0.25,
}

# Scoring weights.
TIMELINE_WEIGHT = 0.1
AUTONOMOUS_WEIGHT = 0.2
OBSTACLE_WEIGHT = 0.2
OBJECT_WEIGHT = 0.2
AIR_DROP_WEIGHT = 0.2
OPERATIONAL_WEIGHT = 0.1

def generate_feedback(mission_config, user, team_eval):
    """Generates mission feedback for the given team and mission.

    Args:
        mission_config: The mission to evaluate the team against.
        user: The team user object for which to evaluate and provide feedback.
        team_eval: The team evaluation to fill.
    """
    feedback = team_eval.feedback

    # Find the user's flights.
    flight_periods = TakeoffOrLandingEvent.flights(mission_config, user)
    for period in flight_periods:
        if period.duration() is None:
            team_eval.warnings.append(
                'Infinite flight period, may be missing TakeoffOrLandingEvent.'
            )
            break
    uas_period_logs = [
        UasTelemetry.dedupe(logs)
        for logs in UasTelemetry.by_time_period(user, flight_periods)
    ]
    uas_logs = list(itertools.chain.from_iterable(uas_period_logs))
    if not uas_logs:
        team_eval.warnings.append('No UAS telemetry logs.')

    # Determine interop telemetry rates.
    telem_max, telem_avg = UasTelemetry.rates(
        user, flight_periods, time_period_logs=uas_period_logs)
    if telem_max:
        feedback.uas_telemetry_time_max_sec = telem_max
    if telem_avg:
        feedback.uas_telemetry_time_avg_sec = telem_avg

    # Determine if the uas hit the waypoints.
    feedback.waypoints.extend(
        UasTelemetry.satisfied_waypoints(
            mission_config.home_pos,
            mission_config.mission_waypoints.order_by('order'), uas_logs))

    # Evaluate the object detections.
    user_odlcs = Odlc.objects.filter(user=user).filter(
        mission=mission_config.pk).all()
    for odlc in user_odlcs:
        if odlc.thumbnail_approved is None:
            team_eval.warnings.append(
                'Odlc thumbnail review not set, may need to review ODLCs.')
            break
    evaluator = OdlcEvaluator(user_odlcs,
                              mission_config.odlcs.all(), flight_periods)
    feedback.odlc.CopyFrom(evaluator.evaluate())

    # Determine collisions with stationary.
    for obst in mission_config.stationary_obstacles.all():
        obst_eval = feedback.stationary_obstacles.add()
        obst_eval.id = obst.pk
        obst_eval.hit = obst.evaluate_collision_with_uas(uas_logs)

    # Add judge feedback.
    try:
        judge_feedback = MissionJudgeFeedback.objects.get(
            mission=mission_config.pk, user=user.pk)
        feedback.judge.CopyFrom(judge_feedback.proto())
        if feedback.judge.min_auto_flight_time and not flight_periods:
            team_eval.warnings.append(
                'Min flight time achieved by no flight periods, may be missing TakeoffOrLandingEvent.'
            )
    except MissionJudgeFeedback.DoesNotExist:
        team_eval.warnings.append('No MissionJudgeFeedback for team.')

def score_team(team_eval):
    """Generates a score from the given feedback.

    Args:
        team_eval: A auvsi_suas.proto.MissionEvaluation for the team.
    """
    feedback = team_eval.feedback
    score = team_eval.score

    # Can't score without judge feedback.
    if not feedback.HasField('judge'):
        team_eval.warnings.append('No judge feedback, skipping scoring.')
        return

    # Determine telemetry prerequisite.
    telem_prereq = False
    if (feedback.HasField('uas_telemetry_time_avg_sec') and
            feedback.uas_telemetry_time_avg_sec > 0):
        telem_prereq = feedback.uas_telemetry_time_avg_sec <= INTEROP_TELEM_THRESHOLD_TIME_SEC

    def points_for_time_sec(flight_sec, process_sec):
        return FLIGHT_TO_PROCESS_TIME_WEIGHT * max(
            0, flight_sec - FLIGHT_TIME_MIN_SEC) + process_sec

    # Score timeline.
    timeline = score.timeline
    time_points = points_for_time_sec(feedback.judge.flight_time_sec,
                                      feedback.judge.post_process_time_sec)
    max_time_points = points_for_time_sec(FLIGHT_TIME_MAX_SEC,
                                          PROCESS_TIME_MAX_SEC)
    timeline.mission_time = max(
        0, (max_time_points - time_points) / max_time_points)
    timeline.mission_penalty = MISSION_TIME_PENALTY_FROM_SEC * (
        max(0, feedback.judge.flight_time_sec - FLIGHT_TIME_MAX_SEC) + max(
            0, feedback.judge.post_process_time_sec - PROCESS_TIME_MAX_SEC))
    timeline.timeout = 0 if feedback.judge.used_timeout else 1
    timeline.score_ratio = (
        (MISSION_TIME_WEIGHT * timeline.mission_time) +
        (TIMEOUT_WEIGHT * timeline.timeout) - timeline.mission_penalty)

    # Score autonomous flight.
    flight = score.autonomous_flight
    flight.flight = 1 if feedback.judge.min_auto_flight_time else 0
    flight.telemetry_prerequisite = telem_prereq
    flight.waypoint_capture = (
        float(feedback.judge.waypoints_captured) / len(feedback.waypoints))
    wpt_scores = [w.score_ratio for w in feedback.waypoints]
    if telem_prereq:
        flight.waypoint_accuracy = sum(wpt_scores) / len(feedback.waypoints)
    else:
        flight.waypoint_accuracy = 0
    flight.safety_pilot_takeover_penalty = AUTONOMOUS_FLIGHT_TAKEOVER * feedback.judge.safety_pilot_takeovers
    flight.out_of_bounds_penalty = (
        feedback.judge.out_of_bounds * BOUND_PENALTY +
        feedback.judge.unsafe_out_of_bounds * SAFETY_BOUND_PENALTY)
    if feedback.judge.things_fell_off_uas:
        flight.things_fell_off_penalty = TFOA_PENALTY
    else:
        flight.things_fell_off_penalty = 0
    if feedback.judge.crashed:
        flight.crashed_penalty = CRASH_PENALTY
    else:
        flight.crashed_penalty = 0
    flight.score_ratio = (
        AUTONOMOUS_FLIGHT_FLIGHT_WEIGHT * flight.flight +
        WAYPOINT_CAPTURE_WEIGHT * flight.waypoint_capture +
        WAYPOINT_ACCURACY_WEIGHT * flight.waypoint_accuracy -
        flight.safety_pilot_takeover_penalty - flight.out_of_bounds_penalty -
        flight.things_fell_off_penalty - flight.crashed_penalty)

    # Score obstacle avoidance.
    avoid = score.obstacle_avoidance
    avoid.telemetry_prerequisite = telem_prereq
    if telem_prereq:
        avoid.score_ratio = pow(
            sum([0.0 if o.hit else 1.0 for o in feedback.stationary_obstacles])
            / len(feedback.stationary_obstacles), 3)
    else:
        avoid.score_ratio = 0

    # Score objects.
    objects = score.object
    object_eval = feedback.odlc
    object_field_mapping = [
        ('classifications_score_ratio', 'characteristics'),
        ('geolocation_score_ratio', 'geolocation'),
        ('actionable_score_ratio', 'actionable'),
        ('autonomous_score_ratio', 'autonomy'),
    ]
    for eval_field, score_field in object_field_mapping:
        if object_eval.odlcs:
            total = sum([getattr(o, eval_field) for o in object_eval.odlcs])
            setattr(objects, score_field,
                    float(total) / len(object_eval.odlcs))
        else:
            setattr(objects, score_field, 0)
    objects.extra_object_penalty = object_eval.extra_object_penalty_ratio
    objects.score_ratio = object_eval.score_ratio

    # Score air drop.
    air = score.air_drop
    air.drop_accuracy = AIR_DROP_DISTANCE_POINT_RATIO[
        feedback.judge.air_drop_accuracy]
    air.drive_to_location = 1 if feedback.judge.ugv_drove_to_location else 0
    air.score_ratio = (AIR_DROP_ACCURACY_WEIGHT * air.drop_accuracy +
                       AIR_DROP_DRIVE_WEIGHT * air.drive_to_location)

    # Score operational excellence.
    score.operational_excellence.score_ratio = (
        feedback.judge.operational_excellence_percent / 100.0)

    # Compute total score.
    if feedback.judge.min_auto_flight_time:
        score.score_ratio = max(
            0, TIMELINE_WEIGHT * score.timeline.score_ratio +
            AUTONOMOUS_WEIGHT * score.autonomous_flight.score_ratio +
            OBSTACLE_WEIGHT * score.obstacle_avoidance.score_ratio +
            OBJECT_WEIGHT * score.object.score_ratio +
            AIR_DROP_WEIGHT * score.air_drop.score_ratio +
            OPERATIONAL_WEIGHT * score.operational_excellence.score_ratio)
    else:
        team_eval.warnings.append(
            'Insufficient flight time to receive any mission points.')
        score.score_ratio = 0

def evaluate_teams(mission_config, users=None):
    """Evaluates the teams (non admin users) of the competition.

    Args:
        mission_config: The mission to evaluate users against.
        users: Optional list of users to eval. If None will evaluate all.
    Returns:
        A auvsi_suas.proto.MultiUserMissionEvaluation.
    """
    # Start a results map from user to MissionEvaluation.
    mission_eval = interop_admin_api_pb2.MultiUserMissionEvaluation()

    # If not provided, eval all users.
    if users is None:
        users = User.objects.all()

    logger.info('Starting team evaluations.')
    for user in sorted(users, key=lambda u: u.username):
        # Ignore admins.
        if user.is_superuser:
            continue

        # Ignore users with no judge feedback for mission.
        try:
            MissionJudgeFeedback.objects.get(
                mission=mission_config.pk, user=user.pk)
        except MissionJudgeFeedback.DoesNotExist:
            logger.info('Skipping user with no feedback: %s' % user.username)
            continue

        # Start the evaluation data structure.
        logger.info('Evaluation starting for user: %s.' % user.username)
        team_eval = mission_eval.teams.add()
        team_eval.team = user.username
        # Generate feedback.
        generate_feedback(mission_config, user, team_eval)
        # Generate score from feedback.
        score_team(team_eval)

    return mission_eval
<commit_msg>Remove no telemetry warning.<commit_after>"""Mission evaluation."""

import itertools
import logging
from auvsi_suas.models.mission_judge_feedback import MissionJudgeFeedback
from auvsi_suas.models.odlc import Odlc
from auvsi_suas.models.odlc import OdlcEvaluator
from auvsi_suas.models.takeoff_or_landing_event import TakeoffOrLandingEvent
from auvsi_suas.models.uas_telemetry import UasTelemetry
from auvsi_suas.proto import interop_admin_api_pb2
from auvsi_suas.proto import interop_api_pb2
from django.contrib.auth.models import User

logger = logging.getLogger(__name__)

# The time between interop telemetry posts that's a prereq for other tasks.
INTEROP_TELEM_THRESHOLD_TIME_SEC = 1.0

# Weight of timeline points for mission time.
MISSION_TIME_WEIGHT = 0.8
# Weight of timeline points for not taking a timeout.
TIMEOUT_WEIGHT = 0.2
# Minimum amount of flight time without losing points.
FLIGHT_TIME_MIN_SEC = 20 * 60
# Maximum amount of flight time allowed.
FLIGHT_TIME_MAX_SEC = 30 * 60
# Maximum amount of post process time allowed.
PROCESS_TIME_MAX_SEC = 10 * 60
# Mission time points lost due for every second over max time.
MISSION_TIME_PENALTY_FROM_SEC = 0.03
# Weighting of flight time relative to post process time.
FLIGHT_TO_PROCESS_TIME_WEIGHT = 5.0

# Ratio of points lost per takeover.
AUTONOMOUS_FLIGHT_TAKEOVER = 0.10
# Ratio of points lost per out of bounds.
BOUND_PENALTY = 0.1
SAFETY_BOUND_PENALTY = 1.0
# Ratio of points lost for TFOA and crash.
TFOA_PENALTY = 0.25
CRASH_PENALTY = 0.35
# Weight of flight points to all autonomous flight.
AUTONOMOUS_FLIGHT_FLIGHT_WEIGHT = 0.4
# Weight of capture points to all autonomous flight.
WAYPOINT_CAPTURE_WEIGHT = 0.1
# Weight of accuracy points to all autonomous flight.
WAYPOINT_ACCURACY_WEIGHT = 0.5

# Weight of air drop points for accuracy.
AIR_DROP_ACCURACY_WEIGHT = 0.5
# Weight of air drop points for UGV driving to location.
AIR_DROP_DRIVE_WEIGHT = 0.5
# Air drop to point ratio.
AIR_DROP_DISTANCE_POINT_RATIO = {
    interop_admin_api_pb2.MissionJudgeFeedback.INSUFFICIENT_ACCURACY: 0,
    interop_admin_api_pb2.MissionJudgeFeedback.WITHIN_05_FT: 1,
    interop_admin_api_pb2.MissionJudgeFeedback.WITHIN_25_FT: 0.5,
    interop_admin_api_pb2.MissionJudgeFeedback.WITHIN_75_FT: 0.25,
}

# Scoring weights.
TIMELINE_WEIGHT = 0.1
AUTONOMOUS_WEIGHT = 0.2
OBSTACLE_WEIGHT = 0.2
OBJECT_WEIGHT = 0.2
AIR_DROP_WEIGHT = 0.2
OPERATIONAL_WEIGHT = 0.1

def generate_feedback(mission_config, user, team_eval):
    """Generates mission feedback for the given team and mission.

    Args:
        mission_config: The mission to evaluate the team against.
        user: The team user object for which to evaluate and provide feedback.
        team_eval: The team evaluation to fill.
    """
    feedback = team_eval.feedback

    # Find the user's flights.
    flight_periods = TakeoffOrLandingEvent.flights(mission_config, user)
    for period in flight_periods:
        if period.duration() is None:
            team_eval.warnings.append(
                'Infinite flight period, may be missing TakeoffOrLandingEvent.'
            )
            break
    uas_period_logs = [
        UasTelemetry.dedupe(logs)
        for logs in UasTelemetry.by_time_period(user, flight_periods)
    ]
    uas_logs = list(itertools.chain.from_iterable(uas_period_logs))

    # Determine interop telemetry rates.
    telem_max, telem_avg = UasTelemetry.rates(
        user, flight_periods, time_period_logs=uas_period_logs)
    if telem_max:
        feedback.uas_telemetry_time_max_sec = telem_max
    if telem_avg:
        feedback.uas_telemetry_time_avg_sec = telem_avg

    # Determine if the uas hit the waypoints.
    feedback.waypoints.extend(
        UasTelemetry.satisfied_waypoints(
            mission_config.home_pos,
            mission_config.mission_waypoints.order_by('order'), uas_logs))

    # Evaluate the object detections.
    user_odlcs = Odlc.objects.filter(user=user).filter(
        mission=mission_config.pk).all()
    for odlc in user_odlcs:
        if odlc.thumbnail_approved is None:
            team_eval.warnings.append(
                'Odlc thumbnail review not set, may need to review ODLCs.')
            break
    evaluator = OdlcEvaluator(user_odlcs,
                              mission_config.odlcs.all(), flight_periods)
    feedback.odlc.CopyFrom(evaluator.evaluate())

    # Determine collisions with stationary.
    for obst in mission_config.stationary_obstacles.all():
        obst_eval = feedback.stationary_obstacles.add()
        obst_eval.id = obst.pk
        obst_eval.hit = obst.evaluate_collision_with_uas(uas_logs)

    # Add judge feedback.
    try:
        judge_feedback = MissionJudgeFeedback.objects.get(
            mission=mission_config.pk, user=user.pk)
        feedback.judge.CopyFrom(judge_feedback.proto())
        if feedback.judge.min_auto_flight_time and not flight_periods:
            team_eval.warnings.append(
                'Min flight time achieved by no flight periods, may be missing TakeoffOrLandingEvent.'
            )
    except MissionJudgeFeedback.DoesNotExist:
        team_eval.warnings.append('No MissionJudgeFeedback for team.')

def score_team(team_eval):
    """Generates a score from the given feedback.

    Args:
        team_eval: A auvsi_suas.proto.MissionEvaluation for the team.
    """
    feedback = team_eval.feedback
    score = team_eval.score

    # Can't score without judge feedback.
    if not feedback.HasField('judge'):
        team_eval.warnings.append('No judge feedback, skipping scoring.')
        return

    # Determine telemetry prerequisite.
    telem_prereq = False
    if (feedback.HasField('uas_telemetry_time_avg_sec') and
            feedback.uas_telemetry_time_avg_sec > 0):
        telem_prereq = feedback.uas_telemetry_time_avg_sec <= INTEROP_TELEM_THRESHOLD_TIME_SEC

    def points_for_time_sec(flight_sec, process_sec):
        return FLIGHT_TO_PROCESS_TIME_WEIGHT * max(
            0, flight_sec - FLIGHT_TIME_MIN_SEC) + process_sec

    # Score timeline.
    timeline = score.timeline
    time_points = points_for_time_sec(feedback.judge.flight_time_sec,
                                      feedback.judge.post_process_time_sec)
    max_time_points = points_for_time_sec(FLIGHT_TIME_MAX_SEC,
                                          PROCESS_TIME_MAX_SEC)
    timeline.mission_time = max(
        0, (max_time_points - time_points) / max_time_points)
    timeline.mission_penalty = MISSION_TIME_PENALTY_FROM_SEC * (
        max(0, feedback.judge.flight_time_sec - FLIGHT_TIME_MAX_SEC) + max(
            0, feedback.judge.post_process_time_sec - PROCESS_TIME_MAX_SEC))
    timeline.timeout = 0 if feedback.judge.used_timeout else 1
    timeline.score_ratio = (
        (MISSION_TIME_WEIGHT * timeline.mission_time) +
        (TIMEOUT_WEIGHT * timeline.timeout) - timeline.mission_penalty)

    # Score autonomous flight.
    flight = score.autonomous_flight
    flight.flight = 1 if feedback.judge.min_auto_flight_time else 0
    flight.telemetry_prerequisite = telem_prereq
    flight.waypoint_capture = (
        float(feedback.judge.waypoints_captured) / len(feedback.waypoints))
    wpt_scores = [w.score_ratio for w in feedback.waypoints]
    if telem_prereq:
        flight.waypoint_accuracy = sum(wpt_scores) / len(feedback.waypoints)
    else:
        flight.waypoint_accuracy = 0
    flight.safety_pilot_takeover_penalty = AUTONOMOUS_FLIGHT_TAKEOVER * feedback.judge.safety_pilot_takeovers
    flight.out_of_bounds_penalty = (
        feedback.judge.out_of_bounds * BOUND_PENALTY +
        feedback.judge.unsafe_out_of_bounds * SAFETY_BOUND_PENALTY)
    if feedback.judge.things_fell_off_uas:
        flight.things_fell_off_penalty = TFOA_PENALTY
    else:
        flight.things_fell_off_penalty = 0
    if feedback.judge.crashed:
        flight.crashed_penalty = CRASH_PENALTY
    else:
        flight.crashed_penalty = 0
    flight.score_ratio = (
        AUTONOMOUS_FLIGHT_FLIGHT_WEIGHT * flight.flight +
        WAYPOINT_CAPTURE_WEIGHT * flight.waypoint_capture +
        WAYPOINT_ACCURACY_WEIGHT * flight.waypoint_accuracy -
        flight.safety_pilot_takeover_penalty - flight.out_of_bounds_penalty -
        flight.things_fell_off_penalty - flight.crashed_penalty)

    # Score obstacle avoidance.
    avoid = score.obstacle_avoidance
    avoid.telemetry_prerequisite = telem_prereq
    if telem_prereq:
        avoid.score_ratio = pow(
            sum([0.0 if o.hit else 1.0 for o in feedback.stationary_obstacles])
            / len(feedback.stationary_obstacles), 3)
    else:
        avoid.score_ratio = 0

    # Score objects.
    objects = score.object
    object_eval = feedback.odlc
    object_field_mapping = [
        ('classifications_score_ratio', 'characteristics'),
        ('geolocation_score_ratio', 'geolocation'),
        ('actionable_score_ratio', 'actionable'),
        ('autonomous_score_ratio', 'autonomy'),
    ]
    for eval_field, score_field in object_field_mapping:
        if object_eval.odlcs:
            total = sum([getattr(o, eval_field) for o in object_eval.odlcs])
            setattr(objects, score_field,
                    float(total) / len(object_eval.odlcs))
        else:
            setattr(objects, score_field, 0)
    objects.extra_object_penalty = object_eval.extra_object_penalty_ratio
    objects.score_ratio = object_eval.score_ratio

    # Score air drop.
    air = score.air_drop
    air.drop_accuracy = AIR_DROP_DISTANCE_POINT_RATIO[
        feedback.judge.air_drop_accuracy]
    air.drive_to_location = 1 if feedback.judge.ugv_drove_to_location else 0
    air.score_ratio = (AIR_DROP_ACCURACY_WEIGHT * air.drop_accuracy +
                       AIR_DROP_DRIVE_WEIGHT * air.drive_to_location)

    # Score operational excellence.
    score.operational_excellence.score_ratio = (
        feedback.judge.operational_excellence_percent / 100.0)

    # Compute total score.
    if feedback.judge.min_auto_flight_time:
        score.score_ratio = max(
            0, TIMELINE_WEIGHT * score.timeline.score_ratio +
            AUTONOMOUS_WEIGHT * score.autonomous_flight.score_ratio +
            OBSTACLE_WEIGHT * score.obstacle_avoidance.score_ratio +
            OBJECT_WEIGHT * score.object.score_ratio +
            AIR_DROP_WEIGHT * score.air_drop.score_ratio +
            OPERATIONAL_WEIGHT * score.operational_excellence.score_ratio)
    else:
        team_eval.warnings.append(
            'Insufficient flight time to receive any mission points.')
        score.score_ratio = 0

def evaluate_teams(mission_config, users=None):
    """Evaluates the teams (non admin users) of the competition.

    Args:
        mission_config: The mission to evaluate users against.
        users: Optional list of users to eval. If None will evaluate all.
    Returns:
        A auvsi_suas.proto.MultiUserMissionEvaluation.
    """
    # Start a results map from user to MissionEvaluation.
    mission_eval = interop_admin_api_pb2.MultiUserMissionEvaluation()

    # If not provided, eval all users.
    if users is None:
        users = User.objects.all()

    logger.info('Starting team evaluations.')
    for user in sorted(users, key=lambda u: u.username):
        # Ignore admins.
        if user.is_superuser:
            continue

        # Ignore users with no judge feedback for mission.
        try:
            MissionJudgeFeedback.objects.get(
                mission=mission_config.pk, user=user.pk)
        except MissionJudgeFeedback.DoesNotExist:
            logger.info('Skipping user with no feedback: %s' % user.username)
            continue

        # Start the evaluation data structure.
        logger.info('Evaluation starting for user: %s.' % user.username)
        team_eval = mission_eval.teams.add()
        team_eval.team = user.username
        # Generate feedback.
        generate_feedback(mission_config, user, team_eval)
        # Generate score from feedback.
        score_team(team_eval)

    return mission_eval
<|endoftext|>