<commit_before># -*- coding: utf-8 -*-
from django.conf import settings
from django.db.models import Count
from django.template import RequestContext
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, Http404
from django.contrib.auth.decorators import login_required
from django.shortcuts import render_to_response, get_object_or_404
from django.contrib.admin.views.decorators import staff_member_required

from djspace.application.forms import *
from djspace.application.models import RocketLaunchTeam, ROCKET_COMPETITIONS
from djspace.registration.models import *
from djspace.core.utils import get_profile_status

from djtools.utils.mail import send_mail
from djtools.utils.convert import str_to_class

import logging
logger = logging.getLogger(__name__)

@login_required
def application_form(request, application_type, aid=None):

    # our user
    user = request.user

    # verify that the user has completed registration
    reg_type = user.profile.registration_type
    try:
        mod = str_to_class(
            "djspace.registration.models", reg_type
        )
        reg = mod.objects.get(user=user)
    except:
        # redirect to dashboard
        return HttpResponseRedirect(reverse('dashboard_home'))

    # verify that the user has an up to date registration
    if not get_profile_status(user):
        # redirect to dashboard
        return HttpResponseRedirect(reverse('dashboard_home'))

    # munge the application type
    slug_list = application_type.split("-")
    app_name = slug_list.pop(0).capitalize()
    for n in slug_list:
        app_name += " %s" % n.capitalize()
    app_type = "".join(app_name.split(" "))

    # check rocket competition teams and member limits.
    # currently, FNL does not have a limit so we can exclude it.
    if "rocket-competition" in application_type:
        teams = RocketLaunchTeam.objects.filter(
            tags__name__contains=app_name[:12]
        )

        '''
        if application_type != "first-nations-rocket-competition":
            teams.annotate(
                count=Count('members')
            ).exclude(
                count__gte=settings.ROCKET_LAUNCH_COMPETITION_TEAM_LIMIT
            ).order_by("name")
        '''
        if not teams:
            return render_to_response(
                "application/form.html",
                {"form": None,"app_name":app_name},
                context_instance=RequestContext(request)
            )

    # email distribution
    if settings.DEBUG:
        TO_LIST = [settings.ADMINS[0][1],]
    else:
        TO_LIST = [settings.WSGC_APPLICATIONS,]

    # fetch object if update
    app = None
    # initialise work plan tasks for industry internship
    tasks = None
    if aid:
        mod = str_to_class(
            "djspace.application.models", app_type
        )

        if user.is_superuser:
            app = get_object_or_404(mod, pk=aid)
        else:
            # prevent users from managing apps that are not theirs
            try:
                app = mod.objects.get(pk=aid, user=user)
            except:
                app = None

    # fetch the form class
    FormClass = str_to_class(
        "djspace.application.forms", (app_type+"Form")
    )
    # fetch the form instance
    try:
        initial = {}
        if app and application_type == "rocket-launch-team":
            initial = {"tags": [t.id for t in app.tags.all()]}
        form = FormClass(instance=app, initial=initial)
    except:
        # app_type does not match an existing form
        raise Http404

    # GET or POST
    if request.method == 'POST':
        try:
            # only rocket launch team form needs request context
            if application_type == "rocket-launch-team":
                form = FormClass(
                    instance=app, data=request.POST, files=request.FILES,
                    request=request
                )
            else:
                form = FormClass(
                    instance=app, data=request.POST, files=request.FILES
                )
        except:
            # app_type does not match an existing form
            raise Http404

        if form.is_valid():
            data = form.save(commit=False)
            data.user = user
            data.updated_by = user
            data.save()
            if application_type == "rocket-launch-team":
                # first remove all tags
                for t in data.tags.all():
                    data.tags.remove(t)
                # then add tags
                for item in form.cleaned_data['tags']:
                    data.tags.add(item)
                # limit number of team members if need be
                if "Midwest High-Powered Rocket Competition" \
                in [t.name for t in form.cleaned_data['tags']]:
                    data.limit = 6
                else:
                    data.limit = 0
                data.save()
            # add user to RocketLaunchTeam member m2m
            if "rocket-competition" in application_type:
                data.team.members.add(data.user)

            # add work plan tasks for industry internship
            if application_type == "industry-internship":
                tid = request.POST.getlist('tid[]')
                title = request.POST.getlist('title[]')
                description = request.POST.getlist('description[]')
                percent = request.POST.getlist('hours_percent[]')
                expected_outcome = request.POST.getlist('expected_outcome[]')

                # remove deleted tasks
                task_list = [unicode(t.id) for t in data.work_plan_tasks.all()]
                dif = set(task_list).difference(tid)
                if len(dif) > 0:
                    for t in list(dif):
                        task = WorkPlanTask.objects.get(pk=int(t))
                        task.delete()
                # add or update tasks
                # len could use any of the above 5 lists from POST
                for i in range (0,len(tid)):
                    try:
                        task = WorkPlanTask.objects.get(pk=tid[i])
                    except:
                        task = WorkPlanTask()
                        task.industry_internship = data
                    task.title = title[i]
                    task.description = description[i]
                    task.hours_percent = percent[i]
                    task.expected_outcome = expected_outcome[i]
                    task.save()

            # if not update add generic many-to-many relationship (gm2m)
            if not aid:
                date = data.date_created
                user.profile.applications.add(data)
            else:
                date = data.date_updated

            # email confirmation
            template = "application/email/{}.html".format(application_type)
            if not settings.DEBUG:
                # send confirmation email to WSGC staff and applicant
                TO_LIST.append(data.user.email)
                if aid:
                    app_name += " (UPDATED)"
                subject = "{} {}: {}, {}".format(
                    app_name, date,
                    data.user.last_name, data.user.first_name
                )
                send_mail(
                    request, TO_LIST,
                    subject, data.user.email,
                    template, data, settings.MANAGERS
                )
                return HttpResponseRedirect(reverse('application_success'))
            else:
                return render_to_response(
                    template,
                    {
                        'data': data,'form':form
                    },
                    context_instance=RequestContext(request)
                )

            return HttpResponseRedirect(reverse('application_success'))
    else:
        # set session values to null for GET requests
        request.session["leader_id"] = ""
        request.session["leader_name"] = ""
    return render_to_response(
        "application/form.html",
        {"form": form,"app_name":app_name,},
        context_instance=RequestContext(request)
    )

@staff_member_required
def application_print(request, application_type, aid):

    # munge the application type
    slug_list = application_type.split("-")
    app_name = slug_list.pop(0).capitalize()
    for n in slug_list:
        app_name += " %s" % n.capitalize()
    app_type = "".join(app_name.split(" "))

    mod = str_to_class(
        "djspace.application.models", app_type
    )
    data = get_object_or_404(mod, pk=aid)

    return render_to_response(
        "application/email/{}.html".format(application_type),
        {'data': data,},
        context_instance=RequestContext(request)
    )
<commit_msg>removed logging; removed comments around team limit sub-query<commit_after># -*- coding: utf-8 -*-
from django.conf import settings
from django.db.models import Count
from django.template import RequestContext
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, Http404
from django.contrib.auth.decorators import login_required
from django.shortcuts import render_to_response, get_object_or_404
from django.contrib.admin.views.decorators import staff_member_required

from djspace.application.forms import *
from djspace.application.models import RocketLaunchTeam, ROCKET_COMPETITIONS
from djspace.registration.models import *
from djspace.core.utils import get_profile_status

from djtools.utils.mail import send_mail
from djtools.utils.convert import str_to_class

@login_required
def application_form(request, application_type, aid=None):

    # our user
    user = request.user

    # verify that the user has completed registration
    reg_type = user.profile.registration_type
    try:
        mod = str_to_class(
            "djspace.registration.models", reg_type
        )
        reg = mod.objects.get(user=user)
    except:
        # redirect to dashboard
        return HttpResponseRedirect(reverse('dashboard_home'))

    # verify that the user has an up to date registration
    if not get_profile_status(user):
        # redirect to dashboard
        return HttpResponseRedirect(reverse('dashboard_home'))

    # munge the application type
    slug_list = application_type.split("-")
    app_name = slug_list.pop(0).capitalize()
    for n in slug_list:
        app_name += " %s" % n.capitalize()
    app_type = "".join(app_name.split(" "))

    # check rocket competition teams and member limits.
    # currently, FNL does not have a limit so we can exclude it.
    if "rocket-competition" in application_type:
        teams = RocketLaunchTeam.objects.filter(
            tags__name__contains=app_name[:12]
        )

        if application_type != "first-nations-rocket-competition":
            teams = teams.annotate(
                count=Count('members')
            ).exclude(
                count__gte=settings.ROCKET_LAUNCH_COMPETITION_TEAM_LIMIT
            ).order_by("name")

        if not teams:
            return render_to_response(
                "application/form.html",
                {"form": None,"app_name":app_name},
                context_instance=RequestContext(request)
            )

    # email distribution
    if settings.DEBUG:
        TO_LIST = [settings.ADMINS[0][1],]
    else:
        TO_LIST = [settings.WSGC_APPLICATIONS,]

    # fetch object if update
    app = None
    # initialise work plan tasks for industry internship
    tasks = None
    if aid:
        mod = str_to_class(
            "djspace.application.models", app_type
        )

        if user.is_superuser:
            app = get_object_or_404(mod, pk=aid)
        else:
            # prevent users from managing apps that are not theirs
            try:
                app = mod.objects.get(pk=aid, user=user)
            except:
                app = None

    # fetch the form class
    FormClass = str_to_class(
        "djspace.application.forms", (app_type+"Form")
    )
    # fetch the form instance
    try:
        initial = {}
        if app and application_type == "rocket-launch-team":
            initial = {"tags": [t.id for t in app.tags.all()]}
        form = FormClass(instance=app, initial=initial)
    except:
        # app_type does not match an existing form
        raise Http404

    # GET or POST
    if request.method == 'POST':
        try:
            # only rocket launch team form needs request context
            if application_type == "rocket-launch-team":
                form = FormClass(
                    instance=app, data=request.POST, files=request.FILES,
                    request=request
                )
            else:
                form = FormClass(
                    instance=app, data=request.POST, files=request.FILES
                )
        except:
            # app_type does not match an existing form
            raise Http404

        if form.is_valid():
            data = form.save(commit=False)
            data.user = user
            data.updated_by = user
            data.save()
            if application_type == "rocket-launch-team":
                # first remove all tags
                for t in data.tags.all():
                    data.tags.remove(t)
                # then add tags
                for item in form.cleaned_data['tags']:
                    data.tags.add(item)
                # limit number of team members if need be
                if "Midwest High-Powered Rocket Competition" \
                in [t.name for t in form.cleaned_data['tags']]:
                    data.limit = 6
                else:
                    data.limit = 0
                data.save()
            # add user to RocketLaunchTeam member m2m
            if "rocket-competition" in application_type:
                data.team.members.add(data.user)

            # add work plan tasks for industry internship
            if application_type == "industry-internship":
                tid = request.POST.getlist('tid[]')
                title = request.POST.getlist('title[]')
                description = request.POST.getlist('description[]')
                percent = request.POST.getlist('hours_percent[]')
                expected_outcome = request.POST.getlist('expected_outcome[]')

                # remove deleted tasks
                task_list = [unicode(t.id) for t in data.work_plan_tasks.all()]
                dif = set(task_list).difference(tid)
                if len(dif) > 0:
                    for t in list(dif):
                        task = WorkPlanTask.objects.get(pk=int(t))
                        task.delete()
                # add or update tasks
                # len could use any of the above 5 lists from POST
                for i in range (0,len(tid)):
                    try:
                        task = WorkPlanTask.objects.get(pk=tid[i])
                    except:
                        task = WorkPlanTask()
                        task.industry_internship = data
                    task.title = title[i]
                    task.description = description[i]
                    task.hours_percent = percent[i]
                    task.expected_outcome = expected_outcome[i]
                    task.save()

            # if not update add generic many-to-many relationship (gm2m)
            if not aid:
                date = data.date_created
                user.profile.applications.add(data)
            else:
                date = data.date_updated

            # email confirmation
            template = "application/email/{}.html".format(application_type)
            if not settings.DEBUG:
                # send confirmation email to WSGC staff and applicant
                TO_LIST.append(data.user.email)
                if aid:
                    app_name += " (UPDATED)"
                subject = "{} {}: {}, {}".format(
                    app_name, date,
                    data.user.last_name, data.user.first_name
                )
                send_mail(
                    request, TO_LIST,
                    subject, data.user.email,
                    template, data, settings.MANAGERS
                )
                return HttpResponseRedirect(reverse('application_success'))
            else:
                return render_to_response(
                    template,
                    {
                        'data': data,'form':form
                    },
                    context_instance=RequestContext(request)
                )

            return HttpResponseRedirect(reverse('application_success'))
    else:
        # set session values to null for GET requests
        request.session["leader_id"] = ""
        request.session["leader_name"] = ""
    return render_to_response(
        "application/form.html",
        {"form": form,"app_name":app_name,},
        context_instance=RequestContext(request)
    )

@staff_member_required
def application_print(request, application_type, aid):

    # munge the application type
    slug_list = application_type.split("-")
    app_name = slug_list.pop(0).capitalize()
    for n in slug_list:
        app_name += " %s" % n.capitalize()
    app_type = "".join(app_name.split(" "))

    mod = str_to_class(
        "djspace.application.models", app_type
    )
    data = get_object_or_404(mod, pk=aid)

    return render_to_response(
        "application/email/{}.html".format(application_type),
        {'data': data,},
        context_instance=RequestContext(request)
    )
<|endoftext|>


<commit_before>import unittest
import mongomock
import ulstats
from dlstats.fetchers._skeleton import (Skeleton, Category, Series, BulkSeries,
                                      Dataset, Provider)
import datetime
from bson import ObjectId

#class CategoriesTestCase(unittest.TestCase):

#if __name__ == '__main__':
#    unittest.main()
<commit_msg>Less annoying imports<commit_after>import unittest
import mongomock
from dlstats.fetchers._skeleton import (Skeleton, Category, Series, BulkSeries,
                                      Dataset, Provider)
import datetime
from bson import ObjectId

#class CategoriesTestCase(unittest.TestCase):

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


<commit_before>import re
import uuid

from stratuslab.pdiskbackend.utils import abort
from stratuslab.pdiskbackend.CommandRunner import CommandRunner
from stratuslab.pdiskbackend.ConfigHolder import ConfigHolder

#################################################################
# Class describing a LUN and implementing the supported actions #
#################################################################

class LUN(object):

    # Some LUN commands (e.g. rebase) needs to return information as a string on stdout
    # that will be captured by pdisk. The return value is built mainly from information
    # capture in command output and returned as optInfo in __executeAction__ method.
    # In addition to these optional informations produced by the command, it is possible
    # to add a value built from LUN class attributes. This value s appended to other
    # optional values, if any.
    # In the following dictionary, the key is an action for which this additional
    # information must be produced. And the value is a string defining the returned
    # value using the same tokens as commands.
    # This information is returned only on successful execution of action.
    # By default, a command returns nothing on stdout.
    additional_opt_info = {'rebase':'%%SNAP_UUID%%',
                          }

    def __init__(self, uuid, size=None, proxy=None, configHolder=ConfigHolder()):
        self.uuid = uuid
        self.size = size
        self.proxy = proxy
        # Another LUN involved in actions like rebase or snapshot
        self.associatedLUN = None
        self.configHolder = configHolder

    def getUuid(self):
        return self.uuid

    def check(self):
        status, _ = self.__executeAction__('check')
        return status

    def create(self):
        status, _ = self.__executeAction__('create')
        return status

    def delete(self):
        status, _ = self.__executeAction__('delete')
        return status

    def getSize(self):
        status, self.size = self.__executeAction__('size')
        if status != 0:
            abort('Failure to retrieve size of LUN %s' % (self.uuid))
        return status

    def getTurl(self):
        status, self.turl = self.__executeAction__('getturl')
        if status != 0:
            abort('Failure to retrieve Transport URL of %s' % (self.uuid))
        return self.turl

    def map(self):
        status, _ = self.__executeAction__('map')
        return status

    def rebase(self):
        if self.proxy.newLunRequired('rebase'):
            # TODO: generate a UUID based on creation timestamp as in PDisk
            new_lun_uuid = str(uuid.uuid4())
            self.getSize()
            self.associatedLUN = LUN(new_lun_uuid, size=self.size, proxy=self.proxy)
            if self.associatedLUN.create() != 0:
                abort('An error occured creating a new LUN for rebasing %s' % (self.uuid))
        else:
            self.associatedLUN = self  # To simplify returned value
        status, rebasedLUN = self.__executeAction__('rebase')
        if status != 0:
            abort('Failure to rebase LUN %s' % (self.uuid))
        # Don't return directly self.associatedLUN but use optional information
        # returned by action execution to allow reformatting if needed.
        return rebasedLUN

    def snapshot(self, snapshot_lun):
        self.associatedLUN = snapshot_lun
        status, _ = self.__executeAction__('snapshot')
        return status

    def unmap(self):
        status, _ = self.__executeAction__('unmap')
        return status

    # Execute an action on a LUN.
    # An action may involve several actual commands : getCmd() method of proxy is a generator returning
    # the commands to execute one by one.
    # In case an error occurs during one command, try to continue...
    # Return the status of the last command executed and an optional additional value returned by the command.
    # Optionally a string is printed on stdout to allow the script to return information to the caller.
    # Special values for commands are:
    #  - None: action is not implemented
    #  - empty list: action does nothing
    def __executeAction__(self, action):
        optInfos = None

        for backendCmd in self._getBackendCmd(action):

            if not backendCmd:
                abort("Action '%s' not implemented by back-end type '%s'" % \
                                                      (action, self._getBackendType()))

            self._detokenizeBackendCmd(backendCmd)

            status, optInfo = self._runCommand(backendCmd)
            if status != 0 and backendCmd.run_on_failure():
                status_, optInfo_ = self._runCommandOnFailure(backendCmd)
                if status_ != 0:
                    if not optInfo_:
                        optInfo_ = ()
                    print "Rollback command", backendCmd.failure_command, "failed:", optInfo_
                break
            # Stop LUN action processing if no on-failure command defined.
            elif not backendCmd.run_on_failure():
                break

            if optInfo:
                if optInfos:
                    optInfos += optInfo
                else:
                    optInfos = optInfo

        # Append an optional additional value built from LUN attributes, if necessary
        if status == 0 and action in self.additional_opt_info:
            if not optInfos:
                optInfos = ()
            optInfos += self._detokenize(self.additional_opt_info[action]),

        if optInfos:
            optInfosStr = self.proxy.formatOptInfos(action, optInfos)
        else:
            optInfosStr = None

        return status, optInfosStr

    def _runCommand(self, backendCmd):
        return self._run_command(backendCmd.action,
                                 backendCmd.command,
                                 backendCmd.success_patterns,
                                 backendCmd.failure_ok_patterns)

    def _runCommandOnFailure(self, backendCmd):
        return self._run_command(backendCmd.action,
                                 backendCmd.failure_command,
                                 backendCmd.success_patterns,
                                 backendCmd.failure_ok_patterns)

    def _run_command(self, action, command, success_patterns, failure_ok_patterns):
        command = CommandRunner(action, command, success_patterns,
                                failure_ok_patterns, configHolder=self.configHolder)
        command.execute()
        return command.checkStatus()

    def _getBackendCmd(self, action):
        return self.proxy.getCmd(action)

    def _getBackendType(self):
        return self.proxy.getType()

    def _detokenizeBackendCmd(self, backendCmd):
        backendCmd.command = self._detokenizeCmd(backendCmd.command)
        backendCmd.failure_command = self._detokenizeCmd(backendCmd.failure_command)

    def _detokenizeCmd(self, action_cmd):
        """LUN related de-tokenization."""
        for i in range(len(action_cmd)):
            action_cmd[i] = self._detokenize(action_cmd[i])
        return action_cmd

    def _detokenize(self, string):
        if re.search('%%SIZE%%', string):
            string = re.sub('%%SIZE%%', self.size, string)
        elif re.search('%%SIZE_MB%%', string):
            string = re.sub('%%SIZE_MB%%', str(int(self.size) * 1024), string)
        elif re.search('%%UUID%%', string):
            string = re.sub('%%UUID%%', self.getUuid(), string)
        elif re.search('%%SNAP_UUID%%', string):
            string = re.sub('%%SNAP_UUID%%', self.associatedLUN.getUuid(), string)
        return string
<commit_msg>don’t try to de-tokenise the command if it’s empty.<commit_after>import re
import uuid

from stratuslab.pdiskbackend.utils import abort
from stratuslab.pdiskbackend.CommandRunner import CommandRunner
from stratuslab.pdiskbackend.ConfigHolder import ConfigHolder

#################################################################
# Class describing a LUN and implementing the supported actions #
#################################################################

class LUN(object):

    # Some LUN commands (e.g. rebase) needs to return information as a string on stdout
    # that will be captured by pdisk. The return value is built mainly from information
    # capture in command output and returned as optInfo in __executeAction__ method.
    # In addition to these optional informations produced by the command, it is possible
    # to add a value built from LUN class attributes. This value s appended to other
    # optional values, if any.
    # In the following dictionary, the key is an action for which this additional
    # information must be produced. And the value is a string defining the returned
    # value using the same tokens as commands.
    # This information is returned only on successful execution of action.
    # By default, a command returns nothing on stdout.
    additional_opt_info = {'rebase':'%%SNAP_UUID%%',
                          }

    def __init__(self, uuid, size=None, proxy=None, configHolder=ConfigHolder()):
        self.uuid = uuid
        self.size = size
        self.proxy = proxy
        # Another LUN involved in actions like rebase or snapshot
        self.associatedLUN = None
        self.configHolder = configHolder

    def getUuid(self):
        return self.uuid

    def check(self):
        status, _ = self.__executeAction__('check')
        return status

    def create(self):
        status, _ = self.__executeAction__('create')
        return status

    def delete(self):
        status, _ = self.__executeAction__('delete')
        return status

    def getSize(self):
        status, self.size = self.__executeAction__('size')
        if status != 0:
            abort('Failure to retrieve size of LUN %s' % (self.uuid))
        return status

    def getTurl(self):
        status, self.turl = self.__executeAction__('getturl')
        if status != 0:
            abort('Failure to retrieve Transport URL of %s' % (self.uuid))
        return self.turl

    def map(self):
        status, _ = self.__executeAction__('map')
        return status

    def rebase(self):
        if self.proxy.newLunRequired('rebase'):
            # TODO: generate a UUID based on creation timestamp as in PDisk
            new_lun_uuid = str(uuid.uuid4())
            self.getSize()
            self.associatedLUN = LUN(new_lun_uuid, size=self.size, proxy=self.proxy)
            if self.associatedLUN.create() != 0:
                abort('An error occured creating a new LUN for rebasing %s' % (self.uuid))
        else:
            self.associatedLUN = self  # To simplify returned value
        status, rebasedLUN = self.__executeAction__('rebase')
        if status != 0:
            abort('Failure to rebase LUN %s' % (self.uuid))
        # Don't return directly self.associatedLUN but use optional information
        # returned by action execution to allow reformatting if needed.
        return rebasedLUN

    def snapshot(self, snapshot_lun):
        self.associatedLUN = snapshot_lun
        status, _ = self.__executeAction__('snapshot')
        return status

    def unmap(self):
        status, _ = self.__executeAction__('unmap')
        return status

    # Execute an action on a LUN.
    # An action may involve several actual commands : getCmd() method of proxy is a generator returning
    # the commands to execute one by one.
    # In case an error occurs during one command, try to continue...
    # Return the status of the last command executed and an optional additional value returned by the command.
    # Optionally a string is printed on stdout to allow the script to return information to the caller.
    # Special values for commands are:
    #  - None: action is not implemented
    #  - empty list: action does nothing
    def __executeAction__(self, action):
        optInfos = None

        for backendCmd in self._getBackendCmd(action):

            if not backendCmd:
                abort("Action '%s' not implemented by back-end type '%s'" % \
                                                      (action, self._getBackendType()))

            self._detokenizeBackendCmd(backendCmd)

            status, optInfo = self._runCommand(backendCmd)
            if status != 0 and backendCmd.run_on_failure():
                status_, optInfo_ = self._runCommandOnFailure(backendCmd)
                if status_ != 0:
                    if not optInfo_:
                        optInfo_ = ()
                    print "Rollback command", backendCmd.failure_command, "failed:", optInfo_
                break
            # Stop LUN action processing if no on-failure command defined.
            elif not backendCmd.run_on_failure():
                break

            if optInfo:
                if optInfos:
                    optInfos += optInfo
                else:
                    optInfos = optInfo

        # Append an optional additional value built from LUN attributes, if necessary
        if status == 0 and action in self.additional_opt_info:
            if not optInfos:
                optInfos = ()
            optInfos += self._detokenize(self.additional_opt_info[action]),

        if optInfos:
            optInfosStr = self.proxy.formatOptInfos(action, optInfos)
        else:
            optInfosStr = None

        return status, optInfosStr

    def _runCommand(self, backendCmd):
        return self._run_command(backendCmd.action,
                                 backendCmd.command,
                                 backendCmd.success_patterns,
                                 backendCmd.failure_ok_patterns)

    def _runCommandOnFailure(self, backendCmd):
        return self._run_command(backendCmd.action,
                                 backendCmd.failure_command,
                                 backendCmd.success_patterns,
                                 backendCmd.failure_ok_patterns)

    def _run_command(self, action, command, success_patterns, failure_ok_patterns):
        command = CommandRunner(action, command, success_patterns,
                                failure_ok_patterns, configHolder=self.configHolder)
        command.execute()
        return command.checkStatus()

    def _getBackendCmd(self, action):
        return self.proxy.getCmd(action)

    def _getBackendType(self):
        return self.proxy.getType()

    def _detokenizeBackendCmd(self, backendCmd):
        backendCmd.command = self._detokenizeCmd(backendCmd.command)
        backendCmd.failure_command = self._detokenizeCmd(backendCmd.failure_command)

    def _detokenizeCmd(self, action_cmd):
        """LUN related de-tokenization."""
        if not action_cmd:
            return action_cmd

        for i in range(len(action_cmd)):
            action_cmd[i] = self._detokenize(action_cmd[i])
        return action_cmd

    def _detokenize(self, string):
        if re.search('%%SIZE%%', string):
            string = re.sub('%%SIZE%%', self.size, string)
        elif re.search('%%SIZE_MB%%', string):
            string = re.sub('%%SIZE_MB%%', str(int(self.size) * 1024), string)
        elif re.search('%%UUID%%', string):
            string = re.sub('%%UUID%%', self.getUuid(), string)
        elif re.search('%%SNAP_UUID%%', string):
            string = re.sub('%%SNAP_UUID%%', self.associatedLUN.getUuid(), string)
        return string
<|endoftext|>


<commit_before>"""Generic tools."""
import binascii
import os
import re
import random
import socket
import string
import urlparse

import dns.resolver
import flask
import requests

from dnstwister import app
from dnstwister import cache
from dnstwister.tools import tld_db
import dnstwister.dnstwist as dnstwist

RESOLVER = dns.resolver.Resolver()
RESOLVER.lifetime = 0.1
RESOLVER.timeout = 0.1

GOOGLEDNS = 'https://dns.google.com/resolve?name={}'
GOOGLEDNS_SUCCESS = 0
GOOGLEDNS_A_RECORD = 1

def fuzzy_domains(domain):
    """Return the fuzzy domains."""
    fuzzer = dnstwist.DomainFuzzer(domain)
    fuzzer.fuzz()
    return list(fuzzer.domains)

def analyse(domain):
    """Analyse a domain."""
    data = {'fuzzy_domains': []}
    results = fuzzy_domains(domain)

    if len(results) == 0:
        return None

    # Add a hex-encoded version of the domain for the later IP resolution. We
    # do this because the same people who may use this app already have
    # blocking on things like www.exampl0e.com in URLs...
    for result in results:
        result['hex'] = binascii.hexlify(result['domain-name'])
    data['fuzzy_domains'] = results

    return (domain, data)

def parse_post_data(post_data):
    """Parse post data to return a domain."""

    # Remove HTTP(s) schemes and trailing slashes.
    domain = re.sub('(^http(s)?://)|(/$)', '', post_data, re.IGNORECASE)

    # Parse through the normal process.
    return parse_domain(domain.strip())

def parse_domain(encoded_domain):
    """Given a hex-encoded string, try to decode and validate it and if it is
    a valid domain, return it.

    Return None on un-decodable or invalid domain.
    """
    try:
        decoded_domain = binascii.unhexlify(encoded_domain)
        if dnstwist.validate_domain(decoded_domain):
            return decoded_domain.lower()
    except:
        pass

def suggest_domain(search_domain):
    """Suggest a domain based on the search fields."""

    search_terms = search_domain.split(' ')

    # Check for a simple common typo first - putting comma instead of period
    # in-between the second- and top-level domains.
    if len(search_terms) == 1:
        candidate = re.sub(r'[,/-]', '.', search_terms[0])
        if dnstwist.validate_domain(candidate):
            return candidate

    # Pick up space-separated domain levels.
    if len(search_terms) == 2 and search_terms[1] in tld_db.TLDS:
        candidate = '.'.join(search_terms)
        if dnstwist.validate_domain(candidate):
            return candidate

    # Attempt to make a domain from the terms.
    joiners = ('', '-') # for now, also trialling ('', '-', '.')
    tlds = ('com',)  # for now
    suggestions = []

    # Filter out a ton of garbage being submitted
    if len(search_terms) > 2:
        return

    # Filter out long words
    search_terms = [term
                    for term
                    in search_terms
                    if len(term) < 30]

    # Filter out silly characters
    search_terms = [re.sub(r'[^a-zA-Z0-9\-]', '', term)
                    for term
                    in search_terms]

    # Join the terms
    for joiner in joiners:
        suggestions.append(joiner.join(search_terms))

    # Add TLDs
    suggested_domains = []
    for tld in tlds:
        suggested_domains.extend(['{}.{}'.format(s.lower(), tld)
                                  for s
                                  in suggestions])

    # Drop out duplicates
    suggested_domains = list(set(suggested_domains))

    # Filter for those that are actually valid domains
    valid_suggestions = filter(
        dnstwist.validate_domain, suggested_domains
    )

    if len(valid_suggestions) == 0:
        return

    return random.choice(valid_suggestions)

def is_valid_ip(ip_string):
    """Matches valid ipv4 IP addresses."""
    try:
        socket.inet_aton(ip_string)
        return True
    except socket.error:
        return False

@cache.memoize(3600)
def resolve(domain):
    """Resolves a domain to an IP.

    Returns and (IP, False) on successful resolution, (False, False) on
    successful failure to resolve and (None, True) on error in attempting to
    resolve.

    Cached to 1 hour.
    """
    if dnstwist.validate_domain(domain) is None:
        return False, True

    # Try for an 'A' record.
    try:
        ip_addr = str(sorted(RESOLVER.query(domain, 'A'))[0].address)

        # Weird edge case that sometimes happens?!?!
        if ip_addr != '127.0.0.1':
            return ip_addr, False
    except:
        pass

    # Try for a simple resolution if the 'A' record request failed
    try:
        ip_addr = socket.gethostbyname(domain)

        # Weird edge case that sometimes happens?!?!
        if ip_addr != '127.0.0.1':
            return ip_addr, False
    except:
        pass

    return google_resolve(domain)

def google_resolve(domain):
    """Google's Public DNS resolver."""
    try:
        response = requests.get(GOOGLEDNS.format(domain)).json()
        if response['Status'] == GOOGLEDNS_SUCCESS:
            if 'Answer' in response.keys():
                answer = response['Answer'][0]
                if answer['type'] == GOOGLEDNS_A_RECORD:
                    ip_addr = answer['data']
                    if is_valid_ip(ip_addr):
                        return ip_addr, False
        return False, False
    except Exception as ex:
        app.logger.error(
            'Failed to resolve IP via Google Public DNS: {}'.format(ex)
        )
        return False, True

def random_id(n_bytes=32):
    """Generate a random id for an email subscription (for instance)."""
    return binascii.hexlify(os.urandom(n_bytes))

def api_url(view, var_pretty_name):
    """Create nice API urls with place holders."""
    view_path = '.{}'.format(view.func_name)
    route_var = view.func_code.co_varnames[:view.func_code.co_argcount][0]
    path = flask.url_for(view_path, **{route_var: ''})
    path += '{' + var_pretty_name + '}'
    return urlparse.urljoin(
        flask.request.url_root,
        path
    )
<commit_msg>Some fundamental tests of encoding and decoding unicode domains to hex<commit_after>"""Generic tools."""
import binascii
import os
import re
import random
import socket
import string
import urlparse

import dns.resolver
import flask
import requests

from dnstwister import app
from dnstwister import cache
from dnstwister.tools import tld_db
import dnstwister.dnstwist as dnstwist

RESOLVER = dns.resolver.Resolver()
RESOLVER.lifetime = 0.1
RESOLVER.timeout = 0.1

GOOGLEDNS = 'https://dns.google.com/resolve?name={}'
GOOGLEDNS_SUCCESS = 0
GOOGLEDNS_A_RECORD = 1

def encode_domain(domain):
    """Given a domain with possible unicode chars, encode it to hex.

    This is done by first Punycoding it.
    """
    try:
        # If already ascii or punycoded
        return binascii.hexlify(domain)
    except UnicodeError:
        domain_pc = domain.encode('punycode')
        return binascii.hexlify(domain_pc)

def decode_domain(encoded_domain):
    """Return a domain from hex."""
    domain_pc = binascii.unhexlify(encoded_domain)
    try:
        return domain_pc.decode('punycode')
    except UnicodeError:
        # Not a punycoded domain
        return domain_pc

def fuzzy_domains(domain):
    """Return the fuzzy domains."""
    fuzzer = dnstwist.DomainFuzzer(domain)
    fuzzer.fuzz()
    return list(fuzzer.domains)

def analyse(domain):
    """Analyse a domain."""
    data = {'fuzzy_domains': []}
    results = fuzzy_domains(domain)

    if len(results) == 0:
        return None

    # Add a hex-encoded version of the domain for the later IP resolution. We
    # do this because the same people who may use this app already have
    # blocking on things like www.exampl0e.com in URLs...
    for result in results:
        result['hex'] = binascii.hexlify(result['domain-name'])
    data['fuzzy_domains'] = results

    return (domain, data)

def parse_post_data(post_data):
    """Parse post data to return a domain."""

    # Remove HTTP(s) schemes and trailing slashes.
    domain = re.sub('(^http(s)?://)|(/$)', '', post_data, re.IGNORECASE)

    # Parse through the normal process.
    return parse_domain(domain.strip())

def parse_domain(encoded_domain):
    """Given a hex-encoded string, try to decode and validate it and if it is
    a valid domain, return it.

    Return None on un-decodable or invalid domain.
    """
    try:
        decoded_domain = binascii.unhexlify(encoded_domain)
        if dnstwist.validate_domain(decoded_domain):
            return decoded_domain.lower()
    except:
        pass

def suggest_domain(search_domain):
    """Suggest a domain based on the search fields."""

    search_terms = search_domain.split(' ')

    # Check for a simple common typo first - putting comma instead of period
    # in-between the second- and top-level domains.
    if len(search_terms) == 1:
        candidate = re.sub(r'[,/-]', '.', search_terms[0])
        if dnstwist.validate_domain(candidate):
            return candidate

    # Pick up space-separated domain levels.
    if len(search_terms) == 2 and search_terms[1] in tld_db.TLDS:
        candidate = '.'.join(search_terms)
        if dnstwist.validate_domain(candidate):
            return candidate

    # Attempt to make a domain from the terms.
    joiners = ('', '-') # for now, also trialling ('', '-', '.')
    tlds = ('com',)  # for now
    suggestions = []

    # Filter out a ton of garbage being submitted
    if len(search_terms) > 2:
        return

    # Filter out long words
    search_terms = [term
                    for term
                    in search_terms
                    if len(term) < 30]

    # Filter out silly characters
    search_terms = [re.sub(r'[^a-zA-Z0-9\-]', '', term)
                    for term
                    in search_terms]

    # Join the terms
    for joiner in joiners:
        suggestions.append(joiner.join(search_terms))

    # Add TLDs
    suggested_domains = []
    for tld in tlds:
        suggested_domains.extend(['{}.{}'.format(s.lower(), tld)
                                  for s
                                  in suggestions])

    # Drop out duplicates
    suggested_domains = list(set(suggested_domains))

    # Filter for those that are actually valid domains
    valid_suggestions = filter(
        dnstwist.validate_domain, suggested_domains
    )

    if len(valid_suggestions) == 0:
        return

    return random.choice(valid_suggestions)

def is_valid_ip(ip_string):
    """Matches valid ipv4 IP addresses."""
    try:
        socket.inet_aton(ip_string)
        return True
    except socket.error:
        return False

@cache.memoize(3600)
def resolve(domain):
    """Resolves a domain to an IP.

    Returns and (IP, False) on successful resolution, (False, False) on
    successful failure to resolve and (None, True) on error in attempting to
    resolve.

    Cached to 1 hour.
    """
    if dnstwist.validate_domain(domain) is None:
        return False, True

    # Try for an 'A' record.
    try:
        ip_addr = str(sorted(RESOLVER.query(domain, 'A'))[0].address)

        # Weird edge case that sometimes happens?!?!
        if ip_addr != '127.0.0.1':
            return ip_addr, False
    except:
        pass

    # Try for a simple resolution if the 'A' record request failed
    try:
        ip_addr = socket.gethostbyname(domain)

        # Weird edge case that sometimes happens?!?!
        if ip_addr != '127.0.0.1':
            return ip_addr, False
    except:
        pass

    return google_resolve(domain)

def google_resolve(domain):
    """Google's Public DNS resolver."""
    try:
        response = requests.get(GOOGLEDNS.format(domain)).json()
        if response['Status'] == GOOGLEDNS_SUCCESS:
            if 'Answer' in response.keys():
                answer = response['Answer'][0]
                if answer['type'] == GOOGLEDNS_A_RECORD:
                    ip_addr = answer['data']
                    if is_valid_ip(ip_addr):
                        return ip_addr, False
        return False, False
    except Exception as ex:
        app.logger.error(
            'Failed to resolve IP via Google Public DNS: {}'.format(ex)
        )
        return False, True

def random_id(n_bytes=32):
    """Generate a random id for an email subscription (for instance)."""
    return binascii.hexlify(os.urandom(n_bytes))

def api_url(view, var_pretty_name):
    """Create nice API urls with place holders."""
    view_path = '.{}'.format(view.func_name)
    route_var = view.func_code.co_varnames[:view.func_code.co_argcount][0]
    path = flask.url_for(view_path, **{route_var: ''})
    path += '{' + var_pretty_name + '}'
    return urlparse.urljoin(
        flask.request.url_root,
        path
    )
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2018 João Pedro Rodrigues
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Extracts the residue sequence in a PDB file to FASTA format. Canonical amino
acids and nucleotides are represented by their one-letter code while all others
are represented by 'X'.

The -multi option splits the different chains into different records in the
FASTA file.

Usage:
    python pdb_toseq.py [-multi] <pdb file>

Example:
    python pdb_toseq.py 1CTF.pdb

This program is part of the `pdb-tools` suite of utilities and should not be
distributed isolatedly. The `pdb-tools` were created to quickly manipulate PDB
files using the terminal, and can be used sequentially, with one tool streaming
data to another. They are based on old FORTRAN77 code that was taking too much
effort to maintain and compile. RIP.
"""

import os
import sys

__author__ = "Joao Rodrigues"
__email__ = "j.p.g.l.m.rodrigues@gmail.com"

def check_input(args):
    """Checks whether to read from stdin/file and validates user input/options.
    """

    # Defaults
    option = None
    fh = sys.stdin  # file handle

    if not len(args):
        # Reading from pipe with default option
        if sys.stdin.isatty():
            sys.stderr.write(__doc__)
            sys.exit(1)

    elif len(args) == 1:
        # One of two options: option & Pipe OR file & default option
        if args[0].startswith('-'):
            option = args[0][1:]
            if sys.stdin.isatty():  # ensure the PDB data is streamed in
                emsg = 'ERROR!! No data to process!\n'
                sys.stderr.write(emsg)
                sys.stderr.write(__doc__)
                sys.exit(1)

        else:
            if not os.path.isfile(args[0]):
                emsg = 'ERROR!! File not found or not readable: \'{}\'\n'
                sys.stderr.write(emsg.format(args[0]))
                sys.stderr.write(__doc__)
                sys.exit(1)

            fh = open(args[0], 'r')

    elif len(args) == 2:
        # Two options: option & File
        if not args[0].startswith('-'):
            emsg = 'ERROR! First argument is not an option: \'{}\'\n'
            sys.stderr.write(emsg.format(args[0]))
            sys.stderr.write(__doc__)
            sys.exit(1)

        if not os.path.isfile(args[1]):
            emsg = 'ERROR!! File not found or not readable: \'{}\'\n'
            sys.stderr.write(emsg.format(args[1]))
            sys.stderr.write(__doc__)
            sys.exit(1)

        option = args[0][1:]
        fh = open(args[1], 'r')

    else:  # Whatever ...
        sys.stderr.write(__doc__)
        sys.exit(1)

    # Validate option
    if option is not None and option != 'multi':
        emsg = 'ERROR!! You provided an invalid option: \'{}\'\n'
        sys.stderr.write(emsg.format(option))
        sys.stderr.write(__doc__)
        sys.exit(1)

    return (option, fh)

def pdb_to_fasta(fhandle, multi):
    """Reads residue names of ATOM/HETATM records and exports them to a FASTA
    file.
    """

    res_codes = [
        # 20 canonical amino acids
        ('CYS', 'C'), ('ASP', 'D'), ('SER', 'S'), ('GLN', 'Q'),
        ('LYS', 'K'), ('ILE', 'I'), ('PRO', 'P'), ('THR', 'T'),
        ('PHE', 'F'), ('ASN', 'N'), ('GLY', 'G'), ('HIS', 'H'),
        ('LEU', 'L'), ('ARG', 'R'), ('TRP', 'W'), ('ALA', 'A'),
        ('VAL', 'V'), ('GLU', 'E'), ('TYR', 'Y'), ('MET', 'M'),
        # Non-canonical amino acids
        # ('MSE', 'M'), ('SOC', 'C'),
        # Canonical xNA
        ('  U', 'U'), ('  A', 'A'), ('  G', 'G'), ('  C', 'C'),
        ('  T', 'T'),
    ]

    three_to_one = dict(res_codes)
    records = ('ATOM', 'HETATM')

    sequence = []  # list of chain sequences
    seen = set()
    prev_chain = None
    for line in fhandle:
        if line.startswith(records):

            chain_id = line[21]
            if chain_id != prev_chain:
                sequence.append([chain_id])
                prev_chain = chain_id

            res_uid = line[17:27]
            if res_uid in seen:
                continue

            seen.add(res_uid)

            aa_resn = three_to_one.get(line[17:20], 'X')
            sequence[-1].append(aa_resn)

    # Yield fasta format
    _olw = 60

    if multi is None:
        # Remove chain labels and merge into one single sequence
        labels = sorted(set([c[0] for c in sequence]))
        sequence = [[r for c in sequence for r in c[1:]]]

        yield '>PDB|' + ''.join(labels) + '\n'

    for chain in sequence:
        if multi is not None:
            label = chain[0]
            yield '>PDB|' + label + '\n'

        seq = ''.join(chain[1:])
        fmt_seq = [seq[i:i + _olw] + '\n' for i in range(0, len(seq), _olw)]
        yield ''.join(fmt_seq)

def main():
    # Check Input
    multi, pdbfh = check_input(sys.argv[1:])

    # Do the job
    fasta = pdb_to_fasta(pdbfh, multi)

    # Output results
    try:
        sys.stdout.write(''.join(fasta))
        sys.stdout.flush()
    except IOError:
        # This is here to catch Broken Pipes
        # for example to use 'head' or 'tail' without
        # the error message showing up
        pass

    # last line of the script
    # Close file handle even if it is sys.stdin, no problem here.
    pdbfh.close()
    sys.exit(0)

if __name__ == '__main__':
    main()
<commit_msg>Fixed bug in pdb_tofasta. First residue is now printed<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2018 João Pedro Rodrigues
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Extracts the residue sequence in a PDB file to FASTA format. Canonical amino
acids and nucleotides are represented by their one-letter code while all others
are represented by 'X'.

The -multi option splits the different chains into different records in the
FASTA file.

Usage:
    python pdb_toseq.py [-multi] <pdb file>

Example:
    python pdb_toseq.py 1CTF.pdb

This program is part of the `pdb-tools` suite of utilities and should not be
distributed isolatedly. The `pdb-tools` were created to quickly manipulate PDB
files using the terminal, and can be used sequentially, with one tool streaming
data to another. They are based on old FORTRAN77 code that was taking too much
effort to maintain and compile. RIP.
"""

import os
import sys

__author__ = "Joao Rodrigues"
__email__ = "j.p.g.l.m.rodrigues@gmail.com"

def check_input(args):
    """Checks whether to read from stdin/file and validates user input/options.
    """

    # Defaults
    option = None
    fh = sys.stdin  # file handle

    if not len(args):
        # Reading from pipe with default option
        if sys.stdin.isatty():
            sys.stderr.write(__doc__)
            sys.exit(1)

    elif len(args) == 1:
        # One of two options: option & Pipe OR file & default option
        if args[0].startswith('-'):
            option = args[0][1:]
            if sys.stdin.isatty():  # ensure the PDB data is streamed in
                emsg = 'ERROR!! No data to process!\n'
                sys.stderr.write(emsg)
                sys.stderr.write(__doc__)
                sys.exit(1)

        else:
            if not os.path.isfile(args[0]):
                emsg = 'ERROR!! File not found or not readable: \'{}\'\n'
                sys.stderr.write(emsg.format(args[0]))
                sys.stderr.write(__doc__)
                sys.exit(1)

            fh = open(args[0], 'r')

    elif len(args) == 2:
        # Two options: option & File
        if not args[0].startswith('-'):
            emsg = 'ERROR! First argument is not an option: \'{}\'\n'
            sys.stderr.write(emsg.format(args[0]))
            sys.stderr.write(__doc__)
            sys.exit(1)

        if not os.path.isfile(args[1]):
            emsg = 'ERROR!! File not found or not readable: \'{}\'\n'
            sys.stderr.write(emsg.format(args[1]))
            sys.stderr.write(__doc__)
            sys.exit(1)

        option = args[0][1:]
        fh = open(args[1], 'r')

    else:  # Whatever ...
        sys.stderr.write(__doc__)
        sys.exit(1)

    # Validate option
    if option is not None and option != 'multi':
        emsg = 'ERROR!! You provided an invalid option: \'{}\'\n'
        sys.stderr.write(emsg.format(option))
        sys.stderr.write(__doc__)
        sys.exit(1)

    return (option, fh)

def pdb_to_fasta(fhandle, multi):
    """Reads residue names of ATOM/HETATM records and exports them to a FASTA
    file.
    """

    res_codes = [
        # 20 canonical amino acids
        ('CYS', 'C'), ('ASP', 'D'), ('SER', 'S'), ('GLN', 'Q'),
        ('LYS', 'K'), ('ILE', 'I'), ('PRO', 'P'), ('THR', 'T'),
        ('PHE', 'F'), ('ASN', 'N'), ('GLY', 'G'), ('HIS', 'H'),
        ('LEU', 'L'), ('ARG', 'R'), ('TRP', 'W'), ('ALA', 'A'),
        ('VAL', 'V'), ('GLU', 'E'), ('TYR', 'Y'), ('MET', 'M'),
        # Non-canonical amino acids
        # ('MSE', 'M'), ('SOC', 'C'),
        # Canonical xNA
        ('  U', 'U'), ('  A', 'A'), ('  G', 'G'), ('  C', 'C'),
        ('  T', 'T'),
    ]

    three_to_one = dict(res_codes)
    records = ('ATOM', 'HETATM')

    sequence = []  # list of chain sequences
    seen = set()
    prev_chain = None
    for line in fhandle:
        if line.startswith(records):

            chain_id = line[21]
            if chain_id != prev_chain:
                sequence.append([chain_id])
                prev_chain = chain_id

            res_uid = line[17:27]
            if res_uid in seen:
                continue

            seen.add(res_uid)

            aa_resn = three_to_one.get(line[17:20], 'X')
            sequence[-1].append(aa_resn)

    # Yield fasta format
    _olw = 60
    if multi is None:
        # Remove chain labels and merge into one single sequence
        labels = sorted(set([c[0] for c in sequence]))
        sequence = [[r for c in sequence for r in c[1:]]]

        yield '>PDB|' + ''.join(labels) + '\n'

    for chain in sequence:
        if multi is not None:
            label = chain[0]
            yield '>PDB|' + label + '\n'
            chain = chain[1:]

        seq = ''.join(chain)
        fmt_seq = [seq[i:i + _olw] + '\n' for i in range(0, len(seq), _olw)]
        yield ''.join(fmt_seq)

def main():
    # Check Input
    multi, pdbfh = check_input(sys.argv[1:])

    # Do the job
    fasta = pdb_to_fasta(pdbfh, multi)

    # Output results
    try:
        sys.stdout.write(''.join(fasta))
        sys.stdout.flush()
    except IOError:
        # This is here to catch Broken Pipes
        # for example to use 'head' or 'tail' without
        # the error message showing up
        pass

    # last line of the script
    # Close file handle even if it is sys.stdin, no problem here.
    pdbfh.close()
    sys.exit(0)

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


<commit_before>"""Defines the URLs for the RESTful source services"""
from django.conf.urls import url

import source.views as views

urlpatterns = [
    url(r'^sources/$', views.SourcesView.as_view(), name='sources_view'),
    url(r'^sources/updates/$', views.SourceUpdatesView.as_view(), name='source_updates_view'),
    url(r'^sources/(?P<source_id>\d+)/$', views.SourceDetailsView.as_view(), name='source_details_view'),
    url(r'^sources/(?P<file_name>[\w.]{0,250})/$', views.SourceDetailsView.as_view(), name='source_details_view'),
    url(r'^sources/(?P<source_id>\d+)/ingests/$', views.SourceIngestsView.as_view(), name='source_ingests_view'),
    url(r'^sources/(?P<source_id>\d+)/jobs/$', views.SourceJobsView.as_view(), name='source_jobs_view'),
    url(r'^sources/(?P<source_id>\d+)/products/$', views.SourceProductsView.as_view(), name='source_products_view'),
]
<commit_msg>:fire:🎄:fire: removed deprecated endpoint<commit_after>"""Defines the URLs for the RESTful source services"""
from django.conf.urls import url

import source.views as views

urlpatterns = [
    url(r'^sources/$', views.SourcesView.as_view(), name='sources_view'),
    url(r'^sources/updates/$', views.SourceUpdatesView.as_view(), name='source_updates_view'),
    url(r'^sources/(?P<source_id>\d+)/$', views.SourceDetailsView.as_view(), name='source_details_view'),
    url(r'^sources/(?P<source_id>\d+)/ingests/$', views.SourceIngestsView.as_view(), name='source_ingests_view'),
    url(r'^sources/(?P<source_id>\d+)/jobs/$', views.SourceJobsView.as_view(), name='source_jobs_view'),
    url(r'^sources/(?P<source_id>\d+)/products/$', views.SourceProductsView.as_view(), name='source_products_view'),
]
<|endoftext|>


<commit_before>import json
from pkg_resources import resource_filename

_registry = {}

def has(name):
    return name in _registry

def get(name):
    if not has(name):
        with open(resource_filename(__name__, name + '-registry.json'), 'r') as fp:
            save(name, json.load(fp))
    return _registry[name]

def save(name, data):
    _registry[name] = data

def build_index(base_name, index_name, key, **predicate):
    def make_key(entry):
        return tuple(entry[k] for k in key) if isinstance(key, tuple) else entry[key]

    def match(entry):
        return all(entry[key] == value for key, value in predicate.items())

    base = get(base_name)
    save(index_name, dict((make_key(entry), entry) for entry in base if match(entry)))

def manipulate(name, func):
    registry = get(name)
    if isinstance(registry, dict):
        for key, value in registry.items():
            registry[key] = func(key, value)
    elif isinstance(registry, list):
        registry = [func(item) for item in registry]
    save(name, registry)
<commit_msg>Allow index to be accumulate values with same key<commit_after>import json
from collections import defaultdict
from pkg_resources import resource_filename

_registry = {}

def has(name):
    return name in _registry

def get(name):
    if not has(name):
        with open(resource_filename(__name__, name + '-registry.json'), 'r') as fp:
            save(name, json.load(fp))
    return _registry[name]

def save(name, data):
    _registry[name] = data

def build_index(base_name, index_name, key, accumulate=False, **predicate):
    def make_key(entry):
        return tuple(entry[k] for k in key) if isinstance(key, tuple) else entry[key]

    def match(entry):
        return all(entry[key] == value for key, value in predicate.items())

    base = get(base_name)
    if accumulate:
        data = defaultdict(list)
        for entry in base:
            if not match(entry):
                continue
            data[make_key(entry)].append(entry)
    else:
        data = dict((make_key(entry), entry) for entry in base if match(entry))
    save(index_name, data)

def manipulate(name, func):
    registry = get(name)
    if isinstance(registry, dict):
        for key, value in registry.items():
            registry[key] = func(key, value)
    elif isinstance(registry, list):
        registry = [func(item) for item in registry]
    save(name, registry)
<|endoftext|>


<commit_before>import numpy as np
from numpy import eye
from numpy.linalg import LinAlgError
import fblas

from scipy.sparse.base import isspmatrix
from scipy.sparse.construct import eye as speye

__all__ = ['LinAlgError', 'norm']

_nrm2_prefix = {'f' : 's', 'F': 'sc', 'D': 'dz'}

def norm(a, ord=None):
    # Differs from numpy only in non-finite handling and the use of
    # blas
    a = np.asarray_chkfinite(a)
    if ord in (None, 2) and (a.ndim == 1) and (a.dtype.char in 'fdFD'):
        # use blas for fast and stable euclidean norm
        func_name = _nrm2_prefix.get(a.dtype.char, 'd') + 'nrm2'
        nrm2 = getattr(fblas, func_name)
        return nrm2(a)
    return np.linalg.norm(a, ord=ord)

norm.__doc__ = np.linalg.norm.__doc__

def _datacopied(arr, original):
    """
    Strict check for `arr` not sharing any data with `original`,
    under the assumption that arr = asarray(original)

    """
    if arr is original:
        return False
    if not isinstance(original, np.ndarray) and hasattr(original, '__array__'):
        return False
    return arr.base is None
<commit_msg>cleanup: remove unused imports<commit_after>import numpy as np
from numpy.linalg import LinAlgError
import fblas

__all__ = ['LinAlgError', 'norm']

_nrm2_prefix = {'f' : 's', 'F': 'sc', 'D': 'dz'}

def norm(a, ord=None):
    # Differs from numpy only in non-finite handling and the use of
    # blas
    a = np.asarray_chkfinite(a)
    if ord in (None, 2) and (a.ndim == 1) and (a.dtype.char in 'fdFD'):
        # use blas for fast and stable euclidean norm
        func_name = _nrm2_prefix.get(a.dtype.char, 'd') + 'nrm2'
        nrm2 = getattr(fblas, func_name)
        return nrm2(a)
    return np.linalg.norm(a, ord=ord)

norm.__doc__ = np.linalg.norm.__doc__

def _datacopied(arr, original):
    """
    Strict check for `arr` not sharing any data with `original`,
    under the assumption that arr = asarray(original)

    """
    if arr is original:
        return False
    if not isinstance(original, np.ndarray) and hasattr(original, '__array__'):
        return False
    return arr.base is None
<|endoftext|>


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

from table.columns import Column, LinkColumn, Link
from table.utils import A
from table import Table
from models import Person

class PersonTable(Table):
    id = Column(field='id', header=u'序号', header_attrs={'width': '50%'})
    name = Column(field='name', header=u'姓名', header_attrs={'width': '50%'})

    class Meta:
        model = Person
        ext_button_link = "http://www.baidu.com"

class LinkColumnTable(Table):
    id = Column(field='id', header=u'序号', header_attrs={'width': '33%'})
    name = Column(field='name', header=u'姓名', header_attrs={'width': '33%'})
    action = LinkColumn(header=u'操作', header_attrs={'width': '33%'}, links=[
        Link(text=u'编辑', viewname='app.views.edit', args=('id',), confirm=u"确定吗？")])

    class Meta:
        model = Person

<commit_msg>remove invalid option in example<commit_after>#!/usr/bin/env python
# coding: utf-8

from table.columns import Column, LinkColumn, Link
from table.utils import A
from table import Table
from models import Person

class PersonTable(Table):
    id = Column(field='id', header=u'序号', header_attrs={'width': '50%'})
    name = Column(field='name', header=u'姓名', header_attrs={'width': '50%'})

    class Meta:
        model = Person
        ext_button_link = "http://www.baidu.com"

class LinkColumnTable(Table):
    id = Column(field='id', header=u'序号', header_attrs={'width': '33%'})
    name = Column(field='name', header=u'姓名', header_attrs={'width': '33%'})
    action = LinkColumn(header=u'操作', header_attrs={'width': '33%'},
        links=[Link(text=u'编辑', viewname='app.views.edit', args=('id',))])

    class Meta:
        model = Person

<|endoftext|>


<commit_before>import os
import sys
import time
import shutil
import logging
import datetime
import tempfile
import subprocess

from django.conf import settings
from django.core.management.base import NoArgsCommand

from live_studio.build.models import Build
from live_studio.templatetags.text import command_line_options

def call(logfile, args):
    logfile.write('$ %s\n' % command_line_options(args))
    logfile.flush()
    subprocess.check_call(args, stdout=logfile, stderr=logfile)

class Command(NoArgsCommand):
    def handle_noargs(self, **options):
        logging.basicConfig(level=logging.INFO)
        self.log = logging.getLogger('live-studio-runner')

        if int(options['verbosity']) > 1:
            self.log.setLevel(logging.DEBUG)

        while True:
            try:
                build = Build.objects.pop()

                def update(**kwargs):
                    self.log.debug('Updating #%d with %r', build.pk, kwargs)
                    Build.objects.filter(pk=build.pk).update(**kwargs)

                update(started=datetime.datetime.utcnow())

                tempdir = tempfile.mkdtemp(prefix='live-studio_')
                target_dir = os.path.join(settings.BUILDS_ROOT, build.ident)

                os.makedirs(target_dir)
                logfile = open(os.path.join(target_dir, 'log.txt'), 'a')

                self.log.info("Building #%d in %s", build.pk, tempdir)

                try:
                    os.chdir(tempdir)

                    call(logfile, ('lh', 'config') + build.config.options())
                    open('binary.iso', 'w').write('iso here') #call(logfile, ('lh', 'build'))

                    # Find file that was created
                    filename = None
                    for extension in ('iso', 'img'):
                        if not os.path.exists('binary.%s' % extension):
                            continue

                        filename = '%s.%s' % (build.ident, extension)
                        os.rename(
                            'binary.%s' % extension,
                            os.path.join(target_dir, filename),
                        )

                        break

                    assert filename, "Did not create any image"

                    update(
                        finished=datetime.datetime.utcnow(),
                        filename=filename,
                    )

                    self.log.info("#%d built successfully", build.pk)
                except:
                    update(finished=datetime.datetime.utcnow())
                    self.log.exception("#%d failed", build.pk)
                    continue
                finally:
                    os.chdir(tempdir)
                    call(logfile, ('lh', 'clean', '--purge'))
                    shutil.rmtree(tempdir)

                    self.log.info("Finished processing #%d", build.pk)

            except IndexError:
                self.log.debug('No items in queue, sleeping for 2s')
                try:
                    time.sleep(2)
                except KeyboardInterrupt:
                    sys.exit(1)
<commit_msg>Add support for daemonising queue_runner<commit_after>from __future__ import with_statement

import os
import sys
import time
import daemon
import shutil
import logging
import datetime
import tempfile
import lockfile
import subprocess

from django.conf import settings
from django.core.management.base import NoArgsCommand, make_option

from live_studio.build.models import Build
from live_studio.templatetags.text import command_line_options

def call(logfile, args):
    logfile.write('$ %s\n' % command_line_options(args))
    logfile.flush()
    subprocess.check_call(args, stdout=logfile, stderr=logfile)

class Command(NoArgsCommand):
    option_list = NoArgsCommand.option_list + (
        make_option('--pidfile', dest='pidfile', help="Pidfile", default=None),
    )

    def handle_noargs(self, **options):
        if not options['pidfile']:
            self.run(options)
            return

        pidfile = lockfile.FileLock(options['pidfile'])

        with daemon.DaemonContext(pidfile=pidfile):
            self.run(options)

    def run(self, options):
        logging.basicConfig(level=logging.INFO)
        self.log = logging.getLogger('live-studio-runner')

        if int(options['verbosity']) > 1:
            self.log.setLevel(logging.DEBUG)

        while True:
            try:
                build = Build.objects.pop()

                def update(**kwargs):
                    self.log.debug('Updating #%d with %r', build.pk, kwargs)
                    Build.objects.filter(pk=build.pk).update(**kwargs)

                update(started=datetime.datetime.utcnow())

                tempdir = tempfile.mkdtemp(prefix='live-studio_')
                target_dir = os.path.join(settings.BUILDS_ROOT, build.ident)

                os.makedirs(target_dir)
                logfile = open(os.path.join(target_dir, 'log.txt'), 'a')

                self.log.info("Building #%d in %s", build.pk, tempdir)

                try:
                    os.chdir(tempdir)

                    call(logfile, ('lh', 'config') + build.config.options())
                    open('binary.iso', 'w').write('iso here') #call(logfile, ('lh', 'build'))

                    # Find file that was created
                    filename = None
                    for extension in ('iso', 'img'):
                        if not os.path.exists('binary.%s' % extension):
                            continue

                        filename = '%s.%s' % (build.ident, extension)
                        os.rename(
                            'binary.%s' % extension,
                            os.path.join(target_dir, filename),
                        )

                        break

                    assert filename, "Did not create any image"

                    update(
                        finished=datetime.datetime.utcnow(),
                        filename=filename,
                    )

                    self.log.info("#%d built successfully", build.pk)
                except:
                    update(finished=datetime.datetime.utcnow())
                    self.log.exception("#%d failed", build.pk)
                    continue
                finally:
                    os.chdir(tempdir)
                    call(logfile, ('lh', 'clean', '--purge'))
                    shutil.rmtree(tempdir)

                    self.log.info("Finished processing #%d", build.pk)

            except IndexError:
                self.log.debug('No items in queue, sleeping for 2s')
                try:
                    time.sleep(2)
                except KeyboardInterrupt:
                    sys.exit(1)
<|endoftext|>


<commit_before>import datetime

from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _

# Inventory Models

@python_2_unicode_compatible
class Category(models.Model):
    ''' Registration product categories, used as logical groupings for Products
    in registration forms.

    Attributes:
        name (str): The display name for the category.

        description (str): Some explanatory text for the category. This is
            displayed alongside the forms where your attendees choose their
            items.

        required (bool): Requires a user to select an item from this category
            during initial registration. You can use this, e.g., for making
            sure that the user has a ticket before they select whether they
            want a t-shirt.

        render_type (int): This is used to determine what sort of form the
            attendee will be presented with when choosing Products from this
            category. These may be either of the following:

            ``RENDER_TYPE_RADIO`` presents the Products in the Category as a
            list of radio buttons. At most one item can be chosen at a time.
            This works well when setting limit_per_user to 1.

            ``RENDER_TYPE_QUANTITY`` shows each Product next to an input field,
            where the user can specify a quantity of each Product type. This is
            useful for additional extras, like Dinner Tickets.

            ``RENDER_TYPE_ITEM_QUANTITY`` shows a select menu to select a
            Product type, and an input field, where the user can specify the
            quantity for that Product type. This is useful for categories that
            have a lot of options, from which the user is not going to select
            all of the options.

        limit_per_user (Optional[int]): This restricts the number of items
            from this Category that each attendee may claim. This extends
            across multiple Invoices.

        order (int): An ascending order for displaying the Categories
            available. By convention, your Category for ticket types should
            have the lowest display order.
    '''

    class Meta:
        app_label = "registrasion"
        verbose_name = _("inventory - category")
        verbose_name_plural = _("inventory - categories")
        ordering = ("order", )

    def __str__(self):
        return self.name

    RENDER_TYPE_RADIO = 1
    RENDER_TYPE_QUANTITY = 2
    RENDER_TYPE_ITEM_QUANTITY = 3

    CATEGORY_RENDER_TYPES = [
        (RENDER_TYPE_RADIO, _("Radio button")),
        (RENDER_TYPE_QUANTITY, _("Quantity boxes")),
        (RENDER_TYPE_ITEM_QUANTITY, _("Product selector and quantity box")),
    ]

    name = models.CharField(
        max_length=255,
        verbose_name=_("Name"),
    )
    description = models.TextField(
        verbose_name=_("Description"),
    )
    limit_per_user = models.PositiveIntegerField(
        null=True,
        blank=True,
        verbose_name=_("Limit per user"),
        help_text=_("The total number of items from this category one "
                    "attendee may purchase."),
    )
    required = models.BooleanField(
        blank=True,
        help_text=_("If enabled, a user must select an "
                    "item from this category."),
    )
    order = models.PositiveIntegerField(
        verbose_name=("Display order"),
        db_index=True,
    )
    render_type = models.IntegerField(
        choices=CATEGORY_RENDER_TYPES,
        verbose_name=_("Render type"),
        help_text=_("The registration form will render this category in this "
                    "style."),
    )

@python_2_unicode_compatible
class Product(models.Model):
    ''' Products make up the conference inventory.

    Attributes:
        name (str): The display name for the product.

        description (str): Some descriptive text that will help the user to
            understand the product when they're at the registration form.

        category (Category): The Category that this product will be grouped
            under.

        price (Decimal): The price that 1 unit of this product will sell for.
            Note that this should be the full price, before any discounts are
            applied.

        limit_per_user (Optional[int]): This restricts the number of this
            Product that each attendee may claim. This extends across multiple
            Invoices.

        reservation_duration (datetime): When a Product is added to the user's
            tentative registration, it is marked as unavailable for a period of
            time. This allows the user to build up their registration and then
            pay for it. This reservation duration determines how long an item
            should be allowed to be reserved whilst being unpaid.

        order (int): An ascending order for displaying the Products
            within each Category.

    '''

    class Meta:
        app_label = "registrasion"
        verbose_name = _("inventory - product")
        ordering = ("category__order", "order")

    def __str__(self):
        return "%s - %s" % (self.category.name, self.name)

    name = models.CharField(
        max_length=255,
        verbose_name=_("Name"),
    )
    description = models.TextField(
        verbose_name=_("Description"),
        null=True,
        blank=True,
    )
    category = models.ForeignKey(
        Category,
        verbose_name=_("Product category")
    )
    price = models.DecimalField(
        max_digits=8,
        decimal_places=2,
        verbose_name=_("Price"),
    )
    limit_per_user = models.PositiveIntegerField(
        null=True,
        blank=True,
        verbose_name=_("Limit per user"),
    )
    reservation_duration = models.DurationField(
        default=datetime.timedelta(hours=1),
        verbose_name=_("Reservation duration"),
        help_text=_("The length of time this product will be reserved before "
                    "it is released for someone else to purchase."),
    )
    order = models.PositiveIntegerField(
        verbose_name=("Display order"),
        db_index=True,
    )

@python_2_unicode_compatible
class Voucher(models.Model):
    ''' Vouchers are used to enable Discounts or Flags for the people who hold
    the voucher code.

    Attributes:
        recipient (str): A display string used to identify the holder of the
            voucher on the admin page.

        code (str): The string that is used to prove that the attendee holds
            this voucher.

        limit (int): The number of attendees who are permitted to hold this
            voucher.

     '''

    class Meta:
        app_label = "registrasion"

    # Vouchers reserve a cart for a fixed amount of time, so that
    # items may be added without the voucher being swiped by someone else
    RESERVATION_DURATION = datetime.timedelta(hours=1)

    def __str__(self):
        return "Voucher for %s" % self.recipient

    @classmethod
    def normalise_code(cls, code):
        return code.upper()

    def save(self, *a, **k):
        ''' Normalise the voucher code to be uppercase '''
        self.code = self.normalise_code(self.code)
        super(Voucher, self).save(*a, **k)

    recipient = models.CharField(max_length=64, verbose_name=_("Recipient"))
    code = models.CharField(max_length=16,
                            unique=True,
                            verbose_name=_("Voucher code"))
    limit = models.PositiveIntegerField(verbose_name=_("Voucher use limit"))
<commit_msg>checkbox skeleton.<commit_after>import datetime

from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _

# Inventory Models

@python_2_unicode_compatible
class Category(models.Model):
    ''' Registration product categories, used as logical groupings for Products
    in registration forms.

    Attributes:
        name (str): The display name for the category.

        description (str): Some explanatory text for the category. This is
            displayed alongside the forms where your attendees choose their
            items.

        required (bool): Requires a user to select an item from this category
            during initial registration. You can use this, e.g., for making
            sure that the user has a ticket before they select whether they
            want a t-shirt.

        render_type (int): This is used to determine what sort of form the
            attendee will be presented with when choosing Products from this
            category. These may be either of the following:

            ``RENDER_TYPE_RADIO`` presents the Products in the Category as a
            list of radio buttons. At most one item can be chosen at a time.
            This works well when setting limit_per_user to 1.

            ``RENDER_TYPE_QUANTITY`` shows each Product next to an input field,
            where the user can specify a quantity of each Product type. This is
            useful for additional extras, like Dinner Tickets.

            ``RENDER_TYPE_ITEM_QUANTITY`` shows a select menu to select a
            Product type, and an input field, where the user can specify the
            quantity for that Product type. This is useful for categories that
            have a lot of options, from which the user is not going to select
            all of the options.

            ``RENDER_TYPE_CHECKBOX`` shows a checkbox beside each product.

        limit_per_user (Optional[int]): This restricts the number of items
            from this Category that each attendee may claim. This extends
            across multiple Invoices.

        order (int): An ascending order for displaying the Categories
            available. By convention, your Category for ticket types should
            have the lowest display order.
    '''

    class Meta:
        app_label = "registrasion"
        verbose_name = _("inventory - category")
        verbose_name_plural = _("inventory - categories")
        ordering = ("order", )

    def __str__(self):
        return self.name

    RENDER_TYPE_RADIO = 1
    RENDER_TYPE_QUANTITY = 2
    RENDER_TYPE_ITEM_QUANTITY = 3
    RENDER_TYPE_CHECKBOX = 4

    CATEGORY_RENDER_TYPES = [
        (RENDER_TYPE_RADIO, _("Radio button")),
        (RENDER_TYPE_QUANTITY, _("Quantity boxes")),
        (RENDER_TYPE_ITEM_QUANTITY, _("Product selector and quantity box")),
        (RENDER_TYPE_CHECKBOX, _("Checkbox button")),
    ]

    name = models.CharField(
        max_length=255,
        verbose_name=_("Name"),
    )
    description = models.TextField(
        verbose_name=_("Description"),
    )
    limit_per_user = models.PositiveIntegerField(
        null=True,
        blank=True,
        verbose_name=_("Limit per user"),
        help_text=_("The total number of items from this category one "
                    "attendee may purchase."),
    )
    required = models.BooleanField(
        blank=True,
        help_text=_("If enabled, a user must select an "
                    "item from this category."),
    )
    order = models.PositiveIntegerField(
        verbose_name=("Display order"),
        db_index=True,
    )
    render_type = models.IntegerField(
        choices=CATEGORY_RENDER_TYPES,
        verbose_name=_("Render type"),
        help_text=_("The registration form will render this category in this "
                    "style."),
    )

@python_2_unicode_compatible
class Product(models.Model):
    ''' Products make up the conference inventory.

    Attributes:
        name (str): The display name for the product.

        description (str): Some descriptive text that will help the user to
            understand the product when they're at the registration form.

        category (Category): The Category that this product will be grouped
            under.

        price (Decimal): The price that 1 unit of this product will sell for.
            Note that this should be the full price, before any discounts are
            applied.

        limit_per_user (Optional[int]): This restricts the number of this
            Product that each attendee may claim. This extends across multiple
            Invoices.

        reservation_duration (datetime): When a Product is added to the user's
            tentative registration, it is marked as unavailable for a period of
            time. This allows the user to build up their registration and then
            pay for it. This reservation duration determines how long an item
            should be allowed to be reserved whilst being unpaid.

        order (int): An ascending order for displaying the Products
            within each Category.

    '''

    class Meta:
        app_label = "registrasion"
        verbose_name = _("inventory - product")
        ordering = ("category__order", "order")

    def __str__(self):
        return "%s - %s" % (self.category.name, self.name)

    name = models.CharField(
        max_length=255,
        verbose_name=_("Name"),
    )
    description = models.TextField(
        verbose_name=_("Description"),
        null=True,
        blank=True,
    )
    category = models.ForeignKey(
        Category,
        verbose_name=_("Product category")
    )
    price = models.DecimalField(
        max_digits=8,
        decimal_places=2,
        verbose_name=_("Price"),
    )
    limit_per_user = models.PositiveIntegerField(
        null=True,
        blank=True,
        verbose_name=_("Limit per user"),
    )
    reservation_duration = models.DurationField(
        default=datetime.timedelta(hours=1),
        verbose_name=_("Reservation duration"),
        help_text=_("The length of time this product will be reserved before "
                    "it is released for someone else to purchase."),
    )
    order = models.PositiveIntegerField(
        verbose_name=("Display order"),
        db_index=True,
    )

@python_2_unicode_compatible
class Voucher(models.Model):
    ''' Vouchers are used to enable Discounts or Flags for the people who hold
    the voucher code.

    Attributes:
        recipient (str): A display string used to identify the holder of the
            voucher on the admin page.

        code (str): The string that is used to prove that the attendee holds
            this voucher.

        limit (int): The number of attendees who are permitted to hold this
            voucher.

     '''

    class Meta:
        app_label = "registrasion"

    # Vouchers reserve a cart for a fixed amount of time, so that
    # items may be added without the voucher being swiped by someone else
    RESERVATION_DURATION = datetime.timedelta(hours=1)

    def __str__(self):
        return "Voucher for %s" % self.recipient

    @classmethod
    def normalise_code(cls, code):
        return code.upper()

    def save(self, *a, **k):
        ''' Normalise the voucher code to be uppercase '''
        self.code = self.normalise_code(self.code)
        super(Voucher, self).save(*a, **k)

    recipient = models.CharField(max_length=64, verbose_name=_("Recipient"))
    code = models.CharField(max_length=16,
                            unique=True,
                            verbose_name=_("Voucher code"))
    limit = models.PositiveIntegerField(verbose_name=_("Voucher use limit"))
<|endoftext|>


<commit_before>import configparser
import json
import bs4

CONFIG_PATH = 'config/scraper.ini'

def get_configuration(config_path=CONFIG_PATH):
    config = configparser.ConfigParser()
    config.read(config_path)
    return {
        'index_file': config.get('Dump Files', 'TopicIndex'),
        'content_file': config.get('Dump Files', 'TopicContents')
    }

def dump_to_json_file(filename, content):
    with open(filename, 'w+') as file_handle:
        file_handle.write(json.dumps(content, indent=2))

def convert_to_soup(html):
    return bs4.BeautifulSoup(html, 'html.parser')

def fetch_as_soup(url):
    print('fetching ' + url)
    response = requests.get(url)
    return convert_to_soup(response.text)
<commit_msg>Added missing import<commit_after>import configparser
import json
import bs4
import requests

CONFIG_PATH = 'config/scraper.ini'

def get_configuration(config_path=CONFIG_PATH):
    config = configparser.ConfigParser()
    config.read(config_path)
    return {
        'index_file': config.get('Dump Files', 'TopicIndex'),
        'content_file': config.get('Dump Files', 'TopicContents')
    }

def dump_to_json_file(filename, content):
    with open(filename, 'w+') as file_handle:
        file_handle.write(json.dumps(content, indent=2))

def convert_to_soup(html):
    return bs4.BeautifulSoup(html, 'html.parser')

def fetch_as_soup(url):
    print('fetching ' + url)
    response = requests.get(url)
    return convert_to_soup(response.text)
<|endoftext|>


<commit_before>import os
import unittest
from base_test import BaseTest
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.select import Select

class DiffTest(BaseTest, unittest.TestCase):

    def job_name(self):
        return 'Diff test'

    def get_drawer_button(self):
        return self.driver.find_element_by_xpath('//*[@id="timeline-link"]')

    def test_diffs(self):
        self.driver.get('http://localhost:8000/1005-2/2011-11111')
        WebDriverWait(self.driver, 30).until(
            lambda driver: driver.find_element_by_css_selector('html.js'))

        WebDriverWait(self.driver, 50)
        drawer_button = self.get_drawer_button()
        drawer_button.click()

        WebDriverWait(self.driver, 60).until(
            lambda driver: driver.find_element_by_css_selector('#timeline:not(.hidden)'))

        # drawer button should be active
        self.assertTrue('current' in drawer_button.get_attribute('class'))

        diff_field = Select(self.driver.find_element_by_xpath('//*[@id="timeline"]/div[2]/ul/li[1]/div/div/div/form/select'))
        # select version to compare to
        diff_field.select_by_value('2012-12121')

        # wait until diff view has loaded w/ JS
        WebDriverWait(self.driver, 30).until(
             lambda driver: driver.find_element_by_css_selector('html.js'))

        WebDriverWait(self.driver, 60)
        # make sure the url is right
        self.assertTrue(self.driver.current_url == 'http://localhost:8000/diff/1005-2/2012-12121/2011-11111?from_version=2011-11111')

        # open diff pane in drawer, make sure its active
        active_drawer_button = self.get_drawer_button()
        active_drawer_button.click()
        WebDriverWait(self.driver, 30).until(
            lambda driver: 'current' in active_drawer_button.get_attribute('class'))

        # navigate to 1005.3
        self.driver.find_element_by_id('menu-link').click()
        WebDriverWait(self.driver, 10).until(
            lambda driver: 'current' in driver.find_element_by_id('table-of-contents').get_attribute('class'))
        toc_link_1005_3 = self.driver.find_element_by_xpath('//*[@id="toc"]/ol/li[3]')
        # drawer should have green bar
        self.assertTrue('modified' in toc_link_1005_3.get_attribute('class'))
        toc_link_1005_3.click()

        # wait until 1005.3 diff loads
        WebDriverWait(self.driver, 30).until(
            lambda driver: driver.current_url == 'http://localhost:8000/diff/1005-3/2012-12121/2011-11111?from_version=2011-11111')

        # make sure new section is greened
        new_section = self.driver.find_element_by_xpath('//*[@id="1005-3-b-1-vi"]')
        self.assertTrue(new_section.find_element_by_tag_name('ins'))

        # make sure changed paragraph has insertions and deletions
        changed_section = self.driver.find_element_by_xpath('//*[@id="1005-3-b-2-ii"]')
        self.assertTrue(len(changed_section.find_elements_by_tag_name('ins')) == 2)
        self.assertTrue(len(changed_section.find_elements_by_tag_name('del')))

        # go back into diff pane in drawer, stop comparing
        self.get_drawer_button().click()
        stop_button = self.driver.find_element_by_xpath('//*[@id="timeline"]/div[2]/ul/li[2]/div/a')
        stop_button.click()

        # make sure it goes back to the right place
        WebDriverWait(self.driver, 30).until(
            lambda driver: driver.current_url == 'http://localhost:8000/1005-3/2011-11111')

if __name__ == '__main__':
    unittest.main()
<commit_msg>comments<commit_after>import os
import unittest
from base_test import BaseTest
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.select import Select

class DiffTest(BaseTest, unittest.TestCase):

    def job_name(self):
        return 'Diff test'

    def get_drawer_button(self):
        return self.driver.find_element_by_xpath('//*[@id="timeline-link"]')

    def test_diffs(self):
        self.driver.get('http://localhost:8000/1005-2/2011-11111')
        WebDriverWait(self.driver, 30).until(
            lambda driver: driver.find_element_by_css_selector('html.js'))

        WebDriverWait(self.driver, 50)
        drawer_button = self.get_drawer_button()
        drawer_button.click()

        WebDriverWait(self.driver, 60).until(
            lambda driver: driver.find_element_by_css_selector('#timeline:not(.hidden)'))

        # drawer button should be active
        self.assertTrue('current' in drawer_button.get_attribute('class'))

        diff_field = Select(self.driver.find_element_by_xpath('//*[@id="timeline"]/div[2]/ul/li[1]/div/div/div/form/select'))
        # select version to compare to
        diff_field.select_by_value('2012-12121')

        # wait until diff view has loaded w/ JS
        WebDriverWait(self.driver, 30).until(
             lambda driver: driver.find_element_by_css_selector('html.js'))

        WebDriverWait(self.driver, 60)
        # make sure the url is right
        self.assertTrue(self.driver.current_url == 'http://localhost:8000/diff/1005-2/2012-12121/2011-11111?from_version=2011-11111')

        # open diff pane in drawer
        active_drawer_button = self.get_drawer_button()
        active_drawer_button.click()
        WebDriverWait(self.driver, 30).until(
            lambda driver: 'current' in active_drawer_button.get_attribute('class'))

        # navigate to 1005.3
        self.driver.find_element_by_id('menu-link').click()
        WebDriverWait(self.driver, 10).until(
            lambda driver: 'current' in driver.find_element_by_id('table-of-contents').get_attribute('class'))
        toc_link_1005_3 = self.driver.find_element_by_xpath('//*[@id="toc"]/ol/li[3]')
        # drawer should have green bar
        self.assertTrue('modified' in toc_link_1005_3.get_attribute('class'))
        toc_link_1005_3.click()

        # wait until 1005.3 diff loads
        WebDriverWait(self.driver, 30).until(
            lambda driver: driver.current_url == 'http://localhost:8000/diff/1005-3/2012-12121/2011-11111?from_version=2011-11111')

        # make sure new section is greened
        new_section = self.driver.find_element_by_xpath('//*[@id="1005-3-b-1-vi"]')
        self.assertTrue(new_section.find_element_by_tag_name('ins'))

        # make sure changed paragraph has insertions and deletions
        changed_section = self.driver.find_element_by_xpath('//*[@id="1005-3-b-2-ii"]')
        self.assertTrue(len(changed_section.find_elements_by_tag_name('ins')) == 2)
        self.assertTrue(len(changed_section.find_elements_by_tag_name('del')))

        # go back into diff pane in drawer, stop comparing
        self.get_drawer_button().click()
        stop_button = self.driver.find_element_by_xpath('//*[@id="timeline"]/div[2]/ul/li[2]/div/a')
        stop_button.click()

        # make sure it goes back to the right place
        WebDriverWait(self.driver, 30).until(
            lambda driver: driver.current_url == 'http://localhost:8000/1005-3/2011-11111')

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