<commit_before>import operator
from functools import reduce
from django.core.urlresolvers import reverse
from django.conf import settings
from django.utils.text import slugify
from django.utils.translation import ugettext as _
from django.views.generic import (CreateView, View, ListView, DetailView,
                                  UpdateView)
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.db.models import Q
from qa.models import (UserQAProfile, Question, Answer, AnswerVote,
                       QuestionVote, AnswerComment, QuestionComment)
from .mixins import LoginRequired, AuthorRequiredMixin

try:
    qa_messages = 'django.contrib.messages' in settings.INSTALLED_APPS and\
        settings.QA_MESSAGES
except AttributeError:
    qa_messages = False

if qa_messages:
    from django.contrib import messages

"""Dear maintainer:

Once you are done trying to 'optimize' this routine, and have realized what a
terrible mistake that was, please increment the following counter as a warning
to the next guy:

total_hours_wasted_here = 2
"""

class AnswerQuestionView(LoginRequired, View):
    """View to select an answer as the satisfying answer to the question and to
    mark the question as closed, validating than the user who created que
    question is the only one allowed to make those changes.
    """
    model = Answer

    def post(self, request, answer_id):
        answer = get_object_or_404(self.model, pk=answer_id)
        if answer.question.user != request.user:
            raise ValidationError(
                "Sorry, you're not allowed to close this question.")
        else:
            answer.question.closed = True
            answer.question.save()
            answer.answer = True
            answer.save()

        next_url = request.POST.get('next', None)
        if next_url is not None:
            return redirect(next_url)

        else:
            return redirect(reverse('qa_index'))

class QuestionIndexView(ListView):
    """CBV to render the index view
    """
    model = Question
    paginate_by = 10
    context_object_name = 'questions'
    template_name = 'qa/index.html'
    ordering = '-pub_date'

    def get_context_data(self, *args, **kwargs):
        context = super(
            QuestionIndexView, self).get_context_data(*args, **kwargs)
        context['totalcount'] = Question.objects.count
        context['anscount'] = Answer.objects.count
        context['noans'] = Question.objects.order_by('-pub_date').filter(
            answer__isnull=True)[:10]
        context['reward'] = Question.objects.order_by('-reward').filter(
            answer__isnull=True, reward__gte=1)[:10]
        return context

    def get_queryset(self):
        queryset = super(QuestionIndexView, self).get_queryset().select_related('user')
        return queryset

class QuestionsSearchView(QuestionIndexView):
    """
    Display a ListView page inherithed from the QuestionIndexView filtered by
    the search query and sorted by the different elements aggregated.
    """

    def get_queryset(self):
        result = super(QuestionsSearchView, self).get_queryset()
        query = self.request.GET.get('word')
        if query:
            query_list = query.split()
            result = result.filter(
                reduce(operator.and_,
                       (Q(title__icontains=q) for q in query_list)) |
                reduce(operator.and_,
                       (Q(description__icontains=q) for q in query_list))
            )

        return result

        def get_context_data(self, *args, **kwargs):
            context = super(
                QuestionsSearchView, self).get_context_data(*args, **kwargs)
            context['totalcount'] = Question.objects.count
            context['anscount'] = Answer.objects.count
            context['noans'] = Question.objects.order_by('-pub_date').filter(
                answer__isnull=True)[:10]
            context['reward'] = Question.objects.order_by('-reward').filter(
                answer__isnull=True, reward__gte=1)[:10]
            return context

class QuestionsByTagView(ListView):
    """View to call all the questions clasiffied under one specific tag.
    """
    model = Question
    paginate_by = 10
    context_object_name = 'questions'
    template_name = 'qa/index.html'

    def get_queryset(self, **kwargs):
        return Question.objects.filter(tags__name__contains=self.kwargs['tag'])

    def get_context_data(self, *args, **kwargs):
        context = super(
            QuestionsByTagView, self).get_context_data(*args, **kwargs)
        context['totalcount'] = Question.objects.count
        context['anscount'] = Answer.objects.count
        context['noans'] = Question.objects.order_by('-pub_date').filter(
            tags__name__contains=self.kwargs['tag'], answer__isnull=True)[:10]
        context['reward'] = Question.objects.order_by('-reward').filter(
            tags__name__contains=self.kwargs['tag'], answer__isnull=True,
            reward__gte=1)[:10]
        return context

class CreateQuestionView(LoginRequired, CreateView):
    """
    View to handle the creation of a new question
    """
    template_name = 'qa/create_question.html'
    model = Question
    fields = ['title', 'description', 'tags']
    message = _('Thank you! your question has been created.')

    def form_valid(self, form):
        """
        Create the required relation
        """
        form.instance.user = self.request.user
        return super(CreateQuestionView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        return reverse('qa_index')

class UpdateQuestionView(LoginRequired, AuthorRequiredMixin, UpdateView):
    """
    Updates the question
    """
    template_name = 'qa/update_question.html'
    model = Question
    pk_url_kwarg = 'question_id'
    fields = ['title', 'description', 'tags']

    def get_success_url(self):
        question = self.get_object()
        return reverse('qa_detail', kwargs={'pk': question.pk})

class CreateAnswerView(LoginRequired, CreateView):
    """
    View to create new answers for a given question
    """
    template_name = 'qa/create_answer.html'
    model = Answer
    fields = ['answer_text']
    message = _('Thank you! your answer has been posted.')

    def form_valid(self, form):
        """
        Creates the required relationship between answer
        and user/question
        """
        form.instance.user = self.request.user
        form.instance.question_id = self.kwargs['question_id']
        return super(CreateAnswerView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        return reverse('qa_detail', kwargs={'pk': self.kwargs['question_id']})

class UpdateAnswerView(LoginRequired, AuthorRequiredMixin, UpdateView):
    """
    Updates the question answer
    """
    template_name = 'qa/update_answer.html'
    model = Answer
    pk_url_kwarg = 'answer_id'
    fields = ['answer_text']

    def get_success_url(self):
        answer = self.get_object()
        return reverse('qa_detail', kwargs={'pk': answer.question.pk})

class CreateAnswerCommentView(LoginRequired, CreateView):
    """
    View to create new comments for a given answer
    """
    template_name = 'qa/create_comment.html'
    model = AnswerComment
    fields = ['comment_text']
    message = _('Thank you! your comment has been posted.')

    def form_valid(self, form):
        """
        Creates the required relationship between answer
        and user/comment
        """
        form.instance.user = self.request.user
        form.instance.answer_id = self.kwargs['answer_id']
        return super(CreateAnswerCommentView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        question_pk = Answer.objects.get(
            id=self.kwargs['answer_id']).question.pk
        return reverse('qa_detail', kwargs={'pk': question_pk})

class CreateQuestionCommentView(LoginRequired, CreateView):
    """
    View to create new comments for a given question
    """
    template_name = 'qa/create_comment.html'
    model = QuestionComment
    fields = ['comment_text']
    message = _('Thank you! your comment has been posted.')

    def form_valid(self, form):
        """
        Creates the required relationship between question
        and user/comment
        """
        form.instance.user = self.request.user
        form.instance.question_id = self.kwargs['question_id']
        return super(CreateQuestionCommentView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        return reverse('qa_detail', kwargs={'pk': self.kwargs['question_id']})

class UpdateQuestionCommentView(LoginRequired,
                                AuthorRequiredMixin, UpdateView):
    """
    Updates the comment question
    """
    template_name = 'qa/create_comment.html'
    model = QuestionComment
    pk_url_kwarg = 'comment_id'
    fields = ['comment_text']

    def get_success_url(self):
        question_comment = self.get_object()
        return reverse(
            'qa_detail', kwargs={'pk': question_comment.question.pk})

class UpdateAnswerCommentView(UpdateQuestionCommentView):
    """
    Updates the comment answer
    """
    model = AnswerComment

    def get_success_url(self):
        answer_comment = self.get_object()
        return reverse(
            'qa_detail', kwargs={'pk': answer_comment.answer.question.pk})

class QuestionDetailView(DetailView):
    """
    View to call a question and to render all the details about that question.
    """
    model = Question
    template_name = 'qa/detail_question.html'
    context_object_name = 'question'

    def get_context_data(self, **kwargs):
        answers = self.object.answer_set.all().order_by('pub_date')
        context = super(QuestionDetailView, self).get_context_data(**kwargs)
        context['last_comments'] = self.object.questioncomment_set.order_by(
            'pub_date')[:5]
        context['answers'] = answers
        return context

    def get(self, request, **kwargs):
        my_object = self.get_object()
        slug = kwargs.get('slug', '')
        if slug!=slugify(my_object.title):
            kwargs['slug'] = slugify(my_object.title)
            return redirect(reverse('qa_detail', kwargs=kwargs))
        else:
            return super(QuestionDetailView, self).get(request, **kwargs)

    def get_object(self):
        # Call the superclass
        question = super(QuestionDetailView, self).get_object()
        question.views += 1
        question.save()
        return question

class ParentVoteView(View):
    """
    Base class to create a vote for a given model (question/answer)
    """
    model = None
    vote_model = None

    def get_vote_kwargs(self, user, vote_target):
        """
        This takes the user and the vote and adjusts the kwargs
        depending on the used model.
        """
        object_kwargs = {'user': user}
        if self.model == Question:
            target_key = 'question'
        elif self.model == Answer:
            target_key = 'answer'
        else:
            raise ValidationError('Not a valid model for votes')
        object_kwargs[target_key] = vote_target
        return object_kwargs

    def post(self, request, object_id):
        vote_target = get_object_or_404(self.model, pk=object_id)
        if vote_target.user == request.user:
            raise ValidationError(
                'Sorry, voting for your own answer is not possible.')
        else:
            upvote = request.POST.get('upvote', None) is not None
            object_kwargs = self.get_vote_kwargs(request.user, vote_target)
            vote, created = self.vote_model.objects.get_or_create(
                defaults={'value': upvote},
                **object_kwargs)
            if created:
                vote_target.user.userqaprofile.points += 1 if upvote else -1
            elif not created:
                if vote.value == upvote:
                    vote.delete()
                    vote_target.user.userqaprofile.points += -1 if upvote else 1
                else:
                    vote_target.user.userqaprofile.points += 2 if upvote else -2
                    vote.value = upvote
                    vote.save()
            vote_target.user.userqaprofile.save()
            vote_target.save()

        next_url = request.POST.get('next', None)
        if next_url is not None:
            return redirect(next_url)
        else:
            return redirect(reverse('qa_index'))

class AnswerVoteView(ParentVoteView):
    """
    Class to upvote answers
    """
    model = Answer
    vote_model = AnswerVote

class QuestionVoteView(ParentVoteView):
    """
    Class to upvote questions
    """
    model = Question
    vote_model = QuestionVote

def profile(request, user_id):
    user_ob = get_user_model().objects.get(id=user_id)
    user = UserQAProfile.objects.get(user=user_ob)
    return render(request, 'qa/profile.html', {'user': user})
<commit_msg>question tags being search by slug<commit_after>import operator
from functools import reduce
from django.core.urlresolvers import reverse
from django.conf import settings
from django.utils.text import slugify
from django.utils.translation import ugettext as _
from django.views.generic import (CreateView, View, ListView, DetailView,
                                  UpdateView)
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.db.models import Q
from qa.models import (UserQAProfile, Question, Answer, AnswerVote,
                       QuestionVote, AnswerComment, QuestionComment)
from .mixins import LoginRequired, AuthorRequiredMixin

try:
    qa_messages = 'django.contrib.messages' in settings.INSTALLED_APPS and\
        settings.QA_MESSAGES
except AttributeError:
    qa_messages = False

if qa_messages:
    from django.contrib import messages

"""Dear maintainer:

Once you are done trying to 'optimize' this routine, and have realized what a
terrible mistake that was, please increment the following counter as a warning
to the next guy:

total_hours_wasted_here = 2
"""

class AnswerQuestionView(LoginRequired, View):
    """View to select an answer as the satisfying answer to the question and to
    mark the question as closed, validating than the user who created que
    question is the only one allowed to make those changes.
    """
    model = Answer

    def post(self, request, answer_id):
        answer = get_object_or_404(self.model, pk=answer_id)
        if answer.question.user != request.user:
            raise ValidationError(
                "Sorry, you're not allowed to close this question.")
        else:
            answer.question.closed = True
            answer.question.save()
            answer.answer = True
            answer.save()

        next_url = request.POST.get('next', None)
        if next_url is not None:
            return redirect(next_url)

        else:
            return redirect(reverse('qa_index'))

class QuestionIndexView(ListView):
    """CBV to render the index view
    """
    model = Question
    paginate_by = 10
    context_object_name = 'questions'
    template_name = 'qa/index.html'
    ordering = '-pub_date'

    def get_context_data(self, *args, **kwargs):
        context = super(
            QuestionIndexView, self).get_context_data(*args, **kwargs)
        context['totalcount'] = Question.objects.count
        context['anscount'] = Answer.objects.count
        context['noans'] = Question.objects.order_by('-pub_date').filter(
            answer__isnull=True)[:10]
        context['reward'] = Question.objects.order_by('-reward').filter(
            answer__isnull=True, reward__gte=1)[:10]
        return context

    def get_queryset(self):
        queryset = super(QuestionIndexView, self).get_queryset().select_related('user')
        return queryset

class QuestionsSearchView(QuestionIndexView):
    """
    Display a ListView page inherithed from the QuestionIndexView filtered by
    the search query and sorted by the different elements aggregated.
    """

    def get_queryset(self):
        result = super(QuestionsSearchView, self).get_queryset()
        query = self.request.GET.get('word')
        if query:
            query_list = query.split()
            result = result.filter(
                reduce(operator.and_,
                       (Q(title__icontains=q) for q in query_list)) |
                reduce(operator.and_,
                       (Q(description__icontains=q) for q in query_list))
            )

        return result

        def get_context_data(self, *args, **kwargs):
            context = super(
                QuestionsSearchView, self).get_context_data(*args, **kwargs)
            context['totalcount'] = Question.objects.count
            context['anscount'] = Answer.objects.count
            context['noans'] = Question.objects.order_by('-pub_date').filter(
                answer__isnull=True)[:10]
            context['reward'] = Question.objects.order_by('-reward').filter(
                answer__isnull=True, reward__gte=1)[:10]
            return context

class QuestionsByTagView(ListView):
    """View to call all the questions clasiffied under one specific tag.
    """
    model = Question
    paginate_by = 10
    context_object_name = 'questions'
    template_name = 'qa/index.html'

    def get_queryset(self, **kwargs):
        return Question.objects.filter(tags__slug=self.kwargs['tag'])

    def get_context_data(self, *args, **kwargs):
        context = super(
            QuestionsByTagView, self).get_context_data(*args, **kwargs)
        context['totalcount'] = Question.objects.count
        context['anscount'] = Answer.objects.count
        context['noans'] = Question.objects.order_by('-pub_date').filter(
            tags__name__contains=self.kwargs['tag'], answer__isnull=True)[:10]
        context['reward'] = Question.objects.order_by('-reward').filter(
            tags__name__contains=self.kwargs['tag'], answer__isnull=True,
            reward__gte=1)[:10]
        return context

class CreateQuestionView(LoginRequired, CreateView):
    """
    View to handle the creation of a new question
    """
    template_name = 'qa/create_question.html'
    model = Question
    fields = ['title', 'description', 'tags']
    message = _('Thank you! your question has been created.')

    def form_valid(self, form):
        """
        Create the required relation
        """
        form.instance.user = self.request.user
        return super(CreateQuestionView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        return reverse('qa_index')

class UpdateQuestionView(LoginRequired, AuthorRequiredMixin, UpdateView):
    """
    Updates the question
    """
    template_name = 'qa/update_question.html'
    model = Question
    pk_url_kwarg = 'question_id'
    fields = ['title', 'description', 'tags']

    def get_success_url(self):
        question = self.get_object()
        return reverse('qa_detail', kwargs={'pk': question.pk})

class CreateAnswerView(LoginRequired, CreateView):
    """
    View to create new answers for a given question
    """
    template_name = 'qa/create_answer.html'
    model = Answer
    fields = ['answer_text']
    message = _('Thank you! your answer has been posted.')

    def form_valid(self, form):
        """
        Creates the required relationship between answer
        and user/question
        """
        form.instance.user = self.request.user
        form.instance.question_id = self.kwargs['question_id']
        return super(CreateAnswerView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        return reverse('qa_detail', kwargs={'pk': self.kwargs['question_id']})

class UpdateAnswerView(LoginRequired, AuthorRequiredMixin, UpdateView):
    """
    Updates the question answer
    """
    template_name = 'qa/update_answer.html'
    model = Answer
    pk_url_kwarg = 'answer_id'
    fields = ['answer_text']

    def get_success_url(self):
        answer = self.get_object()
        return reverse('qa_detail', kwargs={'pk': answer.question.pk})

class CreateAnswerCommentView(LoginRequired, CreateView):
    """
    View to create new comments for a given answer
    """
    template_name = 'qa/create_comment.html'
    model = AnswerComment
    fields = ['comment_text']
    message = _('Thank you! your comment has been posted.')

    def form_valid(self, form):
        """
        Creates the required relationship between answer
        and user/comment
        """
        form.instance.user = self.request.user
        form.instance.answer_id = self.kwargs['answer_id']
        return super(CreateAnswerCommentView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        question_pk = Answer.objects.get(
            id=self.kwargs['answer_id']).question.pk
        return reverse('qa_detail', kwargs={'pk': question_pk})

class CreateQuestionCommentView(LoginRequired, CreateView):
    """
    View to create new comments for a given question
    """
    template_name = 'qa/create_comment.html'
    model = QuestionComment
    fields = ['comment_text']
    message = _('Thank you! your comment has been posted.')

    def form_valid(self, form):
        """
        Creates the required relationship between question
        and user/comment
        """
        form.instance.user = self.request.user
        form.instance.question_id = self.kwargs['question_id']
        return super(CreateQuestionCommentView, self).form_valid(form)

    def get_success_url(self):
        if qa_messages:
            messages.success(
                self.request, self.message)
        return reverse('qa_detail', kwargs={'pk': self.kwargs['question_id']})

class UpdateQuestionCommentView(LoginRequired,
                                AuthorRequiredMixin, UpdateView):
    """
    Updates the comment question
    """
    template_name = 'qa/create_comment.html'
    model = QuestionComment
    pk_url_kwarg = 'comment_id'
    fields = ['comment_text']

    def get_success_url(self):
        question_comment = self.get_object()
        return reverse(
            'qa_detail', kwargs={'pk': question_comment.question.pk})

class UpdateAnswerCommentView(UpdateQuestionCommentView):
    """
    Updates the comment answer
    """
    model = AnswerComment

    def get_success_url(self):
        answer_comment = self.get_object()
        return reverse(
            'qa_detail', kwargs={'pk': answer_comment.answer.question.pk})

class QuestionDetailView(DetailView):
    """
    View to call a question and to render all the details about that question.
    """
    model = Question
    template_name = 'qa/detail_question.html'
    context_object_name = 'question'

    def get_context_data(self, **kwargs):
        answers = self.object.answer_set.all().order_by('pub_date')
        context = super(QuestionDetailView, self).get_context_data(**kwargs)
        context['last_comments'] = self.object.questioncomment_set.order_by(
            'pub_date')[:5]
        context['answers'] = answers
        return context

    def get(self, request, **kwargs):
        my_object = self.get_object()
        slug = kwargs.get('slug', '')
        if slug!=slugify(my_object.title):
            kwargs['slug'] = slugify(my_object.title)
            return redirect(reverse('qa_detail', kwargs=kwargs))
        else:
            return super(QuestionDetailView, self).get(request, **kwargs)

    def get_object(self):
        # Call the superclass
        question = super(QuestionDetailView, self).get_object()
        question.views += 1
        question.save()
        return question

class ParentVoteView(View):
    """
    Base class to create a vote for a given model (question/answer)
    """
    model = None
    vote_model = None

    def get_vote_kwargs(self, user, vote_target):
        """
        This takes the user and the vote and adjusts the kwargs
        depending on the used model.
        """
        object_kwargs = {'user': user}
        if self.model == Question:
            target_key = 'question'
        elif self.model == Answer:
            target_key = 'answer'
        else:
            raise ValidationError('Not a valid model for votes')
        object_kwargs[target_key] = vote_target
        return object_kwargs

    def post(self, request, object_id):
        vote_target = get_object_or_404(self.model, pk=object_id)
        if vote_target.user == request.user:
            raise ValidationError(
                'Sorry, voting for your own answer is not possible.')
        else:
            upvote = request.POST.get('upvote', None) is not None
            object_kwargs = self.get_vote_kwargs(request.user, vote_target)
            vote, created = self.vote_model.objects.get_or_create(
                defaults={'value': upvote},
                **object_kwargs)
            if created:
                vote_target.user.userqaprofile.points += 1 if upvote else -1
            elif not created:
                if vote.value == upvote:
                    vote.delete()
                    vote_target.user.userqaprofile.points += -1 if upvote else 1
                else:
                    vote_target.user.userqaprofile.points += 2 if upvote else -2
                    vote.value = upvote
                    vote.save()
            vote_target.user.userqaprofile.save()
            vote_target.save()

        next_url = request.POST.get('next', None)
        if next_url is not None:
            return redirect(next_url)
        else:
            return redirect(reverse('qa_index'))

class AnswerVoteView(ParentVoteView):
    """
    Class to upvote answers
    """
    model = Answer
    vote_model = AnswerVote

class QuestionVoteView(ParentVoteView):
    """
    Class to upvote questions
    """
    model = Question
    vote_model = QuestionVote

def profile(request, user_id):
    user_ob = get_user_model().objects.get(id=user_id)
    user = UserQAProfile.objects.get(user=user_ob)
    return render(request, 'qa/profile.html', {'user': user})
<|endoftext|>


<commit_before>'''
Include a customized Quip client and some utilities.

NOTICE:  To update the broadcast structure, you need to update
         1) KEYWORD, 2) B_WEIGHT, 3) PN_PER_B;
         To update the host list, you need to update
         1) HOST.
'''

from time import time
from datetime import datetime, timedelta, tzinfo
from quip import QuipClient

class QuipClient4AHA(QuipClient):
    """A customized Quip client using Harry's token and dedicated for AHA Broadcast."""
    AHABC_ID = "PCeAOAQx6sO"
    DESKTOP_ID = "LHEAOAhm7YS" # Harry's private desktop.

    KEYWORD = ("Good Morning AHA",
               "Now for this week in history",
               "In World News",
               "Now for the fun facts",
               "In AHA News")
    B_WEIGHT = (1.00, 1.30, 1.50, 1.20, 1.00)
    HOST = ["Edward", "Katherine", "Sissy", "Harry"]
    PN_PER_B = (1, 1, 2, 1, 2)

    def __init__(self):
        QuipClient.__init__(self,
            access_token="Wk9EQU1BcDZFS04=|1483091850|CF037JVoITJPnAET8aHWnZwEZACvrIm7jtkRIQCaX3g=")
            # Harry's access token.

    def get_folder_AHABC(self):
        return self.get_folder(id=self.AHABC_ID)

    def get_latest_script_ID(self):
        AHABC = self.get_folder_AHABC()
        nxtwed = week.RecentWeekDay('next Wednesday')
        title = nxtwed.strftime('%m%d')
        #lstfri = [int(time.mktime(
        #    time.strptime('%s 16:10:00' % (week.RecentWeekday('last Friday')), "%Y-%m-%d %H:%M:%S")))]
        docID = []
        for td in AHABC['children']:
            if (('thread_id' in td) and (self.get_thread(td['thread_id'])['thread']['title']==title)):
                docID.append(td['thread_id'])
        if docID == []:
            raise InvalidOperation("Script not found: There's no legitimate host script for next week's broadcast.")
        if len(docID) > 1:
            raise InvalidOperation("Redundancy Error: More than one script for the next broadcast are found!", 409)
        return docID[0]

class Week(object):

    class CST(tzinfo):
        utcoffset = lambda self, dt: timedelta(hours=8)
        dst = lambda self, dt: timedelta(0)
    _cst_today = lambda self: datetime.fromtimestamp(time(), self.CST()).date()

    def DaysTo(self, TheDay, IgnoreToday=False):
        """Return the days to a specific day of last/next week.
        e.g. (assume today is May 24, Wed. IgnoreToday=False):
            DaysTo('last Friday') # -5
            DaysTo('next Wednesday') # 0
        """
        argu = TheDay.split(' ')
        rel = {'last':-1, 'next':1}[argu[0].lower()]
        weekday = {'Monday':1, 'Tuesday':2, 'Wednesday':3, 'Thursday':4,
                   'Friday':5, 'Saturday':6, 'Sunday':7}[argu[1]]
        today = self._cst_today().isoweekday()
        if IgnoreToday:
            return weekday - today + (rel*weekday<=rel*today) * rel * 7
        else:
            return weekday - today + (rel*weekday<rel*today) * rel * 7

    def RecentWeekDay(self, TheDay, IgnoreToday=False):
        '''Return the date object for a specific day of last/next week.
        e.g. (assume today is May 24, Wed. IgnoreToday=False):
            RecentWeekDay('last Friday') # <date object of 05-19>
            RecentWeekDay('next Wednesday') # <date object of 05-24>
        '''
        return self._cst_today() + timedelta(self.DaysTo(TheDay,IgnoreToday))

week = Week()

class InvalidOperation(Exception):
    """Exception for all actions that take place when the conditions are not fulfilled."""
    def __init__(self, message, http_code=None):
        Exception.__init__(self, message)
        self.code = http_code or 202
<commit_msg>Wak...<commit_after>'''
Include a customized Quip client and some utilities.

NOTICE:  To update the broadcast structure, you need to update
         1) KEYWORD, 2) B_WEIGHT, 3) PN_PER_B;
         To update the host list, you need to update
         1) HOST.
'''

from time import time
from datetime import datetime, timedelta, tzinfo
from quip import QuipClient

class QuipClient4AHA(QuipClient):
    """A customized Quip client using Harry's token and dedicated for AHA Broadcast."""
    AHABC_ID = "PCeAOAQx6sO"
    DESKTOP_ID = "LHEAOAhm7YS" # Harry's private desktop.

    KEYWORD = ("Good Morning AHA",
               "Now for this week in history",
               "In World News",
               "Now for the fun facts",
               "In AHA News")
    B_WEIGHT = (1.00, 1.30, 1.50, 1.20, 1.00)
    HOST = ["Edward", "Katherine", "Sissy", "Harry"]
    PN_PER_B = (1, 1, 2, 1, 2)

    def __init__(self):
        QuipClient.__init__(self,
            access_token="Wk9EQU1BcDZFS04=|1483091850|CF037JVoITJPnAET8aHWnZwEZACvrIm7jtkRIQCaX3g=")
            # Harry's access token.

    def get_folder_AHABC(self):
        return self.get_folder(id=self.AHABC_ID)

    def get_latest_script_ID(self):
        AHABC = self.get_folder_AHABC()
        title = week.RecentWeekDay('next Wednesday').strftime('%m%d')
        #lstfri = [int(time.mktime(
        #    time.strptime('%s 16:10:00' % (week.RecentWeekday('last Friday')), "%Y-%m-%d %H:%M:%S")))]
        docID = []
        for td in AHABC['children']:
            if (('thread_id' in td) and (self.get_thread(td['thread_id'])['thread']['title']==title)):
                docID.append(td['thread_id'])
        if docID == []:
            raise InvalidOperation("Script not found: There's no legitimate host script for next week's broadcast.")
        if len(docID) > 1:
            raise InvalidOperation("Redundancy Error: More than one script for the next broadcast are found!", 409)
        return docID[0]

class Week(object):

    class CST(tzinfo):
        utcoffset = lambda self, dt: timedelta(hours=8)
        dst = lambda self, dt: timedelta(0)
    _cst_today = lambda self: datetime.fromtimestamp(time(), self.CST()).date()

    def DaysTo(self, TheDay, IgnoreToday=False):
        """Return the days to a specific day of last/next week.
        e.g. (assume today is May 24, Wed. IgnoreToday=False):
            DaysTo('last Friday') # -5
            DaysTo('next Wednesday') # 0
        """
        argu = TheDay.split(' ')
        rel = {'last':-1, 'next':1}[argu[0].lower()]
        weekday = {'Monday':1, 'Tuesday':2, 'Wednesday':3, 'Thursday':4,
                   'Friday':5, 'Saturday':6, 'Sunday':7}[argu[1]]
        today = self._cst_today().isoweekday()
        if IgnoreToday:
            return weekday - today + (rel*weekday<=rel*today) * rel * 7
        else:
            return weekday - today + (rel*weekday<rel*today) * rel * 7

    def RecentWeekDay(self, TheDay, IgnoreToday=False):
        '''Return the date object for a specific day of last/next week.
        e.g. (assume today is May 24, Wed. IgnoreToday=False):
            RecentWeekDay('last Friday') # <date object of 05-19>
            RecentWeekDay('next Wednesday') # <date object of 05-24>
        '''
        return self._cst_today() + timedelta(self.DaysTo(TheDay,IgnoreToday))

week = Week()

class InvalidOperation(Exception):
    """Exception for all actions that take place when the conditions are not fulfilled."""
    def __init__(self, message, http_code=None):
        Exception.__init__(self, message)
        self.code = http_code or 202
<|endoftext|>


<commit_before>import os, socket, sys, threading, time
from __init__ import Armando

sys.path = [Armando.get_lib_dir()] + sys.path

from config import Config

class MpdServerMock(threading.Thread):
    """
    Mocks an MPD server for the predefined calls performed by unit tests
    @author: Fabio "BlackLight" Manganiello <blacklight86@gmail.com>
    """

    __header_str = 'OK MPD 0.19.0\n'
    __footer_str = 'OK\n\n'
    __track = {
        'file': 'spotify:track:79kQqGkJheGjmieG0qOhpu',
        'Time': '342',
        'Artist': 'Miles Davis',
        'Album': 'Amandla',
        'Title': 'Mr. Pastorius',
        'Date': '1989',
        'Track': '8',
        'Pos': '41',
        'Id': '84',
        'AlbumArtist': 'Miles Davis',
        'X-AlbumUri': 'spotify:album:0fabOosWong8kopy57JitO',
    }

    __status = {
        'volume': '100',
        'repeat': '0',
        'random': '0',
        'single': '0',
        'consume': '0',
        'playlist': '5',
        'playlistlength': '44',
        'xfade': '0',
        'song': '3',
        'songid': '90',
        'time': '82:286',
        'elapsed': '82.579',
        'bitrate': '160',
    }

    def __init__(self, rcfile=None):
        """
        Initialize the mock by using the MPD port specified in:
        rcfile -- Configuration file containing mpd.port (default: __TESTS_DIR__/conf/main.test.conf)
        """
        super(MpdServerMock, self).__init__()

        if rcfile is None:
            rcfile = Armando.get_tests_dir() \
                     + os.sep + 'conf' \
                     + os.sep + 'main.test.conf'

        self.__config = Config(rcfile)
        if self.__config.get('mpd.port') is not None:
            self.__port = int(self.__config.get('mpd.port'))
        else:
            raise AttributeError('The configuration file %s has no mpd.port setting' % rcfile)

        self.__state = 'stop'

    def __format_msg(self, msg):
        return self.__header_str + msg + self.__footer_str

    def __serve(self, sock, addr):
        request = sock.recv(1024).decode('utf-8').strip()
        if request == 'currentsong':
            sock.send(self.get_current_song().encode())
        elif request == 'status':
            sock.send(self.get_status().encode())
        elif request == 'play':
            self.__state = 'play'
            sock.send(self.__format_msg("").encode())
        elif request == 'pause':
            self.__state = 'pause'
            sock.send(self.__format_msg("").encode())
        elif request == 'stop':
            self.__state = 'stop'
            sock.send(self.__format_msg("").encode())
        elif request == 'quit':
            self.__state = 'quit'

        else:
            sock.send(self.__get_invalid_command_string(cmd=request))

    def __get_invalid_command_string(self, cmd):
        return u'%sACK [5@0] {} unknown command "%s"\n' % (self.__header_str, cmd)

    def get_current_song(self):
        response = ""
        if self.__state != 'stop':
            for key, value in self.__track.items():
                response += '%s: %s\n' % (key, value)
        # return ""
        return self.__format_msg(response)

    def get_status(self):
        response = ""
        self.__status['state'] = self.__state
        for key, value in self.__status.items():
            response += '%s: %s\n'
        return self.__format_msg(response)

    def run(self):
        self.__ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.__ssock.bind(('127.0.0.1', self.__port))
        self.__ssock.listen(5)
        self.__ssock.settimeout(1)
        self.__sock_pool = []

        while True:
            try:
                (sock, addr) = self.__ssock.accept()
            except (socket.timeout, OSError) as e:
                self.stop()
                break

            self.__sock_pool.append(sock)
            server = threading.Thread(target=self.__serve, args=(sock, addr))
            server.start()

    def stop(self):
        if hasattr(self, '__sock_pool'):
            for s in self.__sock_pool:
                try:
                    s.close()
                except:
                    pass

        self.__ssock.close()

<commit_msg>Forgot format string parameters in MPD mock on get_status()<commit_after>import os, socket, sys, threading, time
from __init__ import Armando

sys.path = [Armando.get_lib_dir()] + sys.path

from config import Config

class MpdServerMock(threading.Thread):
    """
    Mocks an MPD server for the predefined calls performed by unit tests
    @author: Fabio "BlackLight" Manganiello <blacklight86@gmail.com>
    """

    __header_str = 'OK MPD 0.19.0\n'
    __footer_str = 'OK\n\n'
    __track = {
        'file': 'spotify:track:79kQqGkJheGjmieG0qOhpu',
        'Time': '342',
        'Artist': 'Miles Davis',
        'Album': 'Amandla',
        'Title': 'Mr. Pastorius',
        'Date': '1989',
        'Track': '8',
        'Pos': '41',
        'Id': '84',
        'AlbumArtist': 'Miles Davis',
        'X-AlbumUri': 'spotify:album:0fabOosWong8kopy57JitO',
    }

    __status = {
        'volume': '100',
        'repeat': '0',
        'random': '0',
        'single': '0',
        'consume': '0',
        'playlist': '5',
        'playlistlength': '44',
        'xfade': '0',
        'song': '3',
        'songid': '90',
        'time': '82:286',
        'elapsed': '82.579',
        'bitrate': '160',
    }

    def __init__(self, rcfile=None):
        """
        Initialize the mock by using the MPD port specified in:
        rcfile -- Configuration file containing mpd.port (default: __TESTS_DIR__/conf/main.test.conf)
        """
        super(MpdServerMock, self).__init__()

        if rcfile is None:
            rcfile = Armando.get_tests_dir() \
                     + os.sep + 'conf' \
                     + os.sep + 'main.test.conf'

        self.__config = Config(rcfile)
        if self.__config.get('mpd.port') is not None:
            self.__port = int(self.__config.get('mpd.port'))
        else:
            raise AttributeError('The configuration file %s has no mpd.port setting' % rcfile)

        self.__state = 'stop'

    def __format_msg(self, msg):
        return self.__header_str + msg + self.__footer_str

    def __serve(self, sock, addr):
        request = sock.recv(1024).decode('utf-8').strip()
        if request == 'currentsong':
            sock.send(self.get_current_song().encode())
        elif request == 'status':
            sock.send(self.get_status().encode())
        elif request == 'play':
            self.__state = 'play'
            sock.send(self.__format_msg("").encode())
        elif request == 'pause':
            self.__state = 'pause'
            sock.send(self.__format_msg("").encode())
        elif request == 'stop':
            self.__state = 'stop'
            sock.send(self.__format_msg("").encode())
        elif request == 'quit':
            self.__state = 'quit'

        else:
            sock.send(self.__get_invalid_command_string(cmd=request))

    def __get_invalid_command_string(self, cmd):
        return u'%sACK [5@0] {} unknown command "%s"\n' % (self.__header_str, cmd)

    def get_current_song(self):
        response = ""
        if self.__state != 'stop':
            for key, value in self.__track.items():
                response += '%s: %s\n' % (key, value)
        # return ""
        return self.__format_msg(response)

    def get_status(self):
        response = ""
        self.__status['state'] = self.__state
        for key, value in self.__status.items():
            response += '%s: %s\n' % (key, value)
        return self.__format_msg(response)

    def run(self):
        self.__ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.__ssock.bind(('127.0.0.1', self.__port))
        self.__ssock.listen(5)
        self.__ssock.settimeout(1)
        self.__sock_pool = []

        while True:
            try:
                (sock, addr) = self.__ssock.accept()
            except (socket.timeout, OSError) as e:
                self.stop()
                break

            self.__sock_pool.append(sock)
            server = threading.Thread(target=self.__serve, args=(sock, addr))
            server.start()

    def stop(self):
        if hasattr(self, '__sock_pool'):
            for s in self.__sock_pool:
                try:
                    s.close()
                except:
                    pass

        self.__ssock.close()

<|endoftext|>


<commit_before>"""Experimenting with cmd2 modular command sets."""

import argparse

from cmd2 import Cmd, Cmd2ArgumentParser, CommandSet, Statement, with_argparser, with_category, with_default_category

@with_default_category('Fruits')
class LoadableFruits(CommandSet):
    def __init__(self):
        super().__init__()

    def do_apple(self, _: Statement):
        self._cmd.poutput('Apple')

    def do_banana(self, _: Statement):
        self._cmd.poutput('Banana')

@with_default_category('Vegetables')
class LoadableVegetables(CommandSet):
    def __init__(self):
        super().__init__()

    def do_arugula(self, _: Statement):
        self._cmd.poutput('Arugula')

    def do_bokchoy(self, _: Statement):
        self._cmd.poutput('Bok Choy')

class ExampleApp(Cmd):
    """
    CommandSets are loaded via the `load` and `unload` commands
    """

    def __init__(self, *args, **kwargs):
        # gotta have this or neither the plugin or cmd2 will initialize
        super().__init__(*args, auto_load_commands=False, **kwargs)

        self._fruits = LoadableFruits()
        self._vegetables = LoadableVegetables()

    load_parser = Cmd2ArgumentParser()
    load_parser.add_argument('cmds', choices=['fruits', 'vegetables'])

    @with_argparser(load_parser)
    @with_category('Command Loading')
    def do_load(self, ns: argparse.Namespace):
        if ns.cmds == 'fruits':
            try:
                self.register_command_set(self._fruits)
                self.poutput('Fruits loaded')
            except ValueError:
                self.poutput('Fruits already loaded')

        if ns.cmds == 'vegetables':
            try:
                self.register_command_set(self._vegetables)
                self.poutput('Vegetables loaded')
            except ValueError:
                self.poutput('Vegetables already loaded')

    @with_argparser(load_parser)
    def do_unload(self, ns: argparse.Namespace):
        if ns.cmds == 'fruits':
            self.unregister_command_set(self._fruits)
            self.poutput('Fruits unloaded')

        if ns.cmds == 'vegetables':
            self.unregister_command_set(self._vegetables)
            self.poutput('Vegetables unloaded')

if __name__ == '__main__':
    app = ExampleApp()
    app.cmdloop()
<commit_msg>New: add snippet for cmd2 BorderedTable<commit_after>"""Experimenting with cmd2 modular command sets."""

import argparse
from functools import partial
from typing import List

from cmd2 import Cmd, Cmd2ArgumentParser, CommandSet, Statement, with_argparser, with_category, with_default_category
from cmd2.table_creator import BorderedTable, Column

@with_default_category('Fruits')
class LoadableFruits(CommandSet):
    def __init__(self):
        super().__init__()

    def do_apple(self, _: Statement):
        self._cmd.poutput('Apple')

    def do_banana(self, _: Statement):
        self._cmd.poutput('Banana')

@with_default_category('Vegetables')
class LoadableVegetables(CommandSet):
    def __init__(self):
        super().__init__()

    def do_arugula(self, _: Statement):
        self._cmd.poutput('Arugula')

    def do_bokchoy(self, _: Statement):
        self._cmd.poutput('Bok Choy')

class ExampleApp(Cmd):
    """CommandSets are loaded via the `load` and `unload` commands."""

    def __init__(self, *args, **kwargs):
        # gotta have this or neither the plugin or cmd2 will initialize
        super().__init__(*args, auto_load_commands=False, **kwargs)

        self._fruits = LoadableFruits()
        self._vegetables = LoadableVegetables()

    load_parser = Cmd2ArgumentParser()
    load_parser.add_argument('cmds', choices=['fruits', 'vegetables'])

    @with_argparser(load_parser)
    @with_category('Command Loading')
    def do_load(self, ns: argparse.Namespace):
        if ns.cmds == 'fruits':
            try:
                self.register_command_set(self._fruits)
                self.poutput('Fruits loaded')
            except ValueError:
                self.poutput('Fruits already loaded')

        if ns.cmds == 'vegetables':
            try:
                self.register_command_set(self._vegetables)
                self.poutput('Vegetables loaded')
            except ValueError:
                self.poutput('Vegetables already loaded')

    @with_argparser(load_parser)
    def do_unload(self, ns: argparse.Namespace):
        if ns.cmds == 'fruits':
            self.unregister_command_set(self._fruits)
            self.poutput('Fruits unloaded')

        if ns.cmds == 'vegetables':
            self.unregister_command_set(self._vegetables)
            self.poutput('Vegetables unloaded')

# ======================================================================================================
# PLANNED: This is just a cool looking table output that may be useful
def create_cmd_table(table_data: List[List[str]], width: int = 15) -> BorderedTable:
    """Create a bordered table for cmd2 output.

    Args:
        table_data: list of lists with the string data to display
        width: integer width of the columns. Default is 15 which generally works for ~4 columns

    Returns:
        BorderedTable: generated table for printing

    """
    columns = table_data[0]
    auto_column = partial(Column, width=width)
    bt = BorderedTable([*map(auto_column, columns)])
    rows = table_data[1:]
    return bt.generate_table(rows)

class ExtendedDisplay:  # noqa: H601
    """Extended Display Command Set with New Commands for More Interactive Output."""

    def do_display_table(self, statement: Statement) -> None:
        """Display a Table of (TBD) Data.

        Args:
            statement: results of parsing

        """
        # Placeholder sample data
        _table_data = [
            ['Studio', '# Movies', '# PPV', 'Revenue'],
            ['Netflix', '12', '14', f'{999999:,}'],
            ['Amazon Prime Video', '12', '14', f'{21450:,}'],
        ]
        self._cmd.poutput(create_cmd_table(_table_data))

if __name__ == '__main__':
    app = ExampleApp()
    app.cmdloop()
<|endoftext|>


<commit_before>#!/usr/bin/env python

# This script is used to get data from ecmwf web API
# https://software.ecmwf.int/wiki/display/WEBAPI/Python+ERA-interim+examples
# Requests format created from ECMWF GUI and MARS request
# http://apps.ecmwf.int/datasets/data/interim-full-daily/levtype=sfc/
# HIT "View the MARS request buttom at the bottom to use this script for data"

import sys
import numpy as np
from ecmwfapi import ECMWFDataServer

# Get command line arguments
VAR         = sys.argv[1]
startYear   = int(sys.argv[2])
endYear     = int(sys.argv[3])
levtype     = sys.argv[4] #"sfc" # "pl"
gridSpacing = "0.75/0.75" # "0.75/0.75" | "1.50/1.50"

if gridSpacing == "0.75/0.75":
	DataDir = "/barnes-scratch/sbrey/era_interim_nc_6_hourly/"
else:
	DataDir = "/barnes-scratch/sbrey/era_interim_nc_6_hourly_1_5/"

nYears = (endYear - startYear) + 1
yearArray = np.arange(startYear, endYear+1)

# Connect to the server
server = ECMWFDataServer()

# get param based on dictionary
# TODO: UPDATE once the better names are known
param_dict = {"sp":"134.128",
	          "t2m":"167.128",
              "d2m":"168.128",
              "u10":"165.128",
              "v10":"166.128",
              "tp":"228.128",
	          "z":"129.128",
	          "vo":"138.128",
	          "u":"131.128",
              "v":"132.128",
              "t":"130.128",
              "wgust":"49.128",
              "evap":"182.128"
              }

param = param_dict[VAR]

# handle the fact that some variables have different time steps
if (param == "228.128") or (param == "182.128"):
	print "getting precip, changing step and time"
	step = "6"
	time = "00:00:00/12:00:00"
else:
	step = "0"
	time = "00:00:00/06:00:00/12:00:00/18:00:00"

# Loop through years, download each as its own request
for i in range(nYears):

	year_str = str(yearArray[i])

	# write the save location
	target = DataDir + VAR + "_" + year_str + ".nc"
	# write the date range to be downloaded
	date = year_str + "-01-01/to/" + year_str + "-12-31"

	print "---------------------------------------------------------------"
	print "Working on downloading " + VAR +":" +param + " for " + year_str
	print "writing: " + target
	print "---------------------------------------------------------------"

	if levtype == "sfc":

		if (param == "228.128") or (param == "182.128"):
		# precip and evap requires special treatment
			server.retrieve({
    				"class": "ei",
    				"dataset": "interim",
    				"date": date,
				    "expver": "1",
				    "grid": gridSpacing,
			    	"levtype": "sfc",
			    	"param": param,
			    	"step": "6",
			    	"stream": "oper",
			    	"time": "00:00:00/12:00:00",
			    	"type": "fc",
				    "format" : "netcdf",
			    	"target": target,
			})
		else:
			server.retrieve({
				"class": "ei",
				"dataset": "interim",
				"date": date,
				"expver": "1",
				"grid": gridSpacing,
				"levtype": "sfc",
				"param": param,
				"step": step,
				"stream": "oper",
				"time": time,
				"type": "an",
				"format" : "netcdf",
				"target": target,
			})

	else:

		server.retrieve({
		"class": "ei",
		"dataset": "interim",
		"date": date,
		"expver": "1",
		"grid": gridSpacing,
		"levelist": "250/500/850/1000",
		"levtype": "pl",
		"param": param,
		"step": step,
		"stream": "oper",
		"time": time,
		"type": "an",
		"format" : "netcdf",
		"target": target,
		})

<commit_msg>Very important change to ECMWF tp download step parameter. Step change from 6 to 12, to get actually daily total.<commit_after>#!/usr/bin/env python

# This script is used to get data from ecmwf web API
# https://software.ecmwf.int/wiki/display/WEBAPI/Python+ERA-interim+examples
# Requests format created from ECMWF GUI and MARS request
# http://apps.ecmwf.int/datasets/data/interim-full-daily/levtype=sfc/
# HIT "View the MARS request buttom at the bottom to use this script for data"

import sys
import numpy as np
from ecmwfapi import ECMWFDataServer

# Get command line arguments
VAR         = sys.argv[1]
startYear   = int(sys.argv[2])
endYear     = int(sys.argv[3])
levtype     = sys.argv[4] #"sfc" # "pl"
gridSpacing = "0.75/0.75" # "0.75/0.75" | "1.50/1.50"

if gridSpacing == "0.75/0.75":
	DataDir = "/barnes-scratch/sbrey/era_interim_nc_6_hourly/"
else:
	DataDir = "/barnes-scratch/sbrey/era_interim_nc_6_hourly_1_5/"

nYears = (endYear - startYear) + 1
yearArray = np.arange(startYear, endYear+1)

# Connect to the server
server = ECMWFDataServer()

# get param based on dictionary
# TODO: UPDATE once the better names are known
param_dict = {"sp":"134.128",
	           "t2m":"167.128",
              "d2m":"168.128",
              "u10":"165.128",
              "v10":"166.128",
              "tp":"228.128",
	           "z":"129.128",
	           "vo":"138.128",
	           "u":"131.128",
              "v":"132.128",
              "t":"130.128",
              "wgust":"49.128",
              "evap":"182.128"
              }

param = param_dict[VAR]

# handle the fact that some variables have different time steps
if (param == "228.128") or (param == "182.128"):
	# For explanation on why step needs to be 12 for these times to get daily
	# totals, please see example 1 of the following link.
	# https://software.ecmwf.int/wiki/pages/viewpage.action?pageId=56658233
	print "getting precip, changing step and time"
	step = "12"
	time = "00:00:00/12:00:00"
else:
	step = "0"
	time = "00:00:00/06:00:00/12:00:00/18:00:00"

# Loop through years, download each as its own request
for i in range(nYears):

	year_str = str(yearArray[i])

	# write the save location
	target = DataDir + VAR + "_" + year_str + ".nc"
	# write the date range to be downloaded
	date = year_str + "-01-01/to/" + year_str + "-12-31"

	print "---------------------------------------------------------------"
	print "Working on downloading " + VAR +":" +param + " for " + year_str
	print "writing: " + target
	print "---------------------------------------------------------------"

	if levtype == "sfc":

		if (param == "228.128") or (param == "182.128"):
		# precip and evap requires special treatment
			server.retrieve({
    				"class": "ei",
    				"dataset": "interim",
    				"date": date,
				    "expver": "1",
				    "grid": gridSpacing,
			    	"levtype": "sfc",
			    	"param": param,
			    	"step": "6",
			    	"stream": "oper",
			    	"time": "00:00:00/12:00:00",
			    	"type": "fc",
				    "format" : "netcdf",
			    	"target": target,
			})
		else:
			server.retrieve({
				"class": "ei",
				"dataset": "interim",
				"date": date,
				"expver": "1",
				"grid": gridSpacing,
				"levtype": "sfc",
				"param": param,
				"step": step,
				"stream": "oper",
				"time": time,
				"type": "an",
				"format" : "netcdf",
				"target": target,
			})

	else:

		server.retrieve({
		"class": "ei",
		"dataset": "interim",
		"date": date,
		"expver": "1",
		"grid": gridSpacing,
		"levelist": "250/500/850/1000",
		"levtype": "pl",
		"param": param,
		"step": step,
		"stream": "oper",
		"time": time,
		"type": "an",
		"format" : "netcdf",
		"target": target,
		})

<|endoftext|>


<commit_before><commit_msg>Unused import<commit_after><|endoftext|>


<commit_before>#!/usr/bin/env python
# coding=utf8

"""
Convert selected @objc attributes in a source file into access notes, removing
the originals in the process.
"""

from __future__ import print_function

import io
import re
import sys

#
# Entry point
#

def main():
    if len(sys.argv) != 4:
        print('Too few args to ' + sys.argv[0])
        print('Usage: access-note-gen.py <input-file> <output-source-file> ' +
              '<output-access-notes-file>')
        sys.exit(1)

    with io.open(sys.argv[1], mode='r', encoding='utf8') as input_file, \
         io.open(sys.argv[2], mode='w', encoding='utf8') as output_file, \
         io.open(sys.argv[3], mode='w', encoding='utf8') as access_notes_file:

        # Add header to access notes file
        access_notes_file.write(u"""\
Reason: 'fancy tests'
Notes:""")

        # Loop over input lines, transforming them into output lines, writing access
        # notes as a side effect.
        for input_line in input_file:
            # Look for access-note-move comments.
            input_line = access_note_move_re.sub(replacer(move_at_objc_to_access_note,
                                                          access_notes_file),
                                                 input_line, count=1)

            # Look for access-note-adjust comments.
            input_line = adjust_comment_re.sub(replacer(adjust_comments),
                                               input_line, count=1)

            output_file.write(input_line)

#
# Offsets
#

"""Matches an @±N offset."""
offset_re_fragment = r'[ \t]*(?:@([+-]\d+))?[ \t]*'

def offsetify(*offsets):
    """Sum line offsets matched by offset_re_fragment and convert them to strings
       like @+3 or @-2."""

    offset = sum([int(o) for o in offsets if o is not None])
    if offset < 0:
        return u"@-" + str(-offset)
    elif offset > 0:
        return u"@+" + str(offset)
    else:
        return u""

#
# Adjusting comments
#

"""Matches expected-warning/note/remark and its offset."""
expected_other_diag_re = re.compile(r'expected-(warning|note|remark)' +
                                    offset_re_fragment)

"""Matches expected-error and its offset."""
expected_error_re = re.compile(r'expected-error' + offset_re_fragment +
                               r'\s*(\d*\s*)\{\{' +
                               r'([^}\\]*(?:(?:\}?\\.|\}[^}])[^}\\]*)*)' +
                               r'\}\}')

"""Matches the string 'marked @objc'."""
marked_objc_re = re.compile(r'marked @objc')

"""Matches any non-none fix-it expectation."""
fixit_re = re.compile(r'{{\d+-\d+=[^}]*}}')

def adjust_comments(offset, inserted_attr, comment_str):
    """Replace expected-errors with expected-remarks, and make other adjustments
       to diagnostics so that they reflect access notes."""

    prefix = u"{{ignored access note: "
    suffix = u"; did not implicitly add '" + inserted_attr + "' to this }}"

    adjusted = expected_other_diag_re.sub(lambda m: u"expected-" + m.group(1) +
                                                    offsetify(offset, m.group(2)),
                                          comment_str)
    adjusted = expected_error_re.sub(lambda m: u"expected-remark" +
                                               offsetify(offset, m.group(1)) + " " +
                                               m.group(2) + prefix + m.group(3) +
                                               suffix,
                                     adjusted)
    adjusted = marked_objc_re.sub(u"marked @objc by an access note", adjusted)
    adjusted = fixit_re.sub(u"{{none}}", adjusted)

    return u"// [expectations adjusted] " + adjusted

#
# Writing attrs to access notes
#

def move_at_objc_to_access_note(access_notes_file, arg, maybe_bad, offset,
                                access_note_name):
    """Write an @objc attribute into an access notes file, then return the
       string that will replace the attribute and trailing comment."""

    is_bad = (maybe_bad == "bad-")

    access_notes_file.write(u"""
- Name: '{}'
  ObjC: true""".format(access_note_name))
    if arg:
        access_notes_file.write(u"""
  ObjCName: '{}'""".format(arg))

    # Default to shifting expected diagnostics down 1 line.
    if offset is None:
        offset = 1

    inserted_attr = u"@objc"
    if arg:
        inserted_attr += u"(" + arg + u")"

    replacement = u"// access-note-adjust" + offsetify(offset) + \
                  u"{{" + inserted_attr + "}} [attr moved] "

    if not is_bad:
        replacement += u"expected-remark{{implicitly added '" + inserted_attr + \
                       u"' to this }} expected-note{{add '" + inserted_attr + \
                       u"' explicitly to silence this warning}}"

    return replacement

#
# Matching lines
#

"""Matches '@objc(foo) // access-note-move{{access-note-name}}'
   or '@objc // bad-access-note-move{{access-note-name}}'"""
access_note_move_re = re.compile(r'@objc(?:\(([\w:]+)\))?[ \t]*' +
                                 r'//[ \t]*(bad-)?access-note-move' +
                                 offset_re_fragment +
                                 r'\{\{([^}]*)\}\}')

"""Matches // access-note-adjust{{@objc}} <comment>"""
adjust_comment_re = re.compile(r'//[ \t]*access-note-adjust' + offset_re_fragment +
                               r'\{\{([^}]*)\}\}[ \t]*(.*)')

def replacer(fn, *args):
    """Returns a lambda which calls fn with args, followed by the groups from
       the match passed to the lambda."""

    return lambda m: fn(*(args + m.groups()))

main()
<commit_msg>test: correct indentation for linter (NFCI)<commit_after>#!/usr/bin/env python
# coding=utf8

"""
Convert selected @objc attributes in a source file into access notes, removing
the originals in the process.
"""

from __future__ import print_function

import io
import re
import sys

#
# Entry point
#

def main():
    if len(sys.argv) != 4:
        print('Too few args to ' + sys.argv[0])
        print('Usage: access-note-gen.py <input-file> <output-source-file> ' +
              '<output-access-notes-file>')
        sys.exit(1)

    with io.open(sys.argv[1], mode='r', encoding='utf8') as input_file, \
        io.open(sys.argv[2], mode='w', encoding='utf8') as output_file, \
        io.open(sys.argv[3], mode='w', encoding='utf8') as access_notes_file:

        # Add header to access notes file
        access_notes_file.write(u"""\
Reason: 'fancy tests'
Notes:""")

        # Loop over input lines, transforming them into output lines, writing access
        # notes as a side effect.
        for input_line in input_file:
            # Look for access-note-move comments.
            input_line = access_note_move_re.sub(replacer(move_at_objc_to_access_note,
                                                          access_notes_file),
                                                 input_line, count=1)

            # Look for access-note-adjust comments.
            input_line = adjust_comment_re.sub(replacer(adjust_comments),
                                               input_line, count=1)

            output_file.write(input_line)

#
# Offsets
#

"""Matches an @±N offset."""
offset_re_fragment = r'[ \t]*(?:@([+-]\d+))?[ \t]*'

def offsetify(*offsets):
    """Sum line offsets matched by offset_re_fragment and convert them to strings
       like @+3 or @-2."""

    offset = sum([int(o) for o in offsets if o is not None])
    if offset < 0:
        return u"@-" + str(-offset)
    elif offset > 0:
        return u"@+" + str(offset)
    else:
        return u""

#
# Adjusting comments
#

"""Matches expected-warning/note/remark and its offset."""
expected_other_diag_re = re.compile(r'expected-(warning|note|remark)' +
                                    offset_re_fragment)

"""Matches expected-error and its offset."""
expected_error_re = re.compile(r'expected-error' + offset_re_fragment +
                               r'\s*(\d*\s*)\{\{' +
                               r'([^}\\]*(?:(?:\}?\\.|\}[^}])[^}\\]*)*)' +
                               r'\}\}')

"""Matches the string 'marked @objc'."""
marked_objc_re = re.compile(r'marked @objc')

"""Matches any non-none fix-it expectation."""
fixit_re = re.compile(r'{{\d+-\d+=[^}]*}}')

def adjust_comments(offset, inserted_attr, comment_str):
    """Replace expected-errors with expected-remarks, and make other adjustments
       to diagnostics so that they reflect access notes."""

    prefix = u"{{ignored access note: "
    suffix = u"; did not implicitly add '" + inserted_attr + "' to this }}"

    adjusted = expected_other_diag_re.sub(lambda m: u"expected-" + m.group(1) +
                                                    offsetify(offset, m.group(2)),
                                          comment_str)
    adjusted = expected_error_re.sub(lambda m: u"expected-remark" +
                                               offsetify(offset, m.group(1)) + " " +
                                               m.group(2) + prefix + m.group(3) +
                                               suffix,
                                     adjusted)
    adjusted = marked_objc_re.sub(u"marked @objc by an access note", adjusted)
    adjusted = fixit_re.sub(u"{{none}}", adjusted)

    return u"// [expectations adjusted] " + adjusted

#
# Writing attrs to access notes
#

def move_at_objc_to_access_note(access_notes_file, arg, maybe_bad, offset,
                                access_note_name):
    """Write an @objc attribute into an access notes file, then return the
       string that will replace the attribute and trailing comment."""

    is_bad = (maybe_bad == "bad-")

    access_notes_file.write(u"""
- Name: '{}'
  ObjC: true""".format(access_note_name))
    if arg:
        access_notes_file.write(u"""
  ObjCName: '{}'""".format(arg))

    # Default to shifting expected diagnostics down 1 line.
    if offset is None:
        offset = 1

    inserted_attr = u"@objc"
    if arg:
        inserted_attr += u"(" + arg + u")"

    replacement = u"// access-note-adjust" + offsetify(offset) + \
                  u"{{" + inserted_attr + "}} [attr moved] "

    if not is_bad:
        replacement += u"expected-remark{{implicitly added '" + inserted_attr + \
                       u"' to this }} expected-note{{add '" + inserted_attr + \
                       u"' explicitly to silence this warning}}"

    return replacement

#
# Matching lines
#

"""Matches '@objc(foo) // access-note-move{{access-note-name}}'
   or '@objc // bad-access-note-move{{access-note-name}}'"""
access_note_move_re = re.compile(r'@objc(?:\(([\w:]+)\))?[ \t]*' +
                                 r'//[ \t]*(bad-)?access-note-move' +
                                 offset_re_fragment +
                                 r'\{\{([^}]*)\}\}')

"""Matches // access-note-adjust{{@objc}} <comment>"""
adjust_comment_re = re.compile(r'//[ \t]*access-note-adjust' + offset_re_fragment +
                               r'\{\{([^}]*)\}\}[ \t]*(.*)')

def replacer(fn, *args):
    """Returns a lambda which calls fn with args, followed by the groups from
       the match passed to the lambda."""

    return lambda m: fn(*(args + m.groups()))

main()
<|endoftext|>


<commit_before>import argparse
import re

class Elevator(object):

    def __init__(self, start):
        self.current = start

    def up(self):
        self.previous = self.current
        self.current += 1

    def down(self):
        self.previous = self.current
        self.current -= 1

class Generator(object):

    def __init__(self, start):
        self.current = start

class Microchip(object):

    def __init__(self, start):
        self.current = start

def is_valid(floors):
    valid = True
    for floor in floors:
        if len(floor["generators"]) == 0 or len(floor["microchips"]) == 0:
            # If no generators or no microchips are on floor, valid
            valid = True
            continue
        elif sorted(floor["microchips"]) in sorted(floor["generators"]):
            # If all microchips have associated generators on floor, valid
            valid = True
            continue
        else:
            valid = False
            break
    return valid

    """
        for gen in floor["generators"]:
            if gen in floor["microchps"]:
                valid = True
            else:
                ## Raise exception, return False.....#####################
                valid = False
        for chip in floor["microchips"]:
            if chip in floor["generators"]:
                valid = True
            else:
                ## Raise exception, return False.....#####################
                valid = False
    """

def input_parser(lines):
    """
    The first floor contains a promethium generator and a promethium-compatible microchip.
    The second floor contains a cobalt generator, a curium generator, a ruthenium generator, and a plutonium generator.
    The third floor contains a cobalt-compatible microchip, a curium-compatible microchip, a ruthenium-compatible microchip, and a plutonium-compatible microchip.
    The fourth floor contains nothing relevant.
    """
    for line in lines:
        pass

    floors = [
            { "generators": ["promethium"], "microchips": ["promethium"]},
            { "generators": ["cobalt", "curium", "ruthenium", "plutonium"], "microchips": []},
            { "generators": [], "microchips": ["cobalt", "curium", "ruthenium", "plutonium"]},
            { "generators": [], "microchips": []}
            ]

    return floors

def elevator_mover(floors, currentfloor, totalmoves):
    # Possible elevator actions are
    # move 2 items down, move 1 item down, move 1 item up, move 2 items up
    if currentfloor == 0:
        elevator_actions = (2, 1)
    elif currentfloor == 3:
        elevator_actions = (-2, -1)
    else:
        elevator_actions = (-2, -1, 2, 1)
\

parser = argparse.ArgumentParser(description='Advent of code.')
parser.add_argument('inputfile', type=argparse.FileType('r'), help='Path to input file')
args = parser.parse_args()
lines = args.inputfile.read().rstrip("\n").split("\n")

floors = input_parser(lines)
print(floors)
<commit_msg>working on day11<commit_after>import argparse
import re

class Elevator(object):

    def __init__(self, start):
        self.current = start

    def up(self):
        self.previous = self.current
        self.current += 1

    def down(self):
        self.previous = self.current
        self.current -= 1

class Generator(object):

    def __init__(self, start):
        self.current = start

class Microchip(object):

    def __init__(self, start):
        self.current = start

class Floor(object):

    def __init__(self):
        pass

def is_valid(floors):
    valid = True
    for floor in floors:
        if len(floor["generators"]) == 0 or len(floor["microchips"]) == 0:
            # If no generators or no microchips are on floor, valid
            valid = True
            continue
        elif sorted(floor["microchips"]) in sorted(floor["generators"]):
            # If all microchips have associated generators on floor, valid
            valid = True
            continue
        else:
            valid = False
            break
    return valid

    """
        for gen in floor["generators"]:
            if gen in floor["microchps"]:
                valid = True
            else:
                ## Raise exception, return False.....#####################
                valid = False
        for chip in floor["microchips"]:
            if chip in floor["generators"]:
                valid = True
            else:
                ## Raise exception, return False.....#####################
                valid = False
    """

def input_parser(lines):
    """
    The first floor contains a promethium generator and a promethium-compatible microchip.
    The second floor contains a cobalt generator, a curium generator, a ruthenium generator, and a plutonium generator.
    The third floor contains a cobalt-compatible microchip, a curium-compatible microchip, a ruthenium-compatible microchip, and a plutonium-compatible microchip.
    The fourth floor contains nothing relevant.
    """
    for line in lines:
        pass

    floors = [
            { "generators": ["promethium"], "microchips": ["promethium"]},
            { "generators": ["cobalt", "curium", "ruthenium", "plutonium"], "microchips": []},
            { "generators": [], "microchips": ["cobalt", "curium", "ruthenium", "plutonium"]},
            { "generators": [], "microchips": []}
            ]

    return floors

def elevator_mover(floors, currentfloor, totalmoves):
    # Possible elevator actions are
    # move 2 items down, move 1 item down, move 1 item up, move 2 items up
    if currentfloor == 0:
        elevator_actions = (2, 1)
    elif currentfloor == 3:
        elevator_actions = (-2, -1)
    else:
        elevator_actions = (-2, -1, 2, 1)
\

parser = argparse.ArgumentParser(description='Advent of code.')
parser.add_argument('inputfile', type=argparse.FileType('r'), help='Path to input file')
args = parser.parse_args()
lines = args.inputfile.read().rstrip("\n").split("\n")

floors = input_parser(lines)
print(floors)
<|endoftext|>


<commit_before>import datetime
from functools import reduce

import django_rq
import requests
from django.conf.urls import url
from django.contrib import admin
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.test.client import RequestFactory
from django.urls import reverse
from django.utils.html import format_html
from lxml import etree
from lxml.builder import E

from api.export.views import IATIActivityList
from iati_synchroniser.models import Codelist, Dataset, Publisher
from task_queue.tasks import force_parse_source_by_url

class CodeListAdmin(admin.ModelAdmin):
    list_display = ['name', 'description', 'count', 'fields', 'date_updated']

# TODO: Make this a celery task - 2016-01-21
def export_xml_by_source(request, dataset_id):
    """Call export API with this dataset_id, combine paginated responses"""

    if not dataset_id:
        return

    base_url = request.build_absolute_uri(
            reverse('export:activity-export')
        ) + "?dataset={dataset_id}&format=xml&page_size=100&page={page}".format(  # NOQA: E501
            dataset_id=dataset_id, page="{page}"
        )

    def get_result(xml, page_num):
        print('making request, page: ' + str(page_num))
        rf = RequestFactory()
        req = rf.get(base_url.format(page=page_num))

        view = IATIActivityList.as_view()(req).render()
        xml.extend(etree.fromstring(view.content).getchildren())

        link_header = view.get('link')

        if not link_header:
            return xml

        link = requests.utils.parse_header_links(link_header)
        has_next = reduce(lambda acc, x: acc or (
            x['rel'] == 'next'), link, False)

        if has_next:
            return get_result(xml, page_num + 1)
        else:
            return xml

    xml = E('iati-activities', version="2.02")

    final_xml = get_result(xml, 1)
    final_xml.attrib[
        'generated-datetime'
    ] = datetime.datetime.now().isoformat()

    from django.core.files.base import File
    from django.conf import settings
    import uuid

    file_name = "{}.xml".format(uuid.uuid4())
    path = "{}/{}".format(settings.MEDIA_ROOT, file_name)

    xml_file = File(open(path, mode='w'))
    xml_file.write(etree.tostring(final_xml, pretty_print=True))
    xml_file.close()

    return file_name

class DatasetAdmin(admin.ModelAdmin):
    actions = ['really_delete_selected']
    search_fields = ['id', 'name', 'title',
                     'publisher__name', 'publisher__publisher_iati_id']
    list_display = [
        'id',
        'iati_id',
        'name',
        'publisher',
        'title',
        'show_source_url',
        'date_created',
        'export_btn',
        'get_parse_status',
        'get_parse_activity',
        'date_updated',
        'last_found_in_registry',
        'is_parsed',
        'time_to_parse']

    def show_source_url(self, obj):
        return format_html(
            'Open file in new window',
            url=obj.source_url
        )
    show_source_url.allow_tags = True
    show_source_url.short_description = "URL"

    def export_btn(self, obj):
        return format_html(
            'Export',  # NOQA: E501
            id=obj.id
        )
    export_btn.short_description = 'Export XML'
    export_btn.allow_tags = True

    def get_parse_status(self, obj):
        return format_html(
            'Add to parser queue',  # NOQA: E501
            id=obj.id
        )
    get_parse_status.allow_tags = True
    get_parse_status.short_description = "Parse"

    def get_parse_activity(self, obj):
        return format_html(
                "<input type='text' name='activity-id' placeholder='activity id'>Parse Activity",  # NOQA: E501
            id=obj.id)
    get_parse_activity.allow_tags = True
    get_parse_activity.short_description = "Parse Activity"

    def get_urls(self):
        urls = super(DatasetAdmin, self).get_urls()
        extra_urls = [
            url(
                r'^parse-source/$',
                self.admin_site.admin_view(self.parse_source)),
            url(
                r'^add-to-parse-queue/$',
                self.admin_site.admin_view(self.add_to_parse_queue)),
            url(
                r'^parse-xml/(?P<activity_id>[^@$&+,/:;=?]+)$',
                self.admin_site.admin_view(self.parse_activity_view)),
            url(
                r'^export-xml/(?P<id>[^@$&+,/:;=?]+)$',
                self.admin_site.admin_view(self.export_xml),
                name='export-xml'),
        ]
        return extra_urls + urls

    def parse_source(self, request):
        xml_id = request.GET.get('xml_id')
        force = request.GET.get('force', '')
        if force == '0':
            force = False
        else:
            force = True
        obj = get_object_or_404(Dataset, pk=xml_id)
        obj.process(force_reparse=force)
        return HttpResponse(
            'Success', content_type='text/html')

    def add_to_parse_queue(self, request):
        xml_id = request.GET.get('xml_id')
        obj = get_object_or_404(Dataset, pk=xml_id)
        queue = django_rq.get_queue("parser")
        queue.enqueue(force_parse_source_by_url, args=(
            obj.source_url, True), timeout=7200)
        return HttpResponse('Success')

    def parse_activity_view(self, request, activity_id):
        xml_id = request.GET.get('xml_id')
        obj = get_object_or_404(Dataset, pk=xml_id)
        obj.process_activity(activity_id)
        return HttpResponse('Success')

    def export_xml(self, request, id):
        xml_response = export_xml_by_source(request, id)
        # print xml_response
        return HttpResponse(xml_response, content_type='application/xml')

    def get_actions(self, request):
        actions = super(DatasetAdmin, self).get_actions(request)
        del actions['delete_selected']
        return actions

    def really_delete_selected(self, request, queryset):
        for obj in queryset:
            obj.delete()

        if queryset.count() == 1:
            message_bit = "1 IATI data source was"
        else:
            message_bit = "%s IATI data sources were" % queryset.count()
        self.message_user(request, "%s successfully deleted." % message_bit)
    really_delete_selected\
        .short_description = "Delete selected IATI data sources"

class DatasetInline(admin.TabularInline):
    model = Dataset
    extra = 0

class PublisherAdmin(admin.ModelAdmin):
    inlines = [DatasetInline]

    list_display = (
        'publisher_iati_id',
        'display_name',
        'name')

    class Media:
        js = (
            'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js',
            '/static/js/publisher_admin.js',
        )

    def get_urls(self):
        urls = super(PublisherAdmin, self).get_urls()
        extra_urls = [
            url(
                r'^parse-publisher/$',
                self.admin_site.admin_view(self.parse_view)),
        ]
        return extra_urls + urls

    def parse_view(self, request):
        publisher_id = request.GET.get('publisher_id')
        for obj in Dataset.objects.filter(publisher__id=publisher_id):
            obj.process()
        return HttpResponse('Success')

admin.site.register(Codelist, CodeListAdmin)
admin.site.register(Publisher, PublisherAdmin)
admin.site.register(Dataset, DatasetAdmin)
<commit_msg>fixed bug oipa780<commit_after>import datetime
from functools import reduce

import django_rq
import requests
from django.conf.urls import url
from django.contrib import admin
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.test.client import RequestFactory
from django.urls import reverse
from django.utils.html import format_html
from lxml import etree
from lxml.builder import E

from api.export.views import IATIActivityList
from iati_synchroniser.models import Codelist, Dataset, Publisher
from task_queue.tasks import force_parse_source_by_url

class CodeListAdmin(admin.ModelAdmin):
    list_display = ['name', 'description', 'count', 'fields', 'date_updated']

# TODO: Make this a celery task - 2016-01-21
def export_xml_by_source(request, dataset_id):
    """Call export API with this dataset_id, combine paginated responses"""

    if not dataset_id:
        return

    base_url = request.build_absolute_uri(
            reverse('export:activity-export')
        ) + "?dataset={dataset_id}&format=xml&page_size=100&page={page}".format(  # NOQA: E501
            dataset_id=dataset_id, page="{page}"
        )

    def get_result(xml, page_num):
        print('making request, page: ' + str(page_num))
        rf = RequestFactory()
        req = rf.get(base_url.format(page=page_num))

        view = IATIActivityList.as_view()(req).render()
        xml.extend(etree.fromstring(view.content).getchildren())

        link_header = view.get('link')

        if not link_header:
            return xml

        link = requests.utils.parse_header_links(link_header)
        has_next = reduce(lambda acc, x: acc or (
            x['rel'] == 'next'), link, False)

        if has_next:
            return get_result(xml, page_num + 1)
        else:
            return xml

    xml = E('iati-activities', version="2.02")

    final_xml = get_result(xml, 1)
    final_xml.attrib[
        'generated-datetime'
    ] = datetime.datetime.now().isoformat()

    from django.core.files.base import File
    from django.conf import settings
    import uuid

    file_name = "{}.xml".format(uuid.uuid4())
    path = "{}/{}".format(settings.MEDIA_ROOT, file_name)

    xml_file = File(open(path, mode='w'))
    xml_file.write(etree.tostring(final_xml, pretty_print=True))
    xml_file.close()

    return file_name

class DatasetAdmin(admin.ModelAdmin):
    actions = ['really_delete_selected']
    search_fields = ['id', 'name', 'title',
                     'publisher__name', 'publisher__publisher_iati_id']
    list_display = [
        'id',
        'iati_id',
        'name',
        'publisher',
        'title',
        'show_source_url',
        'date_created',
        'export_btn',
        'get_parse_status',
        'get_parse_activity',
        'date_updated',
        'last_found_in_registry',
        'is_parsed',
        'time_to_parse']

    def show_source_url(self, obj):
        return format_html(
            'Open file in new window',
            url=obj.source_url
        )
    show_source_url.allow_tags = True
    show_source_url.short_description = "URL"

    def export_btn(self, obj):
        return format_html(
            'Export',  # NOQA: E501
            id=obj.id
        )
    export_btn.short_description = 'Export XML'
    export_btn.allow_tags = True

    def get_parse_status(self, obj):
        return format_html(
            'Add to parser queue',  # NOQA: E501
            id=obj.id
        )
    get_parse_status.allow_tags = True
    get_parse_status.short_description = "Parse"

    def get_parse_activity(self, obj):
        return format_html(
                "<input type='text' name='activity-id' placeholder='activity id'>Parse Activity",  # NOQA: E501
            id=obj.id)
    get_parse_activity.allow_tags = True
    get_parse_activity.short_description = "Parse Activity"

    def get_urls(self):
        urls = super(DatasetAdmin, self).get_urls()
        extra_urls = [
            url(
                r'^parse-source/$',
                self.admin_site.admin_view(self.parse_source)),
            url(
                r'^add-to-parse-queue/$',
                self.admin_site.admin_view(self.add_to_parse_queue)),
            url(
                r'^parse-xml/(?P<activity_id>[^@$&+,/:;=?]+)$',
                self.admin_site.admin_view(self.parse_activity_view)),
            url(
                r'^export-xml/(?P<id>[^@$&+,/:;=?]+)$',
                self.admin_site.admin_view(self.export_xml),
                name='export-xml'),
        ]
        return extra_urls + urls

    def parse_source(self, request):
        xml_id = request.GET.get('xml_id')
        force = request.GET.get('force', '')
        if force == '0':
            force = False
        else:
            force = True
        obj = get_object_or_404(Dataset, pk=xml_id)
        obj.process(force_reparse=force)
        return HttpResponse(
            'Success', content_type='text/html')

    def add_to_parse_queue(self, request):
        xml_id = request.GET.get('xml_id')
        obj = get_object_or_404(Dataset, pk=xml_id)
        #force_parse_source_by_url(obj.source_url)
        queue = django_rq.get_queue("parser")
        queue.enqueue(force_parse_source_by_url, args=(
            obj.source_url, True), timeout=7200)

        return HttpResponse('Success')

    def parse_activity_view(self, request, activity_id):
        xml_id = request.GET.get('xml_id')
        obj = get_object_or_404(Dataset, pk=xml_id)
        obj.process_activity(activity_id)
        return HttpResponse('Success')

    def export_xml(self, request, id):
        xml_response = export_xml_by_source(request, id)
        # print xml_response
        return HttpResponse(xml_response, content_type='application/xml')

    def get_actions(self, request):
        actions = super(DatasetAdmin, self).get_actions(request)
        del actions['delete_selected']
        return actions

    def really_delete_selected(self, request, queryset):
        for obj in queryset:
            obj.delete()

        if queryset.count() == 1:
            message_bit = "1 IATI data source was"
        else:
            message_bit = "%s IATI data sources were" % queryset.count()
        self.message_user(request, "%s successfully deleted." % message_bit)
    really_delete_selected\
        .short_description = "Delete selected IATI data sources"

class DatasetInline(admin.TabularInline):
    model = Dataset
    extra = 0

class PublisherAdmin(admin.ModelAdmin):
    inlines = [DatasetInline]

    list_display = (
        'publisher_iati_id',
        'display_name',
        'name')

    class Media:
        js = (
            'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js',
            '/static/js/publisher_admin.js',
        )

    def get_urls(self):
        urls = super(PublisherAdmin, self).get_urls()
        extra_urls = [
            url(
                r'^parse-publisher/$',
                self.admin_site.admin_view(self.parse_view)),
        ]
        return extra_urls + urls

    def parse_view(self, request):
        publisher_id = request.GET.get('publisher_id')
        for obj in Dataset.objects.filter(publisher__id=publisher_id):
            obj.process()
        return HttpResponse('Success')

admin.site.register(Codelist, CodeListAdmin)
admin.site.register(Publisher, PublisherAdmin)
admin.site.register(Dataset, DatasetAdmin)
<|endoftext|>