<commit_before>from pprint import pprint

from django.db import models

class RegraColecaoManager(models.Manager):
    def get_queryset(self):
        return super(
            RegraColecaoManager,
            self).get_queryset().filter(referencia='')

class RegraColecao(models.Model):
    colecao = models.IntegerField(
        primary_key=True,
        verbose_name='Coleção')
    lead = models.IntegerField(
        null=True, blank=True, default=0)
    lm_tam = models.IntegerField(
        null=True, blank=True, default=0,
        verbose_name='Lote mínimo por tamanho')
    lm_cor = models.IntegerField(
        null=True, blank=True, default=0,
        verbose_name='Lote mínimo por cor')
    referencia = models.CharField(
        max_length=5, default='',
        verbose_name='Referência')

    objects_referencia = models.Manager()
    objects = RegraColecaoManager()

    def __str__(self):
        return str(self.colecao)

    class Meta:
        db_table = "fo2_lot_regra_colecao"
        verbose_name = "Regra por coleção"
        verbose_name_plural = "Regras por coleção"

class RegraLMTamanho(models.Model):
    tamanho = models.CharField(
        primary_key=True,
        max_length=3,
        verbose_name='Tamanho')

    ordem_tamanho = models.IntegerField(
        null=True, blank=True, default=0,
        verbose_name='Ordem do tamanho')

    min_para_lm = models.IntegerField(
        null=True, blank=True, default=0,
        verbose_name='% mínimo para aplicação do lote mínimo por tamanho')

    lm_cor_sozinha = models.CharField(
        max_length=1, default='s',
        verbose_name='Aplica lote mínimo por cor quando único tamanho')

    def __str__(self):
        return self.tamanho

    class Meta:
        db_table = "fo2_lot_regra_lm_tamanho"
        verbose_name = "Regra de lote mínimo por tamanho"
<commit_msg>model RegraColecao: Só pode definir uma regra por referência se já houver uma sem referência<commit_after>from pprint import pprint

from django.core.exceptions import ValidationError
from django.db import models

class RegraColecaoManager(models.Manager):
    def get_queryset(self):
        return super(
            RegraColecaoManager,
            self).get_queryset().filter(referencia='')

class RegraColecao(models.Model):
    colecao = models.IntegerField(
        primary_key=True,
        verbose_name='Coleção')
    lead = models.IntegerField(
        null=True, blank=True, default=0)
    lm_tam = models.IntegerField(
        null=True, blank=True, default=0,
        verbose_name='Lote mínimo por tamanho')
    lm_cor = models.IntegerField(
        null=True, blank=True, default=0,
        verbose_name='Lote mínimo por cor')
    referencia = models.CharField(
        max_length=5, default='',
        verbose_name='Referência')

    objects_referencia = models.Manager()
    objects = RegraColecaoManager()

    def __str__(self):
        return str(self.colecao)

    class Meta:
        db_table = "fo2_lot_regra_colecao"
        verbose_name = "Regra por coleção"
        verbose_name_plural = "Regras por coleção"

    def save(self, *args, **kwargs):
        if self.referencia:
            try:
                RegraColecao.objects.get(
                    colecao=self.colecao,
                    referencia='',
                )
            except RegraColecao.DoesNotExist:
                raise ValidationError(f"Só pode definir uma regra por referência se já houver uma sem referência.")
        super(RegraColecao, self).save(*args, **kwargs)

class RegraLMTamanho(models.Model):
    tamanho = models.CharField(
        primary_key=True,
        max_length=3,
        verbose_name='Tamanho')

    ordem_tamanho = models.IntegerField(
        null=True, blank=True, default=0,
        verbose_name='Ordem do tamanho')

    min_para_lm = models.IntegerField(
        null=True, blank=True, default=0,
        verbose_name='% mínimo para aplicação do lote mínimo por tamanho')

    lm_cor_sozinha = models.CharField(
        max_length=1, default='s',
        verbose_name='Aplica lote mínimo por cor quando único tamanho')

    def __str__(self):
        return self.tamanho

    class Meta:
        db_table = "fo2_lot_regra_lm_tamanho"
        verbose_name = "Regra de lote mínimo por tamanho"
<|endoftext|>


<commit_before>#
#  This file is part of Bakefile (http://www.bakefile.org)
#
#  Copyright (C) 2008-2009 Vaclav Slavik
#
#  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 OTHER
#  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.
#

"""
The :class:`Expr` class that represents a Bakefile expression (be it a
condition or variable value) is defined in this module, together with
useful functions for evaluating and simplifying expressions.
"""

import os.path
from error import NonConstError, Error

class Expr(object):
    """
    Value expression.

    Represents a value (typically assigned to a variable, but also expressions
    used somewhere else, e.g. as conditions) as tree of expression objects. In
    Bakefile, the expressions are kept in tree representation until the last
    possible moment, and are manipulated in this form.

    Note that expression objects are immutable: if you need to modify an
    expression, replace it with a new object.
    """

    def as_py(self, ctxt=None):
        """
        Returns the expression as Python value (e.g. a list of strings) if it
        evaluates to a constant literal. Throws an exception if the expression
        cannot be evaluated at make-time (such expressions cannot be used in
        some situations, e.g. to specify output files). Paths are returned as
        native paths.

        Use :class:`bkl.expr.Formatter` if you need to format expressions
        into strings.

        :param ctxt: The :class:`bkl.expr.EvalContext` to evaluate the
            expression in.
        """
        raise NotImplementedError

class LiteralExpr(Expr):
    """
    Constant expression -- holds a literal.

    .. attribute:: value

       Value of the literal.
    """

    def __init__(self, value):
        self.value = value

    def as_py(self, ctxt=None):
        return self.value

    def __str__(self):
        return str(self.value)

class ListExpr(Expr):
    """
    List expression -- list of several values of the same type.
    """

    def __init__(self, items):
        self.items = items

    def as_py(self, ctxt=None):
        return [ i.as_py(ctxt) for i in self.items ]

    def __str__(self):
        return "[%s]" % ", ".join(str(x) for x in self.items)

class NullExpr(Expr):
    """
    Empty/unset value.
    """

    def as_py(self, ctxt=None):
        return None

    def __str__(self):
        return "null"

class ReferenceExpr(Expr):
    """
    Reference to a variable.

    .. attribute:: var

       Name of referenced variable.

    .. attribute:: context

       Context of the reference, i.e. the scope in which it was used. This is
       the appropriate :class:`bkl.model.ModelPart` instance (e.g. a target
       or a module).
    """

    def __init__(self, var, context):
        self.var = var
        self.context = context

    def as_py(self, ctxt=None):
        raise NonConstError(self)

    def __str__(self):
        return "$(%s)" % self.var

# anchors -- special syntax first components of a path
ANCHOR_SRCDIR     = "@srcdir"
ANCHOR_TOP_SRCDIR = "@top_srcdir"

# all possible anchors
ANCHORS = [ANCHOR_SRCDIR, ANCHOR_TOP_SRCDIR]

class PathExpr(Expr):
    """
    Expression that holds a file or directory name, or part of it.

    .. attribute:: components

       List of path's components (as expressions). For example, components of
       path ``foo/bar/file.cpp`` are ``["foo", "bar", "file.cpp"]``.

    .. attribute:: anchor

       The point to which the path is relative to. This can be one of the
       following:

       * ``expr.ANCHOR_SRCDIR`` -- Path is relative to the source
         directory (where the ``.bkl`` file is, unless overriden in it).
       * ``expr.ANCHOR_TOP_SRCDIR`` -- Path is relative to the top
         source directory (where the toplevel ``.bkl`` file is, unless
         overriden in it).
    """

    def __init__(self, components, anchor=ANCHOR_SRCDIR):
        self.components = components
        self.anchor = anchor

    def as_py(self, ctxt=None):
        # FIXME: this code doesn't account for the anchor
        comp = (e.as_py() for e in self.components)
        return os.path.sep.join(comp)

    def __str__(self):
        return "%s/%s" % (self.anchor, "/".join(str(e) for e in self.components))

class EvalContext(object):
    """
    Evaluation context information.

    This structure is passed to some functions that work with :class:`Expr`
    and that need to know additional information in order to process the
    expression. For example, the :class:`bkl.expr.Formatter` class needs extra
    information to be able to format file paths using the right separator.

    All of the values may be ``None`` if they are not known yet.

    .. attribute:: dirsep

       Separator to separate path components ("/" on Unix and "\\" on Windows).

    .. attribute:: outdir

       Current output directory, i.e. the directory into which Bakefile is
       writing files at the moment the context is used, relative to the project
       root, in Unix syntax. This value may (and typically does) change during
       processing -- for example, it may be ``build/msvc2005`` when generating
       main library project for VC++ 2005, ``build/msvc2008`` when creating the
       same for VC++ 2008 and ``examples/build/msvc2008`` for a submodule).
    """

    def __init__(self):
        self.dirsep = None
        self.outdir = None

def split(e, sep):
    """
    Splits expression *e* into a list of expressions, using *sep* as the
    delimiter character. Works with conditional expressions and variable
    references too.
    """
    assert len(sep) == 1
    if isinstance(e, LiteralExpr):
        vals = e.value.split(sep)
        return [LiteralExpr(v) for v in vals]
    else:
        # FIXME: set pos
        raise Error("don't know how to split expression \"%s\"" % e)
<commit_msg>Implemented expr.split() for references.<commit_after>#
#  This file is part of Bakefile (http://www.bakefile.org)
#
#  Copyright (C) 2008-2009 Vaclav Slavik
#
#  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 OTHER
#  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.
#

"""
The :class:`Expr` class that represents a Bakefile expression (be it a
condition or variable value) is defined in this module, together with
useful functions for evaluating and simplifying expressions.
"""

import os.path
from error import NonConstError, Error

class Expr(object):
    """
    Value expression.

    Represents a value (typically assigned to a variable, but also expressions
    used somewhere else, e.g. as conditions) as tree of expression objects. In
    Bakefile, the expressions are kept in tree representation until the last
    possible moment, and are manipulated in this form.

    Note that expression objects are immutable: if you need to modify an
    expression, replace it with a new object.
    """

    def as_py(self, ctxt=None):
        """
        Returns the expression as Python value (e.g. a list of strings) if it
        evaluates to a constant literal. Throws an exception if the expression
        cannot be evaluated at make-time (such expressions cannot be used in
        some situations, e.g. to specify output files). Paths are returned as
        native paths.

        Use :class:`bkl.expr.Formatter` if you need to format expressions
        into strings.

        :param ctxt: The :class:`bkl.expr.EvalContext` to evaluate the
            expression in.
        """
        raise NotImplementedError

class LiteralExpr(Expr):
    """
    Constant expression -- holds a literal.

    .. attribute:: value

       Value of the literal.
    """

    def __init__(self, value):
        self.value = value

    def as_py(self, ctxt=None):
        return self.value

    def __str__(self):
        return str(self.value)

class ListExpr(Expr):
    """
    List expression -- list of several values of the same type.
    """

    def __init__(self, items):
        self.items = items

    def as_py(self, ctxt=None):
        return [ i.as_py(ctxt) for i in self.items ]

    def __str__(self):
        return "[%s]" % ", ".join(str(x) for x in self.items)

class NullExpr(Expr):
    """
    Empty/unset value.
    """

    def as_py(self, ctxt=None):
        return None

    def __str__(self):
        return "null"

class ReferenceExpr(Expr):
    """
    Reference to a variable.

    .. attribute:: var

       Name of referenced variable.

    .. attribute:: context

       Context of the reference, i.e. the scope in which it was used. This is
       the appropriate :class:`bkl.model.ModelPart` instance (e.g. a target
       or a module).
    """

    def __init__(self, var, context):
        self.var = var
        self.context = context

    def as_py(self, ctxt=None):
        raise NonConstError(self)

    def get_value(self):
        """
        Returns value of the referenced variable. Throws an exception if
        the reference couldn't be resolved.
        """
        return self.context.get_variable_value(self.var)

    def __str__(self):
        return "$(%s)" % self.var

# anchors -- special syntax first components of a path
ANCHOR_SRCDIR     = "@srcdir"
ANCHOR_TOP_SRCDIR = "@top_srcdir"

# all possible anchors
ANCHORS = [ANCHOR_SRCDIR, ANCHOR_TOP_SRCDIR]

class PathExpr(Expr):
    """
    Expression that holds a file or directory name, or part of it.

    .. attribute:: components

       List of path's components (as expressions). For example, components of
       path ``foo/bar/file.cpp`` are ``["foo", "bar", "file.cpp"]``.

    .. attribute:: anchor

       The point to which the path is relative to. This can be one of the
       following:

       * ``expr.ANCHOR_SRCDIR`` -- Path is relative to the source
         directory (where the ``.bkl`` file is, unless overriden in it).
       * ``expr.ANCHOR_TOP_SRCDIR`` -- Path is relative to the top
         source directory (where the toplevel ``.bkl`` file is, unless
         overriden in it).
    """

    def __init__(self, components, anchor=ANCHOR_SRCDIR):
        self.components = components
        self.anchor = anchor

    def as_py(self, ctxt=None):
        # FIXME: this code doesn't account for the anchor
        comp = (e.as_py() for e in self.components)
        return os.path.sep.join(comp)

    def __str__(self):
        return "%s/%s" % (self.anchor, "/".join(str(e) for e in self.components))

class EvalContext(object):
    """
    Evaluation context information.

    This structure is passed to some functions that work with :class:`Expr`
    and that need to know additional information in order to process the
    expression. For example, the :class:`bkl.expr.Formatter` class needs extra
    information to be able to format file paths using the right separator.

    All of the values may be ``None`` if they are not known yet.

    .. attribute:: dirsep

       Separator to separate path components ("/" on Unix and "\\" on Windows).

    .. attribute:: outdir

       Current output directory, i.e. the directory into which Bakefile is
       writing files at the moment the context is used, relative to the project
       root, in Unix syntax. This value may (and typically does) change during
       processing -- for example, it may be ``build/msvc2005`` when generating
       main library project for VC++ 2005, ``build/msvc2008`` when creating the
       same for VC++ 2008 and ``examples/build/msvc2008`` for a submodule).
    """

    def __init__(self):
        self.dirsep = None
        self.outdir = None

def split(e, sep):
    """
    Splits expression *e* into a list of expressions, using *sep* as the
    delimiter character. Works with conditional expressions and variable
    references too.
    """
    assert len(sep) == 1
    if isinstance(e, LiteralExpr):
        vals = e.value.split(sep)
        return [LiteralExpr(v) for v in vals]
    elif isinstance(e, ReferenceExpr):
        return split(e.get_value(), sep)
    else:
        # FIXME: set pos
        raise Error("don't know how to split expression \"%s\"" % e)
<|endoftext|>


<commit_before>from django.conf.urls import patterns, include, url
from django.views.generic.simple import TemplateView
from django.conf import settings

urlpatterns = patterns('',
    url(r'^$', TemplateView.as_view(template='base.html'), name='home'),
    url(r'^_admin/', TemplateView.as_view(template='admin.html'), name='admin'),
    url(r'^api/', include('hydra.urls')),
)

if settings.DEBUG:
    urlpatterns += patterns('',
        url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {
            'document_root': settings.MEDIA_ROOT}),
    )
<commit_msg>run code before commiting...<commit_after>from django.conf.urls import patterns, include, url
from django.views.generic import TemplateView
from django.conf import settings

urlpatterns = patterns('',
    url(r'^$', TemplateView.as_view(template='base.html'), name='home'),
    url(r'^_admin/', TemplateView.as_view(template='admin.html'), name='admin'),
    url(r'^api/', include('hydra.urls')),
)

if settings.DEBUG:
    urlpatterns += patterns('',
        url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {
            'document_root': settings.MEDIA_ROOT}),
    )
<|endoftext|>


<commit_before># Django imports
from django import forms
from django.utils.translation import ugettext as _
# pluggable apps
from chosen import forms as chosenforms
from entities.models import Entity

class EntityChoiceForm(forms.Form):
    """ this form is used only to display the field, input
        is handled by the client
    """
    entity = chosenforms.ChosenModelChoiceField(
            queryset=Entity.objects.filter(division__index=3),
            label= "",
            empty_label=_("Choose a Place"),
            required=False)
<commit_msg>hide entities with no candidatelists, fix #262<commit_after># Django imports
from django import forms
from django.utils.translation import ugettext as _
# pluggable apps
from chosen import forms as chosenforms
from entities.models import Entity

class EntityChoiceForm(forms.Form):
    """ this form is used only to display the field, input
        is handled by the client
    """
    entity = chosenforms.ChosenModelChoiceField(
            queryset=Entity.objects.exclude(candidatelist__isnull=True).filter(division__index=3),
            label= "",
            empty_label=_("Choose a Place"),
            required=False)
<|endoftext|>


<commit_before>""" The Continuation Monad

* https://wiki.haskell.org/MonadCont_under_the_hood
* http://blog.sigfpe.com/2008/12/mother-of-all-monads.html
* http://www.haskellforall.com/2012/12/the-continuation-monad.html

"""

from typing import Any, Callable

from .util import identity, compose
from .abc import Monad, Functor

class Cont(Monad, Functor):
    """The Continuation Monad.

    The Continuation monad represents computations in continuation-
    passing style (CPS).
    """

    def __init__(self, fn: Callable[[Callable], Any]):
        self._get_value = lambda: fn

    @classmethod
    def unit(cls, a: Any) -> 'Cont':
        return cls(lambda k: k(a))

    def map(self, fn: Callable[[Any], Any]) -> 'Cont':
        """Map a function over a continuation.

        Haskell: fmap f m = Cont $ \c -> runCont m (c . f)
        """
        return Cont(lambda c: self.run(compose(c, fn)))

    def bind(self, fn: Callable[[Any], 'Cont']) -> 'Cont':
        r"""Chain continuation passing functions.

        Haskell: m >>= k = Cont $ \c -> runCont m $ \a -> runCont (k a) c
        """
        s = lambda c: self.run(c)
        t = lambda c: lambda a: fn(a).run(c)
        return Cont(lambda c: s(t(c)))

    @staticmethod
    def call_cc(fn: Callable) -> 'Cont':
        r"""call-with-current-continuation.

        Haskell: callCC f = Cont $ \c -> runCont (f (\a -> Cont $ \_ -> c a )) c
        """
        return Cont(lambda c: fn(lambda a: Cont(lambda _: c(a))).run(c))

    def run(self, *args) -> Any:
        return self._get_value()(*args) if args else self._get_value()

    def __call__(self, *args, **kwargs) -> Any:
        return self.run(*args, **kwargs)

    def __eq__(self, other) -> bool:
        return self(identity) == other(identity)
<commit_msg>Refactored bind<commit_after>""" The Continuation Monad

* https://wiki.haskell.org/MonadCont_under_the_hood
* http://blog.sigfpe.com/2008/12/mother-of-all-monads.html
* http://www.haskellforall.com/2012/12/the-continuation-monad.html

"""

from typing import Any, Callable

from .util import identity, compose
from .abc import Monad, Functor

class Cont(Monad, Functor):
    """The Continuation Monad.

    The Continuation monad represents computations in continuation-
    passing style (CPS).
    """

    def __init__(self, fn: Callable[[Callable], Any]):
        self._get_value = lambda: fn

    @classmethod
    def unit(cls, a: Any) -> 'Cont':
        return cls(lambda k: k(a))

    def map(self, fn: Callable[[Any], Any]) -> 'Cont':
        """Map a function over a continuation.

        Haskell: fmap f m = Cont $ \c -> runCont m (c . f)
        """
        return Cont(lambda c: self.run(compose(c, fn)))

    def bind(self, fn: Callable[[Any], 'Cont']) -> 'Cont':
        r"""Chain continuation passing functions.

        Haskell: m >>= k = Cont $ \c -> runCont m $ \a -> runCont (k a) c
        """
        return Cont(lambda c: self.run(lambda a: (fn(a).run(c))))

    @staticmethod
    def call_cc(fn: Callable) -> 'Cont':
        r"""call-with-current-continuation.

        Haskell: callCC f = Cont $ \c -> runCont (f (\a -> Cont $ \_ -> c a )) c
        """
        return Cont(lambda c: fn(lambda a: Cont(lambda _: c(a))).run(c))

    def run(self, *args) -> Any:
        return self._get_value()(*args) if args else self._get_value()

    def __call__(self, *args, **kwargs) -> Any:
        return self.run(*args, **kwargs)

    def __eq__(self, other) -> bool:
        return self(identity) == other(identity)

<|endoftext|>


<commit_before># Copyright 2022 The KerasCV Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import six
import tensorflow as tf
from keras.callbacks import Callback

from keras_cv import bounding_box
from keras_cv.metrics.coco import compute_pycoco_metrics

class PyCOCOCallback(Callback):
    def __init__(self, validation_data, bounding_box_format, **kwargs):
        self.model = None
        self.val_data = validation_data
        self.bounding_box_format = bounding_box_format
        super().__init__(**kwargs)

    def on_epoch_end(self, epoch, logs=None):
        logs = logs or {}

        gt = {}
        preds = {}

        for i, batch in enumerate(self.val_data):
            gt_i, preds_i = self._eval_batch(batch, i)

            for k, v in six.iteritems(preds_i):
                if k not in preds:
                    preds[k] = [v]
                else:
                    preds[k].append(v)

            for k, v in six.iteritems(gt_i):
                if k not in gt:
                    gt[k] = [v]
                else:
                    gt[k].append(v)

        metrics = compute_pycoco_metrics(gt, preds)
        # Mark these as validation metrics by prepending a val_ prefix
        metrics = {"val_" + name: val for name, val in metrics.items()}

        logs.update(metrics)

    def _eval_batch(self, batch, index):
        images, y = batch
        gt_boxes = y["gt_boxes"]
        gt_classes = y["gt_classes"]
        batch_size = images.shape[0]
        height = images.shape[1]
        width = images.shape[2]

        gt_boxes = bounding_box.convert_format(
            gt_boxes, source=self.bounding_box_format, target="yxyx"
        )

        source_ids = tf.strings.join(
            [
                tf.strings.as_string(tf.tile(tf.constant([index]), [batch_size])),
                tf.strings.as_string(
                    tf.linspace(1, batch_size, batch_size), precision=0
                ),
            ],
            separator="/",
        )

        ground_truth = {}
        ground_truth["source_id"] = source_ids
        ground_truth["height"] = tf.tile(tf.constant([height]), [batch_size])
        ground_truth["width"] = tf.tile(tf.constant([width]), [batch_size])

        num_dets = gt_classes.get_shape().as_list()[1]
        ground_truth["num_detections"] = tf.tile(tf.constant([num_dets]), [batch_size])
        ground_truth["boxes"] = gt_boxes
        ground_truth["classes"] = gt_classes

        y_pred = self.model.predict(images)
        y_pred = bounding_box.convert_format(
            y_pred, source=self.bounding_box_format, target="yxyx"
        )

        predictions = {}
        predictions["num_detections"] = y_pred.row_lengths()
        y_pred = y_pred.to_tensor(-1)

        predictions["source_id"] = source_ids
        predictions["detection_boxes"] = y_pred[:, :, :4]
        predictions["detection_classes"] = y_pred[:, :, 4]
        predictions["detection_scores"] = y_pred[:, :, 5]

        return ground_truth, predictions
<commit_msg>[Object Detection] Speed up the PyCOCO callback by only calling model.predict once (#1026)<commit_after># Copyright 2022 The KerasCV Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import tensorflow as tf
from keras.callbacks import Callback

from keras_cv import bounding_box
from keras_cv.metrics.coco import compute_pycoco_metrics

class PyCOCOCallback(Callback):
    def __init__(self, validation_data, bounding_box_format, cache=True, **kwargs):
        """Creates a callback to evaluate PyCOCO metrics on a validation dataset.

        Args:
            validation_data: a tf.data.Dataset containing validation data. Entries
                should have the form ```(images, {"gt_boxes": boxes,
                "gt_classes": classes})```.
            bounding_box_format: the KerasCV bounding box format used in the
                validation dataset (e.g. "xywh")
            cache: whether the callback should cache the dataset between iterations.
                Note that if the validation dataset has shuffling of any kind
                (e.g from `shuffle_files=True` in a call to TFDS.load or a call
                to tf.data.Dataset.shuffle() with `reshuffle_each_iteration=True`),
                you **must** cache the dataset to preserve iteration order. This
                will store your entire dataset in main memory, so for large datasets
                consider avoiding shuffle operations and passing `cache=False`.
        """
        self.model = None
        self.val_data = validation_data
        if cache:
            # We cache the dataset to preserve a consistent iteration order.
            self.val_data = self.val_data.cache()
        self.bounding_box_format = bounding_box_format
        super().__init__(**kwargs)

    def on_epoch_end(self, epoch, logs=None):
        logs = logs or {}

        def images_only(images, boxes):
            return images

        def boxes_only(images, boxes):
            return boxes

        images_only_ds = self.val_data.map(images_only)
        y_pred = self.model.predict(images_only_ds)

        gt = [boxes for boxes in self.val_data.map(boxes_only)]
        gt_boxes = tf.concat(
            [tf.RaggedTensor.from_tensor(boxes["gt_boxes"]) for boxes in gt], axis=0
        )
        gt_classes = tf.concat(
            [tf.RaggedTensor.from_tensor(boxes["gt_classes"]) for boxes in gt], axis=0
        )

        first_image_batch = next(iter(images_only_ds))
        height = first_image_batch.shape[1]
        width = first_image_batch.shape[2]
        total_images = gt_boxes.shape[0]

        gt_boxes = bounding_box.convert_format(
            gt_boxes, source=self.bounding_box_format, target="yxyx"
        )

        source_ids = tf.strings.as_string(
            tf.linspace(1, total_images, total_images), precision=0
        )

        ground_truth = {}
        ground_truth["source_id"] = [source_ids]
        ground_truth["height"] = [tf.tile(tf.constant([height]), [total_images])]
        ground_truth["width"] = [tf.tile(tf.constant([width]), [total_images])]

        ground_truth["num_detections"] = [gt_boxes.row_lengths(axis=1)]
        ground_truth["boxes"] = [gt_boxes.to_tensor(-1)]
        ground_truth["classes"] = [gt_classes.to_tensor(-1)]

        y_pred = bounding_box.convert_format(
            y_pred, source=self.bounding_box_format, target="yxyx"
        )

        predictions = {}
        predictions["num_detections"] = [y_pred.row_lengths()]
        y_pred = y_pred.to_tensor(-1)

        predictions["source_id"] = [source_ids]
        predictions["detection_boxes"] = [y_pred[:, :, :4]]
        predictions["detection_classes"] = [y_pred[:, :, 4]]
        predictions["detection_scores"] = [y_pred[:, :, 5]]

        metrics = compute_pycoco_metrics(ground_truth, predictions)
        # Mark these as validation metrics by prepending a val_ prefix
        metrics = {"val_" + name: val for name, val in metrics.items()}

        logs.update(metrics)
<|endoftext|>


<commit_before>""" gunicorn.py

    Utilities for running the knowledge app via gunicorn.

    Adapted from example in http://docs.gunicorn.org/en/stable/custom.html.
"""

from __future__ import absolute_import

from gunicorn.app.base import BaseApplication

from .common import KnowledgeDeployer

class GunicornDeployer(BaseApplication, KnowledgeDeployer):

    _registry_keys = ['gunicorn']

    def __init__(self, *args, **kwargs):
        KnowledgeDeployer.__init__(self, *args, **kwargs)
        BaseApplication.__init__(self)

    def load_config(self):
        options = {
            'bind': u'{}:{}'.format(self.host, self.port),
            'workers': self.workers,
            'timeout': self.timeout
        }
        for key, value in options.items():
            self.cfg.set(key, value)

    def load(self):
        return self.builder_func()

    def run(self):
        if not self.app.check_thread_support():
            raise RuntimeError("Database configuration is not suitable for deployment (not thread-safe).")
        return BaseApplication.run(self)
<commit_msg>[gunicorn] Adding environment configuration (#437)<commit_after>""" gunicorn.py

    Utilities for running the knowledge app via gunicorn.

    Adapted from example in http://docs.gunicorn.org/en/stable/custom.html.
"""

from __future__ import absolute_import

from gunicorn.app.base import BaseApplication

from .common import KnowledgeDeployer

class GunicornDeployer(BaseApplication, KnowledgeDeployer):

    _registry_keys = ['gunicorn']

    def __init__(self, *args, **kwargs):
        KnowledgeDeployer.__init__(self, *args, **kwargs)
        BaseApplication.__init__(self)

    def load_config(self):
        env_args = self.cfg.parser().parse_args(self.cfg.get_cmd_args_from_env())

        # Load up environment configuration.
        for key, value in vars(env_args).items():
            if key != 'args' and value is not None:
                self.cfg.set(key, value)

        # Update the configuration with the options specified via KnowledgeDeployer
        deployer_args = {
            'bind': u'{}:{}'.format(self.host, self.port),
            'workers': self.workers,
            'timeout': self.timeout,
        }

        for key, value in deployer_args.items():
            self.cfg.set(key, value)

    def load(self):
        return self.builder_func()

    def run(self):
        if not self.app.check_thread_support():
            raise RuntimeError("Database configuration is not suitable for deployment (not thread-safe).")
        return BaseApplication.run(self)
<|endoftext|>


<commit_before>import cv2, numpy as np
import time
import math as mth
from PIL import Image, ImageDraw, ImageFont
import scipy.io
from keras.models import Sequential
from keras import initializations
from keras.initializations import normal, identity
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.optimizers import RMSprop, SGD, Adam
import random
from scipy import ndimage
from keras.preprocessing import image
from sklearn.preprocessing import OneHotEncoder

from features import get_image_descriptor_for_image, obtain_compiled_vgg_16, vgg_16, \
    get_conv_image_descriptor_for_image, calculate_all_initial_feature_maps
from parse_xml_annotations import *
from image_helper import *
from metrics import *
from visualization import *
from reinforcement import *

if __name__ == "__main__":

    ######## PATHS definition ########

    # path of pascal voc test
    path_voc_test = "./VOC2007_test/"
    # model name of the weights
    model_name = "model_image_zooms"
    # path of folder where the weights are
    weights_path = "../models_image_zooms/"
    # path of where to store visualizations of search sequences
    path_testing_folder = '../testing/'
    # path of VGG16 weights
    path_vgg = "../vgg16_weights.h5"

     ######## MODELS ########

    model_vgg = obtain_compiled_vgg_16(path_vgg)
    model = get_q_network(weights_path + model_name)

    ######## LOAD IMAGE NAMES ########

    image_names = np.array([load_images_names_in_data_set('aeroplane_test', path_voc_test)])
    labels = load_images_labels_in_data_set('aeroplane_test', path_voc_test)

    ######## LOAD IMAGES ########

    images = get_all_images(image_names, path_voc_test)

    ######## PARAMETERS ########

    # Class category of PASCAL that the RL agent will be searching
    class_object = 1
    # 1 if you want to obtain visualizations of the search for objects
    bool_draw = 1
    # Scale of subregion for the hierarchical regions (in quarters, to deal with 1/4, 2/4, 3/4)
    scale_subregion = float(3)/4
    scale_mask = float(1)/(scale_subregion*4)
    # Number of steps that the agent does at each image
    number_of_steps = 10
    # Only search first object
    only_first_object = 1

    for j in range(np.size(image_names)):
        if labels[j] == "1":
            image = np.array(images[j])
            # init drawing for visualization
            background = Image.new('RGBA', (10000, 2000), (255, 255, 255, 255))
            draw = ImageDraw.Draw(background)
            image_name = image_names[0][j]
            annotation = get_bb_of_gt_from_pascal_xml_annotation(image_name, path_voc_test)
            gt_masks = generate_bounding_box_from_annotation(annotation, image.shape)
            array_classes_gt_objects = get_ids_objects_from_annotation(annotation)
            size_mask = (image.shape[0], image.shape[1])
            original_shape = size_mask
            image_for_search = image
            region_mask = np.ones([image.shape[0], image.shape[1]])
            # offset of the region observed at each time step
            offset = (0, 0)
            # absolute status is a boolean we indicate if the agent will continue
            # searching object or not. If the first object already covers the whole
            # image, we can put it at 0 so we do not further search there
            absolute_status = 1
            action = 0
            step = 0
            qval = 0
            region_image = image_for_search
            region_mask = np.ones([image.shape[0], image.shape[1]])
            # we run the agent if the maximum number of steps has not been reached and
            # if the boolean
            while (step < number_of_steps) and (absolute_status == 1):
                iou = 0
                # we init history vector as we are going to find another object
                history_vector = np.zeros([24])
                state = get_state(region_image, history_vector, model_vgg)
                status = 1
                draw_sequences_test(step, action, qval, draw, region_image, background, path_testing_folder,
                                    region_mask, image_name, bool_draw)
                size_mask = (image.shape[0], image.shape[1])
                original_shape = size_mask
                region_mask = np.ones([image.shape[0], image.shape[1]])
                while (status == 1) & (step < number_of_steps):
                    step += 1
                    qval = model.predict(state.T, batch_size=1)
                    action = (np.argmax(qval))+1
                    # movement action, make the proper zoom on the image
                    if action != 6:
                        region_mask = np.zeros(original_shape)
                        size_mask = (size_mask[0] * scale_reduction, size_mask[1] * scale_reduction)
                        if action == 1:
                            offset_aux = (0, 0)
                        elif action == 2:
                            offset_aux = (0, size_mask[1] * scale_mask)
                            offset = (offset[0], offset[1] + size_mask[1] * scale_mask)
                        elif action == 3:
                            offset_aux = (size_mask[0] * scale_mask, 0)
                            offset = (offset[0] + size_mask[0] * scale_mask, offset[1])
                        elif action == 4:
                            offset_aux = (size_mask[0] * scale_mask,
                                          size_mask[1] * scale_mask)
                            offset = (offset[0] + size_mask[0] * scale_mask,
                                      offset[1] + size_mask[1] * scale_mask)
                        elif action == 5:
                            offset_aux = (size_mask[0] * scale_mask / 2,
                                          size_mask[0] * scale_mask / 2)
                            offset = (offset[0] + size_mask[0] * scale_mask / 2,
                                      offset[1] + size_mask[0] * scale_mask / 2)
                        region_image = region_image[offset_aux[0]:offset_aux[0] + size_mask[0],
                                       offset_aux[1]:offset_aux[1] + size_mask[1]]
                        region_mask[offset[0]:offset[0] + size_mask[0], offset[1]:offset[1] + size_mask[1]] = 1
                    draw_sequences_test(step, action, qval, draw, region_image, background, path_testing_folder,
                                        region_mask, image_name, bool_draw)
                    # trigger action
                    if action == 6:
                        offset = (0, 0)
                        status = 0
                        if step == 1:
                            absolute_status = 0
                        if only_first_object == 1:
                            absolute_status = 0
                        image_for_search = mask_image_with_mean_background(region_mask, image_for_search)
                        region_image = image_for_search
                    history_vector = update_history_vector(history_vector, action)
                    new_state = get_state(region_image, history_vector, model_vgg)
                    state = new_state
<commit_msg>Update image_zooms_testing.py<commit_after>import cv2, numpy as np
import time
import math as mth
from PIL import Image, ImageDraw, ImageFont
import scipy.io
from keras.models import Sequential
from keras import initializations
from keras.initializations import normal, identity
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.optimizers import RMSprop, SGD, Adam
import random
from scipy import ndimage
from keras.preprocessing import image
from sklearn.preprocessing import OneHotEncoder

from features import get_image_descriptor_for_image, obtain_compiled_vgg_16, vgg_16, \
    get_conv_image_descriptor_for_image, calculate_all_initial_feature_maps
from parse_xml_annotations import *
from image_helper import *
from metrics import *
from visualization import *
from reinforcement import *

if __name__ == "__main__":

    ######## PATHS definition ########

    # path of pascal voc test
    path_voc_test = "./VOC2007_test/"
    # model name of the weights
    model_name = "model_image_zooms"
    # path of folder where the weights are
    weights_path = "../models_image_zooms/"
    # path of where to store visualizations of search sequences
    path_testing_folder = '../testing/'
    # path of VGG16 weights
    path_vgg = "../vgg16_weights.h5"

     ######## MODELS ########

    model_vgg = obtain_compiled_vgg_16(path_vgg)
    model = get_q_network(weights_path + model_name)

    ######## LOAD IMAGE NAMES ########

    image_names = np.array([load_images_names_in_data_set('aeroplane_test', path_voc_test)])
    labels = load_images_labels_in_data_set('aeroplane_test', path_voc_test)

    ######## LOAD IMAGES ########

    images = get_all_images(image_names, path_voc_test)

    ######## PARAMETERS ########

    # Class category of PASCAL that the RL agent will be searching
    class_object = 1
    # 1 if you want to obtain visualizations of the search for objects
    bool_draw = 1
    # Scale of subregion for the hierarchical regions (to deal with 2/4, 3/4)
    scale_subregion = float(3)/4
    scale_mask = float(1)/(scale_subregion*4)
    # Number of steps that the agent does at each image
    number_of_steps = 10
    # Only search first object
    only_first_object = 1

    for j in range(np.size(image_names)):
        if labels[j] == "1":
            image = np.array(images[j])
            # init drawing for visualization
            background = Image.new('RGBA', (10000, 2000), (255, 255, 255, 255))
            draw = ImageDraw.Draw(background)
            image_name = image_names[0][j]
            annotation = get_bb_of_gt_from_pascal_xml_annotation(image_name, path_voc_test)
            gt_masks = generate_bounding_box_from_annotation(annotation, image.shape)
            array_classes_gt_objects = get_ids_objects_from_annotation(annotation)
            size_mask = (image.shape[0], image.shape[1])
            original_shape = size_mask
            image_for_search = image
            region_mask = np.ones([image.shape[0], image.shape[1]])
            # offset of the region observed at each time step
            offset = (0, 0)
            # absolute status is a boolean we indicate if the agent will continue
            # searching object or not. If the first object already covers the whole
            # image, we can put it at 0 so we do not further search there
            absolute_status = 1
            action = 0
            step = 0
            qval = 0
            region_image = image_for_search
            region_mask = np.ones([image.shape[0], image.shape[1]])
            # we run the agent if the maximum number of steps has not been reached and
            # if the boolean
            while (step < number_of_steps) and (absolute_status == 1):
                iou = 0
                # we init history vector as we are going to find another object
                history_vector = np.zeros([24])
                state = get_state(region_image, history_vector, model_vgg)
                status = 1
                draw_sequences_test(step, action, qval, draw, region_image, background, path_testing_folder,
                                    region_mask, image_name, bool_draw)
                size_mask = (image.shape[0], image.shape[1])
                original_shape = size_mask
                region_mask = np.ones([image.shape[0], image.shape[1]])
                while (status == 1) & (step < number_of_steps):
                    step += 1
                    qval = model.predict(state.T, batch_size=1)
                    action = (np.argmax(qval))+1
                    # movement action, make the proper zoom on the image
                    if action != 6:
                        region_mask = np.zeros(original_shape)
                        size_mask = (size_mask[0] * scale_reduction, size_mask[1] * scale_reduction)
                        if action == 1:
                            offset_aux = (0, 0)
                        elif action == 2:
                            offset_aux = (0, size_mask[1] * scale_mask)
                            offset = (offset[0], offset[1] + size_mask[1] * scale_mask)
                        elif action == 3:
                            offset_aux = (size_mask[0] * scale_mask, 0)
                            offset = (offset[0] + size_mask[0] * scale_mask, offset[1])
                        elif action == 4:
                            offset_aux = (size_mask[0] * scale_mask,
                                          size_mask[1] * scale_mask)
                            offset = (offset[0] + size_mask[0] * scale_mask,
                                      offset[1] + size_mask[1] * scale_mask)
                        elif action == 5:
                            offset_aux = (size_mask[0] * scale_mask / 2,
                                          size_mask[0] * scale_mask / 2)
                            offset = (offset[0] + size_mask[0] * scale_mask / 2,
                                      offset[1] + size_mask[0] * scale_mask / 2)
                        region_image = region_image[offset_aux[0]:offset_aux[0] + size_mask[0],
                                       offset_aux[1]:offset_aux[1] + size_mask[1]]
                        region_mask[offset[0]:offset[0] + size_mask[0], offset[1]:offset[1] + size_mask[1]] = 1
                    draw_sequences_test(step, action, qval, draw, region_image, background, path_testing_folder,
                                        region_mask, image_name, bool_draw)
                    # trigger action
                    if action == 6:
                        offset = (0, 0)
                        status = 0
                        if step == 1:
                            absolute_status = 0
                        if only_first_object == 1:
                            absolute_status = 0
                        image_for_search = mask_image_with_mean_background(region_mask, image_for_search)
                        region_image = image_for_search
                    history_vector = update_history_vector(history_vector, action)
                    new_state = get_state(region_image, history_vector, model_vgg)
                    state = new_state
<|endoftext|>


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

"""Tuttle"""

import sys
from os.path import join
try:
    import setuptools
    from cx_Freeze import setup, Executable
except ImportError:
    print("You need to install setuptools and cx_freeze modules in order to create a Windows installer for tuttle. "
          "You can install these packages with your package manager (usually python-setuptools) or via pip (pip"
          " install setuptools cx_freeze).")
    sys.exit(1)
from setup import tuttle_description # Import description of the package from the standard setup

# cx_freeze option for a command line application
base = None
build_exe_options = {
    "packages": ["os"],
    "excludes": ["tkinter"],
    "include_files": (
        join("tuttle", "report"),
    )
}
cx_freeze_opts = {
    'include_package_data':  True,
    'package_data':  {
        'tuttle.report':  ['*.html', 'html_report_assets/*'],
    },
    'options':  {'build_exe': build_exe_options},
    'executables':  [Executable(join("bin", "tuttle"), base=base)]
}
package_description = tuttle_description.copy()
package_description.update(cx_freeze_opts)

setup(**package_description)<commit_msg>Added msi packaging<commit_after>#!/usr/bin/env python
# -*- coding: utf8 -*-

"""Tuttle"""

import sys
import re
from os.path import join
try:
    import setuptools
    from cx_Freeze import setup, Executable
except ImportError:
    print("You need to install setuptools and cx_freeze modules in order to create a Windows installer for tuttle. "
          "You can install these packages with your package manager (usually python-setuptools) or via pip (pip"
          " install setuptools cx_freeze).")
    sys.exit(1)
from setup import tuttle_description # Import description of the package from the standard setup

def strip_rc(version):
    m = re.search(r'^(\d+)\.(\d+)', version)
    return m.group(0)

# cx_freeze option for a command line application
base = None
build_exe_options = {
    "packages": ["os"],
    "excludes": ["tkinter"],
    "include_files": (
        join("tuttle", "report"),
    )
}
build_msi_options = {
    "add_to_path": True,
}

cx_freeze_opts = {
    'include_package_data':  True,
    'package_data':  {
        'tuttle.report':  ['*.html', 'html_report_assets/*'],
    },
    'options':  {
        'build_exe': build_exe_options,
        'bdist_msi': build_msi_options
    },
    'executables':  [Executable(join("bin", "tuttle"), base=base)]
}
package_description = tuttle_description
package_description.update(cx_freeze_opts)
package_description['version'] = strip_rc(package_description['version'])
setup(**package_description)<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
#
import os
import cv2
from pathlib import Path
#
from dataprocessor import DataProcessor, ImageType

class Clipping(object):
    def __init__(self, media, target=None):
        self.media = media
        self.target = target
        pro = DataProcessor(self.media, ImageType.PLAN)
        pro.prepare()
        self.binary = pro.batch()
        self.color = pro.color
        self.drawClipSource = True
    def number(self):
        """
            fillter
                1,頂点数が3未満
                2,面積が50未満
        """
        cv2.imwrite('./test/binary_color{0}'.format(os.path.basename(self.media)), self.color)
        cv2.imwrite('./test/binary_{0}'.format(os.path.basename(self.media)), self.binary)
        image, contours, hierarchy = cv2.findContours(self.binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        rect = []
        for c in contours:
            approx = cv2.approxPolyDP(c,1,True)
            if len(approx) < 3:
                continue
            area = cv2.contourArea(approx)
            if area < 50:
                continue
            if self.drawClipSource:
                cv2.drawContours(self.color, [c], -1, (0,255,0), 3)
                pass
            rect.append(cv2.boundingRect(approx))

        rect = sorted(rect, key=lambda x:(x[1], x[0]))
        self.splitImage(rect)
        return ''
    def splitImage(self, rect):
        srcPath = Path(self.media)
        srcfilename = os.path.basename(srcPath.stem)
        for i, value  in enumerate(rect):
            x, y = value[0], value[1]
            w, h = value[2], value[3]
            p1 = (x, y)
            p2 = (x+w, y+h)
            cv2.rectangle(self.color, p1, p2, (0,255,0), 2)
            roi = self.color[y:y+h,x:x+w]
            #roi = roi.shape[:2]
            #image = cv2.resize(self.color[y:y+h,x:x+w],(32,32))
            image = roi
            cv2.imwrite('./test/{0}_{1}_{2}{3}'.format(srcfilename, i, value, srcPath.suffix), image)<commit_msg>pylint<commit_after># -*- coding: utf-8 -*-
#
import os
import cv2
from pathlib import Path
#
from dataprocessor import DataProcessor, ImageType

class Clipping(object):
    def __init__(self, media, target=None):
        self.media = media
        self.target = target
        pro = DataProcessor(self.media, ImageType.PLAN)
        pro.prepare()
        self.binary = pro.batch()
        self.color = pro.color
        self.drawClipSource = True
    def number(self):
        """
            fillter
                1,頂点数が3未満
                2,面積が50未満
        """
        cv2.imwrite('./temp/binary_color{0}'.format(os.path.basename(self.media)), self.color)
        cv2.imwrite('./temp/binary_{0}'.format(os.path.basename(self.media)), self.binary)
        image, contours, hierarchy = cv2.findContours(self.binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        rect = []
        for c in contours:
            approx = cv2.approxPolyDP(c, 1, True)
            if len(approx) < 3:
                continue
            area = cv2.contourArea(approx)
            if area < 50:
                continue
            if self.drawClipSource:
                cv2.drawContours(self.color, [c], -1, (0, 255, 0), 3)
                pass
            rect.append(cv2.boundingRect(approx))

        rect = sorted(rect, key=lambda x:(x[1], x[0]))
        self.splitImage(rect)
        return ''
    def splitImage(self, rect):
        srcPath = Path(self.media)
        srcfilename = os.path.basename(srcPath.stem)
        for i, value  in enumerate(rect):
            x, y = value[0], value[1]
            w, h = value[2], value[3]
            p1 = (x, y)
            p2 = (x+w, y+h)
            cv2.rectangle(self.color, p1, p2, (0, 255, 0), 2)
            roi = self.color[y:y+h,x:x+w]
            #roi = roi.shape[:2]
            #image = cv2.resize(self.color[y:y+h,x:x+w],(32,32))
            image = roi
            cv2.imwrite('./temp/{0}_{1}_{2}{3}'.format(srcfilename, i, value, srcPath.suffix), image)
<|endoftext|>


<commit_before>import asyncio
import os.path
import re
import urllib.request
import urllib.error
import discord

from random import choice, random
from subprocess import check_output
from collections import defaultdict
from urllib.parse import urlsplit, urlunsplit, parse_qsl, urlencode

from .plugin_mount import PluginMount

class CommandPlugin(metaclass=PluginMount):
    """
    Class that stores the instances for each command.
    Every command must contain a command string property and a func function
    """

    def func(self, parent, message):
        raise NotImplementedError("Please implement this method.")

    def __init__(self):
        raise NotImplementedError(
            "Please implement a command variable and a helpstring variable.")

class CommandObey(CommandPlugin):

    def __init__(self):
        self.command = "!obey"

        self.helpstring = "!obey: " \
                          "This only works if you are one of the chosen ones."

        self.obey_dict = {
            # neosloth
            "120767447681728512": "I obey.",
            # Average Dragon
            "182268688559374336": "Eat a dick, dragon.",
            # Garta
            "217005730149040128": "Welcome, Srammiest Man",
            # spitefiremase
            "165971889351688192": "Mase, you're cooler and smarter and stronger and funnier in real life",
            # Shaper
            "115501385679634439": "Shaped shape shaping shapes~"
        }

    def func(self, parent, message):
        if message.author.id in self.obey_dict.keys():
            return self.obey_dict[message.author.id]
        else:
            return "I will not obey."

class CommandPing(CommandPlugin):

    def __init__(self):
        self.command = "!pingme"
        self.helpstring = "!pingme: Pings the message.author."

    def func(self, parent, message):
        return message.author.mention

class CommandAddMe(CommandPlugin):
    """!addme: The link to add Bolas to your Discord room."""

    def __init__(self):
        self.command = "!addme"
        self.helpstring = "!addme: " \
                          "The link to add Bolas to your Discord server."

    def func(self, parent, message):
        return "https://discordapp.com/oauth2/authorize?"\
            "client_id=245372541915365377&scope=bot&permissions=0"

class CommandCoin(CommandPlugin):

    def __init__(self):
        self.command = "!coin"
        self.helpstring = "!coin: Flips a coin."

    def func(self, parent, message):
        return choice(["Heads", "Tails"])

class CommandChoice(CommandPlugin):

    def __init__(self):
        self.command = "!choose"
        self.helpstring = "!choose: Chooses an option. "\
                          "Example: !choose apples or oranges"

    def func(self, parent, message):
        return "I choose: {0}".format(
            choice(" ".join(message.content.split(" ")[1:]).split(" or ")))

class CommandGit(CommandPlugin):

    def __init__(self):
        self.command = "!git"
        self.helpstring = "!git: Repo link and changelog."

    def func(self, parent, message):
        return "{0}\n{1}\n```{2}```".format(
            "https://gitlab.com/neosloth/bolas",
            "https://theneosloth.github.io/Bolas/",
            check_output("git log --oneline -3", shell=True).decode("utf-8"))

class CommandStats(CommandPlugin):

    def __init__(self):
        self.command = "!stats"
        self.helpstring = "!stats: " \
                          " Return the number of users and servers served."

    def func(self, parent, message):
        num_servers = len(parent.servers)
        num_users = sum([len(server.members) for server in parent.servers])
        return "Fetching cards for {} servers and {} users".format(
            num_servers,
            num_users
        )

class CommandLfg(CommandPlugin):

    def __init__(self):
        self.command = "!lfg"
        self.helpstring = "!lfg: Add yourself to the LFG role."
        self.role_name = "LFG"

    def func(self, parent, message):

        if message.server is None:
            return "Sorry, I can't set roles in PMs."

        # The discord bot Client only stores the user,
        # so we have to manually get the Member object
        client_member = message.server.get_member(parent.user.id)

        sufficient_permissions = message.channel.permissions_for(
            client_member).manage_roles

        if not sufficient_permissions:
            return None

        lfg_role = None

        # Find the appropriate role object
        for role in message.server.roles:
            if role.name == self.role_name:
                lfg_role = role

        # Can't do anything if the role doesn't exist
        if lfg_role is None:
            return "Sorry, this server does not have a LFG role."

        if lfg_role in message.author.roles:
            # The remove role method is a coroutine
            # so we have to wrap it in an asyncio call
            asyncio.ensure_future(
                parent.remove_roles(message.author, lfg_role)
            )
            return "Removed {0.name} from the LFG role.".format(
                message.author
            )

        asyncio.ensure_future(
            parent.add_roles(message.author, lfg_role)
        )
        return "Added {0.name} to the LFG role.".format(
            message.author
        )

class CommandRule(CommandPlugin):
    def __init__(self):
        self.command = "!rule"
        self.helpstring = "!rule {rule number or set of keywords.}:"\
                          " Cite a mtg rule."
        self.ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
        # Move 1 directory up and into misc
        self.FILE_NAME = os.path.realpath(os.path.join(
            self.ROOT_DIR, "../misc/MagicCompRules_20181005.txt"))

        self.RULE_LIMIT = 10

    def get_rule(self, args):
        # First argument (presumably the rule number)
        num = args[1]
        # All the words after the command
        tokens = args[1:]
        result = ""
        rule_count = 0

        try:
            with open(self.FILE_NAME, "r", encoding="utf-8") as f:
                # Using enumerate so the file is read sequentially
                # and is not stored in memory
                for i, line in enumerate(f):
                    if (line.startswith(str(num))):
                        return line
                    # Append the rule number if all the words are in
                    # that rule.
                    # Only check the lines that start with a number.
                    # Also check if we've gone over our rule count
                    if (line[0].isdigit() and all(
                            word.lower() in line.lower() for word in tokens
                    ) and (rule_count < self.RULE_LIMIT)):

                        result = "{}* {}\n".format(result, line.split(" ")[0])
                        rule_count += 1

            if rule_count >= self.RULE_LIMIT:
                result += "The query returned too many results, " \
                          " so some of the results were omitted. " \
                          "Please provide more keywords to narrow the search."

            return result or "Could not find the matching rule."
        except FileNotFoundError:
            return "Could not find the magic comprehensive rules file."

    def func(self, parent, message):
        args = message.content.split()
        if len(args) > 1:
            # Surround the result with markdown code tags (for nice bullets)
            return "```markdown\n{}```".format(self.get_rule(args))
        else:
            return "Please provide a rule number or a set of keywords." \
                "See the full list of rules here: http://magic.wizards.com" \
                "/en/game-info/gameplay/rules-and-formats/rules"

class CommandAppearin(CommandPlugin):

    def __init__(self):
        self.command = "!appearin"
        self.helpstring = "!appearin:"\
                          " Create a new appearin call with everyone mentioned."

    def func(self, parent, message):
        # Random 10 digit number
        call_id = str(random())[2:12]
        url = "https://appear.in/{}?widescreen".format(call_id)

        # Simply send out the url if no one was mentioned
        if not message.mentions:
            return url

        invite_message = "{} is inviting you to a call.\n{}".format(
            message.author.name,
            url
        )

        asyncio.ensure_future(
            parent.send_message(message.author, invite_message))

        for mention in message.mentions:
            asyncio.ensure_future(
                parent.send_message(mention, invite_message))

        # No message is returned to the chat
        return None

class CommandVideo(CommandPlugin):

    def __init__(self):
        self.command = "!videocall"
        self.helpstring = "!videocall:"\
                          " Create a new videocall with everyone mentioned."

    def func(self, parent, message):
        # Random 10 digit number
        call_id = str(random())[2:12]
        url = "https://meet.jit.si/{}".format(call_id)

        # Simply send out the url if no one was mentioned
        if not message.mentions:
            return url

        invite_message = "{} is inviting you to a videocall.\n{}".format(
            message.author.name,
            url
        )

        asyncio.ensure_future(
            parent.send_message(message.author, invite_message))

        for mention in message.mentions:
            asyncio.ensure_future(
                parent.send_message(mention, invite_message))

        # No message is returned to the chat
        return None

class CommandDiff(CommandPlugin):

    def __init__(self):
        self.command = "!diff"
        self.helpstring = "!diff:"\
                          " Generates diff of two decklists."

        # Dict of valid url domains, and options for those domains
        self.valid_urls = {
            "deckstats.net": {
                "query":[("export_dec", "1")]
            },
            "tappedout.net": {
                "query":[("fmt", "dec")]
            }
        }

        self.re_stripangle = re.compile(r"^<(.*)>$")
        # Gets count and card name from decklist line
        self.re_line = re.compile(
                r"^\s*(?:(?P<sb>SB:)\s)?\s*"
                r"(?P<count>[0-9]+)x?\s+(?P<name>.*)\s*$")
        # Lines to skip when reading decklists
        self.re_skip = re.compile(r"^(?:$|//)")

        # Dict of card names that should be replaced due to inconsistancy
        # AKA Wizards needs to errata Lim-Dûl's Vault already :(
        self.name_replacements = {
            "Lim-Dul's Vault": "Lim-Dûl's Vault"
        }

    #Error class for sending error messages
    class MessageError(Exception):
        def __init__(self, message):
            self.message = message

    # Parses a string to get a valid url
    # Returns None if not a good url
    # MessageError unknown url if url found and not in valid urls
    def get_valid_url(self, s):
        #strip surrounding < >. This allows for non-embedding links
        strip = self.re_stripangle.match(s)
        if strip:
            s = strip[1]

        url = urlsplit(s, scheme="https")
        if (url.netloc and url.path and
                (url.scheme == "http" or url.scheme == "https")):
            valid_opts = self.valid_urls.get(url.netloc, None)
            if not valid_opts:
                raise CommandDiff.MessageError(
                        "Unknown url <{}>".format(s))
            url = list(url)
            query_n = valid_opts.get("query", None)
            if query_n:
                query_l = parse_qsl(url[3])
                query_l.extend(query_n)
                url[3] = urlencode(query_l)
            return urlunsplit(url)
        else:
            return None

    # Normalizes names.
    def filter_name(self, name):
        return self.name_replacements.get(name, name)

    # Parses decklist string into a tuple of dicts for main and sideboards
    def get_list(self, deck):
        mainboard = defaultdict(int)
        sideboard = defaultdict(int)
        for line in deck.split("\n"):
            # Need to allow blank lines
            line = line.strip()
            if self.re_skip.match(line):
                continue
            match = self.re_line.match(line)
            if not match:
                raise CommandDiff.MessageError("Error parsing file.")
            if match["sb"]:
                lst = sideboard
            else:
                lst = mainboard
            lst[self.filter_name(match["name"])] += int(match["count"])
        return (mainboard, sideboard)

    # Diffs two decklist dicts
    # Returns 4-tuple with count and card name columns for both lists
    def get_diff(self, list_l, list_r):
        cards = frozenset(list_l.keys()) | frozenset(list_r.keys())
        diff = ([],[],[],[])
        for c in cards:
            if list_l[c] > list_r[c]:
                diff[1].append(c)
                diff[0].append(list_l[c] - list_r[c])
            elif list_r[c] > list_l[c]:
                diff[3].append(c)
                diff[2].append(list_r[c] - list_l[c])
        return diff

    # Takes a diff 4-tuple and adds it as fields on given embed.
    def format_diff_embed(self, diff, name, embed):
        strdiff = (
                ([str(i) for i in diff[0]], diff[1]),
                ([str(i) for i in diff[2]], diff[3])
        )
        for num, lst in enumerate(strdiff, start=1):
            output = "\n".join(map(lambda x: "{} {}".format(*x), zip(*lst)))
            # Discord doesn't like empty fields
            if output:
                embed.add_field(name="{} {}".format(name, num), value=output,
                        inline=True)
        return embed

    def func(self, parent, message):
        try:
            urls = [m for m in (self.get_valid_url(w)
                for w in message.content.split()[1:]) if m]
            if len(urls) != 2:
                raise CommandDiff.MessageError("Exactly two urls are needed.")

            try:
                files = (urllib.request.urlopen(u)
                        .read().decode("utf-8", "replace")
                    for u in urls)
                decklists = [self.get_list(f) for f in files]
            except urllib.error.URLError as e:
                raise CommandDiff.MessageError("Failed to open url.")

            maindiff = self.get_diff(decklists[0][0], decklists[1][0])
            sidediff = self.get_diff(decklists[0][1], decklists[1][1])

            result = discord.Embed()
            self.format_diff_embed(maindiff, "Mainboard", result)
            self.format_diff_embed(sidediff, "Sideboard", result)
            return result
        except CommandDiff.MessageError as e:
            return e.message

<commit_msg>Fix bug with lists with comments<commit_after>import asyncio
import os.path
import re
import urllib.request
import urllib.error
import discord

from random import choice, random
from subprocess import check_output
from collections import defaultdict
from urllib.parse import urlsplit, urlunsplit, parse_qsl, urlencode

from .plugin_mount import PluginMount

class CommandPlugin(metaclass=PluginMount):
    """
    Class that stores the instances for each command.
    Every command must contain a command string property and a func function
    """

    def func(self, parent, message):
        raise NotImplementedError("Please implement this method.")

    def __init__(self):
        raise NotImplementedError(
            "Please implement a command variable and a helpstring variable.")

class CommandObey(CommandPlugin):

    def __init__(self):
        self.command = "!obey"

        self.helpstring = "!obey: " \
                          "This only works if you are one of the chosen ones."

        self.obey_dict = {
            # neosloth
            "120767447681728512": "I obey.",
            # Average Dragon
            "182268688559374336": "Eat a dick, dragon.",
            # Garta
            "217005730149040128": "Welcome, Srammiest Man",
            # spitefiremase
            "165971889351688192": "Mase, you're cooler and smarter and stronger and funnier in real life",
            # Shaper
            "115501385679634439": "Shaped shape shaping shapes~"
        }

    def func(self, parent, message):
        if message.author.id in self.obey_dict.keys():
            return self.obey_dict[message.author.id]
        else:
            return "I will not obey."

class CommandPing(CommandPlugin):

    def __init__(self):
        self.command = "!pingme"
        self.helpstring = "!pingme: Pings the message.author."

    def func(self, parent, message):
        return message.author.mention

class CommandAddMe(CommandPlugin):
    """!addme: The link to add Bolas to your Discord room."""

    def __init__(self):
        self.command = "!addme"
        self.helpstring = "!addme: " \
                          "The link to add Bolas to your Discord server."

    def func(self, parent, message):
        return "https://discordapp.com/oauth2/authorize?"\
            "client_id=245372541915365377&scope=bot&permissions=0"

class CommandCoin(CommandPlugin):

    def __init__(self):
        self.command = "!coin"
        self.helpstring = "!coin: Flips a coin."

    def func(self, parent, message):
        return choice(["Heads", "Tails"])

class CommandChoice(CommandPlugin):

    def __init__(self):
        self.command = "!choose"
        self.helpstring = "!choose: Chooses an option. "\
                          "Example: !choose apples or oranges"

    def func(self, parent, message):
        return "I choose: {0}".format(
            choice(" ".join(message.content.split(" ")[1:]).split(" or ")))

class CommandGit(CommandPlugin):

    def __init__(self):
        self.command = "!git"
        self.helpstring = "!git: Repo link and changelog."

    def func(self, parent, message):
        return "{0}\n{1}\n```{2}```".format(
            "https://gitlab.com/neosloth/bolas",
            "https://theneosloth.github.io/Bolas/",
            check_output("git log --oneline -3", shell=True).decode("utf-8"))

class CommandStats(CommandPlugin):

    def __init__(self):
        self.command = "!stats"
        self.helpstring = "!stats: " \
                          " Return the number of users and servers served."

    def func(self, parent, message):
        num_servers = len(parent.servers)
        num_users = sum([len(server.members) for server in parent.servers])
        return "Fetching cards for {} servers and {} users".format(
            num_servers,
            num_users
        )

class CommandLfg(CommandPlugin):

    def __init__(self):
        self.command = "!lfg"
        self.helpstring = "!lfg: Add yourself to the LFG role."
        self.role_name = "LFG"

    def func(self, parent, message):

        if message.server is None:
            return "Sorry, I can't set roles in PMs."

        # The discord bot Client only stores the user,
        # so we have to manually get the Member object
        client_member = message.server.get_member(parent.user.id)

        sufficient_permissions = message.channel.permissions_for(
            client_member).manage_roles

        if not sufficient_permissions:
            return None

        lfg_role = None

        # Find the appropriate role object
        for role in message.server.roles:
            if role.name == self.role_name:
                lfg_role = role

        # Can't do anything if the role doesn't exist
        if lfg_role is None:
            return "Sorry, this server does not have a LFG role."

        if lfg_role in message.author.roles:
            # The remove role method is a coroutine
            # so we have to wrap it in an asyncio call
            asyncio.ensure_future(
                parent.remove_roles(message.author, lfg_role)
            )
            return "Removed {0.name} from the LFG role.".format(
                message.author
            )

        asyncio.ensure_future(
            parent.add_roles(message.author, lfg_role)
        )
        return "Added {0.name} to the LFG role.".format(
            message.author
        )

class CommandRule(CommandPlugin):
    def __init__(self):
        self.command = "!rule"
        self.helpstring = "!rule {rule number or set of keywords.}:"\
                          " Cite a mtg rule."
        self.ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
        # Move 1 directory up and into misc
        self.FILE_NAME = os.path.realpath(os.path.join(
            self.ROOT_DIR, "../misc/MagicCompRules_20181005.txt"))

        self.RULE_LIMIT = 10

    def get_rule(self, args):
        # First argument (presumably the rule number)
        num = args[1]
        # All the words after the command
        tokens = args[1:]
        result = ""
        rule_count = 0

        try:
            with open(self.FILE_NAME, "r", encoding="utf-8") as f:
                # Using enumerate so the file is read sequentially
                # and is not stored in memory
                for i, line in enumerate(f):
                    if (line.startswith(str(num))):
                        return line
                    # Append the rule number if all the words are in
                    # that rule.
                    # Only check the lines that start with a number.
                    # Also check if we've gone over our rule count
                    if (line[0].isdigit() and all(
                            word.lower() in line.lower() for word in tokens
                    ) and (rule_count < self.RULE_LIMIT)):

                        result = "{}* {}\n".format(result, line.split(" ")[0])
                        rule_count += 1

            if rule_count >= self.RULE_LIMIT:
                result += "The query returned too many results, " \
                          " so some of the results were omitted. " \
                          "Please provide more keywords to narrow the search."

            return result or "Could not find the matching rule."
        except FileNotFoundError:
            return "Could not find the magic comprehensive rules file."

    def func(self, parent, message):
        args = message.content.split()
        if len(args) > 1:
            # Surround the result with markdown code tags (for nice bullets)
            return "```markdown\n{}```".format(self.get_rule(args))
        else:
            return "Please provide a rule number or a set of keywords." \
                "See the full list of rules here: http://magic.wizards.com" \
                "/en/game-info/gameplay/rules-and-formats/rules"

class CommandAppearin(CommandPlugin):

    def __init__(self):
        self.command = "!appearin"
        self.helpstring = "!appearin:"\
                          " Create a new appearin call with everyone mentioned."

    def func(self, parent, message):
        # Random 10 digit number
        call_id = str(random())[2:12]
        url = "https://appear.in/{}?widescreen".format(call_id)

        # Simply send out the url if no one was mentioned
        if not message.mentions:
            return url

        invite_message = "{} is inviting you to a call.\n{}".format(
            message.author.name,
            url
        )

        asyncio.ensure_future(
            parent.send_message(message.author, invite_message))

        for mention in message.mentions:
            asyncio.ensure_future(
                parent.send_message(mention, invite_message))

        # No message is returned to the chat
        return None

class CommandVideo(CommandPlugin):

    def __init__(self):
        self.command = "!videocall"
        self.helpstring = "!videocall:"\
                          " Create a new videocall with everyone mentioned."

    def func(self, parent, message):
        # Random 10 digit number
        call_id = str(random())[2:12]
        url = "https://meet.jit.si/{}".format(call_id)

        # Simply send out the url if no one was mentioned
        if not message.mentions:
            return url

        invite_message = "{} is inviting you to a videocall.\n{}".format(
            message.author.name,
            url
        )

        asyncio.ensure_future(
            parent.send_message(message.author, invite_message))

        for mention in message.mentions:
            asyncio.ensure_future(
                parent.send_message(mention, invite_message))

        # No message is returned to the chat
        return None

class CommandDiff(CommandPlugin):

    def __init__(self):
        self.command = "!diff"
        self.helpstring = "!diff:"\
                          " Generates diff of two decklists."

        # Dict of valid url domains, and options for those domains
        self.valid_urls = {
            "deckstats.net": {
                "query":[("export_dec", "1")]
            },
            "tappedout.net": {
                "query":[("fmt", "dec")]
            }
        }

        self.re_stripangle = re.compile(r"^<(.*)>$")
        # Gets count and card name from decklist line
        self.re_line = re.compile(
                r"^\s*(?:(?P<sb>SB:)\s)?\s*"
                r"(?P<count>[0-9]+)x?\s+(?P<name>.*?)\s*"
                r"(?:<[^>]*>\s*)*(?:#.*)?$")
        # Lines to skip when reading decklists
        self.re_skip = re.compile(r"^\s*(?:$|//)")

        # Dict of card names that should be replaced due to inconsistancy
        # AKA Wizards needs to errata Lim-Dûl's Vault already :(
        self.name_replacements = {
            "Lim-Dul's Vault": "Lim-Dûl's Vault"
        }

    #Error class for sending error messages
    class MessageError(Exception):
        def __init__(self, message):
            self.message = message

    # Parses a string to get a valid url
    # Returns None if not a good url
    # MessageError unknown url if url found and not in valid urls
    def get_valid_url(self, s):
        #strip surrounding < >. This allows for non-embedding links
        strip = self.re_stripangle.match(s)
        if strip:
            s = strip[1]

        url = urlsplit(s, scheme="https")
        if (url.netloc and url.path and
                (url.scheme == "http" or url.scheme == "https")):
            valid_opts = self.valid_urls.get(url.netloc, None)
            if not valid_opts:
                raise CommandDiff.MessageError(
                        "Unknown url <{}>".format(s))
            url = list(url)
            query_n = valid_opts.get("query", None)
            if query_n:
                query_l = parse_qsl(url[3])
                query_l.extend(query_n)
                url[3] = urlencode(query_l)
            return urlunsplit(url)
        else:
            return None

    # Normalizes names.
    def filter_name(self, name):
        return self.name_replacements.get(name, name)

    # Parses decklist string into a tuple of dicts for main and sideboards
    def get_list(self, deck):
        mainboard = defaultdict(int)
        sideboard = defaultdict(int)
        for line in deck.split("\n"):
            if self.re_skip.match(line):
                continue
            match = self.re_line.match(line)
            if not match:
                raise CommandDiff.MessageError("Error parsing file.")
            if match["sb"]:
                lst = sideboard
            else:
                lst = mainboard
            lst[self.filter_name(match["name"])] += int(match["count"])
        return (mainboard, sideboard)

    # Diffs two decklist dicts
    # Returns 4-tuple with count and card name columns for both lists
    def get_diff(self, list_l, list_r):
        cards = frozenset(list_l.keys()) | frozenset(list_r.keys())
        diff = ([],[],[],[])
        for c in cards:
            if list_l[c] > list_r[c]:
                diff[1].append(c)
                diff[0].append(list_l[c] - list_r[c])
            elif list_r[c] > list_l[c]:
                diff[3].append(c)
                diff[2].append(list_r[c] - list_l[c])
        return diff

    # Takes a diff 4-tuple and adds it as fields on given embed.
    def format_diff_embed(self, diff, name, embed):
        strdiff = (
                ([str(i) for i in diff[0]], diff[1]),
                ([str(i) for i in diff[2]], diff[3])
        )
        for num, lst in enumerate(strdiff, start=1):
            output = "\n".join(map(lambda x: "{} {}".format(*x), zip(*lst)))
            # Discord doesn't like empty fields
            if output:
                embed.add_field(name="{} {}".format(name, num), value=output,
                        inline=True)
        return embed

    def func(self, parent, message):
        try:
            urls = [m for m in (self.get_valid_url(w)
                for w in message.content.split()[1:]) if m]
            if len(urls) != 2:
                raise CommandDiff.MessageError("Exactly two urls are needed.")

            try:
                files = (urllib.request.urlopen(u)
                        .read().decode("utf-8", "replace")
                    for u in urls)
                decklists = [self.get_list(f) for f in files]
            except urllib.error.URLError as e:
                raise CommandDiff.MessageError("Failed to open url.")

            maindiff = self.get_diff(decklists[0][0], decklists[1][0])
            sidediff = self.get_diff(decklists[0][1], decklists[1][1])

            result = discord.Embed()
            self.format_diff_embed(maindiff, "Mainboard", result)
            self.format_diff_embed(sidediff, "Sideboard", result)
            return result
        except CommandDiff.MessageError as e:
            return e.message

<|endoftext|>


<commit_before>## Copyright 2016 Raik Gruenberg

## This file is part of the LabHamster project (https://github.com/graik/labhamster).
## LabHamster is released under the MIT open source license, which you can find
## along with this project (LICENSE) or at <https://opensource.org/licenses/MIT>.

"""
Django settings for labhamster project.
"""

# Build paths inside the project like this: os.path.join(PROJECT_ROOT, ...)
import os
PROJECT_ROOT = os.path.dirname(os.path.dirname(__file__))

# custom: distinguish development from production server
import sys
RUNNING_DEV_SERVER = ('runserver' in sys.argv)

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
try:
	## prepare env variable:
	## heroku config:add DJANGO_SECRET_KEY="your_secret_key"
	## Note: () are not tolerated in the key even using quotation marks
	SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
except:
	SECRET_KEY = 'settings-k^(3w9m#hndetog(ap+f(m+^jn*vu&s4a9cv3%&a(fe)$aq=s'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False

ALLOWED_HOSTS = ['*']

# Database configuration by Heroku $DATABASE_URL
# Use persistent connections
# https://devcenter.heroku.com/articles/django-app-configuration#database-connection-persistence
## this will be overriden by $DATABASE_URL configuration; but doesn't hurt
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(PROJECT_ROOT, 'db.sqlite3'),
    }}

import dj_database_url
db_from_env = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(db_from_env)

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/
# https://devcenter.heroku.com/articles/django-app-configuration#static-assets-and-file-serving

STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles')
STATIC_URL = '/static/'

# Extra places for collectstatic to find static files.
STATICFILES_DIRS = (
    os.path.join(PROJECT_ROOT, 'static'),
)

# Simplified static file serving.
# https://warehouse.python.org/project/whitenoise/
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'

#
# Application definition
#
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'labhamster',
)

MIDDLEWARE_CLASSES = (
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'labhamstersite.urls'

WSGI_APPLICATION = 'labhamstersite.wsgi.application'

# new in Django 1.9 default settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
                 os.path.join(PROJECT_ROOT, 'labhamster', 'templates'),
                 os.path.join(PROJECT_ROOT, 'site_templates'),
                 ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                "django.contrib.auth.context_processors.auth",
                "django.template.context_processors.debug",
                "django.template.context_processors.i18n",
                "django.template.context_processors.media",
                "django.template.context_processors.static",
                "django.template.context_processors.tz",
                "django.contrib.messages.context_processors.messages"
            ],
        },
    },
]

# Activate SSL / HTTPS
if not RUNNING_DEV_SERVER:
	SECURE_SSL_REDIRECT = True # [1]
	SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# Password validation
# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
    {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
# https://docs.djangoproject.com/en/1.9/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = False  ## de-activate automatic localization of numbers and dates
USE_TZ = True
<commit_msg>fix static file folders<commit_after>## Copyright 2016 Raik Gruenberg

## This file is part of the LabHamster project (https://github.com/graik/labhamster).
## LabHamster is released under the MIT open source license, which you can find
## along with this project (LICENSE) or at <https://opensource.org/licenses/MIT>.

"""
Django settings for labhamster project.
"""

# Build paths inside the project like this: os.path.join(PROJECT_ROOT, ...)
import os
PROJECT_ROOT = os.path.dirname(os.path.dirname(__file__))

# custom: distinguish development from production server
import sys
RUNNING_DEV_SERVER = ('runserver' in sys.argv)

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'settings-k^(3w9m#hndetog(ap+f(m+^jn*vu&s4a9cv3%&a(fe)$aq=s'
try:
	## prepare env variable:
	## heroku config:add DJANGO_SECRET_KEY="your_secret_key"
	## Note: () are not tolerated in the key even using quotation marks
	SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY') or SECRET_KEY
except:
	pass

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False

ALLOWED_HOSTS = ['*']

# Database configuration by Heroku $DATABASE_URL
# Use persistent connections
# https://devcenter.heroku.com/articles/django-app-configuration#database-connection-persistence
## this will be overriden by $DATABASE_URL configuration; but doesn't hurt
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(PROJECT_ROOT, 'db.sqlite3'),
    }}

import dj_database_url
db_from_env = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(db_from_env)

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/
# https://devcenter.heroku.com/articles/django-app-configuration#static-assets-and-file-serving

STATIC_ROOT = os.path.join(PROJECT_ROOT, 'labhamstersite','staticfiles')
STATIC_URL = '/static/'

# Extra places for collectstatic to find static files.
##STATICFILES_DIRS = (
##    os.path.join(PROJECT_ROOT, 'static'),
##)

# Simplified static file serving.
# https://warehouse.python.org/project/whitenoise/
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'

#
# Application definition
#
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'labhamster',
)

MIDDLEWARE_CLASSES = (
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'labhamstersite.urls'

WSGI_APPLICATION = 'labhamstersite.wsgi.application'

# new in Django 1.9 default settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
                 os.path.join(PROJECT_ROOT, 'labhamster', 'templates'),
                 os.path.join(PROJECT_ROOT, 'site_templates'),
                 ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                "django.contrib.auth.context_processors.auth",
                "django.template.context_processors.debug",
                "django.template.context_processors.i18n",
                "django.template.context_processors.media",
                "django.template.context_processors.static",
                "django.template.context_processors.tz",
                "django.contrib.messages.context_processors.messages"
            ],
        },
    },
]

# Activate SSL / HTTPS
if not RUNNING_DEV_SERVER:
	SECURE_SSL_REDIRECT = True # [1]
	SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# Password validation
# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
    {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
# https://docs.djangoproject.com/en/1.9/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = False  ## de-activate automatic localization of numbers and dates
USE_TZ = True
<|endoftext|>