<commit_before># Copyright (c) 2014, Salesforce.com, Inc.  All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# - Redistributions of source code must retain the above copyright
#   notice, this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in the
#   documentation and/or other materials provided with the distribution.
# - Neither the name of Salesforce.com nor the names of its contributors
#   may be used to endorse or promote products derived from this
#   software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import os
from itertools import izip
from nose.tools import assert_true, assert_equal
from distributions.dbg.random import sample_bernoulli
from distributions.fileutil import tempdir
from distributions.io.stream import open_compressed
from loom.schema_pb2 import ProductValue, CrossCat, Query
from loom.test.util import for_each_dataset, CLEANUP_ON_ERROR
import loom.query
from loom.query import SingleSampleProtobufServer, MultiSampleProtobufServer
from loom.query import protobuf_to_data_row
from util import load_rows

CONFIG = {}

def get_example_requests(model, rows, query_type='mixed'):
    assert query_type in ['sample', 'score', 'mixed']
    cross_cat = CrossCat()
    with open_compressed(model, 'rb') as f:
        cross_cat.ParseFromString(f.read())
    feature_count = sum(len(kind.featureids) for kind in cross_cat.kinds)
    featureids = range(feature_count)

    nontrivials = [True] * feature_count
    for kind in cross_cat.kinds:
        fs = iter(kind.featureids)
        for model in loom.schema.MODELS.iterkeys():
            for shared in getattr(kind.product_model, model):
                f = fs.next()
                if model == 'dd':
                    if len(shared.alphas) == 0:
                        nontrivials[f] = False
                elif model == 'dpd':
                    if len(shared.betas) == 0:
                        nontrivials[f] = False
    all_observed = nontrivials[:]
    none_observed = [False] * feature_count

    observeds = []
    observeds.append(all_observed)
    for f, nontrivial in izip(featureids, nontrivials):
        if nontrivial:
            observed = all_observed[:]
            observed[f] = False
            observeds.append(observed)
    for f in featureids:
        observed = [
            nontrivial and sample_bernoulli(0.5)
            for nontrivial in nontrivials
        ]
        observeds.append(observed)
    for f, nontrivial in izip(featureids, nontrivials):
        if nontrivial:
            observed = none_observed[:]
            observed[f] = True
            observeds.append(observed)
    observeds.append(none_observed)

    requests = []
    for i, observed in enumerate(observeds):
        request = Query.Request()
        request.id = "example-{}".format(i)
        if query_type in ['sample', 'mixed']:
            request.sample.data.observed.sparsity = ProductValue.Observed.DENSE
            request.sample.data.observed.dense[:] = none_observed
            request.sample.to_sample.sparsity = ProductValue.Observed.DENSE
            request.sample.to_sample.dense[:] = observed
            request.sample.sample_count = 1
        if query_type in ['score', 'mixed']:
            request.score.data.observed.sparsity = ProductValue.Observed.DENSE
            request.score.data.observed.dense[:] = none_observed
        requests.append(request)
    for row in load_rows(rows)[:20]:
        i += 1
        request = Query.Request()
        request.id = "example-{}".format(i)
        if query_type in ['sample', 'mixed']:
            request.sample.sample_count = 1
            request.sample.data.MergeFrom(row.data)
            request.sample.to_sample.sparsity = ProductValue.Observed.DENSE
            for is_observed in row.data.observed.dense:
                request.sample.to_sample.dense.append(not is_observed)
        if query_type in ['score', 'mixed']:
            request.score.data.MergeFrom(row.data)
        requests.append(request)
    return requests

def get_server(Server, model, groups):
    config_in = os.path.abspath('config.pb.gz')
    loom.config.config_dump(CONFIG, config_in)
    kwargs = {
        'config_in': config_in,
        'model_in': model,
        'groups_in': groups,
        'debug': True,
    }
    return Server(**kwargs)

def check_response(request, response):
    assert_equal(request.id, response.id)
    assert_equal(len(response.error), 0)

def get_response(server, request):
    server.send(request)
    return server.receive()

def _test_server(Server, requests, args):
    with get_server(Server, *args) as server:
        query_server = loom.query.QueryServer(server)
        for request in requests:
            response = get_response(server, request)
            check_response(request, response)
            if request.HasField('sample'):
                assert_equal(len(response.sample.samples), 1)
                pod_request = protobuf_to_data_row(request.sample.data)
                to_sample = request.sample.to_sample.dense[:]
                query_server.sample(to_sample, pod_request)
            if request.HasField('score'):
                assert_true(isinstance(response.score.score, float))
                pod_request = protobuf_to_data_row(request.score.data)
                query_server.score(pod_request)

@for_each_dataset
def test_sample_one(model, groups, rows, **unused):
    requests = get_example_requests(model, rows, 'sample')
    with tempdir(cleanup_on_error=CLEANUP_ON_ERROR):
        args = [model, groups]
        _test_server(SingleSampleProtobufServer, requests, args)

@for_each_dataset
def test_sample_multi(model, groups, rows, **unused):
    requests = get_example_requests(model, rows, 'sample')
    with tempdir(cleanup_on_error=CLEANUP_ON_ERROR):
        args = [[model, model], [groups, groups]]
        _test_server(MultiSampleProtobufServer, requests, args)

@for_each_dataset
def test_score_one(model, groups, rows, **unused):
    requests = get_example_requests(model, rows, 'score')
    with tempdir(cleanup_on_error=CLEANUP_ON_ERROR):
        args = [model, groups]
        _test_server(SingleSampleProtobufServer, requests, args)

@for_each_dataset
def test_score_multi(model, groups, rows, **unused):
    requests = get_example_requests(model, rows, 'score')
    with tempdir(cleanup_on_error=CLEANUP_ON_ERROR):
        args = [[model, model], [groups, groups]]
        _test_server(MultiSampleProtobufServer, requests, args)
<commit_msg>Avoid sampling trivial features in get_example_requests<commit_after># Copyright (c) 2014, Salesforce.com, Inc.  All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# - Redistributions of source code must retain the above copyright
#   notice, this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in the
#   documentation and/or other materials provided with the distribution.
# - Neither the name of Salesforce.com nor the names of its contributors
#   may be used to endorse or promote products derived from this
#   software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import os
from itertools import izip
from nose.tools import assert_true, assert_equal
from distributions.dbg.random import sample_bernoulli
from distributions.fileutil import tempdir
from distributions.io.stream import open_compressed
from loom.schema_pb2 import ProductValue, CrossCat, Query
from loom.test.util import for_each_dataset, CLEANUP_ON_ERROR
import loom.query
from loom.query import SingleSampleProtobufServer, MultiSampleProtobufServer
from loom.query import protobuf_to_data_row
from util import load_rows

CONFIG = {}

def get_example_requests(model, rows, query_type='mixed'):
    assert query_type in ['sample', 'score', 'mixed']
    cross_cat = CrossCat()
    with open_compressed(model, 'rb') as f:
        cross_cat.ParseFromString(f.read())
    feature_count = sum(len(kind.featureids) for kind in cross_cat.kinds)
    featureids = range(feature_count)

    nontrivials = [True] * feature_count
    for kind in cross_cat.kinds:
        fs = iter(kind.featureids)
        for model in loom.schema.MODELS.iterkeys():
            for shared in getattr(kind.product_model, model):
                f = fs.next()
                if model == 'dd':
                    if len(shared.alphas) == 0:
                        nontrivials[f] = False
                elif model == 'dpd':
                    if len(shared.betas) == 0:
                        nontrivials[f] = False
    all_observed = nontrivials[:]
    none_observed = [False] * feature_count

    observeds = []
    observeds.append(all_observed)
    for f, nontrivial in izip(featureids, nontrivials):
        if nontrivial:
            observed = all_observed[:]
            observed[f] = False
            observeds.append(observed)
    for f in featureids:
        observed = [
            nontrivial and sample_bernoulli(0.5)
            for nontrivial in nontrivials
        ]
        observeds.append(observed)
    for f, nontrivial in izip(featureids, nontrivials):
        if nontrivial:
            observed = none_observed[:]
            observed[f] = True
            observeds.append(observed)
    observeds.append(none_observed)

    requests = []
    for i, observed in enumerate(observeds):
        request = Query.Request()
        request.id = "example-{}".format(i)
        if query_type in ['sample', 'mixed']:
            request.sample.data.observed.sparsity = ProductValue.Observed.DENSE
            request.sample.data.observed.dense[:] = none_observed
            request.sample.to_sample.sparsity = ProductValue.Observed.DENSE
            request.sample.to_sample.dense[:] = observed
            request.sample.sample_count = 1
        if query_type in ['score', 'mixed']:
            request.score.data.observed.sparsity = ProductValue.Observed.DENSE
            request.score.data.observed.dense[:] = none_observed
        requests.append(request)
    for row in load_rows(rows)[:20]:
        i += 1
        request = Query.Request()
        request.id = "example-{}".format(i)
        if query_type in ['sample', 'mixed']:
            request.sample.sample_count = 1
            request.sample.data.MergeFrom(row.data)
            request.sample.to_sample.sparsity = ProductValue.Observed.DENSE
            conditions = izip(nontrivials, row.data.observed.dense)
            for nontrivial, is_observed in conditions:
                to_sample = nontrivial and not is_observed
                request.sample.to_sample.dense.append(to_sample)
        if query_type in ['score', 'mixed']:
            request.score.data.MergeFrom(row.data)
        requests.append(request)
    return requests

def get_server(Server, model, groups):
    config_in = os.path.abspath('config.pb.gz')
    loom.config.config_dump(CONFIG, config_in)
    kwargs = {
        'config_in': config_in,
        'model_in': model,
        'groups_in': groups,
        'debug': True,
    }
    return Server(**kwargs)

def check_response(request, response):
    assert_equal(request.id, response.id)
    assert_equal(len(response.error), 0)

def get_response(server, request):
    server.send(request)
    return server.receive()

def _test_server(Server, requests, args):
    with get_server(Server, *args) as server:
        query_server = loom.query.QueryServer(server)
        for request in requests:
            response = get_response(server, request)
            check_response(request, response)
            if request.HasField('sample'):
                assert_equal(len(response.sample.samples), 1)
                pod_request = protobuf_to_data_row(request.sample.data)
                to_sample = request.sample.to_sample.dense[:]
                query_server.sample(to_sample, pod_request)
            if request.HasField('score'):
                assert_true(isinstance(response.score.score, float))
                pod_request = protobuf_to_data_row(request.score.data)
                query_server.score(pod_request)

@for_each_dataset
def test_sample_one(model, groups, rows, **unused):
    requests = get_example_requests(model, rows, 'sample')
    with tempdir(cleanup_on_error=CLEANUP_ON_ERROR):
        args = [model, groups]
        _test_server(SingleSampleProtobufServer, requests, args)

@for_each_dataset
def test_sample_multi(model, groups, rows, **unused):
    requests = get_example_requests(model, rows, 'sample')
    with tempdir(cleanup_on_error=CLEANUP_ON_ERROR):
        args = [[model, model], [groups, groups]]
        _test_server(MultiSampleProtobufServer, requests, args)

@for_each_dataset
def test_score_one(model, groups, rows, **unused):
    requests = get_example_requests(model, rows, 'score')
    with tempdir(cleanup_on_error=CLEANUP_ON_ERROR):
        args = [model, groups]
        _test_server(SingleSampleProtobufServer, requests, args)

@for_each_dataset
def test_score_multi(model, groups, rows, **unused):
    requests = get_example_requests(model, rows, 'score')
    with tempdir(cleanup_on_error=CLEANUP_ON_ERROR):
        args = [[model, model], [groups, groups]]
        _test_server(MultiSampleProtobufServer, requests, args)
<|endoftext|>


<commit_before>from django.http import HttpResponse
from lrs import objects, models
from lrs.util import etag
import json
from lrs.objects import Actor, Activity, ActivityState, ActivityProfile, Statement
import uuid
import pdb
import retrieve_statement

import pprint

def statements_post(req_dict):
    #TODO: more elegant way of doing this?
    if req_dict['method'] == 'GET': #type(req_dict) is dict:
        stmtList = retrieve_statement.complexGet(req_dict)
        # pdb.set_trace()
        statementResult = retrieve_statement.buildStatementResult(req_dict.copy(),stmtList)
        return HttpResponse(json.dumps(statementResult, indent=4), mimetype="application/json", status=200)
    else:
        stmtResponses = []
        if not type(req_dict['body']) is list:
            stmt = Statement.Statement(req_dict['body'], auth=req_dict['user']).statement
            stmtResponses.append(str(stmt.statement_id))
        else:
            for st in req_dict['body']:
                stmt = Statement.Statement(st, auth=req_dict['user']).statement
                stmtResponses.append(str(stmt.statement_id))
        # return HttpResponse("StatementID(s) = %s" % stmtResponses, status=200)
        return HttpResponse(stmtResponses, status=200)

def statements_put(req_dict):
    statementId = req_dict['body']['statementId']
    try:
        stmt = models.statement.objects.get(statement_id=statementId)
    except models.statement.DoesNotExist:
        stmt = Statement.Statement(req_dict['body'], auth=req_dict['user']).statement
        return HttpResponse("StatementID = %s" % statementId, status=200)
    else:
        return HttpResponse("Error: %s already exists" % statementId, status=204)

def statements_get(req_dict):
    # pdb.set_trace()
    statementResult = {}
    try:
        statementId = req_dict['statementId']
        st = Statement.Statement(statement_id=statementId, get=True)
        stmt_data = json.dumps(st.get_full_statement_json(), indent=4, sort_keys=True)
        # statementResult['statements'] = st.get_full_statement_json()
        return HttpResponse(stmt_data, mimetype="application/json", status=200)
    except:
        stmtList = retrieve_statement.complexGet(req_dict)
        statementResult = retrieve_statement.buildStatementResult(req_dict.copy(), stmtList)

    return HttpResponse(json.dumps(statementResult, indent=4), mimetype="application/json", status=200)

def activity_state_put(req_dict):
    # test ETag for concurrency
    actstate = ActivityState.ActivityState(req_dict)
    actstate.put()
    return HttpResponse("", status=204)

def activity_state_get(req_dict):
    # add ETag for concurrency
    actstate = ActivityState.ActivityState(req_dict)
    stateId = req_dict.get('stateId', None)
    if stateId: # state id means we want only 1 item
        resource = actstate.get()
        response = HttpResponse(resource.state.read())
        response['ETag'] = '"%s"' %resource.etag
    else: # no state id means we want an array of state ids
        resource = actstate.get_ids()
        response = HttpResponse(json.dumps([k for k in resource]), content_type="application/json")
    return response

def activity_state_delete(req_dict):
    actstate = ActivityState.ActivityState(req_dict)
    actstate.delete()
    return HttpResponse('', status=204)

def activity_profile_put(req_dict):
    #Instantiate ActivityProfile
    ap = ActivityProfile.ActivityProfile()

    #Put profile and return 204 response
    ap.put_profile(req_dict)
    return HttpResponse('Success -- activity profile - method = PUT - profileId = %s' % req_dict['profileId'], status=200)

def activity_profile_get(req_dict):
    #TODO:need eTag for returning list of IDs?

    #Instantiate ActivityProfile
    ap = ActivityProfile.ActivityProfile()

    #Get profileId and activityId
    profileId = req_dict.get('profileId', None)
    activityId = req_dict.get('activityId', None)

    #If the profileId exists, get the profile and return it in the response
    if profileId:
        resource = ap.get_profile(profileId, activityId)
        response = HttpResponse(resource.profile.read(), content_type=resource.content_type)
        response['ETag'] = '"%s"' % resource.etag
        return response

    #Return IDs of profiles stored since profileId was not submitted
    since = req_dict.get('since', None)
    resource = ap.get_profile_ids(since, activityId)
    response = HttpResponse(json.dumps([k for k in resource]), content_type="application/json")
    response['since'] = since
    #response['ETag'] = '"%s"' % resource.etag
    return response

def activity_profile_delete(req_dict):
    #Instantiate activity profile
    ap = ActivityProfile.ActivityProfile()

    #Delete profile and return success
    ap.delete_profile(req_dict)
    return HttpResponse('Success -- activity profile - method = DELETE - profileId = %s' % req_dict['profileId'], status=200)

def activities_get(req_dict):
    activityId = req_dict['activityId']
    a = Activity.Activity(activity_id=activityId, get=True)
    data = a.get_full_activity_json()
    return HttpResponse(stream_response_generator(data), mimetype="application/json")

#Generate JSON
def stream_response_generator(data):
    first = True
    yield '{'
    for k,v in data.items():
        if not first:
            yield ', '
        else:
            first = False
        #Catch next dictionaries
        if type(v) is dict:
            stream_response_generator(v)
        #Catch lists as dictionary values
        if type(v) is list:
            lfirst = True
            yield json.dumps(k)
            yield ': '
            yield '['
            for item in v:
                if not lfirst:
                    yield ', '
                else:
                    lfirst = False
                #Catch dictionaries as items in a list
                if type(item) is dict:
                    stream_response_generator(item)
                yield json.dumps(item)
            yield ']'
        else:
            yield json.dumps(k)
            yield ': '
            yield json.dumps(v)
    yield '}'

def actor_profile_put(req_dict):
    # test ETag for concurrency
    actor = req_dict['actor']
    a = Actor.Actor(actor, create=True)
    a.put_profile(req_dict)
    return HttpResponse("", status=204)

def actor_profile_get(req_dict):
    # add ETag for concurrency
    actor = req_dict['actor']
    a = Actor.Actor(actor)

    profileId = req_dict.get('profileId', None)
    if profileId:
        resource = a.get_profile(profileId)
        response = HttpResponse(resource.profile.read(), content_type=resource.content_type)
        response['ETag'] = '"%s"' % resource.etag
        return response

    since = req_dict.get('since', None)
    resource = a.get_profile_ids(since)
    response = HttpResponse(json.dumps([k for k in resource]), content_type="application/json")
    return response

def actor_profile_delete(req_dict):
    actor = req_dict['actor']
    a = Actor.Actor(actor)
    profileId = req_dict['profileId']
    a.delete_profile(profileId)
    return HttpResponse('', status=204)

def actors_get(req_dict):
    actor = req_dict['actor']
    a = Actor.Actor(actor)
    return HttpResponse(a.full_actor_json(), mimetype="application/json")

# so far unnecessary
class ProcessError(Exception):
    def __init__(self, msg):
        self.message = msg
    def __str__(self):
        return repr(self.message)
<commit_msg>removed code no longer needed in statement post processing<commit_after>from django.http import HttpResponse
from lrs import objects, models
from lrs.util import etag
import json
from lrs.objects import Actor, Activity, ActivityState, ActivityProfile, Statement
import uuid
import pdb
import retrieve_statement

import pprint

def statements_post(req_dict):
    stmtResponses = []
    if not type(req_dict['body']) is list:
        stmt = Statement.Statement(req_dict['body'], auth=req_dict['user']).statement
        stmtResponses.append(str(stmt.statement_id))
    else:
        for st in req_dict['body']:
            stmt = Statement.Statement(st, auth=req_dict['user']).statement
            stmtResponses.append(str(stmt.statement_id))
    # return HttpResponse("StatementID(s) = %s" % stmtResponses, status=200)
    return HttpResponse(stmtResponses, status=200)

def statements_put(req_dict):
    statementId = req_dict['body']['statementId']
    try:
        stmt = models.statement.objects.get(statement_id=statementId)
    except models.statement.DoesNotExist:
        stmt = Statement.Statement(req_dict['body'], auth=req_dict['user']).statement
        return HttpResponse("StatementID = %s" % statementId, status=200)
    else:
        return HttpResponse("Error: %s already exists" % statementId, status=204)

def statements_get(req_dict):
    # pdb.set_trace()
    statementResult = {}
    try:
        statementId = req_dict['statementId']
        st = Statement.Statement(statement_id=statementId, get=True)
        stmt_data = json.dumps(st.get_full_statement_json(), indent=4, sort_keys=True)
        # statementResult['statements'] = st.get_full_statement_json()
        return HttpResponse(stmt_data, mimetype="application/json", status=200)
    except:
        stmtList = retrieve_statement.complexGet(req_dict)
        statementResult = retrieve_statement.buildStatementResult(req_dict.copy(), stmtList)

    return HttpResponse(json.dumps(statementResult, indent=4), mimetype="application/json", status=200)

def activity_state_put(req_dict):
    # test ETag for concurrency
    actstate = ActivityState.ActivityState(req_dict)
    actstate.put()
    return HttpResponse("", status=204)

def activity_state_get(req_dict):
    # add ETag for concurrency
    actstate = ActivityState.ActivityState(req_dict)
    stateId = req_dict.get('stateId', None)
    if stateId: # state id means we want only 1 item
        resource = actstate.get()
        response = HttpResponse(resource.state.read())
        response['ETag'] = '"%s"' %resource.etag
    else: # no state id means we want an array of state ids
        resource = actstate.get_ids()
        response = HttpResponse(json.dumps([k for k in resource]), content_type="application/json")
    return response

def activity_state_delete(req_dict):
    actstate = ActivityState.ActivityState(req_dict)
    actstate.delete()
    return HttpResponse('', status=204)

def activity_profile_put(req_dict):
    #Instantiate ActivityProfile
    ap = ActivityProfile.ActivityProfile()

    #Put profile and return 204 response
    ap.put_profile(req_dict)
    return HttpResponse('Success -- activity profile - method = PUT - profileId = %s' % req_dict['profileId'], status=200)

def activity_profile_get(req_dict):
    #TODO:need eTag for returning list of IDs?

    #Instantiate ActivityProfile
    ap = ActivityProfile.ActivityProfile()

    #Get profileId and activityId
    profileId = req_dict.get('profileId', None)
    activityId = req_dict.get('activityId', None)

    #If the profileId exists, get the profile and return it in the response
    if profileId:
        resource = ap.get_profile(profileId, activityId)
        response = HttpResponse(resource.profile.read(), content_type=resource.content_type)
        response['ETag'] = '"%s"' % resource.etag
        return response

    #Return IDs of profiles stored since profileId was not submitted
    since = req_dict.get('since', None)
    resource = ap.get_profile_ids(since, activityId)
    response = HttpResponse(json.dumps([k for k in resource]), content_type="application/json")
    response['since'] = since
    #response['ETag'] = '"%s"' % resource.etag
    return response

def activity_profile_delete(req_dict):
    #Instantiate activity profile
    ap = ActivityProfile.ActivityProfile()

    #Delete profile and return success
    ap.delete_profile(req_dict)
    return HttpResponse('Success -- activity profile - method = DELETE - profileId = %s' % req_dict['profileId'], status=200)

def activities_get(req_dict):
    activityId = req_dict['activityId']
    a = Activity.Activity(activity_id=activityId, get=True)
    data = a.get_full_activity_json()
    return HttpResponse(stream_response_generator(data), mimetype="application/json")

#Generate JSON
def stream_response_generator(data):
    first = True
    yield '{'
    for k,v in data.items():
        if not first:
            yield ', '
        else:
            first = False
        #Catch next dictionaries
        if type(v) is dict:
            stream_response_generator(v)
        #Catch lists as dictionary values
        if type(v) is list:
            lfirst = True
            yield json.dumps(k)
            yield ': '
            yield '['
            for item in v:
                if not lfirst:
                    yield ', '
                else:
                    lfirst = False
                #Catch dictionaries as items in a list
                if type(item) is dict:
                    stream_response_generator(item)
                yield json.dumps(item)
            yield ']'
        else:
            yield json.dumps(k)
            yield ': '
            yield json.dumps(v)
    yield '}'

def actor_profile_put(req_dict):
    # test ETag for concurrency
    actor = req_dict['actor']
    a = Actor.Actor(actor, create=True)
    a.put_profile(req_dict)
    return HttpResponse("", status=204)

def actor_profile_get(req_dict):
    # add ETag for concurrency
    actor = req_dict['actor']
    a = Actor.Actor(actor)

    profileId = req_dict.get('profileId', None)
    if profileId:
        resource = a.get_profile(profileId)
        response = HttpResponse(resource.profile.read(), content_type=resource.content_type)
        response['ETag'] = '"%s"' % resource.etag
        return response

    since = req_dict.get('since', None)
    resource = a.get_profile_ids(since)
    response = HttpResponse(json.dumps([k for k in resource]), content_type="application/json")
    return response

def actor_profile_delete(req_dict):
    actor = req_dict['actor']
    a = Actor.Actor(actor)
    profileId = req_dict['profileId']
    a.delete_profile(profileId)
    return HttpResponse('', status=204)

def actors_get(req_dict):
    actor = req_dict['actor']
    a = Actor.Actor(actor)
    return HttpResponse(a.full_actor_json(), mimetype="application/json")

# so far unnecessary
class ProcessError(Exception):
    def __init__(self, msg):
        self.message = msg
    def __str__(self):
        return repr(self.message)
<|endoftext|>


<commit_before>import tensorflow as tf

def resize_image(image, bboxes=None, min_size=None, max_size=None):
    """
    We need to resize image and (optionally) bounding boxes when the biggest
    side dimension is bigger than `max_size` or when the smaller side is
    smaller than `min_size`. If no max_size defined it won't scale down and if
    no min_size defined it won't scale up.

    Then, using the ratio we used, we need to properly scale the bounding
    boxes.

    Args:
        image: Tensor with image of shape (H, W, 3).
        bboxes: Optional Tensor with bounding boxes with shape (num_bboxes, 5).
            where we have (x_min, y_min, x_max, y_max, label) for each one.
        min_size: Min size of width or height.
        max_size: Max size of width or height.

    Returns:
        Dictionary containing:
            image: Tensor with scaled image.
            bboxes: Tensor with scaled (using the same factor as the image)
                bounding boxes with shape (num_bboxes, 5).
            scale_factor: Scale factor used to modify the image (1.0 means no
                change).
    """
    image_shape = tf.to_float(tf.shape(image))
    height = image_shape[0]
    width = image_shape[1]

    if min_size is not None:
        # We calculate the upscale factor, the rate we need to use to end up
        # with an image with it's lowest dimension at least `image_min_size`.
        # In case of being big enough the scale factor is 1. (no change)
        min_size = tf.to_float(min_size)
        min_dimension = tf.minimum(height, width)
        upscale_factor = tf.maximum(min_size / min_dimension, 1.)
    else:
        upscale_factor = 1.

    if max_size:
        # We do the same calculating the downscale factor, to end up with an
        # image where the biggest dimension is less than `image_max_size`.
        # When the image is small enough the scale factor is 1. (no change)
        max_size = tf.to_float(max_size)
        max_dimension = tf.maximum(height, width)
        downscale_factor = tf.minimum(max_size / max_dimension, 1.)
    else:
        downscale_factor = 1.

    scale_factor = upscale_factor * downscale_factor

    # New size is calculate using the scale factor and rounding to int.
    new_height = height * scale_factor
    new_width = width * scale_factor

    # Resize image using TensorFlow's own `resize_image` utility.
    image = tf.image.resize_images(
        image, tf.stack(tf.to_int32([new_height, new_width])),
        method=tf.image.ResizeMethod.BILINEAR
    )

    if bboxes is not None:
        # We normalize bounding boxes points before modifying the image.
        bboxes_float = tf.to_float(bboxes)
        x_min, y_min, x_max, y_max, label = tf.unstack(bboxes_float, axis=1)

        x_min = x_min / width
        y_min = y_min / height
        x_max = x_max / width
        y_max = y_max / height

        # Use new size to scale back the bboxes points to absolute values.
        x_min = tf.to_int32(x_min * new_width)
        y_min = tf.to_int32(y_min * new_height)
        x_max = tf.to_int32(x_max * new_width)
        y_max = tf.to_int32(y_max * new_height)
        label = tf.to_int32(label)  # Cast back to int.

        # Concat points and label to return a [num_bboxes, 5] tensor.
        bboxes = tf.stack([x_min, y_min, x_max, y_max, label], axis=1)
        return {
            'image': image,
            'bboxes': bboxes,
            'scale_factor': scale_factor,
        }

    return {
        'image': image,
        'scale_factor': scale_factor,
    }
<commit_msg>Adds flip image utility function<commit_after>import tensorflow as tf

def resize_image(image, bboxes=None, min_size=None, max_size=None):
    """
    We need to resize image and (optionally) bounding boxes when the biggest
    side dimension is bigger than `max_size` or when the smaller side is
    smaller than `min_size`. If no max_size defined it won't scale down and if
    no min_size defined it won't scale up.

    Then, using the ratio we used, we need to properly scale the bounding
    boxes.

    Args:
        image: Tensor with image of shape (H, W, 3).
        bboxes: Optional Tensor with bounding boxes with shape (num_bboxes, 5).
            where we have (x_min, y_min, x_max, y_max, label) for each one.
        min_size: Min size of width or height.
        max_size: Max size of width or height.

    Returns:
        Dictionary containing:
            image: Tensor with scaled image.
            bboxes: Tensor with scaled (using the same factor as the image)
                bounding boxes with shape (num_bboxes, 5).
            scale_factor: Scale factor used to modify the image (1.0 means no
                change).
    """
    image_shape = tf.to_float(tf.shape(image))
    height = image_shape[0]
    width = image_shape[1]

    if min_size is not None:
        # We calculate the upscale factor, the rate we need to use to end up
        # with an image with it's lowest dimension at least `image_min_size`.
        # In case of being big enough the scale factor is 1. (no change)
        min_size = tf.to_float(min_size)
        min_dimension = tf.minimum(height, width)
        upscale_factor = tf.maximum(min_size / min_dimension, 1.)
    else:
        upscale_factor = tf.constant(1.)

    if max_size:
        # We do the same calculating the downscale factor, to end up with an
        # image where the biggest dimension is less than `image_max_size`.
        # When the image is small enough the scale factor is 1. (no change)
        max_size = tf.to_float(max_size)
        max_dimension = tf.maximum(height, width)
        downscale_factor = tf.minimum(max_size / max_dimension, 1.)
    else:
        downscale_factor = tf.constant(1.)

    scale_factor = upscale_factor * downscale_factor

    # New size is calculate using the scale factor and rounding to int.
    new_height = height * scale_factor
    new_width = width * scale_factor

    # Resize image using TensorFlow's own `resize_image` utility.
    image = tf.image.resize_images(
        image, tf.stack(tf.to_int32([new_height, new_width])),
        method=tf.image.ResizeMethod.BILINEAR
    )

    if bboxes is not None:
        # We normalize bounding boxes points before modifying the image.
        bboxes_float = tf.to_float(bboxes)
        x_min, y_min, x_max, y_max, label = tf.unstack(bboxes_float, axis=1)

        x_min = x_min / width
        y_min = y_min / height
        x_max = x_max / width
        y_max = y_max / height

        # Use new size to scale back the bboxes points to absolute values.
        x_min = tf.to_int32(x_min * new_width)
        y_min = tf.to_int32(y_min * new_height)
        x_max = tf.to_int32(x_max * new_width)
        y_max = tf.to_int32(y_max * new_height)
        label = tf.to_int32(label)  # Cast back to int.

        # Concat points and label to return a [num_bboxes, 5] tensor.
        bboxes = tf.stack([x_min, y_min, x_max, y_max, label], axis=1)
        return {
            'image': image,
            'bboxes': bboxes,
            'scale_factor': scale_factor,
        }

    return {
        'image': image,
        'scale_factor': scale_factor,
    }

def flip_image(image, bboxes=None, left_right=True, up_down=False):
    """Flips image on its axis for data augmentation.

    Args:
        image: Tensor with image of shape (H, W, 3).
        bboxes: Optional Tensor with bounding boxes with shape
            (total_bboxes, 5).
        left_right: Boolean flag to flip the image horizontally
            (left to right).
        up_down: Boolean flag to flip the image vertically (upside down)
    Returns:
        image: Flipped image with the same shape.
        bboxes: Tensor with the same shape.
    """

    image_shape = tf.to_float(tf.shape(image))
    height = image_shape[0]
    width = image_shape[1]

    if left_right:
        image = tf.image.flip_left_right(image)
        if bboxes is not None:
            x_min, y_min, x_max, y_max, label = tf.unstack(bboxes, axis=1)
            new_x_min = width - x_max - 1.
            new_y_min = y_min
            new_x_max = new_x_min + (x_max - x_min)
            new_y_max = y_max
            bboxes = tf.stack(
                [new_x_min, new_y_min, new_x_max, new_y_max, label], axis=1
            )

    if up_down:
        image = tf.image.flip_up_down(image)
        if bboxes is not None:
            x_min, y_min, x_max, y_max, label = tf.unstack(bboxes, axis=1)
            new_x_min = x_min
            new_y_min = height - y_max - 1.
            new_x_max = x_max
            new_y_max = new_y_min + (y_max - y_min)
            bboxes = tf.stack(
                [new_x_min, new_y_min, new_x_max, new_y_max, label], axis=1
            )

    return_dict = {'image': image}
    if bboxes is not None:
        return_dict['bboxes'] = bboxes

    return return_dict
<|endoftext|>


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

from __future__ import absolute_import
import logging

from django.conf import settings

from horizon import exceptions
from horizon.utils.memoized import memoized
from openstack_dashboard.api import base

from magnumclient.v1 import certificates
from magnumclient.v1 import client as magnum_client
from magnumclient.v1 import cluster_templates
from magnumclient.v1 import clusters

LOG = logging.getLogger(__name__)

CLUSTER_TEMPLATE_CREATE_ATTRS = cluster_templates.CREATION_ATTRIBUTES
CLUSTER_CREATE_ATTRS = clusters.CREATION_ATTRIBUTES
CERTIFICATE_CREATE_ATTRS = certificates.CREATION_ATTRIBUTES

def _cleanup_params(attrs, create, **params):
    args = {}
    for (key, value) in params.items():
        if key in attrs:
            if value is None:
                if create:
                    value = ''
                else:
                    continue
            args[str(key)] = str(value)
        elif create:
            raise exceptions.BadRequest(
                "Key must be in %s" % ",".join(attrs))
        if key == "labels":
            if isinstance(value, str) or isinstance(value, unicode):
                labels = {}
                vals = value.split(",")
                for v in vals:
                    kv = v.split("=", 1)
                    labels[kv[0]] = kv[1]
                args["labels"] = labels
            else:
                args["labels"] = value
    return args

def _create_patches(old, new):
    """"Create patches for updating cluster template and cluster

    Returns patches include operations for each parameters to update values
    """
    # old = {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D', 'e': 'E'}
    # new = {'a': 'A', 'c': 'c', 'd': None, 'e': '', 'f': 'F'}
    # patch = [
    #     {'op': 'add', 'path': '/f', 'value': 'F'}
    #     {'op': 'remove', 'path': '/b'},
    #     {'op': 'remove', 'path': '/e'},
    #     {'op': 'remove', 'path': '/d'},
    #     {'op': 'replace', 'path': '/c', 'value': 'c'}
    # ]

    patch = []

    for key in new:
        path = '/' + key
        if key in old and old[key] != new[key]:
            if new[key] is None or new[key] is '':
                patch.append({'op': 'remove', 'path': path})
            else:
                patch.append({'op': 'replace', 'path': path,
                              'value': new[key]})
        elif key not in old:
            patch.append({'op': 'add', 'path': path, 'value': new[key]})

    for key in old:
        path = '/' + key
        if key not in new:
            patch.append({'op': 'remove', 'path': path})

    return patch

@memoized
def magnumclient(request):
    magnum_url = ""
    try:
        magnum_url = base.url_for(request, 'container-infra')
    except exceptions.ServiceCatalogException:
        LOG.debug('No Container Infrastructure Management service is '
                  'configured.')
        return None

    LOG.debug('magnumclient connection created using the token "%s" and url'
              '"%s"' % (request.user.token.id, magnum_url))

    insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
    cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None)

    c = magnum_client.Client(username=request.user.username,
                             project_id=request.user.tenant_id,
                             input_auth_token=request.user.token.id,
                             magnum_url=magnum_url,
                             insecure=insecure,
                             cacert=cacert)
    return c

def cluster_template_create(request, **kwargs):
    args = _cleanup_params(CLUSTER_TEMPLATE_CREATE_ATTRS, True, **kwargs)
    return magnumclient(request).cluster_templates.create(**args)

def cluster_template_update(request, id, **kwargs):
    new = _cleanup_params(CLUSTER_TEMPLATE_CREATE_ATTRS, True, **kwargs)
    old = magnumclient(request).cluster_templates.get(id).to_dict()
    old = _cleanup_params(CLUSTER_TEMPLATE_CREATE_ATTRS, False, **old)
    patch = _create_patches(old, new)
    return magnumclient(request).cluster_templates.update(id, patch)

def cluster_template_delete(request, id):
    return magnumclient(request).cluster_templates.delete(id)

def cluster_template_list(request, limit=None, marker=None, sort_key=None,
                          sort_dir=None, detail=True):
    return magnumclient(request).cluster_templates.list(
        limit, marker, sort_key, sort_dir, detail)

def cluster_template_show(request, id):
    return magnumclient(request).cluster_templates.get(id)

def cluster_create(request, **kwargs):
    kwargs.pop("rollback")
    args = _cleanup_params(CLUSTER_CREATE_ATTRS, True, **kwargs)
    return magnumclient(request).clusters.create(**args)

def cluster_update(request, id, **kwargs):
    rollback = kwargs.pop("rollback")
    new = _cleanup_params(CLUSTER_CREATE_ATTRS, True, **kwargs)
    old = magnumclient(request).clusters.get(id).to_dict()
    old = _cleanup_params(CLUSTER_CREATE_ATTRS, False, **old)
    patch = _create_patches(old, new)
    return magnumclient(request).clusters.update(id, patch, rollback=rollback)

def cluster_delete(request, id):
    return magnumclient(request).clusters.delete(id)

def cluster_list(request, limit=None, marker=None, sort_key=None,
                 sort_dir=None, detail=True):
    return magnumclient(request).clusters.list(limit, marker, sort_key,
                                               sort_dir, detail)

def cluster_show(request, id):
    return magnumclient(request).clusters.get(id)

def certificate_create(request, **kwargs):
    args = {}
    for (key, value) in kwargs.items():
        if key in CERTIFICATE_CREATE_ATTRS:
            args[key] = value
        else:
            raise exceptions.BadRequest(
                "Key must be in %s" % ",".join(CERTIFICATE_CREATE_ATTRS))
    return magnumclient(request).certificates.create(**args)

def certificate_show(request, id):
    return magnumclient(request).certificates.get(id)

def certificate_rotate(request, id):
    args = {"cluster_uuid": id}
    return magnumclient(request).certificates.rotate_ca(**args)

def stats_list(request, limit=None, marker=None, sort_key=None,
               sort_dir=None, detail=True):
    return magnumclient(request).stats.list(
        limit, marker, sort_key, sort_dir, detail)
<commit_msg>Fix update for labels<commit_after>#  Copyright 2015 Cisco Systems.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

from __future__ import absolute_import
import logging

from django.conf import settings

from horizon import exceptions
from horizon.utils.memoized import memoized
from openstack_dashboard.api import base

from magnumclient.v1 import certificates
from magnumclient.v1 import client as magnum_client
from magnumclient.v1 import cluster_templates
from magnumclient.v1 import clusters

LOG = logging.getLogger(__name__)

CLUSTER_TEMPLATE_CREATE_ATTRS = cluster_templates.CREATION_ATTRIBUTES
CLUSTER_CREATE_ATTRS = clusters.CREATION_ATTRIBUTES
CERTIFICATE_CREATE_ATTRS = certificates.CREATION_ATTRIBUTES

def _cleanup_params(attrs, create, **params):
    args = {}
    for (key, value) in params.items():
        if key in attrs:
            if value is None:
                if create:
                    value = ''
                else:
                    continue
            args[str(key)] = str(value)
        elif create:
            raise exceptions.BadRequest(
                "Key must be in %s" % ",".join(attrs))
        if key == "labels":
            if isinstance(value, str) or isinstance(value, unicode):
                labels = {}
                vals = value.split(",")
                for v in vals:
                    kv = v.split("=", 1)
                    labels[kv[0]] = kv[1]
                args["labels"] = labels
            else:
                args["labels"] = value
    return args

def _create_patches(old, new):
    """"Create patches for updating cluster template and cluster

    Returns patches include operations for each parameters to update values
    """
    # old = {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D', 'e': 'E'}
    # new = {'a': 'A', 'c': 'c', 'd': None, 'e': '', 'f': 'F'}
    # patch = [
    #     {'op': 'add', 'path': '/f', 'value': 'F'}
    #     {'op': 'remove', 'path': '/b'},
    #     {'op': 'remove', 'path': '/e'},
    #     {'op': 'remove', 'path': '/d'},
    #     {'op': 'replace', 'path': '/c', 'value': 'c'}
    # ]

    patch = []

    for key in new:
        if key == 'labels':
            # NOTE(shu-mutou): labels for cluster template and cluster
            # are not updatable.
            continue
        path = '/' + key
        if key in old and old[key] != new[key]:
            if new[key] is None or new[key] is '':
                patch.append({'op': 'remove', 'path': path})
            else:
                patch.append({'op': 'replace', 'path': path,
                              'value': new[key]})
        elif key not in old:
            patch.append({'op': 'add', 'path': path, 'value': new[key]})

    for key in old:
        if key == 'labels':
            # NOTE(shu-mutou): labels for cluster template and cluster
            # are not updatable.
            continue
        path = '/' + key
        if key not in new:
            patch.append({'op': 'remove', 'path': path})

    return patch

@memoized
def magnumclient(request):
    magnum_url = ""
    try:
        magnum_url = base.url_for(request, 'container-infra')
    except exceptions.ServiceCatalogException:
        LOG.debug('No Container Infrastructure Management service is '
                  'configured.')
        return None

    LOG.debug('magnumclient connection created using the token "%s" and url'
              '"%s"' % (request.user.token.id, magnum_url))

    insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
    cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None)

    c = magnum_client.Client(username=request.user.username,
                             project_id=request.user.tenant_id,
                             input_auth_token=request.user.token.id,
                             magnum_url=magnum_url,
                             insecure=insecure,
                             cacert=cacert)
    return c

def cluster_template_create(request, **kwargs):
    args = _cleanup_params(CLUSTER_TEMPLATE_CREATE_ATTRS, True, **kwargs)
    return magnumclient(request).cluster_templates.create(**args)

def cluster_template_update(request, id, **kwargs):
    new = _cleanup_params(CLUSTER_TEMPLATE_CREATE_ATTRS, True, **kwargs)
    old = magnumclient(request).cluster_templates.get(id).to_dict()
    old = _cleanup_params(CLUSTER_TEMPLATE_CREATE_ATTRS, False, **old)
    patch = _create_patches(old, new)
    return magnumclient(request).cluster_templates.update(id, patch)

def cluster_template_delete(request, id):
    return magnumclient(request).cluster_templates.delete(id)

def cluster_template_list(request, limit=None, marker=None, sort_key=None,
                          sort_dir=None, detail=True):
    return magnumclient(request).cluster_templates.list(
        limit, marker, sort_key, sort_dir, detail)

def cluster_template_show(request, id):
    return magnumclient(request).cluster_templates.get(id)

def cluster_create(request, **kwargs):
    kwargs.pop("rollback")
    args = _cleanup_params(CLUSTER_CREATE_ATTRS, True, **kwargs)
    return magnumclient(request).clusters.create(**args)

def cluster_update(request, id, **kwargs):
    rollback = kwargs.pop("rollback")
    new = _cleanup_params(CLUSTER_CREATE_ATTRS, True, **kwargs)
    old = magnumclient(request).clusters.get(id).to_dict()
    old = _cleanup_params(CLUSTER_CREATE_ATTRS, False, **old)
    patch = _create_patches(old, new)
    return magnumclient(request).clusters.update(id, patch, rollback=rollback)

def cluster_delete(request, id):
    return magnumclient(request).clusters.delete(id)

def cluster_list(request, limit=None, marker=None, sort_key=None,
                 sort_dir=None, detail=True):
    return magnumclient(request).clusters.list(limit, marker, sort_key,
                                               sort_dir, detail)

def cluster_show(request, id):
    return magnumclient(request).clusters.get(id)

def certificate_create(request, **kwargs):
    args = {}
    for (key, value) in kwargs.items():
        if key in CERTIFICATE_CREATE_ATTRS:
            args[key] = value
        else:
            raise exceptions.BadRequest(
                "Key must be in %s" % ",".join(CERTIFICATE_CREATE_ATTRS))
    return magnumclient(request).certificates.create(**args)

def certificate_show(request, id):
    return magnumclient(request).certificates.get(id)

def certificate_rotate(request, id):
    args = {"cluster_uuid": id}
    return magnumclient(request).certificates.rotate_ca(**args)

def stats_list(request, limit=None, marker=None, sort_key=None,
               sort_dir=None, detail=True):
    return magnumclient(request).stats.list(
        limit, marker, sort_key, sort_dir, detail)
<|endoftext|>


<commit_before># -*- encoding: utf-8 -*-
import abc
from abjad.tools import abctools
from abjad.tools import durationtools
from abjad.tools import timespantools

class TimespanMaker(abctools.AbjadValueObject):
    r'''Abstract base class for timespan makers.
    '''

    ### CLASS VARIABLES ###

    __slots__ = (
        '_can_split',
        '_minimum_duration',
        '_seed',
        )

    ### INITIALIZER ###

    @abc.abstractmethod
    def __init__(
        self,
        can_split=None,
        minimum_duration=None,
        seed=None,
        ):
        if can_split is not None:
            can_split = bool(can_split)
        self._can_split = can_split
        if minimum_duration is not None:
            minimum_duration = durationtools.Duration(minimum_duration)
        self._minimum_duration = minimum_duration
        if seed is not None:
            seed = int(seed)
        self._seed = seed

    ### SPECIAL METHODS ###

    def __call__(
        self,
        color=None,
        layer=None,
        music_specifiers=None,
        target_timespan=None,
        timespan_inventory=None,
        ):
        if target_timespan is None:
            raise TypeError
        if timespan_inventory is None:
            timespan_inventory = timespantools.TimespanInventory()
        assert isinstance(timespan_inventory, timespantools.TimespanInventory)
        if not music_specifiers:
            return timespan_inventory
        self._make_timespans(
            color=color,
            layer=layer,
            music_specifiers=music_specifiers,
            target_timespan=target_timespan,
            timespan_inventory=timespan_inventory,
            )
        timespan_inventory.sort()
        return timespan_inventory

    ### PRIVATE METHODS ###

    def _make_performed_timespan(
        self,
        color=None,
        layer=None,
        music_specifier=None,
        start_offset=None,
        stop_offset=None,
        voice_name=None,
        ):
        from consort import makers
        timespan = makers.PerformedTimespan(
            can_split=self.can_split,
            color=color,
            layer=layer,
            minimum_duration=self.minimum_duration,
            music_specifier=music_specifier,
            original_start_offset=start_offset,
            original_stop_offset=stop_offset,
            start_offset=start_offset,
            stop_offset=stop_offset,
            voice_name=voice_name,
            )
        return timespan

    ### PUBLIC PROPERTIES ###

    @property
    def can_split(self):
        return self._can_split

    @property
    def is_dependent(self):
        return False

    @property
    def minimum_duration(self):
        return self._minimum_duration

    @property
    def seed(self):
        return self._seed<commit_msg>Cleaned up TimespanMaker.<commit_after># -*- encoding: utf-8 -*-
import abc
from abjad.tools import abctools
from abjad.tools import durationtools
from abjad.tools import timespantools

class TimespanMaker(abctools.AbjadValueObject):
    r'''Abstract base class for timespan makers.
    '''

    ### CLASS VARIABLES ###

    __slots__ = (
        '_can_split',
        '_minimum_duration',
        '_seed',
        )

    ### INITIALIZER ###

    @abc.abstractmethod
    def __init__(
        self,
        can_split=None,
        minimum_duration=None,
        seed=None,
        ):
        if can_split is not None:
            can_split = bool(can_split)
        self._can_split = can_split
        if minimum_duration is not None:
            minimum_duration = durationtools.Duration(minimum_duration)
        self._minimum_duration = minimum_duration
        if seed is not None:
            seed = int(seed)
        self._seed = seed

    ### SPECIAL METHODS ###

    def __call__(
        self,
        color=None,
        layer=None,
        music_specifiers=None,
        target_timespan=None,
        timespan_inventory=None,
        ):
        if target_timespan is None:
            raise TypeError
        if timespan_inventory is None:
            timespan_inventory = timespantools.TimespanInventory()
        assert isinstance(timespan_inventory, timespantools.TimespanInventory)
        if not music_specifiers:
            return timespan_inventory
        self._make_timespans(
            color=color,
            layer=layer,
            music_specifiers=music_specifiers,
            target_timespan=target_timespan,
            timespan_inventory=timespan_inventory,
            )
        timespan_inventory.sort()
        return timespan_inventory

    ### PRIVATE METHODS ###

    def _make_performed_timespan(
        self,
        color=None,
        layer=None,
        music_specifier=None,
        start_offset=None,
        stop_offset=None,
        voice_name=None,
        ):
        from consort import makers
        timespan = makers.PerformedTimespan(
            can_split=self.can_split,
            color=color,
            layer=layer,
            minimum_duration=self.minimum_duration,
            music_specifier=music_specifier,
            original_start_offset=start_offset,
            original_stop_offset=stop_offset,
            start_offset=start_offset,
            stop_offset=stop_offset,
            voice_name=voice_name,
            )
        return timespan

    ### PUBLIC PROPERTIES ###

    @property
    def can_split(self):
        return self._can_split

    @property
    def is_dependent(self):
        return False

    @property
    def minimum_duration(self):
        return self._minimum_duration

    @property
    def seed(self):
        return self._seed<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
'''
    Mango tools system logic functions.
'''

# This file is part of mango.

# Distributed under the terms of the last AGPL License.
# The full license is in the file LICENCE, distributed as part of this software.

__author__ = 'Team Machine'

import time
import arrow
import ujson as json
import motor
import logging
import uuid
import urllib
from tornado import gen
from mango import errors
from mango.messages import accounts
from tornado import httpclient as _http_client

_http_client.AsyncHTTPClient.configure('tornado.curl_httpclient.CurlAsyncHTTPClient')
http_client = _http_client.AsyncHTTPClient()

def get_average(total, marks):
    '''
        Get average from signals
    '''
    return float(total) / len(marks)

def get_percentage(shit, stuff):
    '''
        Get percentage of shit and stuff.

    '''
    return "{:.0%}".format(shit/stuff)

@gen.coroutine
def check_json(struct):
    '''
        Check for malformed JSON
    '''
    try:
        struct = json.loads(struct)
    except Exception, e:
        api_error = errors.Error(e)
        error = api_error.json()
        raise gen.Return(error)
        return
    raise gen.Return(struct)

@gen.coroutine
def check_account_type(self, account, account_type):
    '''
        check account type
    '''
    search_index = 'mango_account_index'
    query = 'account_type_register:{0}'.format(account_type)
    filter_query = 'account_register:{0}'.format(account)
    # url building

    url = "https://{0}/search/query/{1}?wt=json&q={2}&fq={3}".format(
        self.solr, search_index, query, filter_query
    )

    got_response = []
    # response message
    message = {'message': 'not found'}
    def handle_request(response):
        '''
            Request Async Handler
        '''
        if response.error:
            logging.error(response.error)
            got_response.append({'error':True, 'message': response.error})
        else:
            got_response.append(json.loads(response.body))
    try:
        http_client.fetch(
            url,
            callback=handle_request
        )
        while len(got_response) == 0:
            yield gen.sleep(0.0020) # don't be careless with the time.
        stuff = got_response[0]
        if stuff['response']['numFound']:
            response_doc = stuff['response']['docs'][0]
            IGNORE_ME = ["_yz_id","_yz_rk","_yz_rt","_yz_rb"]
            message = dict(
                (key.split('_register')[0], value)
                for (key, value) in response_doc.items()
                if key not in IGNORE_ME
            )
    except Exception, e:
        logging.exception(e)
        raise gen.Return(e)
    raise gen.Return(message)

@gen.coroutine
def get_account_uuid(self, account, password):
    '''
        Get valid account uuid
    '''
    search_index = 'mango_account_index'
    query = 'password_register:{0}'.format(password)
    filter_query = 'uuid_register:{0}'.format(account)
    # url building

    url = "https://{0}/search/query/{1}?wt=json&q={2}&fq={3}".format(
        self.solr, search_index, query, filter_query
    )
    logging.info(url)

    got_response = []
    # response message
    message = {'message': 'not found'}
    def handle_request(response):
        '''
            Request Async Handler
        '''
        if response.error:
            logging.error(response.error)
            got_response.append({'error':True, 'message': response.error})
        else:
            got_response.append(json.loads(response.body))
    try:
        http_client.fetch(
            url,
            callback=handle_request
        )
        while len(got_response) == 0:
            yield gen.sleep(0.0020) # don't be careless with the time.
        stuff = got_response[0]
        if stuff['response']['numFound']:
            response_doc = stuff['response']['docs'][0]
            IGNORE_ME = ["_yz_id","_yz_rk","_yz_rt","_yz_rb"]
            message = dict(
                (key.split('_register')[0], value)
                for (key, value) in response_doc.items()
                if key not in IGNORE_ME
            )
    except Exception, e:
        logging.exception(e)
        raise gen.Return(e)
    logging.info(message)
    raise gen.Return(message)

@gen.coroutine
def get_account_labels(self, account):
    '''
        Get account labels
    '''
    search_index = 'mango_account_index'
    query = 'account_register:{0}'.format(account)
    filter_query = 'uuid_register:{0}'.format(account)
    # url building

    url = "https://{0}/search/query/{1}?wt=json&q={2}&fq={3}".format(
        self.solr, search_index, query, filter_query
    )
    logging.info(url)
    got_response = []
    # response message
    message = {'message': 'not found'}
    def handle_request(response):
        '''
            Request Async Handler
        '''
        if response.error:
            logging.error(response.error)
            got_response.append({'error':True, 'message': response.error})
        else:
            got_response.append(json.loads(response.body))
    try:
        http_client.fetch(
            url,
            callback=handle_request
        )
        while len(got_response) == 0:
            yield gen.sleep(0.0020) # don't be careless with the time.
        stuff = got_response[0]
        if stuff['response']['numFound']:
            response_doc = stuff['response']['docs'][0]
            IGNORE_ME = ["_yz_id","_yz_rk","_yz_rt","_yz_rb"]
            message = dict(
                (key.split('_register')[0], value)
                for (key, value) in response_doc.items()
                if key not in IGNORE_ME
            )
    except Exception, e:
        logging.exception(e)
        raise gen.Return(e)
    raise gen.Return(message)

@gen.coroutine
def check_times(start, end):
    '''
        Check times
    '''
    try:
        start = (arrow.get(start) if start else arrow.get(arrow.utcnow().date()))
        end = (arrow.get(end) if end else start.replace(days=+1))
        # so... 2 lines more just for the fucking timestamp?
        start = start.timestamp
        end = end.timestamp
    except Exception, e:
        logging.exception(e)
        raise e
        return
    message = {'start':start, 'end':end}
    raise gen.Return(message)

@gen.coroutine
def check_times_get_timestamp(start, end):
    '''
        Check times get timestamp
    '''
    try:
        start = (arrow.get(start) if start else arrow.get(arrow.utcnow().date()))
        end = (arrow.get(end) if end else start.replace(days=+1))
    except Exception, e:
        logging.exception(e)
        raise e
        return
    message = {'start':start.timestamp, 'end':end.timestamp}
    raise gen.Return(message)

@gen.coroutine
def check_times_get_datetime(start, end):
    '''
        Check times get datetime
    '''
    try:
        start = (arrow.get(start) if start else arrow.get(arrow.utcnow().date()))
        end = (arrow.get(end) if end else start.replace(days=+1))
    except Exception, e:
        logging.exception(e)
        raise e
        return
    message = {'start':start.naive, 'end':end.naive}
    raise gen.Return(message)

@gen.coroutine
def new_resource(db, struct, collection=None):
    '''
        New resource function
    '''
    import uuid as _uuid
    from schematics import models as _models
    from schematics import types as _types
    # class MangoResource schematics model.
    class MangoResource(_models.Model):
        '''
            Mango resource
        '''
        uuid = _types.UUIDType(default=_uuid.uuid4)
        account = _types.StringType(required=False)
        resource  = _types.StringType(required=True)
    # Calling getattr(x, "foo") is just another way to write x.foo
    collection = getattr(db, collection)
    # the spawning pool of introspection.
    try:
        message = MangoResource(struct)
        message.validate()
        message = message.to_primitive()
    except Exception, e:
        logging.exception(e)
        raise e
        return
    resource = 'resources.{0}'.format(message.get('resource'))
    try:
        message = yield collection.update(
            {
                'account': message.get('account')
            },
            {
                '$addToSet': {
                    '{0}.contains'.format(resource): message.get('uuid')
                },
                '$inc': {
                    'resources.total': 1,
                    '{0}.total'.format(resource): 1
                }
            }
        )
    except Exception, e:
        logging.exception(e)
        raise e
        return
    raise gen.Return(message)

def clean_message(struct):
    '''
        clean message
    '''
    struct = struct.to_native()
    struct = {
        key: struct[key]
            for key in struct
                if struct[key] is not None
    }
    return struct

def clean_structure(struct):
    '''
        clean structure
    '''
    struct = struct.to_primitive()
    struct = {
        key: struct[key]
            for key in struct
                if struct[key] is not None
    }
    return struct

def clean_results(results):
    '''
        clean results
    '''
    results = results.to_primitive()
    results = results.get('results')
    results = [
        {
            key: dic[key]
                for key in dic
                    if dic[key] is not None
        } for dic in results
    ]
    return {'results': results}

def str2bool(boo):
    '''
        String to boolean
    '''
    return boo.lower() in ('yes', 'true', 't', '1')<commit_msg>update<commit_after># -*- coding: utf-8 -*-
'''
    Mango tools system logic functions.
'''

# This file is part of mango.

# Distributed under the terms of the last AGPL License.
# The full license is in the file LICENCE, distributed as part of this software.

__author__ = 'Team Machine'

import time
import arrow
import ujson as json
import motor
import logging
import uuid
import urllib
from tornado import gen
from mango import errors
from mango.messages import accounts
from tornado import httpclient as _http_client

_http_client.AsyncHTTPClient.configure('tornado.curl_httpclient.CurlAsyncHTTPClient')
http_client = _http_client.AsyncHTTPClient()

def get_average(total, marks):
    '''
        Get average from signals
    '''
    return float(total) / len(marks)

def get_percentage(shit, stuff):
    '''
        Get percentage of shit and stuff.

    '''
    return "{:.0%}".format(shit/stuff)

@gen.coroutine
def check_json(struct):
    '''
        Check for malformed JSON
    '''
    try:
        struct = json.loads(struct)
    except Exception, e:
        api_error = errors.Error(e)
        error = api_error.json()
        raise gen.Return(error)
        return
    raise gen.Return(struct)

@gen.coroutine
def check_account_type(self, account, account_type):
    '''
        check account type
    '''
    search_index = 'mango_account_index'
    query = 'account_type_register:{0}'.format(account_type)
    filter_query = 'account_register:{0}'.format(account)
    # url building

    url = "https://{0}/search/query/{1}?wt=json&q={2}&fq={3}".format(
        self.solr, search_index, query, filter_query
    )

    got_response = []
    # response message
    message = {'message': 'not found'}
    def handle_request(response):
        '''
            Request Async Handler
        '''
        if response.error:
            logging.error(response.error)
            got_response.append({'error':True, 'message': response.error})
        else:
            got_response.append(json.loads(response.body))
    try:
        http_client.fetch(
            url,
            callback=handle_request
        )
        while len(got_response) == 0:
            yield gen.sleep(0.0020) # don't be careless with the time.
        stuff = got_response[0]
        if stuff['response']['numFound']:
            response_doc = stuff['response']['docs'][0]
            IGNORE_ME = ["_yz_id","_yz_rk","_yz_rt","_yz_rb"]
            message = dict(
                (key.split('_register')[0], value)
                for (key, value) in response_doc.items()
                if key not in IGNORE_ME
            )
    except Exception, e:
        logging.exception(e)
        raise gen.Return(e)
    raise gen.Return(message)

@gen.coroutine
def get_account_uuid(self, account, password):
    '''
        Get valid account uuid
    '''
    search_index = 'mango_account_index'
    query = 'password_register:{0}'.format(password)
    filter_query = 'account_register:{0}'.format(account)
    # url building

    url = "https://{0}/search/query/{1}?wt=json&q={2}&fq={3}".format(
        self.solr, search_index, query, filter_query
    )
    logging.info(url)

    got_response = []
    # response message
    message = {'message': 'not found'}
    def handle_request(response):
        '''
            Request Async Handler
        '''
        if response.error:
            logging.error(response.error)
            got_response.append({'error':True, 'message': response.error})
        else:
            got_response.append(json.loads(response.body))
    try:
        http_client.fetch(
            url,
            callback=handle_request
        )
        while len(got_response) == 0:
            yield gen.sleep(0.0020) # don't be careless with the time.
        stuff = got_response[0]
        if stuff['response']['numFound']:
            response_doc = stuff['response']['docs'][0]
            IGNORE_ME = ["_yz_id","_yz_rk","_yz_rt","_yz_rb"]
            message = dict(
                (key.split('_register')[0], value)
                for (key, value) in response_doc.items()
                if key not in IGNORE_ME
            )
    except Exception, e:
        logging.exception(e)
        raise gen.Return(e)
    logging.info(message)
    raise gen.Return(message)

@gen.coroutine
def get_account_labels(self, account):
    '''
        Get account labels
    '''
    search_index = 'mango_account_index'
    query = 'account_register:{0}'.format(account)
    filter_query = 'uuid_register:{0}'.format(account)
    # url building

    url = "https://{0}/search/query/{1}?wt=json&q={2}&fq={3}".format(
        self.solr, search_index, query, filter_query
    )
    logging.info(url)
    got_response = []
    # response message
    message = {'message': 'not found'}
    def handle_request(response):
        '''
            Request Async Handler
        '''
        if response.error:
            logging.error(response.error)
            got_response.append({'error':True, 'message': response.error})
        else:
            got_response.append(json.loads(response.body))
    try:
        http_client.fetch(
            url,
            callback=handle_request
        )
        while len(got_response) == 0:
            yield gen.sleep(0.0020) # don't be careless with the time.
        stuff = got_response[0]
        if stuff['response']['numFound']:
            response_doc = stuff['response']['docs'][0]
            IGNORE_ME = ["_yz_id","_yz_rk","_yz_rt","_yz_rb"]
            message = dict(
                (key.split('_register')[0], value)
                for (key, value) in response_doc.items()
                if key not in IGNORE_ME
            )
    except Exception, e:
        logging.exception(e)
        raise gen.Return(e)
    raise gen.Return(message)

@gen.coroutine
def check_times(start, end):
    '''
        Check times
    '''
    try:
        start = (arrow.get(start) if start else arrow.get(arrow.utcnow().date()))
        end = (arrow.get(end) if end else start.replace(days=+1))
        # so... 2 lines more just for the fucking timestamp?
        start = start.timestamp
        end = end.timestamp
    except Exception, e:
        logging.exception(e)
        raise e
        return
    message = {'start':start, 'end':end}
    raise gen.Return(message)

@gen.coroutine
def check_times_get_timestamp(start, end):
    '''
        Check times get timestamp
    '''
    try:
        start = (arrow.get(start) if start else arrow.get(arrow.utcnow().date()))
        end = (arrow.get(end) if end else start.replace(days=+1))
    except Exception, e:
        logging.exception(e)
        raise e
        return
    message = {'start':start.timestamp, 'end':end.timestamp}
    raise gen.Return(message)

@gen.coroutine
def check_times_get_datetime(start, end):
    '''
        Check times get datetime
    '''
    try:
        start = (arrow.get(start) if start else arrow.get(arrow.utcnow().date()))
        end = (arrow.get(end) if end else start.replace(days=+1))
    except Exception, e:
        logging.exception(e)
        raise e
        return
    message = {'start':start.naive, 'end':end.naive}
    raise gen.Return(message)

@gen.coroutine
def new_resource(db, struct, collection=None):
    '''
        New resource function
    '''
    import uuid as _uuid
    from schematics import models as _models
    from schematics import types as _types
    # class MangoResource schematics model.
    class MangoResource(_models.Model):
        '''
            Mango resource
        '''
        uuid = _types.UUIDType(default=_uuid.uuid4)
        account = _types.StringType(required=False)
        resource  = _types.StringType(required=True)
    # Calling getattr(x, "foo") is just another way to write x.foo
    collection = getattr(db, collection)
    # the spawning pool of introspection.
    try:
        message = MangoResource(struct)
        message.validate()
        message = message.to_primitive()
    except Exception, e:
        logging.exception(e)
        raise e
        return
    resource = 'resources.{0}'.format(message.get('resource'))
    try:
        message = yield collection.update(
            {
                'account': message.get('account')
            },
            {
                '$addToSet': {
                    '{0}.contains'.format(resource): message.get('uuid')
                },
                '$inc': {
                    'resources.total': 1,
                    '{0}.total'.format(resource): 1
                }
            }
        )
    except Exception, e:
        logging.exception(e)
        raise e
        return
    raise gen.Return(message)

def clean_message(struct):
    '''
        clean message
    '''
    struct = struct.to_native()
    struct = {
        key: struct[key]
            for key in struct
                if struct[key] is not None
    }
    return struct

def clean_structure(struct):
    '''
        clean structure
    '''
    struct = struct.to_primitive()
    struct = {
        key: struct[key]
            for key in struct
                if struct[key] is not None
    }
    return struct

def clean_results(results):
    '''
        clean results
    '''
    results = results.to_primitive()
    results = results.get('results')
    results = [
        {
            key: dic[key]
                for key in dic
                    if dic[key] is not None
        } for dic in results
    ]
    return {'results': results}

def str2bool(boo):
    '''
        String to boolean
    '''
    return boo.lower() in ('yes', 'true', 't', '1')<|endoftext|>


<commit_before>#! /usr/bin/python3.2

from KataPotter import calculate_price as cp
from KataPotter import TooManyBooksException
import unittest

def r2(n):
    return round(n, 2)

class KataPotterTest(unittest.TestCase):

    def test_too_many_books(self):
        with self.assertRaises(TooManyBooksException):
            cp(1,2,3,4,5,6)

    def test_no_book(self):
        self.assertEqual(r2(cp(0,0,0,0,0)), 0)

    def test_one_book(self):
        self.assertEqual(r2(cp(1,0,0,0,0)), 8)
        self.assertEqual(r2(cp(0,1,0,0,0)), 8)
        self.assertEqual(r2(cp(0,0,1,0,0)), 8)
        self.assertEqual(r2(cp(0,0,0,1,0)), 8)
        self.assertEqual(r2(cp(0,0,0,0,1)), 8)

    def test_no_discount(self):
        self.assertEqual(r2(cp(2,0,0,0,0)),   2*8)
        self.assertEqual(r2(cp(19,0,0,0,0)), 19*8)
        self.assertEqual(r2(cp(0,0,0,7,0)),   7*8)
        self.assertEqual(r2(cp(0,0,0,0,5)),   5*8)

    # -5%
    def test_simple_discount_5(self):
        self.assertEqual(r2(cp(1,1,0,0,0)), r2(8* 2*0.95))
        self.assertEqual(r2(cp(0,1,0,0,1)), r2(8* 2*0.95))
        self.assertEqual(r2(cp(6,0,0,0,6)), r2(8*12*0.95))

    # -10%
    def test_simple_discount_10(self):
        self.assertEqual(r2(cp(0,0,1,1,1)), r2(8*3*0.9))
        self.assertEqual(r2(cp(2,0,2,0,2)), r2(8*6*0.9))

    # -20%
    def test_simple_discount_20(self):
        self.assertEqual(r2(cp(1,1,0,1,1)), r2(8* 4*0.8))
        self.assertEqual(r2(cp(3,3,3,0,3)), r2(8*12*0.8))

    # -25%
    def test_simple_discount_25(self):
        self.assertEqual(r2(cp(1,1,1,1,1)), r2(8* 5*0.75))
        self.assertEqual(r2(cp(4,4,4,4,4)), r2(8*20*0.75))

    def test_complex_discount(self):
        self.assertEqual(r2(cp(2,2,2,1,1)), 51.2)
        # TODO add some tests

if (__name__ == '__main__'):
    unittest.main()

<commit_msg>some tests for complex discounts added<commit_after>#! /usr/bin/python3.2

from KataPotter import calculate_price as cp
from KataPotter import TooManyBooksException
import unittest

def r2(n):
    return round(n, 2)

class KataPotterTest(unittest.TestCase):

    def test_too_many_books(self):
        with self.assertRaises(TooManyBooksException):
            cp(1,2,3,4,5,6)

    def test_no_book(self):
        self.assertEqual(r2(cp(0,0,0,0,0)), 0)

    def test_one_book(self):
        self.assertEqual(r2(cp(1,0,0,0,0)), 8)
        self.assertEqual(r2(cp(0,1,0,0,0)), 8)
        self.assertEqual(r2(cp(0,0,1,0,0)), 8)
        self.assertEqual(r2(cp(0,0,0,1,0)), 8)
        self.assertEqual(r2(cp(0,0,0,0,1)), 8)

    def test_no_discount(self):
        self.assertEqual(r2(cp(2,0,0,0,0)),   2*8)
        self.assertEqual(r2(cp(19,0,0,0,0)), 19*8)
        self.assertEqual(r2(cp(0,0,0,7,0)),   7*8)
        self.assertEqual(r2(cp(0,0,0,0,5)),   5*8)

    # -5%
    def test_simple_discount_5(self):
        self.assertEqual(r2(cp(1,1,0,0,0)), r2(8* 2*0.95))
        self.assertEqual(r2(cp(0,1,0,0,1)), r2(8* 2*0.95))
        self.assertEqual(r2(cp(6,0,0,0,6)), r2(8*12*0.95))

    # -10%
    def test_simple_discount_10(self):
        self.assertEqual(r2(cp(0,0,1,1,1)), r2(8*3*0.9))
        self.assertEqual(r2(cp(2,0,2,0,2)), r2(8*6*0.9))

    # -20%
    def test_simple_discount_20(self):
        self.assertEqual(r2(cp(1,1,0,1,1)), r2(8* 4*0.8))
        self.assertEqual(r2(cp(3,3,3,0,3)), r2(8*12*0.8))

    # -25%
    def test_simple_discount_25(self):
        self.assertEqual(r2(cp(1,1,1,1,1)), r2(8* 5*0.75))
        self.assertEqual(r2(cp(4,4,4,4,4)), r2(8*20*0.75))

    def test_complex_discount(self):
        self.assertEqual(r2(cp(2,2,2,1,1)), 51.2)
        self.assertEqual(r2(cp(2,1,1,1,1)), 38)
        self.assertEquals(r2(cp(0,3,3,0,1)), 52)
        self.assertEquals(r2(cp(0,1,5,1,0)), 53.6)

if (__name__ == '__main__'):
    unittest.main()

<|endoftext|>