<commit_before>import cupy

from cupy import core

_piecewise_krnl = core.ElementwiseKernel(
    'U condlist, T funclist',
    'T y',
    'if(condlist) y = funclist',
    'piecewise_kernel'
)

def piecewise(x, condlist, funclist):
    """Evaluate a piecewise-defined function.

        Args:
            x (cupy.ndarray): input domain
            condlist (list of cupy.ndarray or bool scalars):
                Each boolean array/ scalar corresponds to a function
                in funclist. Length of funclist is equal to that of
                condlist. If one extra function is given, it is used
                as the default value when the otherwise condition is met
            funclist (list of scalars): list of scalar functions.

        Returns:
            cupy.ndarray: the scalar values in funclist on portions of x
                defined by condlist.

        .. warning::

            This function currently doesn't support callable functions,
            args and kw parameters.

        .. seealso:: :func:`numpy.piecewise`
        """
    diffshape = 0
    if cupy.isscalar(condlist):
        condlist = [condlist]
    elif isinstance(condlist[0], tuple) and x.ndim != 0:
        diffshape = 2
    elif cupy.isscalar(condlist[0]) and x.ndim != 0:
        diffshape = 1
    if not isinstance(condlist[0], cupy.ndarray):
        condlist = cupy.asarray(condlist)
    condlen = len(condlist)
    if diffshape:
        if x.ndim == condlist.ndim:
            if x.shape != condlist.shape:
                raise IndexError('boolean index did not match indexed '
                                 'array along the same dimension; shape '
                                 'is {} but corresponding boolean shape '
                                 'is {}'.format(x.shape,condlist.shape))
        if condlen == x.shape[0]:
            condlen = 1
        else:
            raise IndexError('boolean index did not match indexed array along '
                             'dimension 0; dimension is {} but corresponding '
                             'boolean dimension is {}'
                             .format(x.shape[0], condlen))
        condlist = [condlist]
    if isinstance(funclist, cupy.ndarray):
        funclist = funclist.tolist()
    funclen = len(funclist)
    if condlen == funclen:
        y = cupy.zeros(shape=x.shape, dtype=x.dtype)
    elif condlen + 1 == funclen:  # o.w
        if callable(funclist[-1]):
            raise NotImplementedError(
                'Callable functions are not supported currently')
        y = cupy.full(shape=x.shape,
                      fill_value=x.dtype.type(funclist[-1]), dtype=x.dtype)
        funclist = funclist[:-1]
    else:
        raise ValueError('with {} condition(s), either {} or {} functions'
                         ' are expected'.format(condlen, condlen, condlen + 1))
    for condition, func in zip(condlist, funclist):
        if callable(func):
            raise NotImplementedError(
                'Callable functions are not supported currently')
        if diffshape == 1:
            condition = condition.reshape((-1, 1))
        _piecewise_krnl(condition, func, y)
    return y
<commit_msg>flake fix<commit_after>import cupy

from cupy import core

_piecewise_krnl = core.ElementwiseKernel(
    'U condlist, T funclist',
    'T y',
    'if(condlist) y = funclist',
    'piecewise_kernel'
)

def piecewise(x, condlist, funclist):
    """Evaluate a piecewise-defined function.

        Args:
            x (cupy.ndarray): input domain
            condlist (list of cupy.ndarray or bool scalars):
                Each boolean array/ scalar corresponds to a function
                in funclist. Length of funclist is equal to that of
                condlist. If one extra function is given, it is used
                as the default value when the otherwise condition is met
            funclist (list of scalars): list of scalar functions.

        Returns:
            cupy.ndarray: the scalar values in funclist on portions of x
                defined by condlist.

        .. warning::

            This function currently doesn't support callable functions,
            args and kw parameters.

        .. seealso:: :func:`numpy.piecewise`
        """
    diffshape = 0
    if cupy.isscalar(condlist):
        condlist = [condlist]
    elif isinstance(condlist[0], tuple) and x.ndim != 0:
        diffshape = 2
    elif cupy.isscalar(condlist[0]) and x.ndim != 0:
        diffshape = 1
    if not isinstance(condlist[0], cupy.ndarray):
        condlist = cupy.asarray(condlist)
    condlen = len(condlist)
    if diffshape:
        if x.ndim == condlist.ndim:
            if x.shape != condlist.shape:
                raise IndexError('boolean index did not match indexed '
                                 'array along the same dimension; shape '
                                 'is {} but corresponding boolean shape '
                                 'is {}'.format(x.shape, condlist.shape))
        if condlen == x.shape[0]:
            condlen = 1
        else:
            raise IndexError('boolean index did not match indexed array along '
                             'dimension 0; dimension is {} but corresponding '
                             'boolean dimension is {}'
                             .format(x.shape[0], condlen))
        condlist = [condlist]
    if isinstance(funclist, cupy.ndarray):
        funclist = funclist.tolist()
    funclen = len(funclist)
    if condlen == funclen:
        y = cupy.zeros(shape=x.shape, dtype=x.dtype)
    elif condlen + 1 == funclen:  # o.w
        if callable(funclist[-1]):
            raise NotImplementedError(
                'Callable functions are not supported currently')
        y = cupy.full(shape=x.shape,
                      fill_value=x.dtype.type(funclist[-1]), dtype=x.dtype)
        funclist = funclist[:-1]
    else:
        raise ValueError('with {} condition(s), either {} or {} functions'
                         ' are expected'.format(condlen, condlen, condlen + 1))
    for condition, func in zip(condlist, funclist):
        if callable(func):
            raise NotImplementedError(
                'Callable functions are not supported currently')
        if diffshape == 1:
            condition = condition.reshape((-1, 1))
        _piecewise_krnl(condition, func, y)
    return y
<|endoftext|>


<commit_before>from curses_menu import CursesMenu, MenuItem

class SelectionMenu(CursesMenu):
    def __init__(self, title, subtitle=None, items=list(), exit_option=True, parent=None):
        super().__init__(title, subtitle, list(), exit_option, parent)
        for item in items():
            self.add_item(SelectionItem(item, self))

    @classmethod
    def get_selection(cls, options, title="Select an option", subtitle="", exit_option=True, parent=None):
        menu = cls(title, subtitle, options, exit_option, parent)
        menu.show()
        return menu.get_selection()

class SelectionItem(MenuItem):
    def action(self):
        self.menu.exit()
<commit_msg>reacted to changes in selection menu<commit_after>from curses_menu import CursesMenu, MenuItem

class SelectionMenu(CursesMenu):
    def __init__(self, title, subtitle=None, items=None, exit_option=True, parent=None):
        if items is None:
            self.items = list()
        else:
            self.items = items
        super().__init__(title, subtitle, items, exit_option, parent)
        for item in items():
            self.add_item(SelectionItem(item, self))

    @classmethod
    def get_selection(cls, options, title="Select an option", subtitle="", exit_option=True, parent=None):
        menu = cls(title, subtitle, options, exit_option, parent)
        menu.show()
        return menu.get_selection()

class SelectionItem(MenuItem):
    def action(self):
        self.menu.exit()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    Copyright (C) 2014 Compassion CH (http://www.compassion.ch)
#    Releasing children from poverty in Jesus' name
#    @author: Emanuel Cino <ecino@compassion.ch>
#
#    The licence is in the file __manifest__.py
#
##############################################################################

from odoo import api, fields, models

class AccountStatement(models.Model):
    """ Adds a relation to a recurring invoicer. """

    _inherit = 'account.bank.statement'

    ##########################################################################
    #                                 FIELDS                                 #
    ##########################################################################
    name = fields.Char(
        default=lambda b: b._default_name()
    )

    ##########################################################################
    #                             FIELDS METHODS                             #
    ##########################################################################
    @api.model
    def _default_name(self):
        """ Find the appropriate sequence """
        journal_id = self.env.context.get('default_journal_id')
        if journal_id:
            journal = self.env['account.journal'].browse(journal_id)
            sequence = self.env['ir.sequence'].search([
                ('name', '=', journal.name)])
            if sequence:
                return sequence.next_by_id()
        return ''
<commit_msg>CO-1545 Lors du lettrage: Trier par partenaire-mchanging the display order of bank account statements during the reconciliation process from partner_id to lastname, firstname<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    Copyright (C) 2014 Compassion CH (http://www.compassion.ch)
#    Releasing children from poverty in Jesus' name
#    @author: Emanuel Cino <ecino@compassion.ch>
#    @author: Nicolas Badoux <n.badoux@hotmail.com>
#
#    The licence is in the file __manifest__.py
#
##############################################################################

from odoo import api, fields, models

class AccountStatement(models.Model):
    """ Adds a relation to a recurring invoicer. """

    _inherit = 'account.bank.statement'

    ##########################################################################
    #                                 FIELDS                                 #
    ##########################################################################
    name = fields.Char(
        default=lambda b: b._default_name()
    )

    ##########################################################################
    #                             FIELDS METHODS                             #
    ##########################################################################
    @api.model
    def _default_name(self):
        """ Find the appropriate sequence """
        journal_id = self.env.context.get('default_journal_id')
        if journal_id:
            journal = self.env['account.journal'].browse(journal_id)
            sequence = self.env['ir.sequence'].search([
                ('name', '=', journal.name)])
            if sequence:
                return sequence.next_by_id()
        return ''

    @api.multi
    def reconciliation_widget_preprocess(self):
        """ Overwrite with slight changes
            odoo/addons/account/models/accound_bank_statement.py

            Get statement lines of the specified statements or all
            unreconciled statement lines and try to automatically reconcile
            them / find them a partner.
            Return ids of statement lines left to reconcile and other data
            for the reconciliation widget.
        """
        statements = self
        # NB : The field account_id can be used at the statement line
        # creation/import to avoid the reconciliation process on it later on,
        # this is why we filter out statements lines where account_id is set

        sql_query = """SELECT stl.id
                        FROM account_bank_statement_line AS stl
                        JOIN res_partner AS partner ON partner.id =
                        stl.partner_id
                        WHERE stl.account_id IS NULL AND not exists (select 1
                        from account_move m where m.statement_line_id = stl.id)
                            AND stl.company_id = %s
                """
        params = (self.env.user.company_id.id,)
        if statements:
            sql_query += ' AND stl.statement_id IN %s'
            params += (tuple(statements.ids),)
        sql_query += ' ORDER BY partner.lastname, partner.firstname, ' \
                     'partner.id'
        self.env.cr.execute(sql_query, params)
        x = self.env.cr.dictfetchall()
        lines_left = self.env['account.bank.statement.line'].browse([
            line.get('id') for line in x])
        # try to assign partner to bank_statement_line
        stl_to_assign_partner = [stl.id for stl in lines_left if not
                                 stl.partner_id]
        refs = list(set([st.name for st in lines_left if not
                         stl.partner_id]))
        if lines_left and stl_to_assign_partner and refs \
                and lines_left[0].journal_id.default_credit_account_id \
                and lines_left[0].journal_id.default_debit_account_id:

            sql_query = """SELECT aml.partner_id, aml.ref, stl.id
                            FROM account_move_line aml
                                JOIN account_account acc ON acc.id =
                                aml.account_id
                                JOIN account_bank_statement_line stl ON
                                aml.ref = stl.name
                                JOIN res_partner AS partner ON partner.id =
                        stl.partner_id
                            WHERE (aml.company_id = %s
                                AND aml.partner_id IS NOT NULL)
                                AND (
                                    (aml.statement_id IS NULL AND
                                    aml.account_id IN %s)
                                    OR
                                    (acc.internal_type IN ('payable',
                                    'receivable') AND aml.reconciled = false)
                                    )
                                AND aml.ref IN %s
                                """
            params = (self.env.user.company_id.id,
                      (lines_left[0].journal_id.default_credit_account_id.id,
                       lines_left[0].journal_id.default_debit_account_id.id),
                      tuple(refs))
            if statements:
                sql_query += 'AND stl.id IN %s'
                params += (tuple(stl_to_assign_partner),)
            sql_query += ' ORDER BY partner.lastname, partner.firstname, ' \
                         'partner.id'
            self.env.cr.execute(sql_query, params)
            results = self.env.cr.dictfetchall()
            st_line = self.env['account.bank.statement.line']
            for line in results:
                st_line.browse(line.get('id')).write(
                    {'partner_id': line.get('partner_id')})
        return {
            'st_lines_ids': lines_left.ids,
            'notifications': [],
            'statement_name':
                len(statements) == 1 and statements[0].name or False,
            'num_already_reconciled_lines': 0,
        }
<|endoftext|>


<commit_before>#  -*- coding: utf-8 -*-
"""
This module manage interaction between application and
OpenStack cloud infrastructure
"""
import math

from datetime import date
from dateutil.relativedelta import relativedelta

from django.core.cache import cache
from django.utils.dateparse import parse_datetime

from keystoneauth1.identity import v3
from keystoneauth1 import session, exceptions as ksexceptions
from keystoneclient.v3 import client as ksclient
from novaclient import client as nvclient

from openstack_lease_it.settings import GLOBAL_CONFIG
from lease_it.datastore import InstancesAccess, LEASE_DURATION
from lease_it.backend.Exceptions import PermissionDenied

# Define nova client version as a constant
NOVA_VERSION = 2

# Default cache timeout (in sec)
FLAVOR_CACHE_TIMEOUT = 86400
USERS_CACHE_TIMEOUT = 86400
PROJECTS_CACHE_TIMEOUT = 86400
INSTANCES_CACHE_TIMEOUT = 86400

class OpenstackConnection(object):  # pylint: disable=too-few-public-methods
    """
    This class manage interface between OpenStack Cloud infrastructure and
    views.
    """
    def __init__(self):
        """
        During class initialization, we create a connection to
        OpenStack Cloud
        """
        super(OpenstackConnection, self).__init__()
        # We need to be admin to have access to hypervisor list
        credentials = dict()
        credentials['username'] = GLOBAL_CONFIG['OS_USERNAME']
        credentials['password'] = GLOBAL_CONFIG['OS_PASSWORD']
        credentials['auth_url'] = GLOBAL_CONFIG['OS_AUTH_URL']
        credentials['project_name'] = GLOBAL_CONFIG['OS_PROJECT_NAME']
        credentials['project_domain_name'] = GLOBAL_CONFIG['OS_PROJECT_DOMAIN_NAME']
        credentials['user_domain_name'] = GLOBAL_CONFIG['OS_USER_DOMAIN_NAME']

        try:
            auth = v3.Password(**credentials)
            self.session = session.Session(auth=auth,
                                           verify=GLOBAL_CONFIG['OS_CACERT'])
        except:  # pylint: disable=bare-except
            pass

    def _instances(self):
        """
        List of instances actually launched
        :return: dict()
        """
        response = cache.get('instances')
        if not response:
            response = dict()
            nova = nvclient.Client(NOVA_VERSION, session=self.session)
            data_instances = nova.servers.list(search_opts={'all_tenants': 'true'})
            for instance in data_instances:
                response[instance.id] = {
                    'user_id': instance.user_id,
                    'project_id': instance.tenant_id,
                    'id': instance.id,
                    'name': instance.name,
                    'created_at': parse_datetime(instance.created).date()
                }
            cache.set('instances', response, INSTANCES_CACHE_TIMEOUT)
        return response

    def _hypervisors(self):
        """
        List of hypervisors and their details
        :return: dict()
        """
        nova = nvclient.Client(NOVA_VERSION, session=self.session)
        hypervisors = nova.hypervisors.list()
        response = list()
        for hypervisor in hypervisors:
            response.append({
                'status': hypervisor.status,
                'state': hypervisor.state,
                'vcpus': hypervisor.vcpus,
                'vcpus_used': hypervisor.vcpus_used,
                'free_ram': hypervisor.free_disk_gb,
                'memory': hypervisor.memory_mb,
                'free_disk': hypervisor.free_disk_gb,
                'local_disk': hypervisor.local_gb
            })
        return response

    def _flavors(self):
        """
        List of flavors and their details
        """
        # We retrieve information from memcached
        response = cache.get('flavors')
        if not response:
            response = dict()
            nova = nvclient.Client(NOVA_VERSION, session=self.session)
            flavors = nova.flavors.list()
            for flavor in flavors:
                response[flavor.name] = {
                    'name': flavor.name,
                    'disk': int(flavor.disk),
                    'ram': int(flavor.ram),
                    'cpu': int(flavor.vcpus)
                }
            cache.set('flavors', response, FLAVOR_CACHE_TIMEOUT)
        return response

    def _domains(self):
        """
        List all domains available
        :return: dict()
        """
        response = cache.get('domains')
        if not response:
            response = dict()
            keystone = ksclient.Client(session=self.session)
            try:
                data_domains = keystone.domains.list()
            except ksexceptions.ConnectFailure:
                data_domains = list()
            for domain in data_domains:
                response[domain.id] = {
                    'id': domain.id,
                    'name': domain.name
                }
            cache.set('domain', response, USERS_CACHE_TIMEOUT)
        return response

    def _users(self):
        """
        List of users. If not on admin network, we can't retrieve information,
        so we return a None object
        :return: dict()
        """
        response = cache.get('users')
        if not response:
            response = dict()
            keystone = ksclient.Client(session=self.session)
            data_domain = self._domains()
            for domain in data_domain:
                try:
                    data_users = keystone.users.list(domain=domain)
                except ksexceptions.ConnectFailure:
                    data_users = list(domain)
                for user in data_users:
                    try:
                        user_email = user.email
                    except AttributeError:
                        user_email = ""
                    response[user.id] = {
                        'id': user.id,
                        'domain_id': domain,
                        'name': user.name,
                        'email': user_email
                    }
            cache.set('users', response, USERS_CACHE_TIMEOUT)
        return response

    def _projects(self):
        """
        List of projects on OpenStack.
        :return: dict()
        """
        keystone = ksclient.Client(session=self.session)
        try:
            projects = keystone.projects.list()
        except ksexceptions.ConnectFailure:
            projects = None
        return projects

    def flavors(self):
        """
        Return a list of flavor and a detail about
        * Their properties (CPU / Disk / RAM)
        * The actual Cloud state (number of VM we can start, maximum
        VM we can start if empty)
        :return: dict()
        """
        flavors = self._flavors()
        # Retrieve hypervisor status to populate response
        hypervisors = self._hypervisors()

        # For each flavor, we look @ each hypervisor how many of
        # it can be launch @ the current state and the maximum value
        # based on flavor
        # * disk
        # * CPU
        # * RAM
        for flavor in flavors:
            free_flavor = 0
            max_flavor = 0
            for hypervisor in hypervisors:
                # If hypervisor is disable or down we don't care of it
                if hypervisor['status'] == "enabled" and\
                                hypervisor['state'] == "up":
                    # We round down the number of flavor
                    free_cpu = math.floor((hypervisor['vcpus'] - hypervisor['vcpus_used']) /
                                          flavors[flavor]['cpu'])
                    max_cpu = math.floor(hypervisor['vcpus'] / flavors[flavor]['cpu'])
                    free_ram = math.floor(hypervisor['free_ram'] / flavors[flavor]['ram'])
                    max_ram = math.floor(hypervisor['memory'] / flavors[flavor]['ram'])
                    free_disk = math.floor(hypervisor['free_disk'] / flavors[flavor]['disk'])
                    max_disk = math.floor(hypervisor['local_disk'] / flavors[flavor]['disk'])

                    # We keep the lowest value of ram / cpu / disk as it s
                    # the weak link of the hypervisor
                    if min(free_cpu, free_ram, free_disk) > 0:
                        free_flavor += min(free_cpu, free_ram, free_disk)
                    if min(max_cpu, max_ram, max_disk) > 0:
                        max_flavor += min(max_cpu, max_ram, max_disk)
            flavors[flavor]['free'] = free_flavor
            flavors[flavor]['max'] = max_flavor
        return flavors

    def instances(self, request):
        """
        List all instances started on cluster and owned by user
        :param request: Web request, used to retrieve user id
        :return: dict()
        """
        response = dict()
        data_instances = self._instances()
        # We only display instances that are owned by logged user
        for instance in data_instances:
            if data_instances[instance]['user_id'] == request.user.id:
                response[data_instances[instance]['id']] = data_instances[instance]
        return InstancesAccess.show(response)

    def users(self):
        """
        Return a list of users w/ attributes
        id, first_name, last_name and email
        :return: dict of users
        """
        return self._users()

    def projects(self):  # pylint: disable=missing-docstring, no-self-use
        # We retrieve information from memcached
        response = cache.get('projects')
        if not response:  # If not on memcached, we ask OpenStack
            response = dict()
            data_projects = self._projects()
            if data_projects is not None:
                for project in data_projects:
                    response[project.id] = {
                        'id': project.id,
                        'name': project.name
                    }
            cache.set('projects', response, PROJECTS_CACHE_TIMEOUT)
        return response

    @staticmethod
    def lease_instance(request, instance_id):
        """
        If instance_id is owned by user_id, then update lease information, if not, raise
        PermissionDenied exception
        :param instance_id: id of instance
        :param request: Web request
        :return: void
        """
        data_instances = cache.get('instances')
        if data_instances[instance_id]['user_id'] != request.user.id:
            raise PermissionDenied(request.user.id, instance_id)
        InstancesAccess.save({
            instance_id: data_instances[instance_id]
        })
        return data_instances[instance_id]

    def spy_instances(self):
        """
        spy_instances is started by instance_spy module and check all running VM + notify user
        if a VM is close to its lease time
        :return: dict()
        """
        now = date.today()
        data_instances = InstancesAccess.show(self._instances())
        response = {
            'delete': list(),  # List of instance we must delete
            'notify': list()  # List of instance we must notify user to renew the lease
        }
        for instance in data_instances:
            leased_at = data_instances[instance]['leased_at']
            lease_end = data_instances[instance]['lease_end']
            # If it's a new instance, we put lease value as today
            if leased_at is None:
                InstancesAccess.save({
                    instance: data_instances[instance]
                })
                leased_at = now
                lease_end = now + relativedelta(days=+LEASE_DURATION)
            first_notification_date = leased_at + relativedelta(days=+LEASE_DURATION/3)
            second_notification_date = leased_at + relativedelta(days=+LEASE_DURATION/6)
            # If lease as expire we tag it as delete
            if lease_end < now:
                response['delete'].append(data_instances[instance])
            elif first_notification_date == now or \
                    second_notification_date == now or \
                    lease_end < now - relativedelta(days=-6):
                response['notify'].append(data_instances[instance])
        return response
<commit_msg>Fix minor issue on OpenstackConnection<commit_after>#  -*- coding: utf-8 -*-
"""
This module manage interaction between application and
OpenStack cloud infrastructure
"""
import math

from datetime import date
from dateutil.relativedelta import relativedelta

from django.core.cache import cache
from django.utils.dateparse import parse_datetime

from keystoneauth1.identity import v3
from keystoneauth1 import session, exceptions as ksexceptions
from keystoneclient.v3 import client as ksclient
from novaclient import client as nvclient

from openstack_lease_it.settings import GLOBAL_CONFIG
from lease_it.datastore import InstancesAccess, LEASE_DURATION
from lease_it.backend.Exceptions import PermissionDenied

# Define nova client version as a constant
NOVA_VERSION = 2

# Default cache timeout (in sec)
FLAVOR_CACHE_TIMEOUT = 86400
USERS_CACHE_TIMEOUT = 86400
PROJECTS_CACHE_TIMEOUT = 86400
INSTANCES_CACHE_TIMEOUT = 86400

class OpenstackConnection(object):  # pylint: disable=too-few-public-methods
    """
    This class manage interface between OpenStack Cloud infrastructure and
    views.
    """
    def __init__(self):
        """
        During class initialization, we create a connection to
        OpenStack Cloud
        """
        super(OpenstackConnection, self).__init__()
        # We need to be admin to have access to hypervisor list
        credentials = dict()
        credentials['username'] = GLOBAL_CONFIG['OS_USERNAME']
        credentials['password'] = GLOBAL_CONFIG['OS_PASSWORD']
        credentials['auth_url'] = GLOBAL_CONFIG['OS_AUTH_URL']
        credentials['project_name'] = GLOBAL_CONFIG['OS_PROJECT_NAME']
        credentials['project_domain_name'] = GLOBAL_CONFIG['OS_PROJECT_DOMAIN_NAME']
        credentials['user_domain_name'] = GLOBAL_CONFIG['OS_USER_DOMAIN_NAME']

        try:
            auth = v3.Password(**credentials)
            self.session = session.Session(auth=auth,
                                           verify=GLOBAL_CONFIG['OS_CACERT'])
        except:  # pylint: disable=bare-except
            pass

    def _instances(self):
        """
        List of instances actually launched
        :return: dict()
        """
        response = cache.get('instances')
        if not response:
            response = dict()
            nova = nvclient.Client(NOVA_VERSION, session=self.session)
            data_instances = nova.servers.list(search_opts={'all_tenants': 'true'})
            for instance in data_instances:
                response[instance.id] = {
                    'user_id': instance.user_id,
                    'project_id': instance.tenant_id,
                    'id': instance.id,
                    'name': instance.name,
                    'created_at': parse_datetime(instance.created).date()
                }
            cache.set('instances', response, INSTANCES_CACHE_TIMEOUT)
        return response

    def _hypervisors(self):
        """
        List of hypervisors and their details
        :return: dict()
        """
        nova = nvclient.Client(NOVA_VERSION, session=self.session)
        hypervisors = nova.hypervisors.list()
        response = list()
        for hypervisor in hypervisors:
            response.append({
                'status': hypervisor.status,
                'state': hypervisor.state,
                'vcpus': hypervisor.vcpus,
                'vcpus_used': hypervisor.vcpus_used,
                'free_ram': hypervisor.free_ram_mb,
                'memory': hypervisor.memory_mb,
                'free_disk': hypervisor.free_disk_gb,
                'local_disk': hypervisor.local_gb
            })
        return response

    def _flavors(self):
        """
        List of flavors and their details
        """
        # We retrieve information from memcached
        response = cache.get('flavors')
        if not response:
            response = dict()
            nova = nvclient.Client(NOVA_VERSION, session=self.session)
            flavors = nova.flavors.list()
            for flavor in flavors:
                response[flavor.name] = {
                    'name': flavor.name,
                    'disk': int(flavor.disk),
                    'ram': int(flavor.ram),
                    'cpu': int(flavor.vcpus)
                }
            cache.set('flavors', response, FLAVOR_CACHE_TIMEOUT)
        return response

    def _domains(self):
        """
        List all domains available
        :return: dict()
        """
        response = cache.get('domains')
        if not response:
            response = dict()
            keystone = ksclient.Client(session=self.session)
            try:
                data_domains = keystone.domains.list()
            except ksexceptions.ConnectFailure:
                data_domains = list()
            for domain in data_domains:
                response[domain.id] = {
                    'id': domain.id,
                    'name': domain.name
                }
            cache.set('domain', response, USERS_CACHE_TIMEOUT)
        return response

    def _users(self):
        """
        List of users. If not on admin network, we can't retrieve information,
        so we return a None object
        :return: dict()
        """
        response = cache.get('users')
        if not response:
            response = dict()
            keystone = ksclient.Client(session=self.session)
            data_domain = self._domains()
            for domain in data_domain:
                try:
                    data_users = keystone.users.list(domain=domain)
                except ksexceptions.ConnectFailure:
                    data_users = list(domain)
                for user in data_users:
                    try:
                        user_email = user.email
                    except AttributeError:
                        user_email = ""
                    response[user.id] = {
                        'id': user.id,
                        'domain_id': domain,
                        'name': user.name,
                        'email': user_email
                    }
            cache.set('users', response, USERS_CACHE_TIMEOUT)
        return response

    def _projects(self):
        """
        List of projects on OpenStack.
        :return: dict()
        """
        keystone = ksclient.Client(session=self.session)
        try:
            projects = keystone.projects.list()
        except ksexceptions.ConnectFailure:
            projects = None
        return projects

    def flavors(self):
        """
        Return a list of flavor and a detail about
        * Their properties (CPU / Disk / RAM)
        * The actual Cloud state (number of VM we can start, maximum
        VM we can start if empty)
        :return: dict()
        """
        flavors = self._flavors()
        # Retrieve hypervisor status to populate response
        hypervisors = self._hypervisors()

        # For each flavor, we look @ each hypervisor how many of
        # it can be launch @ the current state and the maximum value
        # based on flavor
        # * disk
        # * CPU
        # * RAM
        for flavor in flavors:
            free_flavor = 0
            max_flavor = 0
            for hypervisor in hypervisors:
                # If hypervisor is disable or down we don't care of it
                if hypervisor['status'] == "enabled" and\
                                hypervisor['state'] == "up":
                    # We round down the number of flavor
                    free_cpu = math.floor((hypervisor['vcpus'] - hypervisor['vcpus_used']) /
                                          flavors[flavor]['cpu'])
                    max_cpu = math.floor(hypervisor['vcpus'] / flavors[flavor]['cpu'])
                    free_ram = math.floor(hypervisor['free_ram'] / flavors[flavor]['ram'])
                    max_ram = math.floor(hypervisor['memory'] / flavors[flavor]['ram'])
                    free_disk = math.floor(hypervisor['free_disk'] / flavors[flavor]['disk'])
                    max_disk = math.floor(hypervisor['local_disk'] / flavors[flavor]['disk'])

                    # We keep the lowest value of ram / cpu / disk as it s
                    # the weak link of the hypervisor
                    if min(free_cpu, free_ram, free_disk) > 0:
                        free_flavor += min(free_cpu, free_ram, free_disk)
                    if min(max_cpu, max_ram, max_disk) > 0:
                        max_flavor += min(max_cpu, max_ram, max_disk)
            flavors[flavor]['free'] = free_flavor
            flavors[flavor]['max'] = max_flavor
        return flavors

    def instances(self, request):
        """
        List all instances started on cluster and owned by user
        :param request: Web request, used to retrieve user id
        :return: dict()
        """
        response = dict()
        data_instances = self._instances()
        # We only display instances that are owned by logged user
        for instance in data_instances:
            if data_instances[instance]['user_id'] == request.user.id:
                response[data_instances[instance]['id']] = data_instances[instance]
        return InstancesAccess.show(response)

    def users(self):
        """
        Return a list of users w/ attributes
        id, first_name, last_name and email
        :return: dict of users
        """
        return self._users()

    def projects(self):  # pylint: disable=missing-docstring, no-self-use
        # We retrieve information from memcached
        response = cache.get('projects')
        if not response:  # If not on memcached, we ask OpenStack
            response = dict()
            data_projects = self._projects()
            if data_projects is not None:
                for project in data_projects:
                    response[project.id] = {
                        'id': project.id,
                        'name': project.name
                    }
            cache.set('projects', response, PROJECTS_CACHE_TIMEOUT)
        return response

    @staticmethod
    def lease_instance(request, instance_id):
        """
        If instance_id is owned by user_id, then update lease information, if not, raise
        PermissionDenied exception
        :param instance_id: id of instance
        :param request: Web request
        :return: void
        """
        data_instances = cache.get('instances')
        if data_instances[instance_id]['user_id'] != request.user.id:
            raise PermissionDenied(request.user.id, instance_id)
        InstancesAccess.save({
            instance_id: data_instances[instance_id]
        })
        return data_instances[instance_id]

    def spy_instances(self):
        """
        spy_instances is started by instance_spy module and check all running VM + notify user
        if a VM is close to its lease time
        :return: dict()
        """
        now = date.today()
        data_instances = InstancesAccess.show(self._instances())
        response = {
            'delete': list(),  # List of instance we must delete
            'notify': list()  # List of instance we must notify user to renew the lease
        }
        for instance in data_instances:
            leased_at = data_instances[instance]['leased_at']
            lease_end = data_instances[instance]['lease_end']
            # If it's a new instance, we put lease value as today
            if leased_at is None:
                InstancesAccess.save({
                    instance: data_instances[instance]
                })
                leased_at = now
                lease_end = now + relativedelta(days=+LEASE_DURATION)
            first_notification_date = leased_at + relativedelta(days=+LEASE_DURATION/3)
            second_notification_date = leased_at + relativedelta(days=+LEASE_DURATION/6)
            # If lease as expire we tag it as delete
            if lease_end < now:
                response['delete'].append(data_instances[instance])
            elif first_notification_date == now or \
                    second_notification_date == now or \
                    lease_end < now - relativedelta(days=-6):
                response['notify'].append(data_instances[instance])
        return response
<|endoftext|>


<commit_before>from datetime import datetime
from django.test import TestCase

from devilry_detektor.models import DetektorAssignment
from devilry_detektor.tasks import run_detektor_on_assignment
from devilry_developer.testhelpers.corebuilder import UserBuilder
from devilry_developer.testhelpers.corebuilder import PeriodBuilder

class TestRunDetektorOnAssignment(TestCase):
    def setUp(self):
        self.testuser = UserBuilder('testuser').user
        self.assignmentbuilder = PeriodBuilder.quickadd_ducku_duck1010_active()\
            .add_assignment('testassignment')

    def test_invalid_assignment(self):
        with self.assertRaises(DetektorAssignment.DoesNotExist):
            run_detektor_on_assignment.delay(
                assignment_id=200001).wait()

    def test_already_running(self):
        processing_started_datetime = datetime.now()
        DetektorAssignment.objects.create(
            assignment_id=self.assignmentbuilder.assignment.id,
            processing_started_by=self.testuser,
            processing_started_datetime=processing_started_datetime)

        run_detektor_on_assignment.delay(
            assignment_id=self.assignmentbuilder.assignment.id).wait()
        detektorassignment = DetektorAssignment.objects.all()[0]
        self.assertEqual(detektorassignment.processing_started_datetime, processing_started_datetime)

    def test_processing_detektorassignment_doesnotexist(self):
        with self.assertRaises(DetektorAssignment.DoesNotExist):
            run_detektor_on_assignment.delay(
                assignment_id=self.assignmentbuilder.assignment.id).wait()

    def test_processing_ok(self):
        DetektorAssignment.objects.create(
            assignment_id=self.assignmentbuilder.assignment.id,
            processing_started_by=self.testuser)

        otheruser = UserBuilder('otheruser').user
        self.assertEquals(DetektorAssignment.objects.count(), 1)
        run_detektor_on_assignment.delay(
            assignment_id=self.assignmentbuilder.assignment.id).wait()
        self.assertEquals(DetektorAssignment.objects.count(), 1)

        detektorassignment = DetektorAssignment.objects.all()[0]
        self.assertEqual(detektorassignment.processing_started_datetime, None)
<commit_msg>devilry_detektor: Fixed tests.<commit_after>from datetime import datetime
from django.test import TestCase

from devilry_detektor.models import DetektorAssignment
from devilry_detektor.tasks import run_detektor_on_assignment
from devilry_developer.testhelpers.corebuilder import UserBuilder
from devilry_developer.testhelpers.corebuilder import PeriodBuilder

class TestRunDetektorOnAssignment(TestCase):
    def setUp(self):
        self.testuser = UserBuilder('testuser').user
        self.assignmentbuilder = PeriodBuilder.quickadd_ducku_duck1010_active()\
            .add_assignment('testassignment')

    def test_invalid_assignment(self):
        with self.assertRaises(DetektorAssignment.DoesNotExist):
            run_detektor_on_assignment.delay(
                assignment_id=200001).wait()

    def test_processing_detektorassignment_doesnotexist(self):
        with self.assertRaises(DetektorAssignment.DoesNotExist):
            run_detektor_on_assignment.delay(
                assignment_id=self.assignmentbuilder.assignment.id).wait()

    def test_processing_ok(self):
        DetektorAssignment.objects.create(
            assignment_id=self.assignmentbuilder.assignment.id,
            processing_started_by=self.testuser)

        otheruser = UserBuilder('otheruser').user
        self.assertEquals(DetektorAssignment.objects.count(), 1)
        run_detektor_on_assignment.delay(
            assignment_id=self.assignmentbuilder.assignment.id).wait()
        self.assertEquals(DetektorAssignment.objects.count(), 1)

        detektorassignment = DetektorAssignment.objects.all()[0]
        self.assertEqual(detektorassignment.processing_started_datetime, None)
<|endoftext|>


<commit_before>from datetime import datetime
from dmutils.formats import DATE_FORMAT

from flask import abort, request, current_app
from sqlalchemy.exc import IntegrityError, DataError

from dmapiclient.audit import AuditTypes

from .. import main
from ...models import db, Brief, BriefResponse, AuditEvent, Framework
from ...utils import (
    get_int_or_400,
    get_json_from_request,
    get_request_page_questions,
    get_valid_page_or_1,
    json_has_required_keys,
    list_result_response,
    paginated_result_response,
    single_result_response,
    validate_and_return_updater_request,
)

from ...brief_utils import get_supplier_service_eligible_for_brief
from ...service_utils import validate_and_return_supplier

COMPLETED_BRIEF_RESPONSE_STATUSES = ['submitted', 'pending-awarded', 'awarded']
RESOURCE_NAME = "briefResponses"

@main.route('/brief-responses', methods=['POST'])
def create_brief_response():
    json_payload = get_json_from_request()
    updater_json = validate_and_return_updater_request()
    page_questions = get_request_page_questions()

    json_has_required_keys(json_payload, ['briefResponses'])
    brief_response_json = json_payload['briefResponses']
    json_has_required_keys(brief_response_json, ['briefId', 'supplierId'])

    try:
        brief = Brief.query.get(brief_response_json['briefId'])
    except DataError:
        brief = None

    if brief is None:
        abort(400, "Invalid brief ID '{}'".format(brief_response_json['briefId']))

    if brief.status != 'live':
        abort(400, "Brief must be live")

    if brief.framework.status not in ['live', 'expired']:
        abort(400, "Brief framework must be live or expired")

    supplier = validate_and_return_supplier(brief_response_json)

    brief_service = get_supplier_service_eligible_for_brief(supplier, brief)
    if not brief_service:
        abort(400, "Supplier is not eligible to apply to this brief")

    # Check if brief response already exists from this supplier
    if BriefResponse.query.filter(BriefResponse.supplier == supplier, BriefResponse.brief == brief).first():
        abort(400, "Brief response already exists for supplier '{}'".format(supplier.supplier_id))

    brief_response = BriefResponse(
        data=brief_response_json,
        supplier=supplier,
        brief=brief,
    )

    brief_role = brief.data["specialistRole"] if brief.lot.slug == "digital-specialists" else None
    service_max_day_rate = brief_service.data[brief_role + "PriceMax"] if brief_role else None

    brief_response.validate(enforce_required=False, required_fields=page_questions, max_day_rate=service_max_day_rate)

    db.session.add(brief_response)
    try:
        db.session.flush()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, format(e))

    audit = AuditEvent(
        audit_type=AuditTypes.create_brief_response,
        user=updater_json['updated_by'],
        data={
            'briefResponseId': brief_response.id,
            'briefResponseJson': brief_response_json,
        },
        db_object=brief_response,
    )

    db.session.add(audit)
    db.session.commit()

    return single_result_response(RESOURCE_NAME, brief_response), 201

@main.route('/brief-responses/<int:brief_response_id>', methods=['POST'])
def update_brief_response(brief_response_id):
    json_payload = get_json_from_request()
    updater_json = validate_and_return_updater_request()
    page_questions = get_request_page_questions()

    json_has_required_keys(json_payload, ['briefResponses'])
    brief_response_json = json_payload['briefResponses']

    brief_response = BriefResponse.query.filter(
        BriefResponse.id == brief_response_id
    ).first_or_404()

    brief = brief_response.brief
    supplier = brief_response.supplier
    brief_service = get_supplier_service_eligible_for_brief(supplier, brief)
    if not brief_service:
        abort(400, "Supplier is not eligible to apply to this brief")

    if brief.status != 'live':
        abort(400, "Brief must have 'live' status for the brief response to be updated")

    if brief.framework.status not in ['live', 'expired']:
        abort(400, "Brief framework must be live or expired")

    brief_role = brief.data["specialistRole"] if brief.lot.slug == "digital-specialists" else None
    service_max_day_rate = brief_service.data[brief_role + "PriceMax"] if brief_role else None

    brief_response.update_from_json(brief_response_json)

    brief_response.validate(enforce_required=False, required_fields=page_questions, max_day_rate=service_max_day_rate)

    audit = AuditEvent(
        audit_type=AuditTypes.update_brief_response,
        user=updater_json['updated_by'],
        data={
            'briefResponseId': brief_response.id,
            'briefResponseData': brief_response_json
        },
        db_object=brief_response,
    )

    db.session.add(brief_response)
    db.session.add(audit)

    try:
        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, format(e))

    return single_result_response(RESOURCE_NAME, brief_response), 200

@main.route('/brief-responses/<int:brief_response_id>/submit', methods=['POST'])
def submit_brief_response(brief_response_id):
    updater_json = validate_and_return_updater_request()

    brief_response = BriefResponse.query.filter(
        BriefResponse.id == brief_response_id
    ).first_or_404()

    brief = brief_response.brief
    supplier = brief_response.supplier
    brief_service = get_supplier_service_eligible_for_brief(supplier, brief)
    if not brief_service:
        abort(400, "Supplier is not eligible to apply to this brief")

    if brief.status != 'live':
        abort(400, "Brief must have 'live' status for the brief response to be submitted")

    if brief.framework.status not in ['live', 'expired']:
        abort(400, "Brief framework must be live or expired")

    brief_role = brief.data["specialistRole"] if brief.lot.slug == "digital-specialists" else None
    service_max_day_rate = brief_service.data[brief_role + "PriceMax"] if brief_role else None

    brief_response.validate(max_day_rate=service_max_day_rate)

    brief_response.submitted_at = datetime.utcnow()

    audit = AuditEvent(
        audit_type=AuditTypes.submit_brief_response,
        user=updater_json['updated_by'],
        data={
            'briefResponseId': brief_response.id
        },
        db_object=brief_response,
    )

    db.session.add(brief_response)
    db.session.add(audit)

    try:
        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, format(e))

    return single_result_response(RESOURCE_NAME, brief_response), 200

@main.route('/brief-responses/<int:brief_response_id>', methods=['GET'])
def get_brief_response(brief_response_id):
    brief_response = BriefResponse.query.filter(
        BriefResponse.id == brief_response_id
    ).first_or_404()

    return single_result_response(RESOURCE_NAME, brief_response), 200

@main.route('/brief-responses', methods=['GET'])
def list_brief_responses():
    page = get_valid_page_or_1()
    brief_id = get_int_or_400(request.args, 'brief_id')
    supplier_id = get_int_or_400(request.args, 'supplier_id')
    awarded_at = request.args.get('awarded_at')

    if request.args.get('status'):
        statuses = request.args['status'].split(',')
    else:
        statuses = COMPLETED_BRIEF_RESPONSE_STATUSES
    brief_responses = BriefResponse.query.filter(BriefResponse.status.in_(statuses))

    if supplier_id is not None:
        brief_responses = brief_responses.filter(BriefResponse.supplier_id == supplier_id)

    if brief_id is not None:
        brief_responses = brief_responses.filter(BriefResponse.brief_id == brief_id)

    if awarded_at is not None:
        day_start = datetime.strptime(awarded_at, DATE_FORMAT)
        day_end = datetime(day_start.year, day_start.month, day_start.day, 23, 59, 59, 999999)
        # Inclusive date range filtering
        brief_responses = brief_responses.filter(BriefResponse.awarded_at.between(day_start, day_end))

    brief_responses = brief_responses.options(
        db.defaultload(BriefResponse.brief).defaultload(Brief.framework).lazyload("*"),
        db.defaultload(BriefResponse.brief).defaultload(Brief.lot).lazyload("*"),
        db.defaultload(BriefResponse.brief).defaultload(Brief.awarded_brief_response).lazyload("*"),
        db.defaultload(BriefResponse.supplier).lazyload("*"),
    )

    if request.args.get('framework'):
        brief_responses = brief_responses.join(BriefResponse.brief).join(Brief.framework).filter(
            Brief.framework.has(Framework.slug.in_(
                framework_slug.strip() for framework_slug in request.args["framework"].split(",")
            ))
        )

    if brief_id or supplier_id:
        return list_result_response(RESOURCE_NAME, brief_responses), 200

    return paginated_result_response(
        result_name=RESOURCE_NAME,
        results_query=brief_responses,
        page=page,
        per_page=current_app.config['DM_API_BRIEF_RESPONSES_PAGE_SIZE'],
        endpoint='.list_brief_responses',
        request_args=request.args
    ), 200
<commit_msg>Add supplierId to audit events in brief responses<commit_after>from datetime import datetime
from dmutils.formats import DATE_FORMAT

from flask import abort, request, current_app
from sqlalchemy.exc import IntegrityError, DataError

from dmapiclient.audit import AuditTypes

from .. import main
from ...models import db, Brief, BriefResponse, AuditEvent, Framework
from ...utils import (
    get_int_or_400,
    get_json_from_request,
    get_request_page_questions,
    get_valid_page_or_1,
    json_has_required_keys,
    list_result_response,
    paginated_result_response,
    single_result_response,
    validate_and_return_updater_request,
)

from ...brief_utils import get_supplier_service_eligible_for_brief
from ...service_utils import validate_and_return_supplier

COMPLETED_BRIEF_RESPONSE_STATUSES = ['submitted', 'pending-awarded', 'awarded']
RESOURCE_NAME = "briefResponses"

@main.route('/brief-responses', methods=['POST'])
def create_brief_response():
    json_payload = get_json_from_request()
    updater_json = validate_and_return_updater_request()
    page_questions = get_request_page_questions()

    json_has_required_keys(json_payload, ['briefResponses'])
    brief_response_json = json_payload['briefResponses']
    json_has_required_keys(brief_response_json, ['briefId', 'supplierId'])

    try:
        brief = Brief.query.get(brief_response_json['briefId'])
    except DataError:
        brief = None

    if brief is None:
        abort(400, "Invalid brief ID '{}'".format(brief_response_json['briefId']))

    if brief.status != 'live':
        abort(400, "Brief must be live")

    if brief.framework.status not in ['live', 'expired']:
        abort(400, "Brief framework must be live or expired")

    supplier = validate_and_return_supplier(brief_response_json)

    brief_service = get_supplier_service_eligible_for_brief(supplier, brief)
    if not brief_service:
        abort(400, "Supplier is not eligible to apply to this brief")

    # Check if brief response already exists from this supplier
    if BriefResponse.query.filter(BriefResponse.supplier == supplier, BriefResponse.brief == brief).first():
        abort(400, "Brief response already exists for supplier '{}'".format(supplier.supplier_id))

    brief_response = BriefResponse(
        data=brief_response_json,
        supplier=supplier,
        brief=brief,
    )

    brief_role = brief.data["specialistRole"] if brief.lot.slug == "digital-specialists" else None
    service_max_day_rate = brief_service.data[brief_role + "PriceMax"] if brief_role else None

    brief_response.validate(enforce_required=False, required_fields=page_questions, max_day_rate=service_max_day_rate)

    db.session.add(brief_response)
    try:
        db.session.flush()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, format(e))

    audit = AuditEvent(
        audit_type=AuditTypes.create_brief_response,
        user=updater_json['updated_by'],
        data={
            'briefResponseId': brief_response.id,
            'briefResponseJson': brief_response_json,
            'supplierId': supplier.supplier_id,
        },
        db_object=brief_response,
    )

    db.session.add(audit)
    db.session.commit()

    return single_result_response(RESOURCE_NAME, brief_response), 201

@main.route('/brief-responses/<int:brief_response_id>', methods=['POST'])
def update_brief_response(brief_response_id):
    json_payload = get_json_from_request()
    updater_json = validate_and_return_updater_request()
    page_questions = get_request_page_questions()

    json_has_required_keys(json_payload, ['briefResponses'])
    brief_response_json = json_payload['briefResponses']

    brief_response = BriefResponse.query.filter(
        BriefResponse.id == brief_response_id
    ).first_or_404()

    brief = brief_response.brief
    supplier = brief_response.supplier
    brief_service = get_supplier_service_eligible_for_brief(supplier, brief)
    if not brief_service:
        abort(400, "Supplier is not eligible to apply to this brief")

    if brief.status != 'live':
        abort(400, "Brief must have 'live' status for the brief response to be updated")

    if brief.framework.status not in ['live', 'expired']:
        abort(400, "Brief framework must be live or expired")

    brief_role = brief.data["specialistRole"] if brief.lot.slug == "digital-specialists" else None
    service_max_day_rate = brief_service.data[brief_role + "PriceMax"] if brief_role else None

    brief_response.update_from_json(brief_response_json)

    brief_response.validate(enforce_required=False, required_fields=page_questions, max_day_rate=service_max_day_rate)

    audit = AuditEvent(
        audit_type=AuditTypes.update_brief_response,
        user=updater_json['updated_by'],
        data={
            'briefResponseId': brief_response.id,
            'briefResponseData': brief_response_json,
            'supplierId': supplier.supplier_id,
        },
        db_object=brief_response,
    )

    db.session.add(brief_response)
    db.session.add(audit)

    try:
        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, format(e))

    return single_result_response(RESOURCE_NAME, brief_response), 200

@main.route('/brief-responses/<int:brief_response_id>/submit', methods=['POST'])
def submit_brief_response(brief_response_id):
    updater_json = validate_and_return_updater_request()

    brief_response = BriefResponse.query.filter(
        BriefResponse.id == brief_response_id
    ).first_or_404()

    brief = brief_response.brief
    supplier = brief_response.supplier
    brief_service = get_supplier_service_eligible_for_brief(supplier, brief)
    if not brief_service:
        abort(400, "Supplier is not eligible to apply to this brief")

    if brief.status != 'live':
        abort(400, "Brief must have 'live' status for the brief response to be submitted")

    if brief.framework.status not in ['live', 'expired']:
        abort(400, "Brief framework must be live or expired")

    brief_role = brief.data["specialistRole"] if brief.lot.slug == "digital-specialists" else None
    service_max_day_rate = brief_service.data[brief_role + "PriceMax"] if brief_role else None

    brief_response.validate(max_day_rate=service_max_day_rate)

    brief_response.submitted_at = datetime.utcnow()

    audit = AuditEvent(
        audit_type=AuditTypes.submit_brief_response,
        user=updater_json['updated_by'],
        data={
            'briefResponseId': brief_response.id,
            'supplierId': supplier.supplier_id,
        },
        db_object=brief_response,
    )

    db.session.add(brief_response)
    db.session.add(audit)

    try:
        db.session.commit()
    except IntegrityError as e:
        db.session.rollback()
        abort(400, format(e))

    return single_result_response(RESOURCE_NAME, brief_response), 200

@main.route('/brief-responses/<int:brief_response_id>', methods=['GET'])
def get_brief_response(brief_response_id):
    brief_response = BriefResponse.query.filter(
        BriefResponse.id == brief_response_id
    ).first_or_404()

    return single_result_response(RESOURCE_NAME, brief_response), 200

@main.route('/brief-responses', methods=['GET'])
def list_brief_responses():
    page = get_valid_page_or_1()
    brief_id = get_int_or_400(request.args, 'brief_id')
    supplier_id = get_int_or_400(request.args, 'supplier_id')
    awarded_at = request.args.get('awarded_at')

    if request.args.get('status'):
        statuses = request.args['status'].split(',')
    else:
        statuses = COMPLETED_BRIEF_RESPONSE_STATUSES
    brief_responses = BriefResponse.query.filter(BriefResponse.status.in_(statuses))

    if supplier_id is not None:
        brief_responses = brief_responses.filter(BriefResponse.supplier_id == supplier_id)

    if brief_id is not None:
        brief_responses = brief_responses.filter(BriefResponse.brief_id == brief_id)

    if awarded_at is not None:
        day_start = datetime.strptime(awarded_at, DATE_FORMAT)
        day_end = datetime(day_start.year, day_start.month, day_start.day, 23, 59, 59, 999999)
        # Inclusive date range filtering
        brief_responses = brief_responses.filter(BriefResponse.awarded_at.between(day_start, day_end))

    brief_responses = brief_responses.options(
        db.defaultload(BriefResponse.brief).defaultload(Brief.framework).lazyload("*"),
        db.defaultload(BriefResponse.brief).defaultload(Brief.lot).lazyload("*"),
        db.defaultload(BriefResponse.brief).defaultload(Brief.awarded_brief_response).lazyload("*"),
        db.defaultload(BriefResponse.supplier).lazyload("*"),
    )

    if request.args.get('framework'):
        brief_responses = brief_responses.join(BriefResponse.brief).join(Brief.framework).filter(
            Brief.framework.has(Framework.slug.in_(
                framework_slug.strip() for framework_slug in request.args["framework"].split(",")
            ))
        )

    if brief_id or supplier_id:
        return list_result_response(RESOURCE_NAME, brief_responses), 200

    return paginated_result_response(
        result_name=RESOURCE_NAME,
        results_query=brief_responses,
        page=page,
        per_page=current_app.config['DM_API_BRIEF_RESPONSES_PAGE_SIZE'],
        endpoint='.list_brief_responses',
        request_args=request.args
    ), 200
<|endoftext|>


<commit_before>from django.contrib.gis.db import models
from django.contrib.gis.geos import GEOSGeometry, Polygon

from model_utils.managers import InheritanceManager

from osmaxx.excerptexport.utils.upload_to import get_private_upload_storage
from osmaxx.utilities.dict_helpers import are_all_keys_in

class BoundingGeometry(models.Model):
    @property
    def type(self):
        return type(self).__name__

    @property
    def geometry(self):
        raise NotImplementedError

    @property
    def extent(self):
        return self.subclass_instance.geometry.extent

    @property
    def type_of_geometry(self):
        return str(self.subclass_instance.geometry.__class__.__name__)

    @property
    def subclass_instance(self):
        # TODO: don't make an extra query for this
        return BoundingGeometry.objects.get_subclass(pk=self.id)

    objects = InheritanceManager()

class OsmosisPolygonFilterBoundingGeometry(BoundingGeometry):
    """
    Bounding geometry based on a 'Osmosis polygon filter file format' file.
    """
    polygon_file = models.FileField(storage=get_private_upload_storage())

    def __str__(self):
        return 'Polygon file: ' + self.polygon_file.name

class BBoxBoundingGeometry(BoundingGeometry):
    def __init__(self, *args, **kwargs):
        attribute_names = ['north', 'east', 'south', 'west']
        if are_all_keys_in(kwargs, attribute_names) \
                and not are_all_keys_in(kwargs, ['south_west', 'north_east']):
            kwargs['south_west'] = GEOSGeometry('POINT(%s %s)' % (kwargs.pop('west'), kwargs.pop('south')))
            kwargs['north_east'] = GEOSGeometry('POINT(%s %s)' % (kwargs.pop('east'), kwargs.pop('north')))
        super().__init__(*args, **kwargs)

    south_west = models.PointField()
    north_east = models.PointField()

    @property
    def west(self):
        return self.south_west[0]

    @property
    def east(self):
        return self.north_east[0]

    @property
    def north(self):
        return self.north_east[1]

    @property
    def south(self):
        return self.south_west[1]

    @property
    def geometry(self):
        polygon = Polygon([
            self.south_west,
            GEOSGeometry('POINT(%s %s)' % (self.west, self.north)),
            self.north_east,
            GEOSGeometry('POINT(%s %s)' % (self.east, self.south)),
            self.south_west
        ])
        return GEOSGeometry(polygon)

    @staticmethod
    def create_from_bounding_box_coordinates(north, east, south, west):
        south_west = GEOSGeometry('POINT(%s %s)' % (west, south))
        north_east = GEOSGeometry('POINT(%s %s)' % (east, north))
        return BBoxBoundingGeometry.objects.create(south_west=south_west, north_east=north_east)

    # overriding the default manager with a GeoManager instance.
    # required to perform spatial queries
    objects = models.GeoManager()

    def __str__(self):
        points = []
        for coordinates in self.geometry[0]:
            points.append('(' + ', '.join([str(round(coordinate, 5)) for coordinate in coordinates]) + ')')
        return 'Bounding box' + ': ' + ', '.join(points)
<commit_msg>bugfix: use bounding geometry type instead of geometry type<commit_after>from django.contrib.gis.db import models
from django.contrib.gis.geos import GEOSGeometry, Polygon

from model_utils.managers import InheritanceManager

from osmaxx.excerptexport.utils.upload_to import get_private_upload_storage
from osmaxx.utilities.dict_helpers import are_all_keys_in

class BoundingGeometry(models.Model):
    @property
    def type(self):
        return type(self).__name__

    @property
    def geometry(self):
        raise NotImplementedError

    @property
    def extent(self):
        return self.subclass_instance.geometry.extent

    @property
    def type_of_geometry(self):
        return str(self.subclass_instance.__class__.__name__)

    @property
    def subclass_instance(self):
        # TODO: don't make an extra query for this
        return BoundingGeometry.objects.get_subclass(pk=self.id)

    objects = InheritanceManager()

class OsmosisPolygonFilterBoundingGeometry(BoundingGeometry):
    """
    Bounding geometry based on a 'Osmosis polygon filter file format' file.
    """
    polygon_file = models.FileField(storage=get_private_upload_storage())

    def __str__(self):
        return 'Polygon file: ' + self.polygon_file.name

class BBoxBoundingGeometry(BoundingGeometry):
    def __init__(self, *args, **kwargs):
        attribute_names = ['north', 'east', 'south', 'west']
        if are_all_keys_in(kwargs, attribute_names) \
                and not are_all_keys_in(kwargs, ['south_west', 'north_east']):
            kwargs['south_west'] = GEOSGeometry('POINT(%s %s)' % (kwargs.pop('west'), kwargs.pop('south')))
            kwargs['north_east'] = GEOSGeometry('POINT(%s %s)' % (kwargs.pop('east'), kwargs.pop('north')))
        super().__init__(*args, **kwargs)

    south_west = models.PointField()
    north_east = models.PointField()

    @property
    def west(self):
        return self.south_west[0]

    @property
    def east(self):
        return self.north_east[0]

    @property
    def north(self):
        return self.north_east[1]

    @property
    def south(self):
        return self.south_west[1]

    @property
    def geometry(self):
        polygon = Polygon([
            self.south_west,
            GEOSGeometry('POINT(%s %s)' % (self.west, self.north)),
            self.north_east,
            GEOSGeometry('POINT(%s %s)' % (self.east, self.south)),
            self.south_west
        ])
        return GEOSGeometry(polygon)

    @staticmethod
    def create_from_bounding_box_coordinates(north, east, south, west):
        south_west = GEOSGeometry('POINT(%s %s)' % (west, south))
        north_east = GEOSGeometry('POINT(%s %s)' % (east, north))
        return BBoxBoundingGeometry.objects.create(south_west=south_west, north_east=north_east)

    # overriding the default manager with a GeoManager instance.
    # required to perform spatial queries
    objects = models.GeoManager()

    def __str__(self):
        points = []
        for coordinates in self.geometry[0]:
            points.append('(' + ', '.join([str(round(coordinate, 5)) for coordinate in coordinates]) + ')')
        return 'Bounding box' + ': ' + ', '.join(points)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp.osv import fields,osv
from openerp import tools
from openerp.addons.decimal_precision import decimal_precision as dp

class report_analytic_account_close(osv.osv):
    _name = "report.analytic.account.close"
    _description = "Analytic account to close"
    _auto = False
    _columns = {
        'name': fields.many2one('account.analytic.account', 'Analytic account', readonly=True),
        'state': fields.char('Status', readonly=True),
        'partner_id': fields.many2one('res.partner', 'Partner', readonly=True),
        'quantity': fields.float('Quantity', readonly=True),
        'quantity_max': fields.float('Max. Quantity', readonly=True),
        'balance': fields.float('Balance', readonly=True),
        'date_deadline': fields.date('Deadline', readonly=True),
    }
    def init(self, cr):
        tools.drop_view_if_exists(cr, 'report_analytic_account_close')
        cr.execute("""
            create or replace view report_analytic_account_close as (
                select
                    a.id as id,
                    a.id as name,
                    a.state as state,
                    sum(l.unit_amount) as quantity,
                    sum(l.amount) as balance,
                    a.partner_id as partner_id,
                    a.quantity_max as quantity_max,
                    a.date as date_deadline
                from
                    account_analytic_line l
                right join
                    account_analytic_account a on (l.account_id=a.id)
                group by
                    a.id,a.state, a.quantity_max,a.date,a.partner_id
                having
                    (a.quantity_max>0 and (sum(l.unit_amount)>=a.quantity_max)) or
                    a.date <= current_date
            )""")

class report_account_analytic_line_to_invoice(osv.osv):
    _name = "report.account.analytic.line.to.invoice"
    _description = "Analytic lines to invoice report"
    _auto = False
    _columns = {
        'name': fields.char('Year', required=False, readonly=True),
        'product_id':fields.many2one('product.product', 'Product', readonly=True),
        'account_id':fields.many2one('account.analytic.account', 'Analytic account', readonly=True),
        'product_uom_id':fields.many2one('product.uom', 'Unit of Measure', readonly=True),
        'unit_amount': fields.float('Units', readonly=True),
        'sale_price': fields.float('Sale price', readonly=True, digits_compute=dp.get_precision('Product Price')),
        'amount': fields.float('Amount', readonly=True, digits_compute=dp.get_precision('Account')),
        'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'), ('05','May'), ('06','June'),
                                  ('07','July'), ('08','August'), ('09','September'), ('10','October'), ('11','November'), ('12','December')],'Month', readonly=True),
    }
    _order = 'name desc, product_id asc, account_id asc'

    def init(self, cr):
        tools.drop_view_if_exists(cr, 'report_account_analytic_line_to_invoice')
        cr.execute("""
            CREATE OR REPLACE VIEW report_account_analytic_line_to_invoice AS (
                SELECT
                    DISTINCT(to_char(l.date,'MM')) as month,
                    to_char(l.date, 'YYYY') as name,
                    MIN(l.id) AS id,
                    l.product_id,
                    l.account_id,
                    SUM(l.amount) AS amount,
                    SUM(l.unit_amount*t.list_price) AS sale_price,
                    SUM(l.unit_amount) AS unit_amount,
                    l.product_uom_id
                FROM
                    account_analytic_line l
                left join
                    product_product p on (l.product_id=p.id)
                left join
                    product_template t on (p.product_tmpl_id=t.id)
                WHERE
                    (invoice_id IS NULL) and (to_invoice IS NOT NULL)
                GROUP BY
                    to_char(l.date, 'YYYY'), to_char(l.date,'MM'), product_id, product_uom_id, account_id
            )
        """)

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

<commit_msg>[IMP] hr_timesheet_invoice: Declare explicitely the field in the view<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp.osv import fields,osv
from openerp import tools
from openerp.addons.decimal_precision import decimal_precision as dp

class report_analytic_account_close(osv.osv):
    _name = "report.analytic.account.close"
    _description = "Analytic account to close"
    _auto = False
    _columns = {
        'name': fields.many2one('account.analytic.account', 'Analytic account', readonly=True),
        'state': fields.char('Status', readonly=True),
        'partner_id': fields.many2one('res.partner', 'Partner', readonly=True),
        'quantity': fields.float('Quantity', readonly=True),
        'quantity_max': fields.float('Max. Quantity', readonly=True),
        'balance': fields.float('Balance', readonly=True),
        'date_deadline': fields.date('Deadline', readonly=True),
    }
    def init(self, cr):
        tools.drop_view_if_exists(cr, 'report_analytic_account_close')
        cr.execute("""
            create or replace view report_analytic_account_close as (
                select
                    a.id as id,
                    a.id as name,
                    a.state as state,
                    sum(l.unit_amount) as quantity,
                    sum(l.amount) as balance,
                    a.partner_id as partner_id,
                    a.quantity_max as quantity_max,
                    a.date as date_deadline
                from
                    account_analytic_line l
                right join
                    account_analytic_account a on (l.account_id=a.id)
                group by
                    a.id,a.state, a.quantity_max,a.date,a.partner_id
                having
                    (a.quantity_max>0 and (sum(l.unit_amount)>=a.quantity_max)) or
                    a.date <= current_date
            )""")

class report_account_analytic_line_to_invoice(osv.osv):
    _name = "report.account.analytic.line.to.invoice"
    _description = "Analytic lines to invoice report"
    _auto = False
    _columns = {
        'name': fields.char('Year', required=False, readonly=True),
        'product_id':fields.many2one('product.product', 'Product', readonly=True),
        'account_id':fields.many2one('account.analytic.account', 'Analytic account', readonly=True),
        'product_uom_id':fields.many2one('product.uom', 'Unit of Measure', readonly=True),
        'unit_amount': fields.float('Units', readonly=True),
        'sale_price': fields.float('Sale price', readonly=True, digits_compute=dp.get_precision('Product Price')),
        'amount': fields.float('Amount', readonly=True, digits_compute=dp.get_precision('Account')),
        'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'), ('05','May'), ('06','June'),
                                  ('07','July'), ('08','August'), ('09','September'), ('10','October'), ('11','November'), ('12','December')],'Month', readonly=True),
    }
    _order = 'name desc, product_id asc, account_id asc'

    def init(self, cr):
        tools.drop_view_if_exists(cr, 'report_account_analytic_line_to_invoice')
        cr.execute("""
            CREATE OR REPLACE VIEW report_account_analytic_line_to_invoice AS (
                SELECT
                    DISTINCT(to_char(l.date,'MM')) as month,
                    to_char(l.date, 'YYYY') as name,
                    MIN(l.id) AS id,
                    l.product_id,
                    l.account_id,
                    SUM(l.amount) AS amount,
                    SUM(l.unit_amount*t.list_price) AS sale_price,
                    SUM(l.unit_amount) AS unit_amount,
                    l.product_uom_id
                FROM
                    account_analytic_line l
                left join
                    product_product p on (l.product_id=p.id)
                left join
                    product_template t on (p.product_tmpl_id=t.id)
                WHERE
                    (invoice_id IS NULL) and (to_invoice IS NOT NULL)
                GROUP BY
                    to_char(l.date, 'YYYY'), to_char(l.date,'MM'), l.product_id, l.product_uom_id, l.account_id
            )
        """)

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

<|endoftext|>


<commit_before>#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you 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.
#
# Note: Any AirflowException raised is expected to cause the TaskInstance
#       to be marked in an ERROR state
"""Exceptions used by Airflow"""
from typing import List, NamedTuple, Optional

from airflow.utils.code_utils import prepare_code_snippet
from airflow.utils.platform import is_tty

class AirflowException(Exception):
    """
    Base class for all Airflow's errors.
    Each custom exception should be derived from this class
    """
    status_code = 500

class AirflowBadRequest(AirflowException):
    """Raise when the application or server cannot handle the request"""
    status_code = 400

class AirflowNotFoundException(AirflowException):
    """Raise when the requested object/resource is not available in the system"""
    status_code = 404

class AirflowConfigException(AirflowException):
    """Raise when there is configuration problem"""

class AirflowSensorTimeout(AirflowException):
    """Raise when there is a timeout on sensor polling"""

class AirflowRescheduleException(AirflowException):
    """
    Raise when the task should be re-scheduled at a later time.

    :param reschedule_date: The date when the task should be rescheduled
    :type reschedule_date: datetime.datetime
    """
    def __init__(self, reschedule_date):
        super().__init__()
        self.reschedule_date = reschedule_date

class InvalidStatsNameException(AirflowException):
    """Raise when name of the stats is invalid"""

class AirflowTaskTimeout(AirflowException):
    """Raise when the task execution times-out"""

class AirflowWebServerTimeout(AirflowException):
    """Raise when the web server times out"""

class AirflowSkipException(AirflowException):
    """Raise when the task should be skipped"""

class AirflowFailException(AirflowException):
    """Raise when the task should be failed without retrying"""

class AirflowDagCycleException(AirflowException):
    """Raise when there is a cycle in Dag definition"""

class DagNotFound(AirflowNotFoundException):
    """Raise when a DAG is not available in the system"""

class DagCodeNotFound(AirflowNotFoundException):
    """Raise when a DAG code is not available in the system"""

class DagRunNotFound(AirflowNotFoundException):
    """Raise when a DAG Run is not available in the system"""

class DagRunAlreadyExists(AirflowBadRequest):
    """Raise when creating a DAG run for DAG which already has DAG run entry"""

class DagFileExists(AirflowBadRequest):
    """Raise when a DAG ID is still in DagBag i.e., DAG file is in DAG folder"""

class DuplicateTaskIdFound(AirflowException):
    """Raise when a Task with duplicate task_id is defined in the same DAG"""

class TaskNotFound(AirflowNotFoundException):
    """Raise when a Task is not available in the system"""

class TaskInstanceNotFound(AirflowNotFoundException):
    """Raise when a Task Instance is not available in the system"""

class PoolNotFound(AirflowNotFoundException):
    """Raise when a Pool is not available in the system"""

class NoAvailablePoolSlot(AirflowException):
    """Raise when there is not enough slots in pool"""

class DagConcurrencyLimitReached(AirflowException):
    """Raise when DAG concurrency limit is reached"""

class TaskConcurrencyLimitReached(AirflowException):
    """Raise when task concurrency limit is reached"""

class BackfillUnfinished(AirflowException):
    """
    Raises when not all tasks succeed in backfill.

    :param message: The human-readable description of the exception
    :zparam ti_status: The information about all task statuses
    """
    def __init__(self, message, ti_status):
        super().__init__(message)
        self.ti_status = ti_status

class FileSyntaxError(NamedTuple):
    """Information about a single error in a file."""
    line_no: Optional[int]
    message: str

    def __str__(self):
        return f"{self.message}. Line number: s{str(self.line_no)},"

class AirflowFileParseException(AirflowException):
    """
    Raises when connection or variable file can not be parsed

    :param msg: The human-readable description of the exception
    :param file_path: A processed file that contains errors
    :param parse_errors: File syntax errors
    """
    def __init__(self, msg: str, file_path: str, parse_errors: List[FileSyntaxError]) -> None:
        super().__init__(msg)
        self.msg = msg
        self.file_path = file_path
        self.parse_errors = parse_errors

    def __str__(self):
        result = f"{self.msg}\nFilename: {self.file_path}\n\n"

        for error_no, parse_error in enumerate(self.parse_errors, 1):
            result += "=" * 20 + f" Parse error {error_no:3} " + "=" * 20 + "\n"
            result += f"{parse_error.message}\n"
            if parse_error.line_no:
                result += f"Line number:  {parse_error.line_no}\n"
                if parse_error.line_no and is_tty():
                    result += "\n" + prepare_code_snippet(self.file_path, parse_error.line_no) + "\n"

        return result
<commit_msg>Fix docstrings in exceptions.py (#9622)<commit_after>#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you 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.
#
# Note: Any AirflowException raised is expected to cause the TaskInstance
#       to be marked in an ERROR state
"""Exceptions used by Airflow"""
from typing import List, NamedTuple, Optional

from airflow.utils.code_utils import prepare_code_snippet
from airflow.utils.platform import is_tty

class AirflowException(Exception):
    """
    Base class for all Airflow's errors.
    Each custom exception should be derived from this class
    """
    status_code = 500

class AirflowBadRequest(AirflowException):
    """Raise when the application or server cannot handle the request"""
    status_code = 400

class AirflowNotFoundException(AirflowException):
    """Raise when the requested object/resource is not available in the system"""
    status_code = 404

class AirflowConfigException(AirflowException):
    """Raise when there is configuration problem"""

class AirflowSensorTimeout(AirflowException):
    """Raise when there is a timeout on sensor polling"""

class AirflowRescheduleException(AirflowException):
    """
    Raise when the task should be re-scheduled at a later time.

    :param reschedule_date: The date when the task should be rescheduled
    :type reschedule_date: datetime.datetime
    """
    def __init__(self, reschedule_date):
        super().__init__()
        self.reschedule_date = reschedule_date

class InvalidStatsNameException(AirflowException):
    """Raise when name of the stats is invalid"""

class AirflowTaskTimeout(AirflowException):
    """Raise when the task execution times-out"""

class AirflowWebServerTimeout(AirflowException):
    """Raise when the web server times out"""

class AirflowSkipException(AirflowException):
    """Raise when the task should be skipped"""

class AirflowFailException(AirflowException):
    """Raise when the task should be failed without retrying"""

class AirflowDagCycleException(AirflowException):
    """Raise when there is a cycle in Dag definition"""

class DagNotFound(AirflowNotFoundException):
    """Raise when a DAG is not available in the system"""

class DagCodeNotFound(AirflowNotFoundException):
    """Raise when a DAG code is not available in the system"""

class DagRunNotFound(AirflowNotFoundException):
    """Raise when a DAG Run is not available in the system"""

class DagRunAlreadyExists(AirflowBadRequest):
    """Raise when creating a DAG run for DAG which already has DAG run entry"""

class DagFileExists(AirflowBadRequest):
    """Raise when a DAG ID is still in DagBag i.e., DAG file is in DAG folder"""

class DuplicateTaskIdFound(AirflowException):
    """Raise when a Task with duplicate task_id is defined in the same DAG"""

class TaskNotFound(AirflowNotFoundException):
    """Raise when a Task is not available in the system"""

class TaskInstanceNotFound(AirflowNotFoundException):
    """Raise when a Task Instance is not available in the system"""

class PoolNotFound(AirflowNotFoundException):
    """Raise when a Pool is not available in the system"""

class NoAvailablePoolSlot(AirflowException):
    """Raise when there is not enough slots in pool"""

class DagConcurrencyLimitReached(AirflowException):
    """Raise when DAG concurrency limit is reached"""

class TaskConcurrencyLimitReached(AirflowException):
    """Raise when task concurrency limit is reached"""

class BackfillUnfinished(AirflowException):
    """
    Raises when not all tasks succeed in backfill.

    :param message: The human-readable description of the exception
    :param ti_status: The information about all task statuses
    """
    def __init__(self, message, ti_status):
        super().__init__(message)
        self.ti_status = ti_status

class FileSyntaxError(NamedTuple):
    """Information about a single error in a file."""
    line_no: Optional[int]
    message: str

    def __str__(self):
        return f"{self.message}. Line number: s{str(self.line_no)},"

class AirflowFileParseException(AirflowException):
    """
    Raises when connection or variable file can not be parsed

    :param msg: The human-readable description of the exception
    :param file_path: A processed file that contains errors
    :param parse_errors: File syntax errors
    """
    def __init__(self, msg: str, file_path: str, parse_errors: List[FileSyntaxError]) -> None:
        super().__init__(msg)
        self.msg = msg
        self.file_path = file_path
        self.parse_errors = parse_errors

    def __str__(self):
        result = f"{self.msg}\nFilename: {self.file_path}\n\n"

        for error_no, parse_error in enumerate(self.parse_errors, 1):
            result += "=" * 20 + f" Parse error {error_no:3} " + "=" * 20 + "\n"
            result += f"{parse_error.message}\n"
            if parse_error.line_no:
                result += f"Line number:  {parse_error.line_no}\n"
                if parse_error.line_no and is_tty():
                    result += "\n" + prepare_code_snippet(self.file_path, parse_error.line_no) + "\n"

        return result
<|endoftext|>


<commit_before>from django.utils import simplejson as json
from django.core.serializers.json import DjangoJSONEncoder

from django.http import HttpResponse, HttpResponseBadRequest, Http404

from ajaxuploader.backends.local import LocalUploadBackend

class AjaxFileUploader(object):
    def __init__(self, backend=None, **kwargs):
        if backend is None:
            backend = LocalUploadBackend
        self.get_backend = lambda: backend(**kwargs)

    def __call__(self, request, *args, **kwargs):
        return self._ajax_upload(request, *args, **kwargs)

    def _ajax_upload(self, request, *args, **kwargs):
        if request.method == "POST":
            if request.is_ajax():
                # the file is stored raw in the request
                upload = request
                is_raw = True
                # AJAX Upload will pass the filename in the querystring if it
                # is the "advanced" ajax upload
                try:
                    filename = request.GET['qqfile']
                except KeyError:
                    return HttpResponseBadRequest("AJAX request not valid")
            # not an ajax upload, so it was the "basic" iframe version with
            # submission via form
            else:
                is_raw = False
                if len(request.FILES) == 1:
                    # FILES is a dictionary in Django but Ajax Upload gives
                    # the uploaded file an ID based on a random number, so it
                    # cannot be guessed here in the code. Rather than editing
                    # Ajax Upload to pass the ID in the querystring, observe
                    # that each upload is a separate request, so FILES should
                    # only have one entry. Thus, we can just grab the first
                    # (and only) value in the dict.
                    upload = request.FILES.values()[0]
                else:
                    raise Http404("Bad Upload")
                filename = upload.name

            backend = self.get_backend()

            # custom filename handler
            filename = (backend.update_filename(request, filename, *args, **kwargs)
                        or filename)
            # save the file
            backend.setup(filename, *args, **kwargs)
            success = backend.upload(upload, filename, is_raw, *args, **kwargs)
            # callback
            extra_context = backend.upload_complete(request, filename, *args, **kwargs)

            # let Ajax Upload know whether we saved it or not
            ret_json = {'success': success, 'filename': filename}
            if extra_context is not None:
                ret_json.update(extra_context)

            # although "application/json" is the correct content type, IE throws a fit
            return HttpResponse(json.dumps(ret_json, cls=DjangoJSONEncoder), content_type='text/html; charset=utf-8')
        else:
            return HttpResponseBadRequest("Only POST requests accepted")<commit_msg>Send the proper 405 HTTP response<commit_after>from django.utils import simplejson as json
from django.core.serializers.json import DjangoJSONEncoder

from django.http import HttpResponse, HttpResponseBadRequest, Http404, HttpResponseNotAllowed

from ajaxuploader.backends.local import LocalUploadBackend

class AjaxFileUploader(object):
    def __init__(self, backend=None, **kwargs):
        if backend is None:
            backend = LocalUploadBackend
        self.get_backend = lambda: backend(**kwargs)

    def __call__(self, request, *args, **kwargs):
        return self._ajax_upload(request, *args, **kwargs)

    def _ajax_upload(self, request, *args, **kwargs):
        if request.method == "POST":
            if request.is_ajax():
                # the file is stored raw in the request
                upload = request
                is_raw = True
                # AJAX Upload will pass the filename in the querystring if it
                # is the "advanced" ajax upload
                try:
                    filename = request.GET['qqfile']
                except KeyError:
                    return HttpResponseBadRequest("AJAX request not valid")
            # not an ajax upload, so it was the "basic" iframe version with
            # submission via form
            else:
                is_raw = False
                if len(request.FILES) == 1:
                    # FILES is a dictionary in Django but Ajax Upload gives
                    # the uploaded file an ID based on a random number, so it
                    # cannot be guessed here in the code. Rather than editing
                    # Ajax Upload to pass the ID in the querystring, observe
                    # that each upload is a separate request, so FILES should
                    # only have one entry. Thus, we can just grab the first
                    # (and only) value in the dict.
                    upload = request.FILES.values()[0]
                else:
                    raise Http404("Bad Upload")
                filename = upload.name

            backend = self.get_backend()

            # custom filename handler
            filename = (backend.update_filename(request, filename, *args, **kwargs)
                        or filename)
            # save the file
            backend.setup(filename, *args, **kwargs)
            success = backend.upload(upload, filename, is_raw, *args, **kwargs)
            # callback
            extra_context = backend.upload_complete(request, filename, *args, **kwargs)

            # let Ajax Upload know whether we saved it or not
            ret_json = {'success': success, 'filename': filename}
            if extra_context is not None:
                ret_json.update(extra_context)

            # although "application/json" is the correct content type, IE throws a fit
            return HttpResponse(json.dumps(ret_json, cls=DjangoJSONEncoder), content_type='text/html; charset=utf-8')
        else:
            response = HttpResponseNotAllowed(['POST'])
            response.write("ERROR: Only POST allowed")
            return response<|endoftext|>


<commit_before>import numpy as np
import matplotlib.pyplot as plt
from time import time

from tensorpac.utils import PacSignals
from tensorpac import Pac
from brainpipe.feature import erpac

ndatasets = 300
x1, tvec = PacSignals(fpha=10, famp=100, ndatasets=ndatasets)
x2, tvec = PacSignals(fpha=20, famp=150, ndatasets=ndatasets)
x = np.concatenate((x1, x2), axis=1)

print('DATASET : ', x.shape)

fpha = [8, 15]
famp = [80, 120]

t = time()
p = Pac(idpac=(5, 0, 0), fpha=fpha, famp=famp, dcomplex='hilbert')
xpac, spac = p.fit(1024, x, x, axis=1, nperm=10, traxis=0, njobs=-1, nblocks=10)
print('Tensorpac : ', time()-t)

t = time()
e = erpac(1024, 2048, pha_f=fpha, amp_f=famp)
bpac = np.squeeze(e.get(x.T, x.T, n_perm=100))[0]
print('Brainpipe : ', time()-t)
print(bpac.shape)

plt.subplot(1, 2, 1)
plt.plot(np.squeeze(xpac))
plt.axis('tight')

plt.subplot(1, 2, 2)
plt.plot(bpac)
plt.axis('tight')

plt.show()<commit_msg>Change erpac example<commit_after>import numpy as np
import matplotlib.pyplot as plt
from time import time

from tensorpac.utils import PacSignals
from tensorpac import Pac
from brainpipe.feature import erpac

ndatasets = 300
x1, tvec = PacSignals(fpha=10, famp=100, ndatasets=ndatasets, noise=1, tmax=2)
x2, tvec = PacSignals(fpha=20, famp=150, ndatasets=ndatasets, noise=1, tmax=2)
x = np.concatenate((x1, x2), axis=1) + 5.

print('DATASET : ', x.shape)

fpha = [9, 11]
famp = [90, 110]

t = time()
p = Pac(idpac=(6, 0, 0), fpha=fpha, famp=famp, dcomplex='hilbert', width=12, nblocks=10)
xpac, spac = p.fit(x, x, axis=1, nperm=10, traxis=0, njobs=-1)
print(xpac.shape)
# 0/0
print('Tensorpac : ', time()-t)

# t = time()
# e = erpac(1024, 2048, pha_f=fpha, amp_f=famp)
# bpac = np.squeeze(e.get(x.T, x.T, n_perm=10))[0]
# print('Brainpipe : ', time()-t)
# print(bpac.shape)

# 0/0
plt.subplot(1, 2, 1)
plt.plot(np.squeeze(xpac))
plt.axis('tight')

# plt.subplot(1, 2, 2)
# plt.plot(bpac)
# plt.axis('tight')

plt.show()<|endoftext|>