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

The latest version of this package is available at:
<https://github.com/jantman/autosimulationcraft>

##################################################################################
Copyright 2015 Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>

    This file is part of autosimulationcraft.

    autosimulationcraft is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    autosimulationcraft is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with autosimulationcraft.  If not, see <http://www.gnu.org/licenses/>.

The Copyright and Authors attributions contained herein may not be removed or
otherwise altered, except to add the Author attribution of a contributor to
this work. (Additional Terms pursuant to Section 7b of the AGPL v3)
##################################################################################
While not legally required, I sincerely request that anyone who finds
bugs please submit them at <https://github.com/jantman/autosimulationcraft> or
to me via email, and that you send any contributions or improvements
either as a pull request on GitHub, or to me via email.
##################################################################################

AUTHORS:
Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>

"""

VERSION = '0.0.1'
<commit_msg>bump version<commit_after># -*- coding: utf-8 -*-
"""
AutoSimulationCraft

The latest version of this package is available at:
<https://github.com/jantman/autosimulationcraft>

##################################################################################
Copyright 2015 Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>

    This file is part of autosimulationcraft.

    autosimulationcraft is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    autosimulationcraft is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with autosimulationcraft.  If not, see <http://www.gnu.org/licenses/>.

The Copyright and Authors attributions contained herein may not be removed or
otherwise altered, except to add the Author attribution of a contributor to
this work. (Additional Terms pursuant to Section 7b of the AGPL v3)
##################################################################################
While not legally required, I sincerely request that anyone who finds
bugs please submit them at <https://github.com/jantman/autosimulationcraft> or
to me via email, and that you send any contributions or improvements
either as a pull request on GitHub, or to me via email.
##################################################################################

AUTHORS:
Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>

"""

VERSION = '0.0.2'
<|endoftext|>


<commit_before>import logging

from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import PermissionDenied
from django.db import models
from django.forms import Form
from django.http import Http404
from django.shortcuts import redirect
from django.urls import reverse_lazy
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.generic import DeleteView, DetailView, TemplateView
from django.views.generic.edit import FormMixin
from django_filters.views import FilterView

from rdmo.accounts.utils import is_site_manager
from rdmo.core.plugins import get_plugin, get_plugins
from rdmo.core.views import ObjectPermissionMixin, RedirectViewMixin

from ..filters import ProjectFilter
from ..models import Integration, Invite, Membership, Project, Value

logger = logging.getLogger(__name__)

class ProjectsView(LoginRequiredMixin, FilterView):
    template_name = 'projects/projects.html'
    context_object_name = 'projects'
    paginate_by = 20
    filterset_class = ProjectFilter

    def get_queryset(self):
        # prepare projects queryset for this user
        queryset = Project.objects.filter(user=self.request.user)
        for instance in queryset:
            queryset |= instance.get_descendants()
        queryset = queryset.distinct()

        # prepare subquery for role
        membership_subquery = models.Subquery(
            Membership.objects.filter(project=models.OuterRef('pk'), user=self.request.user).values('role')
        )
        queryset = queryset.annotate(role=membership_subquery)

        # prepare subquery for last_changed
        last_changed_subquery = models.Subquery(
            Value.objects.filter(project=models.OuterRef('pk')).order_by('-updated').values('updated')[:1]
        )
        queryset = queryset.annotate(last_changed=models.functions.Greatest('updated', last_changed_subquery))

        # order by last changed
        queryset = queryset.order_by('-last_changed')

        return queryset

    def get_context_data(self, **kwargs):
        context = super(ProjectsView, self).get_context_data(**kwargs)
        context['is_site_manager'] = is_site_manager(self.request.user)
        return context

class SiteProjectsView(LoginRequiredMixin, FilterView):
    template_name = 'projects/site_projects.html'
    context_object_name = 'projects'
    paginate_by = 20
    filterset_class = ProjectFilter
    model = Project

    def get_queryset(self):
        if is_site_manager(self.request.user):
            # prepare projects queryset for the site manager
            queryset = Project.objects.filter_current_site()

            # prepare subquery for last_changed
            last_changed_subquery = models.Subquery(
                Value.objects.filter(project=models.OuterRef('pk')).order_by('-updated').values('updated')[:1]
            )
            queryset = queryset.annotate(last_changed=models.functions.Greatest('updated', last_changed_subquery))

            return queryset
        else:
            raise PermissionDenied()

class ProjectDetailView(ObjectPermissionMixin, DetailView):
    model = Project
    queryset = Project.objects.prefetch_related('issues', 'tasks', 'views')
    permission_required = 'projects.view_project_object'

    def get_context_data(self, **kwargs):
        context = super(ProjectDetailView, self).get_context_data(**kwargs)
        project = context['project']

        memberships = Membership.objects.filter(project=project)
        integrations = Integration.objects.filter(project=project)
        for instance in project.get_ancestors():
            memberships |= Membership.objects.filter(project=instance)
            integrations |= Integration.objects.filter(project=instance)

        context['memberships'] = memberships.distinct().order_by('user__last_name')
        context['integrations'] = integrations.distinct().order_by('provider_key')
        context['providers'] = get_plugins('SERVICE_PROVIDERS')
        context['issues'] = project.issues.active()
        context['snapshots'] = project.snapshots.all()
        context['membership'] = Membership.objects.filter(project=project, user=self.request.user).first()

        return context

class ProjectDeleteView(ObjectPermissionMixin, RedirectViewMixin, DeleteView):
    model = Project
    queryset = Project.objects.all()
    success_url = reverse_lazy('projects')
    permission_required = 'projects.delete_project_object'

class ProjectJoinView(LoginRequiredMixin, RedirectViewMixin, TemplateView):
    template_name = 'core/error.html'

    def get(self, request, token):
        try:
            invite = Invite.objects.get(token=token)

            if invite.is_expired:
                error = _('Sorry, your invitation has been expired.')
                invite.delete()
            elif invite.user and invite.user != request.user:
                error = _('Sorry, but this invitation is for the user "%s".' % invite.user)
            else:
                Membership.objects.create(
                    project=invite.project,
                    user=request.user,
                    role=invite.role
                )
                invite.delete()
                return redirect(invite.project.get_absolute_url())

        except Invite.DoesNotExist:
            error = _('Sorry, the invitation link is not valid.')

        return self.render_to_response({
            'title': _('Error'),
            'errors': [error]
        })

class ProjectLeaveView(ObjectPermissionMixin, RedirectViewMixin, FormMixin, DetailView):
    model = Project
    form_class = Form
    queryset = Project.objects.all()
    success_url = reverse_lazy('projects')
    permission_required = 'projects.leave_project_object'
    template_name = 'projects/project_confirm_leave.html'

    def post(self, request, *args, **kwargs):
        form = self.get_form()
        if form.is_valid() and 'cancel' not in request.POST:
            membership = Membership.objects.filter(project=self.get_object()).get(user=request.user)
            if not membership.is_last_owner:
                membership.delete()

        return redirect(self.success_url)

class ProjectExportView(ObjectPermissionMixin, DetailView):
    model = Project
    queryset = Project.objects.all()
    permission_required = 'projects.export_project_object'

    def render_to_response(self, context, **response_kwargs):
        export_plugin = get_plugin('PROJECT_EXPORTS', self.kwargs.get('format'))
        if export_plugin is None:
            raise Http404

        export_plugin.project = context['project']
        export_plugin.snapshot = None

        return export_plugin.render()

class ProjectQuestionsView(ObjectPermissionMixin, DetailView):
    model = Project
    queryset = Project.objects.all()
    permission_required = 'projects.view_project_object'
    template_name = 'projects/project_questions.html'

    @method_decorator(ensure_csrf_cookie)
    def get(self, request, *args, **kwargs):
        self.object = self.get_object()

        if self.object.catalog is None:
            return redirect('project_error', pk=self.object.pk)
        else:
            context = self.get_context_data(object=self.object)
            return self.render_to_response(context)

class ProjectErrorView(ObjectPermissionMixin, DetailView):
    model = Project
    queryset = Project.objects.all()
    permission_required = 'projects.view_project_object'
    template_name = 'projects/project_error.html'
<commit_msg>Refactor membership table<commit_after>import logging

from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import PermissionDenied
from django.db import models
from django.db.models import F, OuterRef, Subquery
from django.forms import Form
from django.http import Http404
from django.shortcuts import redirect
from django.urls import reverse_lazy
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.generic import DeleteView, DetailView, TemplateView
from django.views.generic.edit import FormMixin
from django_filters.views import FilterView

from rdmo.accounts.utils import is_site_manager
from rdmo.core.plugins import get_plugin, get_plugins
from rdmo.core.views import ObjectPermissionMixin, RedirectViewMixin

from ..filters import ProjectFilter
from ..models import Integration, Invite, Membership, Project, Value

logger = logging.getLogger(__name__)

class ProjectsView(LoginRequiredMixin, FilterView):
    template_name = 'projects/projects.html'
    context_object_name = 'projects'
    paginate_by = 20
    filterset_class = ProjectFilter

    def get_queryset(self):
        # prepare projects queryset for this user
        queryset = Project.objects.filter(user=self.request.user)
        for instance in queryset:
            queryset |= instance.get_descendants()
        queryset = queryset.distinct()

        # prepare subquery for role
        membership_subquery = models.Subquery(
            Membership.objects.filter(project=models.OuterRef('pk'), user=self.request.user).values('role')
        )
        queryset = queryset.annotate(role=membership_subquery)

        # prepare subquery for last_changed
        last_changed_subquery = models.Subquery(
            Value.objects.filter(project=models.OuterRef('pk')).order_by('-updated').values('updated')[:1]
        )
        queryset = queryset.annotate(last_changed=models.functions.Greatest('updated', last_changed_subquery))

        # order by last changed
        queryset = queryset.order_by('-last_changed')

        return queryset

    def get_context_data(self, **kwargs):
        context = super(ProjectsView, self).get_context_data(**kwargs)
        context['is_site_manager'] = is_site_manager(self.request.user)
        return context

class SiteProjectsView(LoginRequiredMixin, FilterView):
    template_name = 'projects/site_projects.html'
    context_object_name = 'projects'
    paginate_by = 20
    filterset_class = ProjectFilter
    model = Project

    def get_queryset(self):
        if is_site_manager(self.request.user):
            # prepare projects queryset for the site manager
            queryset = Project.objects.filter_current_site()

            # prepare subquery for last_changed
            last_changed_subquery = models.Subquery(
                Value.objects.filter(project=models.OuterRef('pk')).order_by('-updated').values('updated')[:1]
            )
            queryset = queryset.annotate(last_changed=models.functions.Greatest('updated', last_changed_subquery))

            return queryset
        else:
            raise PermissionDenied()

class ProjectDetailView(ObjectPermissionMixin, DetailView):
    model = Project
    queryset = Project.objects.prefetch_related('issues', 'tasks', 'views')
    permission_required = 'projects.view_project_object'

    def get_context_data(self, **kwargs):
        context = super(ProjectDetailView, self).get_context_data(**kwargs)
        project = context['project']
        ancestors = project.get_ancestors(include_self=True)

        highest = Membership.objects.filter(project__in=ancestors, user_id=OuterRef('user_id')).order_by('-project__level')
        memberships = Membership.objects.filter(project__in=ancestors) \
                                        .annotate(highest=Subquery(highest.values('project__level')[:1])) \
                                        .filter(highest=F('project__level')) \
                                        .select_related('user')

        integrations = Integration.objects.filter(project__in=ancestors)
        context['memberships'] = memberships.order_by('user__last_name', '-project__level')
        context['integrations'] = integrations.order_by('provider_key', '-project__level')
        context['providers'] = get_plugins('SERVICE_PROVIDERS')
        context['issues'] = project.issues.active()
        context['snapshots'] = project.snapshots.all()
        context['membership'] = Membership.objects.filter(project=project, user=self.request.user).first()

        return context

class ProjectDeleteView(ObjectPermissionMixin, RedirectViewMixin, DeleteView):
    model = Project
    queryset = Project.objects.all()
    success_url = reverse_lazy('projects')
    permission_required = 'projects.delete_project_object'

class ProjectJoinView(LoginRequiredMixin, RedirectViewMixin, TemplateView):
    template_name = 'core/error.html'

    def get(self, request, token):
        try:
            invite = Invite.objects.get(token=token)

            if invite.is_expired:
                error = _('Sorry, your invitation has been expired.')
                invite.delete()
            elif invite.user and invite.user != request.user:
                error = _('Sorry, but this invitation is for the user "%s".' % invite.user)
            else:
                Membership.objects.create(
                    project=invite.project,
                    user=request.user,
                    role=invite.role
                )
                invite.delete()
                return redirect(invite.project.get_absolute_url())

        except Invite.DoesNotExist:
            error = _('Sorry, the invitation link is not valid.')

        return self.render_to_response({
            'title': _('Error'),
            'errors': [error]
        })

class ProjectLeaveView(ObjectPermissionMixin, RedirectViewMixin, FormMixin, DetailView):
    model = Project
    form_class = Form
    queryset = Project.objects.all()
    success_url = reverse_lazy('projects')
    permission_required = 'projects.leave_project_object'
    template_name = 'projects/project_confirm_leave.html'

    def post(self, request, *args, **kwargs):
        form = self.get_form()
        if form.is_valid() and 'cancel' not in request.POST:
            membership = Membership.objects.filter(project=self.get_object()).get(user=request.user)
            if not membership.is_last_owner:
                membership.delete()

        return redirect(self.success_url)

class ProjectExportView(ObjectPermissionMixin, DetailView):
    model = Project
    queryset = Project.objects.all()
    permission_required = 'projects.export_project_object'

    def render_to_response(self, context, **response_kwargs):
        export_plugin = get_plugin('PROJECT_EXPORTS', self.kwargs.get('format'))
        if export_plugin is None:
            raise Http404

        export_plugin.project = context['project']
        export_plugin.snapshot = None

        return export_plugin.render()

class ProjectQuestionsView(ObjectPermissionMixin, DetailView):
    model = Project
    queryset = Project.objects.all()
    permission_required = 'projects.view_project_object'
    template_name = 'projects/project_questions.html'

    @method_decorator(ensure_csrf_cookie)
    def get(self, request, *args, **kwargs):
        self.object = self.get_object()

        if self.object.catalog is None:
            return redirect('project_error', pk=self.object.pk)
        else:
            context = self.get_context_data(object=self.object)
            return self.render_to_response(context)

class ProjectErrorView(ObjectPermissionMixin, DetailView):
    model = Project
    queryset = Project.objects.all()
    permission_required = 'projects.view_project_object'
    template_name = 'projects/project_error.html'
<|endoftext|>


<commit_before>from django.conf import settings
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.db import models
from django.template.defaultfilters import slugify
from django.template.loader import render_to_string

from projects import constants
from projects.utils import diff, dmp, safe_write
from taggit.managers import TaggableManager
from vcs_support.base import get_backend
from vcs_support.utils import Lock

import fnmatch
import os
import fnmatch
import re

class ProjectManager(models.Manager):
    def live(self, *args, **kwargs):
        base_qs = self.filter(skip=False)
        return base_qs.filter(*args, **kwargs)

class Project(models.Model):
    #Auto fields
    pub_date = models.DateTimeField(auto_now_add=True)
    modified_date = models.DateTimeField(auto_now=True)

    #Generally from conf.py
    user = models.ForeignKey(User, related_name='projects')
    name = models.CharField(max_length=255)
    slug = models.SlugField()
    description = models.TextField(blank=True,
        help_text='reStructuredText description of the project')
    repo = models.CharField(max_length=100, blank=True,
            help_text='URL for your code (hg or git). Ex. http://github.com/ericholscher/django-kong.git')
    repo_type = models.CharField(max_length=10, choices=constants.REPO_CHOICES, default='git')
    project_url = models.URLField(blank=True, help_text='the project\'s homepage')
    version = models.CharField(max_length=100, blank=True,
        help_text='project version these docs apply to, i.e. 1.0a')
    copyright = models.CharField(max_length=255, blank=True,
        help_text='project copyright information')
    theme = models.CharField(max_length=20,
        choices=constants.DEFAULT_THEME_CHOICES, default=constants.THEME_DEFAULT,
        help_text='Examples')
    suffix = models.CharField(max_length=10, editable=False, default='.rst')
    default_version = models.CharField(max_length=255, default='latest')
    # In default_branch, None means the backend should choose the appropraite branch. Eg 'master' for git
    default_branch = models.CharField(max_length=255, default=None, null=True,
        blank=True, help_text='What branch "latest" points to. Leave empty to use the default value for your VCS (eg. trunk or master).')
    requirements_file = models.CharField(max_length=255, default=None, null=True, blank=True, help_text='A requirements file needed to build your documentation. Path from the root of your project.')
    documentation_type = models.CharField(max_length=20,
        choices=constants.DOCUMENTATION_CHOICES, default='sphinx',
        help_text='Type of documentation you are building.')

    #Other model data.
    path = models.CharField(help_text="The directory where conf.py lives",
                            max_length=255, editable=False)
    featured = models.BooleanField()
    skip = models.BooleanField()
    use_virtualenv = models.BooleanField(help_text="Install your project inside a virtualenv using setup.py install")
    django_packages_url = models.CharField(max_length=255, blank=True)

    tags = TaggableManager(blank=True)
    objects = ProjectManager()

    class Meta:
        ordering = ('slug',)

    def __unicode__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)
        super(Project, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('projects_detail', args=[self.slug])

    def get_docs_url(self, version_slug=None):
        version = version_slug or self.get_default_version()
        return reverse('docs_detail', kwargs={
            'project_slug': self.slug,
            'version_slug': version,
            'filename': '',
        })

    def get_builds_url(self):
        return reverse('builds_project_list', kwargs={
            'project_slug': self.slug,
        })

    def get_pdf_url(self, version_slug='latest'):
        path = os.path.join(settings.MEDIA_URL,
                                'pdf',
                                self.slug,
                                version_slug,
                                '%s.pdf' % self.slug)
        return path

    def get_pdf_path(self, version_slug='latest'):
        path = os.path.join(settings.MEDIA_ROOT,
                                'pdf',
                                self.slug,
                                version_slug,
                                '%s.pdf' % self.slug)
        return path

    #Doc PATH:
    #MEDIA_ROOT/slug/checkouts/version/<repo>

    @property
    def doc_path(self):
        return os.path.join(settings.DOCROOT, self.slug)

    def checkout_path(self, version='latest'):
        return os.path.join(self.doc_path, 'checkouts', version)

    def venv_path(self, version='latest'):
        return os.path.join(self.doc_path, 'envs', version)

    def venv_bin(self, version='latest', bin='python'):
        return os.path.join(self.venv_path(version), 'bin', bin)

    def full_doc_path(self, version='latest'):
        """
        The path to the documentation root in the project.
        """
        doc_base = self.checkout_path(version)
        for possible_path in ['docs', 'doc', 'Doc']:
            if os.path.exists(os.path.join(doc_base, '%s' % possible_path)):
                return os.path.join(doc_base, '%s' % possible_path)
        #No docs directory, docs are at top-level.
        return doc_base

    def full_build_path(self, version='latest'):
        """
        The path to the build html docs in the project.
        """
        return os.path.join(self.conf_dir(version), "_build", "html")

    def rtd_build_path(self, version="latest"):
        """
        The path to the build html docs in the project.
        """
        return os.path.join(self.doc_path, 'rtd-builds', version)

    def conf_file(self, version='latest'):
        files = self.full_find('conf.py', version)
        if len(files) == 1:
            return files[0]
        elif len(files) > 1:
            for file in files:
                #This is only valid in prod.
                if file.find('doc', 70) != -1:
                    return file
        else:
            print("Could not find conf.py in %s" % self)
            return ''

    def conf_dir(self, version='latest'):
        conf_file = self.conf_file(version)
        if conf_file:
            return conf_file.replace('/conf.py', '')

    @property
    def is_imported(self):
        return bool(self.repo)

    @property
    def has_good_build(self):
        return any([build.success for build in self.builds.all()])

    @property
    def has_versions(self):
        return self.versions.exists()

    @property
    def has_aliases(self):
        return self.aliases.exists()

    @property
    def has_pdf(self, version_slug='latest'):
        return os.path.exists(self.get_pdf_path(version_slug))

    @property
    def sponsored(self):
        return False

    def vcs_repo(self, version='latest'):
        #if hasattr(self, '_vcs_repo'):
            #return self._vcs_repo
        backend = get_backend(self.repo_type)
        if not backend:
            repo = None
        else:
            repo = backend(self, version)
        #self._vcs_repo = repo
        return repo

    @property
    def contribution_backend(self):
        if hasattr(self, '_contribution_backend'):
            return self._contribution_backend
        if not self.vcs_repo:
            cb = None
        else:
            cb = self.vcs_repo.get_contribution_backend()
        self._contribution_backend = cb
        return cb

    def repo_lock(self, timeout=5, polling_interval=0.2):
        return Lock(self.slug, timeout, polling_interval)

    def find(self, file, version):
        """
        A balla API to find files inside of a projects dir.
        """
        matches = []
        for root, dirnames, filenames in os.walk(self.full_doc_path(version)):
            for filename in fnmatch.filter(filenames, file):
                matches.append(os.path.join(root, filename))
        return matches

    def full_find(self, file, version):
        """
        A balla API to find files inside of a projects dir.
        """
        matches = []
        for root, dirnames, filenames in os.walk(self.checkout_path(version)):
            for filename in fnmatch.filter(filenames, file):
                matches.append(os.path.join(root, filename))
        return matches

    def get_latest_build(self):
        try:
            return self.builds.all()[0]
        except IndexError:
            return None

    def active_versions(self):
        return self.versions.filter(built=True, active=True) | self.versions.filter(active=True, uploaded=True)

    @property
    def whitelisted(self):
        return self.user.get_profile().whitelisted

    #File Building stuff.

    #Not sure if this is used
    def get_top_level_files(self):
        return self.files.live(parent__isnull=True).order_by('ordering')

    def get_index_filename(self):
        return os.path.join(self.path, 'index.rst')

    def get_rendered_index(self):
        return render_to_string('projects/index.rst.html', {'project': self})

    def write_index(self):
        if not self.is_imported:
            safe_write(self.get_index_filename(), self.get_rendered_index())

    def get_latest_revisions(self):
        revision_qs = FileRevision.objects.filter(file__project=self,
            file__status=constants.LIVE_STATUS)
        return revision_qs.order_by('-created_date')

    def get_default_version(self):
        """
        Get the default version (slug).

        Returns self.default_version if the version with that slug actually
        exists (is built and published). Otherwise returns 'latest'.
        """
        # latest is a special case where we don't have to check if it exists
        if self.default_version == 'latest':
            return self.default_version
        # check if the default_version exists
        version_qs = self.versions.filter(
            slug=self.default_version,
            active=True
        )
        if version_qs.exists():
            return self.default_version
        return 'latest'

class FileManager(models.Manager):
    def live(self, *args, **kwargs):
        base_qs = self.filter(status=constants.LIVE_STATUS)
        return base_qs.filter(*args, **kwargs)

class File(models.Model):
    project = models.ForeignKey(Project, related_name='files')
    parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
    heading = models.CharField(max_length=255)
    slug = models.SlugField()
    content = models.TextField()
    denormalized_path = models.CharField(max_length=255, editable=False)
    ordering = models.PositiveSmallIntegerField(default=1)
    status = models.PositiveSmallIntegerField(choices=constants.STATUS_CHOICES,
        default=constants.LIVE_STATUS)

    objects = FileManager()

    class Meta:
        ordering = ('denormalized_path',)

    def __unicode__(self):
        return '%s: %s' % (self.project.name, self.heading)

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.heading)

        if self.parent:
            path = '%s/%s' % (self.parent.denormalized_path, self.slug)
        else:
            path = self.slug

        self.denormalized_path = path

        super(File, self).save(*args, **kwargs)

        if self.children:
            def update_children(children):
                for child in children:
                    child.save()
                    update_children(child.children.all())
            update_children(self.children.all())
        #Update modified time on project.
        self.project.save()

    @property
    def depth(self):
        return len(self.denormalized_path.split('/'))

    def create_revision(self, old_content, comment):
        FileRevision.objects.create(
            file=self,
            comment=comment,
            diff=diff(self.content, old_content)
        )

    @property
    def current_revision(self):
        return self.revisions.filter(is_reverted=False)[0]

    def get_html_diff(self, rev_from, rev_to):
        rev_from = self.revisions.get(revision_number=rev_from)
        rev_to = self.revisions.get(revision_number=rev_to)

        diffs = dmp.diff_main(rev_from.diff, rev_to.diff)
        return dmp.diff_prettyHtml(diffs)

    def revert_to(self, revision_number):
        revision = self.revisions.get(revision_number=revision_number)
        revision.apply()

    @property
    def filename(self):
        return os.path.join(
            self.project.path,
            '%s.rst' % self.denormalized_path
        )

    def get_rendered(self):
        return render_to_string('projects/doc_file.rst.html', {'file': self})

    def write_to_disk(self):
        safe_write(self.filename, self.get_rendered())

    @models.permalink
    def get_absolute_url(self):
        return ('docs_detail', [self.project.slug, 'en', 'latest', self.denormalized_path + '.html'])

class FileRevision(models.Model):
    file = models.ForeignKey(File, related_name='revisions')
    comment = models.TextField(blank=True)
    diff = models.TextField(blank=True)
    created_date = models.DateTimeField(auto_now_add=True)

    revision_number = models.IntegerField()
    is_reverted = models.BooleanField(default=False)

    class Meta:
        ordering = ('-revision_number',)

    def __unicode__(self):
        return self.comment or '%s #%s' % (self.file.heading, self.revision_number)

    def get_file_content(self):
        """
        Apply the series of diffs after this revision in reverse order,
        bringing the content back to the state it was in this revision
        """
        after = self.file.revisions.filter(revision_number__gt=self.revision_number)
        content = self.file.content

        for revision in after:
            patch = dmp.patch_fromText(revision.diff)
            content = dmp.patch_apply(patch, content)[0]

        return content

    def apply(self):
        original_content = self.file.content

        # store the old content on the file
        self.file.content = self.get_file_content()
        self.file.save()

        # mark reverted changesets
        reverted_qs = self.file.revisions.filter(revision_number__gt=self.revision_number)
        reverted_qs.update(is_reverted=True)

        # create a new revision
        FileRevision.objects.create(
            file=self.file,
            comment='Reverted to #%s' % self.revision_number,
            diff=diff(self.file.content, original_content)
        )

    def save(self, *args, **kwargs):
        if not self.pk:
            max_rev = self.file.revisions.aggregate(max=models.Max('revision_number'))
            if max_rev['max'] is None:
                self.revision_number = 1
            else:
                self.revision_number = max_rev['max'] + 1
        super(FileRevision, self).save(*args, **kwargs)

class ImportedFile(models.Model):
    project = models.ForeignKey(Project, related_name='imported_files')
    name = models.CharField(max_length=255)
    slug = models.SlugField()
    path = models.CharField(max_length=255)
    md5 = models.CharField(max_length=255)

    @models.permalink
    def get_absolute_url(self):
        return ('docs_detail', [self.project.slug, 'en', 'latest', self.path])

    def __unicode__(self):
        return '%s: %s' % (self.name, self.project)
<commit_msg>Handle users without profiles.<commit_after>from django.conf import settings
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.db import models
from django.template.defaultfilters import slugify
from django.template.loader import render_to_string

from projects import constants
from projects.utils import diff, dmp, safe_write
from taggit.managers import TaggableManager
from vcs_support.base import get_backend
from vcs_support.utils import Lock

import fnmatch
import os
import fnmatch
import re

class ProjectManager(models.Manager):
    def live(self, *args, **kwargs):
        base_qs = self.filter(skip=False)
        return base_qs.filter(*args, **kwargs)

class Project(models.Model):
    #Auto fields
    pub_date = models.DateTimeField(auto_now_add=True)
    modified_date = models.DateTimeField(auto_now=True)

    #Generally from conf.py
    user = models.ForeignKey(User, related_name='projects')
    name = models.CharField(max_length=255)
    slug = models.SlugField()
    description = models.TextField(blank=True,
        help_text='reStructuredText description of the project')
    repo = models.CharField(max_length=100, blank=True,
            help_text='URL for your code (hg or git). Ex. http://github.com/ericholscher/django-kong.git')
    repo_type = models.CharField(max_length=10, choices=constants.REPO_CHOICES, default='git')
    project_url = models.URLField(blank=True, help_text='the project\'s homepage')
    version = models.CharField(max_length=100, blank=True,
        help_text='project version these docs apply to, i.e. 1.0a')
    copyright = models.CharField(max_length=255, blank=True,
        help_text='project copyright information')
    theme = models.CharField(max_length=20,
        choices=constants.DEFAULT_THEME_CHOICES, default=constants.THEME_DEFAULT,
        help_text='Examples')
    suffix = models.CharField(max_length=10, editable=False, default='.rst')
    default_version = models.CharField(max_length=255, default='latest')
    # In default_branch, None means the backend should choose the appropraite branch. Eg 'master' for git
    default_branch = models.CharField(max_length=255, default=None, null=True,
        blank=True, help_text='What branch "latest" points to. Leave empty to use the default value for your VCS (eg. trunk or master).')
    requirements_file = models.CharField(max_length=255, default=None, null=True, blank=True, help_text='A requirements file needed to build your documentation. Path from the root of your project.')
    documentation_type = models.CharField(max_length=20,
        choices=constants.DOCUMENTATION_CHOICES, default='sphinx',
        help_text='Type of documentation you are building.')

    #Other model data.
    path = models.CharField(help_text="The directory where conf.py lives",
                            max_length=255, editable=False)
    featured = models.BooleanField()
    skip = models.BooleanField()
    use_virtualenv = models.BooleanField(help_text="Install your project inside a virtualenv using setup.py install")
    django_packages_url = models.CharField(max_length=255, blank=True)

    tags = TaggableManager(blank=True)
    objects = ProjectManager()

    class Meta:
        ordering = ('slug',)

    def __unicode__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)
        super(Project, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('projects_detail', args=[self.slug])

    def get_docs_url(self, version_slug=None):
        version = version_slug or self.get_default_version()
        return reverse('docs_detail', kwargs={
            'project_slug': self.slug,
            'version_slug': version,
            'filename': '',
        })

    def get_builds_url(self):
        return reverse('builds_project_list', kwargs={
            'project_slug': self.slug,
        })

    def get_pdf_url(self, version_slug='latest'):
        path = os.path.join(settings.MEDIA_URL,
                                'pdf',
                                self.slug,
                                version_slug,
                                '%s.pdf' % self.slug)
        return path

    def get_pdf_path(self, version_slug='latest'):
        path = os.path.join(settings.MEDIA_ROOT,
                                'pdf',
                                self.slug,
                                version_slug,
                                '%s.pdf' % self.slug)
        return path

    #Doc PATH:
    #MEDIA_ROOT/slug/checkouts/version/<repo>

    @property
    def doc_path(self):
        return os.path.join(settings.DOCROOT, self.slug)

    def checkout_path(self, version='latest'):
        return os.path.join(self.doc_path, 'checkouts', version)

    def venv_path(self, version='latest'):
        return os.path.join(self.doc_path, 'envs', version)

    def venv_bin(self, version='latest', bin='python'):
        return os.path.join(self.venv_path(version), 'bin', bin)

    def full_doc_path(self, version='latest'):
        """
        The path to the documentation root in the project.
        """
        doc_base = self.checkout_path(version)
        for possible_path in ['docs', 'doc', 'Doc']:
            if os.path.exists(os.path.join(doc_base, '%s' % possible_path)):
                return os.path.join(doc_base, '%s' % possible_path)
        #No docs directory, docs are at top-level.
        return doc_base

    def full_build_path(self, version='latest'):
        """
        The path to the build html docs in the project.
        """
        return os.path.join(self.conf_dir(version), "_build", "html")

    def rtd_build_path(self, version="latest"):
        """
        The path to the build html docs in the project.
        """
        return os.path.join(self.doc_path, 'rtd-builds', version)

    def conf_file(self, version='latest'):
        files = self.full_find('conf.py', version)
        if len(files) == 1:
            return files[0]
        elif len(files) > 1:
            for file in files:
                #This is only valid in prod.
                if file.find('doc', 70) != -1:
                    return file
        else:
            print("Could not find conf.py in %s" % self)
            return ''

    def conf_dir(self, version='latest'):
        conf_file = self.conf_file(version)
        if conf_file:
            return conf_file.replace('/conf.py', '')

    @property
    def is_imported(self):
        return bool(self.repo)

    @property
    def has_good_build(self):
        return any([build.success for build in self.builds.all()])

    @property
    def has_versions(self):
        return self.versions.exists()

    @property
    def has_aliases(self):
        return self.aliases.exists()

    @property
    def has_pdf(self, version_slug='latest'):
        return os.path.exists(self.get_pdf_path(version_slug))

    @property
    def sponsored(self):
        return False

    def vcs_repo(self, version='latest'):
        #if hasattr(self, '_vcs_repo'):
            #return self._vcs_repo
        backend = get_backend(self.repo_type)
        if not backend:
            repo = None
        else:
            repo = backend(self, version)
        #self._vcs_repo = repo
        return repo

    @property
    def contribution_backend(self):
        if hasattr(self, '_contribution_backend'):
            return self._contribution_backend
        if not self.vcs_repo:
            cb = None
        else:
            cb = self.vcs_repo.get_contribution_backend()
        self._contribution_backend = cb
        return cb

    def repo_lock(self, timeout=5, polling_interval=0.2):
        return Lock(self.slug, timeout, polling_interval)

    def find(self, file, version):
        """
        A balla API to find files inside of a projects dir.
        """
        matches = []
        for root, dirnames, filenames in os.walk(self.full_doc_path(version)):
            for filename in fnmatch.filter(filenames, file):
                matches.append(os.path.join(root, filename))
        return matches

    def full_find(self, file, version):
        """
        A balla API to find files inside of a projects dir.
        """
        matches = []
        for root, dirnames, filenames in os.walk(self.checkout_path(version)):
            for filename in fnmatch.filter(filenames, file):
                matches.append(os.path.join(root, filename))
        return matches

    def get_latest_build(self):
        try:
            return self.builds.all()[0]
        except IndexError:
            return None

    def active_versions(self):
        return self.versions.filter(built=True, active=True) | self.versions.filter(active=True, uploaded=True)

    @property
    def whitelisted(self):
        try:
            return self.user.get_profile().whitelisted
        except:
            #Bare except so we don't have to import user.models.UserProfile
            return False

    #File Building stuff.

    #Not sure if this is used
    def get_top_level_files(self):
        return self.files.live(parent__isnull=True).order_by('ordering')

    def get_index_filename(self):
        return os.path.join(self.path, 'index.rst')

    def get_rendered_index(self):
        return render_to_string('projects/index.rst.html', {'project': self})

    def write_index(self):
        if not self.is_imported:
            safe_write(self.get_index_filename(), self.get_rendered_index())

    def get_latest_revisions(self):
        revision_qs = FileRevision.objects.filter(file__project=self,
            file__status=constants.LIVE_STATUS)
        return revision_qs.order_by('-created_date')

    def get_default_version(self):
        """
        Get the default version (slug).

        Returns self.default_version if the version with that slug actually
        exists (is built and published). Otherwise returns 'latest'.
        """
        # latest is a special case where we don't have to check if it exists
        if self.default_version == 'latest':
            return self.default_version
        # check if the default_version exists
        version_qs = self.versions.filter(
            slug=self.default_version,
            active=True
        )
        if version_qs.exists():
            return self.default_version
        return 'latest'

class FileManager(models.Manager):
    def live(self, *args, **kwargs):
        base_qs = self.filter(status=constants.LIVE_STATUS)
        return base_qs.filter(*args, **kwargs)

class File(models.Model):
    project = models.ForeignKey(Project, related_name='files')
    parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
    heading = models.CharField(max_length=255)
    slug = models.SlugField()
    content = models.TextField()
    denormalized_path = models.CharField(max_length=255, editable=False)
    ordering = models.PositiveSmallIntegerField(default=1)
    status = models.PositiveSmallIntegerField(choices=constants.STATUS_CHOICES,
        default=constants.LIVE_STATUS)

    objects = FileManager()

    class Meta:
        ordering = ('denormalized_path',)

    def __unicode__(self):
        return '%s: %s' % (self.project.name, self.heading)

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.heading)

        if self.parent:
            path = '%s/%s' % (self.parent.denormalized_path, self.slug)
        else:
            path = self.slug

        self.denormalized_path = path

        super(File, self).save(*args, **kwargs)

        if self.children:
            def update_children(children):
                for child in children:
                    child.save()
                    update_children(child.children.all())
            update_children(self.children.all())
        #Update modified time on project.
        self.project.save()

    @property
    def depth(self):
        return len(self.denormalized_path.split('/'))

    def create_revision(self, old_content, comment):
        FileRevision.objects.create(
            file=self,
            comment=comment,
            diff=diff(self.content, old_content)
        )

    @property
    def current_revision(self):
        return self.revisions.filter(is_reverted=False)[0]

    def get_html_diff(self, rev_from, rev_to):
        rev_from = self.revisions.get(revision_number=rev_from)
        rev_to = self.revisions.get(revision_number=rev_to)

        diffs = dmp.diff_main(rev_from.diff, rev_to.diff)
        return dmp.diff_prettyHtml(diffs)

    def revert_to(self, revision_number):
        revision = self.revisions.get(revision_number=revision_number)
        revision.apply()

    @property
    def filename(self):
        return os.path.join(
            self.project.path,
            '%s.rst' % self.denormalized_path
        )

    def get_rendered(self):
        return render_to_string('projects/doc_file.rst.html', {'file': self})

    def write_to_disk(self):
        safe_write(self.filename, self.get_rendered())

    @models.permalink
    def get_absolute_url(self):
        return ('docs_detail', [self.project.slug, 'en', 'latest', self.denormalized_path + '.html'])

class FileRevision(models.Model):
    file = models.ForeignKey(File, related_name='revisions')
    comment = models.TextField(blank=True)
    diff = models.TextField(blank=True)
    created_date = models.DateTimeField(auto_now_add=True)

    revision_number = models.IntegerField()
    is_reverted = models.BooleanField(default=False)

    class Meta:
        ordering = ('-revision_number',)

    def __unicode__(self):
        return self.comment or '%s #%s' % (self.file.heading, self.revision_number)

    def get_file_content(self):
        """
        Apply the series of diffs after this revision in reverse order,
        bringing the content back to the state it was in this revision
        """
        after = self.file.revisions.filter(revision_number__gt=self.revision_number)
        content = self.file.content

        for revision in after:
            patch = dmp.patch_fromText(revision.diff)
            content = dmp.patch_apply(patch, content)[0]

        return content

    def apply(self):
        original_content = self.file.content

        # store the old content on the file
        self.file.content = self.get_file_content()
        self.file.save()

        # mark reverted changesets
        reverted_qs = self.file.revisions.filter(revision_number__gt=self.revision_number)
        reverted_qs.update(is_reverted=True)

        # create a new revision
        FileRevision.objects.create(
            file=self.file,
            comment='Reverted to #%s' % self.revision_number,
            diff=diff(self.file.content, original_content)
        )

    def save(self, *args, **kwargs):
        if not self.pk:
            max_rev = self.file.revisions.aggregate(max=models.Max('revision_number'))
            if max_rev['max'] is None:
                self.revision_number = 1
            else:
                self.revision_number = max_rev['max'] + 1
        super(FileRevision, self).save(*args, **kwargs)

class ImportedFile(models.Model):
    project = models.ForeignKey(Project, related_name='imported_files')
    name = models.CharField(max_length=255)
    slug = models.SlugField()
    path = models.CharField(max_length=255)
    md5 = models.CharField(max_length=255)

    @models.permalink
    def get_absolute_url(self):
        return ('docs_detail', [self.project.slug, 'en', 'latest', self.path])

    def __unicode__(self):
        return '%s: %s' % (self.name, self.project)
<|endoftext|>


<commit_before>from ledger import makeLedgerForSave
import sys, os

from http.server import BaseHTTPRequestHandler, HTTPServer
import time

hostName = "localhost"
hostPort = 12852

basePath = sys.argv[0][:sys.argv[0].rfind('start.py')]

f = open(basePath + 'base.html', 'r')
basehtml = f.read()
f.close()

path = 'C:/Python33/stellarisscorechecker/ver2/2204.01.07.sav'

class LedgerServer(BaseHTTPRequestHandler):
    def do_GET(self):
        global path
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()

##        self.wfile.write(bytes("<title>Title goes here.</title>", "utf-8"))
##        self.wfile.write(bytes("
This is a test.
", "utf-8"))
##        self.wfile.write(bytes("
You accessed path: %s
" % self.path, "utf-8"))
##        self.wfile.write(bytes("", "utf-8"))

        #try:
        if (True):
            games = [i for i in os.listdir(path)]
            saves = []
            for i in games:

                svs = [path + '/' + i + '/' + j for j in os.listdir(path + '/' + i)]

                saves.extend(svs)
            if (len(saves)):
                least = saves[0]

                for i in range(1, len(saves)):
                    if (os.path.getmtime(saves[i]) > os.path.getmtime(least)):
                        least = saves[i]

                led = makeLedgerForSave(least, basePath)

                result = basehtml.replace('{{HERE}}', led)
                self.wfile.write(bytes(result, "utf-8"))
            else:
                self.wfile.write(bytes('No save found', "utf-8"))
        #except:
        #    self.wfile.write(bytes('Internal server error', "utf-8"))

if (len(sys.argv) > 1):
    savespath = sys.argv[1]
    f = open(sys.argv[0][:sys.argv[0].rfind('start.py')] + 'path.txt', 'w')
    f.write(savespath)
    f.close()

    input("Path successfully configured.")
else:
    if (os.path.exists('path.txt')):
        f = open('path.txt', 'r')
        path = f.read()
        f.close()

        if (path[-1] == '/' or path[-1] == '\\'):
            path = path[:len(path)-1]

        myServer = HTTPServer((hostName, hostPort), LedgerServer)
        print("Server Starts - %s:%s" % (hostName, hostPort))

        try:
            myServer.serve_forever()
        except KeyboardInterrupt:
            pass

        myServer.server_close()
        print("Server Stops - %s:%s" % (hostName, hostPort))
    else:
        input("Error: Save directory path not set")
<commit_msg>Only use the game save file in case the folder contains other files<commit_after>from ledger import makeLedgerForSave
import sys, os

from http.server import BaseHTTPRequestHandler, HTTPServer
import time

hostName = "localhost"
hostPort = 12852

basePath = sys.argv[0][:sys.argv[0].rfind('start.py')]

f = open(basePath + 'base.html', 'r')
basehtml = f.read()
f.close()

path = 'C:/Python33/stellarisscorechecker/ver2/2204.01.07.sav'

class LedgerServer(BaseHTTPRequestHandler):
    def do_GET(self):
        global path
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()

##        self.wfile.write(bytes("<title>Title goes here.</title>", "utf-8"))
##        self.wfile.write(bytes("
This is a test.
", "utf-8"))
##        self.wfile.write(bytes("
You accessed path: %s
" % self.path, "utf-8"))
##        self.wfile.write(bytes("", "utf-8"))

        #try:
        if (True):
            games = [i for i in os.listdir(path)]
            saves = []
            for i in games:

                svs = [path + '/' + i + '/' + j for j in os.listdir(path + '/' + i) if j.endswith(".sav")]

                saves.extend(svs)
            if (len(saves)):
                least = saves[0]

                for i in range(1, len(saves)):
                    if (os.path.getmtime(saves[i]) > os.path.getmtime(least)):
                        least = saves[i]

                led = makeLedgerForSave(least, basePath)

                result = basehtml.replace('{{HERE}}', led)
                self.wfile.write(bytes(result, "utf-8"))
            else:
                self.wfile.write(bytes('No save found', "utf-8"))
        #except:
        #    self.wfile.write(bytes('Internal server error', "utf-8"))

if (len(sys.argv) > 1):
    savespath = sys.argv[1]
    f = open(sys.argv[0][:sys.argv[0].rfind('start.py')] + 'path.txt', 'w')
    f.write(savespath)
    f.close()

    input("Path successfully configured.")
else:
    if (os.path.exists('path.txt')):
        f = open('path.txt', 'r')
        path = f.read()
        f.close()

        if (path[-1] == '/' or path[-1] == '\\'):
            path = path[:len(path)-1]

        myServer = HTTPServer((hostName, hostPort), LedgerServer)
        print("Server Starts - %s:%s" % (hostName, hostPort))

        try:
            myServer.serve_forever()
        except KeyboardInterrupt:
            pass

        myServer.server_close()
        print("Server Stops - %s:%s" % (hostName, hostPort))
    else:
        input("Error: Save directory path not set")
<|endoftext|>


<commit_before>#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Standard library
import argparse
import multiprocessing
from pprint import pprint
import random
import sys
# Third-party
import ggplot
import pandas
# RPG Dice
from .rulesets import dw
from .rulesets import sweote

args = None
rulemod = None
srand = random.SystemRandom()

def register_rules(subparser):
    for mod in sys.modules:
        parts = mod.split(".")
        if len(parts) == 3 and parts[1] == "rulesets":
            try:
                sys.modules[mod].setup(subparser)
            except:
                pass

def parser_setup():
    """Instantiate, configure and return an ArgumentParser instance."""

    def deformat_int(string):
        """Remove commas from a string and return int"""
        return int(string.replace(",", ""))

    # Top level argument parser
    argparser = argparse.ArgumentParser(description=__doc__)
    argparser.add_argument("-r", "--rolls", default="10,000",
                           type=deformat_int, help="Number of rolls to "
                           "simulate per dice combination (default: "
                           "%(default)s)")
    argparser.add_argument("-d", "--debug", action="store_true")
    argparser.add_argument("--dumpsave", action="store_true")
    argparser.add_argument("--nograph", action="store_false", dest="graph")
    # Sub-parser for modules to register themselves
    subparser = argparser.add_subparsers(title="Ruleset subcommands:",
                                         dest="ruleset", metavar="RULESET" )
    return (argparser, subparser)

def main():
    global args, ruleset
    # Arguments Parser
    argparser, subparser = parser_setup()
    register_rules(subparser)
    args = argparser.parse_args()
    rulemod = sys.modules["rpgdice.rulesets.%s" % args.ruleset]
    rulemod.prepare(args, srand)

    if args.debug:
        print "DEBUG: args", args
        print

    results = list()
    pool = multiprocessing.Pool()
    try:
        for result in pool.map(rulemod.simulate_rolls, rulemod.variables):
            results.extend(result)
        pool.close()
        pool.join()
    except KeyboardInterrupt:
        sys.exit(130)
    if args.debug:
        print "DEBUG: results:"
        pprint(results)
        print

    columns = ("Batch", rulemod.variables_label, rulemod.outcomes_label,
               "Count", "Percent")
    data = pandas.DataFrame.from_records(results, columns=columns)
    for i in rulemod.batches:
        batch = rulemod.batches[i]

        # plot_data
        plot_data = data[data["Batch"] == i]
        plot_data.index = range(1, len(plot_data) + 1)
        if args.debug:
            print "DEBUG: plot_data:"
            pprint(plot_data)
            print

        # Graph Defaults
        conf = dict()
        # colors
        colors_lower = ["#ff0000", "#cc0000", "#993300", "#666600"]
        colors_upper = ["#006666", "#003399", "#0000cc", "#0000ff"]
        colors_mid = ["#000000", ]
        color_count = len(rulemod.variables) - 1
        if color_count % 2 == 0:
            lower_slice = (color_count / 2) * -1
            upper_slice = color_count / 2
        else:
            lower_slice = ((color_count - 1) / 2) * -1
            upper_slice = (color_count + 1) / 2
        conf["color_list"] = (colors_lower[lower_slice:] + colors_mid +
                               colors_upper[0:upper_slice])

        # conf from batch
        batch_items = ("color_list", "graph_type", "limits", "scale_breaks",
                       "scale_labels", "title", "variables_label")
        for item in batch_items:
            try:
                conf[item] = batch[item]
            except:
                try:
                    conf[item] = getattr(rulemod, item)
                except:
                    if item not in conf:
                        conf[item] = None
        if args.debug:
            print "DEBUG: conf:"
            pprint(conf)
            print

        # Create plot
        if args.graph:
            plot = (ggplot.ggplot(ggplot.aes(x=rulemod.outcomes_label,
                                             y="Percent",
                                             color=conf["variables_label"]),
                                  data=plot_data) +
                    ggplot.ggtitle(conf["title"]) +
                    ggplot.scale_x_discrete(breaks=conf["scale_breaks"],
                                            labels=conf["scale_labels"]) +
                    ggplot.theme_gray() +
                    ggplot.scale_colour_manual(values=conf["color_list"])
                    )
            if conf["limits"]:
                plot += ggplot.ylim(conf["limits"][0], conf["limits"][1])
            if conf["graph_type"] == "bars":
                plot += ggplot.geom_line(size=20)
            else:
                plot += ggplot.geom_line()
                plot += ggplot.geom_point(alpha=0.3, size=50)
            plot.rcParams["font.family"] = "monospace"
            if hasattr(rulemod, "update_plot"):
                plot = rulemod.update_plot(i, batch, conf, plot)
            if args.dumpsave:
                filename = "/dev/null"
            else:
                suffix = str()
                if "file_suffix" in batch:
                    suffix = batch["file_suffix"]
                filename = "%s%02d%s.png" % (args.ruleset, i, suffix)
            ggplot.ggsave(filename, plot, format="png", dpi=300)

    return 0
<commit_msg>added percent text to "bar" graphs<commit_after>#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Standard library
import argparse
import multiprocessing
from pprint import pprint
import random
import sys
# Third-party
import ggplot
import pandas
# RPG Dice
from .rulesets import dw
from .rulesets import sweote

args = None
rulemod = None
srand = random.SystemRandom()

def register_rules(subparser):
    for mod in sys.modules:
        parts = mod.split(".")
        if len(parts) == 3 and parts[1] == "rulesets":
            try:
                sys.modules[mod].setup(subparser)
            except:
                pass

def parser_setup():
    """Instantiate, configure and return an ArgumentParser instance."""

    def deformat_int(string):
        """Remove commas from a string and return int"""
        return int(string.replace(",", ""))

    # Top level argument parser
    argparser = argparse.ArgumentParser(description=__doc__)
    argparser.add_argument("-r", "--rolls", default="10,000",
                           type=deformat_int, help="Number of rolls to "
                           "simulate per dice combination (default: "
                           "%(default)s)")
    argparser.add_argument("-d", "--debug", action="store_true")
    argparser.add_argument("--dumpsave", action="store_true")
    argparser.add_argument("--nograph", action="store_false", dest="graph")
    # Sub-parser for modules to register themselves
    subparser = argparser.add_subparsers(title="Ruleset subcommands:",
                                         dest="ruleset", metavar="RULESET" )
    return (argparser, subparser)

def main():
    global args, ruleset
    # Arguments Parser
    argparser, subparser = parser_setup()
    register_rules(subparser)
    args = argparser.parse_args()
    rulemod = sys.modules["rpgdice.rulesets.%s" % args.ruleset]
    rulemod.prepare(args, srand)

    if args.debug:
        print "DEBUG: args", args
        print

    results = list()
    pool = multiprocessing.Pool()
    try:
        for result in pool.map(rulemod.simulate_rolls, rulemod.variables):
            results.extend(result)
        pool.close()
        pool.join()
    except KeyboardInterrupt:
        sys.exit(130)
    if args.debug:
        print "DEBUG: results:"
        pprint(results)
        print

    columns = ("Batch", rulemod.variables_label, rulemod.outcomes_label,
               "Count", "Percent")
    data = pandas.DataFrame.from_records(results, columns=columns)
    for i in rulemod.batches:
        batch = rulemod.batches[i]

        # plot_data
        plot_data = data[data["Batch"] == i]
        plot_data.index = range(1, len(plot_data) + 1)
        if args.debug:
            print "DEBUG: plot_data:"
            pprint(plot_data)
            print

        # Graph Defaults
        conf = dict()
        # colors
        colors_lower = ["#ff0000", "#cc0000", "#993300", "#666600"]
        colors_upper = ["#006666", "#003399", "#0000cc", "#0000ff"]
        colors_mid = ["#000000", ]
        color_count = len(rulemod.variables) - 1
        if color_count % 2 == 0:
            lower_slice = (color_count / 2) * -1
            upper_slice = color_count / 2
        else:
            lower_slice = ((color_count - 1) / 2) * -1
            upper_slice = (color_count + 1) / 2
        conf["color_list"] = (colors_lower[lower_slice:] + colors_mid +
                               colors_upper[0:upper_slice])

        # conf from batch
        batch_items = ("color_list", "graph_type", "limits", "scale_breaks",
                       "scale_labels", "title", "variables_label")
        for item in batch_items:
            try:
                conf[item] = batch[item]
            except:
                try:
                    conf[item] = getattr(rulemod, item)
                except:
                    if item not in conf:
                        conf[item] = None
        if args.debug:
            print "DEBUG: conf:"
            pprint(conf)
            print

        # Create plot
        if args.graph:
            plot = (ggplot.ggplot(ggplot.aes(x=rulemod.outcomes_label,
                                             y="Percent",
                                             color=conf["variables_label"]),
                                  data=plot_data) +
                    ggplot.ggtitle(conf["title"]) +
                    ggplot.scale_x_discrete(breaks=conf["scale_breaks"],
                                            labels=conf["scale_labels"]) +
                    ggplot.theme_gray() +
                    ggplot.scale_colour_manual(values=conf["color_list"])
                    )
            plot.rcParams["font.family"] = "monospace"
            if conf["limits"]:
                plot += ggplot.ylim(conf["limits"][0], conf["limits"][1])
            if conf["graph_type"] == "bars":
                plot += ggplot.geom_line(size=20)
                text_data = plot_data[plot_data["Count"] > 0]
                text_data.index = range(0, len(text_data))
                outcomes = dict(text_data[rulemod.outcomes_label])
                percents = dict(text_data["Percent"])
                for k in outcomes:
                    percent = "%4.1f%%" % percents[k]
                    x = outcomes[k]
                    y = percents[k] + 4
                    color = conf["color_list"][k]
                    plot += ggplot.geom_text(label=[percent, ], x=[x, x + 1],
                         y=[y, y - 1], color=color)
            else:
                plot += ggplot.geom_line()
                plot += ggplot.geom_point(alpha=0.3, size=50)
            if hasattr(rulemod, "update_plot"):
                plot = rulemod.update_plot(i, batch, conf, plot)
            if args.dumpsave:
                filename = "/dev/null"
            else:
                suffix = str()
                if "file_suffix" in batch:
                    suffix = batch["file_suffix"]
                filename = "%s%02d%s.png" % (args.ruleset, i, suffix)
            ggplot.ggsave(filename, plot, format="png", dpi=300)

    return 0
<|endoftext|>


<commit_before>from Config import *

# Not sure what this number does, but we need some threshold that we'd like to
# avoid crossing.
setOption("BadnessThreshold", 42)

# Ignore documentation issues.
addFilter('no-manual-page-for-binary')
addFilter('no-documentation')
addFilter('name-repeated-in-summary')

# Ignore spelling errors unilt there's a support for custom dictionaries.
# TODO: add such support.
addFilter('spelling-error')

# Ignore unversioned bundled provides.
addFilter('unversioned-explicit-provides bundled\([a-z\-]+\)')

# Don't care about groups.
addFilter('non-standard-group')

# Ignore all lint warnings in submodules:
addFilter('third_party/submodules/')
# Ignore all lint warnings in symlinks from submodules.
addFilter('SPECS/cmake.spec')
addFilter('SPECS/gdb.spec')
addFilter('grub2\.(x86_64|src|spec)')
addFilter('grub2-(tools|debuginfo|efi|efi-modules)\.x86_64')
addFilter('SPECS/gperftools.spec')
addFilter('libev-devel.x86_64')
addFilter('SPECS/libcomps.spec')
addFilter('nginx\.(spec|x86_64|src)')
addFilter('perl-common-sense.x86_64')
addFilter('perl-Compress-Raw-Bzip2.x86_64')
addFilter('perl-Data-OptList.src')
addFilter('perl-Data-Section.src')
addFilter('perl-GD.x86_64')
addFilter('perl-HTML-Parser.x86_64')
addFilter('perl-libintl\.(x86_64|src|spec)')
addFilter('perl-Mojolicious\.(src|spec)')
addFilter('perl-Params-Util.x86_64')
addFilter('perl-Pod-Coverage.spec')
addFilter('perl-Software-License\.(src|spec)')
addFilter('perl-Sub-Exporter\.(src|spec)')
addFilter('perl-Sub-Install.src')
addFilter('perl-Pod-Coverage.src')
addFilter('perl-libintl\.(x86_64|src)')
addFilter('perl-Test-Pod\.(src|spec)')
addFilter('perl-TermReadKey\.(x86_64|src)')
addFilter('perl-Test-Pod\.(src|spec)')
addFilter('perl-Text-Template.noarch')
addFilter('perl-Time-HiRes.x86_64')
addFilter('SPECS/puppet.spec')
addFilter('pyOpenSSL(-doc)?\.(noarch|spec)')
addFilter('python(2|3)?-acme\.(src|noarch)')
addFilter('python(2|3)?-hypothesis\.(src|noarch)')
addFilter('python(2|3)-dialog.noarch')
addFilter('python-mock.spec')
addFilter('python-ndg_httpsclient\.(src|spec)')
addFilter('python-parsedatetime.spec')
addFilter('python-psutil.spec')
addFilter('python-pyrfc3339.src')
addFilter('python-twisted.x86_64')
addFilter('python(2|3)?-rpm-macros\.(noarch|src)')
addFilter('python-srpm-macros.noarch')
addFilter('python-zbase32.noarch')
addFilter('python3?-zope-event\.(noarch|spec)')
addFilter('python3?-zope-interface\.(x86_64|src)')
addFilter('SPECS/python-iniparse.spec')
addFilter('python-pyrfc3339.src')
addFilter('python-zope-event.noarch')
addFilter('pyutil.noarch')
addFilter('SPECS/os-prober.spec')
addFilter('SPECS/puppet.spec')
addFilter('yum\.(spec|src)')

# Python is mostly third-party and has lots of warnings.
# TODO: clean those up.
addFilter('SPECS/python.spec')
addFilter('SPECS/python3.spec')
addFilter('third_party/subtrees/python/python.spec')
addFilter('third_party/subtrees/python3/python3.spec')
addFilter('python-libs.x86_64')
addFilter('python-debuginfo.x86_64')
addFilter('python-libs.x86_64')
addFilter('python-devel.x86_64')
addFilter('python-macros.noarch')
addFilter('python.x86_64')
addFilter('python3?.src:[0-9]+: W: hardcoded-library-path')
addFilter('python.src: W: %ifarch-applied-patch Patch131')
addFilter('python.src:[0-9]+: W: unversioned-explicit-obsoletes')
addFilter('python.src:[0-9]+: W: unversioned-explicit-provides')
addFilter('python.src: W: strange-permission pythondeps.sh')

# RPM is special, let's ignore warnings from it.
addFilter('SPECS/rpm.spec')
addFilter('third_party/subtrees/rpm/rpm.spec')

# DNF have a lot of weird stuff:
addFilter('dnf.spec.*libdir-macro-in-noarch-package')

# VIM: allow mixed space/tab usage in specific line.
addFilter('vim.spec:218: W: mixed-use-of-spaces-and-tabs')
# Ignore unversioned provide /bin/vi, versioning it triggers another lint
# warning.
addFilter('vim.spec:[0-9]+: W: unversioned-explicit-provides /bin/vi')

## Perl
# Perl packages are weird and often don't have -devel part.
addFilter('perl-Tk.x86_64: W: devel-file-in-non-devel-package')
# Some of them also depend on perl-devel
addFilter('perl-ExtUtils-Miniperl.noarch: W: devel-dependency')
# Perl-Tk has weird deps
addFilter('perl-Tk.spec:63: W: comparison-operator-in-deptoken')

## Let's encrypt:
# Allow pems in test files.
addFilter('python2-letsencrypt.noarch: W: pem-certificate /usr/lib/python2.7/site-packages/letsencrypt/tests/testdata/.*')
# Allow some nonstandard permissions
addFilter('letsencrypt.noarch: W: non-standard-dir-perm /var/log/letsencrypt 0')
addFilter('letsencrypt.noarch: W: non-standard-dir-perm /var/lib/letsencrypt 0')
addFilter('letsencrypt.noarch: W: non-standard-dir-perm /etc/letsencrypt 0')
# TODO: fix following
addFilter('letsencrypt.noarch: W: log-files-without-logrotate')

## Libcomps
# URL broken :(
addFilter('libcomps.spec: W: invalid-url Source0: https://github.com/midnightercz/libcomps/libcomps-0.1.7.tar.gz')

## GDB
# Following should be ok for debugger.
addFilter('gdb\.(spec|src):[0-9]+: W: unversioned-explicit-obsoletes devtoolset')
addFilter('gdb.x86_64: W: unstripped-binary-or-object /usr/bin/gdb')
addFilter('gdb-gdbserver.x86_64: W: unstripped-binary-or-object /usr/lib64/libinproctrace.so')
addFilter('gdb-gdbserver.x86_64: W: unstripped-binary-or-object /usr/bin/gdbserver')
addFilter('gdb-gdbserver.x86_64: W: shared-lib-calls-exit /usr/lib64/libinproctrace.so exit@GLIBC_2.2.5')
addFilter('gdb.x86_64: W: only-non-binary-in-usr-lib')
addFilter('gdb-gdbserver.x86_64: W: no-soname /usr/lib64/libinproctrace.so')
addFilter('gdb.spec:[0-9]+: W: hardcoded-library-path')
addFilter('gdb.x86_64: W: dangerous-command-in-%pre mv')
addFilter('gdb.x86_64: W: devel-file-in-non-devel-package /usr/include/gdb/jit-reader.h')
addFilter('gdb.src:[0-9]+: W: hardcoded-library-path')
# Snapshots dissapear quickly
addFilter('gdb\.(src|spec): W: invalid-url Source0: ftp://sourceware.org/pub/gdb/snapshots/current/.*')

## Python-pip
addFilter('python(3|2)?-pip.noarch: W: non-executable-script /usr/lib/python.\../site-packages/pip/_vendor/requests/packages/chardet/chardetect.py')

## Cython
# There's no -devel package.
addFilter('(python3-)?Cython.x86_64: W: devel-file-in-non-devel-package')
# false-positives
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python(2|3)\.[0-9]/site-packages/cython.py')
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python(2|3)\.[0-9]/site-packages/Cython/Build/Cythonize.py')
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python[0-9]\.[0-9]/site-packages/Cython/Debugger/Cygdb.py')
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python[0-9]\.[0-9]/site-packages/Cython/Debugger/libpython.py')

## Perl
addFilter('perl.spec: W: %ifarch-applied-patch Patch3: perl-5.8.0-libdir64.patch')
addFilter('perl\.(src|spec): W: invalid-license')
addFilter('perl.spec:[0-9]+: W: unversioned-explicit-obsoletes')

## Python-cryptoghraphy
addFilter('python3?-cryptography-vectors.noarch: W: pem-certificate')

## Python-ply
# cpython stuff:
addFilter('python3?-ply.noarch: W: python-bytecode-without-source.*cpython.*')

## libsolv
addFilter('libsolv.x86_64: W: shared-lib-calls-exit')

# Python-cffi
addFilter('python-cffi.x86_64: W: devel-file-in-non-devel-package')
addFilter('python3-cffi.x86_64: W: unstripped-binary-or-object')

# pyparsing
addFilter('pyparsing-doc.noarch: W: file-not-utf8')
<commit_msg>python-zope-interface: Ignore lint warnings in the spec.<commit_after>from Config import *

# Not sure what this number does, but we need some threshold that we'd like to
# avoid crossing.
setOption("BadnessThreshold", 42)

# Ignore documentation issues.
addFilter('no-manual-page-for-binary')
addFilter('no-documentation')
addFilter('name-repeated-in-summary')

# Ignore spelling errors unilt there's a support for custom dictionaries.
# TODO: add such support.
addFilter('spelling-error')

# Ignore unversioned bundled provides.
addFilter('unversioned-explicit-provides bundled\([a-z\-]+\)')

# Don't care about groups.
addFilter('non-standard-group')

# Ignore all lint warnings in submodules:
addFilter('third_party/submodules/')
# Ignore all lint warnings in symlinks from submodules.
addFilter('SPECS/cmake.spec')
addFilter('SPECS/gdb.spec')
addFilter('grub2\.(x86_64|src|spec)')
addFilter('grub2-(tools|debuginfo|efi|efi-modules)\.x86_64')
addFilter('SPECS/gperftools.spec')
addFilter('libev-devel.x86_64')
addFilter('SPECS/libcomps.spec')
addFilter('nginx\.(spec|x86_64|src)')
addFilter('perl-common-sense.x86_64')
addFilter('perl-Compress-Raw-Bzip2.x86_64')
addFilter('perl-Data-OptList.src')
addFilter('perl-Data-Section.src')
addFilter('perl-GD.x86_64')
addFilter('perl-HTML-Parser.x86_64')
addFilter('perl-libintl\.(x86_64|src|spec)')
addFilter('perl-Mojolicious\.(src|spec)')
addFilter('perl-Params-Util.x86_64')
addFilter('perl-Pod-Coverage.spec')
addFilter('perl-Software-License\.(src|spec)')
addFilter('perl-Sub-Exporter\.(src|spec)')
addFilter('perl-Sub-Install.src')
addFilter('perl-Pod-Coverage.src')
addFilter('perl-libintl\.(x86_64|src)')
addFilter('perl-Test-Pod\.(src|spec)')
addFilter('perl-TermReadKey\.(x86_64|src)')
addFilter('perl-Test-Pod\.(src|spec)')
addFilter('perl-Text-Template.noarch')
addFilter('perl-Time-HiRes.x86_64')
addFilter('SPECS/puppet.spec')
addFilter('pyOpenSSL(-doc)?\.(noarch|spec)')
addFilter('python(2|3)?-acme\.(src|noarch)')
addFilter('python(2|3)?-hypothesis\.(src|noarch)')
addFilter('python(2|3)-dialog.noarch')
addFilter('python-mock.spec')
addFilter('python-ndg_httpsclient\.(src|spec)')
addFilter('python-parsedatetime.spec')
addFilter('python-psutil.spec')
addFilter('python-pyrfc3339.src')
addFilter('python-twisted.x86_64')
addFilter('python(2|3)?-rpm-macros\.(noarch|src)')
addFilter('python-srpm-macros.noarch')
addFilter('python-zbase32.noarch')
addFilter('python3?-zope-event\.(noarch|spec)')
addFilter('python3?-zope-interface\.(x86_64|src|spec)')
addFilter('SPECS/python-iniparse.spec')
addFilter('python-pyrfc3339.src')
addFilter('python-zope-event.noarch')
addFilter('pyutil.noarch')
addFilter('SPECS/os-prober.spec')
addFilter('SPECS/puppet.spec')
addFilter('yum\.(spec|src)')

# Python is mostly third-party and has lots of warnings.
# TODO: clean those up.
addFilter('SPECS/python.spec')
addFilter('SPECS/python3.spec')
addFilter('third_party/subtrees/python/python.spec')
addFilter('third_party/subtrees/python3/python3.spec')
addFilter('python-libs.x86_64')
addFilter('python-debuginfo.x86_64')
addFilter('python-libs.x86_64')
addFilter('python-devel.x86_64')
addFilter('python-macros.noarch')
addFilter('python.x86_64')
addFilter('python3?.src:[0-9]+: W: hardcoded-library-path')
addFilter('python.src: W: %ifarch-applied-patch Patch131')
addFilter('python.src:[0-9]+: W: unversioned-explicit-obsoletes')
addFilter('python.src:[0-9]+: W: unversioned-explicit-provides')
addFilter('python.src: W: strange-permission pythondeps.sh')

# RPM is special, let's ignore warnings from it.
addFilter('SPECS/rpm.spec')
addFilter('third_party/subtrees/rpm/rpm.spec')

# DNF have a lot of weird stuff:
addFilter('dnf.spec.*libdir-macro-in-noarch-package')

# VIM: allow mixed space/tab usage in specific line.
addFilter('vim.spec:218: W: mixed-use-of-spaces-and-tabs')
# Ignore unversioned provide /bin/vi, versioning it triggers another lint
# warning.
addFilter('vim.spec:[0-9]+: W: unversioned-explicit-provides /bin/vi')

## Perl
# Perl packages are weird and often don't have -devel part.
addFilter('perl-Tk.x86_64: W: devel-file-in-non-devel-package')
# Some of them also depend on perl-devel
addFilter('perl-ExtUtils-Miniperl.noarch: W: devel-dependency')
# Perl-Tk has weird deps
addFilter('perl-Tk.spec:63: W: comparison-operator-in-deptoken')

## Let's encrypt:
# Allow pems in test files.
addFilter('python2-letsencrypt.noarch: W: pem-certificate /usr/lib/python2.7/site-packages/letsencrypt/tests/testdata/.*')
# Allow some nonstandard permissions
addFilter('letsencrypt.noarch: W: non-standard-dir-perm /var/log/letsencrypt 0')
addFilter('letsencrypt.noarch: W: non-standard-dir-perm /var/lib/letsencrypt 0')
addFilter('letsencrypt.noarch: W: non-standard-dir-perm /etc/letsencrypt 0')
# TODO: fix following
addFilter('letsencrypt.noarch: W: log-files-without-logrotate')

## Libcomps
# URL broken :(
addFilter('libcomps.spec: W: invalid-url Source0: https://github.com/midnightercz/libcomps/libcomps-0.1.7.tar.gz')

## GDB
# Following should be ok for debugger.
addFilter('gdb\.(spec|src):[0-9]+: W: unversioned-explicit-obsoletes devtoolset')
addFilter('gdb.x86_64: W: unstripped-binary-or-object /usr/bin/gdb')
addFilter('gdb-gdbserver.x86_64: W: unstripped-binary-or-object /usr/lib64/libinproctrace.so')
addFilter('gdb-gdbserver.x86_64: W: unstripped-binary-or-object /usr/bin/gdbserver')
addFilter('gdb-gdbserver.x86_64: W: shared-lib-calls-exit /usr/lib64/libinproctrace.so exit@GLIBC_2.2.5')
addFilter('gdb.x86_64: W: only-non-binary-in-usr-lib')
addFilter('gdb-gdbserver.x86_64: W: no-soname /usr/lib64/libinproctrace.so')
addFilter('gdb.spec:[0-9]+: W: hardcoded-library-path')
addFilter('gdb.x86_64: W: dangerous-command-in-%pre mv')
addFilter('gdb.x86_64: W: devel-file-in-non-devel-package /usr/include/gdb/jit-reader.h')
addFilter('gdb.src:[0-9]+: W: hardcoded-library-path')
# Snapshots dissapear quickly
addFilter('gdb\.(src|spec): W: invalid-url Source0: ftp://sourceware.org/pub/gdb/snapshots/current/.*')

## Python-pip
addFilter('python(3|2)?-pip.noarch: W: non-executable-script /usr/lib/python.\../site-packages/pip/_vendor/requests/packages/chardet/chardetect.py')

## Cython
# There's no -devel package.
addFilter('(python3-)?Cython.x86_64: W: devel-file-in-non-devel-package')
# false-positives
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python(2|3)\.[0-9]/site-packages/cython.py')
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python(2|3)\.[0-9]/site-packages/Cython/Build/Cythonize.py')
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python[0-9]\.[0-9]/site-packages/Cython/Debugger/Cygdb.py')
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python[0-9]\.[0-9]/site-packages/Cython/Debugger/libpython.py')

## Perl
addFilter('perl.spec: W: %ifarch-applied-patch Patch3: perl-5.8.0-libdir64.patch')
addFilter('perl\.(src|spec): W: invalid-license')
addFilter('perl.spec:[0-9]+: W: unversioned-explicit-obsoletes')

## Python-cryptoghraphy
addFilter('python3?-cryptography-vectors.noarch: W: pem-certificate')

## Python-ply
# cpython stuff:
addFilter('python3?-ply.noarch: W: python-bytecode-without-source.*cpython.*')

## libsolv
addFilter('libsolv.x86_64: W: shared-lib-calls-exit')

# Python-cffi
addFilter('python-cffi.x86_64: W: devel-file-in-non-devel-package')
addFilter('python3-cffi.x86_64: W: unstripped-binary-or-object')

# pyparsing
addFilter('pyparsing-doc.noarch: W: file-not-utf8')
<|endoftext|>


<commit_before>from Config import *

# Not sure what this number does, but we need some threshold that we'd like to
# avoid crossing.
setOption("BadnessThreshold", 42)

# Ignore documentation issues.
addFilter('no-manual-page-for-binary')
addFilter('no-documentation')
addFilter('name-repeated-in-summary')

# Ignore spelling errors unilt there's a support for custom dictionaries.
# TODO: add such support.
addFilter('spelling-error')

# Ignore unversioned bundled provides.
addFilter('unversioned-explicit-provides bundled\([a-z\-]+\)')

# Don't care about groups.
addFilter('non-standard-group')

# Ignore all lint warnings in submodules:
addFilter('third_party/submodules/')
# Ignore all lint warnings in symlinks from submodules.
addFilter('SPECS/cmake.spec')
addFilter('SPECS/gdb.spec')
addFilter('SPECS/gperftools.spec')
addFilter('libev-devel.x86_64')
addFilter('SPECS/libcomps.spec')
addFilter('nginx\.(spec|x86_64|src)')
addFilter('perl-common-sense.x86_64')
addFilter('perl-Compress-Raw-Bzip2.x86_64')
addFilter('perl-Data-OptList.src')
addFilter('perl-Data-Section.src')
addFilter('perl-GD.x86_64')
addFilter('perl-HTML-Parser.x86_64')
addFilter('perl-libintl\.(x86_64|src|spec)')
addFilter('perl-Mojolicious\.(src|spec)')
addFilter('perl-Params-Util.x86_64')
addFilter('perl-Pod-Coverage.spec')
addFilter('perl-Software-License\.(src|spec)')
addFilter('perl-Sub-Exporter\.(src|spec)')
addFilter('perl-Sub-Install.src')
addFilter('perl-Pod-Coverage.src')
addFilter('perl-libintl\.(x86_64|src)')
addFilter('perl-Test-Pod\.(src|spec)')
addFilter('perl-TermReadKey\.(x86_64|src)')
addFilter('perl-Test-Pod\.(src|spec)')
addFilter('perl-Text-Template.noarch')
addFilter('pyOpenSSL(-doc)?\.(noarch|spec)')
addFilter('python(2|3)?-acme\.(src|noarch)')
addFilter('python(2|3)?-hypothesis\.(src|noarch)')
addFilter('python(2|3)-dialog.noarch')
addFilter('python-mock.spec')
addFilter('python-ndg_httpsclient\.(src|spec)')
addFilter('python-parsedatetime.spec')
addFilter('python-psutil.spec')
addFilter('python-pyrfc3339.src')
addFilter('python3?-zope-event\.(noarch|spec)')
addFilter('SPECS/puppet.spec')
addFilter('SPECS/python-iniparse.spec')
addFilter('python-pyrfc3339.src')
addFilter('python-zope-event.noarch')
addFilter('SPECS/os-prober.spec')
addFilter('SPECS/puppet.spec')
addFilter('yum\.(spec|src)')

# Python is mostly third-party and has lots of warnings.
# TODO: clean those up.
addFilter('SPECS/python.spec')
addFilter('SPECS/python3.spec')
addFilter('third_party/subtrees/python/python.spec')
addFilter('third_party/subtrees/python3/python3.spec')
addFilter('python-libs.x86_64')
addFilter('python-debuginfo.x86_64')
addFilter('python-libs.x86_64')
addFilter('python-devel.x86_64')
addFilter('python-macros.noarch')
addFilter('python.x86_64')
addFilter('python3.src:[0-9]+: W: hardcoded-library-path')

# RPM is special, let's ignore warnings from it.
addFilter('SPECS/rpm.spec')
addFilter('third_party/subtrees/rpm/rpm.spec')

# DNF have a lot of weird stuff:
addFilter('dnf.spec.*libdir-macro-in-noarch-package')

# VIM: allow mixed space/tab usage in specific line.
addFilter('vim.spec:218: W: mixed-use-of-spaces-and-tabs')
# Ignore unversioned provide /bin/vi, versioning it triggers another lint
# warning.
addFilter('vim.spec:[0-9]+: W: unversioned-explicit-provides /bin/vi')

## Perl
# Perl packages are weird and often don't have -devel part.
addFilter('perl-Tk.x86_64: W: devel-file-in-non-devel-package')
# Some of them also depend on perl-devel
addFilter('perl-ExtUtils-Miniperl.noarch: W: devel-dependency')
# Perl-Tk has weird deps
addFilter('perl-Tk.spec:63: W: comparison-operator-in-deptoken')

## Let's encrypt:
# Allow pems in test files.
addFilter('python2-letsencrypt.noarch: W: pem-certificate /usr/lib/python2.7/site-packages/letsencrypt/tests/testdata/.*')
# Allow some nonstandard permissions
addFilter('letsencrypt.noarch: W: non-standard-dir-perm /var/log/letsencrypt 0')
addFilter('letsencrypt.noarch: W: non-standard-dir-perm /var/lib/letsencrypt 0')
addFilter('letsencrypt.noarch: W: non-standard-dir-perm /etc/letsencrypt 0')
# TODO: fix following
addFilter('letsencrypt.noarch: W: log-files-without-logrotate')

## Libcomps
# URL broken :(
addFilter('libcomps.spec: W: invalid-url Source0: https://github.com/midnightercz/libcomps/libcomps-0.1.7.tar.gz')

## GDB
# Following should be ok for debugger.
addFilter('gdb.spec:[0-9]+: W: unversioned-explicit-obsoletes devtoolset')
addFilter('gdb.x86_64: W: unstripped-binary-or-object /usr/bin/gdb')
addFilter('gdb-gdbserver.x86_64: W: unstripped-binary-or-object /usr/lib64/libinproctrace.so')
addFilter('gdb-gdbserver.x86_64: W: unstripped-binary-or-object /usr/bin/gdbserver')
addFilter('gdb-gdbserver.x86_64: W: shared-lib-calls-exit /usr/lib64/libinproctrace.so exit@GLIBC_2.2.5')
addFilter('gdb.x86_64: W: only-non-binary-in-usr-lib')
addFilter('gdb-gdbserver.x86_64: W: no-soname /usr/lib64/libinproctrace.so')
addFilter('gdb.spec:[0-9]+: W: hardcoded-library-path')
addFilter('gdb.x86_64: W: dangerous-command-in-%pre mv')
addFilter('gdb.x86_64: W: devel-file-in-non-devel-package /usr/include/gdb/jit-reader.h')
addFilter('gdb.src:[0-9]+: W: hardcoded-library-path')
# Snapshots dissapear quickly
addFilter('gdb\.(src|spec): W: invalid-url Source0: ftp://sourceware.org/pub/gdb/snapshots/current/.*')

## Python-pip
addFilter('python(3|2)?-pip.noarch: W: non-executable-script /usr/lib/python.\../site-packages/pip/_vendor/requests/packages/chardet/chardetect.py')

## Cython
# There's no -devel package.
addFilter('(python3-)?Cython.x86_64: W: devel-file-in-non-devel-package')
# false-positives
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python(2|3)\.[0-9]/site-packages/cython.py')
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python(2|3)\.[0-9]/site-packages/Cython/Build/Cythonize.py')
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python[0-9]\.[0-9]/site-packages/Cython/Debugger/Cygdb.py')
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python[0-9]\.[0-9]/site-packages/Cython/Debugger/libpython.py')

## Perl
addFilter('perl.spec: W: %ifarch-applied-patch Patch3: perl-5.8.0-libdir64.patch')
addFilter('perl\.(src|spec): W: invalid-license')

## Python-cryptoghraphy
addFilter('python3?-cryptography-vectors.noarch: W: pem-certificate')

## Python-ply
# cpython stuff:
addFilter('python3?-ply.noarch: W: python-bytecode-without-source.*cpython.*')

## libsolv
addFilter('libsolv.x86_64: W: shared-lib-calls-exit')

# Python-cffi
addFilter('python-cffi.x86_64: W: devel-file-in-non-devel-package')
<commit_msg>python: Ignore ifarch-applied-patch Patch131.<commit_after>from Config import *

# Not sure what this number does, but we need some threshold that we'd like to
# avoid crossing.
setOption("BadnessThreshold", 42)

# Ignore documentation issues.
addFilter('no-manual-page-for-binary')
addFilter('no-documentation')
addFilter('name-repeated-in-summary')

# Ignore spelling errors unilt there's a support for custom dictionaries.
# TODO: add such support.
addFilter('spelling-error')

# Ignore unversioned bundled provides.
addFilter('unversioned-explicit-provides bundled\([a-z\-]+\)')

# Don't care about groups.
addFilter('non-standard-group')

# Ignore all lint warnings in submodules:
addFilter('third_party/submodules/')
# Ignore all lint warnings in symlinks from submodules.
addFilter('SPECS/cmake.spec')
addFilter('SPECS/gdb.spec')
addFilter('SPECS/gperftools.spec')
addFilter('libev-devel.x86_64')
addFilter('SPECS/libcomps.spec')
addFilter('nginx\.(spec|x86_64|src)')
addFilter('perl-common-sense.x86_64')
addFilter('perl-Compress-Raw-Bzip2.x86_64')
addFilter('perl-Data-OptList.src')
addFilter('perl-Data-Section.src')
addFilter('perl-GD.x86_64')
addFilter('perl-HTML-Parser.x86_64')
addFilter('perl-libintl\.(x86_64|src|spec)')
addFilter('perl-Mojolicious\.(src|spec)')
addFilter('perl-Params-Util.x86_64')
addFilter('perl-Pod-Coverage.spec')
addFilter('perl-Software-License\.(src|spec)')
addFilter('perl-Sub-Exporter\.(src|spec)')
addFilter('perl-Sub-Install.src')
addFilter('perl-Pod-Coverage.src')
addFilter('perl-libintl\.(x86_64|src)')
addFilter('perl-Test-Pod\.(src|spec)')
addFilter('perl-TermReadKey\.(x86_64|src)')
addFilter('perl-Test-Pod\.(src|spec)')
addFilter('perl-Text-Template.noarch')
addFilter('pyOpenSSL(-doc)?\.(noarch|spec)')
addFilter('python(2|3)?-acme\.(src|noarch)')
addFilter('python(2|3)?-hypothesis\.(src|noarch)')
addFilter('python(2|3)-dialog.noarch')
addFilter('python-mock.spec')
addFilter('python-ndg_httpsclient\.(src|spec)')
addFilter('python-parsedatetime.spec')
addFilter('python-psutil.spec')
addFilter('python-pyrfc3339.src')
addFilter('python3?-zope-event\.(noarch|spec)')
addFilter('SPECS/puppet.spec')
addFilter('SPECS/python-iniparse.spec')
addFilter('python-pyrfc3339.src')
addFilter('python-zope-event.noarch')
addFilter('SPECS/os-prober.spec')
addFilter('SPECS/puppet.spec')
addFilter('yum\.(spec|src)')

# Python is mostly third-party and has lots of warnings.
# TODO: clean those up.
addFilter('SPECS/python.spec')
addFilter('SPECS/python3.spec')
addFilter('third_party/subtrees/python/python.spec')
addFilter('third_party/subtrees/python3/python3.spec')
addFilter('python-libs.x86_64')
addFilter('python-debuginfo.x86_64')
addFilter('python-libs.x86_64')
addFilter('python-devel.x86_64')
addFilter('python-macros.noarch')
addFilter('python.x86_64')
addFilter('python3.src:[0-9]+: W: hardcoded-library-path')
addFilter('python.src: W: %ifarch-applied-patch Patch131')

# RPM is special, let's ignore warnings from it.
addFilter('SPECS/rpm.spec')
addFilter('third_party/subtrees/rpm/rpm.spec')

# DNF have a lot of weird stuff:
addFilter('dnf.spec.*libdir-macro-in-noarch-package')

# VIM: allow mixed space/tab usage in specific line.
addFilter('vim.spec:218: W: mixed-use-of-spaces-and-tabs')
# Ignore unversioned provide /bin/vi, versioning it triggers another lint
# warning.
addFilter('vim.spec:[0-9]+: W: unversioned-explicit-provides /bin/vi')

## Perl
# Perl packages are weird and often don't have -devel part.
addFilter('perl-Tk.x86_64: W: devel-file-in-non-devel-package')
# Some of them also depend on perl-devel
addFilter('perl-ExtUtils-Miniperl.noarch: W: devel-dependency')
# Perl-Tk has weird deps
addFilter('perl-Tk.spec:63: W: comparison-operator-in-deptoken')

## Let's encrypt:
# Allow pems in test files.
addFilter('python2-letsencrypt.noarch: W: pem-certificate /usr/lib/python2.7/site-packages/letsencrypt/tests/testdata/.*')
# Allow some nonstandard permissions
addFilter('letsencrypt.noarch: W: non-standard-dir-perm /var/log/letsencrypt 0')
addFilter('letsencrypt.noarch: W: non-standard-dir-perm /var/lib/letsencrypt 0')
addFilter('letsencrypt.noarch: W: non-standard-dir-perm /etc/letsencrypt 0')
# TODO: fix following
addFilter('letsencrypt.noarch: W: log-files-without-logrotate')

## Libcomps
# URL broken :(
addFilter('libcomps.spec: W: invalid-url Source0: https://github.com/midnightercz/libcomps/libcomps-0.1.7.tar.gz')

## GDB
# Following should be ok for debugger.
addFilter('gdb.spec:[0-9]+: W: unversioned-explicit-obsoletes devtoolset')
addFilter('gdb.x86_64: W: unstripped-binary-or-object /usr/bin/gdb')
addFilter('gdb-gdbserver.x86_64: W: unstripped-binary-or-object /usr/lib64/libinproctrace.so')
addFilter('gdb-gdbserver.x86_64: W: unstripped-binary-or-object /usr/bin/gdbserver')
addFilter('gdb-gdbserver.x86_64: W: shared-lib-calls-exit /usr/lib64/libinproctrace.so exit@GLIBC_2.2.5')
addFilter('gdb.x86_64: W: only-non-binary-in-usr-lib')
addFilter('gdb-gdbserver.x86_64: W: no-soname /usr/lib64/libinproctrace.so')
addFilter('gdb.spec:[0-9]+: W: hardcoded-library-path')
addFilter('gdb.x86_64: W: dangerous-command-in-%pre mv')
addFilter('gdb.x86_64: W: devel-file-in-non-devel-package /usr/include/gdb/jit-reader.h')
addFilter('gdb.src:[0-9]+: W: hardcoded-library-path')
# Snapshots dissapear quickly
addFilter('gdb\.(src|spec): W: invalid-url Source0: ftp://sourceware.org/pub/gdb/snapshots/current/.*')

## Python-pip
addFilter('python(3|2)?-pip.noarch: W: non-executable-script /usr/lib/python.\../site-packages/pip/_vendor/requests/packages/chardet/chardetect.py')

## Cython
# There's no -devel package.
addFilter('(python3-)?Cython.x86_64: W: devel-file-in-non-devel-package')
# false-positives
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python(2|3)\.[0-9]/site-packages/cython.py')
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python(2|3)\.[0-9]/site-packages/Cython/Build/Cythonize.py')
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python[0-9]\.[0-9]/site-packages/Cython/Debugger/Cygdb.py')
addFilter('(python3-)?Cython.x86_64: W: non-executable-script /usr/lib64/python[0-9]\.[0-9]/site-packages/Cython/Debugger/libpython.py')

## Perl
addFilter('perl.spec: W: %ifarch-applied-patch Patch3: perl-5.8.0-libdir64.patch')
addFilter('perl\.(src|spec): W: invalid-license')

## Python-cryptoghraphy
addFilter('python3?-cryptography-vectors.noarch: W: pem-certificate')

## Python-ply
# cpython stuff:
addFilter('python3?-ply.noarch: W: python-bytecode-without-source.*cpython.*')

## libsolv
addFilter('libsolv.x86_64: W: shared-lib-calls-exit')

# Python-cffi
addFilter('python-cffi.x86_64: W: devel-file-in-non-devel-package')
<|endoftext|>


<commit_before>import pygame, sys
from pygame.locals import *

WHITE = (255,255,255,0)
YELLOW = (255,253,99,0)

class Window(object):

    def __init__(self, strings, sizeX, sizeY, posX, posY, DISPLAYSURF, action=None):

        self.action = action
        self.posX = posX
        self.posY = posY
        self.strings = strings

        textOffsetY = 30
        textOffsetX = (sizeX/2)

        menuSurf = pygame.Surface((sizeX, sizeY))
        menuSurf.fill((0,0,0,0))

        textBox = pygame.image.load('rprpg/assets/textbox.bmp')
        pygame.transform.scale(textBox, (sizeX, sizeY))
        menuSurf.blit(textBox, (0,0))
        self.menuSurf = menuSurf

        fontObj = pygame.font.Font('freesansbold.ttf',32)
        self.fontObj = fontObj
        menuOptions=[]
        self.menuOptions = menuOptions
        for string in strings:
            text = fontObj.render(string, True, WHITE)
            textRect=text.get_rect()
            textRect.center = (textOffsetX, textOffsetY)
            self.menuSurf.blit(text, textRect)
            textOffsetY += 40
            self.menuOptions.append([string, text, textRect, self.action])

        DISPLAYSURF.blit(menuSurf, (posX, posY))

    def highlight(self, selection,DISPLAYSURF):
        currentOption = self.menuOptions[selection]
        string = currentOption[0]
        currentOption[1] = self.fontObj.render(string, True, YELLOW)
        self.menuSurf.blit(currentOption[1],currentOption[2])
        DISPLAYSURF.blit(self.menuSurf, (self.posX, self.posY))

    def unhighlight(self, selection, DISPLAYSURF):
        currentOption = self.menuOptions[selection]
        string = currentOption[0]
        currentOption[1] = self.fontObj.render(string, True, WHITE)
        self.menuSurf.blit(currentOption[1],currentOption[2])
        DISPLAYSURF.blit(self.menuSurf, (self.posX, self.posY))

    def select(self, selection):
        currentOption = self.menuOptions[selection]
        currentAction = currentOption[3]
        currentAction.execute()

    def getSize(self):
        return len(self.menuOptions)
<commit_msg>keeping the window class up to date<commit_after>import pygame, sys
from pygame.locals import *

WHITE = (255,255,255,0)
YELLOW = (255,253,99,0)

class Window(object):

    def __init__(self, strings, sizeX, sizeY, posX, posY, DISPLAYSURF, action=None):

        self.action = action
        self.posX = posX
        self.posY = posY
        self.strings = strings

        textOffsetY = 30
        textOffsetX = (sizeX/2)

        menuSurf = pygame.Surface((sizeX, sizeY))
        menuSurf.fill((0,0,0,0))

        textBox = pygame.image.load('rprpg/assets/textbox.bmp')
        pygame.transform.scale(textBox, (sizeX, sizeY))
        menuSurf.blit(textBox, (0,0))
        self.menuSurf = menuSurf

        fontObj = pygame.font.Font('freesansbold.ttf',32)
        self.fontObj = fontObj
        menuOptions=[]
        self.menuOptions = menuOptions
        count = 0
        for string in strings:
            text = fontObj.render(string, True, WHITE)
            textRect=text.get_rect()
            textRect.center = (textOffsetX, textOffsetY)
            self.menuSurf.blit(text, textRect)
            textOffsetY += 40
            self.menuOptions.append([string, text, textRect, self.action[count]])
            count = count+1

        DISPLAYSURF.blit(menuSurf, (posX, posY))

    def highlight(self, selection,DISPLAYSURF):
        currentOption = self.menuOptions[selection]
        string = currentOption[0]
        currentOption[1] = self.fontObj.render(string, True, YELLOW)
        self.menuSurf.blit(currentOption[1],currentOption[2])
        DISPLAYSURF.blit(self.menuSurf, (self.posX, self.posY))

    def unhighlight(self, selection, DISPLAYSURF):
        currentOption = self.menuOptions[selection]
        string = currentOption[0]
        currentOption[1] = self.fontObj.render(string, True, WHITE)
        self.menuSurf.blit(currentOption[1],currentOption[2])
        DISPLAYSURF.blit(self.menuSurf, (self.posX, self.posY))

    def select(self, selection):
        currentOption = self.menuOptions[selection]
        currentAction = currentOption[3]
        return currentAction

    def getSize(self):
        return len(self.menuOptions)
<|endoftext|>