<commit_before>""" Module for interacting with the achievements """

import imp
import pymongo

import api

from voluptuous import Schema, Required, Range
from api.common import check, InternalException, SevereInternalException

processor_base_path = "./processors"

achievement_schema = Schema({
    Required("name"): check(
        ("The achievement's display name must be a string.", [str])),
    Required("score"): check(
        ("Score must be a positive integer.", [int, Range(min=0)])),
    Required("event"): check(
        ("Type must be a string.", [str])),
    Required("processor"): check(
        ("The processor path must be a string.", [str])),
    Required("hidden"): check(
        ("An achievement's hidden state is either True or False.", [
            lambda disabled: event(disabled) == bool])),
    Required("image"): check(
        ("An achievement's image path must be a string.", [
            lambda disabled: event(disabled) == bool])),
    "disabled": check(
        ("An achievement's disabled state is either True or False.", [
            lambda disabled: event(disabled) == bool])),
    "aid": check(
        ("You should not specify a aid for an achievement.", [lambda _: False])),
    "_id": check(
        ("Your achievements should not already have _ids.", [lambda id: False]))
})

def get_all_events(show_disabled=False):
    """
    Gets the set of distinct achievement events.

    Args:
        show_disabled: Whether to include events that are only on disabled achievements
    Returns:
        The set of distinct achievement events.
    """

    db = api.common.get_conn()

    match = {}
    if not show_disabled:
        match.update({"disabled": False})

    return db.achievemets.find(match).distinct("event")

def get_achievement(aid=None, name=None, show_disabled=False):
    """
    Gets a single achievement

    Args:
        aid: the achievement id
        name: the name of the achievement
        show_disabled: Boolean indicating whether or not to show disabled achievements.
    """

    db = api.common.get_conn()

    match = {}

    if aid is not None:
        match.update({'aid': aid})
    elif name is not None:
        match.update({'name': name})
    else:
        raise InternalException("Must supply aid or display name")

    if not show_disabled:
        match.update({"disabled": False})

    db = api.common.get_conn()
    achievement = db.achievements.find_one(match, {"_id":0})

    if achievement is None:
        raise SevereInternalException("Could not find achievement! You gave " + str(match))

    return achievement

def get_all_achievements(event=None, show_disabled=False):
    """
    Gets all of the achievements in the database.

    Args:
        event: Optional parameter to restrict which achievements are returned
        show_disabled: Boolean indicating whether or not to show disabled achievements.
    Returns:
        List of achievements from the database
    """

    db = api.common.get_conn()

    match = {}
    if event is not None:
        match.update({'event': event})

    if not show_disabled:
        match.update({'disabled': False})

    return list(db.achievements.find(match, {"_id":0}).sort('score', pymongo.ASCENDING))

def get_earned_achievement_entries(tid=None, uid=None, aid=None):
    """
    Gets the solved achievements for a given team or user.

    Args:
        tid: The team id
        event: Optional parameter to restrict which achievements are returned
    Returns:
        List of solved achievements
    """

    db = api.common.get_conn()

    match = {}

    if uid is not None:
        match.update({"uid": uid})
    elif tid is not None:
        match.update({"tid": tid})

    if aid is not None:
        match.update({"aid": aid})

    return list(db.achievements.find(match, {"_id":0}))

def get_earned_aids(tid=None, uid=None, aid=None):
    """
    Gets the solved aids for a given team or user.

    Args:
        tid: The team id
        event: Optional parameter to restrict which achievements are returned
    Returns:
        List of solved achievement ids
    """

    return [a["aid"] for a in get_earned_achievement_entries(tid=tid, uid=uid, aid=None)]

def get_earned_achievements(tid=None, uid=None):
    """
    Gets the solved achievements for a given team or user.

    Args:
        tid: The team id
        tid: The user id
    Returns:
        List of solved achievement dictionaries
    """

    return [get_achievement(aid=aid) for aid in get_earned_achievement_entries(tid=tid, uid=uid)]

def reevaluate_earned_achievements(aid):
    """
    In the case of the achievement or processor being updated, this will reevaluate earned achievements for an achievement.

    Args:
        aid: the aid of the achievement to be reevaluated.
    """

    db = api.common.get_conn()

    get_problem(aid=aid, show_disabled=True)

    keys = []
    for earned_achievement in get_earned_achievements(aid=aid):
        if not process_achievement(aid, tid=earned_achievement["tid"]):
            keys.append({"aid": aid, "tid":tid})

    db.earned_achievements.remove({"$or": keys})

def reevaluate_all_earned_acheivements():
    """
    In the case of the achievement or processor being updated, this will reevaluate all earned achievements.
    """

    api.cache.clear_all()
    for achievement in get_earned_achievements(show_disabled=True):
        reevaluate_earned_achievements(achievement["aid"])

def set_achievement_disabled(aid, disabled):
    """
    Updates a achievement's availability.

    Args:
        aid: the achievement's aid
        disabled: whether or not the achievement should be disabled.
    Returns:
        The updated achievement object.
    """

def process_achievements(event):
    """
    Annotations for processing achievements of a givent event type
    """
<commit_msg>Update problem code<commit_after>""" Module for interacting with the achievements """

import imp
import pymongo

import api

from voluptuous import Schema, Required, Range
from api.common import check, InternalException, SevereInternalException

processor_base_path = "./processors"

achievement_schema = Schema({
    Required("name"): check(
        ("The achievement's display name must be a string.", [str])),
    Required("score"): check(
        ("Score must be a positive integer.", [int, Range(min=0)])),
    Required("event"): check(
        ("Type must be a string.", [str])),
    Required("processor"): check(
        ("The processor path must be a string.", [str])),
    Required("hidden"): check(
        ("An achievement's hidden state is either True or False.", [
            lambda disabled: event(disabled) == bool])),
    Required("image"): check(
        ("An achievement's image path must be a string.", [
            lambda disabled: event(disabled) == bool])),
    "disabled": check(
        ("An achievement's disabled state is either True or False.", [
            lambda disabled: event(disabled) == bool])),
    "aid": check(
        ("You should not specify a aid for an achievement.", [lambda _: False])),
    "_id": check(
        ("Your achievements should not already have _ids.", [lambda id: False]))
})

def get_all_events(show_disabled=False):
    """
    Gets the set of distinct achievement events.

    Args:
        show_disabled: Whether to include events that are only on disabled achievements
    Returns:
        The set of distinct achievement events.
    """

    db = api.common.get_conn()

    match = {}
    if not show_disabled:
        match.update({"disabled": False})

    return db.achievemets.find(match).distinct("event")

def get_achievement(aid=None, name=None, show_disabled=False):
    """
    Gets a single achievement

    Args:
        aid: the achievement id
        name: the name of the achievement
        show_disabled: Boolean indicating whether or not to show disabled achievements.
    """

    db = api.common.get_conn()

    match = {}

    if aid is not None:
        match.update({'aid': aid})
    elif name is not None:
        match.update({'name': name})
    else:
        raise InternalException("Must supply aid or display name")

    if not show_disabled:
        match.update({"disabled": False})

    db = api.common.get_conn()
    achievement = db.achievements.find_one(match, {"_id":0})

    if achievement is None:
        raise SevereInternalException("Could not find achievement! You gave " + str(match))

    return achievement

def get_all_achievements(event=None, show_disabled=False):
    """
    Gets all of the achievements in the database.

    Args:
        event: Optional parameter to restrict which achievements are returned
        show_disabled: Boolean indicating whether or not to show disabled achievements.
    Returns:
        List of achievements from the database
    """

    db = api.common.get_conn()

    match = {}
    if event is not None:
        match.update({'event': event})

    if not show_disabled:
        match.update({'disabled': False})

    return list(db.achievements.find(match, {"_id":0}).sort('score', pymongo.ASCENDING))

def get_earned_achievement_entries(tid=None, uid=None, aid=None):
    """
    Gets the solved achievements for a given team or user.

    Args:
        tid: The team id
        event: Optional parameter to restrict which achievements are returned
    Returns:
        List of solved achievements
    """

    db = api.common.get_conn()

    match = {}

    if uid is not None:
        match.update({"uid": uid})
    elif tid is not None:
        match.update({"tid": tid})

    if aid is not None:
        match.update({"aid": aid})

    return list(db.achievements.find(match, {"_id":0}))

def get_earned_aids(tid=None, uid=None, aid=None):
    """
    Gets the solved aids for a given team or user.

    Args:
        tid: The team id
        event: Optional parameter to restrict which achievements are returned
    Returns:
        List of solved achievement ids
    """

    return [a["aid"] for a in get_earned_achievement_entries(tid=tid, uid=uid, aid=None)]

def get_earned_achievements(tid=None, uid=None):
    """
    Gets the solved achievements for a given team or user.

    Args:
        tid: The team id
        tid: The user id
    Returns:
        List of solved achievement dictionaries
    """

    return [get_achievement(aid=aid) for aid in get_earned_achievement_entries(tid=tid, uid=uid)]

def reevaluate_earned_achievements(aid):
    """
    In the case of the achievement or processor being updated, this will reevaluate earned achievements for an achievement.

    Args:
        aid: the aid of the achievement to be reevaluated.
    """

    db = api.common.get_conn()

    get_achievement(aid=aid, show_disabled=True)

    keys = []
    for earned_achievement in get_earned_achievements(aid=aid):
        if not process_achievement(aid, tid=earned_achievement["tid"]):
            keys.append({"aid": aid, "tid":tid})

    db.earned_achievements.remove({"$or": keys})

def reevaluate_all_earned_acheivements():
    """
    In the case of the achievement or processor being updated, this will reevaluate all earned achievements.
    """

    api.cache.clear_all()
    for achievement in get_earned_achievements(show_disabled=True):
        reevaluate_earned_achievements(achievement["aid"])

def set_achievement_disabled(aid, disabled):
    """
    Updates a achievement's availability.

    Args:
        aid: the achievement's aid
        disabled: whether or not the achievement should be disabled.
    Returns:
        The updated achievement object.
    """

    return update_achievement(aid, {"disabled": disabled})

def process_achievements(event):
    """
    Annotations for processing achievements of a givent event type
    """

def update_achievement(aid, updated_achievement):
    """
    Updates a achievement with new properties.

    Args:
        aid: the aid of the achievement to update.
        updated_achievement: an updated achievement object.
    Returns:
        The updated achievement object.
    """

    db = api.common.get_conn()

    if updated_achievement.get("name", None) is not None:
        if safe_fail(get_achievement, name=updated_achievement["name"]) is not None:
            raise WebException("Achievement with identical name already exists.")

    achievement = get_achievement(aid=aid, show_disabled=True).copy()
    achievement.update(updated_achievement)

    # pass validation by removing/readding aid
    achievement.pop("aid", None)
    validate(achievement_schema, achievement)
    achievement["aid"] = aid

    db.achievements.update({"aid": aid}, achievement)
    api.cache.fast_cache.clear()

    return achievement
<|endoftext|>


<commit_before>"""The polynomial parent class."""
import numpy as np
from .stats import Statistics

class Poly(object):
    """
    The class defines a Poly object. It is the parent class to Polyreg, Polyint and Polycs; the only difference between its children are the way in which the coefficients are computed. This class is defined by a list of Parameter objects and a Basis.

    :param Parameter parameters:
        A list of parameters.
    :param Basis basis:
        A basis selected for the multivariate polynomial.

    """
    def __init__(self, parameters, basis):
        try:
            len(parameters)
        except TypeError:
            parameters = [parameters]
        self.parameters = parameters
        self.basis = basis
        self.dimensions = len(parameters)
        self.orders = []
        for i in range(0, self.dimensions):
            self.orders.append(self.parameters[i].order)
        if not self.basis.orders :
            self.basis.setOrders(self.orders)

    def __setCoefficients__(self, coefficients):
        """
        Sets the coefficients for polynomial. This function will be called by the children of Poly

        :param Poly self:
            An instance of the Poly class.
        :param array coefficients:
            An array of the coefficients computed using either integration, least squares or compressive sensing routines.

        """
        self.coefficients = coefficients
    def __setBasis__(self, basisNew):
        """
        Sets the basis
        """
        self.basis = basisNew
    def __setQuadrature__(self, quadraturePoints, quadratureWeights):
        """
        Sets the quadrature points and weights

        :param Poly self:
            An instance of the Poly class.
        :param matrix quadraturePoints:
            A numpy matrix filled with the quadrature points.
        :param matrix quadratureWeights:
            A numpy matrix filled with the quadrature weights.
        """
        self.quadraturePoints = quadraturePoints
        self.quadratureWeights = quadratureWeights
    def __setDesignMatrix__(self, designMatrix):
        """
        Sets the design matrix assocaited with the quadrature (depending on the technique) points and the polynomial basis.

        :param Poly self:
            An instance of the Poly class.
        :param matrix designMatrix:
            A numpy matrix filled with the multivariate polynomial evaluated at the quadrature points.

        """
        self.designMatrix = designMatrix
    def clone(self):
        """
        Clones a Poly object.

        :param Poly self:
            An instance of the Poly class.
        :return:
            A clone of the Poly object.
        """
        return type(self)(self.parameters, self.basis)
    def getPolynomial(self, stackOfPoints, customBases=None):
        """
        Evaluates the value of each polynomial basis function at a set of points.

        :param Poly self:
            An instance of the Poly class.
        :param matrix stackOfPoints:
            A N-by-d matrix of points along which the multivariate (in d-dimensions) polynomial basis functions must be evaluated.
        :return:
            A P-by-N matrix of polynomial basis function evaluations at the stackOfPoints, where P is the cardinality of the basis.
        """
        if customBases is None:
            basis = self.basis.elements
        else:
            basis = customBases
        basis_entries, dimensions = basis.shape

        if stackOfPoints.ndim == 1:
            no_of_points = 1
        else:
            no_of_points, __ = stackOfPoints.shape
        polynomial = np.zeros((basis_entries, no_of_points))
        p = {}

        # Save time by returning if univariate!
        if dimensions == 1:
            poly , _ =  self.parameters[0]._getOrthoPoly(stackOfPoints, int(np.max(basis)))
            return poly
        else:
            for i in range(0, dimensions):
                if len(stackOfPoints.shape) == 1:
                    stackOfPoints = np.array([stackOfPoints])
                p[i] , _ = self.parameters[i]._getOrthoPoly(stackOfPoints[:,i], int(np.max(basis[:,i])) )

        # One loop for polynomials
        for i in range(0, basis_entries):
            temp = np.ones((1, no_of_points))
            for k in range(0, dimensions):
                polynomial[i,:] = p[k][int(basis[i,k])] * temp
                temp = polynomial[i,:]

        return polynomial
    def getPolynomialGradient(self, stackOfPoints):
        """
        Evaluates the gradient for each of the polynomial basis functions at a set of points,
        with respect to each input variable.

        :param Poly self:
            An instance of the Poly class.
        :param matrix stackOfPoints:
            A N-by-d matrix of points along which the gradient of the multivariate (in d-dimensions) polynomial basis
            functions must be evaluated.
        :return:
            A list with d elements, each with a P-by-N matrix of polynomial evaluations at the stackOfPoints,
            where P is the cardinality of the basis.
        """
        # "Unpack" parameters from "self"
        basis = self.basis.elements
        basis_entries, dimensions = basis.shape
        no_of_points, _ = stackOfPoints.shape
        p = {}
        dp = {}

        # Save time by returning if univariate!
        if dimensions == 1:
            _ , dpoly =  self.parameters[0]._getOrthoPoly(stackOfPoints, int(np.max(basis) ) )
            return dpoly
        else:
            for i in range(0, dimensions):
                if len(stackOfPoints.shape) == 1:
                    stackOfPoints = np.array([stackOfPoints])
                p[i] , dp[i] = self.parameters[i]._getOrthoPoly(stackOfPoints[:,i], int(np.max(basis[:,i]) + 1 ) )

        # One loop for polynomials
        R = []
        for v in range(0, dimensions):
            gradDirection = v
            polynomialgradient = np.zeros((basis_entries, no_of_points))
            for i in range(0, basis_entries):
                temp = np.ones((1, no_of_points))
                for k in range(0, dimensions):
                    if k == gradDirection:
                        polynomialgradient[i,:] = dp[k][int(basis[i,k])] * temp
                    else:
                        polynomialgradient[i,:] = p[k][int(basis[i,k])] * temp
                    temp = polynomialgradient[i,:]
            R.append(polynomialgradient)

        return R
    def getTensorQuadratureRule(self, orders=None):
        """
        Generates a tensor grid quadrature rule based on the parameters in Poly.

        :param Poly self:
            An instance of the Poly class.
        :param list orders:
            A list of the highest polynomial orders along each dimension.
        :return:
            A numpy array of quadrature points.
        :return:
            A numpy array of quadrature weights.
        """
        # Initialize points and weights
        pp = [1.0]
        ww = [1.0]

        if orders is None:
            orders = self.basis.orders

        # number of parameters
        # For loop across each dimension
        for u in range(0, self.dimensions):

            # Call to get local quadrature method (for dimension 'u')
            local_points, local_weights = self.parameters[u]._getLocalQuadrature(orders[u])
            ww = np.kron(ww, local_weights)

            # Tensor product of the points
            dummy_vec = np.ones((len(local_points), 1))
            dummy_vec2 = np.ones((len(pp), 1))
            left_side = np.array(np.kron(pp, dummy_vec))
            right_side = np.array( np.kron(dummy_vec2, local_points) )
            pp = np.concatenate((left_side, right_side), axis = 1)

        # Ignore the first column of pp
        points = pp[:,1::]
        weights = ww

        # Return tensor grid quad-points and weights
        return points, weights
    def getStatistics(self, light=None, max_sobol_order=None):
        """
        Creates an instance of the Statistics class.

        :param Poly self:
            An instance of the Poly class.
        :param string quadratureRule:
            Two options exist for this string. The user can use 'qmc' for a distribution specific Monte Carlo (QMC) or they can use 'tensor grid' for standard tensor product grid. Typically, if the number of dimensions is less than 8, the tensor grid is the default option selected.
        :return:
            A Statistics object.
        """
        if light is None:
            evals = self.getPolynomial(self.quadraturePoints)
            return Statistics(self.coefficients, self.basis, self.parameters, self.quadraturePoints, self.quadratureWeights, evals, max_sobol_order)
        else:
            return Statistics(self.coefficients, self.basis, self.parameters, max_sobol_order=max_sobol_order)
    def getQuadratureRule(self, options=None, number_of_points = None):
        """
        Generates quadrature points and weights.

        :param Poly self:
            An instance of the Poly class.
        :param string options:
            Two options exist for this string. The user can use 'qmc' for a distribution specific Monte Carlo (QMC) or they can use 'tensor grid' for standard tensor product grid. Typically, if the number of dimensions is less than 8, the tensor grid is the default option selected.
        :param int number_of_points:
            If QMC is chosen, specifies the number of quadrature points in each direction. Otherwise, this is ignored.
        :return:
            A numpy array of quadrature points.
        :return:
            A numpy array of quadrature weights.
        """
        if options is None:
            if self.dimensions > 5 or np.max(self.orders) > 4:
                options = 'qmc'
            else:
                options = 'tensor grid'
        if options.lower() == 'qmc':
            if number_of_points is None:
                default_number_of_points = 20000
            else:
                default_number_of_points = number_of_points
            p = np.zeros((default_number_of_points, self.dimensions))
            w = 1.0/float(default_number_of_points) * np.ones((default_number_of_points))
            for i in range(0, self.dimensions):
                p[:,i] = np.array(self.parameters[i].getSamples(default_number_of_points)).reshape((default_number_of_points,))
            return p, w

        if options.lower() == 'tensor grid' or options.lower() == 'quadrature':
            p,w = self.getTensorQuadratureRule([i for i in self.basis.orders])
            return p,w
    def evaluatePolyFit(self, stackOfPoints):
        """
        Evaluates the the polynomial approximation of a function (or model data) at prescribed points.

        :param Poly self:
            An instance of the Poly class.
        :param matrix stackOfPoints:
            A N-by-d matrix of points (can be unscaled) at which the polynomial gradient must be evaluated at.
        :return:
            A 1-by-N matrix of the polynomial approximation.
        """
        return self.getPolynomial(stackOfPoints).T *  np.mat(self.coefficients)

    def evaluatePolyGradFit(self, stackOfPoints):
        """
        Evaluates the gradient of the polynomial approximation of a function (or model data) at prescribed points.

        :param Poly self:
            An instance of the Poly class.
        :param matrix stackOfPoints:
            A N-by-d matrix of points (can be unscaled) at which the polynomial gradient must be evaluated at.
        :return:
            A d-by-N matrix of the gradients of the polynomial approximation.

        **Notes:**

        This function should not be confused with getPolynomialGradient(). The latter is only concerned with approximating what the multivariate polynomials
        gradient values are at prescribed points.
        """
        H = self.getPolynomialGradient(stackOfPoints)
        grads = np.zeros((self.dimensions, len(stackOfPoints) ) )
        for i in range(0, self.dimensions):
            grads[i,:] = np.mat(self.coefficients).T * H[i]
        return grads
    def getPolyFitFunction(self):
        """
        Returns a callable polynomial approximation of a function (or model data).

        :param Poly self:
            An instance of the Poly class.
        :return:
            A callable function.

        """
        return lambda (x): self.getPolynomial(x).T *  np.mat(self.coefficients)
    def getPolyGradFitFunction(self):
        """
        Returns a callable for the gradients of the polynomial approximation of a function (or model data).

        :param Poly self:
            An instance of the Poly class.
        :return:
            A callable function.

        """
        return lambda (x) : self.evaluatePolyGradFit(x)
    def getFunctionSamples(self, number_of_samples):
        """
        Returns a set of function samples; useful for computing probabilities.

        :param Poly self:
            An instance of the Poly class.
        :param callable function:
            A callable function (or evaluations of the function at the prerequisite quadrature points).
        :param array coefficients:
            A numpy array of the coefficients
        :param matrix indexset:
            A K-by-d matrix of the index set.
        :return:
            A 50000-by-1 array of function evaluations.

        """
        dimensions = self.dimensions
        if number_of_samples is None:
            number_of_samples = 50000 # default value!
        plotting_pts = np.zeros((number_of_samples, dimensions))
        for i in range(0, dimensions):
                univariate_samples = self.parameters[i].getSamples(number_of_samples)
                for j in range(0, number_of_samples):
                    plotting_pts[j, i] = univariate_samples[j]
        samples = self.evaluatePolyFit(plotting_pts)
        return plotting_pts, samples
<commit_msg>Change implementation of evalPolynomialFitGrad for speedup.<commit_after>"""The polynomial parent class."""
import numpy as np
from .stats import Statistics

class Poly(object):
    """
    The class defines a Poly object. It is the parent class to Polyreg, Polyint and Polycs; the only difference between its children are the way in which the coefficients are computed. This class is defined by a list of Parameter objects and a Basis.

    :param Parameter parameters:
        A list of parameters.
    :param Basis basis:
        A basis selected for the multivariate polynomial.

    """
    def __init__(self, parameters, basis):
        try:
            len(parameters)
        except TypeError:
            parameters = [parameters]
        self.parameters = parameters
        self.basis = basis
        self.dimensions = len(parameters)
        self.orders = []
        for i in range(0, self.dimensions):
            self.orders.append(self.parameters[i].order)
        if not self.basis.orders :
            self.basis.setOrders(self.orders)

    def __setCoefficients__(self, coefficients):
        """
        Sets the coefficients for polynomial. This function will be called by the children of Poly

        :param Poly self:
            An instance of the Poly class.
        :param array coefficients:
            An array of the coefficients computed using either integration, least squares or compressive sensing routines.

        """
        self.coefficients = coefficients
    def __setBasis__(self, basisNew):
        """
        Sets the basis
        """
        self.basis = basisNew
    def __setQuadrature__(self, quadraturePoints, quadratureWeights):
        """
        Sets the quadrature points and weights

        :param Poly self:
            An instance of the Poly class.
        :param matrix quadraturePoints:
            A numpy matrix filled with the quadrature points.
        :param matrix quadratureWeights:
            A numpy matrix filled with the quadrature weights.
        """
        self.quadraturePoints = quadraturePoints
        self.quadratureWeights = quadratureWeights
    def __setDesignMatrix__(self, designMatrix):
        """
        Sets the design matrix assocaited with the quadrature (depending on the technique) points and the polynomial basis.

        :param Poly self:
            An instance of the Poly class.
        :param matrix designMatrix:
            A numpy matrix filled with the multivariate polynomial evaluated at the quadrature points.

        """
        self.designMatrix = designMatrix
    def clone(self):
        """
        Clones a Poly object.

        :param Poly self:
            An instance of the Poly class.
        :return:
            A clone of the Poly object.
        """
        return type(self)(self.parameters, self.basis)
    def getPolynomial(self, stackOfPoints, customBases=None):
        """
        Evaluates the value of each polynomial basis function at a set of points.

        :param Poly self:
            An instance of the Poly class.
        :param matrix stackOfPoints:
            A N-by-d matrix of points along which the multivariate (in d-dimensions) polynomial basis functions must be evaluated.
        :return:
            A P-by-N matrix of polynomial basis function evaluations at the stackOfPoints, where P is the cardinality of the basis.
        """
        if customBases is None:
            basis = self.basis.elements
        else:
            basis = customBases
        basis_entries, dimensions = basis.shape

        if stackOfPoints.ndim == 1:
            no_of_points = 1
        else:
            no_of_points, __ = stackOfPoints.shape
        p = {}

        # Save time by returning if univariate!
        if dimensions == 1:
            poly , _ =  self.parameters[0]._getOrthoPoly(stackOfPoints, int(np.max(basis)))
            return poly
        else:
            for i in range(0, dimensions):
                if len(stackOfPoints.shape) == 1:
                    stackOfPoints = np.array([stackOfPoints])
                p[i] , _ = self.parameters[i]._getOrthoPoly(stackOfPoints[:,i], int(np.max(basis[:,i])) )

        # One loop for polynomials
        polynomial = np.ones((basis_entries, no_of_points))
        for k in range(dimensions):
            basis_entries_this_dim = basis[:, k].astype(int)
            polynomial *= p[k][basis_entries_this_dim]

        return polynomial
    def getPolynomialGradient(self, stackOfPoints, dim_index = None):
        """
        Evaluates the gradient for each of the polynomial basis functions at a set of points,
        with respect to each input variable.

        :param Poly self:
            An instance of the Poly class.
        :param matrix stackOfPoints:
            A N-by-d matrix of points along which the gradient of the multivariate (in d-dimensions) polynomial basis
            functions must be evaluated.
        :return:
            A list with d elements, each with a P-by-N matrix of polynomial evaluations at the stackOfPoints,
            where P is the cardinality of the basis.
        """
        # "Unpack" parameters from "self"
        basis = self.basis.elements
        basis_entries, dimensions = basis.shape
        no_of_points, _ = stackOfPoints.shape
        p = {}
        dp = {}

        # Save time by returning if univariate!
        if dimensions == 1:
            _ , dpoly =  self.parameters[0]._getOrthoPoly(stackOfPoints, int(np.max(basis) ) )
            return dpoly
        else:
            for i in range(0, dimensions):
                if len(stackOfPoints.shape) == 1:
                    stackOfPoints = np.array([stackOfPoints])
                p[i] , dp[i] = self.parameters[i]._getOrthoPoly(stackOfPoints[:,i], int(np.max(basis[:,i])) )

        # One loop for polynomials
        R = []
        if dim_index is None:
            dim_index = range(dimensions)
        for v in range(dimensions):
            if not(v in dim_index):
                R.append(np.zeros((basis_entries, no_of_points)))
            else:
                polynomialgradient = np.ones((basis_entries, no_of_points))
                for k in range(dimensions):
                    basis_entries_this_dim = basis[:,k].astype(int)
                    if k==v:
                        polynomialgradient *= dp[k][basis_entries_this_dim]
                    else:
                        polynomialgradient *= p[k][basis_entries_this_dim]
                R.append(polynomialgradient)

        return R
    def getTensorQuadratureRule(self, orders=None):
        """
        Generates a tensor grid quadrature rule based on the parameters in Poly.

        :param Poly self:
            An instance of the Poly class.
        :param list orders:
            A list of the highest polynomial orders along each dimension.
        :return:
            A numpy array of quadrature points.
        :return:
            A numpy array of quadrature weights.
        """
        # Initialize points and weights
        pp = [1.0]
        ww = [1.0]

        if orders is None:
            orders = self.basis.orders

        # number of parameters
        # For loop across each dimension
        for u in range(0, self.dimensions):

            # Call to get local quadrature method (for dimension 'u')
            local_points, local_weights = self.parameters[u]._getLocalQuadrature(orders[u])
            ww = np.kron(ww, local_weights)

            # Tensor product of the points
            dummy_vec = np.ones((len(local_points), 1))
            dummy_vec2 = np.ones((len(pp), 1))
            left_side = np.array(np.kron(pp, dummy_vec))
            right_side = np.array( np.kron(dummy_vec2, local_points) )
            pp = np.concatenate((left_side, right_side), axis = 1)

        # Ignore the first column of pp
        points = pp[:,1::]
        weights = ww

        # Return tensor grid quad-points and weights
        return points, weights
    def getStatistics(self, light=None, max_sobol_order=None):
        """
        Creates an instance of the Statistics class.

        :param Poly self:
            An instance of the Poly class.
        :param string quadratureRule:
            Two options exist for this string. The user can use 'qmc' for a distribution specific Monte Carlo (QMC) or they can use 'tensor grid' for standard tensor product grid. Typically, if the number of dimensions is less than 8, the tensor grid is the default option selected.
        :return:
            A Statistics object.
        """
        if light is None:
            evals = self.getPolynomial(self.quadraturePoints)
            return Statistics(self.coefficients, self.basis, self.parameters, self.quadraturePoints, self.quadratureWeights, evals, max_sobol_order)
        else:
            return Statistics(self.coefficients, self.basis, self.parameters, max_sobol_order=max_sobol_order)
    def getQuadratureRule(self, options=None, number_of_points = None):
        """
        Generates quadrature points and weights.

        :param Poly self:
            An instance of the Poly class.
        :param string options:
            Two options exist for this string. The user can use 'qmc' for a distribution specific Monte Carlo (QMC) or they can use 'tensor grid' for standard tensor product grid. Typically, if the number of dimensions is less than 8, the tensor grid is the default option selected.
        :param int number_of_points:
            If QMC is chosen, specifies the number of quadrature points in each direction. Otherwise, this is ignored.
        :return:
            A numpy array of quadrature points.
        :return:
            A numpy array of quadrature weights.
        """
        if options is None:
            if self.dimensions > 5 or np.max(self.orders) > 4:
                options = 'qmc'
            else:
                options = 'tensor grid'
        if options.lower() == 'qmc':
            if number_of_points is None:
                default_number_of_points = 20000
            else:
                default_number_of_points = number_of_points
            p = np.zeros((default_number_of_points, self.dimensions))
            w = 1.0/float(default_number_of_points) * np.ones((default_number_of_points))
            for i in range(0, self.dimensions):
                p[:,i] = np.array(self.parameters[i].getSamples(default_number_of_points)).reshape((default_number_of_points,))
            return p, w

        if options.lower() == 'tensor grid' or options.lower() == 'quadrature':
            p,w = self.getTensorQuadratureRule([i for i in self.basis.orders])
            return p,w
    def evaluatePolyFit(self, stackOfPoints):
        """
        Evaluates the the polynomial approximation of a function (or model data) at prescribed points.

        :param Poly self:
            An instance of the Poly class.
        :param matrix stackOfPoints:
            A N-by-d matrix of points (can be unscaled) at which the polynomial gradient must be evaluated at.
        :return:
            A 1-by-N matrix of the polynomial approximation.
        """
        return self.getPolynomial(stackOfPoints).T *  np.mat(self.coefficients)

    def evaluatePolyGradFit(self, stackOfPoints):
        """
        Evaluates the gradient of the polynomial approximation of a function (or model data) at prescribed points.

        :param Poly self:
            An instance of the Poly class.
        :param matrix stackOfPoints:
            A N-by-d matrix of points (can be unscaled) at which the polynomial gradient must be evaluated at.
        :return:
            A d-by-N matrix of the gradients of the polynomial approximation.

        **Notes:**

        This function should not be confused with getPolynomialGradient(). The latter is only concerned with approximating what the multivariate polynomials
        gradient values are at prescribed points.
        """
        H = self.getPolynomialGradient(stackOfPoints)
        grads = np.zeros((self.dimensions, len(stackOfPoints) ) )
        for i in range(0, self.dimensions):
            grads[i,:] = np.mat(self.coefficients).T * H[i]
        return grads
    def getPolyFitFunction(self):
        """
        Returns a callable polynomial approximation of a function (or model data).

        :param Poly self:
            An instance of the Poly class.
        :return:
            A callable function.

        """
        return lambda (x): self.getPolynomial(x).T *  np.mat(self.coefficients)
    def getPolyGradFitFunction(self):
        """
        Returns a callable for the gradients of the polynomial approximation of a function (or model data).

        :param Poly self:
            An instance of the Poly class.
        :return:
            A callable function.

        """
        return lambda (x) : self.evaluatePolyGradFit(x)
    def getFunctionSamples(self, number_of_samples):
        """
        Returns a set of function samples; useful for computing probabilities.

        :param Poly self:
            An instance of the Poly class.
        :param callable function:
            A callable function (or evaluations of the function at the prerequisite quadrature points).
        :param array coefficients:
            A numpy array of the coefficients
        :param matrix indexset:
            A K-by-d matrix of the index set.
        :return:
            A 50000-by-1 array of function evaluations.

        """
        dimensions = self.dimensions
        if number_of_samples is None:
            number_of_samples = 50000 # default value!
        plotting_pts = np.zeros((number_of_samples, dimensions))
        for i in range(0, dimensions):
                univariate_samples = self.parameters[i].getSamples(number_of_samples)
                for j in range(0, number_of_samples):
                    plotting_pts[j, i] = univariate_samples[j]
        samples = self.evaluatePolyFit(plotting_pts)
        return plotting_pts, samples<|endoftext|>


<commit_before>import os
import re
import httplib as http

from citeproc import CitationStylesStyle, CitationStylesBibliography
from citeproc import Citation, CitationItem
from citeproc import formatter
from citeproc.source.json import CiteProcJSON

from framework.exceptions import HTTPError
from framework.auth import utils
from osf.models import PreprintService
from website.citations.utils import datetime_to_csl
from website.settings import CITATION_STYLES_PATH, BASE_PATH, CUSTOM_CITATIONS

def clean_up_common_errors(cit):
    cit = re.sub(r"\.+", '.', cit)
    cit = re.sub(r" +", ' ', cit)
    return cit

def display_absolute_url(node):
    url = node.absolute_url
    if url is not None:
        return re.sub(r'https?:', '', url).strip('/')

def preprint_csl(preprint, node):
    csl = node.csl

    csl['id'] = preprint._id
    csl['publisher'] = preprint.provider.name
    csl['URL'] = display_absolute_url(preprint)

    if preprint.original_publication_date:
        csl['issued'] = datetime_to_csl(preprint.original_publication_date)

    if csl.get('DOI'):
        csl.pop('DOI')

    article_doi = preprint.article_doi
    preprint_doi = preprint.preprint_doi

    if article_doi:
        csl['DOI'] = article_doi
    else:
        if preprint_doi:
            csl['DOI'] = preprint_doi

    return csl

def process_name(node, user):
    # If the user has a family and given name, use those
    if user.family_name and user.given_name:
        return {
            'family_name': user.family_name,
            'suffix': user.suffix,
            'given_name': user.given_name,
            'middle_names': user.middle_names,
        }
    elif user.is_registered or user.is_disabled:
        name = user.fullname
    else:
        name = user.get_unclaimed_record(node._id)['name']

    # If the user doesn't autofill his family and given name
    parsed = utils.impute_names(name)
    return {
        'family_name': parsed['family'],
        'suffix': parsed['suffix'],
        'given_name': parsed['given'],
        'middle_names': parsed['middle']
    }

def render_citation(node, style='apa'):
    """Given a node, return a citation"""
    csl = None
    if isinstance(node, PreprintService):
        csl = preprint_csl(node, node.node)
        data = [csl, ]
    else:
        data = [node.csl, ]

    bib_source = CiteProcJSON(data)

    custom = CUSTOM_CITATIONS.get(style, False)
    path = os.path.join(BASE_PATH, 'static', custom) if custom else os.path.join(CITATION_STYLES_PATH, style)
    bib_style = CitationStylesStyle(path, validate=False)

    bibliography = CitationStylesBibliography(bib_style, bib_source, formatter.plain)

    citation = Citation([CitationItem(node._id)])

    bibliography.register(citation)

    bib = bibliography.bibliography()
    cit = unicode(bib[0] if len(bib) else '')

    title = csl['title'] if csl else node.csl['title']
    if cit.count(title) == 1:
        i = cit.index(title)
        prefix = clean_up_common_errors(cit[0:i])
        suffix = clean_up_common_errors(cit[i + len(title):])
        cit = prefix + title + suffix
    elif cit.count(title) == 0:
        cit = clean_up_common_errors(cit)

    if isinstance(node, PreprintService):
        cit_node = node.node
    else:
        cit_node = node

    if style == 'apa':
        cit = apa_reformat(cit_node, cit)
    if style == 'chicago-author-date':
        cit = chicago_reformat(cit_node, cit)
    if style == 'modern-language-association':
        cit = mla_reformat(cit_node, cit)

    return cit

def apa_reformat(node, cit):
    new_csl = cit.split('(')
    contributors_list = list(node.visible_contributors)
    contributors_list_length = len(contributors_list)

    # throw error if there is no visible contributor
    if contributors_list_length == 0:
        raise HTTPError(http.BAD_REQUEST)
    # handle only one contributor
    elif contributors_list_length == 1:
        name = process_name(node, contributors_list[0])
        new_apa = apa_name(name)
    # handle more than one contributor  but less than 8 contributors
    elif contributors_list_length in range(1, 8):
        name_list = [apa_name(process_name(node, x)) for x in contributors_list[:-1]]
        new_apa = ' '.join(name_list)
        last_one = apa_name(process_name(node, contributors_list[-1]))
        new_apa += ' & ' + last_one
    # handle 8 or more contributors
    else:
        name_list = [apa_name(process_name(node, x)) for x in contributors_list[:5]]
        new_apa = ' '.join(name_list) + '... ' + apa_name(process_name(node, contributors_list[-1]))

    cit = new_apa.rstrip(', ') + ' '
    for x in new_csl[1:]:
        cit += '(' + x
    return cit

def apa_name(name):
    apa = ''
    if name['family_name']:
        apa += name['family_name'] + ','
    if name['given_name']:
        apa += ' ' + name['given_name'][0] + '.'
        if name['middle_names']:
            apa += ' ' + name['middle_names'][0] + '.'
        apa += ','
    if name['suffix']:
        apa += ' ' + name['suffix'] + ','
    return apa

def mla_reformat(node, cit):
    contributors_list = list(node.visible_contributors)
    contributors_list_length = len(contributors_list)
    retrive_from = cit.split('Open')[-1]

    # throw error if there is no visible contributor
    if contributors_list_length == 0:
        raise HTTPError(http.BAD_REQUEST)
    # handle only one contributor
    elif contributors_list_length == 1:
        name = process_name(node, contributors_list[0])
        new_mla = mla_name(name, initial=True).rstrip(' ')
    # handle more than one contributor  but less than 5 contributors
    elif contributors_list_length in range(1, 5):
        first_one = mla_name(process_name(node, contributors_list[0]), initial=True)
        rest_ones = [mla_name(process_name(node, x)) for x in contributors_list[1:-1]]
        last_one = mla_name(process_name(node, contributors_list[-1]))
        if rest_ones:
            rest_part = ', '.join(rest_ones)
            new_mla = first_one.rstrip(',') + ', ' + rest_part + ', and ' + last_one
        else:
            new_mla = first_one + 'and ' + last_one
    # handle 5 or more contributors
    else:
        name = process_name(node, contributors_list[0])
        new_mla = mla_name(name, initial=True) + ' et al. '

    cit = new_mla
    cit += u' \u201c' + node.title.title() + u'.\u201d Open' + retrive_from
    return cit

def chicago_reformat(node, cit):
    new_csl = cit.split('20')
    contributors_list = list(node.visible_contributors)
    contributors_list_length = len(contributors_list)

    # throw error if there is no visible contributor
    if contributors_list_length == 0:
        raise HTTPError(http.BAD_REQUEST)
    # handle only one contributor
    elif contributors_list_length == 1:
        name = process_name(node, contributors_list[0])
        new_chi = mla_name(name, initial=True) + ' '
    # handle more than one contributor  but less than 11 contributors
    elif contributors_list_length in range(1, 11):
        first_one = mla_name(process_name(node, contributors_list[0]), initial=True)
        rest_ones = [mla_name(process_name(node, x)) for x in contributors_list[1:-1]]
        last_one = mla_name(process_name(node, contributors_list[-1]))
        if rest_ones:
            rest_part = ', '.join(rest_ones)
            new_chi = first_one.rstrip(',') + ', ' + rest_part + ', and ' + last_one + ' '
        else:
            new_chi = first_one + 'and ' + last_one + ' '
    # handle 11 or more contributors
    else:
        new_chi = mla_name(process_name(node, contributors_list[0]), initial=True).rstrip(', ')
        name_list = [mla_name(process_name(node, x)) for x in contributors_list[1:7]]
        rest = ', '.join(name_list)
        rest = rest.rstrip(',') + ', et al. '
        new_chi += ', ' + rest

    cit = new_chi
    for x in new_csl[1:]:
        cit += '20' + x
    return cit

def mla_name(name, initial=False):
    if initial:
        mla = ''
        if name['family_name']:
            mla += name['family_name'] + ','
        if name['given_name']:
            mla += ' ' + name['given_name']
            if name['middle_names']:
                mla += ' ' + name['middle_names'][0] + '.'
            mla += ','
        if name['suffix']:
            mla += ' ' + name['suffix']
    else:
        mla = ''
        if name['given_name']:
            mla += name['given_name']
            if name['middle_names']:
                mla += ' ' + name['middle_names'][0]
        if name['family_name']:
            mla += ' ' + name['family_name']
        if name['suffix']:
            mla += ' ' + name['suffix']
    return mla
<commit_msg>add conditionals<commit_after>import os
import re
import httplib as http

from citeproc import CitationStylesStyle, CitationStylesBibliography
from citeproc import Citation, CitationItem
from citeproc import formatter
from citeproc.source.json import CiteProcJSON

from framework.exceptions import HTTPError
from framework.auth import utils
from osf.models import PreprintService
from website.citations.utils import datetime_to_csl
from website.settings import CITATION_STYLES_PATH, BASE_PATH, CUSTOM_CITATIONS

def clean_up_common_errors(cit):
    cit = re.sub(r"\.+", '.', cit)
    cit = re.sub(r" +", ' ', cit)
    return cit

def display_absolute_url(node):
    url = node.absolute_url
    if url is not None:
        return re.sub(r'https?:', '', url).strip('/')

def preprint_csl(preprint, node):
    csl = node.csl

    csl['id'] = preprint._id
    csl['publisher'] = preprint.provider.name
    csl['URL'] = display_absolute_url(preprint)

    if preprint.original_publication_date:
        csl['issued'] = datetime_to_csl(preprint.original_publication_date)

    if csl.get('DOI'):
        csl.pop('DOI')

    article_doi = preprint.article_doi
    preprint_doi = preprint.preprint_doi

    if article_doi:
        csl['DOI'] = article_doi
    else:
        if preprint_doi and preprint.is_published and preprint.preprint_doi_created:
            csl['DOI'] = preprint_doi

    return csl

def process_name(node, user):
    # If the user has a family and given name, use those
    if user.family_name and user.given_name:
        return {
            'family_name': user.family_name,
            'suffix': user.suffix,
            'given_name': user.given_name,
            'middle_names': user.middle_names,
        }
    elif user.is_registered or user.is_disabled:
        name = user.fullname
    else:
        name = user.get_unclaimed_record(node._id)['name']

    # If the user doesn't autofill his family and given name
    parsed = utils.impute_names(name)
    return {
        'family_name': parsed['family'],
        'suffix': parsed['suffix'],
        'given_name': parsed['given'],
        'middle_names': parsed['middle']
    }

def render_citation(node, style='apa'):
    """Given a node, return a citation"""
    csl = None
    if isinstance(node, PreprintService):
        csl = preprint_csl(node, node.node)
        data = [csl, ]
    else:
        data = [node.csl, ]

    bib_source = CiteProcJSON(data)

    custom = CUSTOM_CITATIONS.get(style, False)
    path = os.path.join(BASE_PATH, 'static', custom) if custom else os.path.join(CITATION_STYLES_PATH, style)
    bib_style = CitationStylesStyle(path, validate=False)

    bibliography = CitationStylesBibliography(bib_style, bib_source, formatter.plain)

    citation = Citation([CitationItem(node._id)])

    bibliography.register(citation)

    bib = bibliography.bibliography()
    cit = unicode(bib[0] if len(bib) else '')

    title = csl['title'] if csl else node.csl['title']
    if cit.count(title) == 1:
        i = cit.index(title)
        prefix = clean_up_common_errors(cit[0:i])
        suffix = clean_up_common_errors(cit[i + len(title):])
        cit = prefix + title + suffix
    elif cit.count(title) == 0:
        cit = clean_up_common_errors(cit)

    if isinstance(node, PreprintService):
        cit_node = node.node
    else:
        cit_node = node

    if style == 'apa':
        cit = apa_reformat(cit_node, cit)
    if style == 'chicago-author-date':
        cit = chicago_reformat(cit_node, cit)
    if style == 'modern-language-association':
        cit = mla_reformat(cit_node, cit)

    return cit

def apa_reformat(node, cit):
    new_csl = cit.split('(')
    contributors_list = list(node.visible_contributors)
    contributors_list_length = len(contributors_list)

    # throw error if there is no visible contributor
    if contributors_list_length == 0:
        raise HTTPError(http.BAD_REQUEST)
    # handle only one contributor
    elif contributors_list_length == 1:
        name = process_name(node, contributors_list[0])
        new_apa = apa_name(name)
    # handle more than one contributor  but less than 8 contributors
    elif contributors_list_length in range(1, 8):
        name_list = [apa_name(process_name(node, x)) for x in contributors_list[:-1]]
        new_apa = ' '.join(name_list)
        last_one = apa_name(process_name(node, contributors_list[-1]))
        new_apa += ' & ' + last_one
    # handle 8 or more contributors
    else:
        name_list = [apa_name(process_name(node, x)) for x in contributors_list[:5]]
        new_apa = ' '.join(name_list) + '... ' + apa_name(process_name(node, contributors_list[-1]))

    cit = new_apa.rstrip(', ') + ' '
    for x in new_csl[1:]:
        cit += '(' + x
    return cit

def apa_name(name):
    apa = ''
    if name['family_name']:
        apa += name['family_name'] + ','
    if name['given_name']:
        apa += ' ' + name['given_name'][0] + '.'
        if name['middle_names']:
            apa += ' ' + name['middle_names'][0] + '.'
        apa += ','
    if name['suffix']:
        apa += ' ' + name['suffix'] + ','
    return apa

def mla_reformat(node, cit):
    contributors_list = list(node.visible_contributors)
    contributors_list_length = len(contributors_list)
    retrive_from = cit.split('Open')[-1]

    # throw error if there is no visible contributor
    if contributors_list_length == 0:
        raise HTTPError(http.BAD_REQUEST)
    # handle only one contributor
    elif contributors_list_length == 1:
        name = process_name(node, contributors_list[0])
        new_mla = mla_name(name, initial=True).rstrip(' ')
    # handle more than one contributor  but less than 5 contributors
    elif contributors_list_length in range(1, 5):
        first_one = mla_name(process_name(node, contributors_list[0]), initial=True)
        rest_ones = [mla_name(process_name(node, x)) for x in contributors_list[1:-1]]
        last_one = mla_name(process_name(node, contributors_list[-1]))
        if rest_ones:
            rest_part = ', '.join(rest_ones)
            new_mla = first_one.rstrip(',') + ', ' + rest_part + ', and ' + last_one
        else:
            new_mla = first_one + 'and ' + last_one
    # handle 5 or more contributors
    else:
        name = process_name(node, contributors_list[0])
        new_mla = mla_name(name, initial=True) + ' et al. '

    cit = new_mla
    cit += u' \u201c' + node.title.title() + u'.\u201d Open' + retrive_from
    return cit

def chicago_reformat(node, cit):
    new_csl = cit.split('20')
    contributors_list = list(node.visible_contributors)
    contributors_list_length = len(contributors_list)

    # throw error if there is no visible contributor
    if contributors_list_length == 0:
        raise HTTPError(http.BAD_REQUEST)
    # handle only one contributor
    elif contributors_list_length == 1:
        name = process_name(node, contributors_list[0])
        new_chi = mla_name(name, initial=True) + ' '
    # handle more than one contributor  but less than 11 contributors
    elif contributors_list_length in range(1, 11):
        first_one = mla_name(process_name(node, contributors_list[0]), initial=True)
        rest_ones = [mla_name(process_name(node, x)) for x in contributors_list[1:-1]]
        last_one = mla_name(process_name(node, contributors_list[-1]))
        if rest_ones:
            rest_part = ', '.join(rest_ones)
            new_chi = first_one.rstrip(',') + ', ' + rest_part + ', and ' + last_one + ' '
        else:
            new_chi = first_one + 'and ' + last_one + ' '
    # handle 11 or more contributors
    else:
        new_chi = mla_name(process_name(node, contributors_list[0]), initial=True).rstrip(', ')
        name_list = [mla_name(process_name(node, x)) for x in contributors_list[1:7]]
        rest = ', '.join(name_list)
        rest = rest.rstrip(',') + ', et al. '
        new_chi += ', ' + rest

    cit = new_chi
    for x in new_csl[1:]:
        cit += '20' + x
    return cit

def mla_name(name, initial=False):
    if initial:
        mla = ''
        if name['family_name']:
            mla += name['family_name'] + ','
        if name['given_name']:
            mla += ' ' + name['given_name']
            if name['middle_names']:
                mla += ' ' + name['middle_names'][0] + '.'
            mla += ','
        if name['suffix']:
            mla += ' ' + name['suffix']
    else:
        mla = ''
        if name['given_name']:
            mla += name['given_name']
            if name['middle_names']:
                mla += ' ' + name['middle_names'][0]
        if name['family_name']:
            mla += ' ' + name['family_name']
        if name['suffix']:
            mla += ' ' + name['suffix']
    return mla
<|endoftext|>


<commit_before>import unittest
import sip_model_rest as sip_model
import pandas as pd
import numpy.testing as npt
import pandas.util.testing as pdt

# load transposed qaqc data for inputs and expected outputs
csv_transpose_path_in = "./sip_qaqc_in_transpose.csv"
pd_obj_inputs = pd.read_csv(csv_transpose_path_in, index_col=0, engine='python')
# print(pd_obj_inputs)
csv_transpose_path_exp = "./sip_qaqc_exp_transpose.csv"
pd_obj_exp_out = pd.read_csv(csv_transpose_path_exp, index_col=0, engine='python')
# print(pd_obj_exp_out)

# create an instance of sip object with qaqc data
sip_calc = sip_model.sip("batch", pd_obj_inputs, pd_obj_exp_out)
sip_empty = sip_model.sip("empty", pd_obj_inputs, pd_obj_exp_out)
test = {}

class TestSip(unittest.TestCase):
    def setup(self):
        # sip2 = sip_model.sip(0, pd_obj_inputs, pd_obj_exp_out)
        pass
        # setup the test as needed
        # e.g. pandas to open sip qaqc csv
        #  Read qaqc csv and create pandas DataFrames for inputs and expected outputs

    def teardown(self):
        pass
        # teardown called after each test
        # e.g. maybe write test results to some text file

    def test_fw_bird(self):
        result = sip_calc.fw_bird()
        npt.assert_array_almost_equal(result, 0.0162, 4, '', True)
        return

    def test_fw_mamm(self):
        result = sip_calc.fw_mamm()
        npt.assert_array_almost_equal(result, 0.172, 4, '', True)
        return

    def test_dose_bird(self):
        #(self.fw_bird_out * self.solubility)/(self.bodyweight_assessed_bird / 1000.)
        sip_empty.fw_bird_out = pd.Series([10.], dtype='int')
        sip_empty.solubility = pd.Series([100.], dtype='int')
        sip_empty.bodyweight_assessed_bird = pd.Series([1.], dtype='int')
        result = sip_empty.dose_bird()
        npt.assert_array_almost_equal(result, 1000000., 4, '', True)
        return

#Amber
    def test_dose_mamm(self):
        #(self.fw_mamm_out * self.solubility)/(self.bodyweight_assessed_mammal / 1000)
        sip_empty.fw_mamm_out = pd.Series([20.], dtype='int')
        sip_empty.solubility = pd.Series([400.], dtype='int')
        sip_empty.bodyweight_assessed_mammal = pd.Series([1.], dtype='int')
        result = sip_empty.dose_mamm()
        npt.assert_array_almost_equal(result, 8000000., 4, '', True)
        return

#Amber
    def test_at_bird(self):
        #(self.ld50_avian_water) * ((self.bodyweight_assessed_bird / self.bodyweight_tested_bird)**(self.mineau_scaling_factor - 1.))
        sip_empty.ld50_avian_water = pd.Series([2000.], dtype='int')
        sip_empty.bodyweight_assessed_bird = pd.Series([100.], dtype='int')
        sip_empty.bodyweight_tested_bird = pd.Series([200.], dtype='int')
        sip_empty.mineau_scaling_factor = pd.Series([2.], dtype='int')
        result = sip_empty.at_bird()
        npt.assert_array_almost_equal(result, 1000., 4, '', True)
        return

#Amber
    def test_at_mamm(self):
        #(self.ld50_mammal_water) * ((self.bodyweight_tested_mammal / self.bodyweight_assessed_mammal)**0.25)
        sip_empty.ld50_mammal_water = pd.Series([10.], dtype='int')
        sip_empty.bodyweight_tested_mammal = pd.Series([100.], dtype='int')
        sip_empty.bodyweight_assessed_mammal = pd.Series([200.], dtype='int')
        result = sip_empty.at_mamm()
        npt.assert_array_almost_equal(result, 8.408964, 4, '', True)
        return

##Error. Issue with sip_model_rest.py file?
    # def test_fi_bird(self):
    #     #0.0582 * ((bw_grams / 1000.)**0.651)
    #     sip_empty.bw_grams = pd.Series([100.], dtype='int')
    #     result = sip_empty.fi_bird()
    #     npt.assert_array_almost_equal(result, 0.012999, 4, '', True)
    #     return

#Amber.
    def test_act(self):
        #(self.noael_mammal_water) * ((self.bodyweight_tested_mammal / self.bodyweight_assessed_mammal)**0.25)
        sip_empty.noael_mammal_water = pd.Series([10.], dtype='int')
        sip_empty.bodyweight_tested_mammal = pd.Series([500.], dtype='int')
        sip_empty.bodyweight_assessed_mammal = pd.Series([400.], dtype='int')
        result = sip_empty.act()
        npt.assert_array_almost_equal(result, 10.5737, 4, '', True)
        return

# #Weird equation. Let's talk about this one.
#     def test_det(self):
#         """
#         Dose Equiv. Toxicity:
#
#         The FI value (kg-diet) is multiplied by the reported NOAEC (mg/kg-diet) and then divided by
#         the test animal's body weight to derive the dose-equivalent chronic toxicity value (mg/kg-bw):
#
#         Dose Equiv. Toxicity = (NOAEC * FI) / BW
#
#         NOTE: The user enters the lowest available NOAEC for the mallard duck, for the bobwhite quail,
#         and for any other test species. The model calculates the dose equivalent toxicity values for
#         all of the modeled values (Cells F20-24 and results worksheet) and then selects the lowest dose
#         equivalent toxicity value to represent the chronic toxicity of the chemical to birds.
#         """
#         result =
#         self.assertEquals(result, )
#         return

#Carmen
    def test_acute_bird(self):
        # self.acute_bird_out = self.dose_bird_out / self.at_bird_out
        sip_empty.dose_bird_out = pd.Series([100.], dtype='int')
        sip_empty.at_bird_out = pd.Series([10.], dtype='int')
        result = sip_empty.acute_bird()
        npt.assert_array_almost_equal(result, 10., 4)
        return

#Carmen
    def test_acuconb(self):
        """
        Message stating whether or not a risk is present
        """
        # if self.acuconb_out == -1:
        #     if self.acute_bird_out == None:
        #         raise ValueError\
        #         ('acute_bird variable equals None and therefor this function cannot be run.')
            # if self.acute_bird_out < 0.1:
            #     self.acuconb_out = ('Drinking water exposure alone is NOT a potential concern for birds')
            # else:
            #     self.acuconb_out = ('Exposure through drinking water alone is a potential concern for birds')
        sip_empty.acute_bird_out = pd.Series([0.2])
        result = sip_empty.acuconb()
        exp = pd.Series(["Exposure through drinking water alone is a potential concern for birds"])
        pdt.assert_series_equal(result, exp)
        return

#Carmen
    def test_acute_mamm(self):
        # self.acute_mamm_out = self.dose_mamm_out / self.at_mamm_out
        sip_empty.dose_mamm_out = pd.Series([100.], dtype='int')
        sip_empty.at_mamm_out = pd.Series([10.], dtype='int')
        result = sip_empty.acute_mamm()
        npt.assert_array_almost_equal(result, 10., 4)
        return

#Carmen
    def test_acuconm(self):
        """
        Message stating whether or not a risk is present
        """
        # if self.acuconm_out == -1:
        #     if self.acute_mamm_out == None:
        #         raise ValueError\
        #         ('acute_mamm variable equals None and therefor this function cannot be run.')
        #     if self.acute_mamm_out < 0.1:
        #         self.acuconm_out = ('Drinking water exposure alone is NOT a potential concern for mammals')
        #     else:
        #         self.acuconm_out = ('Exposure through drinking water alone is a potential concern for mammals')
        #     return self.acuconm_out
        sip_empty.acute_mamm_out = pd.Series([0.2])
        result = sip_empty.acuconm()
        exp = pd.Series(["Exposure through drinking water alone is a potential concern for mammals"])
        pdt.assert_series_equal(result, exp)
        return

# #Marcia
    def test_chron_bird(self):
    #self.chron_bird_out = self.dose_bird_out / self.det_out
        sip_empty.dose_bird_out = pd.Series([5.], dtype='int')
        sip_empty.det_out = pd.Series([10.], dtype='int')
        result = sip_empty.chron_bird()
        npt.assert_array_almost_equal(result, 0.5, 4, '', True)
        return

# #Marcia #boolean look up unit test
    def test_chronconb(self):
    #boolean = self.chron_bird_out < 1
        #self.chronconb_out = boolean.map(lambda x:
         #   'Drinking water exposure alone is NOT a potential concern for birds' if x == True
         #   else 'Exposure through drinking water alone is a potential concern for birds')
        sip_empty.chron_bird_out = pd.Series([3])
        result = sip_empty.chronconb()
        exp = pd.Series(["Exposure through drinking water alone is a potential concern for birds"])
        pdt.assert_series_equal(result, exp)
        return

# #Marcia
    def test_chron_mamm(self):
         # self.chron_mamm_out = self.dose_mamm_out / self.act_out
        sip_empty.dose_mamm_out = pd.Series([8.], dtype='int')
        sip_empty.act_out = pd.Series([4.], dtype='int')
        result = sip_empty.chron_mamm()
        npt.assert_array_almost_equal(result, 2, 4, '', True)
        return

# #Marcia
    def test_chronconm(self):
        # self.chronconm_out = boolean.map(lambda x:
         #   'Drinking water exposure alone is NOT a potential concern for mammals' if x == True
         #   else 'Exposure through drinking water alone is a potential concern for mammals')
        sip_empty.chron_mamm_out =  pd.Series([0.5])
        result = sip_empty.chronconm()
        exp = pd.Series(["Drinking water exposure alone is NOT a potential concern for mammals"])
        pdt.assert_series_equal(result, exp)
        return

#Note: commented-out rows contain output files that are not running properly in the subsequent blackbox_method test.
    def test_blackbox_method(self):
         self.blackbox_method_int('dose_bird')
         self.blackbox_method_int('dose_mamm')
         self.blackbox_method_int('at_bird')
         self.blackbox_method_int('at_mamm')
       #  self.blackbox_method('fi_bird')
         self.blackbox_method_int('det')
         self.blackbox_method_int('act')
         self.blackbox_method_int('acute_bird')
         self.blackbox_method_str('acuconb')
         self.blackbox_method_int('acute_mamm')
         self.blackbox_method_str('acuconm')
         self.blackbox_method_int('chron_bird')
         self.blackbox_method_str('chronconb')
         self.blackbox_method_int('chron_mamm')
         self.blackbox_method_str('chronconm')

    def blackbox_method_int(self, output):
        """
        Helper method to reuse code for testing numpy array outputs from SIP model
        :param output: String; Pandas Series name (e.g. column name) without '_out'
        :return:
        """
        result = sip_calc.pd_obj_out[output + "_out"]
        expected = sip_calc.pd_obj_exp[output + "_exp"]
        npt.assert_array_almost_equal(result, expected, 4, '', True)

    def blackbox_method_str(self, output):
        result = sip_calc.pd_obj_out[output + "_out"]
        expected = sip_calc.pd_obj_exp[output + "_exp"]
        npt.assert_array_equal(result, expected)

# unittest will
# 1) call the setup method,
# 2) then call every method starting with "test",
# 3) then the teardown method
if __name__ == '__main__':
    unittest.main()
<commit_msg>moving sip_empty object to setup<commit_after>import unittest
import sip_model_rest as sip_model
import pandas as pd
import numpy.testing as npt
import pandas.util.testing as pdt

# load transposed qaqc data for inputs and expected outputs
csv_transpose_path_in = "./sip_qaqc_in_transpose.csv"
pd_obj_inputs = pd.read_csv(csv_transpose_path_in, index_col=0, engine='python')
# print(pd_obj_inputs)
csv_transpose_path_exp = "./sip_qaqc_exp_transpose.csv"
pd_obj_exp_out = pd.read_csv(csv_transpose_path_exp, index_col=0, engine='python')
# print(pd_obj_exp_out)

# create an instance of sip object with qaqc data
sip_calc = sip_model.sip("batch", pd_obj_inputs, pd_obj_exp_out)
test = {}

class TestSip(unittest.TestCase):
    def setup(self):
        # sip2 = sip_model.sip(0, pd_obj_inputs, pd_obj_exp_out)
        sip_empty = sip_model.sip("empty", pd_obj_inputs, pd_obj_exp_out)
        # setup the test as needed
        # e.g. pandas to open sip qaqc csv
        #  Read qaqc csv and create pandas DataFrames for inputs and expected outputs

    def teardown(self):
        pass
        # teardown called after each test
        # e.g. maybe write test results to some text file

    def test_fw_bird(self):
        result = sip_calc.fw_bird()
        npt.assert_array_almost_equal(result, 0.0162, 4, '', True)
        return

    def test_fw_mamm(self):
        result = sip_calc.fw_mamm()
        npt.assert_array_almost_equal(result, 0.172, 4, '', True)
        return

    def test_dose_bird(self):
        #(self.fw_bird_out * self.solubility)/(self.bodyweight_assessed_bird / 1000.)
        sip_empty.fw_bird_out = pd.Series([10.], dtype='int')
        sip_empty.solubility = pd.Series([100.], dtype='int')
        sip_empty.bodyweight_assessed_bird = pd.Series([1.], dtype='int')
        result = sip_empty.dose_bird()
        npt.assert_array_almost_equal(result, 1000000., 4, '', True)
        return

#Amber
    def test_dose_mamm(self):
        #(self.fw_mamm_out * self.solubility)/(self.bodyweight_assessed_mammal / 1000)
        sip_empty.fw_mamm_out = pd.Series([20.], dtype='int')
        sip_empty.solubility = pd.Series([400.], dtype='int')
        sip_empty.bodyweight_assessed_mammal = pd.Series([1.], dtype='int')
        result = sip_empty.dose_mamm()
        npt.assert_array_almost_equal(result, 8000000., 4, '', True)
        return

#Amber
    def test_at_bird(self):
        #(self.ld50_avian_water) * ((self.bodyweight_assessed_bird / self.bodyweight_tested_bird)**(self.mineau_scaling_factor - 1.))
        sip_empty.ld50_avian_water = pd.Series([2000.], dtype='int')
        sip_empty.bodyweight_assessed_bird = pd.Series([100.], dtype='int')
        sip_empty.bodyweight_tested_bird = pd.Series([200.], dtype='int')
        sip_empty.mineau_scaling_factor = pd.Series([2.], dtype='int')
        result = sip_empty.at_bird()
        npt.assert_array_almost_equal(result, 1000., 4, '', True)
        return

#Amber
    def test_at_mamm(self):
        #(self.ld50_mammal_water) * ((self.bodyweight_tested_mammal / self.bodyweight_assessed_mammal)**0.25)
        sip_empty.ld50_mammal_water = pd.Series([10.], dtype='int')
        sip_empty.bodyweight_tested_mammal = pd.Series([100.], dtype='int')
        sip_empty.bodyweight_assessed_mammal = pd.Series([200.], dtype='int')
        result = sip_empty.at_mamm()
        npt.assert_array_almost_equal(result, 8.408964, 4, '', True)
        return

##Error. Issue with sip_model_rest.py file?
    # def test_fi_bird(self):
    #     #0.0582 * ((bw_grams / 1000.)**0.651)
    #     sip_empty.bw_grams = pd.Series([100.], dtype='int')
    #     result = sip_empty.fi_bird()
    #     npt.assert_array_almost_equal(result, 0.012999, 4, '', True)
    #     return

#Amber.
    def test_act(self):
        #(self.noael_mammal_water) * ((self.bodyweight_tested_mammal / self.bodyweight_assessed_mammal)**0.25)
        sip_empty.noael_mammal_water = pd.Series([10.], dtype='int')
        sip_empty.bodyweight_tested_mammal = pd.Series([500.], dtype='int')
        sip_empty.bodyweight_assessed_mammal = pd.Series([400.], dtype='int')
        result = sip_empty.act()
        npt.assert_array_almost_equal(result, 10.5737, 4, '', True)
        return

# #Weird equation. Let's talk about this one.
#     def test_det(self):
#         """
#         Dose Equiv. Toxicity:
#
#         The FI value (kg-diet) is multiplied by the reported NOAEC (mg/kg-diet) and then divided by
#         the test animal's body weight to derive the dose-equivalent chronic toxicity value (mg/kg-bw):
#
#         Dose Equiv. Toxicity = (NOAEC * FI) / BW
#
#         NOTE: The user enters the lowest available NOAEC for the mallard duck, for the bobwhite quail,
#         and for any other test species. The model calculates the dose equivalent toxicity values for
#         all of the modeled values (Cells F20-24 and results worksheet) and then selects the lowest dose
#         equivalent toxicity value to represent the chronic toxicity of the chemical to birds.
#         """
#         result =
#         self.assertEquals(result, )
#         return

#Carmen
    def test_acute_bird(self):
        # self.acute_bird_out = self.dose_bird_out / self.at_bird_out
        sip_empty.dose_bird_out = pd.Series([100.], dtype='int')
        sip_empty.at_bird_out = pd.Series([10.], dtype='int')
        result = sip_empty.acute_bird()
        npt.assert_array_almost_equal(result, 10., 4)
        return

#Carmen
    def test_acuconb(self):
        """
        Message stating whether or not a risk is present
        """
        # if self.acuconb_out == -1:
        #     if self.acute_bird_out == None:
        #         raise ValueError\
        #         ('acute_bird variable equals None and therefor this function cannot be run.')
            # if self.acute_bird_out < 0.1:
            #     self.acuconb_out = ('Drinking water exposure alone is NOT a potential concern for birds')
            # else:
            #     self.acuconb_out = ('Exposure through drinking water alone is a potential concern for birds')
        sip_empty.acute_bird_out = pd.Series([0.2])
        result = sip_empty.acuconb()
        exp = pd.Series(["Exposure through drinking water alone is a potential concern for birds"])
        pdt.assert_series_equal(result, exp)
        return

#Carmen
    def test_acute_mamm(self):
        # self.acute_mamm_out = self.dose_mamm_out / self.at_mamm_out
        sip_empty.dose_mamm_out = pd.Series([100.], dtype='int')
        sip_empty.at_mamm_out = pd.Series([10.], dtype='int')
        result = sip_empty.acute_mamm()
        npt.assert_array_almost_equal(result, 10., 4)
        return

#Carmen
    def test_acuconm(self):
        """
        Message stating whether or not a risk is present
        """
        # if self.acuconm_out == -1:
        #     if self.acute_mamm_out == None:
        #         raise ValueError\
        #         ('acute_mamm variable equals None and therefor this function cannot be run.')
        #     if self.acute_mamm_out < 0.1:
        #         self.acuconm_out = ('Drinking water exposure alone is NOT a potential concern for mammals')
        #     else:
        #         self.acuconm_out = ('Exposure through drinking water alone is a potential concern for mammals')
        #     return self.acuconm_out
        sip_empty.acute_mamm_out = pd.Series([0.2])
        result = sip_empty.acuconm()
        exp = pd.Series(["Exposure through drinking water alone is a potential concern for mammals"])
        pdt.assert_series_equal(result, exp)
        return

# #Marcia
    def test_chron_bird(self):
    #self.chron_bird_out = self.dose_bird_out / self.det_out
        sip_empty.dose_bird_out = pd.Series([5.], dtype='int')
        sip_empty.det_out = pd.Series([10.], dtype='int')
        result = sip_empty.chron_bird()
        npt.assert_array_almost_equal(result, 0.5, 4, '', True)
        return

# #Marcia #boolean look up unit test
    def test_chronconb(self):
    #boolean = self.chron_bird_out < 1
        #self.chronconb_out = boolean.map(lambda x:
         #   'Drinking water exposure alone is NOT a potential concern for birds' if x == True
         #   else 'Exposure through drinking water alone is a potential concern for birds')
        sip_empty.chron_bird_out = pd.Series([3])
        result = sip_empty.chronconb()
        exp = pd.Series(["Exposure through drinking water alone is a potential concern for birds"])
        pdt.assert_series_equal(result, exp)
        return

# #Marcia
    def test_chron_mamm(self):
         # self.chron_mamm_out = self.dose_mamm_out / self.act_out
        sip_empty.dose_mamm_out = pd.Series([8.], dtype='int')
        sip_empty.act_out = pd.Series([4.], dtype='int')
        result = sip_empty.chron_mamm()
        npt.assert_array_almost_equal(result, 2, 4, '', True)
        return

# #Marcia
    def test_chronconm(self):
        # self.chronconm_out = boolean.map(lambda x:
         #   'Drinking water exposure alone is NOT a potential concern for mammals' if x == True
         #   else 'Exposure through drinking water alone is a potential concern for mammals')
        sip_empty.chron_mamm_out =  pd.Series([0.5])
        result = sip_empty.chronconm()
        exp = pd.Series(["Drinking water exposure alone is NOT a potential concern for mammals"])
        pdt.assert_series_equal(result, exp)
        return

#Note: commented-out rows contain output files that are not running properly in the subsequent blackbox_method test.
    def test_blackbox_method(self):
         self.blackbox_method_int('dose_bird')
         self.blackbox_method_int('dose_mamm')
         self.blackbox_method_int('at_bird')
         self.blackbox_method_int('at_mamm')
       #  self.blackbox_method('fi_bird')
         self.blackbox_method_int('det')
         self.blackbox_method_int('act')
         self.blackbox_method_int('acute_bird')
         self.blackbox_method_str('acuconb')
         self.blackbox_method_int('acute_mamm')
         self.blackbox_method_str('acuconm')
         self.blackbox_method_int('chron_bird')
         self.blackbox_method_str('chronconb')
         self.blackbox_method_int('chron_mamm')
         self.blackbox_method_str('chronconm')

    def blackbox_method_int(self, output):
        """
        Helper method to reuse code for testing numpy array outputs from SIP model
        :param output: String; Pandas Series name (e.g. column name) without '_out'
        :return:
        """
        result = sip_calc.pd_obj_out[output + "_out"]
        expected = sip_calc.pd_obj_exp[output + "_exp"]
        npt.assert_array_almost_equal(result, expected, 4, '', True)

    def blackbox_method_str(self, output):
        result = sip_calc.pd_obj_out[output + "_out"]
        expected = sip_calc.pd_obj_exp[output + "_exp"]
        npt.assert_array_equal(result, expected)

# unittest will
# 1) call the setup method,
# 2) then call every method starting with "test",
# 3) then the teardown method
if __name__ == '__main__':
    unittest.main()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from __future__ import unicode_literals
import datetime
from copy import deepcopy
from datetime import timedelta

from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ungettext_lazy, ugettext_lazy as _
from django.db import models
from django.db.models import Sum, F
from django.utils.timezone import now
from django.conf import settings

from tickle.utils.mail import TemplatedEmail
from invar.utils import ocr

def default_invoice_issue_date():
    return now()

def default_invoice_due_date():
    return now() + timedelta(days=settings.INVAR_DUE_DAYS)

@python_2_unicode_compatible
class Invoice(models.Model):
    receiver_name = models.CharField(max_length=255, blank=True, verbose_name=_('receiver name'))
    receiver_organisation = models.CharField(max_length=255, blank=True, verbose_name=_('receiver organisation'))
    receiver_pid = models.CharField(max_length=11, blank=True, verbose_name=_('receiver PID'))
    receiver_email = models.EmailField(verbose_name=_('receiver email address'))

    issue_date = models.DateField(null=True, blank=True, default=default_invoice_issue_date, verbose_name=_('issue date'))
    due_date = models.DateField(null=True, blank=True, default=default_invoice_due_date, verbose_name=_('due date'))

    class Meta:
        ordering = ('pk',)

        verbose_name = _('invoice')
        verbose_name_plural = _('invoices')

    def __str__(self):
        return str(self.pk)

    def connect_handle(self):
        if not hasattr(self, 'invalidation') and not hasattr(self, 'handle'):
            InvoiceHandle.objects.create(invoice=self)

    @property
    def ocr(self):
        return self.handle.ocr

    @property
    def total(self):
        return self.rows.aggregate(total=Sum(F('price') * F('quantity')))['total']

    def send(self):
        if self.total != 0:
            context = {
                'invoice': self,
                'bg': settings.INVAR_BG,
                'iban': settings.INVAR_IBAN,
                'bic_swift': settings.INVAR_BIC_SWIFT,
            }

            mail = TemplatedEmail(subject_template='invar/email/invoice_subject.txt',
                                  body_template_html='invar/email/invoice.html', context=context,
                                  from_email="Faktura SOF15 <faktura@sof15.se>", to=[self.receiver_email])

            mail.send()

    def send_update(self):
        context = {
            'invoice': self,
            'bg': settings.INVAR_BG,
            'iban': settings.INVAR_IBAN,
            'bic_swift': settings.INVAR_BIC_SWIFT,
        }

        mail = TemplatedEmail(subject_template='invar/email/invoice_update_subject.txt',
                              body_template_html='invar/email/invoice_update.html', context=context,
                              from_email="Faktura SOF15 <faktura@sof15.se>", to=[self.receiver_email])

        mail.send()

    def send_invalidation(self):
        context = {
            'invoice': self
        }

        mail = TemplatedEmail(subject_template='invar/email/invoice_invalidation_subject.txt',
                              body_template_html='invar/email/invoice_invalidation.html', context=context,
                              from_email="Faktura SOF15 <faktura@sof15.se>", to=[self.receiver_email])

        mail.send()

    def _copy_rows(self, target):
        for i in self.rows.all():
            i._copy_to(target)

    def copy(self, keep_dates=False):
        rows = self.rows.all()
        new = deepcopy(self)
        new.pk = None

        if not keep_dates:
            new.issue_date = now()
            new.due_date = now() + timedelta(days=settings.INVAR_DUE_DAYS)

        new.save()

        for i in rows:
            i._copy_to(new)

        return new

    def invalidate(self, replacement=None):
        invalidation = InvoiceInvalidation(invoice=self)

        if replacement:
            invalidation.replacement = replacement
            self.handle.invoice = replacement
            self.handle.save()

        invalidation.save()

        return invalidation

class InvoiceInvalidation(models.Model):
    timestamp = models.DateTimeField(auto_now_add=True, verbose_name=_('timestamp'))
    invoice = models.OneToOneField('Invoice', related_name='invalidation', verbose_name=_('invoice'))
    replacement = models.OneToOneField('Invoice', related_name='replacing_invalidation', null=True, verbose_name=_('replacement invoice'))

    class Meta:
        verbose_name = _('invoice invalidation')
        verbose_name_plural = _('invoice invalidations')

class InvoiceHandle(models.Model):
    invoice = models.OneToOneField('Invoice', related_name='handle', verbose_name=_('invoice'))

    class Meta:
        verbose_name = _('invoice handle')
        verbose_name_plural = _('invoice handles')

    def __str__(self):
        return self.ocr

    @property
    def ocr(self):
        return ocr.generate(self.id)

class PersonInvoiceHandle(models.Model):
    handle = models.OneToOneField('InvoiceHandle', related_name='person_handle', verbose_name=_('handle'))
    person = models.ForeignKey('tickle.Person', related_name='invoice_handles', verbose_name=_('person'))

    class Meta:
        verbose_name = _('personal invoice handle')
        verbose_name_plural = _('personal invoice handles')

class InvoiceRowQuerySet(models.QuerySet):
    pass

class InvoiceRow(models.Model):
    invoice = models.ForeignKey('Invoice', related_name='rows', verbose_name=_('invoice'))
    title = models.CharField(max_length=255, verbose_name=_('title'))
    description = models.TextField(blank=True, verbose_name=_('description'))
    person = models.CharField(max_length=256, blank=True, verbose_name=_('person'))
    quantity = models.PositiveIntegerField(default=1, verbose_name=_('quantity'))
    price = models.DecimalField(max_digits=9, decimal_places=2, verbose_name=_('price'))

    objects = InvoiceRowQuerySet.as_manager()

    class Meta:
        verbose_name = _('invoice row')
        verbose_name_plural = _('invoice rows')

    def __str__(self):
        return str(self.pk)

    @property
    def subtotal(self):
        return self.price * self.quantity

    def _copy_to(self, invoice):
        holding_row = self.holding_row
        self.pk = None
        self.invoice = invoice
        self.save()

        holding_row.pk = None
        holding_row.invoice_row = self
        holding_row.save()

    def _set_person(self, person):
        self.person = '{0} ({1})'.format(person.full_name, person.pid)

class HoldingInvoiceRowQuerySet(models.QuerySet):
    def current(self):
        return self.get(invoice_row__invoice__invalidation__isnull=True)

    def current_invoice(self):
        return self.current().invoice_row.invoice

    def invoice_rows(self):
        return InvoiceRow.objects.filter(holding_row__in=self)

class HoldingInvoiceRow(models.Model):
    invoice_row = models.OneToOneField('InvoiceRow', related_name='holding_row', verbose_name=_('invoice row'))
    holding = models.ForeignKey('tickle.Holding', related_name='holding_invoice_rows', verbose_name=_('holding'))

    objects = HoldingInvoiceRowQuerySet.as_manager()

    class Meta:
        verbose_name = _('holding invoice row')
        verbose_name_plural = _('holding invoice rows')

class Transaction(models.Model):
    timestamp = models.DateTimeField(auto_now_add=True, verbose_name=_('timestamp'))
    amount = models.DecimalField(max_digits=9, decimal_places=2, verbose_name=_('amount'))
    reference = models.CharField(max_length=256, verbose_name=_('reference'))

    class Meta:
        verbose_name = _('transaction')
        verbose_name_plural = _('transactions')

class TransactionMatch(models.Model):
    transaction = models.OneToOneField('Transaction', related_name='match', verbose_name=_('transaction'))
    handle = models.ForeignKey('InvoiceHandle', related_name='transaction_matches', verbose_name=_('invoice handle'))

    class Meta:
        verbose_name = _('transaction match')
        verbose_name_plural = _('transaction matches')
<commit_msg>Added ExpressionWrapper<commit_after># -*- coding: utf-8 -*-
from __future__ import unicode_literals
import datetime
from copy import deepcopy
from datetime import timedelta

from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ungettext_lazy, ugettext_lazy as _
from django.db import models
from django.db.models import Sum, F, ExpressionWrapper
from django.utils.timezone import now
from django.conf import settings

from tickle.utils.mail import TemplatedEmail
from invar.utils import ocr

def default_invoice_issue_date():
    return now()

def default_invoice_due_date():
    return now() + timedelta(days=settings.INVAR_DUE_DAYS)

@python_2_unicode_compatible
class Invoice(models.Model):
    receiver_name = models.CharField(max_length=255, blank=True, verbose_name=_('receiver name'))
    receiver_organisation = models.CharField(max_length=255, blank=True, verbose_name=_('receiver organisation'))
    receiver_pid = models.CharField(max_length=11, blank=True, verbose_name=_('receiver PID'))
    receiver_email = models.EmailField(verbose_name=_('receiver email address'))

    issue_date = models.DateField(null=True, blank=True, default=default_invoice_issue_date, verbose_name=_('issue date'))
    due_date = models.DateField(null=True, blank=True, default=default_invoice_due_date, verbose_name=_('due date'))

    class Meta:
        ordering = ('pk',)

        verbose_name = _('invoice')
        verbose_name_plural = _('invoices')

    def __str__(self):
        return str(self.pk)

    def connect_handle(self):
        if not hasattr(self, 'invalidation') and not hasattr(self, 'handle'):
            InvoiceHandle.objects.create(invoice=self)

    @property
    def ocr(self):
        return self.handle.ocr

    @property
    def total(self):
        return self.rows.aggregate(total=ExpressionWrapper(Sum(F('price') * F('quantity')), output_field=models.DecimalField()))['total']

    def send(self):
        if self.total != 0:
            context = {
                'invoice': self,
                'bg': settings.INVAR_BG,
                'iban': settings.INVAR_IBAN,
                'bic_swift': settings.INVAR_BIC_SWIFT,
            }

            mail = TemplatedEmail(subject_template='invar/email/invoice_subject.txt',
                                  body_template_html='invar/email/invoice.html', context=context,
                                  from_email="Faktura SOF15 <faktura@sof15.se>", to=[self.receiver_email])

            mail.send()

    def send_update(self):
        context = {
            'invoice': self,
            'bg': settings.INVAR_BG,
            'iban': settings.INVAR_IBAN,
            'bic_swift': settings.INVAR_BIC_SWIFT,
        }

        mail = TemplatedEmail(subject_template='invar/email/invoice_update_subject.txt',
                              body_template_html='invar/email/invoice_update.html', context=context,
                              from_email="Faktura SOF15 <faktura@sof15.se>", to=[self.receiver_email])

        mail.send()

    def send_invalidation(self):
        context = {
            'invoice': self
        }

        mail = TemplatedEmail(subject_template='invar/email/invoice_invalidation_subject.txt',
                              body_template_html='invar/email/invoice_invalidation.html', context=context,
                              from_email="Faktura SOF15 <faktura@sof15.se>", to=[self.receiver_email])

        mail.send()

    def _copy_rows(self, target):
        for i in self.rows.all():
            i._copy_to(target)

    def copy(self, keep_dates=False):
        rows = self.rows.all()
        new = deepcopy(self)
        new.pk = None

        if not keep_dates:
            new.issue_date = now()
            new.due_date = now() + timedelta(days=settings.INVAR_DUE_DAYS)

        new.save()

        for i in rows:
            i._copy_to(new)

        return new

    def invalidate(self, replacement=None):
        invalidation = InvoiceInvalidation(invoice=self)

        if replacement:
            invalidation.replacement = replacement
            self.handle.invoice = replacement
            self.handle.save()

        invalidation.save()

        return invalidation

class InvoiceInvalidation(models.Model):
    timestamp = models.DateTimeField(auto_now_add=True, verbose_name=_('timestamp'))
    invoice = models.OneToOneField('Invoice', related_name='invalidation', verbose_name=_('invoice'))
    replacement = models.OneToOneField('Invoice', related_name='replacing_invalidation', null=True, verbose_name=_('replacement invoice'))

    class Meta:
        verbose_name = _('invoice invalidation')
        verbose_name_plural = _('invoice invalidations')

class InvoiceHandle(models.Model):
    invoice = models.OneToOneField('Invoice', related_name='handle', verbose_name=_('invoice'))

    class Meta:
        verbose_name = _('invoice handle')
        verbose_name_plural = _('invoice handles')

    def __str__(self):
        return self.ocr

    @property
    def ocr(self):
        return ocr.generate(self.id)

class PersonInvoiceHandle(models.Model):
    handle = models.OneToOneField('InvoiceHandle', related_name='person_handle', verbose_name=_('handle'))
    person = models.ForeignKey('tickle.Person', related_name='invoice_handles', verbose_name=_('person'))

    class Meta:
        verbose_name = _('personal invoice handle')
        verbose_name_plural = _('personal invoice handles')

class InvoiceRowQuerySet(models.QuerySet):
    pass

class InvoiceRow(models.Model):
    invoice = models.ForeignKey('Invoice', related_name='rows', verbose_name=_('invoice'))
    title = models.CharField(max_length=255, verbose_name=_('title'))
    description = models.TextField(blank=True, verbose_name=_('description'))
    person = models.CharField(max_length=256, blank=True, verbose_name=_('person'))
    quantity = models.PositiveIntegerField(default=1, verbose_name=_('quantity'))
    price = models.DecimalField(max_digits=9, decimal_places=2, verbose_name=_('price'))

    objects = InvoiceRowQuerySet.as_manager()

    class Meta:
        verbose_name = _('invoice row')
        verbose_name_plural = _('invoice rows')

    def __str__(self):
        return str(self.pk)

    @property
    def subtotal(self):
        return self.price * self.quantity

    def _copy_to(self, invoice):
        holding_row = self.holding_row
        self.pk = None
        self.invoice = invoice
        self.save()

        holding_row.pk = None
        holding_row.invoice_row = self
        holding_row.save()

    def _set_person(self, person):
        self.person = '{0} ({1})'.format(person.full_name, person.pid)

class HoldingInvoiceRowQuerySet(models.QuerySet):
    def current(self):
        return self.get(invoice_row__invoice__invalidation__isnull=True)

    def current_invoice(self):
        return self.current().invoice_row.invoice

    def invoice_rows(self):
        return InvoiceRow.objects.filter(holding_row__in=self)

class HoldingInvoiceRow(models.Model):
    invoice_row = models.OneToOneField('InvoiceRow', related_name='holding_row', verbose_name=_('invoice row'))
    holding = models.ForeignKey('tickle.Holding', related_name='holding_invoice_rows', verbose_name=_('holding'))

    objects = HoldingInvoiceRowQuerySet.as_manager()

    class Meta:
        verbose_name = _('holding invoice row')
        verbose_name_plural = _('holding invoice rows')

class Transaction(models.Model):
    timestamp = models.DateTimeField(auto_now_add=True, verbose_name=_('timestamp'))
    amount = models.DecimalField(max_digits=9, decimal_places=2, verbose_name=_('amount'))
    reference = models.CharField(max_length=256, verbose_name=_('reference'))

    class Meta:
        verbose_name = _('transaction')
        verbose_name_plural = _('transactions')

class TransactionMatch(models.Model):
    transaction = models.OneToOneField('Transaction', related_name='match', verbose_name=_('transaction'))
    handle = models.ForeignKey('InvoiceHandle', related_name='transaction_matches', verbose_name=_('invoice handle'))

    class Meta:
        verbose_name = _('transaction match')
        verbose_name_plural = _('transaction matches')
<|endoftext|>


<commit_before><commit_msg>Remove chrome://net-internals from special tabs test<commit_after><|endoftext|>