<commit_before>#!/usr/bin/env python
import rospy
from pynput import keyboard
import threading

from std_msgs.msg import Bool
from uarm_metal.msg import JointAngles, Beep

global rec_data
global data_sub

def shutdown_signal_handler(signal, frame):
    global exit
    exit = True
    print 'Shutting Down!'

def data_callback(data):
    global rec_data
    rec_data.append(data)

def start_record():
    global rec_data
    global data_sub
    rec_data = []
    ns = "/uarm_metal/"

    data_sub = rospy.Subscriber(ns + "joint_angles_read", JointAngles, data_callback)
    return data_sub

def start_playback(data):
    ns = "/uarm_metal/"
    data_pub = rospy.Publisher(ns + 'joint_angles_write', JointAngles, queue_size=10)
    att_pub = rospy.Publisher(ns + 'attach', Bool, queue_size=10)
    att_pub.publish(Bool(True))
    pub_thread = threading.Thread(target=play, args=(data, data_pub, att_pub))
    pub_thread.daemon = True
    pub_thread.start()

    return data_pub

def play(data, data_pub, att_pub):
    rate = rospy.rate = 20
    for point in data:
        data_pub.publish(point)
        rate.sleep()

    att_pub.publish(Bool(False))
    print "Done!"

def stop_ROS_sub(sub):
    try:
        #rospy.signal_shutdown("Stop Rec/Play")
        sub.unregister()
    except Exception as e:
        print "Error in stop_ROS_processes(): ", e
        pass

def on_press(key):
    global rec_data
    global data_sub

    if key == keyboard.Key.esc:
        raise Exception(key)
    elif key.char == '1':
        start_record()
        print "RECORD"
    elif key.char == '2':
        print "STOP"
        stop_ROS_sub(data_sub)
        print len(rec_data)
    elif key.char == '3':
        print "PLAY"
        if len(rec_data) > 0:
            start_playback(rec_data)
    elif key.char == '4':
        rec_data = []
        print "RESET"

if __name__ == '__main__':
    global rec_data
    rec_data = []
    ns = "/uarm_metal/"
    rospy.set_param(ns + 'read_joint_angles', 1)
    rospy.set_param(ns + 'read_position', 0)

    rospy.init_node('record_node', anonymous=False)

    print "Start."
    with keyboard.Listener(on_press=on_press) as listener:
        try:
            listener.join()
        except Exception as e:
            print "Error", e

    #
    # record = False
    # play = False
    # stop = False
    # reset = False
    # rec_data = []
    #
    # signal.signal(signal.SIGINT, shutdown_signal_handler)
    # print 'Ctrl+C or q to exit'
    # exit = False
    # ns = "/uarm_metal/"
    # rospy.set_param(ns + 'read_joint_angles', 1)
    # rospy.set_param(ns + 'read_position', 0)
    # rospy.set_param(ns + 'read_digital_inputs', [0,0])
    # rospy.set_param(ns + 'read_analog_inputs', [0,0])
    #
    # rospy.init_node('record_play_node', anonymous=False)
    #
    # ja_pub = rospy.Publisher(ns + 'joint_angles_write', JointAngles, queue_size=10)
    # att_pub = rospy.Publisher(ns + 'attach', Bool, queue_size=10)
    # beep_pub = rospy.Publisher(ns + 'beep', Beep, queue_size=10)
    #
    # rospy.Subscriber(ns + "joint_angles_read", JointAngles, data_callback)
    #
    #
    # rw_rate = 1000.0
    # rate = rospy.Rate(100)
    # rec_data = []
    # play_data = []
    # start = True
    #
    # bp = Beep()
    # bp.frequency = 12000
    # bp.duration = 0.1
    #
    # while exit is False:
    #
    #     key = getch.getch()
    #     process(key)
    #
    #     if record:
    #         #att_pub.publish(False)
    #         if start:
    #             print "Record"
    #             att_pub.publish(Bool(False))
    #             print "Beep"
    #             beep_pub.publish(bp)
    #             start = False
    #
    #     elif play:
    #         if start:
    #             print "play"
    #             play_data = rec_data[:]
    #             att_pub.publish(Bool(True))
    #             beep_pub.publish(bp)
    #             start = False
    #         try:
    #             ja_pub.publish(play_data.pop(0))
    #         except Exception as e:
    #             print e
    #             beep_pub.publish(bp)
    #             play = False
    #
    #     elif stop:
    #         print "stop"
    #         att_pub.publish(Bool(False))
    #         beep_pub.publish(bp)
    #         start = True
    #         stop = False
    #
    #     rate.sleep()
        #time.sleep(1.0 / rw_rate)

<commit_msg>rec play<commit_after>#!/usr/bin/env python
import rospy
from pynput import keyboard
import threading

from std_msgs.msg import Bool
from uarm_metal.msg import JointAngles, Beep

global rec_data
global data_sub

def shutdown_signal_handler(signal, frame):
    global exit
    exit = True
    print 'Shutting Down!'

def data_callback(data):
    global rec_data
    rec_data.append(data)

def start_record():
    global rec_data
    global data_sub
    rec_data = []
    ns = "/uarm_metal/"

    data_sub = rospy.Subscriber(ns + "joint_angles_read", JointAngles, data_callback)
    return data_sub

def start_playback(data):
    ns = "/uarm_metal/"
    data_pub = rospy.Publisher(ns + 'joint_angles_write', JointAngles, queue_size=10)
    att_pub = rospy.Publisher(ns + 'attach', Bool, queue_size=10)
    att_pub.publish(Bool(True))
    pub_thread = threading.Thread(target=play, args=(data, data_pub, att_pub))
    pub_thread.daemon = True
    pub_thread.start()

    return data_pub

def play(data, data_pub, att_pub):
    rate = rospy.Rate(20)
    for point in data:
        data_pub.publish(point)
        rate.sleep()

    att_pub.publish(Bool(False))
    print "Done!"

def stop_ROS_sub(sub):
    try:
        #rospy.signal_shutdown("Stop Rec/Play")
        sub.unregister()
    except Exception as e:
        print "Error in stop_ROS_processes(): ", e
        pass

def on_press(key):
    global rec_data
    global data_sub

    if key == keyboard.Key.esc:
        raise Exception(key)
    elif key.char == '1':
        start_record()
        print "RECORD"
    elif key.char == '2':
        print "STOP"
        stop_ROS_sub(data_sub)
        print len(rec_data)
    elif key.char == '3':
        print "PLAY"
        if len(rec_data) > 0:
            start_playback(rec_data)
    elif key.char == '4':
        rec_data = []
        print "RESET"

if __name__ == '__main__':
    global rec_data
    rec_data = []
    ns = "/uarm_metal/"
    rospy.set_param(ns + 'read_joint_angles', 1)
    rospy.set_param(ns + 'read_position', 0)

    rospy.init_node('record_node', anonymous=False)

    print "Start."
    with keyboard.Listener(on_press=on_press) as listener:
        try:
            listener.join()
        except Exception as e:
            print "Error", e

    #
    # record = False
    # play = False
    # stop = False
    # reset = False
    # rec_data = []
    #
    # signal.signal(signal.SIGINT, shutdown_signal_handler)
    # print 'Ctrl+C or q to exit'
    # exit = False
    # ns = "/uarm_metal/"
    # rospy.set_param(ns + 'read_joint_angles', 1)
    # rospy.set_param(ns + 'read_position', 0)
    # rospy.set_param(ns + 'read_digital_inputs', [0,0])
    # rospy.set_param(ns + 'read_analog_inputs', [0,0])
    #
    # rospy.init_node('record_play_node', anonymous=False)
    #
    # ja_pub = rospy.Publisher(ns + 'joint_angles_write', JointAngles, queue_size=10)
    # att_pub = rospy.Publisher(ns + 'attach', Bool, queue_size=10)
    # beep_pub = rospy.Publisher(ns + 'beep', Beep, queue_size=10)
    #
    # rospy.Subscriber(ns + "joint_angles_read", JointAngles, data_callback)
    #
    #
    # rw_rate = 1000.0
    # rate = rospy.Rate(100)
    # rec_data = []
    # play_data = []
    # start = True
    #
    # bp = Beep()
    # bp.frequency = 12000
    # bp.duration = 0.1
    #
    # while exit is False:
    #
    #     key = getch.getch()
    #     process(key)
    #
    #     if record:
    #         #att_pub.publish(False)
    #         if start:
    #             print "Record"
    #             att_pub.publish(Bool(False))
    #             print "Beep"
    #             beep_pub.publish(bp)
    #             start = False
    #
    #     elif play:
    #         if start:
    #             print "play"
    #             play_data = rec_data[:]
    #             att_pub.publish(Bool(True))
    #             beep_pub.publish(bp)
    #             start = False
    #         try:
    #             ja_pub.publish(play_data.pop(0))
    #         except Exception as e:
    #             print e
    #             beep_pub.publish(bp)
    #             play = False
    #
    #     elif stop:
    #         print "stop"
    #         att_pub.publish(Bool(False))
    #         beep_pub.publish(bp)
    #         start = True
    #         stop = False
    #
    #     rate.sleep()
        #time.sleep(1.0 / rw_rate)

<|endoftext|>


<commit_before>from flask import request, Module, flash, render_template, \
                  redirect, url_for, abort, g

from codebox.apps.auth.models import User
from codebox.apps.auth.decorators import login_required
from codebox.apps.organizations.decorators import can_view_org
from codebox.apps.organizations.models import Organization
from codebox.apps.snippets.models import Snippet
from codebox.apps.snippets.forms import NewSnippetForm
from codebox.utils.shortcuts import get_object_or_404

frontend = Module(__name__)

@frontend.route('/')
# @login_required
def dashboard():
    """
    Shows organizations/recent pastes/etc
    """

    snippets = list(Snippet.objects.for_index('dashboard', g.user.pk, 0, 10))
    snippets_users = User.objects.get_many([s.user for s in snippets])

    my_organizations = g.user.get_all_organizations(g.user.pk)

    return render_template('snippets/dashboard.html', **{
            'snippets': snippets,
            'snippets_users': dict([(u.pk, u) for u in snippets_users]),
            'my_organizations': my_organizations,
            })

@frontend.route('/<org>/view/<id>')
# @login_required
#@can_view_org
def snippet_detail(org, id):
    org = get_object_or_404(Organization, org)

    snippet = get_object_or_404(Snippet, id)
    if snippet.org != org.pk:
        abort(404)

    user = User.objects.get(snippet.user)

    return render_template('snippets/detail.html', **{
            'snippet': snippet,
            'org': org,
            'user': user,
            })

@frontend.route('/<org>/new', methods=['GET', 'POST'])
## @login_required
def new_snippet(org):
    """
    Creates a new snippet for an organization.
    """
    org = get_object_or_404(Organization, org)

    form = NewSnippetForm()
    if form.validate_on_submit():
        # Generate a unique slug from name
        snippet = Snippet.objects.create(
            org=org,
            text=form.text.data,
            lang=form.lang.data,
            user=g.user.pk,
        )

        if request.is_xhr:
            return 'Success'

        flash("Success")

        return redirect(url_for('snippet_detail', org=org.pk, id=snippet.pk))

    return render_template('snippets/new_snippet.html', **{
        'org': org,
        'form': form,
    })

@frontend.route('/<org>')
# @login_required
# @can_view_org
def list_snippets(org):
    org = get_object_or_404(Organization, org)
    org_members = org.get_all_members()

    snippets = list(Snippet.objects.for_index('org', org.pk, 0, 10))
    snippets_users = User.objects.get_many([s.user for s in snippets])

    return render_template('organizations/detail.html', **{
            'org': org,
            'org_members': org_members,
            'snippets': snippets,
            'snippets_users': dict([(u.pk, u) for u in snippets_users]),
            })

@frontend.route('/<org>/search')
# @login_required
# @can_view_org
def search_snippets(org):
    query = request.args.get('q')

    org = get_object_or_404(Organization, org)
    org_members = org.get_all_members()

    if query:
        i, n = 0, 0
        results = []
        words = query.lower().split(' ')
        for snippet in Snippet.objects.all():
            i += 1
            text = snippet.text.lower().split(' ')
            for word in words:
                for otherword in text:
                    if word in otherword:
                        results.append(snippet)
                        n += 1
            if i > 1000 or n > 25:
                break
        if results:
            snippets_users = User.objects.get_many([s.user for s in results])
        else:
            snippets_users = []
    else:
        results = []
        snippets_users = []

    return render_template('organizations/search.html', **{
            'query': query,
            'org': org,
            'org_members': org_members,
            'snippets': results,
            'snippets_users': dict([(u.pk, u) for u in snippets_users]),
            })
<commit_msg>Force auth and org requirements on snippet views<commit_after>from flask import request, Module, flash, render_template, \
                  redirect, url_for, abort, g

from codebox.apps.auth.models import User
from codebox.apps.auth.decorators import login_required
from codebox.apps.organizations.decorators import can_view_org
from codebox.apps.organizations.models import Organization
from codebox.apps.snippets.models import Snippet
from codebox.apps.snippets.forms import NewSnippetForm
from codebox.utils.shortcuts import get_object_or_404

frontend = Module(__name__)

@frontend.route('/')
@login_required
def dashboard():
    """
    Shows organizations/recent pastes/etc
    """

    snippets = list(Snippet.objects.for_index('dashboard', g.user.pk, 0, 10))
    snippets_users = User.objects.get_many([s.user for s in snippets])

    my_organizations = g.user.get_all_organizations(g.user.pk)

    return render_template('snippets/dashboard.html', **{
            'snippets': snippets,
            'snippets_users': dict([(u.pk, u) for u in snippets_users]),
            'my_organizations': my_organizations,
            })

@frontend.route('/<org>/view/<id>')
@login_required
@can_view_org
def snippet_detail(org, id):
    org = get_object_or_404(Organization, org)

    snippet = get_object_or_404(Snippet, id)
    if snippet.org != org.pk:
        abort(404)

    user = User.objects.get(snippet.user)

    return render_template('snippets/detail.html', **{
            'snippet': snippet,
            'org': org,
            'user': user,
            })

@frontend.route('/<org>/new', methods=['GET', 'POST'])
@login_required
@can_view_org
def new_snippet(org):
    """
    Creates a new snippet for an organization.
    """
    org = get_object_or_404(Organization, org)

    form = NewSnippetForm()
    if form.validate_on_submit():
        # Generate a unique slug from name
        snippet = Snippet.objects.create(
            org=org,
            text=form.text.data,
            lang=form.lang.data,
            user=g.user.pk,
        )

        if request.is_xhr:
            return 'Success'

        flash("Success")

        return redirect(url_for('snippet_detail', org=org.pk, id=snippet.pk))

    return render_template('snippets/new_snippet.html', **{
        'org': org,
        'form': form,
    })

@frontend.route('/<org>')
@login_required
@can_view_org
def list_snippets(org):
    org = get_object_or_404(Organization, org)
    org_members = org.get_all_members()

    snippets = list(Snippet.objects.for_index('org', org.pk, 0, 10))
    snippets_users = User.objects.get_many([s.user for s in snippets])

    return render_template('organizations/detail.html', **{
            'org': org,
            'org_members': org_members,
            'snippets': snippets,
            'snippets_users': dict([(u.pk, u) for u in snippets_users]),
            })

@frontend.route('/<org>/search')
@login_required
@can_view_org
def search_snippets(org):
    query = request.args.get('q')

    org = get_object_or_404(Organization, org)
    org_members = org.get_all_members()

    if query:
        i, n = 0, 0
        results = []
        words = query.lower().split(' ')
        for snippet in Snippet.objects.all():
            i += 1
            text = snippet.text.lower().split(' ')
            for word in words:
                for otherword in text:
                    if word in otherword:
                        results.append(snippet)
                        n += 1
            if i > 1000 or n > 25:
                break
        if results:
            snippets_users = User.objects.get_many([s.user for s in results])
        else:
            snippets_users = []
    else:
        results = []
        snippets_users = []

    return render_template('organizations/search.html', **{
            'query': query,
            'org': org,
            'org_members': org_members,
            'snippets': results,
            'snippets_users': dict([(u.pk, u) for u in snippets_users]),
            })
<|endoftext|>


<commit_before>#!/usr/bih/env python
from ..timerfd import Timerfd as orig_Timerfd, _ffi, CLOCK_REALTIME
from os import read as _read, write as _write, close as _close
from collections import deque
import asyncio

class Timerfd:
    def __init__(self, clock_type=CLOCK_REALTIME, flags=0, *, loop=None):
        self._loop = loop or asyncio.get_event_loop()
        self._timerfd = orig_Timerfd(clock_type, flags)
        self._fd =  self._timerfd.fileno()
        self._getters = deque()

        self.set_one_off = self._timerfd.set_one_off
        self.set_reoccuring = self._timerfd.set_reoccuring
        self.enabled = self._timerfd.__class__.__dict__['enabled']
        self.disabled = self._timerfd.__class__.__dict__['disabled']
        self.disable = self._timerfd.disable
        self.get_current = self._timerfd.get_current
        self.close = self._timerfd.close

    @asyncio.coroutine
    def wait(self):
        """Wait for the timer to expire, returning how many events have
        elappsed since the last call to wait()

        Returns
        --------
        :return: The current count of the timer
        :rtype: int
        """
        self._loop.add_reader(self._fd, self._read_event)

        waiter = asyncio.Future(loop=self._loop)

        self._getters.append(waiter)

        return (yield from waiter)

    def _consume_done_getters(self):
        # Delete waiters at the head of the get() queue who've timed out.
        while self._getters and self._getters[0].done():
            self._getters.popleft()

    def _read_event(self):
        data = _read(self._fd, 8)
        value = _ffi.new('uint64_t[1]')
        _ffi.buffer(value, 8)[0:8] = data

        self._put_event(value[0])

    def _put_event(self, value):
        """Put an item into the queue without blocking.

        If no free slot is immediately available, raise QueueFull.
        """
        self._loop.remove_reader(self._fd)

        self._consume_done_getters()

        for getter in self._getters:
            getter.set_result(value)

    def close(self):
        _close(self._fd)

def watcher(loop):
    from asyncio import sleep
    from time import time

    t = Timerfd()

    time_val = 0.5
    t.set_reoccuring(time_val)
    print("Setting time interval to {:.2f} seconds".format(time_val))

    for i in range(5):
        old_time = time()
        num_events = yield from t.wait()
        new_time = time()
        assert num_events == 1, "Too many events"
        print("Woke up after {:.2f} seconds".format(new_time - old_time))

    print("Got all 5 events")

    print("Sleeping for 0.3s")
    yield from sleep(0.3)
    print("Next event:", t.get_current())

def main():
    import logging

    log = logging.getLogger()
    log.setLevel(logging.DEBUG)
    log.addHandler(logging.StreamHandler())

    loop = asyncio.get_event_loop()

    from asyncio import Task
    task = Task(watcher(loop))

    loop.run_forever()

if __name__ == "__main__":
    main()
<commit_msg>Use fileno() for fd<commit_after>#!/usr/bih/env python
from ..timerfd import Timerfd as orig_Timerfd, _ffi, CLOCK_REALTIME
from os import read as _read, write as _write, close as _close
from collections import deque
import asyncio

class Timerfd:
    def __init__(self, clock_type=CLOCK_REALTIME, flags=0, *, loop=None):
        self._loop = loop or asyncio.get_event_loop()
        self._timerfd = orig_Timerfd(clock_type, flags)
        self._getters = deque()

        self.set_one_off = self._timerfd.set_one_off
        self.set_reoccuring = self._timerfd.set_reoccuring
        self.enabled = self._timerfd.__class__.__dict__['enabled']
        self.disabled = self._timerfd.__class__.__dict__['disabled']
        self.disable = self._timerfd.disable
        self.get_current = self._timerfd.get_current
        self.close = self._timerfd.close

    @asyncio.coroutine
    def wait(self):
        """Wait for the timer to expire, returning how many events have
        elappsed since the last call to wait()

        Returns
        --------
        :return: The current count of the timer
        :rtype: int
        """
        self._loop.add_reader(self._timerfd.fileno(), self._read_event)

        waiter = asyncio.Future(loop=self._loop)

        self._getters.append(waiter)

        return (yield from waiter)

    def _consume_done_getters(self):
        # Delete waiters at the head of the get() queue who've timed out.
        while self._getters and self._getters[0].done():
            self._getters.popleft()

    def _read_event(self):
        data = _read(self._timerfd.fileno(), 8)
        value = _ffi.new('uint64_t[1]')
        _ffi.buffer(value, 8)[0:8] = data

        self._put_event(value[0])

    def _put_event(self, value):
        """Put an item into the queue without blocking.

        If no free slot is immediately available, raise QueueFull.
        """
        self._loop.remove_reader(self._timerfd.fileno())

        self._consume_done_getters()

        for getter in self._getters:
            getter.set_result(value)

    def close(self):
        _close(self._timerfd.fileno())

def watcher(loop):
    from asyncio import sleep
    from time import time

    t = Timerfd()

    time_val = 0.5
    t.set_reoccuring(time_val)
    print("Setting time interval to {:.2f} seconds".format(time_val))

    for i in range(5):
        old_time = time()
        num_events = yield from t.wait()
        new_time = time()
        assert num_events == 1, "Too many events"
        print("Woke up after {:.2f} seconds".format(new_time - old_time))

    print("Got all 5 events")

    print("Sleeping for 0.3s")
    yield from sleep(0.3)
    print("Next event:", t.get_current())

def main():
    import logging

    log = logging.getLogger()
    log.setLevel(logging.DEBUG)
    log.addHandler(logging.StreamHandler())

    loop = asyncio.get_event_loop()

    from asyncio import Task
    task = Task(watcher(loop))

    loop.run_forever()

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


<commit_before># MIT License
# Copyright (c) 2017 MassChallenge, Inc.

import simplejson as json
from django.contrib.auth import get_user_model
from django.urls import reverse
from rest_framework.test import APIClient

from accelerator.models import UserRole
from accelerator.tests.factories import (
    NamedGroupFactory,
    ProgramFactory,
    ProgramRoleFactory,
    ProgramRoleGrantFactory,
    UserRoleFactory,
    EntrepreneurFactory,
    ExpertFactory,
)
from accelerator_abstract.models import (
    ACTIVE_PROGRAM_STATUS,
    UPCOMING_PROGRAM_STATUS,
    ENDED_PROGRAM_STATUS,
    ENTREPRENEUR_USER_TYPE
)
from impact.tests.api_test_case import APITestCase
from impact.tests.factories import UserFactory
from impact.views import AlgoliaApiKeyView
from impact.views.algolia_api_key_view import IS_CONFIRMED_MENTOR_FILTER

User = get_user_model()  # pylint: disable=invalid-name

def _create_expert():
    return _create_user(ExpertFactory)

def _create_entrepreneur():
    return _create_user(EntrepreneurFactory)

def _create_user(factory):
    user = factory()
    user.set_password("password")
    user.save()
    return user

def _create_batch_program_and_named_group(status, batch_size):
    named_group = NamedGroupFactory()
    programs = ProgramFactory.create_batch(
        batch_size,
        mentor_program_group=named_group,
        program_status=status)
    return programs

class TestAlgoliaApiKeyView(APITestCase):
    client_class = APIClient
    user_factory = UserFactory
    url = reverse(AlgoliaApiKeyView.view_name)

    def test_logged_in_user_with_role_grants_in_ended_programs_gets_403(self):
        program = _create_batch_program_and_named_group(
                        ENDED_PROGRAM_STATUS, 1)
        user = self._create_user_with_role_grant(program[0], UserRole.FINALIST)
        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                self.assertTrue(response.status_code, 403)

    def test_logged_in_user_generates_token(self):
        program = _create_batch_program_and_named_group(
                        ACTIVE_PROGRAM_STATUS, 1)
        user = self._create_user_with_role_grant(program[0], UserRole.FINALIST)
        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                response_data = json.loads(response.content)
                self.assertTrue('token' in response_data.keys())

    def test_unauthenticated_user_is_denied(self):
        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            response = self.client.get(self.url)
            response_data = json.loads(response.content)
            self.assertTrue(
                response_data['detail'] == 'Authentication credentials '
                                           'were not provided.')

    def test_entrepreneur_that_never_had_a_finalist_role_gets_403(self):
        user = _create_entrepreneur()
        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                self.assertTrue(response.status_code, 403)

    def test_user_with_staff_role_grant_sees_all_mentors(self):
        user = self.basic_user()
        program = _create_batch_program_and_named_group(
                        ACTIVE_PROGRAM_STATUS, 1)

        self._create_user_with_role_grant(program[0], UserRole.STAFF, user)

        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                response_data = json.loads(response.content)
                self.assertEqual(response_data["filters"], [])

    def test_finalist_user_gets_all_programs_in_program_group(
            self):
        programs = _create_batch_program_and_named_group(
                        ACTIVE_PROGRAM_STATUS, 5)
        other_program = ProgramFactory(program_status=ACTIVE_PROGRAM_STATUS)
        program = programs[0]
        user = self._create_user_with_role_grant(program, UserRole.FINALIST)
        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                response_data = json.loads(response.content)

                for program in programs:
                    self.assertIn(program.name, response_data["filters"])
                self.assertNotIn(other_program.name, response_data["filters"])

    def test_finalist_user_gets_all_programs_in_past_or_present(
            self):
        programs = _create_batch_program_and_named_group(
                        ACTIVE_PROGRAM_STATUS, 5)
        other_program = ProgramFactory(
                            program_status=UPCOMING_PROGRAM_STATUS,
                            mentor_program_group=NamedGroupFactory())
        program = programs[0]
        user = self._create_user_with_role_grant(program, UserRole.FINALIST)
        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                response_data = json.loads(response.content)

                for program in programs:
                    self.assertIn(program.name, response_data["filters"])
                self.assertNotIn(other_program.name, response_data["filters"])

    def test_alumni_user_only_sees_mentors_of_alumni_programs(
            self):
        programs = _create_batch_program_and_named_group(
                        ENDED_PROGRAM_STATUS, 5)
        named_alumni_group = NamedGroupFactory()
        alumni_program = ProgramFactory(
                                program_status=ACTIVE_PROGRAM_STATUS,
                                mentor_program_group=named_alumni_group)
        finalist_program = programs[0]

        user = self._create_user_with_role_grant(
            finalist_program, UserRole.FINALIST)
        self._create_user_with_role_grant(
            alumni_program, UserRole.ALUM, user)

        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                response_data = json.loads(response.content)

                for program in programs:
                    self.assertNotIn(program.name, response_data["filters"])
                self.assertIn(alumni_program.name, response_data["filters"])

    def test_alumni_user_who_is_also_finalist_sees_mentors_of_both_programs(
            self):
        programs = _create_batch_program_and_named_group(
                        ACTIVE_PROGRAM_STATUS, 5)
        named_alumni_group = NamedGroupFactory()
        other_program = ProgramFactory(program_status=ACTIVE_PROGRAM_STATUS,
                                       mentor_program_group=named_alumni_group)

        finalist_program = programs[1]

        user = self._create_user_with_role_grant(
            other_program, UserRole.ALUM)
        self._create_user_with_role_grant(
            finalist_program, UserRole.FINALIST, user)

        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                response_data = json.loads(response.content)

                for program in programs:
                    self.assertIn(program.name, response_data["filters"])
                self.assertIn(other_program.name, response_data["filters"])

    def test_superuser_employee_sees_all_mentors(self):
        user = _create_expert()
        user.is_superuser = True
        user.save()

        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                response_data = json.loads(response.content)

                self.assertEqual(response_data["filters"], [])

    def _create_user_with_role_grant(
            self, program, user_role_name, user=False):
        user_role = UserRoleFactory(name=user_role_name)
        program_role = ProgramRoleFactory(
            user_role=user_role,
            program=program
        )

        if not user:
            user = _create_entrepreneur()

        ProgramRoleGrantFactory(person=user, program_role=program_role)
        return user
<commit_msg>[AC-6377] fix failing tests<commit_after># MIT License
# Copyright (c) 2017 MassChallenge, Inc.

import simplejson as json
from django.contrib.auth import get_user_model
from django.urls import reverse
from rest_framework.test import APIClient

from accelerator.models import UserRole
from accelerator.tests.factories import (
    NamedGroupFactory,
    ProgramFactory,
    ProgramRoleFactory,
    ProgramRoleGrantFactory,
    UserRoleFactory,
    EntrepreneurFactory,
    ExpertFactory,
)
from accelerator_abstract.models import (
    ACTIVE_PROGRAM_STATUS,
    UPCOMING_PROGRAM_STATUS,
    ENDED_PROGRAM_STATUS,
    ENTREPRENEUR_USER_TYPE
)
from impact.tests.api_test_case import APITestCase
from impact.tests.factories import UserFactory
from impact.views import AlgoliaApiKeyView
from impact.views.algolia_api_key_view import IS_CONFIRMED_MENTOR_FILTER

User = get_user_model()  # pylint: disable=invalid-name

def _create_expert():
    return _create_user(ExpertFactory)

def _create_entrepreneur():
    return _create_user(EntrepreneurFactory)

def _create_user(factory):
    user = factory()
    user.set_password("password")
    user.save()
    return user

def _create_batch_program_and_named_group(status, batch_size):
    named_group = NamedGroupFactory()
    programs = ProgramFactory.create_batch(
        batch_size,
        mentor_program_group=named_group,
        program_status=status)
    return programs

class TestAlgoliaApiKeyView(APITestCase):
    client_class = APIClient
    user_factory = UserFactory
    url = "{}?index=mentor".format(reverse(AlgoliaApiKeyView.view_name))

    def test_logged_in_user_with_role_grants_in_ended_programs_gets_403(self):
        program = _create_batch_program_and_named_group(
                        ENDED_PROGRAM_STATUS, 1)
        user = self._create_user_with_role_grant(program[0], UserRole.FINALIST)
        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                self.assertTrue(response.status_code, 403)

    def test_logged_in_user_generates_token(self):
        program = _create_batch_program_and_named_group(
                        ACTIVE_PROGRAM_STATUS, 1)
        user = self._create_user_with_role_grant(program[0], UserRole.FINALIST)
        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                response_data = json.loads(response.content)
                self.assertTrue('token' in response_data.keys())

    def test_unauthenticated_user_is_denied(self):
        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            response = self.client.get(self.url)
            response_data = json.loads(response.content)
            self.assertTrue(
                response_data['detail'] == 'Authentication credentials '
                                           'were not provided.')

    def test_entrepreneur_that_never_had_a_finalist_role_gets_403(self):
        user = _create_entrepreneur()
        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                self.assertTrue(response.status_code, 403)

    def test_user_with_staff_role_grant_sees_all_mentors(self):
        user = self.basic_user()
        program = _create_batch_program_and_named_group(
                        ACTIVE_PROGRAM_STATUS, 1)

        self._create_user_with_role_grant(program[0], UserRole.STAFF, user)

        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                response_data = json.loads(response.content)
                self.assertEqual(response_data["filters"], [])

    def test_finalist_user_gets_all_programs_in_program_group(
            self):
        programs = _create_batch_program_and_named_group(
                        ACTIVE_PROGRAM_STATUS, 5)
        other_program = ProgramFactory(program_status=ACTIVE_PROGRAM_STATUS)
        program = programs[0]
        user = self._create_user_with_role_grant(program, UserRole.FINALIST)
        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                response_data = json.loads(response.content)

                for program in programs:
                    self.assertIn(program.name, response_data["filters"])
                self.assertNotIn(other_program.name, response_data["filters"])

    def test_finalist_user_gets_all_programs_in_past_or_present(
            self):
        programs = _create_batch_program_and_named_group(
                        ACTIVE_PROGRAM_STATUS, 5)
        other_program = ProgramFactory(
                            program_status=UPCOMING_PROGRAM_STATUS,
                            mentor_program_group=NamedGroupFactory())
        program = programs[0]
        user = self._create_user_with_role_grant(program, UserRole.FINALIST)
        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                response_data = json.loads(response.content)

                for program in programs:
                    self.assertIn(program.name, response_data["filters"])
                self.assertNotIn(other_program.name, response_data["filters"])

    def test_alumni_user_only_sees_mentors_of_alumni_programs(
            self):
        programs = _create_batch_program_and_named_group(
                        ENDED_PROGRAM_STATUS, 5)
        named_alumni_group = NamedGroupFactory()
        alumni_program = ProgramFactory(
                                program_status=ACTIVE_PROGRAM_STATUS,
                                mentor_program_group=named_alumni_group)
        finalist_program = programs[0]

        user = self._create_user_with_role_grant(
            finalist_program, UserRole.FINALIST)
        self._create_user_with_role_grant(
            alumni_program, UserRole.ALUM, user)

        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                response_data = json.loads(response.content)

                for program in programs:
                    self.assertNotIn(program.name, response_data["filters"])
                self.assertIn(alumni_program.name, response_data["filters"])

    def test_alumni_user_who_is_also_finalist_sees_mentors_of_both_programs(
            self):
        programs = _create_batch_program_and_named_group(
                        ACTIVE_PROGRAM_STATUS, 5)
        named_alumni_group = NamedGroupFactory()
        other_program = ProgramFactory(program_status=ACTIVE_PROGRAM_STATUS,
                                       mentor_program_group=named_alumni_group)

        finalist_program = programs[1]

        user = self._create_user_with_role_grant(
            other_program, UserRole.ALUM)
        self._create_user_with_role_grant(
            finalist_program, UserRole.FINALIST, user)

        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                response_data = json.loads(response.content)

                for program in programs:
                    self.assertIn(program.name, response_data["filters"])
                self.assertIn(other_program.name, response_data["filters"])

    def test_superuser_employee_sees_all_mentors(self):
        user = _create_expert()
        user.is_superuser = True
        user.save()

        with self.settings(
                ALGOLIA_APPLICATION_ID='test',
                ALGOLIA_API_KEY='test'):
            with self.login(email=user.email):
                response = self.client.get(self.url)
                response_data = json.loads(response.content)

                self.assertEqual(response_data["filters"], [])

    def _create_user_with_role_grant(
            self, program, user_role_name, user=False):
        user_role = UserRoleFactory(name=user_role_name)
        program_role = ProgramRoleFactory(
            user_role=user_role,
            program=program
        )

        if not user:
            user = _create_entrepreneur()

        ProgramRoleGrantFactory(person=user, program_role=program_role)
        return user
<|endoftext|>


<commit_before>import logging

from statsd import statsd

log = logging.getLogger(__name__)

class MySQLBaseScorer(object):
    """ Base class for scoring of MySQL query problems.

    :param str student_answer: the student query
    :param tuple student_results: a two item tuple: (result columns,
                                  result rows)
    :param str grader_answer: the student query
    :param tuple grader_results: a two item tuple: (result columns,
                                  result rows)
    :returns: a two item tuple with score (float), message (str)
    :rtype: tuple

    This class defines several test methods that score various aspects of the
    query results.

    Subclasses must implement the ``score`` method to implement a specific
    scoring algorothim.

    """

    KEYWORDS = ["SELECT", "WHERE", "JOIN", "ORDER BY", "ASC", "DESC", "GROUP BY", "LIMIT"]

    DEFAULT_SCALE = {
        "perfect": 1.0,
        "close":  0.8,
        "nicetry": 0.6,
        "decent": 0.4,
        "fail": 0.0
        }

    def __init__(self, student_answer, student_results, grader_answer,
                 grader_results, scale=None):
        self.student_answer = student_answer
        self.student_cols = student_results[0]
        self.student_rows = student_results[1]
        self.grader_answer = grader_answer
        self.grader_cols = grader_results[0]
        self.grader_rows = grader_results[1]

        self.scale = self.parse_scale_map(scale)

        self.missing_keywords = []
        self._tests = []

    def score(self):
        """ Subclasses should implement the scoring algorithm """
        raise NotImplemented

    def parse_scale_map(self, scale_map):
        """ Converts grader payload provided scale to dict """

        if not isinstance(scale_map, dict):
            return self.DEFAULT_SCALE

        # Merge provided scale mapping with defaults
        scale = dict(self.DEFAULT_SCALE.items() + scale_map.items())

        # Cooerce scale values to floats
        for key, val in scale.items():
            try:
                scale[key] = float(val)
            except ValueError:
                # Fallback to default value on fail
                if key in self.DEFAULT_SCALE:
                    scale[key] = self.DEFAULT_SCALE[key]
                else:
                    # Or delete if key is not present in default scale
                    del scale[key]

        return scale

    def test_rows_match(self):
        """ Do result rows match exactly? """
        return self.student_rows == self.grader_rows

    def test_rows_match_unsorted(self):
        """ Do result rows match if sort order is ignored?

        First each row is indiviudally sorted, then the list of rows is sorted
        Can return false passes (incorrectly guess that unsorted data matches)

        TODO: Optimize sorts using numpy
        TODO: Improve accuracy by doing the same sorts on columns of data

        """
        sorted_grader_rows = sorted(sorted(row, reverse=True) for row in self.grader_rows)
        sorted_student_rows = sorted(sorted(row, reverse=True) for row in self.student_rows)

        return (sorted_grader_rows == sorted_student_rows)

    def test_row_counts_match(self):
        """ Do row counts match exactly? """
        return (len(self.student_rows) == len(self.grader_rows))

    def test_row_counts_close(self, threshold=.5):
        """ Are row counts reasonbly close? """
        return (abs(1.0 * len(self.student_rows) - len(self.grader_rows)) /
                len(self.grader_rows)) <= threshold

    def test_cols_match(self):
        """ Do result columns match exactly? """
        return (self.student_cols == self.grader_cols)

    def test_cols_match_unsorted(self):
        """ Do result columns match if sort order is ignored? """
        return (sorted(self.student_cols) == sorted(self.grader_cols))

    def test_col_counts_match(self):
        """ Do column counts match exactly? """
        return (len(self.student_cols) == len(self.grader_cols))

    def test_col_counts_close(self, threshold=.5):
        """ Are column counts reasonably close? """
        return (abs(1.0 * len(self.student_cols) - len(self.grader_cols)) /
                len(self.grader_cols)) <= threshold

    def test_keywords_match(self):
        """ Are SQL keywords in the grader query in the student response?

        Builds a list of missing keywords for use when generating hints.

        """
        # TODO: Use sqlparse to make sure the keywords are placed correctly
        for keyword in self.KEYWORDS:
            if keyword in self.grader_answer.upper():
                if keyword not in self.student_answer.upper():
                    self.missing_keywords.append(keyword)
        return (len(self.missing_keywords) == 0)

    @property
    def tests(self):
        """ Returns callable test methods (methods prefixed with 'test_') """
        if self._tests:
            return self._tests

        self._tests = []
        attrs = [attr for attr in dir(self) if attr.startswith('test_')]
        for name in attrs:
            attr = getattr(self, name)
            if hasattr(attr, '__call__'):
                self._tests.append(attr)
        return self._tests

class MySQLRubricScorer(MySQLBaseScorer):

    def score(self):
        """ Generate a score using a hard coded rubric approach """
        results = {}

        # TODO: Don't run unneccesary tests, clearer test logic
        for test in self.tests:
            timer = statsd.timer('bux_sql_grader.scoring.%s' % test.__name__).start()
            result = test()
            timer.stop()
            results[test.__name__] = result

        # "Perfect"
        if (results["test_rows_match"] and
           results["test_cols_match"] and
           results["test_keywords_match"]):
            score = self.scale["perfect"]

        # "Really Close":
        # - Columns are either out of order or named incorrectly
        elif (results["test_rows_match_unsorted"] and
              results["test_keywords_match"]):
            score = self.scale["close"]

        # "Nice Try"
        # - Row counts match but not unsorted contents (bad WHERE clause)
        # - Too many / few rows (bad LIMIT)
        elif (((results["test_cols_match_unsorted"] and
                results["test_row_counts_close"]) or
               (results["test_col_counts_match"] and
                results["test_row_counts_match"]) or
               (results["test_cols_match"])) and
              results["test_keywords_match"]):
            score = self.scale["nicetry"]

        # "Decent Attempt"
        # - Row and column counts are in the right ballpark
        elif (results["test_row_counts_close"] and results["test_col_counts_close"]):
            score = self.scale["decent"]

        # "Fail"
        else:
            score = self.scale["fail"]

        # Generate hints based on the test results
        hints = self.generate_hints(results)

        return score, hints

    def generate_hints(self, results):
        """ Examines scoring results, building a list of hints for the student
        depending on which tests passed.

        """
        hints = []

        # Keyword hints
        if not results["test_keywords_match"]:
            hints.append("Missing SQL Keywords: %s" %
                         ", ".join(self.missing_keywords))

        # Row count hints
        if not results["test_row_counts_match"]:
            if len(self.student_rows) > len(self.grader_rows):
                hints.append("Too many rows.")
            else:
                hints.append("Too few rows.")

        # Column count hints
        if not results["test_col_counts_match"]:
            if len(self.student_cols) > len(self.grader_cols):
                hints.append("Too many columns.")
            else:
                hints.append("Too few columns.")

        # Column names / ordering
        elif not results["test_cols_match_unsorted"]:
            hints.append("Columns are named incorrectly.")

        elif not results["test_cols_match"]:
            hints.append("Columns are out of order.")

        elif results["test_row_counts_match"] and not results["test_rows_match_unsorted"]:
            hints.append("Row count and column names are correct. Compare your rows against the expected results.")

        # Row ordering
        elif results["test_rows_match_unsorted"] and not results["test_rows_match"]:
            hints.append("Rows are out of order.")

        return hints

    def close(self):
        self.student_cols = None
        self.student_rows = None
        self.grader_cols = None
        self.grader_rows = None
<commit_msg>Moves scoring cleanup method to base class.<commit_after>import logging

from statsd import statsd

log = logging.getLogger(__name__)

class MySQLBaseScorer(object):
    """ Base class for scoring of MySQL query problems.

    :param str student_answer: the student query
    :param tuple student_results: a two item tuple: (result columns,
                                  result rows)
    :param str grader_answer: the student query
    :param tuple grader_results: a two item tuple: (result columns,
                                  result rows)
    :returns: a two item tuple with score (float), message (str)
    :rtype: tuple

    This class defines several test methods that score various aspects of the
    query results.

    Subclasses must implement the ``score`` method to implement a specific
    scoring algorothim.

    """

    KEYWORDS = ["SELECT", "WHERE", "JOIN", "ORDER BY", "ASC", "DESC", "GROUP BY", "LIMIT"]

    DEFAULT_SCALE = {
        "perfect": 1.0,
        "close":  0.8,
        "nicetry": 0.6,
        "decent": 0.4,
        "fail": 0.0
        }

    def __init__(self, student_answer, student_results, grader_answer,
                 grader_results, scale=None):
        self.student_answer = student_answer
        self.student_cols = student_results[0]
        self.student_rows = student_results[1]
        self.grader_answer = grader_answer
        self.grader_cols = grader_results[0]
        self.grader_rows = grader_results[1]

        self.scale = self.parse_scale_map(scale)

        self.missing_keywords = []
        self._tests = []

    def score(self):
        """ Subclasses should implement the scoring algorithm """
        raise NotImplemented

    def parse_scale_map(self, scale_map):
        """ Converts grader payload provided scale to dict """

        if not isinstance(scale_map, dict):
            return self.DEFAULT_SCALE

        # Merge provided scale mapping with defaults
        scale = dict(self.DEFAULT_SCALE.items() + scale_map.items())

        # Cooerce scale values to floats
        for key, val in scale.items():
            try:
                scale[key] = float(val)
            except ValueError:
                # Fallback to default value on fail
                if key in self.DEFAULT_SCALE:
                    scale[key] = self.DEFAULT_SCALE[key]
                else:
                    # Or delete if key is not present in default scale
                    del scale[key]

        return scale

    def test_rows_match(self):
        """ Do result rows match exactly? """
        return self.student_rows == self.grader_rows

    def test_rows_match_unsorted(self):
        """ Do result rows match if sort order is ignored?

        First each row is indiviudally sorted, then the list of rows is sorted
        Can return false passes (incorrectly guess that unsorted data matches)

        TODO: Optimize sorts using numpy
        TODO: Improve accuracy by doing the same sorts on columns of data

        """
        sorted_grader_rows = sorted(sorted(row, reverse=True) for row in self.grader_rows)
        sorted_student_rows = sorted(sorted(row, reverse=True) for row in self.student_rows)

        return (sorted_grader_rows == sorted_student_rows)

    def test_row_counts_match(self):
        """ Do row counts match exactly? """
        return (len(self.student_rows) == len(self.grader_rows))

    def test_row_counts_close(self, threshold=.5):
        """ Are row counts reasonbly close? """
        return (abs(1.0 * len(self.student_rows) - len(self.grader_rows)) /
                len(self.grader_rows)) <= threshold

    def test_cols_match(self):
        """ Do result columns match exactly? """
        return (self.student_cols == self.grader_cols)

    def test_cols_match_unsorted(self):
        """ Do result columns match if sort order is ignored? """
        return (sorted(self.student_cols) == sorted(self.grader_cols))

    def test_col_counts_match(self):
        """ Do column counts match exactly? """
        return (len(self.student_cols) == len(self.grader_cols))

    def test_col_counts_close(self, threshold=.5):
        """ Are column counts reasonably close? """
        return (abs(1.0 * len(self.student_cols) - len(self.grader_cols)) /
                len(self.grader_cols)) <= threshold

    def test_keywords_match(self):
        """ Are SQL keywords in the grader query in the student response?

        Builds a list of missing keywords for use when generating hints.

        """
        # TODO: Use sqlparse to make sure the keywords are placed correctly
        for keyword in self.KEYWORDS:
            if keyword in self.grader_answer.upper():
                if keyword not in self.student_answer.upper():
                    self.missing_keywords.append(keyword)
        return (len(self.missing_keywords) == 0)

    def close(self):
        self.student_cols = None
        self.student_rows = None
        self.grader_cols = None
        self.grader_rows = None

    @property
    def tests(self):
        """ Returns callable test methods (methods prefixed with 'test_') """
        if self._tests:
            return self._tests

        self._tests = []
        attrs = [attr for attr in dir(self) if attr.startswith('test_')]
        for name in attrs:
            attr = getattr(self, name)
            if hasattr(attr, '__call__'):
                self._tests.append(attr)
        return self._tests

class MySQLRubricScorer(MySQLBaseScorer):

    def score(self):
        """ Generate a score using a hard coded rubric approach """
        results = {}

        # TODO: Don't run unneccesary tests, clearer test logic
        for test in self.tests:
            timer = statsd.timer('bux_sql_grader.scoring.%s' % test.__name__).start()
            result = test()
            timer.stop()
            results[test.__name__] = result

        # "Perfect"
        if (results["test_rows_match"] and
           results["test_cols_match"] and
           results["test_keywords_match"]):
            score = self.scale["perfect"]

        # "Really Close":
        # - Columns are either out of order or named incorrectly
        elif (results["test_rows_match_unsorted"] and
              results["test_keywords_match"]):
            score = self.scale["close"]

        # "Nice Try"
        # - Row counts match but not unsorted contents (bad WHERE clause)
        # - Too many / few rows (bad LIMIT)
        elif (((results["test_cols_match_unsorted"] and
                results["test_row_counts_close"]) or
               (results["test_col_counts_match"] and
                results["test_row_counts_match"]) or
               (results["test_cols_match"])) and
              results["test_keywords_match"]):
            score = self.scale["nicetry"]

        # "Decent Attempt"
        # - Row and column counts are in the right ballpark
        elif (results["test_row_counts_close"] and results["test_col_counts_close"]):
            score = self.scale["decent"]

        # "Fail"
        else:
            score = self.scale["fail"]

        # Generate hints based on the test results
        hints = self.generate_hints(results)

        return score, hints

    def generate_hints(self, results):
        """ Examines scoring results, building a list of hints for the student
        depending on which tests passed.

        """
        hints = []

        # Keyword hints
        if not results["test_keywords_match"]:
            hints.append("Missing SQL Keywords: %s" %
                         ", ".join(self.missing_keywords))

        # Row count hints
        if not results["test_row_counts_match"]:
            if len(self.student_rows) > len(self.grader_rows):
                hints.append("Too many rows.")
            else:
                hints.append("Too few rows.")

        # Column count hints
        if not results["test_col_counts_match"]:
            if len(self.student_cols) > len(self.grader_cols):
                hints.append("Too many columns.")
            else:
                hints.append("Too few columns.")

        # Column names / ordering
        elif not results["test_cols_match_unsorted"]:
            hints.append("Columns are named incorrectly.")

        elif not results["test_cols_match"]:
            hints.append("Columns are out of order.")

        elif results["test_row_counts_match"] and not results["test_rows_match_unsorted"]:
            hints.append("Row count and column names are correct. Compare your rows against the expected results.")

        # Row ordering
        elif results["test_rows_match_unsorted"] and not results["test_rows_match"]:
            hints.append("Rows are out of order.")

        return hints
<|endoftext|>


<commit_before>data = {"year": "2001", "country": "USA", "title": "Johnny 5", "duration": "119 min"}

print('optimistic style')
# TODO: good, bad

print()
print('pessimistic style')
# TODO: try

print()
print('safety first style')
# TODO: test good, bad
print()

print('accept None instead style')
# TODO: both
print()

print('Explicit alternate value style')
# TODO: both via get
print()

# via defaultdict
print('accept default value instead style')
print()
<commit_msg>final code for safe access<commit_after>from collections import defaultdict

data = {"year": 2001, "country": "USA", "title": "Johnny 5", "duration": "119 min"}

print('optimistic style')
print(data['year'])
# print(data['rating']) # Crash!

print()
print('pessimistic style')
try:
    print(data['year'])
    print(data['rating'])
except Exception as x:
    print("Oops! {}".format(x))

print()
print('safety first style')
if 'year' in data:
    print(data['year'])
if 'rating' in data:
    print(data['rating'])
else:
    print("Oh we didn't find a rating...")
print()

print('accept None instead style')
print(data.get('year'))
print(data.get('rating'))
print()

print('Explicit alternate value style')
print(data.get('year', 0))
print(data.get('rating', '***'))
print()

data = defaultdict(lambda: "MISSING", data)
print('accept default value instead style')
print(data['year'])
print(data['rating'])
print()
<|endoftext|>


<commit_before>import pandas as pd
import numpy as np

class cSignalDecomposition_Options:

    def __init__(self):
        self.mParallelMode = False;
        self.mEnablePlots = False;
        self.mEstimRatio = 0.8;
        self.enable_fast_mode();
        self.mTimeDeltaComputationMethod = "AVG"; # can be "AVG", "MODE", "USER"
        self.mUserTimeDelta = None;
        self.mBusinessDaysOnly = False;
        self.mNoCoxBoxOrders = [];
        self.mCoxBoxOrders = [-2.0, -1.0 , 0.0,  2.0];
        self.mExtensiveCoxBoxOrders = [-2, -1, -0.5, -0.33 , -0.25 , 0.0, 2, 0.5, 0.33 , 0.25];
        self.mEnableTrends = True;
        self.mEnableCycles = True;
        self.mEnableARModels = True;
        self.mEnableARXModels = True;
        self.disableDebuggingOptions();

    def disableDebuggingOptions(self):
        self.mDebug = False;
        self.mDebugCycles = False;
        self.mDebugProfile = False;
        self.mDebugPerformance = False;

    def enable_slow_mode(self):
        self.mEnableCoxBox = True;
        # self.mCoxBoxOrders = self.mExtensiveCoxBoxOrders;
        self.mEnableQuantization = True;
        self.mQuantiles = [5, 10, 20]; # quintiles, deciles, and vingtiles;)
        self.mEnableMovingAverageTrends = True;
        self.mEnableMovingMedianTrends = True;
        self.mEnableDifferentiationTransforms = True;
        self.mEnableIntegrationTransforms = True;
        self.mEnableTimeBasedTrends = True;
        self.mMovingAverageLengths = [5, 7, 12, 24 , 30, 60];
        self.mMovingMedianLengths = [5, 7, 12, 24 , 30, 60];

        self.mCycleLengths = [5, 7, 12, 24 , 30, 60];
        self.mCycle_Criterion = "MAPE";
        self.mCycle_Criterion_Threshold = None;

        self.mEnableSeasonals = True;

        self.mMaxAROrder = 256;

    def enable_fast_mode(self):
        self.mEnableCoxBox = False;
        self.mEnableQuantization = False;
        self.mQuantiles = [5, 10, 20]; # quintiles, deciles, and vingtiles;)
        self.mEnableMovingAverageTrends = False;
        self.mEnableMovingMedianTrends = False;
        self.mEnableDifferentiationTransforms = True;
        self.mEnableIntegrationTransforms = True;
        self.mEnableTimeBasedTrends = True;
        self.mMovingAverageLengths = [5, 7, 12, 24 , 30, 60];
        self.mMovingMedianLengths = [5, 7, 12, 24 , 30, 60];

        self.mEnableCycles = True;
        self.mCycleLengths = [5, 7, 12, 24 , 30, 60];
        self.mCycle_Criterion = "MAPE";
        self.mCycle_Criterion_Threshold = None;

        self.mEnableSeasonals = True;

        self.mEnableARModels = True;
        self.mMaxAROrder = 256;

<commit_msg>Added +        self.mMaxExogenousCategories = 5;<commit_after>import pandas as pd
import numpy as np

class cSignalDecomposition_Options:

    def __init__(self):
        self.mParallelMode = False;
        self.mEnablePlots = False;
        self.mEstimRatio = 0.8;
        self.enable_fast_mode();
        self.mTimeDeltaComputationMethod = "AVG"; # can be "AVG", "MODE", "USER"
        self.mUserTimeDelta = None;
        self.mBusinessDaysOnly = False;
        self.mMaxExogenousCategories = 5;
        self.mNoCoxBoxOrders = [];
        self.mCoxBoxOrders = [-2.0, -1.0 , 0.0,  2.0];
        self.mExtensiveCoxBoxOrders = [-2, -1, -0.5, -0.33 , -0.25 , 0.0, 2, 0.5, 0.33 , 0.25];
        self.mEnableTrends = True;
        self.mEnableCycles = True;
        self.mEnableARModels = True;
        self.mEnableARXModels = True;
        self.disableDebuggingOptions();

    def disableDebuggingOptions(self):
        self.mDebug = False;
        self.mDebugCycles = False;
        self.mDebugProfile = False;
        self.mDebugPerformance = False;

    def enable_slow_mode(self):
        self.mEnableCoxBox = True;
        # self.mCoxBoxOrders = self.mExtensiveCoxBoxOrders;
        self.mEnableQuantization = True;
        self.mQuantiles = [5, 10, 20]; # quintiles, deciles, and vingtiles;)
        self.mEnableMovingAverageTrends = True;
        self.mEnableMovingMedianTrends = True;
        self.mEnableDifferentiationTransforms = True;
        self.mEnableIntegrationTransforms = True;
        self.mEnableTimeBasedTrends = True;
        self.mMovingAverageLengths = [5, 7, 12, 24 , 30, 60];
        self.mMovingMedianLengths = [5, 7, 12, 24 , 30, 60];

        self.mCycleLengths = [5, 7, 12, 24 , 30, 60];
        self.mCycle_Criterion = "MAPE";
        self.mCycle_Criterion_Threshold = None;

        self.mEnableSeasonals = True;

        self.mMaxAROrder = 256;

    def enable_fast_mode(self):
        self.mEnableCoxBox = False;
        self.mEnableQuantization = False;
        self.mQuantiles = [5, 10, 20]; # quintiles, deciles, and vingtiles;)
        self.mEnableMovingAverageTrends = False;
        self.mEnableMovingMedianTrends = False;
        self.mEnableDifferentiationTransforms = True;
        self.mEnableIntegrationTransforms = True;
        self.mEnableTimeBasedTrends = True;
        self.mMovingAverageLengths = [5, 7, 12, 24 , 30, 60];
        self.mMovingMedianLengths = [5, 7, 12, 24 , 30, 60];

        self.mEnableCycles = True;
        self.mCycleLengths = [5, 7, 12, 24 , 30, 60];
        self.mCycle_Criterion = "MAPE";
        self.mCycle_Criterion_Threshold = None;

        self.mEnableSeasonals = True;

        self.mEnableARModels = True;
        self.mMaxAROrder = 256;

<|endoftext|>


<commit_before># coding: utf-8
from pupa.scrape import Scraper

from utils import lxmlize, CanadianLegislator as Legislator

from urlparse import urljoin

import re

COUNCIL_PAGE = 'http://www.kitchener.ca/en/insidecityhall/WhoIsMyCouncillor.asp'
MAYOR_PAGE = 'http://www.kitchener.ca/en/insidecityhall/MayorSLandingPage.asp'

class KitchenerPersonScraper(Scraper):

  def get_people(self):
    page = lxmlize(COUNCIL_PAGE)

    councillor_urls = page.xpath('//div[@id="printArea"]//li/a/@href')

    for councillor_url in councillor_urls:
      cd = councillor_data(councillor_url)
      if cd: # see below about rep page with no ward
        yield cd

    yield mayor_data(MAYOR_PAGE)

def councillor_data(url):
  page = lxmlize(url)

  infobox_node = page.xpath('//div[@id="printArea"]')[0]
  name = infobox_node.xpath('string(.//h1[1])')[len('Councillor'):]
  district = infobox_node.xpath('string(.//h2[contains(., "Ward")])')

  contact_node = infobox_node.xpath('.//p[contains(text(), "Coun.")]')[0]
  email = contact_node.xpath('string(.//text()[contains(., "@")])').split()[-1]

  # TODO: contact details are tricky
  #address = '\n'.join(contact_node.xpath('./text()')[:4])
  #phone = contact_node.xpath('string(./text()[5])').strip('City hall:')

  photo_url_rel = page.xpath('string(//div[@id="sideBar"]//img/@src)')
  photo_url = urljoin(COUNCIL_PAGE, photo_url_rel)

  # if statement below because one rep page doesn't list ward:
  # http://www.kitchener.ca/en/insidecityhall/Yvonne.asp
  if district:
    p = Legislator(name=name, post_id=district, role='Councillor')
    p.add_source(COUNCIL_PAGE)
    p.add_source(url)
    if email:
      p.add_contact('email', email, None)
    p.image = photo_url

    return p

def mayor_data(url):
  page = lxmlize(url)

  infobox_node = page.xpath('//div[@id="printArea"]')[0]
  name = infobox_node.xpath('string(.//h1)')[6:] # strip 'Mayor' prefix

  contact_node = page.xpath('//div[@id="contentIntContact"]')[0]

  # TODO: fruitlessly wasted way too much time below
  address = '\n'.join(contact_node.xpath('./p[2]/text()')[:3])
  phone = contact_node.xpath('string(./p[2]/text()[contains(., "T.")])')[3:]

  photo_url_rel = page.xpath('string(//div[@id="sideBar"]//img/@src)')
  photo_url = urljoin(COUNCIL_PAGE, photo_url_rel)

  p = Legislator(name=name, post_id='Kitchener', role='Mayor')
  p.add_source(url)
  p.image = photo_url

  return p

<commit_msg>kitchener: get all councillors<commit_after># coding: utf-8
from pupa.scrape import Scraper

from utils import lxmlize, CanadianLegislator as Legislator

from urlparse import urljoin

import re

COUNCIL_PAGE = 'http://www.kitchener.ca/en/insidecityhall/WhoIsMyCouncillor.asp'
MAYOR_PAGE = 'http://www.kitchener.ca/en/insidecityhall/MayorSLandingPage.asp'

class KitchenerPersonScraper(Scraper):

  def get_people(self):
    page = lxmlize(COUNCIL_PAGE)

    councillor_nodes = page.xpath('//div[@id="printArea"]//li')

    for node in councillor_nodes:
      councillor_url = node.xpath('string(./a/@href)')
      ward = node.xpath('string(./strong)').split('-')[0]
      yield councillor_data(councillor_url, ward)

    yield mayor_data(MAYOR_PAGE)

def councillor_data(url, ward):
  page = lxmlize(url)

  infobox_node = page.xpath('//div[@id="printArea"]')[0]
  name = infobox_node.xpath('string(.//h1[1])')[len('Councillor'):]

  contact_node = infobox_node.xpath('.//p[contains(text(), "Coun.")]')[0]
  email = contact_node.xpath('string(.//text()[contains(., "@")])').split()[-1]

  # TODO: contact details are tricky
  #address = '\n'.join(contact_node.xpath('./text()')[:4])
  #phone = contact_node.xpath('string(./text()[5])').strip('City hall:')

  photo_url_rel = page.xpath('string(//div[@id="sideBar"]//img/@src)')
  photo_url = urljoin(COUNCIL_PAGE, photo_url_rel)

  p = Legislator(name=name, post_id=ward, role='Councillor')
  p.add_source(COUNCIL_PAGE)
  p.add_source(url)
  if email:
    p.add_contact('email', email, None)
  p.image = photo_url

  return p

def mayor_data(url):
  page = lxmlize(url)

  infobox_node = page.xpath('//div[@id="printArea"]')[0]
  name = infobox_node.xpath('string(.//h1)')[6:] # strip 'Mayor' prefix

  contact_node = page.xpath('//div[@id="contentIntContact"]')[0]

  # TODO: fruitlessly wasted way too much time below
  address = '\n'.join(contact_node.xpath('./p[2]/text()')[:3])
  phone = contact_node.xpath('string(./p[2]/text()[contains(., "T.")])')[3:]

  photo_url_rel = page.xpath('string(//div[@id="sideBar"]//img/@src)')
  photo_url = urljoin(COUNCIL_PAGE, photo_url_rel)

  p = Legislator(name=name, post_id='Kitchener', role='Mayor')
  p.add_source(url)
  p.image = photo_url

  return p

<|endoftext|>


<commit_before>import unittest
import sys
import requests
from bs4 import BeautifulSoup
from mock import patch
sys.path.append("../")

import bgg_collector

class CollectorTest(unittest.TestCase):

    def setUp(self):
        pass

    def tearDown(self):
        pass

    @patch("bgg_collector.get_page_text")
    def test_get_games(self, get_mock):
        with open("tests/test_html.html") as td:
            test_data = td.read()

        get_mock.return_value = test_data
        game_list = bgg_collector.extract_games_from_page(1, "all")
        self.assertEquals(len(game_list), 100)

    def test_get_entry(self):

        expected_entry = {"gameid":"12333",
                          "title":"Twilight Struggle",
                          "year":"2005"}
        soup_parse = BeautifulSoup("

Twilight Struggle(2005)
")
        rough_cut = soup_parse.find_all('div', attrs={"style":"z-index:1000;"})

        for tag in rough_cut:
            test_entry = bgg_collector.extract_game_from_entry(tag)

        self.assertEquals(expected_entry, test_entry)

    @patch("bgg_collector.get_page_text")
    def test_get_games_on_page(self, get_mock):
        with open("tests/test_html.html") as td:
            test_data = td.read()

        get_mock.return_value = test_data

        games = bgg_collector.get_list_of_top_games(100)
        self.assertEquals(len(games), 100)

<commit_msg>add more tests<commit_after>import unittest
import sys
import requests
from bs4 import BeautifulSoup
from mock import patch
sys.path.append("../")

import bgg_collector

class CollectorTest(unittest.TestCase):

    def setUp(self):
        pass

    def tearDown(self):
        pass

    @patch("bgg_collector.get_page_text")
    def test_get_games_on_page(self, get_mock):
        with open("tests/test_html.html") as td:
            test_data = td.read()

        get_mock.return_value = test_data
        game_list = bgg_collector.extract_games_from_page(1, "all")
        self.assertEquals(len(game_list), 100)

    def test_get_entry(self):

        expected_entry = {"gameid":"12333",
                          "title":"Twilight Struggle",
                          "year":"2005"}
        soup_parse = BeautifulSoup("

Twilight Struggle(2005)
")
        rough_cut = soup_parse.find_all('div', attrs={"style":"z-index:1000;"})

        for tag in rough_cut:
            test_entry = bgg_collector.extract_game_from_entry(tag)

        self.assertEquals(expected_entry, test_entry)

    @patch("bgg_collector.get_page_text")
    def test_get_games(self, get_mock):
        with open("tests/test_html.html") as td:
            test_data = td.read()

        get_mock.return_value = test_data

        games = bgg_collector.get_list_of_top_games(100)
        self.assertEquals(len(games), 100)

    @patch("bgg_collector.get_page_text")
    def test_get_games_300(self, get_mock):
        with open("tests/test_html.html") as td:
            test_data = td.read()

        get_mock.return_value = test_data

        games = bgg_collector.get_list_of_top_games(300)
        self.assertEquals(len(games), 300)

    @patch("bgg_collector.get_page_text")
    def test_get_games_355(self, get_mock):
        with open("tests/test_html.html") as td:
            test_data = td.read()

        get_mock.return_value = test_data

        games = bgg_collector.get_list_of_top_games(355)
        self.assertEquals(len(games), 355)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

from django.db import models
from django.contrib.auth.models import User

from calebasse.agenda.models import Event, EventType
from calebasse.agenda.managers import EventManager

from validation_states import VALIDATION_STATES

class ActValidationState(models.Model):

    class Meta:
        app_label = 'actes'

    act = models.ForeignKey('actes.Act',
        verbose_name=u'Acte', editable=False)
    state_name = models.CharField(max_length=150)
    created = models.DateTimeField(u'Création', auto_now_add=True)
    author = \
        models.ForeignKey(User,
        verbose_name=u'Auteur', editable=False)
    previous_state = models.ForeignKey('ActValidationState',
        verbose_name=u'Etat précédent',
        editable=False, blank=True, null=True)
    # To record if the validation has be done by the automated validation
    auto = models.BooleanField(default=False,
            verbose_name=u'Vérouillage')

class Act(models.Model):
    patient = models.ForeignKey('dossiers.PatientRecord')
    date = models.DateTimeField()
    act_type = models.ForeignKey('ressources.ActType',
            verbose_name=u'Type d\'acte')
    validation_locked = models.BooleanField(default=False,
            verbose_name=u'Vérouillage')
    transport_company = models.ForeignKey('ressources.TransportCompany',
            blank=True,
            null=True,
            verbose_name=u'Compagnie de transport')
    transport_type = models.ForeignKey('ressources.TransportType',
            blank=True,
            null=True,
            verbose_name=u'Type de transport')
    doctors = models.ManyToManyField('personnes.Worker',
            limit_choices_to={'type__intervene': True},
            verbose_name=u'Thérapeutes')
    histories = models.ManyToManyField('HistoryAct')

    def is_absent(self):
        if self.get_state() in ('ABS_NON_EXC', 'ABS_EXC', 'ANNUL_NOUS',
                'ANNUL_FAMILLE', 'ABS_ESS_PPS', 'ENF_HOSP'):
            return True

    def get_state(self):
        return self.actvalidationstate_set.latest('created')

    def is_state(self, state_name):
        state = self.get_state()
        if state and state.state_name == state_name:
            return True
        return False

    def set_state(self, state_name, author, auto=False,
            change_state_check=True):
        if not author:
            raise Exception('Missing author to set state')
        if not state_name in VALIDATION_STATES.keys():
            raise Exception("Etat d'acte non existant %s")
        current_state = self.get_state()
        ActValidationState(act=self, state_name=state_name,
            author=author, previous_state=current_state).save()

    def __unicode__(self):
        return '{0} le {1} pour {2} avec {3}'.format(
                self.act_type, self.date, self.patient,
                ', '.join(map(unicode, self.doctors.all())))

    def __repr__(self):
        return '<%s %r %r>' % (self.__class__.__name__, unicode(self), self.id)

    class Meta:
        verbose_name = u"Acte"
        verbose_name_plural = u"Actes"
        ordering = ['-date', 'patient']

class HistoryAct(models.Model):
    EVENT_CHOICES = (
            ('NR', u'Nouveau rendez-vous'),
            ('AV', u'Acte validé'),
            ('CF', u'En cours de facturation'),
            ('AF', u'Acte facturé'),
            )
    date = models.DateTimeField()
    event_type = models.CharField(max_length=2,
            choices=EVENT_CHOICES)
    description = models.TextField(default='')

class EventActManager(EventManager):

    def create_patient_appointment(self, creator, title, patient, participants,
            act_type, service, start_datetime, end_datetime, description='',
            room=None, note=None, **rrule_params):
        """
        This method allow you to create a new patient appointment quickly

        Args:
            title: patient appointment title (str)
            patient: Patient object
            participants: List of CalebasseUser (therapists)
            act_type: ActType object
            service: Service object. Use session service by defaut
            start_datetime: datetime with the start date and time
            end_datetime: datetime with the end date and time
            freq, count, until, byweekday, rrule_params:
            follow the ``dateutils`` API (see http://labix.org/python-dateutil)

        Example:
            Look at calebasse.agenda.tests.EventTest (test_create_appointments
            method)
        """

        event_type, created = EventType.objects.get_or_create(
                label=u"Rendez-vous patient"
                )

        history = HistoryAct.objects.create(
                date = datetime.now(),
                event_type = 'NR')
        act_event = EventAct.objects.create(
                title=title,
                event_type=event_type,
                patient=patient,
                act_type=act_type,
                date=start_datetime,
                histories = [history]
                )
        act_event.doctors = participants
        ActValidationState(act=act_event, state_name='NON_VALIDE',
            author=creator, previous_state=None).save()

        return self._set_event(act_event, participants, description,
                services=[service], start_datetime=start_datetime,
                end_datetime=end_datetime,
                room=room, note=note, **rrule_params)

class EventAct(Act, Event):
    objects = EventActManager()

    VALIDATION_CODE_CHOICES = (
            ('absent', u'Absent'),
            ('present', u'Présent'),
            )
    attendance = models.CharField(max_length=16,
            choices=VALIDATION_CODE_CHOICES,
            default='absent',
            verbose_name=u'Présence')
    convocation_sent = models.BooleanField(blank=True,
            verbose_name=u'Convoqué')

    def __unicode__(self):
        return 'Rdv le {0} de {1} avec {2} pour {3}'.format(
                self.occurrence_set.all()[0].start_time, self.patient,
                ', '.join(map(unicode, self.participants.all())),
                self.act_type)

    def __repr__(self):
        return '<%s %r %r>' % (self.__class__.__name__, unicode(self),
            self.id)

    class Meta:
        verbose_name = 'Rendez-vous patient'
        verbose_name_plural = 'Rendez-vous patient'
        ordering = ['-date', 'patient']
<commit_msg>actes: add function to Act for Sessad notification.<commit_after># -*- coding: utf-8 -*-

from django.db import models
from django.contrib.auth.models import User

from calebasse.agenda.models import Event, EventType
from calebasse.agenda.managers import EventManager

from validation_states import VALIDATION_STATES

class ActValidationState(models.Model):

    class Meta:
        app_label = 'actes'

    act = models.ForeignKey('actes.Act',
        verbose_name=u'Acte', editable=False)
    state_name = models.CharField(max_length=150)
    created = models.DateTimeField(u'Création', auto_now_add=True)
    author = \
        models.ForeignKey(User,
        verbose_name=u'Auteur', editable=False)
    previous_state = models.ForeignKey('ActValidationState',
        verbose_name=u'Etat précédent',
        editable=False, blank=True, null=True)
    # To record if the validation has be done by the automated validation
    auto = models.BooleanField(default=False,
            verbose_name=u'Vérouillage')

    def __unicode__(self):
        return self.state_name + ' ' + str(self.created)

class Act(models.Model):
    patient = models.ForeignKey('dossiers.PatientRecord')
    date = models.DateTimeField()
    act_type = models.ForeignKey('ressources.ActType',
            verbose_name=u'Type d\'acte')
    validation_locked = models.BooleanField(default=False,
            verbose_name=u'Vérouillage')
    transport_company = models.ForeignKey('ressources.TransportCompany',
            blank=True,
            null=True,
            verbose_name=u'Compagnie de transport')
    transport_type = models.ForeignKey('ressources.TransportType',
            blank=True,
            null=True,
            verbose_name=u'Type de transport')
    doctors = models.ManyToManyField('personnes.Worker',
            limit_choices_to={'type__intervene': True},
            verbose_name=u'Thérapeutes')
    histories = models.ManyToManyField('HistoryAct')

    def is_absent(self):
        if self.get_state() in ('ABS_NON_EXC', 'ABS_EXC', 'ANNUL_NOUS',
                'ANNUL_FAMILLE', 'ABS_ESS_PPS', 'ENF_HOSP'):
            return True

    def get_state(self):
        return self.actvalidationstate_set.latest('created')

    def is_state(self, state_name):
        state = self.get_state()
        if state and state.state_name == state_name:
            return True
        return False

    def set_state(self, state_name, author, auto=False,
            change_state_check=True):
        if not author:
            raise Exception('Missing author to set state')
        if not state_name in VALIDATION_STATES.keys():
            raise Exception("Etat d'acte non existant %s")
        current_state = self.get_state()
        ActValidationState(act=self, state_name=state_name,
            author=author, previous_state=current_state).save()

    # START Specific to sessad healthcare
    def was_covered_by_notification(self):
        notifications = \
            SessadHealthCareNotification.objects.filter(patient=self.patient,
            start_date__lte=self.date, end_date__gte=self.date)
        if notifications:
            return True
    # END Specific to sessad healthcare

    def __unicode__(self):
        return '{0} le {1} pour {2} avec {3}'.format(
                self.act_type, self.date, self.patient,
                ', '.join(map(unicode, self.doctors.all())))

    def __repr__(self):
        return '<%s %r %r>' % (self.__class__.__name__, unicode(self), self.id)

    class Meta:
        verbose_name = u"Acte"
        verbose_name_plural = u"Actes"
        ordering = ['-date', 'patient']

class HistoryAct(models.Model):
    EVENT_CHOICES = (
            ('NR', u'Nouveau rendez-vous'),
            ('AV', u'Acte validé'),
            ('CF', u'En cours de facturation'),
            ('AF', u'Acte facturé'),
            )
    date = models.DateTimeField()
    event_type = models.CharField(max_length=2,
            choices=EVENT_CHOICES)
    description = models.TextField(default='')

class EventActManager(EventManager):

    def create_patient_appointment(self, creator, title, patient, participants,
            act_type, service, start_datetime, end_datetime, description='',
            room=None, note=None, **rrule_params):
        """
        This method allow you to create a new patient appointment quickly

        Args:
            title: patient appointment title (str)
            patient: Patient object
            participants: List of CalebasseUser (therapists)
            act_type: ActType object
            service: Service object. Use session service by defaut
            start_datetime: datetime with the start date and time
            end_datetime: datetime with the end date and time
            freq, count, until, byweekday, rrule_params:
            follow the ``dateutils`` API (see http://labix.org/python-dateutil)

        Example:
            Look at calebasse.agenda.tests.EventTest (test_create_appointments
            method)
        """

        event_type, created = EventType.objects.get_or_create(
                label=u"Rendez-vous patient"
                )

        history = HistoryAct.objects.create(
                date = datetime.now(),
                event_type = 'NR')
        act_event = EventAct.objects.create(
                title=title,
                event_type=event_type,
                patient=patient,
                act_type=act_type,
                date=start_datetime,
                histories = [history]
                )
        act_event.doctors = participants
        ActValidationState(act=act_event, state_name='NON_VALIDE',
            author=creator, previous_state=None).save()

        return self._set_event(act_event, participants, description,
                services=[service], start_datetime=start_datetime,
                end_datetime=end_datetime,
                room=room, note=note, **rrule_params)

class EventAct(Act, Event):
    objects = EventActManager()

    VALIDATION_CODE_CHOICES = (
            ('absent', u'Absent'),
            ('present', u'Présent'),
            )
    attendance = models.CharField(max_length=16,
            choices=VALIDATION_CODE_CHOICES,
            default='absent',
            verbose_name=u'Présence')
    convocation_sent = models.BooleanField(blank=True,
            verbose_name=u'Convoqué')

    def __unicode__(self):
        return 'Rdv le {0} de {1} avec {2} pour {3}'.format(
                self.occurrence_set.all()[0].start_time, self.patient,
                ', '.join(map(unicode, self.participants.all())),
                self.act_type)

    def __repr__(self):
        return '<%s %r %r>' % (self.__class__.__name__, unicode(self),
            self.id)

    class Meta:
        verbose_name = 'Rendez-vous patient'
        verbose_name_plural = 'Rendez-vous patient'
        ordering = ['-date', 'patient']
<|endoftext|>