<commit_before>import json

from atom.ext.crispy_forms.forms import BaseTableFormSet
from atom.views import DeleteMessageMixin
from braces.views import FormValidMessageMixin, SelectRelatedMixin, UserFormKwargsMixin
from cached_property import cached_property
from dal import autocomplete
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.core.urlresolvers import reverse_lazy
from django.http import HttpResponseRedirect, JsonResponse
from django.shortcuts import get_object_or_404
from django.utils.encoding import force_text
from django.utils.translation import ugettext as _f
from django.utils.translation import ugettext_lazy as _
from django.views.generic import DeleteView, DetailView, ListView, TemplateView
from django_filters.views import FilterView
from extra_views import InlineFormSet, NamedFormsetsMixin, UpdateWithInlinesView
from braces.views import JSONResponseMixin
from ..institutions.filters import InstitutionFilter
from ..institutions.models import Institution
from ..monitoring_pages.forms import MiniPageForm
from ..monitoring_pages.models import Page
from ..questions.forms import ChoiceForm, ConditionForm, QuestionForm, get_form_cls_for_question
from ..questions.models import Question, Sheet
from .forms import MonitoringForm
from .models import Monitoring, MonitoringInstitution

NO_QUESTION = _f("Questions are required. No questions provided")

UNKNOWN_TARGET = _f("Attempt to create reference to non-exists target.")

class CustomJSONResponseMixin(object):
    def error_list(self, form):
        return [(k, force_text(v[0])) for k, v in form.errors.items()]

    def error(self, **kwargs):
        kwargs['success'] = False
        # transaction.rollback() # TODO: Rollback on error
        return JsonResponse(kwargs, status=400)

class MonitoringListView(SelectRelatedMixin, ListView):
    model = Monitoring
    select_related = ['user']
    paginate_by = 25

class MonitoringDetailView(SelectRelatedMixin, DetailView):
    model = Monitoring
    select_related = ['user', ]

class MonitoringCreateView(LoginRequiredMixin, CustomJSONResponseMixin, PermissionRequiredMixin,
                           TemplateView):
    model = Monitoring
    permission_required = 'monitorings.add_monitoring'
    template_name = 'monitorings/monitoring_form_monitoring.html'

    def post(self, *args, **kwargs):  # TODO: Transactions in MonitoringCreateView
        data = json.loads(self.request.body.decode('utf-8'))

        # Validate
        # Validate monitoring
        form = MonitoringForm(data=data, user=self.request.user)
        if not form.is_valid():
            return self.error(errors=self.error_list(form))

        # Validate provided any questions
        questions = data.get('questions', None)
        if not questions:
            return self.error(error=NO_QUESTION)

        # Validate questions
        question_forms = [QuestionForm(data=x) for x in questions]
        if not all(x.is_valid() for x in question_forms):
            return self.error(errors=[self.error_list(x) for x in question_forms])

        # Validate condition by form
        condition_list = [condition
                          for question in questions if 'hideConditions' in question
                          for condition in question['hideConditions']]
        condition_forms = [ConditionForm(data=condition) for condition in condition_list]
        if not all(x.is_valid() for x in condition_forms):
            return self.error(errors=[self.error_list(x) for x in condition_forms])

        # Validate condition by target limit
        if not all(x.get('target', 0) < len(questions) and x.get('target', 0) >= 0
                   for x in condition_list):
            return self.error(error=UNKNOWN_TARGET)

        # Validate choices
        options_sets = [option for question in questions
                        if 'options' in question and question.get('type', None) == 'choice'
                        for option in question['options']]
        choices_forms = [ChoiceForm(data=options) for options in options_sets]
        if not all(x.is_valid() for x in choices_forms):
            return self.error(errors=[self.error_list(x) for x in choices_forms])

        # Save
        # Save monitoring
        monitoring = form.save()

        # Save question
        question_objs = []
        for i, x in enumerate(questions):
            related = {'monitoring': monitoring,
                       'created_by': self.request.user,
                       'order': i}
            question_objs.append(QuestionForm(data=x, related=related).save())

        # Save condition
        condition_objs = []
        for i, question in enumerate(questions):
            if not question.get('hideConditions', False):  # Skip if no conditions
                continue
            for condition in question['hideConditions']:
                related = {'related': question_objs[i],
                           'target': question_objs[condition.get('target', 0)],
                           'value': condition.get('value', '') or ''}
                condition_objs.append(ConditionForm(data=condition, related=related).save())

        # Save choices
        choice_objs = []
        for i, question in enumerate(questions):
            if 'options' not in question:  # Skip if no options
                continue
            if not question.get('type', None) != 'choice':  # Skip if bad type
                continue
            for j, option in enumerate(question['options']):
                related = {'question': question_objs[i], 'order': j}
                choice_objs.append(ChoiceForm(option, related=related).save())
        return JsonResponse({'success': True, 'url': monitoring.get_absolute_url()})

class PageInline(InlineFormSet):
    model = Page
    fields = ['title', 'ordering']
    form_class = MiniPageForm
    formset_class = BaseTableFormSet

    def get_factory_kwargs(self):  # Hack, see AndrewIngram/django-extra-views#121
        kwargs = super(PageInline, self).get_factory_kwargs()
        kwargs.pop('fields', None)
        return kwargs

class MonitoringUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UserFormKwargsMixin,
                           FormValidMessageMixin, NamedFormsetsMixin, UpdateWithInlinesView):
    inlines = [PageInline, ]
    inlines_names = ['pages', ]
    model = Monitoring
    form_class = MonitoringForm
    permission_required = 'monitorings.change_monitoring'

    def get_form_valid_message(self):
        return _("{0} updated!").format(self.object)

# TODO Tests for MonitoringAssignUpdateView
class MonitoringAssignUpdateView(LoginRequiredMixin, PermissionRequiredMixin, FilterView):
    model = Institution
    filterset_class = InstitutionFilter
    permission_required = 'monitorings.change_monitoring'
    template_name = 'monitorings/institution_assign.html'

    def get_queryset(self, *args, **kwargs):
        qs = super(MonitoringAssignUpdateView, self).get_queryset(*args, **kwargs)
        return qs.exclude(monitorings=self.monitoring.pk).select_related('region')

    @cached_property
    def monitoring(self):
        return get_object_or_404(Monitoring, slug=self.kwargs['slug'])

    def get_context_data(self, *args, **kwargs):
        context = super(MonitoringAssignUpdateView, self).get_context_data(*args, **kwargs)
        context['monitoring'] = self.monitoring
        return context

    def post(self, request, *args, **kwargs):
        ids = request.POST.getlist('to_assign')
        qs = Institution.objects.filter(pk__in=ids).exclude(monitorings=self.monitoring.pk)
        count = 0
        for institution in qs:
            self.monitoring.institutions.add(institution)
            count += 1
        msg = _("%(count)d institutions was assigned " +
                "to %(monitoring)s") % {'count': count,
                                        'monitoring': self.monitoring}
        messages.success(self.request, msg)
        return HttpResponseRedirect(request.get_full_path())

class MonitoringDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteMessageMixin,
                           DeleteView):
    model = Monitoring
    success_url = reverse_lazy('monitorings:list')
    permission_required = 'monitorings.delete_monitoring'

    def get_success_message(self):
        return _("{0} deleted!").format(self.object)

class MonitoringAutocomplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        qs = Monitoring.objects.all()

        if self.q:
            qs = qs.filter(name__istartswith=self.q)

        return qs

class MonitoringAnswerView(LoginRequiredMixin, CustomJSONResponseMixin, TemplateView):
    template_name = 'monitorings/monitoring_form_answer.html'

    def get_object(self):
        return get_object_or_404(MonitoringInstitution,
                                 monitoring__slug=self.kwargs['slug'],
                                 institution__slug=self.kwargs['institution_slug'])

    def get_context_data(self, *args, **kwargs):
        context = super(MonitoringAnswerView, self).get_context_data(*args, **kwargs)
        thr = self.get_object()
        context['monitoring'] = thr.monitoring
        context['institution'] = thr.institution
        return context

    @cached_property
    def answer_dict(self):
        return {answer.get('question_id'): answer for answer in self.data.get('result', {})}

    def get_answer_by_pk(self, pk):
        return self.answer_dict[pk]

    def _construct_answer_forms(self, questions, sheet):
        forms = []
        for question in questions:
            answer = self.get_answer_by_pk(question.pk)
            form_cls = get_form_cls_for_question(question)
            form = form_cls(data=answer, question=question, sheet=sheet)
            forms.append(form)
        return forms

    def post(self, *args, **kwargs):  # TODO: Transactions in MonitoringAnswerView
        self.data = json.loads(self.request.body.decode('utf-8'))

        thr = self.get_object()
        (monitoring, institution) = (thr.monitoring, thr.institution)

        questions = Question.objects.filter(monitoring=monitoring).all()
        sheet, created = Sheet.objects.get_or_create(monitoring=monitoring,
                                                     institution=institution,
                                                     user=self.request.user,
                                                     point=self.data.get('point', 0))

        # Validate one sheet per user
        if not created:
            return self.error(error="Unable to answer twice")

        # Validate all answers
        for question in questions:
            answer = self.get_answer_by_pk(question.pk)
            if not answer:
                return self.error(error="Missing answer for question #%d" % (question.pk))
        # Construct forms
        answer_forms = self._construct_answer_forms(questions, sheet)

        # Validate forms
        if not all(x.is_valid() for x in answer_forms):
            return self.error(errors=[self.error_list(x) for x in answer_forms])

        # Save answers
        [form.save() for form in answer_forms]

        return JsonResponse({'success': True,
                             'return_url': monitoring.get_institution_url(institution)})

class MonitoringApiDetailView(JSONResponseMixin, DetailView):
    model = Monitoring

    def get_options(self, question):
        for choice in question.choice_set.all():
            yield {'key': choice.key, 'value': choice.value}

    def get_conditions(self, question):
        for condition in question.condition_related.all():  # TODO: Prefetch condition.target
            data = {}
            data['type'] = condition.type
            data['target'] = condition.target.order  # It's ok, "order"
            data['value'] = condition.value
            yield data

    def get_questions(self):
        for question in self.object.question_set.all():
            data = {}
            data['name'] = question.name
            data['description'] = question.description
            data['type'] = question.type
            data['hideConditions'] = list(self.get_conditions(question))
            if question.type == Question.TYPE.choice:
                data['options'] = list(self.get_options(question))
            yield data

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        context = {}
        context['name'] = self.object.name
        context['description'] = self.object.description
        context['questons'] = list(self.get_questions())
        return self.render_json_response(context)

    def get_queryset(self, *args, **kwargs):
        qs = super(MonitoringApiDetailView, self).get_queryset(*args, **kwargs)
        return qs.prefetch_related('question_set',
                                   'question_set__condition_related',
                                   'question_set__condition_related__target',
                                   'question_set__choice_set',
                                   )
<commit_msg>Add question.id to MonitoringApiDetailView<commit_after>import json

from atom.ext.crispy_forms.forms import BaseTableFormSet
from atom.views import DeleteMessageMixin
from braces.views import FormValidMessageMixin, SelectRelatedMixin, UserFormKwargsMixin
from cached_property import cached_property
from dal import autocomplete
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.core.urlresolvers import reverse_lazy
from django.http import HttpResponseRedirect, JsonResponse
from django.shortcuts import get_object_or_404
from django.utils.encoding import force_text
from django.utils.translation import ugettext as _f
from django.utils.translation import ugettext_lazy as _
from django.views.generic import DeleteView, DetailView, ListView, TemplateView
from django_filters.views import FilterView
from extra_views import InlineFormSet, NamedFormsetsMixin, UpdateWithInlinesView
from braces.views import JSONResponseMixin
from ..institutions.filters import InstitutionFilter
from ..institutions.models import Institution
from ..monitoring_pages.forms import MiniPageForm
from ..monitoring_pages.models import Page
from ..questions.forms import ChoiceForm, ConditionForm, QuestionForm, get_form_cls_for_question
from ..questions.models import Question, Sheet
from .forms import MonitoringForm
from .models import Monitoring, MonitoringInstitution

NO_QUESTION = _f("Questions are required. No questions provided")

UNKNOWN_TARGET = _f("Attempt to create reference to non-exists target.")

class CustomJSONResponseMixin(object):
    def error_list(self, form):
        return [(k, force_text(v[0])) for k, v in form.errors.items()]

    def error(self, **kwargs):
        kwargs['success'] = False
        # transaction.rollback() # TODO: Rollback on error
        return JsonResponse(kwargs, status=400)

class MonitoringListView(SelectRelatedMixin, ListView):
    model = Monitoring
    select_related = ['user']
    paginate_by = 25

class MonitoringDetailView(SelectRelatedMixin, DetailView):
    model = Monitoring
    select_related = ['user', ]

class MonitoringCreateView(LoginRequiredMixin, CustomJSONResponseMixin, PermissionRequiredMixin,
                           TemplateView):
    model = Monitoring
    permission_required = 'monitorings.add_monitoring'
    template_name = 'monitorings/monitoring_form_monitoring.html'

    def post(self, *args, **kwargs):  # TODO: Transactions in MonitoringCreateView
        data = json.loads(self.request.body.decode('utf-8'))

        # Validate
        # Validate monitoring
        form = MonitoringForm(data=data, user=self.request.user)
        if not form.is_valid():
            return self.error(errors=self.error_list(form))

        # Validate provided any questions
        questions = data.get('questions', None)
        if not questions:
            return self.error(error=NO_QUESTION)

        # Validate questions
        question_forms = [QuestionForm(data=x) for x in questions]
        if not all(x.is_valid() for x in question_forms):
            return self.error(errors=[self.error_list(x) for x in question_forms])

        # Validate condition by form
        condition_list = [condition
                          for question in questions if 'hideConditions' in question
                          for condition in question['hideConditions']]
        condition_forms = [ConditionForm(data=condition) for condition in condition_list]
        if not all(x.is_valid() for x in condition_forms):
            return self.error(errors=[self.error_list(x) for x in condition_forms])

        # Validate condition by target limit
        if not all(x.get('target', 0) < len(questions) and x.get('target', 0) >= 0
                   for x in condition_list):
            return self.error(error=UNKNOWN_TARGET)

        # Validate choices
        options_sets = [option for question in questions
                        if 'options' in question and question.get('type', None) == 'choice'
                        for option in question['options']]
        choices_forms = [ChoiceForm(data=options) for options in options_sets]
        if not all(x.is_valid() for x in choices_forms):
            return self.error(errors=[self.error_list(x) for x in choices_forms])

        # Save
        # Save monitoring
        monitoring = form.save()

        # Save question
        question_objs = []
        for i, x in enumerate(questions):
            related = {'monitoring': monitoring,
                       'created_by': self.request.user,
                       'order': i}
            question_objs.append(QuestionForm(data=x, related=related).save())

        # Save condition
        condition_objs = []
        for i, question in enumerate(questions):
            if not question.get('hideConditions', False):  # Skip if no conditions
                continue
            for condition in question['hideConditions']:
                related = {'related': question_objs[i],
                           'target': question_objs[condition.get('target', 0)],
                           'value': condition.get('value', '') or ''}
                condition_objs.append(ConditionForm(data=condition, related=related).save())

        # Save choices
        choice_objs = []
        for i, question in enumerate(questions):
            if 'options' not in question:  # Skip if no options
                continue
            if not question.get('type', None) != 'choice':  # Skip if bad type
                continue
            for j, option in enumerate(question['options']):
                related = {'question': question_objs[i], 'order': j}
                choice_objs.append(ChoiceForm(option, related=related).save())
        return JsonResponse({'success': True, 'url': monitoring.get_absolute_url()})

class PageInline(InlineFormSet):
    model = Page
    fields = ['title', 'ordering']
    form_class = MiniPageForm
    formset_class = BaseTableFormSet

    def get_factory_kwargs(self):  # Hack, see AndrewIngram/django-extra-views#121
        kwargs = super(PageInline, self).get_factory_kwargs()
        kwargs.pop('fields', None)
        return kwargs

class MonitoringUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UserFormKwargsMixin,
                           FormValidMessageMixin, NamedFormsetsMixin, UpdateWithInlinesView):
    inlines = [PageInline, ]
    inlines_names = ['pages', ]
    model = Monitoring
    form_class = MonitoringForm
    permission_required = 'monitorings.change_monitoring'

    def get_form_valid_message(self):
        return _("{0} updated!").format(self.object)

# TODO Tests for MonitoringAssignUpdateView
class MonitoringAssignUpdateView(LoginRequiredMixin, PermissionRequiredMixin, FilterView):
    model = Institution
    filterset_class = InstitutionFilter
    permission_required = 'monitorings.change_monitoring'
    template_name = 'monitorings/institution_assign.html'

    def get_queryset(self, *args, **kwargs):
        qs = super(MonitoringAssignUpdateView, self).get_queryset(*args, **kwargs)
        return qs.exclude(monitorings=self.monitoring.pk).select_related('region')

    @cached_property
    def monitoring(self):
        return get_object_or_404(Monitoring, slug=self.kwargs['slug'])

    def get_context_data(self, *args, **kwargs):
        context = super(MonitoringAssignUpdateView, self).get_context_data(*args, **kwargs)
        context['monitoring'] = self.monitoring
        return context

    def post(self, request, *args, **kwargs):
        ids = request.POST.getlist('to_assign')
        qs = Institution.objects.filter(pk__in=ids).exclude(monitorings=self.monitoring.pk)
        count = 0
        for institution in qs:
            self.monitoring.institutions.add(institution)
            count += 1
        msg = _("%(count)d institutions was assigned " +
                "to %(monitoring)s") % {'count': count,
                                        'monitoring': self.monitoring}
        messages.success(self.request, msg)
        return HttpResponseRedirect(request.get_full_path())

class MonitoringDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteMessageMixin,
                           DeleteView):
    model = Monitoring
    success_url = reverse_lazy('monitorings:list')
    permission_required = 'monitorings.delete_monitoring'

    def get_success_message(self):
        return _("{0} deleted!").format(self.object)

class MonitoringAutocomplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        qs = Monitoring.objects.all()

        if self.q:
            qs = qs.filter(name__istartswith=self.q)

        return qs

class MonitoringAnswerView(LoginRequiredMixin, CustomJSONResponseMixin, TemplateView):
    template_name = 'monitorings/monitoring_form_answer.html'

    def get_object(self):
        return get_object_or_404(MonitoringInstitution,
                                 monitoring__slug=self.kwargs['slug'],
                                 institution__slug=self.kwargs['institution_slug'])

    def get_context_data(self, *args, **kwargs):
        context = super(MonitoringAnswerView, self).get_context_data(*args, **kwargs)
        thr = self.get_object()
        context['monitoring'] = thr.monitoring
        context['institution'] = thr.institution
        return context

    @cached_property
    def answer_dict(self):
        return {answer.get('question_id'): answer for answer in self.data.get('result', {})}

    def get_answer_by_pk(self, pk):
        return self.answer_dict[pk]

    def _construct_answer_forms(self, questions, sheet):
        forms = []
        for question in questions:
            answer = self.get_answer_by_pk(question.pk)
            form_cls = get_form_cls_for_question(question)
            form = form_cls(data=answer, question=question, sheet=sheet)
            forms.append(form)
        return forms

    def post(self, *args, **kwargs):  # TODO: Transactions in MonitoringAnswerView
        self.data = json.loads(self.request.body.decode('utf-8'))

        thr = self.get_object()
        (monitoring, institution) = (thr.monitoring, thr.institution)

        questions = Question.objects.filter(monitoring=monitoring).all()
        sheet, created = Sheet.objects.get_or_create(monitoring=monitoring,
                                                     institution=institution,
                                                     user=self.request.user,
                                                     point=self.data.get('point', 0))

        # Validate one sheet per user
        if not created:
            return self.error(error="Unable to answer twice")

        # Validate all answers
        for question in questions:
            answer = self.get_answer_by_pk(question.pk)
            if not answer:
                return self.error(error="Missing answer for question #%d" % (question.pk))
        # Construct forms
        answer_forms = self._construct_answer_forms(questions, sheet)

        # Validate forms
        if not all(x.is_valid() for x in answer_forms):
            return self.error(errors=[self.error_list(x) for x in answer_forms])

        # Save answers
        [form.save() for form in answer_forms]

        return JsonResponse({'success': True,
                             'return_url': monitoring.get_institution_url(institution)})

class MonitoringApiDetailView(JSONResponseMixin, DetailView):
    model = Monitoring

    def get_options(self, question):
        for choice in question.choice_set.all():
            yield {'key': choice.key, 'value': choice.value}

    def get_conditions(self, question):
        for condition in question.condition_related.all():  # TODO: Prefetch condition.target
            data = {}
            data['type'] = condition.type
            data['target'] = condition.target.order  # It's ok, "order"
            data['value'] = condition.value
            yield data

    def get_questions(self):
        for question in self.object.question_set.all():
            data = {}
            data['id'] = question.id
            data['name'] = question.name
            data['description'] = question.description
            data['type'] = question.type
            data['hideConditions'] = list(self.get_conditions(question))
            if question.type == Question.TYPE.choice:
                data['options'] = list(self.get_options(question))
            yield data

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        context = {}
        context['name'] = self.object.name
        context['description'] = self.object.description
        context['questons'] = list(self.get_questions())
        return self.render_json_response(context)

    def get_queryset(self, *args, **kwargs):
        qs = super(MonitoringApiDetailView, self).get_queryset(*args, **kwargs)
        return qs.prefetch_related('question_set',
                                   'question_set__condition_related',
                                   'question_set__condition_related__target',
                                   'question_set__choice_set',
                                   )
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
'''
Use consul data as a Pillar source

:depends:  - python-consul

In order to use an consul server, a profile must be created in the master
configuration file:

.. code-block:: yaml

    my_consul_config:
      consul.host: 127.0.0.1
      consul.port: 8500

After the profile is created, configure the external pillar system to use it.
Optionally, a root may be specified.

.. code-block:: yaml

    ext_pillar:
      - consul: my_consul_config

    ext_pillar:
      - consul: my_consul_config root=/salt

Using these configuration profiles, multiple consul sources may also be used:

.. code-block:: yaml

    ext_pillar:
      - consul: my_consul_config
      - consul: my_other_consul_config

Either the ``minion_id``, or the ``role`` grain  may be used in the ``root``
path to expose minion-specific information stored in consul.

.. code-block:: yaml

    ext_pillar:
      - consul: my_consul_config root=/salt/%(minion_id)s
      - consul: my_consul_config root=/salt/%(role)s

Minion-specific values may override shared values when the minion-specific root
appears after the shared root:

.. code-block:: yaml

    ext_pillar:
      - consul: my_consul_config root=/salt-shared
      - consul: my_other_consul_config root=/salt-private/%(minion_id)s

If using the ``role`` grain in the consul key path, be sure to define it using
`/etc/salt/grains`, or similar:

.. code-block:: yaml

    role: my-minion-role

'''
from __future__ import absolute_import

# Import python libs
import logging

import re

from salt.exceptions import CommandExecutionError
from salt.utils.dictupdate import update as dict_merge

# Import third party libs
try:
    import consul
    HAS_CONSUL = True
except ImportError:
    HAS_CONSUL = False

__virtualname__ = 'consul'

# Set up logging
log = logging.getLogger(__name__)

def __virtual__():
    '''
    Only return if python-consul is installed
    '''
    return __virtualname__ if HAS_CONSUL else False

def ext_pillar(minion_id,
               pillar,  # pylint: disable=W0613
               conf):
    '''
    Check consul for all data
    '''
    comps = conf.split()

    profile = None
    if comps[0]:
        profile = comps[0]
    client = get_conn(__opts__, profile)

    path = ''
    if len(comps) > 1 and comps[1].startswith('root='):
        path = comps[1].replace('root=', '')

    role = __salt__['grains.get']('role')
    # put the minion's ID in the path if necessary
    path %= {
        'minion_id': minion_id,
        'role': role
    }

    try:
        pillar = fetch_tree(client, path)
    except KeyError:
        log.error('No such key in consul profile {0}: {1}'
                  .format(profile, path))
        pillar = {}

    return pillar

def consul_fetch(client, path):
    '''
    Query consul for all keys/values within base path
    '''
    return client.kv.get(path, recurse=True)

def fetch_tree(client, path):
    '''
    Grab data from consul, trim base path and remove any keys which
    are folders. Take the remaining data and send it to be formatted
    in such a way as to be used as pillar data.
    '''
    index, items = consul_fetch(client, path)
    ret = {}
    has_children = re.compile(r'/$')

    log.debug('Fetched items: %r', format(items))

    if items is None:
        return ret
    for item in reversed(items):
        key = re.sub(r'^' + path + '/?', '', item['Key'])
        if key != "":
            log.debug('key/path - {0}: {1}'.format(path, key))
            log.debug('has_children? %r', format(has_children.search(key)))
        if has_children.search(key) is None:
            ret = pillar_format(ret, key.split('/'), item['Value'])
            log.debug('Fetching subkeys for key: %r', format(item))

    return ret

def pillar_format(ret, keys, value):
    '''
    Perform data formatting to be used as pillar data and
    merge it with the current pillar data
    '''
    # skip it
    if value is None:
        return ret
    # if wrapped in quotes, drop them
    if value[0] == value[-1] == '"':
        pillar_value = value[1:-1]
    # if we have a list, reformat into a list
    if value[0] == '-' and value[1] == ' ':
        array_data = value.split('\n')
        # drop the '- ' on each element
        pillar_value = [elem[2:] for elem in array_data]
    # leave it be
    else:
        pillar_value = value
    keyvalue = keys.pop()
    pil = {keyvalue: pillar_value}
    keys.reverse()
    for k in keys:
        pil = {k: pil}

    return dict_merge(ret, pil)

def get_conn(opts, profile):

    '''
    Return a client object for accessing consul
    '''
    opts_pillar = opts.get('pillar', {})
    opts_master = opts_pillar.get('master', {})

    opts_merged = {}
    opts_merged.update(opts_master)
    opts_merged.update(opts_pillar)
    opts_merged.update(opts)

    if profile:
        conf = opts_merged.get(profile, {})
    else:
        conf = opts_merged

    consul_host = conf.get('consul.host', '127.0.0.1')
    consul_port = conf.get('consul.port', 8500)

    if HAS_CONSUL:
        return consul.Consul(host=consul_host, port=consul_port)
    else:
        raise CommandExecutionError(
            '(unable to import consul, '
            'module most likely not installed. Download python-consul '
            'module and be sure to import consul)'
        )
<commit_msg>strip whitespace from pillar keys looked up in consul<commit_after># -*- coding: utf-8 -*-
'''
Use consul data as a Pillar source

:depends:  - python-consul

In order to use an consul server, a profile must be created in the master
configuration file:

.. code-block:: yaml

    my_consul_config:
      consul.host: 127.0.0.1
      consul.port: 8500

After the profile is created, configure the external pillar system to use it.
Optionally, a root may be specified.

.. code-block:: yaml

    ext_pillar:
      - consul: my_consul_config

    ext_pillar:
      - consul: my_consul_config root=/salt

Using these configuration profiles, multiple consul sources may also be used:

.. code-block:: yaml

    ext_pillar:
      - consul: my_consul_config
      - consul: my_other_consul_config

Either the ``minion_id``, or the ``role`` grain  may be used in the ``root``
path to expose minion-specific information stored in consul.

.. code-block:: yaml

    ext_pillar:
      - consul: my_consul_config root=/salt/%(minion_id)s
      - consul: my_consul_config root=/salt/%(role)s

Minion-specific values may override shared values when the minion-specific root
appears after the shared root:

.. code-block:: yaml

    ext_pillar:
      - consul: my_consul_config root=/salt-shared
      - consul: my_other_consul_config root=/salt-private/%(minion_id)s

If using the ``role`` grain in the consul key path, be sure to define it using
`/etc/salt/grains`, or similar:

.. code-block:: yaml

    role: my-minion-role

'''
from __future__ import absolute_import

# Import python libs
import logging

import re

from salt.exceptions import CommandExecutionError
from salt.utils.dictupdate import update as dict_merge

# Import third party libs
try:
    import consul
    HAS_CONSUL = True
except ImportError:
    HAS_CONSUL = False

__virtualname__ = 'consul'

# Set up logging
log = logging.getLogger(__name__)

def __virtual__():
    '''
    Only return if python-consul is installed
    '''
    return __virtualname__ if HAS_CONSUL else False

def ext_pillar(minion_id,
               pillar,  # pylint: disable=W0613
               conf):
    '''
    Check consul for all data
    '''
    comps = conf.split()

    profile = None
    if comps[0]:
        profile = comps[0]
    client = get_conn(__opts__, profile)

    path = ''
    if len(comps) > 1 and comps[1].startswith('root='):
        path = comps[1].replace('root=', '')

    role = __salt__['grains.get']('role')
    # put the minion's ID in the path if necessary
    path %= {
        'minion_id': minion_id,
        'role': role
    }

    try:
        pillar = fetch_tree(client, path)
    except KeyError:
        log.error('No such key in consul profile {0}: {1}'
                  .format(profile, path))
        pillar = {}

    return pillar

def consul_fetch(client, path):
    '''
    Query consul for all keys/values within base path
    '''
    return client.kv.get(path, recurse=True)

def fetch_tree(client, path):
    '''
    Grab data from consul, trim base path and remove any keys which
    are folders. Take the remaining data and send it to be formatted
    in such a way as to be used as pillar data.
    '''
    index, items = consul_fetch(client, path)
    ret = {}
    has_children = re.compile(r'/$')

    log.debug('Fetched items: %r', format(items))

    if items is None:
        return ret
    for item in reversed(items):
        key = re.sub(r'^' + path + '/?', '', item['Key'])
        if key != "":
            log.debug('key/path - {0}: {1}'.format(path, key))
            log.debug('has_children? %r', format(has_children.search(key)))
        if has_children.search(key) is None:
            ret = pillar_format(ret, key.split('/'), item['Value'])
            log.debug('Fetching subkeys for key: %r', format(item))

    return ret

def pillar_format(ret, keys, value):
    '''
    Perform data formatting to be used as pillar data and
    merge it with the current pillar data
    '''
    # drop leading/trailing whitespace, if any
    value = value.strip(' \t\n\r')
    # skip it
    if value is None:
        return ret
    # if wrapped in quotes, drop them
    if value[0] == value[-1] == '"':
        pillar_value = value[1:-1]
    # if we have a list, reformat into a list
    if value[0] == '-' and value[1] == ' ':
        array_data = value.split('\n')
        # drop the '- ' on each element
        pillar_value = [elem[2:] for elem in array_data]
    # leave it be
    else:
        pillar_value = value
    keyvalue = keys.pop()
    pil = {keyvalue: pillar_value}
    keys.reverse()
    for k in keys:
        pil = {k: pil}

    return dict_merge(ret, pil)

def get_conn(opts, profile):

    '''
    Return a client object for accessing consul
    '''
    opts_pillar = opts.get('pillar', {})
    opts_master = opts_pillar.get('master', {})

    opts_merged = {}
    opts_merged.update(opts_master)
    opts_merged.update(opts_pillar)
    opts_merged.update(opts)

    if profile:
        conf = opts_merged.get(profile, {})
    else:
        conf = opts_merged

    consul_host = conf.get('consul.host', '127.0.0.1')
    consul_port = conf.get('consul.port', 8500)

    if HAS_CONSUL:
        return consul.Consul(host=consul_host, port=consul_port)
    else:
        raise CommandExecutionError(
            '(unable to import consul, '
            'module most likely not installed. Download python-consul '
            'module and be sure to import consul)'
        )
<|endoftext|>


<commit_before>"""
.. todo::

    WRITEME
"""
import os, cPickle, logging
_logger = logging.getLogger(__name__)

import numpy as np
N = np
from pylearn2.datasets import dense_design_matrix
from pylearn2.expr.preprocessing import global_contrast_normalize

class CIFAR10(dense_design_matrix.DenseDesignMatrix):
    """
    .. todo::

        WRITEME

    Parameters
    ----------
    which_set : str
        One of 'train', 'test'
    center : WRITEME
    rescale : WRITEME
    gcn : float, optional
        Multiplicative constant to use for global contrast normalization.
        No global contrast normalization is applied, if None
    one_hot : WRITEME
    start : WRITEME
    stop : WRITEME
    axes : WRITEME
    toronto_prepro : WRITEME
    preprocessor : WRITEME
    """

    def __init__(self, which_set, center = False, rescale = False, gcn = None,
            one_hot = False, start = None, stop = None, axes=('b', 0, 1, 'c'),
            toronto_prepro = False, preprocessor = None):
        # note: there is no such thing as the cifar10 validation set;
        # pylearn1 defined one but really it should be user-configurable
        # (as it is here)

        self.axes = axes

        # we define here:
        dtype  = 'uint8'
        ntrain = 50000
        nvalid = 0  # artefact, we won't use it
        ntest  = 10000

        # we also expose the following details:
        self.img_shape = (3,32,32)
        self.img_size = N.prod(self.img_shape)
        self.n_classes = 10
        self.label_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',
                            'dog', 'frog','horse','ship','truck']

        # prepare loading
        fnames = ['data_batch_%i' % i for i in range(1,6)]
        lenx = N.ceil((ntrain + nvalid) / 10000.)*10000
        x = N.zeros((lenx,self.img_size), dtype=dtype)
        y = N.zeros(lenx, dtype=dtype)

        # load train data
        nloaded = 0
        for i, fname in enumerate(fnames):
            data = CIFAR10._unpickle(fname)
            x[i*10000:(i+1)*10000, :] = data['data']
            y[i*10000:(i+1)*10000] = data['labels']
            nloaded += 10000
            if nloaded >= ntrain + nvalid + ntest: break;

        # load test data
        data = CIFAR10._unpickle('test_batch')

        # process this data
        Xs = {
                'train' : x[0:ntrain],
                'test'  : data['data'][0:ntest]
            }

        Ys = {
                'train' : y[0:ntrain],
                'test'  : data['labels'][0:ntest]
            }

        X = N.cast['float32'](Xs[which_set])
        y = Ys[which_set]

        if isinstance(y,list):
            y = np.asarray(y)

        if which_set == 'test':
            assert y.shape[0] == 10000

        self.one_hot = one_hot
        if one_hot:
            one_hot = np.zeros((y.shape[0],10),dtype='float32')
            for i in xrange(y.shape[0]):
                one_hot[i,y[i]] = 1.
            y = one_hot

        if center:
            X -= 127.5
        self.center = center

        if rescale:
            X /= 127.5
        self.rescale = rescale

        if toronto_prepro:
            assert not center
            assert not gcn
            X = X / 255.
            if which_set == 'test':
                other = CIFAR10(which_set='train')
                oX = other.X
                oX /= 255.
                X = X - oX.mean(axis=0)
            else:
                X = X - X.mean(axis=0)
        self.toronto_prepro = toronto_prepro

        self.gcn = gcn
        if gcn is not None:
            gcn = float(gcn)
            X = global_contrast_normalize(X, scale=gcn)

        if start is not None:
            # This needs to come after the prepro so that it doesn't change the pixel
            # means computed above for toronto_prepro
            assert start >= 0
            assert stop > start
            assert stop <= X.shape[0]
            X = X[start:stop, :]
            y = y[start:stop]
            assert X.shape[0] == y.shape[0]

        if which_set == 'test':
            assert X.shape[0] == 10000

        view_converter = dense_design_matrix.DefaultViewConverter((32,32,3), axes)

        super(CIFAR10, self).__init__(X=X, y=y, view_converter=view_converter)

        assert not np.any(np.isnan(self.X))

        if preprocessor:
            preprocessor.apply(self)

    def adjust_for_viewer(self, X):
        """
        .. todo::

            WRITEME
        """
        #assumes no preprocessing. need to make preprocessors mark the new ranges
        rval = X.copy()

        #patch old pkl files
        if not hasattr(self,'center'):
            self.center = False
        if not hasattr(self,'rescale'):
            self.rescale = False
        if not hasattr(self,'gcn'):
            self.gcn = False

        if self.gcn is not None:
            rval = X.copy()
            for i in xrange(rval.shape[0]):
                rval[i,:] /= np.abs(rval[i,:]).max()
            return rval

        if not self.center:
            rval -= 127.5

        if not self.rescale:
            rval /= 127.5

        rval = np.clip(rval,-1.,1.)

        return rval

    def adjust_to_be_viewed_with(self, X, orig, per_example = False):
        """
        .. todo::

            WRITEME
        """
        # if the scale is set based on the data, display X oring the scale determined
        # by orig
        # assumes no preprocessing. need to make preprocessors mark the new ranges
        rval = X.copy()

        #patch old pkl files
        if not hasattr(self,'center'):
            self.center = False
        if not hasattr(self,'rescale'):
            self.rescale = False
        if not hasattr(self,'gcn'):
            self.gcn = False

        if self.gcn is not None:
            rval = X.copy()
            if per_example:
                for i in xrange(rval.shape[0]):
                    rval[i,:] /= np.abs(orig[i,:]).max()
            else:
                rval /= np.abs(orig).max()
            rval = np.clip(rval, -1., 1.)
            return rval

        if not self.center:
            rval -= 127.5

        if not self.rescale:
            rval /= 127.5

        rval = np.clip(rval,-1.,1.)

        return rval

    def get_test_set(self):
        """
        .. todo::

            WRITEME
        """
        return CIFAR10(which_set='test', center=self.center, rescale=self.rescale, gcn=self.gcn,
                one_hot=self.one_hot, toronto_prepro=self.toronto_prepro, axes=self.axes)

    @classmethod
    def _unpickle(cls, file):
        """
        .. todo::

            What is this? why not just use serial.load like the CIFAR-100
            class? Whoever wrote it shows up as "unknown" in git blame.
        """
        from pylearn2.utils import string_utils
        fname = os.path.join(
                string_utils.preprocess('${PYLEARN2_DATA_PATH}'),
                'cifar10',
                'cifar-10-batches-py',
                file)
        if not os.path.exists(fname):
            raise IOError(fname+" was not found. You probably need to download "
                    "the CIFAR-10 dataset by using the download script in pylearn2/scripts/datasets/download_cifar10.sh "
                    "or manually from http://www.cs.utoronto.ca/~kriz/cifar.html")
        _logger.info('loading file %s' % fname)
        fo = open(fname, 'rb')
        dict = cPickle.load(fo)
        fo.close()
        return dict
<commit_msg>cache the cifar 10 datasets<commit_after>"""
.. todo::

    WRITEME
"""
import os, cPickle, logging
_logger = logging.getLogger(__name__)

import numpy as np
N = np
from pylearn2.datasets import cache, dense_design_matrix
from pylearn2.expr.preprocessing import global_contrast_normalize

class CIFAR10(dense_design_matrix.DenseDesignMatrix):
    """
    .. todo::

        WRITEME

    Parameters
    ----------
    which_set : str
        One of 'train', 'test'
    center : WRITEME
    rescale : WRITEME
    gcn : float, optional
        Multiplicative constant to use for global contrast normalization.
        No global contrast normalization is applied, if None
    one_hot : WRITEME
    start : WRITEME
    stop : WRITEME
    axes : WRITEME
    toronto_prepro : WRITEME
    preprocessor : WRITEME
    """

    def __init__(self, which_set, center = False, rescale = False, gcn = None,
            one_hot = False, start = None, stop = None, axes=('b', 0, 1, 'c'),
            toronto_prepro = False, preprocessor = None):
        # note: there is no such thing as the cifar10 validation set;
        # pylearn1 defined one but really it should be user-configurable
        # (as it is here)

        self.axes = axes

        # we define here:
        dtype  = 'uint8'
        ntrain = 50000
        nvalid = 0  # artefact, we won't use it
        ntest  = 10000

        # we also expose the following details:
        self.img_shape = (3,32,32)
        self.img_size = N.prod(self.img_shape)
        self.n_classes = 10
        self.label_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',
                            'dog', 'frog','horse','ship','truck']

        # prepare loading
        fnames = ['data_batch_%i' % i for i in range(1,6)]
        lenx = N.ceil((ntrain + nvalid) / 10000.)*10000
        x = N.zeros((lenx,self.img_size), dtype=dtype)
        y = N.zeros(lenx, dtype=dtype)

        # load train data
        nloaded = 0
        for i, fname in enumerate(fnames):
            data = CIFAR10._unpickle(fname)
            x[i*10000:(i+1)*10000, :] = data['data']
            y[i*10000:(i+1)*10000] = data['labels']
            nloaded += 10000
            if nloaded >= ntrain + nvalid + ntest: break;

        # load test data
        data = CIFAR10._unpickle('test_batch')

        # process this data
        Xs = {
                'train' : x[0:ntrain],
                'test'  : data['data'][0:ntest]
            }

        Ys = {
                'train' : y[0:ntrain],
                'test'  : data['labels'][0:ntest]
            }

        X = N.cast['float32'](Xs[which_set])
        y = Ys[which_set]

        if isinstance(y,list):
            y = np.asarray(y)

        if which_set == 'test':
            assert y.shape[0] == 10000

        self.one_hot = one_hot
        if one_hot:
            one_hot = np.zeros((y.shape[0],10),dtype='float32')
            for i in xrange(y.shape[0]):
                one_hot[i,y[i]] = 1.
            y = one_hot

        if center:
            X -= 127.5
        self.center = center

        if rescale:
            X /= 127.5
        self.rescale = rescale

        if toronto_prepro:
            assert not center
            assert not gcn
            X = X / 255.
            if which_set == 'test':
                other = CIFAR10(which_set='train')
                oX = other.X
                oX /= 255.
                X = X - oX.mean(axis=0)
            else:
                X = X - X.mean(axis=0)
        self.toronto_prepro = toronto_prepro

        self.gcn = gcn
        if gcn is not None:
            gcn = float(gcn)
            X = global_contrast_normalize(X, scale=gcn)

        if start is not None:
            # This needs to come after the prepro so that it doesn't change the pixel
            # means computed above for toronto_prepro
            assert start >= 0
            assert stop > start
            assert stop <= X.shape[0]
            X = X[start:stop, :]
            y = y[start:stop]
            assert X.shape[0] == y.shape[0]

        if which_set == 'test':
            assert X.shape[0] == 10000

        view_converter = dense_design_matrix.DefaultViewConverter((32,32,3), axes)

        super(CIFAR10, self).__init__(X=X, y=y, view_converter=view_converter)

        assert not np.any(np.isnan(self.X))

        if preprocessor:
            preprocessor.apply(self)

    def adjust_for_viewer(self, X):
        """
        .. todo::

            WRITEME
        """
        #assumes no preprocessing. need to make preprocessors mark the new ranges
        rval = X.copy()

        #patch old pkl files
        if not hasattr(self,'center'):
            self.center = False
        if not hasattr(self,'rescale'):
            self.rescale = False
        if not hasattr(self,'gcn'):
            self.gcn = False

        if self.gcn is not None:
            rval = X.copy()
            for i in xrange(rval.shape[0]):
                rval[i,:] /= np.abs(rval[i,:]).max()
            return rval

        if not self.center:
            rval -= 127.5

        if not self.rescale:
            rval /= 127.5

        rval = np.clip(rval,-1.,1.)

        return rval

    def adjust_to_be_viewed_with(self, X, orig, per_example = False):
        """
        .. todo::

            WRITEME
        """
        # if the scale is set based on the data, display X oring the scale determined
        # by orig
        # assumes no preprocessing. need to make preprocessors mark the new ranges
        rval = X.copy()

        #patch old pkl files
        if not hasattr(self,'center'):
            self.center = False
        if not hasattr(self,'rescale'):
            self.rescale = False
        if not hasattr(self,'gcn'):
            self.gcn = False

        if self.gcn is not None:
            rval = X.copy()
            if per_example:
                for i in xrange(rval.shape[0]):
                    rval[i,:] /= np.abs(orig[i,:]).max()
            else:
                rval /= np.abs(orig).max()
            rval = np.clip(rval, -1., 1.)
            return rval

        if not self.center:
            rval -= 127.5

        if not self.rescale:
            rval /= 127.5

        rval = np.clip(rval,-1.,1.)

        return rval

    def get_test_set(self):
        """
        .. todo::

            WRITEME
        """
        return CIFAR10(which_set='test', center=self.center, rescale=self.rescale, gcn=self.gcn,
                one_hot=self.one_hot, toronto_prepro=self.toronto_prepro, axes=self.axes)

    @classmethod
    def _unpickle(cls, file):
        """
        .. todo::

            What is this? why not just use serial.load like the CIFAR-100
            class? Whoever wrote it shows up as "unknown" in git blame.
        """
        from pylearn2.utils import string_utils
        fname = os.path.join(
                string_utils.preprocess('${PYLEARN2_DATA_PATH}'),
                'cifar10',
                'cifar-10-batches-py',
                file)
        if not os.path.exists(fname):
            raise IOError(fname+" was not found. You probably need to download "
                    "the CIFAR-10 dataset by using the download script in pylearn2/scripts/datasets/download_cifar10.sh "
                    "or manually from http://www.cs.utoronto.ca/~kriz/cifar.html")
        fname = cache.datasetCache.cache_file(fname)

        _logger.info('loading file %s' % fname)
        fo = open(fname, 'rb')
        dict = cPickle.load(fo)
        fo.close()
        return dict
<|endoftext|>


<commit_before>from sample_project.blog.models import Image
from sample_project.blog.forms import AjaxImageForm

from file_picker.views import FilePicker

from sorl.thumbnail.main import DjangoThumbnail

class ImagePicker(FilePicker):
    model = Image
    form = AjaxImageForm

    def get_queryset(self,search):
        return Image.objects.filter(name__icontains=search)

    def append(self, obj):
        thumb = DjangoThumbnail(obj.file, (150, 150))
        return {
            'name': unicode(obj), 'url': obj.file.url,
            'thumb': {
                'url': thumb.absolute_url,
                'width': thumb.width(),
                'height': thumb.height(),
            },
            'insert': '' % obj.file.url
        }

file_picker = ImagePicker()
<commit_msg>moved blog over to gerenal<commit_after>from sample_project.blog.models import Image
from sample_project.blog.forms import AjaxImageForm

from file_picker.views import FilePicker

from sorl.thumbnail.main import DjangoThumbnail

class ImagePicker(FilePicker):
    model = Image

    def get_queryset(self,search):
        return Image.objects.filter(name__icontains=search)

    def append(self, obj):
        thumb = DjangoThumbnail(obj.file, (150, 150))
        return {
            'name': unicode(obj), 'url': obj.file.url,
            'thumb': {
                'url': thumb.absolute_url,
                'width': thumb.width(),
                'height': thumb.height(),
            },
            'insert': '' % obj.file.url
        }

file_picker = ImagePicker()
<|endoftext|>


<commit_before>from numpy import pi
from numpy import array
from numpy import linspace
from numpy import arange
from numpy import zeros
from numpy import empty
from numpy import column_stack
from numpy import array
from numpy.random import random
from numpy.random import randint
from numpy.random import uniform
from numpy import cos
from numpy import sin
from time import time
from math import radians

import cairocffi as cairo
from sand import Sand
from ..lib.sand_spline import SandSpline
from ..lib.helpers import hex_to_rgb_decimal, SimpleLinearScale

WIDTH = 900
HEIGHT = 900

cgrid = zeros(WIDTH * HEIGHT)

class Crack:

    def __init__(self, sand):
        self.x = 0  # X position on grid
        self.y = 0  # Y position on grid
        self.t = 0  # Direction of travel
        self.w = WIDTH
        self.h = WIDTH
        self.xs = SimpleLinearScale(domain=array([0, self.w]), range=array([0, 1]))
        self.ys = SimpleLinearScale(domain=array([0, self.h]), range=array([0, 1]))

        self.sand = sand
        self.find_start()

    def find_start(self):
        px = 0
        py = 0
        timeout = 0
        found = False

        while not found:
            px = randint(self.w)
            py = randint(self.h)
            # print(cgrid[py * self.w + px], cgrid[py * self.w + px] < 10000, timeout)
            if(cgrid[py * self.w + px] < 10000):
                found = True

        if found:
            a = cgrid[py * self.w + px]
            if randint(100) < 50:
                a -= 90 + int(uniform(-2, 2.1))
            else:
                a += 90 + int(uniform(-2, 2.1))
            self.start_crack(px, py, a)

    def start_crack(self, x, y, t):
        self.t = t
        self.x += 0.61 * cos(t * pi / 180)
        self.y += 0.61 * sin(t * pi / 180)

    def move(self):
        px = self.x
        py = self.y
        self.x += 0.42 * cos(self.t * pi / 180)
        self.y += 0.42 * sin(self.t * pi / 180)

        z = 0.33
        cx = int(self.x + uniform(-z, z))
        cy = int(self.y + uniform(-z, z))

        # dots = random((1, 2))
        dots = array([[
            self.xs(self.x),
            self.ys(self.y)
        ]])
        self.sand.paint_dots(dots)

def generate(args):

    width = args.width
    height = args.height

    xscale = SimpleLinearScale(domain=array([0, width]), range=array([0, 1]))
    yscale = SimpleLinearScale(domain=array([0, height]), range=array([0, 1]))

    # Margin as a pixel value of total size.  Convert that margin to a number between 0..1
    # representing the percentage of total pixel size
    margin = args.margin
    margin_x = xscale(margin)
    margin_y = yscale(margin)

    # The current number of cracks
    num = 0
    max_cracks = 200
    cracks = empty(max_cracks, dtype=Crack)

    # Output PNG gamma
    gamma = 1.5

    # What frame to write out
    save_frame = args.save_every

    # The number of points along the spline.  More points means a denser-looking spline.
    stroke_limit = 100

    # Convert colors to RGB decimal
    sand_color = hex_to_rgb_decimal(args.color)
    bg_color = hex_to_rgb_decimal(args.bg_color)

    # Set alpha
    sand_color.append(0.1)
    bg_color.append(1)

    sand = Sand(width, height)
    sand.set_rgba(sand_color)
    sand.set_bg(bg_color)

    splines = []

    # TODO: move to initialization of cgrid
    for y in range(HEIGHT):
        for x in range(WIDTH):
            cgrid[y * WIDTH + x] = 10001

    for k in range(16):
        i = randint(WIDTH * HEIGHT - 1)
        cgrid[i] = randint(360)

    for k in range(3):
        cracks[num] = Crack(sand=sand)
        num += 1

    # c = Crack()
    i = 0
    try:
        while True:
            for n in range(num):
                cracks[n].move()
            # for crack in cracks:
            #     crack.move()
            #
            if i % 100000 == 0:
                sand.write_to_png('tmp/c-{}.png'.format(i))
            i += 1
            # if i % 50000 == 0:
            #     c.sand.write_to_png('tmp/c-{}.png'.format(i))
            # c.move()
            # i += 1
    except KeyboardInterrupt:
        print('Finished!')
<commit_msg>:skull: some dead code<commit_after>from numpy import pi
from numpy import array
from numpy import linspace
from numpy import arange
from numpy import zeros
from numpy import empty
from numpy import column_stack
from numpy import array
from numpy.random import random
from numpy.random import randint
from numpy.random import uniform
from numpy import cos
from numpy import sin
from time import time
from math import radians

import cairocffi as cairo
from sand import Sand
from ..lib.sand_spline import SandSpline
from ..lib.helpers import hex_to_rgb_decimal, SimpleLinearScale

WIDTH = 900
HEIGHT = 900

cgrid = zeros(WIDTH * HEIGHT)

class Crack:

    def __init__(self, sand):
        self.x = 0  # X position on grid
        self.y = 0  # Y position on grid
        self.t = 0  # Direction of travel
        self.w = WIDTH
        self.h = WIDTH
        self.xs = SimpleLinearScale(domain=array([0, self.w]), range=array([0, 1]))
        self.ys = SimpleLinearScale(domain=array([0, self.h]), range=array([0, 1]))

        self.sand = sand
        self.find_start()

    def find_start(self):
        px = 0
        py = 0
        timeout = 0
        found = False

        while not found:
            px = randint(self.w)
            py = randint(self.h)
            # print(cgrid[py * self.w + px], cgrid[py * self.w + px] < 10000, timeout)
            if(cgrid[py * self.w + px] < 10000):
                found = True

        if found:
            a = cgrid[py * self.w + px]
            if randint(100) < 50:
                a -= 90 + int(uniform(-2, 2.1))
            else:
                a += 90 + int(uniform(-2, 2.1))
            self.start_crack(px, py, a)

    def start_crack(self, x, y, t):
        self.t = t
        self.x += 0.61 * cos(t * pi / 180)
        self.y += 0.61 * sin(t * pi / 180)

    def move(self):
        px = self.x
        py = self.y
        self.x += 0.42 * cos(self.t * pi / 180)
        self.y += 0.42 * sin(self.t * pi / 180)

        z = 0.33
        cx = int(self.x + uniform(-z, z))
        cy = int(self.y + uniform(-z, z))

        # dots = random((1, 2))
        dots = array([[
            self.xs(self.x),
            self.ys(self.y)
        ]])
        self.sand.paint_dots(dots)

def generate(args):

    width = args.width
    height = args.height

    xscale = SimpleLinearScale(domain=array([0, width]), range=array([0, 1]))
    yscale = SimpleLinearScale(domain=array([0, height]), range=array([0, 1]))

    # Margin as a pixel value of total size.  Convert that margin to a number between 0..1
    # representing the percentage of total pixel size
    margin = args.margin
    margin_x = xscale(margin)
    margin_y = yscale(margin)

    # The current number of cracks
    num = 0
    max_cracks = 200
    cracks = empty(max_cracks, dtype=Crack)

    # Output PNG gamma
    gamma = 1.5

    # What frame to write out
    save_frame = args.save_every

    # The number of points along the spline.  More points means a denser-looking spline.
    stroke_limit = 100

    # Convert colors to RGB decimal
    sand_color = hex_to_rgb_decimal(args.color)
    bg_color = hex_to_rgb_decimal(args.bg_color)

    # Set alpha
    sand_color.append(0.1)
    bg_color.append(1)

    sand = Sand(width, height)
    sand.set_rgba(sand_color)
    sand.set_bg(bg_color)

    splines = []

    # TODO: move to initialization of cgrid
    for y in range(HEIGHT):
        for x in range(WIDTH):
            cgrid[y * WIDTH + x] = 10001

    for k in range(16):
        i = randint(WIDTH * HEIGHT - 1)
        cgrid[i] = randint(360)

    for k in range(3):
        cracks[num] = Crack(sand=sand)
        num += 1

    i = 0
    try:
        while True:
            for n in range(num):
                cracks[n].move()

            if i % 100000 == 0:
                sand.write_to_png('tmp/c-{}.png'.format(i))
            i += 1

    except KeyboardInterrupt:
        print('Finished!')
<|endoftext|>


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

import os
import sys

try:
    from gluon import current
except ImportError:
    print >> sys.stderr, """
The installed version of Web2py is too old -- it does not define current.
Please upgrade Web2py to a more recent version.
"""

# Version of 000_config.py
# Increment this if the user should update their running instance
VERSION = 1

#def update_check(environment, template="default"):
def update_check():
    """
        Check whether the dependencies are sufficient to run Eden

        @ToDo: Integrate into WebSetup:
               http://eden.sahanafoundation.org/wiki/DeveloperGuidelines/WebSetup
    """

    # Get Web2py environment into our globals.
    #globals().update(**environment)
    request = current.request

    # Fatal errors
    errors = []
    # Non-fatal warnings
    warnings = []

    # -------------------------------------------------------------------------
    # Check Python libraries
    try:
        import dateutil
    except(ImportError):
        errors.append("S3 unresolved dependency: dateutil required for Sahana to run")
    try:
        import lxml
    except(ImportError):
        errors.append("S3XML unresolved dependency: lxml required for Sahana to run")
    try:
        import shapely
    except(ImportError):
        warnings.append("S3GIS unresolved dependency: shapely required for GIS support")
    try:
        import xlrd
    except(ImportError):
        warnings.append("S3XLS unresolved dependency: xlrd required for XLS import")
    try:
        import xlwt
    except(ImportError):
        warnings.append("S3XLS unresolved dependency: xlwt required for XLS export")
    try:
        from PIL import Image
    except(ImportError):
        try:
            import Image
        except(ImportError):
            warnings.append("S3PDF unresolved dependency: Python Imaging required for PDF export")
    try:
        import reportlab
    except(ImportError):
        warnings.append("S3PDF unresolved dependency: reportlab required for PDF export")
    try:
        import matplotlib
    except(ImportError):
        warnings.append("S3Chart unresolved dependency: matplotlib required for charting")
    try:
        import numpy
    except(ImportError):
        warnings.append("S3Report unresolved dependency: numpy required for pivot table reports")
    try:
        import tweepy
    except(ImportError):
        warnings.append("S3Msg unresolved dependency: tweepy required for non-Tropo Twitter support")
    try:
        import PyRTF
    except(ImportError):
        warnings.append("Survey unresolved dependency: PyRTF required if you want to export assessment templates as a Word document")

    # -------------------------------------------------------------------------
    # Check Web2Py version
    #
    # Currently, the minimum usable Web2py is determined by whether the
    # Scheduler is available
    web2py_minimum_version = "Version 1.99.3 (2011-10-27 13:23:13)"
    web2py_version_ok = True
    try:
        from gluon.fileutils import parse_version
    except ImportError:
        web2py_version_ok = False
    if web2py_version_ok:
        web2py_minimum_datetime = parse_version(web2py_minimum_version)[3]
        web2py_installed_datetime = request.global_settings.web2py_version[3]
        web2py_version_ok = web2py_installed_datetime >= web2py_minimum_datetime
    if not web2py_version_ok:
        warnings.append(
            "The installed version of Web2py is too old to provide the Scheduler,"
            "\nso scheduled tasks will not be available. If you need scheduled tasks,"
            "\nplease upgrade Web2py to at least version: %s" % \
            web2py_minimum_version)

    # -------------------------------------------------------------------------
    # Create required directories if needed
    app_path = request.folder
    databases_dir = os.path.join(app_path, "databases")
    try:
        os.stat(databases_dir)
    except OSError:
        # not found, create it
        os.mkdir(databases_dir)

    # -------------------------------------------------------------------------
    # Copy in Templates
    # - 000_config.py (machine-specific settings)
    # - rest are run in-place
    #
    template_folder = os.path.join(app_path, "private", "templates")

    template_files = {
        # source : destination
        "000_config.py" : os.path.join("models", "000_config.py"),
    }

    copied_from_template = []

    for t in template_files:
        src_path = os.path.join(template_folder, t)
        dst_path = os.path.join(app_path, template_files[t])
        try:
            os.stat(dst_path)
        except OSError:
            # Not found, copy from template
            if t == "000_config.py":
                input = open(src_path)
                output = open(dst_path, "w")
                for line in input:
                    if "akeytochange" in line:
                        # Generate a random hmac_key to secure the passwords in case
                        # the database is compromised
                        import uuid
                        hmac_key = uuid.uuid4()
                        line = 'deployment_settings.auth.hmac_key = "%s"' % hmac_key
                    output.write(line)
                output.close()
                input.close()
            else:
                import shutil
                shutil.copy(src_path, dst_path)
            copied_from_template.append(template_files[t])
        else:
            # Found the file in the destination
            # Check if it has been edited
            import re
            edited_pattern = r"FINISHED_EDITING_\w*\s*=\s*(True|False)"
            edited_matcher = re.compile(edited_pattern).match
            has_edited = False
            with open(dst_path) as f:
                for line in f:
                    edited_result = edited_matcher(line)
                    if edited_result:
                        has_edited = True
                        edited = edited_result.group(1)
                        break
            if has_edited and (edited != "True"):
                errors.append("Please edit %s before starting the system." % t)
            # Check if it's up to date (i.e. a critical update requirement)
            version_pattern = r"VERSION =\s*([0-9]+)"
            version_matcher = re.compile(version_pattern).match
            has_version = False
            with open(dst_path) as f:
                for line in f:
                    version_result = version_matcher(line)
                    if version_result:
                        has_version = True
                        version = version_result.group(1)
                        break
            if not has_version:
                error = "Your %s is using settings from the old templates system. Please switch to the new templates system: http://eden.sahanafoundation.org/wiki/DeveloperGuidelines/Templates" % t
                errors.append(error)
            elif int(version) != VERSION:
                error = "Your %s is using settings from template version %s. Please update with new settings from template version %s before starting the system." % \
                                (t, version, VERSION)
                errors.append(error)

    if copied_from_template:
        errors.append(
            "The following files were copied from templates and should be edited: %s" %
            ", ".join(copied_from_template))

    return {"error_messages": errors, "warning_messages": warnings}

# END =========================================================================
<commit_msg>Web2py parse_version return value changed.<commit_after># -*- coding: utf-8 -*-

import os
import sys

try:
    from gluon import current
except ImportError:
    print >> sys.stderr, """
The installed version of Web2py is too old -- it does not define current.
Please upgrade Web2py to a more recent version.
"""

# Version of 000_config.py
# Increment this if the user should update their running instance
VERSION = 1

#def update_check(environment, template="default"):
def update_check():
    """
        Check whether the dependencies are sufficient to run Eden

        @ToDo: Integrate into WebSetup:
               http://eden.sahanafoundation.org/wiki/DeveloperGuidelines/WebSetup
    """

    # Get Web2py environment into our globals.
    #globals().update(**environment)
    request = current.request

    # Fatal errors
    errors = []
    # Non-fatal warnings
    warnings = []

    # -------------------------------------------------------------------------
    # Check Python libraries
    try:
        import dateutil
    except(ImportError):
        errors.append("S3 unresolved dependency: dateutil required for Sahana to run")
    try:
        import lxml
    except(ImportError):
        errors.append("S3XML unresolved dependency: lxml required for Sahana to run")
    try:
        import shapely
    except(ImportError):
        warnings.append("S3GIS unresolved dependency: shapely required for GIS support")
    try:
        import xlrd
    except(ImportError):
        warnings.append("S3XLS unresolved dependency: xlrd required for XLS import")
    try:
        import xlwt
    except(ImportError):
        warnings.append("S3XLS unresolved dependency: xlwt required for XLS export")
    try:
        from PIL import Image
    except(ImportError):
        try:
            import Image
        except(ImportError):
            warnings.append("S3PDF unresolved dependency: Python Imaging required for PDF export")
    try:
        import reportlab
    except(ImportError):
        warnings.append("S3PDF unresolved dependency: reportlab required for PDF export")
    try:
        import matplotlib
    except(ImportError):
        warnings.append("S3Chart unresolved dependency: matplotlib required for charting")
    try:
        import numpy
    except(ImportError):
        warnings.append("S3Report unresolved dependency: numpy required for pivot table reports")
    try:
        import tweepy
    except(ImportError):
        warnings.append("S3Msg unresolved dependency: tweepy required for non-Tropo Twitter support")
    try:
        import PyRTF
    except(ImportError):
        warnings.append("Survey unresolved dependency: PyRTF required if you want to export assessment templates as a Word document")

    # -------------------------------------------------------------------------
    # Check Web2Py version
    #
    # Currently, the minimum usable Web2py is determined by whether the
    # Scheduler is available
    web2py_minimum_version = "Version 1.99.3 (2011-10-27 13:23:13)"
    # Offset of datetime in return value of parse_version.
    datetime_index = 4
    web2py_version_ok = True
    try:
        from gluon.fileutils import parse_version
    except ImportError:
        web2py_version_ok = False
    if web2py_version_ok:
        web2py_minimum_parsed = parse_version(web2py_minimum_version)
        web2py_minimum_datetime = web2py_minimum_parsed[datetime_index]
        web2py_installed_datetime = request.global_settings.web2py_version[datetime_index]
        web2py_version_ok = web2py_installed_datetime >= web2py_minimum_datetime
    if not web2py_version_ok:
        warnings.append(
            "The installed version of Web2py is too old to provide the Scheduler,"
            "\nso scheduled tasks will not be available. If you need scheduled tasks,"
            "\nplease upgrade Web2py to at least version: %s" % \
            web2py_minimum_version)

    # -------------------------------------------------------------------------
    # Create required directories if needed
    app_path = request.folder
    databases_dir = os.path.join(app_path, "databases")
    try:
        os.stat(databases_dir)
    except OSError:
        # not found, create it
        os.mkdir(databases_dir)

    # -------------------------------------------------------------------------
    # Copy in Templates
    # - 000_config.py (machine-specific settings)
    # - rest are run in-place
    #
    template_folder = os.path.join(app_path, "private", "templates")

    template_files = {
        # source : destination
        "000_config.py" : os.path.join("models", "000_config.py"),
    }

    copied_from_template = []

    for t in template_files:
        src_path = os.path.join(template_folder, t)
        dst_path = os.path.join(app_path, template_files[t])
        try:
            os.stat(dst_path)
        except OSError:
            # Not found, copy from template
            if t == "000_config.py":
                input = open(src_path)
                output = open(dst_path, "w")
                for line in input:
                    if "akeytochange" in line:
                        # Generate a random hmac_key to secure the passwords in case
                        # the database is compromised
                        import uuid
                        hmac_key = uuid.uuid4()
                        line = 'deployment_settings.auth.hmac_key = "%s"' % hmac_key
                    output.write(line)
                output.close()
                input.close()
            else:
                import shutil
                shutil.copy(src_path, dst_path)
            copied_from_template.append(template_files[t])
        else:
            # Found the file in the destination
            # Check if it has been edited
            import re
            edited_pattern = r"FINISHED_EDITING_\w*\s*=\s*(True|False)"
            edited_matcher = re.compile(edited_pattern).match
            has_edited = False
            with open(dst_path) as f:
                for line in f:
                    edited_result = edited_matcher(line)
                    if edited_result:
                        has_edited = True
                        edited = edited_result.group(1)
                        break
            if has_edited and (edited != "True"):
                errors.append("Please edit %s before starting the system." % t)
            # Check if it's up to date (i.e. a critical update requirement)
            version_pattern = r"VERSION =\s*([0-9]+)"
            version_matcher = re.compile(version_pattern).match
            has_version = False
            with open(dst_path) as f:
                for line in f:
                    version_result = version_matcher(line)
                    if version_result:
                        has_version = True
                        version = version_result.group(1)
                        break
            if not has_version:
                error = "Your %s is using settings from the old templates system. Please switch to the new templates system: http://eden.sahanafoundation.org/wiki/DeveloperGuidelines/Templates" % t
                errors.append(error)
            elif int(version) != VERSION:
                error = "Your %s is using settings from template version %s. Please update with new settings from template version %s before starting the system." % \
                                (t, version, VERSION)
                errors.append(error)

    if copied_from_template:
        errors.append(
            "The following files were copied from templates and should be edited: %s" %
            ", ".join(copied_from_template))

    return {"error_messages": errors, "warning_messages": warnings}

# END =========================================================================
<|endoftext|>


<commit_before># Licensed to the StackStorm, Inc ('StackStorm') under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Plugin which tells Pylint how to handle classes which define attributes using jsonschema
in "schema" class attribute.

Those classes dyamically assign attributes defined in the schema on the class inside the
constructor.
"""

import six

from astroid import MANAGER
from astroid import nodes
from astroid import scoped_nodes

# A list of class names for which we want to skip the checks
CLASS_NAME_BLACKLIST = [
    'ExecutionParametersAPI'
]

def register(linter):
    pass

def transform(cls):
    if cls.name in CLASS_NAME_BLACKLIST:
        return

    if cls.name.endswith('API') or 'schema' in cls.locals:
        # This is a class which defines attributes in "schema" variable using json schema.
        # Those attributes are then assigned during run time inside the constructor
        fqdn = cls.qname()
        module_name, class_name = fqdn.rsplit('.', 1)

        module = __import__(module_name, fromlist=[class_name])
        actual_cls = getattr(module, class_name)

        schema = actual_cls.schema

        if not isinstance(schema, dict):
            # Not a class we are interested in
            return

        properties = schema.get('properties', {})
        for property_name, property_data in six.iteritems(properties):
            property_name = property_name.replace('-', '_')  # Note: We do the same in Python code
            property_type = property_data.get('type', None)

            if property_type == 'object':
                node = nodes.Dict()
            elif property_type == 'array':
                node = nodes.List()
            elif property_type == 'integer':
                node = scoped_nodes.builtin_lookup('int')[1][0]
            elif property_type == 'number':
                node = scoped_nodes.builtin_lookup('float')[1][0]
            elif property_type == 'string':
                node = scoped_nodes.builtin_lookup('str')[1][0]
            elif property_type == 'boolean':
                node = scoped_nodes.builtin_lookup('bool')[1][0]

            cls.locals[property_name] = [node]

MANAGER.register_transform(scoped_nodes.Class, transform)
<commit_msg>Also teach it to handle null (none) types.<commit_after># Licensed to the StackStorm, Inc ('StackStorm') under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Plugin which tells Pylint how to handle classes which define attributes using jsonschema
in "schema" class attribute.

Those classes dyamically assign attributes defined in the schema on the class inside the
constructor.
"""

import six

from astroid import MANAGER
from astroid import nodes
from astroid import scoped_nodes

# A list of class names for which we want to skip the checks
CLASS_NAME_BLACKLIST = [
    'ExecutionParametersAPI'
]

def register(linter):
    pass

def transform(cls):
    if cls.name in CLASS_NAME_BLACKLIST:
        return

    if cls.name.endswith('API') or 'schema' in cls.locals:
        # This is a class which defines attributes in "schema" variable using json schema.
        # Those attributes are then assigned during run time inside the constructor
        fqdn = cls.qname()
        module_name, class_name = fqdn.rsplit('.', 1)

        module = __import__(module_name, fromlist=[class_name])
        actual_cls = getattr(module, class_name)

        schema = actual_cls.schema

        if not isinstance(schema, dict):
            # Not a class we are interested in
            return

        properties = schema.get('properties', {})
        for property_name, property_data in six.iteritems(properties):
            property_name = property_name.replace('-', '_')  # Note: We do the same in Python code
            property_type = property_data.get('type', None)

            if isinstance(property_type, (list, tuple)):
                # Hack for attributes with multiple types (e.g. string, null)
                property_type = property_type[0]

            if property_type == 'object':
                node = nodes.Dict()
            elif property_type == 'array':
                node = nodes.List()
            elif property_type == 'integer':
                node = scoped_nodes.builtin_lookup('int')[1][0]
            elif property_type == 'number':
                node = scoped_nodes.builtin_lookup('float')[1][0]
            elif property_type == 'string':
                node = scoped_nodes.builtin_lookup('str')[1][0]
            elif property_type == 'boolean':
                node = scoped_nodes.builtin_lookup('bool')[1][0]
            elif property_type == 'null':
                node = scoped_nodes.builtin_lookup('None')[1][0]
            else:
                node = scoped_nodes.Class(property_name, None)

            cls.locals[property_name] = [node]

MANAGER.register_transform(scoped_nodes.Class, transform)
<|endoftext|>


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

from pylua.validator import Validator

class TestValidator(object):

    _xml_schema = '''\
        <root>
            <function name="update" id="update" type="request">
                <param name="some_list" minsize="1" maxsize="100" array="true" mandatory="false">
                </param>
                <param name="some_bool_param" type="Boolean" mandatory="true">
                </param>
            </function>
            <function name="put" id="put" type="request">
                <param name="some_string" type="String" mandatory="true">
                </param>
            </function>
            <function name="get" id="get" type="request">
            </function>
        </root>
        '''

    def __init__(self):
        self._validator = None

    def setup(self):
        self._validator = Validator()
        loaded = self._validator.load_schema_from_string(self._xml_schema)
        assert loaded

    def test_load_invalid_xml(self):
        invalid_xml = '<root><sub-root></sub-root>'
        loaded = self._validator.load_schema_from_string(invalid_xml)
        assert not loaded

    def test_not_found(self):
        code, error = self._validator.validate('get', 'response')
        assert code == 1
        assert error == 'Function not found'

    def test_ok_no_params(self):
        code, error = self._validator.validate('get', 'request')
        assert code == 0
        assert error == 'Ok'

    def test_ok_params(self):
        code, error = self._validator.validate('put', 'request', '{"some_string": "string_value"}')
        assert code == 0
        assert error == 'Ok'

    def test_error_params_wrong_name(self):
        code, error = self._validator.validate(
            'put', 'request', '{"some_another_string": "string_value"}')
        assert code == 2
        assert error == 'Validation error'

    def test_error_wrong_function(self):
        code, error = self._validator.validate('delete', 'request')
        assert code == 1
        assert error == 'Function not found'
<commit_msg>Add python and lua tests for validator<commit_after># -*- coding: utf-8 -*-

from gc import collect
from pylua.validator import Validator
from lupa import LuaRuntime

class TestValidator(object):

    _xml_schema = '''\
        <root>
            <function name="update" id="update" type="request">
                <param name="some_list" minsize="1" maxsize="100" array="true" mandatory="false">
                </param>
                <param name="some_bool_param" type="Boolean" mandatory="true">
                </param>
            </function>
            <function name="put" id="put" type="request">
                <param name="some_string" type="String" mandatory="true">
                </param>
            </function>
            <function name="get" id="get" type="request">
            </function>
        </root>
        '''

    def __init__(self):
        self._validator = None
        self._lua_runtime = None

    def setup(self):
        self._validator = Validator()
        self._lua_runtime = LuaRuntime(unpack_returned_tuples=True)
        loaded = self._validator.load_schema_from_string(self._xml_schema)
        self._lua_runtime.globals()['Validator'] = self._validator
        assert loaded

    def teardown(self):
        self._lua_runtime = None
        collect()

    def test_load_invalid_xml(self):
        invalid_xml = '<root><sub-root></sub-root>'
        loaded = self._validator.load_schema_from_string(invalid_xml)
        assert not loaded

    def test_load_invalid_xml_lua(self):
        lua_code = '''\
            local invalid_xml = '<root><sub-root></sub-root>'
            local loaded = Validator.load_schema_from_string(invalid_xml)
            assert(not loaded, "Expected to fail on invalid xml")
            '''
        self._lua_runtime.execute(lua_code)

    def test_not_found(self):
        code, error = self._validator.validate('get', 'response')
        assert code == 1
        assert error == 'Function not found'

    def test_not_found_lua(self):
        lua_code = '''\
            local code, error = Validator.validate('get', 'response')
            assert(code == 1)
            assert(error == 'Function not found')
            '''
        self._lua_runtime.execute(lua_code)

    def test_ok_no_params(self):
        code, error = self._validator.validate('get', 'request')
        assert code == 0
        assert error == 'Ok'

    def test_ok_no_params_lua(self):
        lua_code = '''\
            local code, error = Validator.validate('get', 'request')
            assert(code == 0)
            assert(error == 'Ok')
            '''
        self._lua_runtime.execute(lua_code)

    def test_ok_params(self):
        code, error = self._validator.validate('put', 'request', '{"some_string": "string_value"}')
        assert code == 0
        assert error == 'Ok'

    def test_ok_params_lua(self):
        lua_code = '''\
            local code, error = Validator.validate('put', 'request', '{"some_string": "string_value"}')
            assert(code == 0)
            assert(error == 'Ok')
            '''
        self._lua_runtime.execute(lua_code)

    def test_error_params_wrong_name(self):
        code, error = self._validator.validate(
            'put', 'request', '{"some_another_string": "string_value"}')
        assert code == 2
        assert error == 'Validation error'

    def test_error_params_wrong_name_lua(self):
        lua_code = '''\
            local code, error = Validator.validate('put', 'request', '{"some_another_string": "string_value"}')
            assert(code == 2)
            assert(error == 'Validation error')
            '''
        self._lua_runtime.execute(lua_code)

    def test_error_wrong_function(self):
        code, error = self._validator.validate('delete', 'request')
        assert code == 1
        assert error == 'Function not found'

    def test_error_wrong_function_lua(self):
        lua_code = '''\
            local code, error = Validator.validate('delete', 'request')
            assert(code == 1)
            assert(error == 'Function not found')
            '''
        self._lua_runtime.execute(lua_code)
<|endoftext|>