<commit_before># (c) Stefan Countryman 2017
# get some basic config just the way i like it, no heavy stuff
import sys
import os
import IPython.core.magic
import IPython.utils.path
sys.path.append(os.path.expanduser('~/dev/geco_data'))

# get the location of the ipython directory
# ipydir = IPython.utils.path.get_ipython_dir()

# aliases for my fav commands; more ideas at
# https://gist.github.com/taldcroft/547c0b6e0ae15e0c970d
get_ipython().run_line_magic('alias', 'vim vim')
get_ipython().run_line_magic('alias', 'imgcat imgcat')
get_ipython().run_line_magic('alias', 'find find')
get_ipython().run_line_magic('alias', 'git git')
get_ipython().run_line_magic('alias', 'pstree pstree')
get_ipython().run_line_magic('alias', 'mutt mutt')

@IPython.core.magic.register_line_magic
def shit(line):
    """shell it; make ipython act more like a system shell by making it add
    all executables to the path and by activating autocall."""
    get_ipython().run_line_magic('autocall', '1')
    get_ipython().run_line_magic('rehashx', '')
del shit

@IPython.core.magic.register_line_magic
def cpin(line):
    """Read from ``In[-n-2]`` and copy it to the system clipboard
    using ``pyperclip``. Indexing starts at 1. So to get the most recent
    input text, run ``cpin 1`` or ``cpin`` etc."""
    import pyperclip
    import shlex
    args = shlex.split(line)
    if len(args) == 0:
        num_lines_prior = 1
    else:
        num_lines_prior = int(args[1])
    pyperclip.copy(In[-1-num_lines_prior])
del cpin

@IPython.core.magic.register_line_magic
def win(line):
    """Write contents of ``In[-n-2]`` to ``~/.ipyscratch`` (or some other
    file) for easy use elsewhere. Use caution; will overwrite contents of
    this scratch file.

    Usage:
      %win
      %win 1
      %win 1 ~/foo.py
      %win ~/foo.py

    CAUTION: Positive integers are assumed to specify the number of lines
    prior in the interpreter to read from. The first positive integer in
    the argument list will be thus interpreted. If you need to write to a
    file whose name is also a positive integer, make sure to explicitly
    specify the number of lines back before specifying the file name, even if
    you just want the last line. For example, to write the most recent line
    to a file called ``5``, call:

      %win 1 5

    Omitting the ``1`` will imply that the default scratch file should be
    used and that the command 5 lines prior in the interpreter should be
    copied.
    """
    import shlex
    import os
    args = shlex.split(line)
    # get the number of lines prior as the first positive integer
    if len(args) == 0:
        num_lines_prior = 1
    for arg in args:
        try:
            num_lines_prior = int(arg)
            if num_lines_prior > 0:
                args.remove(arg)
                continue
        except ValueError:
            pass
    # get the first remaining argument and use that as the text file. if no
    # args remain, use the default path.
    if len(args) == 0:
        fname = '~/.ipyscratch'
    else:
        fname = args[0]
    with open(os.path.expanduser(fname), 'w') as outfile:
        outfile.write(In[-1-num_lines_prior])
del win

# functions for working with processes
def _cmd_path_lex(line):
    """Split a ``magic`` input line so that ``%which`` and ``%ps`` can
    interpret a command name and a path in a convenient manner."""
    import os
    args = line.split(' ', 1)
    cmd = args.pop(0)
    if len(args) == 0:
        paths = os.environ["PATH"].split(":")
    else:
        pathstr = args[0].strip()
        try:
            paths = eval(pathstr)
        except:
            paths = pathstr
        if isinstance(paths, unicode) or isinstance(paths, str):
            if ":" in paths:
                paths = paths.split(":")
            else:
                paths = [paths]
    return cmd, paths

@IPython.core.magic.register_line_magic
def whicha(line):
    """Get an array of all matching executable files in PATH; same as UNIX
    which -a. Optionally specify a custom list of executable paths like that
    returned by ``os.environ["PATH"].split(":")``. You don't have to quote the
    command name (first arg).

    If you choose to specify the path, you must leave a space between the
    command name and the path. For the path, you can either:

      1. Provide a list whose elements are directories in $PATH
      2. Provide a string resembling the shell $PATH format (no need to
         escape spaces in the middle of the path, though leading and
         trailing spaces are stripped)
      3. Leave the shell-formatted $PATH literal unquoted, in which case it
         will be interpreted exactly the same as a shell $PATH, colons and all;
         note that this variant will be masked by variable names that are the
         same as the path due to ``eval()``, though this is an edge case.
    """
    return _whicha(*_cmd_path_lex(line))
del whicha

def _whicha(cmd, paths=None):
    """Get an array of all matching executable files in PATH; same as UNIX
    which -a. ``paths`` must be a list of dirs like that returned by
    ``os.environ['PATH'].split(':')."""
    import os
    if paths is None:
        paths = os.environ['PATH'].split(':')
    possibilities = [os.path.expanduser(os.path.join(p, cmd)) for p in paths]
    return filter(lambda bin: os.path.exists(bin), possibilities)

@IPython.core.magic.register_line_magic
def psa(line):
    """Get all matching processees for a command, searching for executable
    names along either the OS $PATH or along a custom specified path (see
    ``%which`` documentation for syntax)"""
    cmd, paths = _cmd_path_lex(line)
    return _psa(cmd, allmatching=True, paths=paths)
del psa

def _psa(cmd, allmatching=True, paths=None):
    """Get processes whose command lines include binaries (according to the PATH
    variable) for the given command. Optionally, only look for the top result,
    or only look for results in given path directories.

    Returns a tuple of the form ``(pids, cmdlines)``, where ``pids`` is a list
    of matching pids and ``cmdlines`` is the corresponding list of their
    command lines."""
    import psutil
    pids = list()
    cmdlines = list()
    cmdline = ''
    bins = _whicha(cmd, paths)
    if not allmatching:
        bins = bins[:1]
    for pid in psutil.pids():
        try:
            cmdline = psutil.Process(pid).cmdline()
            if any([bin in cmdline for bin in bins]):
                cmdlines.append(cmdline)
                pids.append(pid)
        except psutil.ZombieProcess:
            pass
        except psutil.AccessDenied:
            pass
    return (pids, cmdlines)
<commit_msg>Add read in (rin) to ipython<commit_after># (c) Stefan Countryman 2017
# get some basic config just the way i like it, no heavy stuff
import sys
import os
import IPython.core.magic
import IPython.utils.path
sys.path.append(os.path.expanduser('~/dev/geco_data'))

# get the location of the ipython directory
# ipydir = IPython.utils.path.get_ipython_dir()

# aliases for my fav commands; more ideas at
# https://gist.github.com/taldcroft/547c0b6e0ae15e0c970d
get_ipython().run_line_magic('alias', 'vim vim')
get_ipython().run_line_magic('alias', 'imgcat imgcat')
get_ipython().run_line_magic('alias', 'find find')
get_ipython().run_line_magic('alias', 'git git')
get_ipython().run_line_magic('alias', 'pstree pstree')
get_ipython().run_line_magic('alias', 'mutt mutt')

@IPython.core.magic.register_line_magic
def shit(line):
    """shell it; make ipython act more like a system shell by making it add
    all executables to the path and by activating autocall."""
    get_ipython().run_line_magic('autocall', '1')
    get_ipython().run_line_magic('rehashx', '')
del shit

@IPython.core.magic.register_line_magic
def cpin(line):
    """Read from ``In[-n-2]`` and copy it to the system clipboard
    using ``pyperclip``. Indexing starts at 1. So to get the most recent
    input text, run ``cpin 1`` or ``cpin`` etc."""
    import pyperclip
    import shlex
    args = shlex.split(line)
    if len(args) == 0:
        num_lines_prior = 1
    else:
        num_lines_prior = int(args[1])
    pyperclip.copy(In[-1-num_lines_prior])
del cpin

@IPython.core.magic.register_line_magic
def win(line):
    """Write contents of ``In[-n-2]`` to ``~/.ipyscratch`` (or some other
    file) for easy use elsewhere. Use caution; will overwrite contents of
    this scratch file.

    Usage:
      %win
      %win 1
      %win 1 ~/foo.py
      %win ~/foo.py

    CAUTION: Positive integers are assumed to specify the number of lines
    prior in the interpreter to read from. The first positive integer in
    the argument list will be thus interpreted. If you need to write to a
    file whose name is also a positive integer, make sure to explicitly
    specify the number of lines back before specifying the file name, even if
    you just want the last line. For example, to write the most recent line
    to a file called ``5``, call:

      %win 1 5

    Omitting the ``1`` will imply that the default scratch file should be
    used and that the command 5 lines prior in the interpreter should be
    copied.
    """
    import shlex
    import os
    args = shlex.split(line)
    # get the number of lines prior as the first positive integer
    if len(args) == 0:
        num_lines_prior = 1
    for arg in args:
        try:
            num_lines_prior = int(arg)
            if num_lines_prior > 0:
                args.remove(arg)
                continue
        except ValueError:
            pass
    # get the first remaining argument and use that as the text file. if no
    # args remain, use the default path.
    if len(args) == 0:
        fname = '~/.ipyscratch'
    else:
        fname = args[0]
    with open(os.path.expanduser(fname), 'w') as outfile:
        outfile.write(In[-1-num_lines_prior])
del win

@IPython.core.magic.register_line_magic
def rin(line):
    """Run input from file; default to ~/.ipyscratch."""
    import os
    import shlex
    import textwrap
    args = shlex.split(line)
    if len(args) == 0:
        path = '~/.ipyscratch'
    else:
        try:
            path = eval(line)
        except:
            path = args[0]
    with open(os.path.expanduser(path)) as f:
        cmd = textwrap.dedent(f.read())
    get_ipython().run_line_magic('pycat', path)
    # update history
    In[-1] = cmd
    get_ipython().run_code(cmd)
del rin

# functions for working with processes
def _cmd_path_lex(line):
    """Split a ``magic`` input line so that ``%which`` and ``%ps`` can
    interpret a command name and a path in a convenient manner."""
    import os
    args = line.split(' ', 1)
    cmd = args.pop(0)
    if len(args) == 0:
        paths = os.environ["PATH"].split(":")
    else:
        pathstr = args[0].strip()
        try:
            paths = eval(pathstr)
        except:
            paths = pathstr
        if isinstance(paths, unicode) or isinstance(paths, str):
            if ":" in paths:
                paths = paths.split(":")
            else:
                paths = [paths]
    return cmd, paths

@IPython.core.magic.register_line_magic
def whicha(line):
    """Get an array of all matching executable files in PATH; same as UNIX
    which -a. Optionally specify a custom list of executable paths like that
    returned by ``os.environ["PATH"].split(":")``. You don't have to quote the
    command name (first arg).

    If you choose to specify the path, you must leave a space between the
    command name and the path. For the path, you can either:

      1. Provide a list whose elements are directories in $PATH
      2. Provide a string resembling the shell $PATH format (no need to
         escape spaces in the middle of the path, though leading and
         trailing spaces are stripped)
      3. Leave the shell-formatted $PATH literal unquoted, in which case it
         will be interpreted exactly the same as a shell $PATH, colons and all;
         note that this variant will be masked by variable names that are the
         same as the path due to ``eval()``, though this is an edge case.
    """
    return _whicha(*_cmd_path_lex(line))
del whicha

def _whicha(cmd, paths=None):
    """Get an array of all matching executable files in PATH; same as UNIX
    which -a. ``paths`` must be a list of dirs like that returned by
    ``os.environ['PATH'].split(':')."""
    import os
    if paths is None:
        paths = os.environ['PATH'].split(':')
    possibilities = [os.path.expanduser(os.path.join(p, cmd)) for p in paths]
    return filter(lambda bin: os.path.exists(bin), possibilities)

@IPython.core.magic.register_line_magic
def psa(line):
    """Get all matching processees for a command, searching for executable
    names along either the OS $PATH or along a custom specified path (see
    ``%which`` documentation for syntax)"""
    cmd, paths = _cmd_path_lex(line)
    return _psa(cmd, allmatching=True, paths=paths)
del psa

def _psa(cmd, allmatching=True, paths=None):
    """Get processes whose command lines include binaries (according to the PATH
    variable) for the given command. Optionally, only look for the top result,
    or only look for results in given path directories.

    Returns a tuple of the form ``(pids, cmdlines)``, where ``pids`` is a list
    of matching pids and ``cmdlines`` is the corresponding list of their
    command lines."""
    import psutil
    pids = list()
    cmdlines = list()
    cmdline = ''
    bins = _whicha(cmd, paths)
    if not allmatching:
        bins = bins[:1]
    for pid in psutil.pids():
        try:
            cmdline = psutil.Process(pid).cmdline()
            if any([bin in cmdline for bin in bins]):
                cmdlines.append(cmdline)
                pids.append(pid)
        except psutil.ZombieProcess:
            pass
        except psutil.AccessDenied:
            pass
    return (pids, cmdlines)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Generated by Django 1.11.3 on 2017-10-27 12:52
from __future__ import unicode_literals

from django.db import migrations

def create_upvotes(apps, schema_editor):
    TranscriptPhraseDownvote = apps.get_model(
        'transcript', 'TranscriptPhraseDownvote'
    )
    TranscriptPhraseVote = apps.get_model(
        'transcript', 'TranscriptPhraseVote'
    )
    for downvote in TranscriptPhraseDownvote.objects.all():
        vote = TranscriptPhraseVote(
            transcript_phrase=downvote.transcript_phrase,
            user=downvote.user,
            upvote=False
        )
        vote.save()

class Migration(migrations.Migration):

    dependencies = [
        ('transcript', '0014_transcriptphrasevote'),
    ]

    operations = [
        migrations.RunPython(create_upvotes)
    ]
<commit_msg>Rename function<commit_after># -*- coding: utf-8 -*-
# Generated by Django 1.11.3 on 2017-10-27 12:52
from __future__ import unicode_literals

from django.db import migrations

def create_votes(apps, schema_editor):
    TranscriptPhraseDownvote = apps.get_model(
        'transcript', 'TranscriptPhraseDownvote'
    )
    TranscriptPhraseVote = apps.get_model(
        'transcript', 'TranscriptPhraseVote'
    )
    for downvote in TranscriptPhraseDownvote.objects.all():
        vote = TranscriptPhraseVote(
            transcript_phrase=downvote.transcript_phrase,
            user=downvote.user,
            upvote=False
        )
        vote.save()

class Migration(migrations.Migration):

    dependencies = [
        ('transcript', '0014_transcriptphrasevote'),
    ]

    operations = [
        migrations.RunPython(create_upvotes)
    ]
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from org.wikiup.database.orm import WikiupEntityManager
from org.wikiup.modules.jython.orm import PythonEntity

def getEntity(name, ctx=None, **selection):
    return PythonEntity(_getEntity(name, ctx, selection))

def query(name, relation, ctx=None, **selection):
    entity = _getEntity(name, ctx, selection, False)
    relatives = entity.getRelatives(relation, None)
    props = [str(i.getName()) for i in relatives.getProperties()]
    r = [dict([(j, str(i.get(j))) for j in props]) for i in relatives]
    if len(r) == 0:
        r = dict([(str(i.getName()), i.getObject()) for i in relatives.getProperties()])
    entity.release()
    return r

def _getEntity(name, ctx=None, selection=None, autoselect=True):
    entity = None
    if ctx is not None:
        entity = ctx.get(name)
    if entity is None:
        entity = (ctx or WikiupEntityManager.getInstance()).getEntity(name)
    if selection:
        for k in selection:
            entity.set(k, selection[k])
        if autoselect:
            entity.select()
    return entity<commit_msg>do not select entity after creation<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from org.wikiup.database.orm import WikiupEntityManager
from org.wikiup.modules.jython.orm import PythonEntity

def getEntity(name, ctx=None, **selection):
    return PythonEntity(_getEntity(name, ctx, selection))

def query(name, relation, ctx=None, **selection):
    entity = _getEntity(name, ctx, selection)
    relatives = entity.getRelatives(relation, None)
    props = [str(i.getName()) for i in relatives.getProperties()]
    r = [dict([(j, str(i.get(j))) for j in props]) for i in relatives]
    if len(r) == 0:
        r = dict([(str(i.getName()), i.getObject()) for i in relatives.getProperties()])
    entity.release()
    return r

def _getEntity(name, ctx=None, selection=None):
    entity = None
    if ctx is not None:
        entity = ctx.get(name)
    if entity is None:
        entity = (ctx or WikiupEntityManager.getInstance()).getEntity(name)
    if selection:
        for k in selection:
            entity.set(k, selection[k])
    return entity<|endoftext|>


<commit_before># coding: utf-8

from __future__ import unicode_literals
from collections import defaultdict
from ajax_select.fields import AutoCompleteSelectMultipleField, \
    AutoCompleteWidget
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit, Field, HTML
from datetime import timedelta
from django.db.models import Q
from django.forms import ValidationError, ModelForm, Form, CharField, TextInput
from django.utils.translation import ugettext_lazy as _
from common.utils.text import capfirst
from .models import (
    Oeuvre, Source, Individu, ElementDeProgramme, ElementDeDistribution,
    Ensemble, Saison)
from range_slider.fields import RangeSliderField

__all__ = (b'IndividuForm', b'EnsembleForm', b'OeuvreForm',
           b'ElementDeDistributionForm', b'ElementDeProgrammeForm',
           b'SourceForm', b'SaisonForm', b'EvenementListForm')

class IndividuForm(ModelForm):
    class Meta(object):
        model = Individu
        widgets = {
            b'prenoms':
                AutoCompleteWidget('individu__prenoms',
                                   attrs={'style': 'width: 300px;'})
        }

    def __init__(self, *args, **kwargs):
        super(IndividuForm, self).__init__(*args, **kwargs)

        def apply_style(fieldname, style):
            self.fields[fieldname].widget.attrs['style'] = style

        apply_style('particule_nom', 'width: 50px;')
        apply_style('particule_nom_naissance', 'width: 50px;')

    def clean_designation(self):
        # Anticipe si la désignation donnera un résultat nul.
        data = self.cleaned_data
        designation = data[b'designation']
        if designation == 'P' and not data[b'pseudonyme'] \
            or designation == 'B' and not data[b'nom_naissance'] \
                or designation == 'F' and not data[b'prenoms']:
            raise ValidationError(_('Il manque des données pour pouvoir '
                                    'choisir cette désignation.'))
        return designation

class EnsembleForm(ModelForm):
    class Meta(object):
        model = Ensemble
        widgets = {
            b'particule_nom':
                AutoCompleteWidget('ensemble__particule_nom',
                                   attrs={'style': 'width: 50px;'})
        }

class OeuvreForm(ModelForm):
    def clean(self):
        data = super(OeuvreForm, self).clean()

        type_extrait = data['type_extrait']
        type_extrait_affiche = (
            type_extrait and type_extrait not in Oeuvre.TYPES_EXTRAIT_CACHES)

        if not type_extrait_affiche and not data['titre'] and not data['genre'] and not data['tempo']:
            msg = _('Un titre, un genre ou un tempo '
                    'doit au moins être précisé.')
            self._errors['titre'] = self.error_class([msg])
            self._errors['genre'] = self.error_class([msg])
            self._errors['tempo'] = self.error_class([msg])

        # Ensures title look like "Le Tartuffe, ou l’Imposteur.".
        data['prefixe_titre'] = capfirst(data['prefixe_titre'])
        data['titre'] = capfirst(data['titre'])
        data['prefixe_titre_secondaire'] = data['prefixe_titre_secondaire'].lower()
        data['titre_secondaire'] = capfirst(data['titre_secondaire'])

        if type_extrait or data['numero_extrait']:
            if not type_extrait:
                self._errors['type_extrait'] = self.error_class([
                    _('Ce champ doit être rempli '
                      'pour pouvoir utiliser « Numéro d’extrait ».')])
            if not data['numero_extrait']:
                self._errors['numero_extrait'] = self.error_class([
                    _('Ce champ doit être rempli '
                      'pour pouvoir utiliser « Type d’extrait ».')])
            if not data['extrait_de']:
                self._errors['extrait_de'] = self.error_class([
                    _('Ce champ doit être rempli pour pouvoir utiliser '
                      '« Type d’extrait » et « Numéro d’extrait ».')])

        return data

    class Meta(object):
        model = Oeuvre
        widgets = {
            b'prefixe_titre':
                AutoCompleteWidget('oeuvre__prefixe_titre',
                                   attrs={'style': 'width: 50px;'}),
            b'coordination':
                AutoCompleteWidget('oeuvre__coordination',
                                   attrs={'style': 'width: 70px;'}),
            b'prefixe_titre_secondaire':
                AutoCompleteWidget('oeuvre__prefixe_titre_secondaire',
                                   attrs={'style': 'width: 50px;'}),
            b'coupe': AutoCompleteWidget('oeuvre__coupe',
                                         attrs={'style': 'width: 500px;'}),
            b'tempo': AutoCompleteWidget('oeuvre__tempo',
                                         attrs={'style': 'width: 500px;'}),
            b'numero_extrait': TextInput(attrs={'cols': 10})
        }

class ElementDeDistributionForm(ModelForm):
    class Meta(object):
        model = ElementDeDistribution

    def clean(self):
        data = super(ElementDeDistributionForm, self).clean()

        error_msgs = defaultdict(list)
        if not (data[b'individu'] or data[b'ensemble']):
            msg = _('Vous devez remplir « Individu » ou « Ensemble ».')
            error_msgs[b'individu'].append(msg)
            error_msgs[b'ensemble'].append(msg)
        if data[b'individu'] and data[b'ensemble']:
            msg = _('Vous ne pouvez remplir à la fois '
                    '« Individu » et « Ensemble ».')
            error_msgs[b'individu'].append(msg)
            error_msgs[b'ensemble'].append(msg)
        if data.get(b'pupitre') and data.get(b'profession'):
            msg = _('Vous ne pouvez remplir à la fois '
                    '« Pupitre » et « Profession ».')
            error_msgs[b'pupitre'].append(msg)
            error_msgs[b'profession'].append(msg)
        if data.get(b'pupitre', '') != '' \
                and data.get(b'profession') \
                and data[b'profession'].parties.exists():
            msg = _('Au moins un rôle ou instrument est lié à cette '
                    'profession. Remplissez donc « Pupitre » à la place.')
            error_msgs[b'profession'].append(msg)

        for k, v in error_msgs.items():
            self._errors[k] = self.error_class(v)
            if k in data:
                del data[k]

        return data

class ElementDeProgrammeForm(ModelForm):
    class Meta(object):
        model = ElementDeProgramme
        # FIXME: Rendre fonctionnel ce qui suit.
        # widgets = {
        #     b'autre': AutoCompleteWidget('elementdeprogramme__autre',
        #                                  attrs={'style': 'width: 600px;'}),
        # }

    def clean(self):
        data = super(ElementDeProgrammeForm, self).clean()

        if not (data[b'autre'] or data[b'oeuvre'] or data[b'distribution']):
            raise ValidationError(_('Vous devez remplir au moins « Œuvre », '
                                    '« Autre » ou « Distribution ».'))

        if data[b'autre'] and data[b'oeuvre']:
            raise ValidationError(_('Vous ne pouvez remplir à la fois '
                                    '« Œuvre » et « Autre ».'))

        return data

class SourceForm(ModelForm):
    class Meta(object):
        model = Source
        widgets = {
            b'titre': AutoCompleteWidget('source__titre',
                                         attrs={'style': 'width: 600px;'}),
            b'numero': TextInput(attrs={'cols': 10}),
            b'folio': TextInput(attrs={'cols': 10}),
            b'page': TextInput(attrs={'cols': 10}),
        }

    def clean(self):
        data = super(SourceForm, self).clean()

        if not (data['titre'] or (data['lieu_conservation'] and data['cote'])):
            raise ValidationError(_('Vous devez remplir « Titre » ou '
                                    '« Lieu de conservation » et « Cote ».'))

        return data

class SaisonForm(ModelForm):
    class Meta(object):
        model = Source

    def clean(self):
        data = super(SaisonForm, self).clean()

        debut = data.get('debut')
        fin = data.get('fin')
        ensemble = data.get('ensemble')
        lieu = data.get('lieu')

        if not ((ensemble is None) ^ (lieu is None)):
            raise ValidationError(
                _('Vous devez remplir « Ensemble » '
                  'ou « Lieu ou Institution »'))

        if debut and fin:
            if debut > fin:
                raise ValidationError(_('La fin ne peut précéder le début.'))
            elif fin - debut > timedelta(365):
                raise ValidationError(_('La durée d’une saison ne peut excéder '
                                        'un an.'))

        overlapping_seasons = Saison.objects.filter(
            Q(debut__range=(debut, fin)) | Q(fin__range=(debut, fin))
            | Q(debut__lt=debut, fin__gt=fin),
            ensemble=ensemble, lieu=lieu)
        if overlapping_seasons.exists():
            raise ValidationError(
                _('Une saison existe déjà sur cette période pour « %s ».')
                % (ensemble or lieu))
        return data

class EvenementListForm(Form):
    q = CharField(label=_('Recherche libre'), required=False)
    dates = RangeSliderField(required=False)
    lieu = AutoCompleteSelectMultipleField('lieu', label=_('Lieu'),
                                           required=False, help_text='')
    oeuvre = AutoCompleteSelectMultipleField(
        'oeuvre', required=False, label=_('Œuvre'), help_text='')
    individu = AutoCompleteSelectMultipleField(
        'individu', required=False, label=_('Individu'), help_text='')
    ensemble = AutoCompleteSelectMultipleField(
        'ensemble', required=False, label=_('Ensemble'), help_text='')

    def __init__(self, *args, **kwargs):
        queryset = kwargs.pop('queryset')

        self.helper = FormHelper()
        self.helper.form_method = 'GET'
        self.helper.form_class = 'well well-sm'
        self.helper.layout = Layout(
            Field('q', css_class='input-lg'),
            HTML('
'),
            'dates',
            HTML('
'),
            'lieu', 'oeuvre', 'individu', 'ensemble',
            HTML('
'),
            Submit('', _('Filtrer'), css_class='btn-lg btn-block',
                   data_loading_text=_('Chargement…')),
        )

        super(EvenementListForm, self).__init__(*args, **kwargs)

        for field in self.fields.values():
            field.widget.attrs[b'placeholder'] = (field.label or '') + '…'
            field.label = ''

        self.fields['dates'].widget.queryset = queryset
<commit_msg>Ajoute quelques contraintes de formulaire.<commit_after># coding: utf-8

from __future__ import unicode_literals
from collections import defaultdict
from ajax_select.fields import AutoCompleteSelectMultipleField, \
    AutoCompleteWidget
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit, Field, HTML
from datetime import timedelta
from django.db.models import Q
from django.forms import ValidationError, ModelForm, Form, CharField, TextInput
from django.utils.translation import ugettext_lazy as _
from common.utils.text import capfirst
from .models import (
    Oeuvre, Source, Individu, ElementDeProgramme, ElementDeDistribution,
    Ensemble, Saison)
from range_slider.fields import RangeSliderField

__all__ = (b'IndividuForm', b'EnsembleForm', b'OeuvreForm',
           b'ElementDeDistributionForm', b'ElementDeProgrammeForm',
           b'SourceForm', b'SaisonForm', b'EvenementListForm')

class IndividuForm(ModelForm):
    class Meta(object):
        model = Individu
        widgets = {
            b'prenoms':
                AutoCompleteWidget('individu__prenoms',
                                   attrs={'style': 'width: 300px;'})
        }

    def __init__(self, *args, **kwargs):
        super(IndividuForm, self).__init__(*args, **kwargs)

        def apply_style(fieldname, style):
            self.fields[fieldname].widget.attrs['style'] = style

        apply_style('particule_nom', 'width: 50px;')
        apply_style('particule_nom_naissance', 'width: 50px;')

    def clean_designation(self):
        # Anticipe si la désignation donnera un résultat nul.
        data = self.cleaned_data
        designation = data[b'designation']
        if designation == 'P' and not data[b'pseudonyme'] \
            or designation == 'B' and not data[b'nom_naissance'] \
                or designation == 'F' and not data[b'prenoms']:
            raise ValidationError(_('Il manque des données pour pouvoir '
                                    'choisir cette désignation.'))
        return designation

class EnsembleForm(ModelForm):
    class Meta(object):
        model = Ensemble
        widgets = {
            b'particule_nom':
                AutoCompleteWidget('ensemble__particule_nom',
                                   attrs={'style': 'width: 50px;'})
        }

class OeuvreForm(ModelForm):
    def clean(self):
        data = super(OeuvreForm, self).clean()

        type_extrait = data['type_extrait']
        type_extrait_affiche = (
            type_extrait and type_extrait not in Oeuvre.TYPES_EXTRAIT_CACHES)

        if not type_extrait_affiche and \
                not data['titre'] and not data['genre'] and not data['tempo']:
            msg = _('Un titre, un genre ou un tempo '
                    'doit au moins être précisé.')
            self._errors['titre'] = self.error_class([msg])
            self._errors['genre'] = self.error_class([msg])
            self._errors['tempo'] = self.error_class([msg])

        # Ensures title look like "Le Tartuffe, ou l’Imposteur.".
        data['prefixe_titre'] = capfirst(data['prefixe_titre'])
        data['titre'] = capfirst(data['titre'])
        data['prefixe_titre_secondaire'] = data['prefixe_titre_secondaire'].lower()
        data['titre_secondaire'] = capfirst(data['titre_secondaire'])

        if data['titre_secondaire'] and not data['titre']:
            self._errors['titre_secondaire'] = self.error_class([
                _('« Titre secondaire » ne peut être saisi sans « Titre ».')
            ])
        if data['titre_secondaire'] and not data['coordination']:
            self._errors['titre_secondaire'] = self.error_class([
                _('« Titre secondaire » ne peut être saisi '
                  'sans « Coordination ».')
            ])
        if data['coordination'] and not data['titre_secondaire']:
            self._errors['coordination'] = self.error_class([
                _('« Coordination » ne peut être saisi '
                  'sans « Titre secondaire ».')
            ])
        if data['prefixe_titre'] and not data['titre']:
            self._errors['prefixe_titre'] = self.error_class([
                _('« Article » ne peut être saisi sans « Titre ».')
            ])
        if data['prefixe_titre_secondaire'] and not data['titre_secondaire']:
            self._errors['prefixe_titre_secondaire'] = self.error_class([
                _('« Article » ne peut être saisi sans « Titre secondaire ».')
            ])

        if type_extrait or data['numero_extrait']:
            if not type_extrait:
                self._errors['type_extrait'] = self.error_class([
                    _('Ce champ doit être rempli '
                      'pour pouvoir utiliser « Numéro d’extrait ».')])
            if not data['numero_extrait']:
                self._errors['numero_extrait'] = self.error_class([
                    _('Ce champ doit être rempli '
                      'pour pouvoir utiliser « Type d’extrait ».')])
            if not data['extrait_de']:
                self._errors['extrait_de'] = self.error_class([
                    _('Ce champ doit être rempli pour pouvoir utiliser '
                      '« Type d’extrait » et « Numéro d’extrait ».')])

        return data

    class Meta(object):
        model = Oeuvre
        widgets = {
            b'prefixe_titre':
                AutoCompleteWidget('oeuvre__prefixe_titre',
                                   attrs={'style': 'width: 50px;'}),
            b'coordination':
                AutoCompleteWidget('oeuvre__coordination',
                                   attrs={'style': 'width: 70px;'}),
            b'prefixe_titre_secondaire':
                AutoCompleteWidget('oeuvre__prefixe_titre_secondaire',
                                   attrs={'style': 'width: 50px;'}),
            b'coupe': AutoCompleteWidget('oeuvre__coupe',
                                         attrs={'style': 'width: 500px;'}),
            b'tempo': AutoCompleteWidget('oeuvre__tempo',
                                         attrs={'style': 'width: 500px;'}),
            b'numero_extrait': TextInput(attrs={'cols': 10})
        }

class ElementDeDistributionForm(ModelForm):
    class Meta(object):
        model = ElementDeDistribution

    def clean(self):
        data = super(ElementDeDistributionForm, self).clean()

        error_msgs = defaultdict(list)
        if not (data[b'individu'] or data[b'ensemble']):
            msg = _('Vous devez remplir « Individu » ou « Ensemble ».')
            error_msgs[b'individu'].append(msg)
            error_msgs[b'ensemble'].append(msg)
        if data[b'individu'] and data[b'ensemble']:
            msg = _('Vous ne pouvez remplir à la fois '
                    '« Individu » et « Ensemble ».')
            error_msgs[b'individu'].append(msg)
            error_msgs[b'ensemble'].append(msg)
        if data.get(b'pupitre') and data.get(b'profession'):
            msg = _('Vous ne pouvez remplir à la fois '
                    '« Pupitre » et « Profession ».')
            error_msgs[b'pupitre'].append(msg)
            error_msgs[b'profession'].append(msg)
        if data.get(b'pupitre', '') != '' \
                and data.get(b'profession') \
                and data[b'profession'].parties.exists():
            msg = _('Au moins un rôle ou instrument est lié à cette '
                    'profession. Remplissez donc « Pupitre » à la place.')
            error_msgs[b'profession'].append(msg)

        for k, v in error_msgs.items():
            self._errors[k] = self.error_class(v)
            if k in data:
                del data[k]

        return data

class ElementDeProgrammeForm(ModelForm):
    class Meta(object):
        model = ElementDeProgramme
        # FIXME: Rendre fonctionnel ce qui suit.
        # widgets = {
        #     b'autre': AutoCompleteWidget('elementdeprogramme__autre',
        #                                  attrs={'style': 'width: 600px;'}),
        # }

    def clean(self):
        data = super(ElementDeProgrammeForm, self).clean()

        if not (data[b'autre'] or data[b'oeuvre'] or data[b'distribution']):
            raise ValidationError(_('Vous devez remplir au moins « Œuvre », '
                                    '« Autre » ou « Distribution ».'))

        if data[b'autre'] and data[b'oeuvre']:
            raise ValidationError(_('Vous ne pouvez remplir à la fois '
                                    '« Œuvre » et « Autre ».'))

        return data

class SourceForm(ModelForm):
    class Meta(object):
        model = Source
        widgets = {
            b'titre': AutoCompleteWidget('source__titre',
                                         attrs={'style': 'width: 600px;'}),
            b'numero': TextInput(attrs={'cols': 10}),
            b'folio': TextInput(attrs={'cols': 10}),
            b'page': TextInput(attrs={'cols': 10}),
        }

    def clean(self):
        data = super(SourceForm, self).clean()

        if not (data['titre'] or (data['lieu_conservation'] and data['cote'])):
            raise ValidationError(_('Vous devez remplir « Titre » ou '
                                    '« Lieu de conservation » et « Cote ».'))

        return data

class SaisonForm(ModelForm):
    class Meta(object):
        model = Source

    def clean(self):
        data = super(SaisonForm, self).clean()

        debut = data.get('debut')
        fin = data.get('fin')
        ensemble = data.get('ensemble')
        lieu = data.get('lieu')

        if not ((ensemble is None) ^ (lieu is None)):
            raise ValidationError(
                _('Vous devez remplir « Ensemble » '
                  'ou « Lieu ou Institution »'))

        if debut and fin:
            if debut > fin:
                raise ValidationError(_('La fin ne peut précéder le début.'))
            elif fin - debut > timedelta(365):
                raise ValidationError(_('La durée d’une saison ne peut excéder '
                                        'un an.'))

        overlapping_seasons = Saison.objects.filter(
            Q(debut__range=(debut, fin)) | Q(fin__range=(debut, fin))
            | Q(debut__lt=debut, fin__gt=fin),
            ensemble=ensemble, lieu=lieu)
        if overlapping_seasons.exists():
            raise ValidationError(
                _('Une saison existe déjà sur cette période pour « %s ».')
                % (ensemble or lieu))
        return data

class EvenementListForm(Form):
    q = CharField(label=_('Recherche libre'), required=False)
    dates = RangeSliderField(required=False)
    lieu = AutoCompleteSelectMultipleField('lieu', label=_('Lieu'),
                                           required=False, help_text='')
    oeuvre = AutoCompleteSelectMultipleField(
        'oeuvre', required=False, label=_('Œuvre'), help_text='')
    individu = AutoCompleteSelectMultipleField(
        'individu', required=False, label=_('Individu'), help_text='')
    ensemble = AutoCompleteSelectMultipleField(
        'ensemble', required=False, label=_('Ensemble'), help_text='')

    def __init__(self, *args, **kwargs):
        queryset = kwargs.pop('queryset')

        self.helper = FormHelper()
        self.helper.form_method = 'GET'
        self.helper.form_class = 'well well-sm'
        self.helper.layout = Layout(
            Field('q', css_class='input-lg'),
            HTML('
'),
            'dates',
            HTML('
'),
            'lieu', 'oeuvre', 'individu', 'ensemble',
            HTML('
'),
            Submit('', _('Filtrer'), css_class='btn-lg btn-block',
                   data_loading_text=_('Chargement…')),
        )

        super(EvenementListForm, self).__init__(*args, **kwargs)

        for field in self.fields.values():
            field.widget.attrs[b'placeholder'] = (field.label or '') + '…'
            field.label = ''

        self.fields['dates'].widget.queryset = queryset
<|endoftext|>


<commit_before># All of SubliminalCollaborator is licensed under the MIT license.

#   Copyright (c) 2012 Nick Lloyd

#   Permission is hereby granted, free of charge, to any person obtaining a copy
#   of this software and associated documentation files (the "Software"), to deal
#   in the Software without restriction, including without limitation the rights
#   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#   copies of the Software, and to permit persons to whom the Software is
#   furnished to do so, subject to the following conditions:

#   The above copyright notice and this permission notice shall be included in
#   all copies or substantial portions of the Software.

#   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHE`R
#   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#   THE SOFTWARE.
from zope.interface import implements
from peer import interface
from twisted.internet import reactor, protocol, error, interfaces
from twisted.protocols import basic
import sublime
import logging, sys, socket, struct, os

logger = logging.getLogger(__name__)
logger.propagate = False
# purge previous handlers set... for plugin reloading
del logger.handlers[:]
stdoutHandler = logging.StreamHandler(sys.stdout)
stdoutHandler.setFormatter(logging.Formatter(fmt='[SubliminalCollaborator|Peer(%(levelname)s): %(message)s]'))
logger.addHandler(stdoutHandler)
logger.setLevel(logging.DEBUG)

# in bytes
MAX_CHUNK_SIZE = 512

# build off of the Int32StringReceiver to leverage its unprocessed buffer handling
class BasePeer(basic.Int32StringReceiver, protocol.ClientFactory, protocol.ServerFactory):
    """
    One side of a peer-to-peer collaboration connection.
    This is a direct connection with another peer endpoint for sending
    view data and events.
    """
    implements(interface.Peer)

    # Message header structure in struct format:
    # '!HBB'

    # elements:
    # - magicNumber: 9, http://futurama.wikia.com/wiki/Number_9_man
    # - messageType: see constants below
    # - messageSubType: see constants below, 0 in all but edit-messages
    messageHeaderFmt = '!HBB'
    messageHeaderSize = struct.calcsize(messageHeaderFmt)

    # registered callback methods
    switchRole = None
    peerInitiatedDisconnect = None

    def __init__(self, username, failedToInitConnectCallback=None):
        self.sharingWithUser = username
        # connection can be an IListeningPort or IConnector
        self.connection = None
        self.host = None
        self.port = None
        # CLIENT or SERVER
        self.peerType = None
        # HOST_ROLE or PARTNER_ROLE
        self.role = None
        # STATE_CONNECTING, STATE_CONNECTED, STATE_DISCONNECTED
        self.state = None
        self.view = None
        self.failedToInitConnectCallback = failedToInitConnectCallback

    def hostConnect(self, port = 0):
        """
        Initiate a peer-to-peer session as the host by listening on the
        given port for a connection.

        @param port: C{int} port number to listen on, defaults to 0 (system will pick one)

        @return: the connected port number
        """
        self.peerType = interface.SERVER
        self.role = interface.HOST_ROLE
        self.state = interface.STATE_CONNECTING
        self.connection = reactor.listenTCP(port, self)
        self.port = self.connection.getHost().port
        logger.info('Listening for peers on port %d' % self.port)
        return self.port

    def clientConnect(self, host, port):
        """
        Initiate a peer-to-peer session as the partner by connecting to the
        host peer with the given host and port.

        @param host: ip address of the host Peer
        @param port: C{int} port number of the host Peer
        """
        logger.info('Connecting to peer at %s:%d' % (host, port))
        self.host = host
        self.port = port
        self.peerType = interface.CLIENT
        self.role = interface.PARTNER_ROLE
        self.state = interface.STATE_CONNECTING
        self.connection = reactor.connectTCP(self.host, self.port, self)

    def recvd_CONNECTED(self, messageSubType, payload):
        if self.peerType == interface.CLIENT:
            if self.state == interface.STATE_CONNECTING:
                self.state = interface.STATE_CONNECTED
                logger.info('Connected to peer: %s' % self.sharingWithUser)
            else:
                logger.error('Received CONNECTED message from server-peer when in state %s' % self.state)
        else:
            # client is connected, send ACK and set our state to be connected
            self.sendMessage(interface.CONNECTED)
            self.state = interface.STATE_CONNECTED
            logger.info('Connected to peer: %s' % self.sharingWithUser)

    def disconnect(self):
        """
        Disconnect from the peer-to-peer session.
        """
        if self.state == interface.STATE_DISCONNECTED:
            # already disconnected!
            return
        earlierState = self.state
        self.state = interface.STATE_DISCONNECTING
        if self.peerType == interface.SERVER:
            reactor.callFromThread(self.connection.stopListening)
            if not earlierState == interface.STATE_REJECT_TRIGGERED_DISCONNECTING:
                logger.debug('Telling peer to disconnect')
                self.sendMessage(interface.DISCONNECT)
        elif self.peerType == interface.CLIENT:
            logger.debug('Closing client-side connection')
            # self.connection.disconnect()
            self.sendMessage(interface.DISCONNECT)
            reactor.callFromThread(self.connection.disconnect)

    def recvd_DISCONNECT(self, messsageSubType=None, payload=''):
        """
        Callback method if we receive a DISCONNECT message.
        """
        if self.peerType == interface.CLIENT:
            logger.debug('Disconnecting from peer at %s:%d' % (self.host, self.port))
        else:
            logger.debug('Disconnecting from peer at %d' % self.port)
        self.disconnect()
        self.state = interface.STATE_DISCONNECTED
        logger.info('Disconnected from peer %s' % self.sharingWithUser)

    def startCollab(self, view):
        """
        Send the provided C{sublime.View} contents to the connected peer.
        """
        self.view = view
        self.view.set_read_only(True)
        viewName = self.view.file_name()
        if not viewName == None:
            viewName = os.path.basename(viewName)
        else:
            viewName = 'SHARED-WITH-%s' % self.sharingWithUser
        totalToSend = self.view.size()
        begin = 0
        end = MAX_CHUNK_SIZE
        logger.info('Sharing view %s with %s' % (self.view.file_name(), self.sharingWithUser))
        self.toAck = []
        self.sendMessage(interface.SHARE_VIEW, payload=viewName)
        while begin < totalToSend:
            chunkToSend = self.view.substr(sublime.Region(begin, end))
            self.toAck.append(len(chunkToSend))
            self.sendMessage(interface.VIEW_CHUNK, payload=chunkToSend)
            begin = begin + MAX_CHUNK_SIZE
            end = end + MAX_CHUNK_SIZE
        self.sendMessage(interface.END_OF_VIEW)
        self.view.set_read_only(False)

    def onStartCollab(self):
        """
        Callback method informing the peer that we have received the view.
        """
        logger.debug('collaboration session with view started!')

    def stopCollab(self):
        """
        Notify the connected peer that we are terminating the collaborating session.
        """
        pass

    def onStopCollab(self):
        """
        Callback method informing the peer that we are terminating a collaborating session.
        """
        pass

    def sendViewPositionUpdate(self, centerOnRegion):
        """
        Send a window view position update to the peer so they know what
        we are looking at.

        @param centerOnRegion: C{sublime.Region} of the current visible portion of the view to send to the peer.
        """
        pass

    def recvViewPositionUpdate(self, centerOnRegion):
        """
        Callback method for handling view position updates from the peer.

        @param centerOnRegion: C{sublime.Region} of the region to set as the current visible portion of the view.
        """
        pass

    def sendSelectionUpdate(self, selectedRegions):
        """
        Send currently selected regions to the peer.

        @param selectedRegions: C{sublime.RegionSet} of all selected regions in the current view.
        """
        pass

    def recvSelectionUpdate(self, selectedRegions):
        """
        Callback method for handling selected regions updates from the peer.

        @param selectedRegions: C{sublime.RegionSet} of all selected regions to be set.
        """
        pass

    def sendEdit(self, editType, content):
        """
        Send an edit event to the peer.

        @param editType: C{str} insert, edit, delete
        @param content: C{str} contents of the edit (None if delete editType)
        """
        pass

    def recvEdit(self, editType, content):
        """
        Callback method for handling edit events from the peer.

        @param editType: C{str} insert, edit, delete
        @param content: C{str} contents of the edit (None if delete editType)
        """
        pass

    def recvd_SHARE_VIEW(self, messageSubType, payload):
        self.view = sublime.active_window().new_file()
        self.view.set_name(payload)
        self.view.set_read_only(True)
        self.view.set_scratch(True)
        self.viewPopulateEdit = self.view.begin_edit()
        self.sendMessage(interface.SHARE_VIEW_ACK)

    def recvd_SHARE_VIEW_ACK(self, messageSubType, payload):
        self.ackdChunks = []

    def recvd_VIEW_CHUNK(self, messageSubType, payload):
        self.view.insert(self.viewPopulateEdit, self.view.size(), payload)
        self.sendMessage(interface.VIEW_CHUNK_ACK, payload=str(len(payload)))

    def recvd_VIEW_CHUNK_ACK(self, messageSubType, payload):
        ackdChunkSize = int(payload)
        self.ackdChunks.append(ackdChunkSize)

    def recvd_END_OF_VIEW(self, messageSubType, payload):
        self.view.end_edit(self.viewPopulateEdit)
        self.viewPopulateEdit = None
        self.view.set_read_only(False)
        self.sendMessage(interface.END_OF_VIEW_ACK)
        self.onStartCollab()

    def recvd_END_OF_VIEW_ACK(self, messageSubType, payload):
        if self.toAck == self.ackdChunks:
            self.toAck = None
            self.ackdChunks = None
        else:
            logger.error('Sent %s chunks of data to peer but peer received %s chunks of data' % (self.toAck, self.ackdChunks))
            self.toAck = None
            self.ackdChunks = None
            self.sendMessage(interface.BAD_VIEW_SEND)
            # TODO status bar message as well... or perhaps a popup alert?
            self.disconnect()

    def recvdUnknown(self, messageType, messageSubType, payload):
        logger.warn('Received unknown message: %s, %s, %s' % (messageType, messageSubType, payload))

    def stringReceived(self, data):
        magicNumber, msgTypeNum, msgSubTypeNum = struct.unpack(self.messageHeaderFmt, data[:self.messageHeaderSize])
        assert magicNumber == interface.MAGIC_NUMBER
        msgType = interface.numeric_to_symbolic[msgTypeNum]
        msgSubType = interface.numeric_to_symbolic[msgSubTypeNum]
        payload = data[self.messageHeaderSize:]
        logger.debug('RECVD: %s, %s, %d' % (msgType, msgSubType, len(payload)))
        method = getattr(self, "recvd_%s" % msgType, None)
        if method is not None:
            method(msgSubType, payload)
        else:
            self.recvdUnknown(msgType, msgSubType, payload)

    def connectionLost(self, reason):
        if self.peerType == interface.CLIENT:
            # ignore this, clientConnectionLost() below will also be called
            return
        self.state = interface.STATE_DISCONNECTED
        if error.ConnectionDone == reason.type:
            self.disconnect()
        else:
            # may want to reconnect, but for now lets print why
            logger.error('Connection lost: %s - %s' % (reason.type, reason.value))

    #*** protocol.Factory method implementations ***#

    def buildProtocol(self, addr):
        logger.debug('building protocol for %s' % self.peerType)
        if self.peerType == interface.CLIENT:
            logger.debug('Connected to peer at %s:%d' % (self.host, self.port))
            self.sendMessage(interface.CONNECTED)
        return self

    #*** protocol.ClientFactory method implementations ***#

    def clientConnectionLost(self, connector, reason):
        self.state = interface.STATE_DISCONNECTED
        if error.ConnectionDone == reason.type:
            self.disconnect()
        else:
            # may want to reconnect, but for now lets print why
            logger.error('Connection lost: %s - %s' % (reason.type, reason.value))

    def clientConnectionFailed(self, connector, reason):
        logger.error('Connection failed: %s - %s' % (reason.type, reason.value))
        self.state = interface.STATE_DISCONNECTED
        if error.ConnectionRefusedError == reason.type:
            if (self.peerType == interface.CLIENT) and (not self.failedToInitConnectCallback == None):
                self.failedToInitConnectCallback(self.sharingWithUser)
        self.disconnect()

    #*** helper functions ***#

    def sendMessage(self, messageType, messageSubType=interface.EDIT_TYPE_NA, payload=''):
        logger.debug('SEND: %s-%s[%d]' % (interface.numeric_to_symbolic[messageType], interface.numeric_to_symbolic[messageSubType], len(payload)))
        reactor.callFromThread(self.sendString, struct.pack(self.messageHeaderFmt, interface.MAGIC_NUMBER, messageType, messageSubType) + payload.encode())

    def str(self):
        return self.sharingWithUser
<commit_msg>- partner/client-peer view set to read only<commit_after># All of SubliminalCollaborator is licensed under the MIT license.

#   Copyright (c) 2012 Nick Lloyd

#   Permission is hereby granted, free of charge, to any person obtaining a copy
#   of this software and associated documentation files (the "Software"), to deal
#   in the Software without restriction, including without limitation the rights
#   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#   copies of the Software, and to permit persons to whom the Software is
#   furnished to do so, subject to the following conditions:

#   The above copyright notice and this permission notice shall be included in
#   all copies or substantial portions of the Software.

#   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHE`R
#   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#   THE SOFTWARE.
from zope.interface import implements
from peer import interface
from twisted.internet import reactor, protocol, error, interfaces
from twisted.protocols import basic
import sublime
import logging, sys, socket, struct, os

logger = logging.getLogger(__name__)
logger.propagate = False
# purge previous handlers set... for plugin reloading
del logger.handlers[:]
stdoutHandler = logging.StreamHandler(sys.stdout)
stdoutHandler.setFormatter(logging.Formatter(fmt='[SubliminalCollaborator|Peer(%(levelname)s): %(message)s]'))
logger.addHandler(stdoutHandler)
logger.setLevel(logging.DEBUG)

# in bytes
MAX_CHUNK_SIZE = 512

# build off of the Int32StringReceiver to leverage its unprocessed buffer handling
class BasePeer(basic.Int32StringReceiver, protocol.ClientFactory, protocol.ServerFactory):
    """
    One side of a peer-to-peer collaboration connection.
    This is a direct connection with another peer endpoint for sending
    view data and events.
    """
    implements(interface.Peer)

    # Message header structure in struct format:
    # '!HBB'

    # elements:
    # - magicNumber: 9, http://futurama.wikia.com/wiki/Number_9_man
    # - messageType: see constants below
    # - messageSubType: see constants below, 0 in all but edit-messages
    messageHeaderFmt = '!HBB'
    messageHeaderSize = struct.calcsize(messageHeaderFmt)

    # registered callback methods
    switchRole = None
    peerInitiatedDisconnect = None

    def __init__(self, username, failedToInitConnectCallback=None):
        self.sharingWithUser = username
        # connection can be an IListeningPort or IConnector
        self.connection = None
        self.host = None
        self.port = None
        # CLIENT or SERVER
        self.peerType = None
        # HOST_ROLE or PARTNER_ROLE
        self.role = None
        # STATE_CONNECTING, STATE_CONNECTED, STATE_DISCONNECTED
        self.state = None
        self.view = None
        self.failedToInitConnectCallback = failedToInitConnectCallback

    def hostConnect(self, port = 0):
        """
        Initiate a peer-to-peer session as the host by listening on the
        given port for a connection.

        @param port: C{int} port number to listen on, defaults to 0 (system will pick one)

        @return: the connected port number
        """
        self.peerType = interface.SERVER
        self.role = interface.HOST_ROLE
        self.state = interface.STATE_CONNECTING
        self.connection = reactor.listenTCP(port, self)
        self.port = self.connection.getHost().port
        logger.info('Listening for peers on port %d' % self.port)
        return self.port

    def clientConnect(self, host, port):
        """
        Initiate a peer-to-peer session as the partner by connecting to the
        host peer with the given host and port.

        @param host: ip address of the host Peer
        @param port: C{int} port number of the host Peer
        """
        logger.info('Connecting to peer at %s:%d' % (host, port))
        self.host = host
        self.port = port
        self.peerType = interface.CLIENT
        self.role = interface.PARTNER_ROLE
        self.state = interface.STATE_CONNECTING
        self.connection = reactor.connectTCP(self.host, self.port, self)

    def recvd_CONNECTED(self, messageSubType, payload):
        if self.peerType == interface.CLIENT:
            if self.state == interface.STATE_CONNECTING:
                self.state = interface.STATE_CONNECTED
                logger.info('Connected to peer: %s' % self.sharingWithUser)
            else:
                logger.error('Received CONNECTED message from server-peer when in state %s' % self.state)
        else:
            # client is connected, send ACK and set our state to be connected
            self.sendMessage(interface.CONNECTED)
            self.state = interface.STATE_CONNECTED
            logger.info('Connected to peer: %s' % self.sharingWithUser)

    def disconnect(self):
        """
        Disconnect from the peer-to-peer session.
        """
        if self.state == interface.STATE_DISCONNECTED:
            # already disconnected!
            return
        earlierState = self.state
        self.state = interface.STATE_DISCONNECTING
        if self.peerType == interface.SERVER:
            reactor.callFromThread(self.connection.stopListening)
            if not earlierState == interface.STATE_REJECT_TRIGGERED_DISCONNECTING:
                logger.debug('Telling peer to disconnect')
                self.sendMessage(interface.DISCONNECT)
        elif self.peerType == interface.CLIENT:
            logger.debug('Closing client-side connection')
            # self.connection.disconnect()
            self.sendMessage(interface.DISCONNECT)
            reactor.callFromThread(self.connection.disconnect)

    def recvd_DISCONNECT(self, messsageSubType=None, payload=''):
        """
        Callback method if we receive a DISCONNECT message.
        """
        if self.peerType == interface.CLIENT:
            logger.debug('Disconnecting from peer at %s:%d' % (self.host, self.port))
        else:
            logger.debug('Disconnecting from peer at %d' % self.port)
        self.disconnect()
        self.state = interface.STATE_DISCONNECTED
        logger.info('Disconnected from peer %s' % self.sharingWithUser)

    def startCollab(self, view):
        """
        Send the provided C{sublime.View} contents to the connected peer.
        """
        self.view = view
        self.view.set_read_only(True)
        viewName = self.view.file_name()
        if not viewName == None:
            viewName = os.path.basename(viewName)
        else:
            viewName = 'SHARED-WITH-%s' % self.sharingWithUser
        totalToSend = self.view.size()
        begin = 0
        end = MAX_CHUNK_SIZE
        logger.info('Sharing view %s with %s' % (self.view.file_name(), self.sharingWithUser))
        self.toAck = []
        self.sendMessage(interface.SHARE_VIEW, payload=viewName)
        while begin < totalToSend:
            chunkToSend = self.view.substr(sublime.Region(begin, end))
            self.toAck.append(len(chunkToSend))
            self.sendMessage(interface.VIEW_CHUNK, payload=chunkToSend)
            begin = begin + MAX_CHUNK_SIZE
            end = end + MAX_CHUNK_SIZE
        self.sendMessage(interface.END_OF_VIEW)
        self.view.set_read_only(False)

    def onStartCollab(self):
        """
        Callback method informing the peer that we have received the view.
        """
        logger.debug('collaboration session with view started!')

    def stopCollab(self):
        """
        Notify the connected peer that we are terminating the collaborating session.
        """
        pass

    def onStopCollab(self):
        """
        Callback method informing the peer that we are terminating a collaborating session.
        """
        pass

    def sendViewPositionUpdate(self, centerOnRegion):
        """
        Send a window view position update to the peer so they know what
        we are looking at.

        @param centerOnRegion: C{sublime.Region} of the current visible portion of the view to send to the peer.
        """
        pass

    def recvViewPositionUpdate(self, centerOnRegion):
        """
        Callback method for handling view position updates from the peer.

        @param centerOnRegion: C{sublime.Region} of the region to set as the current visible portion of the view.
        """
        pass

    def sendSelectionUpdate(self, selectedRegions):
        """
        Send currently selected regions to the peer.

        @param selectedRegions: C{sublime.RegionSet} of all selected regions in the current view.
        """
        pass

    def recvSelectionUpdate(self, selectedRegions):
        """
        Callback method for handling selected regions updates from the peer.

        @param selectedRegions: C{sublime.RegionSet} of all selected regions to be set.
        """
        pass

    def sendEdit(self, editType, content):
        """
        Send an edit event to the peer.

        @param editType: C{str} insert, edit, delete
        @param content: C{str} contents of the edit (None if delete editType)
        """
        pass

    def recvEdit(self, editType, content):
        """
        Callback method for handling edit events from the peer.

        @param editType: C{str} insert, edit, delete
        @param content: C{str} contents of the edit (None if delete editType)
        """
        pass

    def recvd_SHARE_VIEW(self, messageSubType, payload):
        self.view = sublime.active_window().new_file()
        self.view.set_name(payload)
        self.view.set_read_only(True)
        self.view.set_scratch(True)
        self.viewPopulateEdit = self.view.begin_edit()
        self.sendMessage(interface.SHARE_VIEW_ACK)

    def recvd_SHARE_VIEW_ACK(self, messageSubType, payload):
        self.ackdChunks = []

    def recvd_VIEW_CHUNK(self, messageSubType, payload):
        self.view.insert(self.viewPopulateEdit, self.view.size(), payload)
        self.sendMessage(interface.VIEW_CHUNK_ACK, payload=str(len(payload)))

    def recvd_VIEW_CHUNK_ACK(self, messageSubType, payload):
        ackdChunkSize = int(payload)
        self.ackdChunks.append(ackdChunkSize)

    def recvd_END_OF_VIEW(self, messageSubType, payload):
        self.view.end_edit(self.viewPopulateEdit)
        self.viewPopulateEdit = None
        # self.view.set_read_only(False)
        self.sendMessage(interface.END_OF_VIEW_ACK)
        self.onStartCollab()

    def recvd_END_OF_VIEW_ACK(self, messageSubType, payload):
        if self.toAck == self.ackdChunks:
            self.toAck = None
            self.ackdChunks = None
        else:
            logger.error('Sent %s chunks of data to peer but peer received %s chunks of data' % (self.toAck, self.ackdChunks))
            self.toAck = None
            self.ackdChunks = None
            self.sendMessage(interface.BAD_VIEW_SEND)
            # TODO status bar message as well... or perhaps a popup alert?
            self.disconnect()

    def recvdUnknown(self, messageType, messageSubType, payload):
        logger.warn('Received unknown message: %s, %s, %s' % (messageType, messageSubType, payload))

    def stringReceived(self, data):
        magicNumber, msgTypeNum, msgSubTypeNum = struct.unpack(self.messageHeaderFmt, data[:self.messageHeaderSize])
        assert magicNumber == interface.MAGIC_NUMBER
        msgType = interface.numeric_to_symbolic[msgTypeNum]
        msgSubType = interface.numeric_to_symbolic[msgSubTypeNum]
        payload = data[self.messageHeaderSize:]
        logger.debug('RECVD: %s, %s, %d' % (msgType, msgSubType, len(payload)))
        method = getattr(self, "recvd_%s" % msgType, None)
        if method is not None:
            method(msgSubType, payload)
        else:
            self.recvdUnknown(msgType, msgSubType, payload)

    def connectionLost(self, reason):
        if self.peerType == interface.CLIENT:
            # ignore this, clientConnectionLost() below will also be called
            return
        self.state = interface.STATE_DISCONNECTED
        if error.ConnectionDone == reason.type:
            self.disconnect()
        else:
            # may want to reconnect, but for now lets print why
            logger.error('Connection lost: %s - %s' % (reason.type, reason.value))

    #*** protocol.Factory method implementations ***#

    def buildProtocol(self, addr):
        logger.debug('building protocol for %s' % self.peerType)
        if self.peerType == interface.CLIENT:
            logger.debug('Connected to peer at %s:%d' % (self.host, self.port))
            self.sendMessage(interface.CONNECTED)
        return self

    #*** protocol.ClientFactory method implementations ***#

    def clientConnectionLost(self, connector, reason):
        self.state = interface.STATE_DISCONNECTED
        if error.ConnectionDone == reason.type:
            self.disconnect()
        else:
            # may want to reconnect, but for now lets print why
            logger.error('Connection lost: %s - %s' % (reason.type, reason.value))

    def clientConnectionFailed(self, connector, reason):
        logger.error('Connection failed: %s - %s' % (reason.type, reason.value))
        self.state = interface.STATE_DISCONNECTED
        if error.ConnectionRefusedError == reason.type:
            if (self.peerType == interface.CLIENT) and (not self.failedToInitConnectCallback == None):
                self.failedToInitConnectCallback(self.sharingWithUser)
        self.disconnect()

    #*** helper functions ***#

    def sendMessage(self, messageType, messageSubType=interface.EDIT_TYPE_NA, payload=''):
        logger.debug('SEND: %s-%s[%d]' % (interface.numeric_to_symbolic[messageType], interface.numeric_to_symbolic[messageSubType], len(payload)))
        reactor.callFromThread(self.sendString, struct.pack(self.messageHeaderFmt, interface.MAGIC_NUMBER, messageType, messageSubType) + payload.encode())

    def str(self):
        return self.sharingWithUser
<|endoftext|>


<commit_before>#! /usr/bin/env python
import random
import string

import bs4
import requests

class UpBeatBot(object):
    """Source of uplifting media"""

    # List of animals to look for in a message
    # Used by _get_animal_from_message
    animals = [
        'kittens', 'kitten', 'pugs', 'pug', 'cats', 'cat', 'gerbils',
        'gerbil', 'bunnies', 'bunny', 'chipmunks', 'chipmunk', 'dogs',
        'dog', 'otters', 'otter', 'chinchillas', 'chinchilla', 'red pandas',
        'red panda', 'squirrel', 'squirrels'
    ]

    def get_cute_animal_picture(self, message=None):
        """
        Return a link to a cute picture of an animal. If a message is provided, will try to parse the message for an
        animal we have registered and try to find a picture of the animal. If the message does not contain an animal
        we have registered, or is not provided, will search for a random animal from our choices.
        :param message: (str) Optional message to parse to determine what animal to search for
        :return: (str) Link to an image of a cute animal
        """
        if message:
            animal = self._get_animal_from_message(message)

        else:
            animal = random.choice(self.animals)

        # Get preview page for animal
        preview_html = requests.get('http://www.cutestpaw.com/?s={0}'.format(animal))

        preview_html.raise_for_status()

        preview_soup = bs4.BeautifulSoup(preview_html.text, 'html.parser')

        # Get random picture from preview page
        photos = preview_soup.select('#photos a')
        choice = random.choice(photos)

        # Get picture page
        picture_html = requests.get(choice['href'])
        picture_html.raise_for_status()

        picture_soup = bs4.BeautifulSoup(picture_html.text, 'html.parser')

        # Parse picture page for image
        img = picture_soup.select('#single-cute-wrap img')
        link = img[0]['src']

        return link

    def _get_animal_from_message(self, message):
        """
        Given a message (tweet, comment, post, etc.) parse the string to find if the message contains an animal in
        our choices list. If we can't find an animal from our choices in the text, return a random animal from our
        choices list.
        :param message: (str) Text to search for an animal we have registered
        :return: (str) Cute animal to be used for retrieving a cute picture
        """
        animal = None

        for char in string.punctuation:
            message = message.replace(char, '')

        for word in message.split(' '):
            if word in self.animals:
                animal = word
                break

        if animal is None:
            animal = random.choice(self.animals)

        return animal
<commit_msg>Remove shebang from upbeatbot module<commit_after>import random
import string

import bs4
import requests

class UpBeatBot(object):
    """Source of uplifting media"""

    # List of animals to look for in a message
    animals = [
        'kittens', 'kitten', 'pugs', 'pug', 'cats', 'cat', 'gerbils',
        'gerbil', 'bunnies', 'bunny', 'chipmunks', 'chipmunk', 'dogs',
        'dog', 'otters', 'otter', 'chinchillas', 'chinchilla', 'red pandas',
        'red panda', 'squirrel', 'squirrels'
    ]

    def get_cute_animal_picture(self, message=None):
        """
        Return a link to a cute picture of an animal. If a message is provided, will try to parse the message for an
        animal we have registered and try to find a picture of the animal. If the message does not contain an animal
        we have registered, or is not provided, will search for a random animal from our choices.
        :param message: (str) Optional message to parse to determine what animal to search for
        :return: (str) Link to an image of a cute animal
        """
        if message:
            animal = self._get_animal_from_message(message)

        else:
            animal = random.choice(self.animals)

        # Get preview page for animal
        preview_html = requests.get('http://www.cutestpaw.com/?s={0}'.format(animal))

        preview_html.raise_for_status()

        preview_soup = bs4.BeautifulSoup(preview_html.text, 'html.parser')

        # Get random picture from preview page
        photos = preview_soup.select('#photos a')
        choice = random.choice(photos)

        # Get picture page
        picture_html = requests.get(choice['href'])
        picture_html.raise_for_status()

        picture_soup = bs4.BeautifulSoup(picture_html.text, 'html.parser')

        # Parse picture page for image
        img = picture_soup.select('#single-cute-wrap img')
        link = img[0]['src']

        return link

    def _get_animal_from_message(self, message):
        """
        Given a message (tweet, comment, post, etc.) parse the string to find if the message contains an animal in
        our choices list. If we can't find an animal from our choices in the text, return a random animal from our
        choices list.
        :param message: (str) Text to search for an animal we have registered
        :return: (str) Cute animal to be used for retrieving a cute picture
        """
        animal = None

        for char in string.punctuation:
            message = message.replace(char, '')

        for word in message.split(' '):
            if word in self.animals:
                animal = word
                break

        if animal is None:
            animal = random.choice(self.animals)

        return animal
<|endoftext|>


<commit_before>from __future__ import division

try:
  from glob import glob
  import libtbx.load_env
  import os
  dials_path = libtbx.env.dist_path('dials')
  filenames = glob(os.path.join(dials_path, "extensions", "*.pyc"))
  if len(filenames) > 0:
    print "Cleaning up 'dials/extensions':"
    for filename in filenames:
      print " Deleting %s" % filename
      os.remove(filename)
except Exception:
  pass

try:
  from dials.framework import env
  env.cache.wipe()
except Exception:
  pass

try:
  from dials.util.version import dials_version
  print dials_version()
except Exception:
  pass

def _install_dials_autocompletion():
  '''generate init.sh and SConscript file in /build/dials/autocomplete'''
  import libtbx.load_env
  import os

  # Find the dials source directory
  dist_path = libtbx.env.dist_path('dials')

  # Set the location of the output directory
  output_directory = libtbx.env.under_build(os.path.join('dials', 'autocomplete'))
  try:
    os.makedirs(output_directory)
  except OSError:
    pass

  commands_dir = os.path.join(dist_path, 'command_line')
  command_list = []
  print 'Identifying autocompletable commands:',
  for file in sorted(os.listdir(commands_dir)):
    if not file.startswith('_') and file.endswith('.py'):
      if 'DIALS_ENABLE_COMMAND_LINE_COMPLETION' in open(os.path.join(commands_dir, file)).read():
        command_name = 'dials.%s' % file[:-3]
        print command_name,
        command_list.append(command_name)
  print

  # Generate the autocompletion SConscript.
  with open(os.path.join(output_directory, 'SConscript'), 'w') as builder:
    builder.write('''Import("env")
import os.path
import libtbx.load_env
def dispatcher_outer(name):
  return os.path.join(libtbx.env.under_build('bin'), name)
def dispatcher_inner(name):
  return os.path.join(libtbx.env.dist_path('dials'), 'command_line', '%%s.py' %% name.partition('.')[2])
env.Append( BUILDERS={'AutoComplete': Builder(action='-$SOURCE --export-autocomplete-hints > $TARGET')} )
for cmd in [%s]:
  ac = env.AutoComplete(cmd, [dispatcher_outer(cmd), dispatcher_inner(cmd)])
  Requires(ac, Dir(libtbx.env.under_build('lib')))
  Depends(ac, os.path.join(libtbx.env.dist_path('dials'), 'util', 'options.py'))
  Depends(ac, os.path.join(libtbx.env.dist_path('dials'), 'util', 'autocomplete.sh'))
''' % ( ', '.join(["'%s'" % cmd for cmd in command_list]) ))

  # Generate a bash script activating command line completion for each relevant command
  with open(os.path.join(output_directory, 'bash.sh'), 'w') as script:
    script.write("type compopt &>/dev/null && {\n")
    for cmd in command_list:
      script.write(" complete -F _dials_autocomplete %s\n" % cmd)
    script.write("}\n")
    script.write("type compopt &>/dev/null || {\n")
    for cmd in command_list:
      script.write(" complete -o nospace -F _dials_autocomplete %s\n" % cmd)
    script.write("}\n")

  # Find the dials build directory
  build_path = abs(libtbx.env.build_path)

  # Permanently install the autocompletion script into setpaths-scripts.
  print "Installing autocompletion script into:",
  for file in os.listdir(build_path):
    if file.startswith('setpath') and file.endswith('.sh'):
      original_file = open(os.path.join(build_path, file)).read()
      if not 'DIALS_ENABLE_COMMAND_LINE_COMPLETION' in original_file:
        marker = "\nexport PATH\n"
        insert_position = original_file.find(marker) + len(marker)
        if insert_position >= 0:
          print file,
          added_script = \
            '# DIALS_ENABLE_COMMAND_LINE_COMPLETION\n' \
            '[ -n "$BASH_VERSION" ] && {\n' \
            ' source $(libtbx.find_in_repositories dials/util/autocomplete.sh)\n' \
            ' source %s\n' \
            '}\n' % (
              os.path.join('$LIBTBX_BUILD', 'dials', 'autocomplete', 'bash.sh'))
          with open(os.path.join(build_path, file), 'w') as script:
            script.write(original_file[:insert_position] +
                         added_script +
                         original_file[insert_position:])
  print

_install_dials_autocompletion()
<commit_msg>fix comment. init.sh is no more.<commit_after>from __future__ import division

try:
  from glob import glob
  import libtbx.load_env
  import os
  dials_path = libtbx.env.dist_path('dials')
  filenames = glob(os.path.join(dials_path, "extensions", "*.pyc"))
  if len(filenames) > 0:
    print "Cleaning up 'dials/extensions':"
    for filename in filenames:
      print " Deleting %s" % filename
      os.remove(filename)
except Exception:
  pass

try:
  from dials.framework import env
  env.cache.wipe()
except Exception:
  pass

try:
  from dials.util.version import dials_version
  print dials_version()
except Exception:
  pass

def _install_dials_autocompletion():
  '''generate bash.sh and SConscript file in /build/dials/autocomplete'''
  import libtbx.load_env
  import os

  # Find the dials source directory
  dist_path = libtbx.env.dist_path('dials')

  # Set the location of the output directory
  output_directory = libtbx.env.under_build(os.path.join('dials', 'autocomplete'))
  try:
    os.makedirs(output_directory)
  except OSError:
    pass

  commands_dir = os.path.join(dist_path, 'command_line')
  command_list = []
  print 'Identifying autocompletable commands:',
  for file in sorted(os.listdir(commands_dir)):
    if not file.startswith('_') and file.endswith('.py'):
      if 'DIALS_ENABLE_COMMAND_LINE_COMPLETION' in open(os.path.join(commands_dir, file)).read():
        command_name = 'dials.%s' % file[:-3]
        print command_name,
        command_list.append(command_name)
  print

  # Generate the autocompletion SConscript.
  with open(os.path.join(output_directory, 'SConscript'), 'w') as builder:
    builder.write('''Import("env")
import os.path
import libtbx.load_env
def dispatcher_outer(name):
  return os.path.join(libtbx.env.under_build('bin'), name)
def dispatcher_inner(name):
  return os.path.join(libtbx.env.dist_path('dials'), 'command_line', '%%s.py' %% name.partition('.')[2])
env.Append( BUILDERS={'AutoComplete': Builder(action='-$SOURCE --export-autocomplete-hints > $TARGET')} )
for cmd in [%s]:
  ac = env.AutoComplete(cmd, [dispatcher_outer(cmd), dispatcher_inner(cmd)])
  Requires(ac, Dir(libtbx.env.under_build('lib')))
  Depends(ac, os.path.join(libtbx.env.dist_path('dials'), 'util', 'options.py'))
  Depends(ac, os.path.join(libtbx.env.dist_path('dials'), 'util', 'autocomplete.sh'))
''' % ( ', '.join(["'%s'" % cmd for cmd in command_list]) ))

  # Generate a bash script activating command line completion for each relevant command
  with open(os.path.join(output_directory, 'bash.sh'), 'w') as script:
    script.write("type compopt &>/dev/null && {\n")
    for cmd in command_list:
      script.write(" complete -F _dials_autocomplete %s\n" % cmd)
    script.write("}\n")
    script.write("type compopt &>/dev/null || {\n")
    for cmd in command_list:
      script.write(" complete -o nospace -F _dials_autocomplete %s\n" % cmd)
    script.write("}\n")

  # Find the dials build directory
  build_path = abs(libtbx.env.build_path)

  # Permanently install the autocompletion script into setpaths-scripts.
  print "Installing autocompletion script into:",
  for file in os.listdir(build_path):
    if file.startswith('setpath') and file.endswith('.sh'):
      original_file = open(os.path.join(build_path, file)).read()
      if not 'DIALS_ENABLE_COMMAND_LINE_COMPLETION' in original_file:
        marker = "\nexport PATH\n"
        insert_position = original_file.find(marker) + len(marker)
        if insert_position >= 0:
          print file,
          added_script = \
            '# DIALS_ENABLE_COMMAND_LINE_COMPLETION\n' \
            '[ -n "$BASH_VERSION" ] && {\n' \
            ' source $(libtbx.find_in_repositories dials/util/autocomplete.sh)\n' \
            ' source %s\n' \
            '}\n' % (
              os.path.join('$LIBTBX_BUILD', 'dials', 'autocomplete', 'bash.sh'))
          with open(os.path.join(build_path, file), 'w') as script:
            script.write(original_file[:insert_position] +
                         added_script +
                         original_file[insert_position:])
  print

_install_dials_autocompletion()
<|endoftext|>


<commit_before>from datetime import datetime
from pytz import timezone

from django.core.management.base import BaseCommand

from oysterapp.oyster.models import TaskRule
from oysterapp.oyster.models import Task

class Command(BaseCommand):
    help = "Creates tasks based off task rules"

    def handle(self, *args, **options):
        now_utc = datetime.now(timezone('UTC'))

        print "###################################################"

        print "Now: %s" % now_utc.strftime("%D %H:%M %z")

        all_recurring_tasks = TaskRule.objects.all()
        recurring_tasks = TaskRule.objects.filter(
            next_scheduled_run__lte=now_utc)

        print "Total rules: %s out of %s" % (recurring_tasks.count(),
                                             all_recurring_tasks.count())

        for task_rule in recurring_tasks:
            tasks = Task.objects.filter(completed=False, task_rule=task_rule)
            if not tasks.count():
                task_rule.create_new_task()
                run = task_rule.calculate_next_run()
                print "task created next run: %s" % run.strftime("%D %H:%M %z")
            else:
                run = task_rule.calculate_next_run()
                print "a task already exists, no task created"

        print "###################################################"
<commit_msg>Delete extra tasks<commit_after>from datetime import datetime
from pytz import timezone

from django.core.management.base import BaseCommand

from oysterapp.oyster.models import TaskRule
from oysterapp.oyster.models import Task

class Command(BaseCommand):
    help = "Creates tasks based off task rules"

    def handle(self, *args, **options):
        now_utc = datetime.now(timezone('UTC'))

        all_recurring_tasks = TaskRule.objects.all()
        recurring_tasks = TaskRule.objects.filter(
            next_scheduled_run__lte=now_utc)

        for task_rule in recurring_tasks:
            tasks = Task.objects.filter(completed=False, task_rule=task_rule)
            if not tasks.count():
                task_rule.create_new_task()
                run = task_rule.calculate_next_run()
            else:
                run = task_rule.calculate_next_run()

            if tasks.count() > 1:
                extras = tasks.exclude(pk=tasks.first().pk)
                extras.delete()
<|endoftext|>


<commit_before>import os

import pytest

import test_util.aws
import test_util.helpers

@pytest.fixture(scope='session')
def dcos_launchpad(cluster):
    """Interface for direct interation to dcos_launchpad hardware
    Currently only supports AWS CF with AWS VPC coming soon
    """
    if cluster.provider != 'aws':
        # TODO(mellenburg): update when advanced templates are merged
        pytest.skip('Must be AWS CF to run test')
    aws_access_key_id = os.environ['AWS_ACCESS_KEY_ID']
    aws_secret_access_key = os.environ['AWS_SECRET_ACCESS_KEY']
    aws_region = os.environ['AWS_REGION']
    stack_name = os.environ['AWS_STACK_NAME']
    bw = test_util.aws.BotoWrapper(aws_region, aws_access_key_id, aws_secret_access_key)
    return test_util.aws.DcosCfSimple(stack_name, bw)

@pytest.mark.last
@pytest.mark.resiliency
def test_agent_failure(dcos_launchpad, cluster, vip_apps):
    # make sure the app works before starting
    test_util.helpers.wait_for_pong(vip_apps[0][1], 120)
    test_util.helpers.wait_for_pong(vip_apps[1][1], 10)

    agents = [i['InstanceId'] for i in dcos_launchpad.
              get_group_instances(['PublicSlaveServerGroup', 'SlaveServerGroup'], state_list=['running'])]

    # Agents are in autoscaling groups, so they will automatically be replaced
    dcos_launchpad.boto_wrapper.client('ec2').terminate_instances(InstanceIds=agents)
    dcos_launchpad.boto_wrapper.client('ec2').get_waiter('instance_terminated').wait(InstanceIds=agents)

    def get_running_agents():
        return dcos_launchpad.get_group_instances(
            ['PublicSlaveServerGroup', 'SlaveServerGroup'], state_list=['running'])

    # Wait for replacements
    test_util.helpers.wait_for_len(get_running_agents, len(cluster.all_slaves), 600)

    # Reset the cluster to have the replacement agents
    cluster.slaves = sorted([agent.private_ip for agent in
                             dcos_launchpad.get_private_agent_ips(state_list=['running'])])
    cluster.public_slaves = sorted([agent.private_ip for agent in
                                    dcos_launchpad.get_public_agent_ips(state_list=['running'])])
    cluster.all_slaves = sorted(cluster.slaves + cluster.public_slaves)

    # verify that everything else is still working
    cluster.wait_for_dcos()
    # finally verify that the app is again running somewhere with its VIPs
    # Give marathon five minutes to deploy both the apps
    test_util.helpers.wait_for_pong(vip_apps[0][1], 300)
    test_util.helpers.wait_for_pong(vip_apps[1][1], 10)
<commit_msg>Teach AWS resiliency test to tell mesos agents are gone so Marathon gets TASK_LOST<commit_after>import os

import pytest

import test_util.aws
import test_util.helpers

@pytest.fixture(scope='session')
def dcos_launchpad(cluster):
    """Interface for direct interation to dcos_launchpad hardware
    Currently only supports AWS CF with AWS VPC coming soon
    """
    if cluster.provider != 'aws':
        # TODO(mellenburg): update when advanced templates are merged
        pytest.skip('Must be AWS CF to run test')
    aws_access_key_id = os.environ['AWS_ACCESS_KEY_ID']
    aws_secret_access_key = os.environ['AWS_SECRET_ACCESS_KEY']
    aws_region = os.environ['AWS_REGION']
    stack_name = os.environ['AWS_STACK_NAME']
    bw = test_util.aws.BotoWrapper(aws_region, aws_access_key_id, aws_secret_access_key)
    return test_util.aws.DcosCfSimple(stack_name, bw)

@pytest.mark.last
@pytest.mark.resiliency
def test_agent_failure(dcos_launchpad, cluster, vip_apps):
    # make sure the app works before starting
    test_util.helpers.wait_for_pong(vip_apps[0][1], 120)
    test_util.helpers.wait_for_pong(vip_apps[1][1], 10)

    agents = [i['InstanceId'] for i in dcos_launchpad.
              get_group_instances(['PublicSlaveServerGroup', 'SlaveServerGroup'], state_list=['running'])]

    # Agents are in autoscaling groups, so they will automatically be replaced
    dcos_launchpad.boto_wrapper.client('ec2').terminate_instances(InstanceIds=agents)
    dcos_launchpad.boto_wrapper.client('ec2').get_waiter('instance_terminated').wait(InstanceIds=agents)

    def get_running_agents():
        return dcos_launchpad.get_group_instances(
            ['PublicSlaveServerGroup', 'SlaveServerGroup'], state_list=['running'])

    # Tell mesos the machines are "down" and not coming up so things get rescheduled.
    down_hosts = [{'hostname': slave, 'ip': slave} for slave in cluster.all_slaves]
    cluster.post(
        '/mesos/maintenance/schedule',
        json={'windows': [{
            'machine_ids': down_hosts,
            'unavailability': {'start': {'nanoseconds': 0}}
        }]}).raise_for_status()
    cluster.post('/mesos/machine/down', json=down_hosts).raise_for_status()

    # Wait for replacements
    test_util.helpers.wait_for_len(get_running_agents, len(cluster.all_slaves), 600)

    # Reset the cluster to have the replacement agents
    cluster.slaves = sorted([agent.private_ip for agent in
                             dcos_launchpad.get_private_agent_ips(state_list=['running'])])
    cluster.public_slaves = sorted([agent.private_ip for agent in
                                    dcos_launchpad.get_public_agent_ips(state_list=['running'])])
    cluster.all_slaves = sorted(cluster.slaves + cluster.public_slaves)

    # verify that everything else is still working
    cluster.wait_for_dcos()
    # finally verify that the app is again running somewhere with its VIPs
    # Give marathon five minutes to deploy both the apps
    test_util.helpers.wait_for_pong(vip_apps[0][1], 300)
    test_util.helpers.wait_for_pong(vip_apps[1][1], 10)
<|endoftext|>