<commit_before># -*- coding: utf-8 -*-
from acq4.devices.PMT import *
from acq4.devices.DAQGeneric import *
from acq4.devices.HamamatsuPMT.HamamatsuPMTDevGui import HamamatsuPMTDevGui
from acq4.util.Mutex import Mutex
from acq4.util.Thread import Thread
import acq4.util.debug as debug
import numpy as np
import time

class HamamatsuPMT(PMT):
    """
    Control of the Hamamtsu PMT (H7422) through the M9012 temperature control and power supply unit. Cooling and high voltage settings can be controlled throug the I/O connecters on the card which in turn are linked to the DAQ input/output channels. The device interface allows to arm the PMT and control the gain voltage. Furthermore, resetting is possible in case cooling and overload errors occur.

    Configuration example:

    # Hamamatsu Photomultiplier device
    PMT:
        driver: 'HamamatsuPMT'
        parentDevice: 'FilterWheel'
        PMTgain : 0.85 # optimal gain in volts
        channels:
            Input:
                device: 'DAQ'
                channel: '/Dev2/ctr0' #'/Dev1/ai0'
                #mode: 'PseudoDiff'
                type: 'ci' #'ai'
            PeltierPower:
                device: 'DAQ'
                channel: '/Dev2/port1/line1'
                type: 'do' #'ai'
            PeltierError:
                device: 'DAQ'
                channel: '/Dev2/port1/line2'
                type: 'di' #'ai'
            PMTPower:
                device: 'DAQ'
                channel: '/Dev2/port1/line3'
                type: 'do' #'ai'
            PMTOverloadError:
                device: 'DAQ'
                channel: '/Dev2/port1/line4'
                type: 'di' #'ai'
            VcontExt:
                device: 'DAQ'
                channel: '/Dev2/ao3'
                type: 'ao' #'ai'
            VcontMon:
                device: 'DAQ'
                channel: '/Dev2/ai9'
                mode: 'rse'
                type: 'ai' #'ai'

    """

    sigPMTGainChanged = QtCore.Signal(object)
    sigCoolerErrorOccurred = QtCore.Signal(object)
    sigOverloadErrorOccurred = QtCore.Signal(object)
    sigPeltierStatus = QtCore.Signal(object)
    sigPMTPower = QtCore.Signal(object)

    def __init__(self, dm, config, name):
        self.currentSetGain = config.get('PMTgain',0.85)
        self.gainStepSize = 0.001
        self.gainStepWait = 0.01 # in sec
        self.HVpowerTimeOut = 5.
        self.PelPowerTimeOut = 1.
        self.fixingOverloadError = False
        self.fixingPelError = False

        PMT.__init__(self, dm, config, name)
        self.hamamatsuLock = Mutex(QtCore.QMutex.Recursive)  ## access to self.attributes

        if self.isHVOn():
            self.currentGain = self.getPMTGain()
        else:
            self.currentGain = 0.

        self.hThread = HamamatsuPMTThread(self)
        self.hThread.sigPMTGainChang.connect(self.gainChanged)
        self.hThread.sigCoolerError.connect(self.coolerError)
        self.hThread.sigOverloadError.connect(self.overloadError)
        self.hThread.sigPeltierStat.connect(self.peltierStatus)
        self.hThread.sigPMTPow.connect(self.PMTPower)
        self.hThread.start()

        dm.declareInterface(name, ['HamamatsuPMT'], self)
        dm.sigAbortAll.connect(self.deactivatePMT)

    def quit(self):
        self.deactivatePMT()

    def isHVOn(self):
        with self.hamamatsuLock:
            return self.getChanHolding('PMTPower')

    def switchHVOn(self):
        with self.hamamatsuLock:
            self.setChanHolding('PMTPower',1)

    def switchHVOff(self):
        with self.hamamatsuLock:
            self.setChanHolding('PMTPower',0)

    def isPeltierOn(self):
       with self.hamamatsuLock:
           return self.getChanHolding('PeltierPower')

    def switchPeltierOn(self):
        with self.hamamatsuLock:
            self.setChanHolding('PeltierPower',1)

    def switchPeltierOff(self):
        with self.hamamatsuLock:
            self.setChanHolding('PeltierPower',0)

    def setPMTGain(self,value):
        self.currentSetGain = value

    def changePMTGain(self,gainOn=False):
        if gainOn:
            with self.hamamatsuLock:
                self.setChanHolding('VcontExt',1)
        else:
            with self.hamamatsuLock:
                self.setChanHolding('VcontExt',0)

    def deactivatePMT(self):
        if self.isHVOn():
            self.deactivateHV()
        if self.isPeltierOn():
            self.deactivatePeltier()

    def activatePeltier(self):
        print 'Peltier:', self.isPeltierOn()
        print 'turn Peltier on'
        self.switchPeltierOn()
        print 'Peltier:', self.isPeltierOn()

    def deactivatePeltier(self):
        if self.isHVOn():
            self.deactivateHV()
        print 'Peltier:', self.isPeltierOn()
        print 'turn Peltier off'
        self.switchPeltierOff()
        print 'Peltier:', self.isPeltierOn()

    def activateHV(self):
        print 'High Voltage:', self.isHVOn()
        print 'turn High Voltage on'
        self.switchHVOn()
        self.changePMTGain(gainOn=True)
        print 'High voltage:',self.isHVOn()

    def deactivateHV(self):
        print 'turn High Voltage off'
        self.changePMTGain(gainOn=False)
        self.switchHVOff()
        print 'High voltage:',self.isHVOn()

    def getPMTGain(self):
        with self.hamamatsuLock:
            gain = self.getChannelValue('VcontMon')
            return gain

    def getCoolerStatus(self):
        with self.hamamatsuLock:
            coolerError = self.getChannelValue('PeltierError')
            return coolerError

    def getOverloadStatus(self):
        with self.hamamatsuLock:
            overloadError = self.getChannelValue('PMTOverloadError')
            return overloadError

    def gainChanged(self,gain):
        with self.hamamatsuLock:
            self.pmtGain = gain
            self.sigPMTGainChanged.emit(gain)

    def coolerError(self,coolerError):
        with self.hamamatsuLock:
            self.sigCoolerErrorOccurred.emit(coolerError)
            if (coolerError) and (not self.fixingPelError):
                self.fixingPelError = True
                self.deactivateHV()
                time.sleep(self.HVpowerTimeOut)
                self.deactivatePeltier()
                time.sleep(self.PelPowerTimeOut)
                self.activatePeltier()
                self.activateHV()
                self.fixingPelError = False

    def overloadError(self,overloadError):
        with self.hamamatsuLock:
            self.sigOverloadErrorOccurred.emit(overloadError)
            if (overloadError) and (not self.fixingOverloadError):
                self.fixingOverloadError = True
                self.deactivateHV()
                print 'high voltage time out ...',
                time.sleep(self.HVpowerTimeOut)
                print 'ended'
                self.activateHV()
                self.fixingOverloadError = False

    def peltierStatus(self,peltierStat):
        with self.hamamatsuLock:
            self.sigPeltierStatus.emit(peltierStat)

    def PMTPower(self,pmtP):
        with self.hamamatsuLock:
            self.sigPMTPower.emit(pmtP)

    def createTask(self, cmd, parentTask):
        return HamamatsuPMTTask(self, cmd, parentTask)

    def deviceInterface(self, win):
        return HamamatsuPMTDevGui(self)

class HamamatsuPMTTask(DAQGenericTask):
    pass

class HamamatsuPMTThread(Thread):

    sigPMTGainChang = QtCore.Signal(object)
    sigCoolerError = QtCore.Signal(object)
    sigOverloadError = QtCore.Signal(object)
    sigPeltierStat = QtCore.Signal(object)
    sigPMTPow = QtCore.Signal(object)

    def __init__(self, dev):
        Thread.__init__(self)
        self.lock = Mutex(QtCore.QMutex.Recursive)
        self.dev = dev
        self.cmds = {}
        self.overloaded = False

    def run(self):
        self.stopThread = False
        while True:
            try:
                gain = self.dev.getPMTGain()
                coolerError = self.dev.getCoolerStatus()
                overloadError = self.dev.getOverloadStatus()
                peltierStatus = self.dev.isPeltierOn()
                pmtPower = self.dev.isHVOn()

                self.sigPMTGainChang.emit(gain)
                self.sigCoolerError.emit(coolerError)
                self.sigOverloadError.emit(overloadError)
                self.sigPeltierStat.emit(peltierStatus)
                self.sigPMTPow.emit(pmtPower)
                time.sleep(0.5)
            except:
                debug.printExc("Error in Hamamatsu PMT communication thread:")

            self.lock.lock()
            if self.stopThread:
                self.lock.unlock()
                break
            self.lock.unlock()
            time.sleep(0.02)

    def stop(self, block=False):
        with self.lock:
            self.stopThread = True
        if block:
            if not self.wait(10000):
                raise Exception("Timed out while waiting for thread exit!")
<commit_msg>removed all the printouts<commit_after># -*- coding: utf-8 -*-
from acq4.devices.PMT import *
from acq4.devices.DAQGeneric import *
from acq4.devices.HamamatsuPMT.HamamatsuPMTDevGui import HamamatsuPMTDevGui
from acq4.util.Mutex import Mutex
from acq4.util.Thread import Thread
import acq4.util.debug as debug
import numpy as np
import time

class HamamatsuPMT(PMT):
    """
    Control of the Hamamtsu PMT (H7422) through the M9012 temperature control and power supply unit. Cooling and high voltage settings can be controlled throug the I/O connecters on the card which in turn are linked to the DAQ input/output channels. The device interface allows to arm the PMT and control the gain voltage. Furthermore, resetting is possible in case cooling and overload errors occur.

    Configuration example:

    # Hamamatsu Photomultiplier device
    PMT:
        driver: 'HamamatsuPMT'
        parentDevice: 'FilterWheel'
        PMTgain : 0.85 # optimal gain in volts
        channels:
            Input:
                device: 'DAQ'
                channel: '/Dev2/ctr0' #'/Dev1/ai0'
                #mode: 'PseudoDiff'
                type: 'ci' #'ai'
            PeltierPower:
                device: 'DAQ'
                channel: '/Dev2/port1/line1'
                type: 'do' #'ai'
            PeltierError:
                device: 'DAQ'
                channel: '/Dev2/port1/line2'
                type: 'di' #'ai'
            PMTPower:
                device: 'DAQ'
                channel: '/Dev2/port1/line3'
                type: 'do' #'ai'
            PMTOverloadError:
                device: 'DAQ'
                channel: '/Dev2/port1/line4'
                type: 'di' #'ai'
            VcontExt:
                device: 'DAQ'
                channel: '/Dev2/ao3'
                type: 'ao' #'ai'
            VcontMon:
                device: 'DAQ'
                channel: '/Dev2/ai9'
                mode: 'rse'
                type: 'ai' #'ai'

    """

    sigPMTGainChanged = QtCore.Signal(object)
    sigCoolerErrorOccurred = QtCore.Signal(object)
    sigOverloadErrorOccurred = QtCore.Signal(object)
    sigPeltierStatus = QtCore.Signal(object)
    sigPMTPower = QtCore.Signal(object)

    def __init__(self, dm, config, name):
        self.currentSetGain = config.get('PMTgain',0.85)
        self.HVpowerTimeOut = 6.
        self.PelPowerTimeOut = 1.
        self.fixingOverloadError = False
        self.fixingPelError = False

        PMT.__init__(self, dm, config, name)
        self.hamamatsuLock = Mutex(QtCore.QMutex.Recursive)  ## access to self.attributes

        if self.isHVOn():
            self.currentGain = self.getPMTGain()
        else:
            self.currentGain = 0.

        self.hThread = HamamatsuPMTThread(self)
        self.hThread.sigPMTGainChang.connect(self.gainChanged)
        self.hThread.sigCoolerError.connect(self.coolerError)
        self.hThread.sigOverloadError.connect(self.overloadError)
        self.hThread.sigPeltierStat.connect(self.peltierStatus)
        self.hThread.sigPMTPow.connect(self.PMTPower)
        self.hThread.start()

        dm.declareInterface(name, ['HamamatsuPMT'], self)
        dm.sigAbortAll.connect(self.deactivatePMT)

    def quit(self):
        self.deactivatePMT()

    def isHVOn(self):
        with self.hamamatsuLock:
            return self.getChanHolding('PMTPower')

    def switchHVOn(self):
        with self.hamamatsuLock:
            self.setChanHolding('PMTPower',1)

    def switchHVOff(self):
        with self.hamamatsuLock:
            self.setChanHolding('PMTPower',0)

    def isPeltierOn(self):
       with self.hamamatsuLock:
           return self.getChanHolding('PeltierPower')

    def switchPeltierOn(self):
        with self.hamamatsuLock:
            self.setChanHolding('PeltierPower',1)

    def switchPeltierOff(self):
        with self.hamamatsuLock:
            self.setChanHolding('PeltierPower',0)

    def setPMTGain(self,value):
        self.currentSetGain = value

    def changePMTGain(self,gainOn=False):
        if gainOn:
            with self.hamamatsuLock:
                self.setChanHolding('VcontExt',1)
        else:
            with self.hamamatsuLock:
                self.setChanHolding('VcontExt',0)

    def deactivatePMT(self):
        if self.isHVOn():
            self.deactivateHV()
        if self.isPeltierOn():
            self.deactivatePeltier()

    def activatePeltier(self):
        self.switchPeltierOn()

    def deactivatePeltier(self):
        if self.isHVOn():
            self.deactivateHV()
        self.switchPeltierOff()

    def activateHV(self):
        self.switchHVOn()
        self.changePMTGain(gainOn=True)

    def deactivateHV(self):
        self.changePMTGain(gainOn=False)
        self.switchHVOff()

    def getPMTGain(self):
        with self.hamamatsuLock:
            gain = self.getChannelValue('VcontMon')
            return gain

    def getCoolerStatus(self):
        with self.hamamatsuLock:
            coolerError = self.getChannelValue('PeltierError')
            return coolerError

    def getOverloadStatus(self):
        with self.hamamatsuLock:
            overloadError = self.getChannelValue('PMTOverloadError')
            return overloadError

    def gainChanged(self,gain):
        with self.hamamatsuLock:
            self.pmtGain = gain
            self.sigPMTGainChanged.emit(gain)

    def coolerError(self,coolerError):
        with self.hamamatsuLock:
            self.sigCoolerErrorOccurred.emit(coolerError)
            if (coolerError) and (not self.fixingPelError):
                self.fixingPelError = True
                self.deactivateHV()
                time.sleep(self.HVpowerTimeOut)
                self.deactivatePeltier()
                time.sleep(self.PelPowerTimeOut)
                self.activatePeltier()
                self.activateHV()
                self.fixingPelError = False

    def overloadError(self,overloadError):
        with self.hamamatsuLock:
            self.sigOverloadErrorOccurred.emit(overloadError)
            if (overloadError) and (not self.fixingOverloadError):
                self.fixingOverloadError = True
                self.deactivateHV()
                time.sleep(self.HVpowerTimeOut)
                self.activateHV()
                self.fixingOverloadError = False

    def peltierStatus(self,peltierStat):
        with self.hamamatsuLock:
            self.sigPeltierStatus.emit(peltierStat)

    def PMTPower(self,pmtP):
        with self.hamamatsuLock:
            self.sigPMTPower.emit(pmtP)

    def createTask(self, cmd, parentTask):
        return HamamatsuPMTTask(self, cmd, parentTask)

    def deviceInterface(self, win):
        return HamamatsuPMTDevGui(self)

class HamamatsuPMTTask(DAQGenericTask):
    pass

class HamamatsuPMTThread(Thread):

    sigPMTGainChang = QtCore.Signal(object)
    sigCoolerError = QtCore.Signal(object)
    sigOverloadError = QtCore.Signal(object)
    sigPeltierStat = QtCore.Signal(object)
    sigPMTPow = QtCore.Signal(object)

    def __init__(self, dev):
        Thread.__init__(self)
        self.lock = Mutex(QtCore.QMutex.Recursive)
        self.dev = dev
        self.cmds = {}
        self.overloaded = False

    def run(self):
        self.stopThread = False
        while True:
            try:
                gain = self.dev.getPMTGain()
                coolerError = self.dev.getCoolerStatus()
                overloadError = self.dev.getOverloadStatus()
                peltierStatus = self.dev.isPeltierOn()
                pmtPower = self.dev.isHVOn()

                self.sigPMTGainChang.emit(gain)
                self.sigCoolerError.emit(coolerError)
                self.sigOverloadError.emit(overloadError)
                self.sigPeltierStat.emit(peltierStatus)
                self.sigPMTPow.emit(pmtPower)
                time.sleep(0.5)
            except:
                debug.printExc("Error in Hamamatsu PMT communication thread:")

            self.lock.lock()
            if self.stopThread:
                self.lock.unlock()
                break
            self.lock.unlock()
            time.sleep(0.02)

    def stop(self, block=False):
        with self.lock:
            self.stopThread = True
        if block:
            if not self.wait(10000):
                raise Exception("Timed out while waiting for thread exit!")
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import io
import os
import urlparse
import zipfile
import requests
import ckanapi

dadosgovbr = ckanapi.RemoteCKAN('http://dados.gov.br', user_agent='fatias/1.0 (+http://github.com/augusto-herrmann/fatias)')
dataset_filiados = dadosgovbr.action.package_show(id='filiados-partidos-politicos')
urls = [resource['url'] for resource in dataset_filiados['resources']]

if not os.path.exists('dados'):
    print u'Criando diretório "dados"...'
    os.mkdir('dados')

for url in urls:
    filename = os.path.basename(urlparse.urlparse(url).path)
    if os.path.exists('dados/%s.csv' % filename.split('.')[0]):
        print u'Pulando arquivo existente: %s' % filename
        continue
    print u'Baixando a url %s' % url
    response = requests.get(url, stream=True)
    if response.ok:
        z = zipfile.ZipFile(io.BytesIO(response.content))
        # queremos apenas o arquivo csv, e nao queremos o sub judice
        path_planilha = [name for name in z.namelist() if os.path.splitext(name)[-1] == '.csv' and not 'sub_jud' in name][0]
        nome_planilha = os.path.basename(path_planilha)
        with z.open(path_planilha) as p, open('dados/%s' % nome_planilha, 'w') as f:
            print u'Gravando arquivo %s' % nome_planilha
            f.write(p.read())
    else:
        print 'ERRO: Código %d ao acessar a url.' % response.status_code

<commit_msg>trata o caso em que o arquivo zip não contém planilhas<commit_after># -*- coding: utf-8 -*-
import io
import os
import urlparse
import zipfile
import requests
import ckanapi

dadosgovbr = ckanapi.RemoteCKAN('http://dados.gov.br', user_agent='fatias/1.0 (+http://github.com/augusto-herrmann/fatias)')
dataset_filiados = dadosgovbr.action.package_show(id='filiados-partidos-politicos')
urls = [resource['url'] for resource in dataset_filiados['resources']]

if not os.path.exists('dados'):
    print u'Criando diretório "dados"...'
    os.mkdir('dados')

for url in urls:
    filename = os.path.basename(urlparse.urlparse(url).path)
    if os.path.exists('dados/%s.csv' % filename.split('.')[0]):
        print u'Pulando arquivo existente: %s' % filename
        continue
    print u'Baixando a url %s' % url
    response = requests.get(url, stream=True)
    if response.ok:
        z = zipfile.ZipFile(io.BytesIO(response.content))
        # queremos apenas o arquivo csv, e nao queremos o sub judice
        planilhas = [name for name in z.namelist() if os.path.splitext(name)[-1] == '.csv' and not 'sub_jud' in name]
        if not planilhas:
            print u'Aviso: O arquivo %s não contém planilhas.' % filename
            # pula para a proxima url
            continue
        path_planilha = planilhas[0] # le a primeira planilha
        nome_planilha = os.path.basename(path_planilha)
        with z.open(path_planilha) as p, open('dados/%s' % nome_planilha, 'w') as f:
            print u'Gravando arquivo %s' % nome_planilha
            f.write(p.read())
    else:
        print 'ERRO: Código %d ao acessar a url.' % response.status_code

<|endoftext|>


<commit_before>from django.contrib import admin
from django import forms
from django.conf.urls import url
from django.shortcuts import render
from django.db.models.fields import BLANK_CHOICE_DASH

from django.core.urlresolvers import reverse

from tabbed_admin import TabbedModelAdmin

from .models import Driver, Team, Competition, Circuit, Season, GrandPrix, Race, Result
from .models import Contender, Seat, TeamSeason
from .models import ContenderSeason
from . import punctuation

lr_diff = lambda l, r: list(set(l).difference(r))
lr_intr = lambda l, r: list(set(l).intersection(r))

class RelatedCompetitionAdmin(object):
    """ Aux class to share print_competitions method between driver and team """
    def print_competitions(self, obj):
        if hasattr(obj, 'competitions'):
            return ', '.join("%s" % competition for competition in obj.competitions.all())
        else:
            return None
    print_competitions.short_description = 'competitions'

class CompetitionFilterInline(admin.TabularInline):
    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
        if request._obj_ is not None:
            if db_field.name == 'team':
                kwargs['queryset'] = Team.objects.filter(competitions__exact=request._obj_.competition)
            elif db_field.name == 'grand_prix':
                kwargs['queryset'] = GrandPrix.objects.filter(competitions__exact=request._obj_.competition)
            elif db_field.name == 'seat':
                kwargs['queryset'] = Seat.objects.filter(contender__competition__exact=request._obj_.competition)
        return super(CompetitionFilterInline, self).formfield_for_foreignkey(db_field, request, **kwargs)

class CommonRaceAdmin(object):
    def print_results_link(self, obj):
        if obj.pk:
            results_url = reverse("admin:driver27_race_results", args=[obj.pk])
            return '%s' % (results_url, 'Results')
        else:
            return None
    print_results_link.allow_tags = True
    print_results_link.short_description = 'link'

class RaceInline(CommonRaceAdmin, CompetitionFilterInline):
    model = Race
    extra = 1
    readonly_fields = ('print_results_link', )

class SeatInline(CompetitionFilterInline):
    model = Seat
    extra = 3

class SeatSeasonInline(CompetitionFilterInline):
    model = Seat.seasons.through
    extra = 3
    ordering = ('seat',)

class ContenderInline(admin.TabularInline):
    model = Contender
    extra = 1

class TeamSeasonInline(CompetitionFilterInline):
    model = TeamSeason
    extra = 1

class TeamInline(admin.TabularInline):
    model = Team
    extra = 1

class DriverAdmin(RelatedCompetitionAdmin, TabbedModelAdmin):
    list_display = ('__unicode__', 'country', 'print_competitions')
    list_filter = ('competitions__name',)
    tab_overview = (
        (None, {
        'fields': ('last_name', 'first_name', 'year_of_birth', 'country')
        }),
    )
    tab_competitions = (
        ContenderInline,
    )
    tabs = [
        ('Overview', tab_overview),
        ('Competitions', tab_competitions)
    ]

class TeamAdmin(RelatedCompetitionAdmin, admin.ModelAdmin):
    list_display = ('__unicode__', 'country', 'print_competitions')

class CompetitionAdmin(TabbedModelAdmin):
    model = Competition
    list_display = ('name', 'full_name')
    tab_overview = (
        (None, {
        'fields': ('name', 'full_name', 'country', 'slug')
        }),
    )
    tab_drivers = (
        ContenderInline,
    )
    tabs = [
        ('Overview', tab_overview),
        ('Drivers', tab_drivers)
    ]

class CircuitAdmin(admin.ModelAdmin):
    list_display = ('name', 'city', 'country', 'opened_in')

class GrandPrixAdmin(RelatedCompetitionAdmin, admin.ModelAdmin):
    list_display = ('name', 'country', 'default_circuit', 'print_competitions')

class SeasonAdminForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(SeasonAdminForm, self).__init__(*args, **kwargs)
        punctuation_dict = punctuation.DRIVER27_PUNCTUATION
        punctuation_choices = [(punct['code'], punct['label']) for punct in punctuation_dict]
        self.fields['punctuation'] = forms.ChoiceField(choices=BLANK_CHOICE_DASH + list(punctuation_choices), initial=None)

    class Meta:
        model = Season
        fields = ('year', 'competition', 'rounds', 'punctuation')

class SeasonAdmin(TabbedModelAdmin):
    form = SeasonAdminForm
    tab_overview = (
        (None, {
        'fields': ('year', 'competition', 'rounds', 'punctuation')
        }),
    )
    tab_teams = (
        TeamSeasonInline,
    )
    tab_drivers = (
        # (None, {
        #     'fields': ('team_contenders',)
        # }),
        SeatSeasonInline,
    )
    tab_races = (
        RaceInline,
    )
    tabs = [
        ('Overview', tab_overview),
        ('Teams', tab_teams),
        ('Drivers', tab_drivers),
        ('Races', tab_races),
    ]

    def get_form(self, request, obj=None, **kwargs):
        # just save obj reference for future processing in Inline
        if request and obj:
            request._obj_ = obj
        return super(SeasonAdmin, self).get_form(request, obj, **kwargs)

class RaceAdmin(CommonRaceAdmin, admin.ModelAdmin):
    list_display = ('__unicode__', 'season', 'print_pole', 'print_winner', 'print_fastest')
    list_filter = ('season',)
    readonly_fields = ('print_results_link',)

    def print_pole(self, obj):
        pole = obj.pole
        return "%s" % obj.pole.contender.driver if pole else None
    print_pole.short_description = 'Pole'

    def print_winner(self, obj):
        winner = obj.winner
        return "%s" % winner.contender.driver if winner else None
    print_winner.short_description = 'Winner'

    def print_fastest(self, obj):
        fastest = obj.fastest
        return "%s" % fastest.contender.driver if fastest else None
    print_fastest.short_description = 'Fastest'

    def get_urls(self):
        urls = super(RaceAdmin, self).get_urls()
        urlpatterns = [
            url(r'(?P<race_id>\d+)/results/$', self.admin_site.admin_view(self.results), name='driver27_race_results')
        ]

        return urlpatterns + urls

    def add_result_entries(self, request, entries, race):
        for entry in entries:
            field_prefix = '%s-%s-' % ('seat-', str(entry))
            qualifying = request.POST.get(field_prefix + 'qualifying', None)
            finish = request.POST.get(field_prefix + 'finish', None)
            fastest_lap = request.POST.get(field_prefix + 'fastest-lap', None)
            retired = request.POST.get(field_prefix + 'retired', None)
            wildcard = request.POST.get(field_prefix + 'wildcard', None)
            Result.objects.create(
                race=race,
                seat_id=entry,
                qualifying=qualifying if qualifying else None,
                finish=finish if finish else None,
                fastest_lap=fastest_lap if fastest_lap else False,
                retired = retired if retired else False,
                wildcard = wildcard if wildcard else False
            )

    def update_result_entries(self, request, entries, race):
        for entry in entries:
            field_prefix = '%s-%s-' % ('seat', entry)
            # raise Exception('field_prefix')
            qualifying = request.POST.get(field_prefix + 'qualifying', None)
            finish = request.POST.get(field_prefix + 'finish', None)
            fastest_lap = request.POST.get(field_prefix + 'fastest-lap', None)
            retired = request.POST.get(field_prefix + 'retired', None)
            wildcard = request.POST.get(field_prefix + 'wildcard', None)
            result = Result.objects.get(race=race, seat_id=entry)
            update_needed = False
            if qualifying != result.qualifying:
                result.qualifying = qualifying if qualifying else None
                update_needed = True
            if finish != result.finish:
                result.finish = finish if finish else None
                update_needed = True
            if fastest_lap != result.fastest_lap:
                result.fastest_lap = fastest_lap if fastest_lap else False
            if retired != result.retired:
                result.retired = retired if retired else False
            if wildcard != result.wildcard:
                result.wildcard = wildcard if wildcard else False
            if update_needed:
                result.save()

    def del_result_entries(self, request, entries, race):
        for entry in entries:
            result = Result.objects.get(race=race, seat_id=entry)
            result.delete()

    def update_race_seats(self, request, new_seats, race):
        old_seats = [result.seat_id for result in race.results.all()]
        entries_to_add = lr_diff(new_seats, old_seats)
        entries_to_upd = lr_intr(new_seats, old_seats)
        entries_to_del = lr_diff(old_seats, new_seats)
        if entries_to_add:
            self.add_result_entries(request, entries_to_add, race)

        if entries_to_upd:
            self.update_result_entries(request, entries_to_upd, race)

        if entries_to_del:
            self.del_result_entries(request, entries_to_del, race)

    def results(self, request, race_id):
        race = self.model.objects.get(pk=race_id)
        title = 'Results in %s' % race
        season = race.season
        season_seats = Seat.objects.filter(seasons__pk=season.pk)
        if request.POST:
            post_entries = request.POST.getlist('entry[]')
            if post_entries:
                post_entries = map(int, post_entries)
                self.update_race_seats(request, post_entries, race)

            else:
                race_seats = [result.seat_id for result in race.results.all()]
                self.del_result_entries(request, race_seats, race)
        race_seats = [result.seat_id for result in race.results.all()]
        entries = []
        for seat in season_seats:
            contender = seat.contender
            driver_name = ' '.join((contender.driver.first_name, contender.driver.last_name))
            season_points = ContenderSeason(contender, season).get_points(limit_races=race.round)

            points = finish = qualifying = None
            fastest_lap = retired = wildcard = False

            is_race_seat = False
            if seat.pk in race_seats:
                result = Result.objects.get(race=race, seat=seat)
                qualifying = result.qualifying
                finish = result.finish if result.finish else None
                points = result.points
                fastest_lap = result.fastest_lap
                retired = result.retired
                wildcard = result.wildcard
                is_race_seat = True

            entry = {
                'seat': seat.pk,
                'driver_name': driver_name,
                'team': seat.team.name,
                'checked': is_race_seat,
                'qualifying': qualifying,
                'qualified': True if qualifying else False,
                'finish': finish,
                'finished': True if finish else False,
                'fastest_lap': fastest_lap,
                'retired': retired,
                'wildcard': wildcard,
                'points': points,
                'season_points': season_points
            }
            entries.append(entry)

        if race_seats:
            entries = sorted(entries, key=lambda x: (
                -x['checked'],
                -x['finished'],
                x['finish'],
                -x['qualified'],
                x['qualifying'],
                -x['season_points']
            ))
        else:
            entries = sorted(entries, key=lambda x: -x['season_points'])

        context = {
            'race': race, 'season': season, 'entries': entries, 'title': title,
            'opts': self.model._meta,
            'app_label': self.model._meta.app_label,
            'change': True
        }
        tpl = 'driver27/admin/results.html'
        return render(request, tpl, context)

class ContenderAdmin(TabbedModelAdmin):
    list_display = ('__unicode__', 'competition', 'teams_verbose', 'print_current')
    list_filter = ('competition',)
    tab_overview = (
        (None, {
        'fields': ('driver', 'competition')
        }),
    )
    tab_teams = (
        SeatInline,
    )
    tabs = [
        ('Overview', tab_overview),
        ('Teams', tab_teams)
    ]

    def print_current(self, obj):
        filter_current = Seat.objects.filter(
            contender__driver=obj.driver,
            contender__competition=obj.competition,
            current=True)
        return filter_current[0].team if filter_current.count() else None
    print_current.short_description = 'current team'

    def get_form(self, request, obj=None, **kwargs):
        # just save obj reference for future processing in Inline
        request._obj_ = obj
        return super(ContenderAdmin, self).get_form(request, obj, **kwargs)

admin.site.register(Driver, DriverAdmin)
admin.site.register(Team, TeamAdmin)
admin.site.register(Competition, CompetitionAdmin)
admin.site.register(Circuit, CircuitAdmin)
admin.site.register(GrandPrix, GrandPrixAdmin)
admin.site.register(Season, SeasonAdmin)
admin.site.register(Race, RaceAdmin)

# m2m admin
admin.site.register(Contender, ContenderAdmin)
<commit_msg>Fix Result admin save.<commit_after>from django.contrib import admin
from django import forms
from django.conf.urls import url
from django.shortcuts import render
from django.db.models.fields import BLANK_CHOICE_DASH

from django.core.urlresolvers import reverse

from tabbed_admin import TabbedModelAdmin

from .models import Driver, Team, Competition, Circuit, Season, GrandPrix, Race, Result
from .models import Contender, Seat, TeamSeason
from .models import ContenderSeason
from . import punctuation

lr_diff = lambda l, r: list(set(l).difference(r))
lr_intr = lambda l, r: list(set(l).intersection(r))

class RelatedCompetitionAdmin(object):
    """ Aux class to share print_competitions method between driver and team """
    def print_competitions(self, obj):
        if hasattr(obj, 'competitions'):
            return ', '.join("%s" % competition for competition in obj.competitions.all())
        else:
            return None
    print_competitions.short_description = 'competitions'

class CompetitionFilterInline(admin.TabularInline):
    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
        if request._obj_ is not None:
            if db_field.name == 'team':
                kwargs['queryset'] = Team.objects.filter(competitions__exact=request._obj_.competition)
            elif db_field.name == 'grand_prix':
                kwargs['queryset'] = GrandPrix.objects.filter(competitions__exact=request._obj_.competition)
            elif db_field.name == 'seat':
                kwargs['queryset'] = Seat.objects.filter(contender__competition__exact=request._obj_.competition)
        return super(CompetitionFilterInline, self).formfield_for_foreignkey(db_field, request, **kwargs)

class CommonRaceAdmin(object):
    def print_results_link(self, obj):
        if obj.pk:
            results_url = reverse("admin:driver27_race_results", args=[obj.pk])
            return '%s' % (results_url, 'Results')
        else:
            return None
    print_results_link.allow_tags = True
    print_results_link.short_description = 'link'

class RaceInline(CommonRaceAdmin, CompetitionFilterInline):
    model = Race
    extra = 1
    readonly_fields = ('print_results_link', )

class SeatInline(CompetitionFilterInline):
    model = Seat
    extra = 3

class SeatSeasonInline(CompetitionFilterInline):
    model = Seat.seasons.through
    extra = 3
    ordering = ('seat',)

class ContenderInline(admin.TabularInline):
    model = Contender
    extra = 1

class TeamSeasonInline(CompetitionFilterInline):
    model = TeamSeason
    extra = 1

class TeamInline(admin.TabularInline):
    model = Team
    extra = 1

class DriverAdmin(RelatedCompetitionAdmin, TabbedModelAdmin):
    list_display = ('__unicode__', 'country', 'print_competitions')
    list_filter = ('competitions__name',)
    tab_overview = (
        (None, {
        'fields': ('last_name', 'first_name', 'year_of_birth', 'country')
        }),
    )
    tab_competitions = (
        ContenderInline,
    )
    tabs = [
        ('Overview', tab_overview),
        ('Competitions', tab_competitions)
    ]

class TeamAdmin(RelatedCompetitionAdmin, admin.ModelAdmin):
    list_display = ('__unicode__', 'country', 'print_competitions')

class CompetitionAdmin(TabbedModelAdmin):
    model = Competition
    list_display = ('name', 'full_name')
    tab_overview = (
        (None, {
        'fields': ('name', 'full_name', 'country', 'slug')
        }),
    )
    tab_drivers = (
        ContenderInline,
    )
    tabs = [
        ('Overview', tab_overview),
        ('Drivers', tab_drivers)
    ]

class CircuitAdmin(admin.ModelAdmin):
    list_display = ('name', 'city', 'country', 'opened_in')

class GrandPrixAdmin(RelatedCompetitionAdmin, admin.ModelAdmin):
    list_display = ('name', 'country', 'default_circuit', 'print_competitions')

class SeasonAdminForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(SeasonAdminForm, self).__init__(*args, **kwargs)
        punctuation_dict = punctuation.DRIVER27_PUNCTUATION
        punctuation_choices = [(punct['code'], punct['label']) for punct in punctuation_dict]
        self.fields['punctuation'] = forms.ChoiceField(choices=BLANK_CHOICE_DASH + list(punctuation_choices), initial=None)

    class Meta:
        model = Season
        fields = ('year', 'competition', 'rounds', 'punctuation')

class SeasonAdmin(TabbedModelAdmin):
    form = SeasonAdminForm
    tab_overview = (
        (None, {
        'fields': ('year', 'competition', 'rounds', 'punctuation')
        }),
    )
    tab_teams = (
        TeamSeasonInline,
    )
    tab_drivers = (
        # (None, {
        #     'fields': ('team_contenders',)
        # }),
        SeatSeasonInline,
    )
    tab_races = (
        RaceInline,
    )
    tabs = [
        ('Overview', tab_overview),
        ('Teams', tab_teams),
        ('Drivers', tab_drivers),
        ('Races', tab_races),
    ]

    def get_form(self, request, obj=None, **kwargs):
        # just save obj reference for future processing in Inline
        if request and obj:
            request._obj_ = obj
        return super(SeasonAdmin, self).get_form(request, obj, **kwargs)

class RaceAdmin(CommonRaceAdmin, admin.ModelAdmin):
    list_display = ('__unicode__', 'season', 'print_pole', 'print_winner', 'print_fastest', 'print_results_link',)
    list_filter = ('season',)
    readonly_fields = ('print_results_link',)

    def print_pole(self, obj):
        pole = obj.pole
        return "%s" % obj.pole.contender.driver if pole else None
    print_pole.short_description = 'Pole'

    def print_winner(self, obj):
        winner = obj.winner
        return "%s" % winner.contender.driver if winner else None
    print_winner.short_description = 'Winner'

    def print_fastest(self, obj):
        fastest = obj.fastest
        return "%s" % fastest.contender.driver if fastest else None
    print_fastest.short_description = 'Fastest'

    def get_urls(self):
        urls = super(RaceAdmin, self).get_urls()
        urlpatterns = [
            url(r'(?P<race_id>\d+)/results/$', self.admin_site.admin_view(self.results), name='driver27_race_results')
        ]

        return urlpatterns + urls

    def edit_result_entries(self, request, entries, race, action='update'):
        for entry in entries:
            field_prefix = '%s-%s-' % ('seat', str(entry))
            qualifying = request.POST.get(field_prefix + 'qualifying', None)
            finish = request.POST.get(field_prefix + 'finish', None)
            fastest_lap = request.POST.get(field_prefix + 'fastest-lap', False)
            retired = request.POST.get(field_prefix + 'retired', False)
            wildcard = request.POST.get(field_prefix + 'wildcard', False)

            try:
                qualifying = int(qualifying)
            except ValueError:
                qualifying = None

            try:
                finish = int(finish)
            except ValueError:
                finish = None

            dict_to_save = {
                'qualifying': qualifying,
                'finish': finish,
                'fastest_lap': fastest_lap,
                'retired': retired,
                'wildcard': wildcard
            }
            if action == 'update':
                # filter allows update
                result = Result.objects.filter(race=race, seat_id=entry)
                result.update(**dict_to_save)
            elif action == 'add':
                Result.objects.create(
                    race=race,
                    seat_id=entry,
                    **dict_to_save
                )

    def add_result_entries(self, request, entries, race):
        self.edit_result_entries(request, entries, race, action='add')

    def update_result_entries(self, request, entries, race):
        self.edit_result_entries(request, entries, race, action='update')

    def del_result_entries(self, request, entries, race):
        for entry in entries:
            result = Result.objects.get(race=race, seat_id=entry)
            result.delete()

    def update_race_seats(self, request, new_seats, race):
        old_seats = [result.seat_id for result in race.results.all()]
        entries_to_add = lr_diff(new_seats, old_seats)
        entries_to_upd = lr_intr(new_seats, old_seats)
        entries_to_del = lr_diff(old_seats, new_seats)
        if entries_to_add:
            self.add_result_entries(request, entries_to_add, race)

        if entries_to_upd:
            self.update_result_entries(request, entries_to_upd, race)

        if entries_to_del:
            self.del_result_entries(request, entries_to_del, race)

    def order_entries(self, entries, seats_len):
        if seats_len:
            entries = sorted(entries, key=lambda x: (
                -x['checked'],
                -x['finished'],
                x['finish'],
                -x['qualified'],
                x['qualifying'],
                -x['season_points']
            ))
        else:
            entries = sorted(entries, key=lambda x: -x['season_points'])
        return entries

    def results(self, request, race_id):
        race = self.model.objects.get(pk=race_id)
        title = 'Results in %s' % race
        season = race.season
        season_seats = Seat.objects.filter(seasons__pk=season.pk)
        if request.POST:
            post_entries = request.POST.getlist('entry[]')
            if post_entries:
                post_entries = map(int, post_entries)
                self.update_race_seats(request, post_entries, race)

            else:
                race_seats = [result.seat_id for result in race.results.all()]
                self.del_result_entries(request, race_seats, race)
        race_seats = [result.seat_id for result in race.results.all()]
        entries = []
        for seat in season_seats:
            contender = seat.contender
            driver_name = ' '.join((contender.driver.first_name, contender.driver.last_name))
            season_points = ContenderSeason(contender, season).get_points(limit_races=race.round)

            points = finish = qualifying = None
            fastest_lap = retired = wildcard = False

            is_race_seat = False
            if seat.pk in race_seats:
                result = Result.objects.get(race=race, seat=seat)
                qualifying = result.qualifying
                finish = result.finish if result.finish else None
                points = result.points
                fastest_lap = result.fastest_lap
                retired = result.retired
                wildcard = result.wildcard
                is_race_seat = True

            entry = {
                'seat': seat.pk,
                'driver_name': driver_name,
                'team': seat.team.name,
                'checked': is_race_seat,
                'qualifying': qualifying,
                'qualified': bool(qualifying),
                'finish': finish,
                'finished': bool(finish),
                'fastest_lap': fastest_lap,
                'retired': retired,
                'wildcard': wildcard,
                'points': points,
                'season_points': season_points
            }
            entries.append(entry)

        entries = self.order_entries(entries, len(race_seats))

        context = {
            'race': race, 'season': season, 'entries': entries, 'title': title,
            'opts': self.model._meta,
            'app_label': self.model._meta.app_label,
            'change': True
        }
        tpl = 'driver27/admin/results.html'
        return render(request, tpl, context)

class ContenderAdmin(TabbedModelAdmin):
    list_display = ('__unicode__', 'competition', 'teams_verbose', 'print_current')
    list_filter = ('competition',)
    tab_overview = (
        (None, {
        'fields': ('driver', 'competition')
        }),
    )
    tab_teams = (
        SeatInline,
    )
    tabs = [
        ('Overview', tab_overview),
        ('Teams', tab_teams)
    ]

    def print_current(self, obj):
        filter_current = Seat.objects.filter(
            contender__driver=obj.driver,
            contender__competition=obj.competition,
            current=True)
        return filter_current[0].team if filter_current.count() else None
    print_current.short_description = 'current team'

    def get_form(self, request, obj=None, **kwargs):
        # just save obj reference for future processing in Inline
        request._obj_ = obj
        return super(ContenderAdmin, self).get_form(request, obj, **kwargs)

admin.site.register(Driver, DriverAdmin)
admin.site.register(Team, TeamAdmin)
admin.site.register(Competition, CompetitionAdmin)
admin.site.register(Circuit, CircuitAdmin)
admin.site.register(GrandPrix, GrandPrixAdmin)
admin.site.register(Season, SeasonAdmin)
admin.site.register(Race, RaceAdmin)

# m2m admin
admin.site.register(Contender, ContenderAdmin)
<|endoftext|>


<commit_before>from .streak import Streak
from django.core.exceptions import ValidationError
from django.db import models
from .records import get_record_config
from . import LIMIT_POSITION_LIST

class AbstractStreakModel(object):
    def get_results(self, *args, **kwargs):
        raise NotImplementedError('Not implemented property')

    def get_reverse_results(self, *args, **kwargs):
        raise NotImplementedError('Not implemented property')

    @property
    def is_active(self):
        raise NotImplementedError('Not implemented property')

    def get_streak(self, max_streak=False, result_filter=None, unique_by_race=False, **filters):
        from .models import get_tuples_from_results
        if not result_filter:
            result_filter = {}
        results = self.get_reverse_results(**result_filter)
        results_tuples = get_tuples_from_results(results=results)
        return Streak(results=results_tuples, max_streak=max_streak, unique_by_race=unique_by_race).run(filters)

    def get_positions(self, qualifying=False, limit_races=None, competition=None, **kwargs):
        pos_field = 'qualifying' if qualifying else 'finish'
        results = self.get_results(limit_races=limit_races, competition=competition, **kwargs)
        positions = results.values_list(pos_field, flat=True)
        return list(positions)

    def get_positions_count_list(self, limit_races=None, competition=None, **kwargs):
        """ Return a list with the count of each 20 first positions """
        finish_pos = self.get_positions(limit_races=limit_races, competition=competition, **kwargs)
        positions_count = []
        for x in range(LIMIT_POSITION_LIST):
            position_count = finish_pos.count(x+1)
            positions_count.append(position_count)
        return positions_count

    def get_positions_count_str(self, position_list=None, limit_races=None):
        """ Return a str with position_count_list to order """
        " Each list item will be filled to zeros until get three digits e.g. 1 => 001, 12 => 012 "
        if not position_list:
            position_list = self.get_positions_count_list(limit_races=limit_races)
        positions_str = ''.join([str(x).zfill(3) for x in position_list])
        return positions_str

class AbstractStatsModel(AbstractStreakModel, models.Model):

    def get_results(self, *args, **kwargs):
        raise NotImplementedError('Not implemented property')

    @property
    def is_active(self):
        raise NotImplementedError('Not implemented property')

    @property
    def result_filter_kwargs(self):
        raise NotImplementedError('Not implemented property')

    def get_points(self, *args, **kwargs):
        raise NotImplementedError('Not implemented property')

    def season_stats_cls(self, *args, **kwargs):
        raise NotImplementedError('Not implemented method')

    def get_season(self, season):
        try:
            season_stats = self.season_stats_cls(season)
            return season_stats
        except ValidationError:
            return None

    def get_multiple_records(self, records_list=None, append_points=False, **kwargs):
        multiple_records = {}
        if records_list is None:
            records_list = ['RACE', 'POLE', 'WIN', 'PODIUM', 'FASTEST']
        for record in records_list:
            record_config = get_record_config(record).get('filter')
            if hasattr(self, 'get_total_races') and record == 'RACE':
                record_stat = self.get_total_races(**dict(kwargs, **record_config))
            else:
                record_stat = self.get_stats(**dict(kwargs, **record_config))
            multiple_records[record] = record_stat
        if append_points:
            multiple_records['POINTS'] = self.get_points(**kwargs)
        return multiple_records

    def get_saved_points(self, limit_races=None, **kwargs):
        results = self.get_results(limit_races=limit_races, **kwargs)
        return [result.points for result in results if not result.wildcard and result.points is not None]

    def get_reverse_results(self, limit_races=None, **extra_filter):
        return self.get_results(limit_races=limit_races, reverse_order=True, **extra_filter)

    def get_races(self, **filters):
        """ Return only race id of team in season """
        results = self.get_results(**filters).values('race').annotate(count_race=models.Count('race')).order_by()
        return results

    def get_stats(self, **filters):
        """ Count 1 by each result """
        return self.get_results(**filters).count()

    class Meta:
        abstract = True

class TeamStatsModel(AbstractStatsModel):
    def season_stats_cls(self, *args, **kwargs):
        raise NotImplementedError('Not implemented property')

    def get_points(self, *args, **kwargs):
        raise NotImplementedError('Not implemented property')

    @property
    def result_filter_kwargs(self):
        raise NotImplementedError('Not implemented property')

    @property
    def is_active(self):
        raise NotImplementedError('Not implemented property')

    def get_results(self, *args, **kwargs):
        raise NotImplementedError('Not implemented property')

    def get_total_races(self, **filters):
        """ Only count 1 by race with any driver in filter """
        return self.get_races(**filters).count()

    def get_doubles_races(self, **filters):
        """ Only count 1 by race with at least two drivers in filter """
        return self.get_races(**filters).filter(count_race__gte=2).count()

    def get_total_stats(self, **filters):  # noqa
        """ Count 1 by each result """
        return self.get_results(**filters).count()

    def get_team_total_races(self, **filters):
        """ Only count 1 by race with any driver in filter """
        return self.get_races(**filters).count()

    def get_team_doubles_races(self, **filters):
        """ Only count 1 by race with at least two drivers in filter """
        return self.get_races(**filters).filter(count_race__gte=2).count()

    def get_team_total_stats(self, **filters):  # noqa
        """ Count 1 by each result """
        return self.get_results(**filters).count()

    class Meta:
        abstract = True

class StatsByCompetitionModel(AbstractStatsModel):
    def get_multiple_records_by_competition(self, records_list=None, append_points=False, **kwargs):
        stats_by_competition = []
        for competition in getattr(self, 'competitions').all():
            stats_by_competition.append(
                {
                    'competition': competition,
                    'stats': self.get_multiple_records(records_list=records_list,
                                                       append_points=append_points,
                                                       competition=competition, **kwargs)
                }
            )
        return stats_by_competition

    class Meta:
        abstract = True

<commit_msg>Remove duplicate methods<commit_after>from .streak import Streak
from django.core.exceptions import ValidationError
from django.db import models
from .records import get_record_config
from . import LIMIT_POSITION_LIST

class AbstractStreakModel(object):
    def get_results(self, *args, **kwargs):
        raise NotImplementedError('Not implemented property')

    def get_reverse_results(self, *args, **kwargs):
        raise NotImplementedError('Not implemented property')

    @property
    def is_active(self):
        raise NotImplementedError('Not implemented property')

    def get_streak(self, max_streak=False, result_filter=None, unique_by_race=False, **filters):
        from .models import get_tuples_from_results
        if not result_filter:
            result_filter = {}
        results = self.get_reverse_results(**result_filter)
        results_tuples = get_tuples_from_results(results=results)
        return Streak(results=results_tuples, max_streak=max_streak, unique_by_race=unique_by_race).run(filters)

    def get_positions(self, qualifying=False, limit_races=None, competition=None, **kwargs):
        pos_field = 'qualifying' if qualifying else 'finish'
        results = self.get_results(limit_races=limit_races, competition=competition, **kwargs)
        positions = results.values_list(pos_field, flat=True)
        return list(positions)

    def get_positions_count_list(self, limit_races=None, competition=None, **kwargs):
        """ Return a list with the count of each 20 first positions """
        finish_pos = self.get_positions(limit_races=limit_races, competition=competition, **kwargs)
        positions_count = []
        for x in range(LIMIT_POSITION_LIST):
            position_count = finish_pos.count(x+1)
            positions_count.append(position_count)
        return positions_count

    def get_positions_count_str(self, position_list=None, limit_races=None):
        """ Return a str with position_count_list to order """
        " Each list item will be filled to zeros until get three digits e.g. 1 => 001, 12 => 012 "
        if not position_list:
            position_list = self.get_positions_count_list(limit_races=limit_races)
        positions_str = ''.join([str(x).zfill(3) for x in position_list])
        return positions_str

class AbstractStatsModel(AbstractStreakModel, models.Model):

    def get_results(self, *args, **kwargs):
        raise NotImplementedError('Not implemented property')

    @property
    def is_active(self):
        raise NotImplementedError('Not implemented property')

    @property
    def result_filter_kwargs(self):
        raise NotImplementedError('Not implemented property')

    def get_points(self, *args, **kwargs):
        raise NotImplementedError('Not implemented property')

    def season_stats_cls(self, *args, **kwargs):
        raise NotImplementedError('Not implemented method')

    def get_season(self, season):
        try:
            season_stats = self.season_stats_cls(season)
            return season_stats
        except ValidationError:
            return None

    def get_multiple_records(self, records_list=None, append_points=False, **kwargs):
        multiple_records = {}
        if records_list is None:
            records_list = ['RACE', 'POLE', 'WIN', 'PODIUM', 'FASTEST']
        for record in records_list:
            record_config = get_record_config(record).get('filter')
            if hasattr(self, 'get_total_races') and record == 'RACE':
                record_stat = self.get_total_races(**dict(kwargs, **record_config))
            else:
                record_stat = self.get_stats(**dict(kwargs, **record_config))
            multiple_records[record] = record_stat
        if append_points:
            multiple_records['POINTS'] = self.get_points(**kwargs)
        return multiple_records

    def get_saved_points(self, limit_races=None, **kwargs):
        results = self.get_results(limit_races=limit_races, **kwargs)
        return [result.points for result in results if not result.wildcard and result.points is not None]

    def get_reverse_results(self, limit_races=None, **extra_filter):
        return self.get_results(limit_races=limit_races, reverse_order=True, **extra_filter)

    def get_races(self, **filters):
        """ Return only race id of team in season """
        results = self.get_results(**filters).values('race').annotate(count_race=models.Count('race')).order_by()
        return results

    def get_stats(self, **filters):
        """ Count 1 by each result """
        return self.get_results(**filters).count()

    class Meta:
        abstract = True

class TeamStatsModel(AbstractStatsModel):
    def season_stats_cls(self, *args, **kwargs):
        raise NotImplementedError('Not implemented property')

    def get_points(self, *args, **kwargs):
        raise NotImplementedError('Not implemented property')

    @property
    def result_filter_kwargs(self):
        raise NotImplementedError('Not implemented property')

    @property
    def is_active(self):
        raise NotImplementedError('Not implemented property')

    def get_results(self, *args, **kwargs):
        raise NotImplementedError('Not implemented property')

    def get_total_races(self, **filters):
        """ Only count 1 by race with any driver in filter """
        return self.get_races(**filters).count()

    def get_total_stats(self, **filters):  # noqa
        """ Count 1 by each result """
        return self.get_results(**filters).count()

    def get_doubles_races(self, **filters):
        """ Only count 1 by race with at least two drivers in filter """
        return self.get_races(**filters).filter(count_race__gte=2).count()

    class Meta:
        abstract = True

class StatsByCompetitionModel(AbstractStatsModel):
    def get_multiple_records_by_competition(self, records_list=None, append_points=False, **kwargs):
        stats_by_competition = []
        for competition in getattr(self, 'competitions').all():
            stats_by_competition.append(
                {
                    'competition': competition,
                    'stats': self.get_multiple_records(records_list=records_list,
                                                       append_points=append_points,
                                                       competition=competition, **kwargs)
                }
            )
        return stats_by_competition

    class Meta:
        abstract = True

<|endoftext|>


<commit_before>from email.mime.text import MIMEText
from functools import wraps
from itertools import chain
import smtplib
import argparse
import os
import socket
import subprocess
import sys
import time
import traceback
import errno

# TODO: refactor everything
# TODO: write docstrings

class donemail(object):
    def __init__(self, to, subject='', body='', sender=''):
        self._to = to
        self._subject = subject
        self._body = body
        self._sender = sender or _get_default_sender()

    def __call__(self, function):
        @wraps(function)
        def donemail_function(*args, **kwargs):
            call_str = _make_call_str(function, args, kwargs)
            try:
                result = function(*args, **kwargs)
            except Exception as exc:
                exc_type, exc_value, tb = sys.exc_info()
                subject = '{} raised {}'.format(call_str, exc_type.__name__)
                # tb_next is to hide the fact that we're inside of the decorator
                body = '\n'.join(traceback.format_exception(exc_type, exc_value, tb.tb_next))
                self.send_email(subject, body)
                raise exc_type, exc_value, tb.tb_next
            else:
                self.send_email('{} returned {!r}'.format(call_str, result))
                return result

        return donemail_function

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, tb):
        if exc_value is not None:
            subject = 'block raised {}'.format(exc_type.__name__)
            body = '\n'.join(traceback.format_exception(exc_type, exc_value, tb))
            self.send_email(subject, body)
        else:
            self.send_email(subject='done')

    def send_email(self, subject='', body=''):
        msg = MIMEText(self._body or body)
        # TODO: do we need both msg['To'] and sendmail(..., [self._to], ...)?
        msg['To'] = self._to
        msg['From'] = self._sender
        msg['Subject'] = self._subject or subject
        # TODO: handle bad connection gracefully
        s = smtplib.SMTP('localhost')
        try:
            s.sendmail(self._sender, [self._to], msg.as_string())
        finally:
            s.quit()

def main(cmd_args=None):
    parser = argparse.ArgumentParser(prog='donemail')
    subparsers = parser.add_subparsers()
    parent_parser = _get_parent_parser()

    wait_parser = subparsers.add_parser(
        'wait', parents=[parent_parser],
        help='send an email after the process with the specified pid exits')
    wait_parser.add_argument('pid', type=int, help='pid to wait for')
    wait_parser.set_defaults(func=_wait_pid)

    run_parser = subparsers.add_parser(
        'run', parents=[parent_parser],
        help='run a command and send an email after a command exits')
    run_parser.add_argument('command', help='command to execute')
    run_parser.add_argument('command_args', nargs=argparse.REMAINDER, help='command arguments')
    run_parser.set_defaults(func=_run_command)
    args = parser.parse_args(cmd_args)
    donemail_obj = donemail(to=args.email, body=args.body, subject=args.subject)
    args.func(args, donemail_obj)

def _email(s):
    if '@' not in s:
        raise argparse.ArgumentTypeError(
            'email should contain @. Got: {!r}'.format(s))
    return s

def _pid_exists(pid):
    try:
        os.kill(pid, 0)
        return True
    except OSError as exc:
        if exc.errno == errno.ESRCH:  # no such process
            return False
        elif exc.errno == errno.EPERM:  # process exists, but is not killable
            return True
        return False

def _wait_pid(args, donemail_obj):
    if not _pid_exists(args.pid):
        sys.exit('pid {:d} doesn\'t exist'.format(args.pid))
    sys.stderr.write('waiting for pid {:d} to finish\n'.format(args.pid))

    # TODO: make poll_interval_sec a command-line option
    poll_interval_sec = 1
    while _pid_exists(args.pid):
        time.sleep(poll_interval_sec)
    subject = 'process with pid {:d} exited'.format(args.pid)
    donemail_obj.send_email(subject)

def _run_command(args, donemail_obj):
    cmd = [args.command] + args.command_args
    status_code = subprocess.call(cmd)
    subject = '`{}` exited with status code {:d}'.format(
        ' '.join(cmd), status_code)
    donemail_obj.send_email(subject)

def _make_call_str(function, args, kwargs):
    args_part = map(repr, args)
    kwargs_part = ['{}={!r}'.format(name, value)
                   for name, value in kwargs.viewitems()]
    all_args_part = ', '.join(chain(args_part, kwargs_part))
    return '{}({})'.format(function.__name__, all_args_part)

def _get_default_sender():
    return 'donemail@{}'.format(socket.gethostname())

def _get_parent_parser():
    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument('email', type=_email, help='address to send email to')
    parser.add_argument('--subject', help='subject of the email')
    parser.add_argument('--body', help='body of the email')
    return parser<commit_msg>Add --poll-interval option for donemail-wait<commit_after>from email.mime.text import MIMEText
from functools import wraps
from itertools import chain
import smtplib
import argparse
import os
import socket
import subprocess
import sys
import time
import traceback
import errno

# TODO: refactor everything
# TODO: write docstrings

class donemail(object):
    # TODO: allow to configure smtp connection
    def __init__(self, to, subject='', body='', sender=''):
        self._to = to
        self._subject = subject
        self._body = body
        self._sender = sender or _get_default_sender()

    def __call__(self, function):
        @wraps(function)
        def donemail_function(*args, **kwargs):
            call_str = _make_call_str(function, args, kwargs)
            try:
                result = function(*args, **kwargs)
            except Exception as exc:
                exc_type, exc_value, tb = sys.exc_info()
                subject = '{} raised {}'.format(call_str, exc_type.__name__)
                # tb_next is to hide the fact that we're inside of the decorator
                body = '\n'.join(traceback.format_exception(exc_type, exc_value, tb.tb_next))
                self.send_email(subject, body)
                raise exc_type, exc_value, tb.tb_next
            else:
                self.send_email('{} returned {!r}'.format(call_str, result))
                return result

        return donemail_function

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, tb):
        if exc_value is not None:
            subject = 'block raised {}'.format(exc_type.__name__)
            body = '\n'.join(traceback.format_exception(exc_type, exc_value, tb))
            self.send_email(subject, body)
        else:
            self.send_email(subject='done')

    def send_email(self, subject='', body=''):
        msg = MIMEText(self._body or body)
        # TODO: do we need both msg['To'] and sendmail(..., [self._to], ...)?
        msg['To'] = self._to
        msg['From'] = self._sender
        msg['Subject'] = self._subject or subject
        # TODO: handle bad connection gracefully
        s = smtplib.SMTP('localhost')
        try:
            s.sendmail(self._sender, [self._to], msg.as_string())
        finally:
            s.quit()

def main(cmd_args=None):
    parser = argparse.ArgumentParser(prog='donemail')
    subparsers = parser.add_subparsers()
    parent_parser = _get_parent_parser()

    wait_parser = subparsers.add_parser(
        'wait', parents=[parent_parser],
        help='send an email after the process with the specified pid exits')
    wait_parser.add_argument('--poll-interval', type=float, default=1.0,
                             help='sleep duration (in seconds) between pid checks')
    wait_parser.add_argument('pid', type=int, help='pid to wait for')
    wait_parser.set_defaults(func=_wait_pid)

    run_parser = subparsers.add_parser(
        'run', parents=[parent_parser],
        help='run a command and send an email after a command exits')
    run_parser.add_argument('command', help='command to execute')
    run_parser.add_argument('command_args', nargs=argparse.REMAINDER, help='command arguments')
    run_parser.set_defaults(func=_run_command)
    args = parser.parse_args(cmd_args)
    donemail_obj = donemail(to=args.email, body=args.body, subject=args.subject)
    args.func(args, donemail_obj)

def _email(s):
    if '@' not in s:
        raise argparse.ArgumentTypeError(
            'email should contain @. Got: {!r}'.format(s))
    return s

def _pid_exists(pid):
    try:
        os.kill(pid, 0)
        return True
    except OSError as exc:
        if exc.errno == errno.ESRCH:  # no such process
            return False
        elif exc.errno == errno.EPERM:  # process exists, but is not killable
            return True
        return False

def _wait_pid(args, donemail_obj):
    if not _pid_exists(args.pid):
        sys.exit('pid {:d} doesn\'t exist'.format(args.pid))
    sys.stderr.write('waiting for pid {:d} to finish\n'.format(args.pid))

    while _pid_exists(args.pid):
        time.sleep(args.poll_interval)
    subject = 'process with pid {:d} exited'.format(args.pid)
    donemail_obj.send_email(subject)

def _run_command(args, donemail_obj):
    cmd = [args.command] + args.command_args
    status_code = subprocess.call(cmd)
    subject = '`{}` exited with status code {:d}'.format(
        ' '.join(cmd), status_code)
    donemail_obj.send_email(subject)

def _make_call_str(function, args, kwargs):
    args_part = map(repr, args)
    kwargs_part = ['{}={!r}'.format(name, value)
                   for name, value in kwargs.viewitems()]
    all_args_part = ', '.join(chain(args_part, kwargs_part))
    return '{}({})'.format(function.__name__, all_args_part)

def _get_default_sender():
    return 'donemail@{}'.format(socket.gethostname())

def _get_parent_parser():
    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument('email', type=_email, help='address to send email to')
    parser.add_argument('--subject', help='subject of the email')
    parser.add_argument('--body', help='body of the email')
    return parser<|endoftext|>


<commit_before>#!/usr/bin/python
#  This script will build platform-specific dotfiles and create the appropriate symlinks in ~

import platform
import os
import sys
sysName = ''
homeDir = ''
destDir = ''
bashrc = ''
def init():
  global sysName
  global bashrc
  global homeDir
  global destDir
  sysName = platform.system()
  if sysName != 'Linux' and sysName != 'Darwin':
    print "System not supported!"
    exit(1)
  else:
    print "System identified as " + sysName

  homeDir = os.path.expanduser('~') + '/'
  destDir = os.path.dirname(os.path.abspath(__file__)) + '/'
  os.chdir(destDir)
  cleanUp()
  bashrc = open('bashrc','a')
  bashrc.write("#!/bin/bash\n")
  bashrc.write("# This file was generated by a script. Do not edit manually!\n")

def cleanUp():
  print "Cleaning up files in " + destDir + " ..."
  for file in ['bashrc']:
    if os.path.isfile(file):
      print file
      os.remove(file)

def writeSection(fileName, allowComments):
  f = open(fileName,'r')
  for line in f:
    if line.startswith('#'):
      if allowComments:
        bashrc.write(line)
    else:
      bashrc.write(line)

def createSymlink(targetName, linkName)	:
  target = destDir + targetName
  link = homeDir +  linkName
  print "Creating symlink: " + link + " -> " + target
  if os.path.islink(link):
    print "Link exists. Removing..."
    os.remove(link)
  os.symlink(target, link)
  print "Link created."

def install():
  if sysName == 'Linux':
    bashrc.write("# ~/.bashrc: executed by bash(1) for non-login shells.\n")
    if os.path.isfile('bash_private'):
      writeSection('bash_private',False)
    writeSection('bash_common',False)
    writeSection('bash_linux',True)
    createSymlink('bashrc','.bashrc')
  elif sysName == 'Darwin':
    bashrc.write("# ~/.bash_profile: executed by bash(1) for lon-login shells.\n")
    if os.path.isfile('bash_private'):
      writeSection('bash_private',False)
    writeSection('bash_common',False)
    writeSection('bash_mac',True)
    createSymlink('bashrc','.bash_profile')

  createSymlink('vimrc','.vimrc')
  bashrc.close()

init()
if __name__ == '__main__':
  install()
<commit_msg>Break out init logic into separate methods.<commit_after>#!/usr/bin/python
#  This script will build platform-specific dotfiles and create the appropriate symlinks in ~

import platform
import os
import sys
sysName = ''
homeDir = ''
destDir = ''
bashrc = ''
def init():
  global homeDir
  global destDir

  homeDir = os.path.expanduser('~') + '/'
  destDir = os.path.dirname(os.path.abspath(__file__)) + '/'
  os.chdir(destDir)

def identifySystem():
  global sysName
  sysName = platform.system()
  if sysName != 'Linux' and sysName != 'Darwin':
    print "System not supported!"
    exit(1)
  else:
    print "System identified as " + sysName

def cleanUp():
  print "Cleaning up files in " + destDir + " ..."
  for file in ['bashrc']:
    if os.path.isfile(file):
      print file
      os.remove(file)

def writeFileHeader():
  global bashrc
  bashrc = open('bashrc','a')
  bashrc.write("#!/bin/bash\n")
  bashrc.write("# This file was generated by a script. Do not edit manually!\n")

def writeSection(fileName, allowComments):
  f = open(fileName,'r')
  for line in f:
    if line.startswith('#'):
      if allowComments:
        bashrc.write(line)
    else:
      bashrc.write(line)

def createSymlink(targetName, linkName)	:
  target = destDir + targetName
  link = homeDir +  linkName
  print "Creating symlink: " + link + " -> " + target
  if os.path.islink(link):
    print "Link exists. Removing..."
    os.remove(link)
  os.symlink(target, link)
  print "Link created."

def install():
  if sysName == 'Linux':
    bashrc.write("# ~/.bashrc: executed by bash(1) for non-login shells.\n")
    if os.path.isfile('bash_private'):
      writeSection('bash_private',False)
    writeSection('bash_common',False)
    writeSection('bash_linux',True)
    createSymlink('bashrc','.bashrc')
  elif sysName == 'Darwin':
    bashrc.write("# ~/.bash_profile: executed by bash(1) for lon-login shells.\n")
    if os.path.isfile('bash_private'):
      writeSection('bash_private',False)
    writeSection('bash_common',False)
    writeSection('bash_mac',True)
    createSymlink('bashrc','.bash_profile')

  createSymlink('vimrc','.vimrc')
  bashrc.close()

if __name__ == '__main__':
  init()
  identifySystem()
  cleanUp()
  writeFileHeader()
  install()
<|endoftext|>


<commit_before>import logging

def spawn_rconsole(env):
    rfoo_logger = logging.getLogger('rfoo')
    rfoo_logger.disabled = 1
    try:
        import rfoo.utils.rconsole
        import rfoo._rfoo
        rfoo._rfoo.logging = rfoo.utils.rconsole.logging = rfoo_logger

        from rfoo.utils import rconsole
        rconsole.spawn_server(env, 0)
    except ImportError:
        pass
<commit_msg>Refactor import.<commit_after>import logging

def spawn_rconsole(env):
    rfoo_logger = logging.getLogger('rfoo')
    rfoo_logger.disabled = 1
    try:
        from rfoo.utils import rconsole
        import rfoo._rfoo
        rfoo._rfoo.logging = rconsole.logging = rfoo_logger
        rconsole.spawn_server(env, 0)
    except ImportError:
        pass
<|endoftext|>


<commit_before>#!/usr/bin/python
# filename: tasks.py

#
# Copyright (c) 2015 Bryan Briney
# License: The MIT license (http://opensource.org/licenses/MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software
# and associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
# BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

from Bio import SeqIO

from abtools.queue.celery import celery
from abtools.utils.alignment import global_alignment
from abtools.utils.sequence import Sequence

@celery.task
def identity(f, standard, is_aa, debug=False):
	seqs = [s for s in SeqIO.parse(open(f, 'r'), 'fasta')]
	scores = []
	for s in seqs:
		seq_id = '_'.join(s.id.split('_')[:-1])
		germ_identity = float(s.id.split('_')[-1])
		seq = str(s.seq).upper()
		matrix = 'blosum62' if is_aa else None
		aln = global_alignment(seq,
							  str(standard.seq.upper()),
							  matrix=matrix,
							  gap_open=-15,
							  gap_extend=-2,
							  score_match=1,
							  score_mismatch=0,
							  score_gap_open=0,
							  score_gap_extend=0,
							  aa=is_aa)
		score = aln.score
		aln_length = min(len(aln.aligned_query.strip('-')), len(aln.aligned_target.strip('-')))
		norm_score = 100. * score / aln_length
		norm_score = round(norm_score, 1)
		scores.append((seq_id, norm_score, germ_identity))
	return scores
<commit_msg>fix abfinder import<commit_after>#!/usr/bin/python
# filename: tasks.py

#
# Copyright (c) 2015 Bryan Briney
# License: The MIT license (http://opensource.org/licenses/MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software
# and associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
# BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

from Bio import SeqIO

from abtools.queue.celery import celery
from abtools.alignment import global_alignment
from abtools.sequence import Sequence

@celery.task
def identity(f, standard, is_aa, debug=False):
	seqs = [s for s in SeqIO.parse(open(f, 'r'), 'fasta')]
	scores = []
	for s in seqs:
		seq_id = '_'.join(s.id.split('_')[:-1])
		germ_identity = float(s.id.split('_')[-1])
		seq = str(s.seq).upper()
		matrix = 'blosum62' if is_aa else None
		aln = global_alignment(seq,
							  str(standard.seq.upper()),
							  matrix=matrix,
							  gap_open=-15,
							  gap_extend=-2,
							  score_match=1,
							  score_mismatch=0,
							  score_gap_open=0,
							  score_gap_extend=0,
							  aa=is_aa)
		score = aln.score
		aln_length = min(len(aln.aligned_query.strip('-')), len(aln.aligned_target.strip('-')))
		norm_score = 100. * score / aln_length
		norm_score = round(norm_score, 1)
		scores.append((seq_id, norm_score, germ_identity))
	return scores
<|endoftext|>


<commit_before>"""

acreroad_1420 Drive software

Software designed to drive the 1420 MHz telescope on the roof of the
Acre Road observatory. This class interacts with "qp", the telescope
drive software by Norman Gray (https://bitbucket.org/nxg/qp) via a
serial (USB) interface.

The serial interfacing is done through pySerial.

Parameters
----------

device : str
   The name of the unix device which the drive is connected to
port : int
   The port number of the drive
simulate : bool
   A boolean flag to set the drive in simulation mode
   (the class does not connect to the controller in simulation mode)

"""

import re, datetime

import astropy
from astropy.coordinates import SkyCoord, ICRS, EarthLocation
import astropy.units as u

class Drive():

    sim = 0
    acre_road = EarthLocation(lat=55.9024278*u.deg, lon=-4.307582*u.deg, height=61*u.m)

    # String formats

    com_format = re.compile("[A-Za-z]{1,2} ?([-+]?[0-9]{0,4}\.[0-9]{0,8} ?){0,6}") # general command string format
    cal_format = re.compile("[0-9]{3} [0-9]{3}") # calibration string format

    def __init__(self, device, port, simulate):
        """
        Software designed to drive the 1420 MHz telescope on the roof of the
        Acre Road observatory. This class interacts with "qp", the telescope
        drive software by Norman Gray (https://bitbucket.org/nxg/qp) via a
        serial (USB) interface.

        The serial interfacing is done through pySerial.

        Parameters
        ----------

        device : str
           The name of the unix device which the drive is connected to
        port : int
           The port number of the drive
        simulate : bool
           A boolean flag to set the drive in simulation mode
           (the class does not connect to the controller in simulation mode)

        """
        self.sim = simulate
        pass

    def _command(self, string):
        """
        Passes commands to the controller.
        """

        # Check that the command string is a string, and that it
        # matches the format required for a command string
        string = str(string)

        if not self.com_format.match(string):
            raise ValueError(string+" : This string doesn't have the format of a valid controller command.'")

        if self.sim:
            print("In simulation mode, command ignored.")
            return 1

    def calibrate(self, values=None):
        """
        Carries-out a calibration run, returning two numbers which are offsets, or sets the calibration if known values are provided.

        Parameters
        ----------

        values : str
           The calibration values produced by a previous calibration run of the telescope, provided in the format "nnn nnn"

        """
        if values:
            # Check the format of the values string.
            if self.cal_format.match(values):
                return self._command("c "+values)
        if self.sim: return ">c 000 000"
        pass

    def setTime(self):
        """
        Sets the time on the drive controller's clock to the current system time.

        """
        time = datetime.datetime.utcnow()

        command_str = "t {} {} {} {} {} {}".format(time.year, time.month, time.day, time.hour, time.minute, time.second)

        return self._command(command_str)

    def setLocation(self, location=None, dlat=0, dlon=0):
        """
        Sets the location of the telescope.

        Parameters
        ----------
        location : astropy.coordinates.EarthLocation object
        """
        if not location:
            # Assume we're at Acre Road, in Glasgow
            location = self.acre_road

        latitude  = location.latitude
        longitude = location.longitude

        # Construct the command
        command_str = "T {} {} {} {}".format(latitude, longitude, dlat, dlon)
        return self._command(command_str)

    def goto(self, skycoord):
        """
        Moves the telescope to point at a given sky location, and then commands the drive to track the point.

        Parameters
        ----------
        skycoord : astropy.SkyCoord object
           An astropy SkyCoord object which contains the sky location to slew to.
           This can also be a list of locations which the telescope will slew to sequentially.

        """

        if not type(skycoord)==astropy.coordinates.sky_coordinate.SkyCoord:
            raise ValueError("The sky coordinates provided aren't an astropy SkyCoord object!'")

        # We need to make sure that we send RA and DEC values to the
        # controller (it is theoretically possible to do ALTAZ too,
        # but let's start simple, eh?')

        skycoord = skycoord.transform_to(frame=ICRS)
        ra  = skycoord.ra
        dec = skycoord.dec

        # construct a command string
        command_str = "gE {} {}".format(ra, dec)
        # pass the slew-to command to the controller
        if self._command(command_str):
            # We need to do more here than just check the command has
            # passed successfully; we need to check the telescope is
            # (or thinks it is) pointing where we asked.
            if self.sim:
                self.ra  = ra
                self.dec = dec

            # If the command completes then set the controller to track the object
            command_str = "ts"
            return self._command(command_str)
        else:
            raise ControllerError("The telescope has failed to slew to the requested location")

    def home(self):
        """
        Slews the telescope to the home position.

        """
        command_str = "gh"
        return self._command(command_str)

    def status(self):
        """
        Returns a dictionary describing the status of the telescope (e.g. its location).

        Returns
        -------
        dict
           A dictionary containing the right ascension, declination, altitude, and azimuth of the telescope.

        Examples
        --------

        >>> from astropy.coordinates import SkyCoord
        >>> from astropy.coordinates import ICRS,
        >>> c = SkyCoord(frame="galactic", l="1h12m43.2s", b="+1d12m43s")
        >>> self.connection.goto(c)
        >>> ra = self.connection.status()['ra'].value

        """
        return {'ra':self.ra, 'dec': self.dec, 'alt':0, 'az':0}<commit_msg>Added more documentation.<commit_after>"""

acreroad_1420 Drive software

Software designed to drive the 1420 MHz telescope on the roof of the
Acre Road observatory. This class interacts with "qp", the telescope
drive software by Norman Gray (https://bitbucket.org/nxg/qp) via a
serial (USB) interface.

The serial interfacing is done through pySerial.

Parameters
----------

device : str
   The name of the unix device which the drive is connected to
port : int
   The port number of the drive
simulate : bool
   A boolean flag to set the drive in simulation mode
   (the class does not connect to the controller in simulation mode)

"""

import re, datetime

import astropy
from astropy.coordinates import SkyCoord, ICRS, EarthLocation
import astropy.units as u

class Drive():

    sim = 0
    acre_road = EarthLocation(lat=55.9024278*u.deg, lon=-4.307582*u.deg, height=61*u.m)

    # String formats

    com_format = re.compile("[A-Za-z]{1,2} ?([-+]?[0-9]{0,4}\.[0-9]{0,8} ?){0,6}") # general command string format
    cal_format = re.compile("[0-9]{3} [0-9]{3}") # calibration string format

    def __init__(self, device, port, simulate, calibration=None, location=None):
        """
        Software designed to drive the 1420 MHz telescope on the roof of the
        Acre Road observatory. This class interacts with "qp", the telescope
        drive software by Norman Gray (https://bitbucket.org/nxg/qp) via a
        serial (USB) interface.

        The serial interfacing is done through pySerial.

        Parameters
        ----------

        device : str
           The name of the unix device which the drive is connected to
        port : int
           The port number of the drive
        simulate : bool
           A boolean flag to set the drive in simulation mode
           (the class does not connect to the controller in simulation mode)
        calibration : str
           The calibration figures which have been returned by a previous run of the *calibrate()* method.
           The default is `None` which forces a calibration run to be carried-out.
        location : astropy.coordinates.EarthLocation object
           The Earth location of the telescope. The default is `None`, which sets the location as Acre Road Observatory, Glasgow.

        Examples
        --------

        >>> from acreroad_1420 import drive
        >>> connection = drive.Drive('/dev/tty.usbserial', 9600, simulate=1)

        """
        self.sim = simulate
        self.calibrate(calibration)
        self.setTime()
        self.setLocation(location)
        pass

    def _command(self, string):
        """
        Passes commands to the controller.
        """

        # Check that the command string is a string, and that it
        # matches the format required for a command string
        string = str(string)

        if not self.com_format.match(string):
            raise ValueError(string+" : This string doesn't have the format of a valid controller command.'")

        if self.sim:
            print("In simulation mode, command ignored.")
            return 1

    def calibrate(self, values=None):
        """
        Carries-out a calibration run, returning two numbers which are offsets, or sets the calibration if known values are provided.

        Parameters
        ----------

        values : str
           The calibration values produced by a previous calibration run of the telescope, provided in the format "nnn nnn"

        """
        if values:
            # Check the format of the values string.
            if self.cal_format.match(values):
                return self._command("c "+values)
        if self.sim: return ">c 000 000"
        pass

    def setTime(self):
        """
        Sets the time on the drive controller's clock to the current system time.

        """
        time = datetime.datetime.utcnow()

        command_str = "t {} {} {} {} {} {}".format(time.year, time.month, time.day, time.hour, time.minute, time.second)

        return self._command(command_str)

    def setLocation(self, location=None, dlat=0, dlon=0):
        """
        Sets the location of the telescope.

        Parameters
        ----------
        location : astropy.coordinates.EarthLocation object
        """
        if not location:
            # Assume we're at Acre Road, in Glasgow
            location = self.acre_road

        latitude  = location.latitude
        longitude = location.longitude

        # Construct the command
        command_str = "T {} {} {} {}".format(latitude, longitude, dlat, dlon)
        return self._command(command_str)

    def goto(self, skycoord):
        """
        Moves the telescope to point at a given sky location, and then commands the drive to track the point.

        Parameters
        ----------
        skycoord : astropy.SkyCoord object
           An astropy SkyCoord object which contains the sky location to slew to.
           This can also be a list of locations which the telescope will slew to sequentially.

        """

        if not type(skycoord)==astropy.coordinates.sky_coordinate.SkyCoord:
            raise ValueError("The sky coordinates provided aren't an astropy SkyCoord object!'")

        # We need to make sure that we send RA and DEC values to the
        # controller (it is theoretically possible to do ALTAZ too,
        # but let's start simple, eh?')

        skycoord = skycoord.transform_to(frame=ICRS)
        ra  = skycoord.ra
        dec = skycoord.dec

        # construct a command string
        command_str = "gE {} {}".format(ra, dec)
        # pass the slew-to command to the controller
        if self._command(command_str):
            # We need to do more here than just check the command has
            # passed successfully; we need to check the telescope is
            # (or thinks it is) pointing where we asked.
            if self.sim:
                self.ra  = ra
                self.dec = dec

            # If the command completes then set the controller to track the object
            command_str = "ts"
            return self._command(command_str)
        else:
            raise ControllerError("The telescope has failed to slew to the requested location")

    def home(self):
        """
        Slews the telescope to the home position.

        """
        command_str = "gh"
        return self._command(command_str)

    def status(self):
        """
        Returns a dictionary describing the status of the telescope (e.g. its location).

        Returns
        -------
        dict
           A dictionary containing the right ascension, declination, altitude, and azimuth of the telescope.

        Examples
        --------

        >>> from astropy.coordinates import SkyCoord
        >>> from astropy.coordinates import ICRS,
        >>> c = SkyCoord(frame="galactic", l="1h12m43.2s", b="+1d12m43s")
        >>> self.connection.goto(c)
        >>> ra = self.connection.status()['ra'].value

        """
        return {'ra':self.ra, 'dec': self.dec, 'alt':0, 'az':0}<|endoftext|>