<commit_before># coding: utf-8

from .functions import ex, hlp, str_list, str_list_w_last, href, cite
from django.db.models import CharField, ManyToManyField, \
                             PositiveIntegerField, FloatField, ForeignKey, \
                             OneToOneField, IntegerField, TextField, \
                             permalink, get_model
from tinymce.models import HTMLField
from django.utils.html import strip_tags
from django.utils.translation import ungettext_lazy, ugettext, \
                                     ugettext_lazy as _
from django.template.defaultfilters import capfirst
from django.contrib.humanize.templatetags.humanize import apnumber
from .common import CustomModel, AutoriteModel, LOWER_MSG, PLURAL_MSG, \
                    calc_pluriel, SlugModel, UniqueSlugModel, CustomManager, \
                    CustomQuerySet
from django.core.exceptions import ValidationError
from collections import defaultdict
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.generic import GenericForeignKey
from django.contrib.contenttypes.generic import GenericRelation


class GenreDOeuvre(CustomModel, SlugModel):
    nom = CharField(max_length=255, help_text=LOWER_MSG, unique=True)
    nom_pluriel = CharField(max_length=430, blank=True,
        verbose_name=_('nom (au pluriel)'),
        help_text=PLURAL_MSG)
    parents = ManyToManyField('GenreDOeuvre', related_name='enfants',
        blank=True, null=True)

    class Meta:
        verbose_name = ungettext_lazy(u'genre d’œuvre', u'genres d’œuvre', 1)
        verbose_name_plural = ungettext_lazy(u'genre d’œuvre',
                                             u'genres d’œuvre', 2)
        ordering = ['slug']
        app_label = 'catalogue'

    def html(self, tags=True, caps=False, pluriel=False):
        nom = self.pluriel() if pluriel else self.nom
        if caps:
            nom = capfirst(nom)
        return hlp(nom, ugettext('genre'), tags)

    def pluriel(self):
        return calc_pluriel(self)

    def __unicode__(self):
        return strip_tags(self.html(False))

    @staticmethod
    def autocomplete_search_fields():
        return 'nom__icontains', 'nom_pluriel__icontains',


class TypeDeCaracteristiqueDOeuvre(CustomModel):
    nom = CharField(max_length=200, help_text=ex(_(u'tonalité')), unique=True)
    nom_pluriel = CharField(max_length=230, blank=True,
        verbose_name=_('nom (au pluriel)'), help_text=PLURAL_MSG)
    classement = FloatField(default=1.0)

    class Meta:
        verbose_name = ungettext_lazy(u'type de caractéristique d’œuvre',
                                      u'types de caracteristique d’œuvre', 1)
        verbose_name_plural = ungettext_lazy(
                u'type de caractéristique d’œuvre',
                u'types de caracteristique d’œuvre',
                2)
        ordering = ['classement']
        app_label = 'catalogue'

    def pluriel(self):
        return calc_pluriel(self)

    def __unicode__(self):
        return self.nom


class CaracteristiqueDOeuvre(CustomModel):
    type = ForeignKey('TypeDeCaracteristiqueDOeuvre',
        related_name='caracteristiques_d_oeuvre')
    # TODO: Changer valeur en nom ?
    valeur = CharField(max_length=400, help_text=ex(_(u'en trois actes')))
    classement = FloatField(default=1.0,
        help_text=_(u'''Par exemple, on peut choisir de classer'''
                    u'''les découpages par nombre d’actes.'''))

    class Meta:
        verbose_name = ungettext_lazy(u'caractéristique d’œuvre',
                                      u'caractéristiques d’œuvre', 1)
        verbose_name_plural = ungettext_lazy(u'caractéristique d’œuvre',
                                             u'caractéristiques d’œuvre', 2)
        ordering = ['type', 'classement']
        app_label = 'catalogue'

    def html(self, tags=True):
        return hlp(self.valeur, self.type, tags)
    html.allow_tags = True

    def __unicode__(self):
        return unicode(self.type) + ' : ' + strip_tags(self.valeur)

    @staticmethod
    def autocomplete_search_fields():
        return 'type__nom__icontains', 'valeur__icontains',


class Partie(CustomModel, SlugModel):
    nom = CharField(max_length=200,
        help_text=_(u'Le nom d’une partie de la partition, '
                    u'instrumentale ou vocale.'))
    nom_pluriel = CharField(_('nom (au pluriel)'), max_length=230, blank=True,
        help_text=PLURAL_MSG)
    professions = ManyToManyField('Profession', related_name='parties',
        help_text=_(u'La ou les profession(s) permettant '
                    u'd’assurer cette partie.'))
    parente = ForeignKey('Partie', related_name='enfant', blank=True,
                         null=True, verbose_name=_('parente'))
    classement = FloatField(default=1.0)

    class Meta:
        verbose_name = ungettext_lazy('partie', 'parties', 1)
        verbose_name_plural = ungettext_lazy('partie', 'parties', 2)
        ordering = ['classement', 'nom']
        app_label = 'catalogue'

    def interpretes(self):
        return get_model('catalogue', 'Individu').objects.filter(
                                 attributions_de_pupitre__pupitre__partie=self)

    def interpretes_html(self):
        return str_list(i.html() for i in self.interpretes())

    def pluriel(self):
        return calc_pluriel(self)

    @permalink
    def get_absolute_url(self):
        return 'partie', (self.slug,)

    @permalink
    def permalien(self):
        return 'partie_pk', (self.pk,)

    def link(self):
        return href(self.get_absolute_url(), self.html())

    def html(self):
        return self.nom

    def __unicode__(self):
        return capfirst(self.nom)

    @staticmethod
    def autocomplete_search_fields():
        return ('nom__icontains', 'nom_pluriel__icontains',
                'professions__nom__icontains',
                'professions__nom_pluriel__icontains',)


class Pupitre(CustomModel):
    partie = ForeignKey('Partie', related_name='pupitres')
    quantite_min = IntegerField(_(u'quantité minimale'), default=1)
    quantite_max = IntegerField(_(u'quantité maximale'), default=1)

    class Meta:
        verbose_name = ungettext_lazy('pupitre', 'pupitres', 1)
        verbose_name_plural = ungettext_lazy('pupitre', 'pupitres', 2)
        ordering = ['partie']
        app_label = 'catalogue'

    def __unicode__(self):
        out = ''
        partie = self.partie
        mi = self.quantite_min
        ma = self.quantite_max
        if ma > 1:
            partie = partie.pluriel()
        else:
            partie = unicode(partie)
        mi_str = apnumber(mi)
        ma_str = apnumber(ma)
        if mi != ma:
            d = {'min': mi_str, 'max': ma_str}
            out += ugettext(u'%(min)s à %(max)s ') % d
        elif mi > 1:
            out += mi_str + ' '
        out += partie
        return out

    @staticmethod
    def autocomplete_search_fields():
        return ('partie__nom__icontains', 'partie__nom_pluriel__icontains',
                'partie__professions__nom__icontains',
                'partie__professions__nom_pluriel__icontains',)


class TypeDeParenteDOeuvres(CustomModel):
    nom = CharField(max_length=100, help_text=LOWER_MSG, unique=True)
    nom_relatif = CharField(max_length=100, help_text=LOWER_MSG, unique=True)
    nom_relatif_pluriel = CharField(max_length=130, blank=True,
        verbose_name=_('nom relatif (au pluriel)'), help_text=PLURAL_MSG)
    classement = FloatField(default=1.0)

    class Meta:
        verbose_name = ungettext_lazy(u'type de parenté d’œuvres',
                                      u'types de parentés d’œuvres', 1)
        verbose_name_plural = ungettext_lazy(u'type de parenté d’œuvres',
                                             u'types de parentés d’œuvres', 2)
        ordering = ['classement']
        app_label = 'catalogue'

    def relatif_pluriel(self):
        return calc_pluriel(self, attr_base='nom_relatif')

    def __unicode__(self):
        return '< %s | %s >' % (self.nom, self.nom_relatif)


class ParenteDOeuvres(CustomModel):
    type = ForeignKey('TypeDeParenteDOeuvres', related_name='parentes')
    mere = ForeignKey('Oeuvre', related_name='parentes_filles',
                      verbose_name=_(u'œuvre mère'))
    fille = ForeignKey('Oeuvre', related_name='parentes_meres',
                       verbose_name=_(u'œuvre fille'))

    class Meta:
        verbose_name = ungettext_lazy(u'parenté d’œuvres',
                                      u'parentés d’œuvres', 1)
        verbose_name_plural = ungettext_lazy(u'parenté d’œuvres',
                                             u'parentés d’œuvres', 2)
        ordering = ['type']
        app_label = 'catalogue'
        unique_together = ('type', 'mere', 'fille',)

    def __unicode__(self):
        return u'%s %s %s' % (self.fille, self.type.nom, self.mere)

    def clean(self):
        try:
            type, mere, fille = self.type, self.mere, self.fille
            if mere == fille:
                raise ValidationError(_(u'Les deux champs de parenté ne '
                                        u'peuvent pas être identiques'))
            if ParenteDOeuvres.objects.filter(mere=fille,
                                              fille=mere).exists():
                raise ValidationError(_(u'Une relation entre ces deux objets '
                                        u'existe déjà dans le sens inverse'))
        except Oeuvre.DoesNotExist:
            pass


class AuteurQuerySet(CustomQuerySet):
    def individus(self):
        return get_model('catalogue', 'Individu').objects.filter(
                                                   auteurs__in=self).distinct()

    def professions(self):
        return get_model('catalogue', 'Profession').objects.filter(
                                                   auteurs__in=self).distinct()

    def oeuvres(self):
        return get_model('catalogue', 'Oeuvre').objects.filter(
                                                   auteurs__in=self).distinct()

    def sources(self):
        return get_model('catalogue', 'Source').objects.filter(
                                                   auteurs__in=self).distinct()

    def html(self, tags=True):
        auteurs = self
        d = defaultdict(list)
        for auteur in auteurs:
            d[auteur.profession].append(auteur.individu)
        return str_list(
            '%s [%s]' % (str_list_w_last(i.html(tags) for i in ins),
                         p.short_html(tags))
                for p, ins in d.iteritems())


class AuteurManager(CustomManager):
    def get_query_set(self):
        return AuteurQuerySet(self.model, using=self._db)

    def individus(self):
        return self.get_query_set().individus()

    def professions(self):
        return self.get_query_set().professions()

    def oeuvres(self):
        return self.get_query_set().oeuvres()

    def sources(self):
        return self.get_query_set().sources()

    def html(self, tags=True):
        return self.get_query_set().html(tags)


class Auteur(CustomModel):
    content_type = ForeignKey(ContentType)
    object_id = PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')
    individu = ForeignKey('Individu', related_name='auteurs',
                          verbose_name=_('individu'))
    profession = ForeignKey('Profession', related_name='auteurs',
                            verbose_name=_('profession'))
    objects = AuteurManager()

    def html(self, tags=True):
        return Auteur.objects.filter(pk=self.pk).html(tags)
    html.short_description = _('rendu HTML')
    html.allow_tags = True

    def clean(self):
        if hasattr(self, 'individu') and hasattr(self, 'profession'):
            self.individu.professions.add(self.profession)

    class Meta:
        verbose_name = ungettext_lazy('auteur', 'auteurs', 1)<commit_msg>Tente de résoudre le rare problème d'enregistrement de source.<commit_after># coding: utf-8

from .functions import ex, hlp, str_list, str_list_w_last, href, cite
from django.db.models import CharField, ManyToManyField, \
                             PositiveIntegerField, FloatField, ForeignKey, \
                             OneToOneField, IntegerField, TextField, \
                             permalink, get_model
from tinymce.models import HTMLField
from django.utils.html import strip_tags
from django.utils.translation import ungettext_lazy, ugettext, \
                                     ugettext_lazy as _
from django.template.defaultfilters import capfirst
from django.contrib.humanize.templatetags.humanize import apnumber
from .common import CustomModel, AutoriteModel, LOWER_MSG, PLURAL_MSG, \
                    calc_pluriel, SlugModel, UniqueSlugModel, CustomManager, \
                    CustomQuerySet
from django.core.exceptions import ValidationError
from collections import defaultdict
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.generic import GenericForeignKey
from django.contrib.contenttypes.generic import GenericRelation


class GenreDOeuvre(CustomModel, SlugModel):
    nom = CharField(max_length=255, help_text=LOWER_MSG, unique=True)
    nom_pluriel = CharField(max_length=430, blank=True,
        verbose_name=_('nom (au pluriel)'),
        help_text=PLURAL_MSG)
    parents = ManyToManyField('GenreDOeuvre', related_name='enfants',
        blank=True, null=True)

    class Meta:
        verbose_name = ungettext_lazy(u'genre d’œuvre', u'genres d’œuvre', 1)
        verbose_name_plural = ungettext_lazy(u'genre d’œuvre',
                                             u'genres d’œuvre', 2)
        ordering = ['slug']
        app_label = 'catalogue'

    def html(self, tags=True, caps=False, pluriel=False):
        nom = self.pluriel() if pluriel else self.nom
        if caps:
            nom = capfirst(nom)
        return hlp(nom, ugettext('genre'), tags)

    def pluriel(self):
        return calc_pluriel(self)

    def __unicode__(self):
        return strip_tags(self.html(False))

    @staticmethod
    def autocomplete_search_fields():
        return 'nom__icontains', 'nom_pluriel__icontains',


class TypeDeCaracteristiqueDOeuvre(CustomModel):
    nom = CharField(max_length=200, help_text=ex(_(u'tonalité')), unique=True)
    nom_pluriel = CharField(max_length=230, blank=True,
        verbose_name=_('nom (au pluriel)'), help_text=PLURAL_MSG)
    classement = FloatField(default=1.0)

    class Meta:
        verbose_name = ungettext_lazy(u'type de caractéristique d’œuvre',
                                      u'types de caracteristique d’œuvre', 1)
        verbose_name_plural = ungettext_lazy(
                u'type de caractéristique d’œuvre',
                u'types de caracteristique d’œuvre',
                2)
        ordering = ['classement']
        app_label = 'catalogue'

    def pluriel(self):
        return calc_pluriel(self)

    def __unicode__(self):
        return self.nom


class CaracteristiqueDOeuvre(CustomModel):
    type = ForeignKey('TypeDeCaracteristiqueDOeuvre',
        related_name='caracteristiques_d_oeuvre')
    # TODO: Changer valeur en nom ?
    valeur = CharField(max_length=400, help_text=ex(_(u'en trois actes')))
    classement = FloatField(default=1.0,
        help_text=_(u'''Par exemple, on peut choisir de classer'''
                    u'''les découpages par nombre d’actes.'''))

    class Meta:
        verbose_name = ungettext_lazy(u'caractéristique d’œuvre',
                                      u'caractéristiques d’œuvre', 1)
        verbose_name_plural = ungettext_lazy(u'caractéristique d’œuvre',
                                             u'caractéristiques d’œuvre', 2)
        ordering = ['type', 'classement']
        app_label = 'catalogue'

    def html(self, tags=True):
        return hlp(self.valeur, self.type, tags)
    html.allow_tags = True

    def __unicode__(self):
        return unicode(self.type) + ' : ' + strip_tags(self.valeur)

    @staticmethod
    def autocomplete_search_fields():
        return 'type__nom__icontains', 'valeur__icontains',


class Partie(CustomModel, SlugModel):
    nom = CharField(max_length=200,
        help_text=_(u'Le nom d’une partie de la partition, '
                    u'instrumentale ou vocale.'))
    nom_pluriel = CharField(_('nom (au pluriel)'), max_length=230, blank=True,
        help_text=PLURAL_MSG)
    professions = ManyToManyField('Profession', related_name='parties',
        help_text=_(u'La ou les profession(s) permettant '
                    u'd’assurer cette partie.'))
    parente = ForeignKey('Partie', related_name='enfant', blank=True,
                         null=True, verbose_name=_('parente'))
    classement = FloatField(default=1.0)

    class Meta:
        verbose_name = ungettext_lazy('partie', 'parties', 1)
        verbose_name_plural = ungettext_lazy('partie', 'parties', 2)
        ordering = ['classement', 'nom']
        app_label = 'catalogue'

    def interpretes(self):
        return get_model('catalogue', 'Individu').objects.filter(
                                 attributions_de_pupitre__pupitre__partie=self)

    def interpretes_html(self):
        return str_list(i.html() for i in self.interpretes())

    def pluriel(self):
        return calc_pluriel(self)

    @permalink
    def get_absolute_url(self):
        return 'partie', (self.slug,)

    @permalink
    def permalien(self):
        return 'partie_pk', (self.pk,)

    def link(self):
        return href(self.get_absolute_url(), self.html())

    def html(self):
        return self.nom

    def __unicode__(self):
        return capfirst(self.nom)

    @staticmethod
    def autocomplete_search_fields():
        return ('nom__icontains', 'nom_pluriel__icontains',
                'professions__nom__icontains',
                'professions__nom_pluriel__icontains',)


class Pupitre(CustomModel):
    partie = ForeignKey('Partie', related_name='pupitres')
    quantite_min = IntegerField(_(u'quantité minimale'), default=1)
    quantite_max = IntegerField(_(u'quantité maximale'), default=1)

    class Meta:
        verbose_name = ungettext_lazy('pupitre', 'pupitres', 1)
        verbose_name_plural = ungettext_lazy('pupitre', 'pupitres', 2)
        ordering = ['partie']
        app_label = 'catalogue'

    def __unicode__(self):
        out = ''
        partie = self.partie
        mi = self.quantite_min
        ma = self.quantite_max
        if ma > 1:
            partie = partie.pluriel()
        else:
            partie = unicode(partie)
        mi_str = apnumber(mi)
        ma_str = apnumber(ma)
        if mi != ma:
            d = {'min': mi_str, 'max': ma_str}
            out += ugettext(u'%(min)s à %(max)s ') % d
        elif mi > 1:
            out += mi_str + ' '
        out += partie
        return out

    @staticmethod
    def autocomplete_search_fields():
        return ('partie__nom__icontains', 'partie__nom_pluriel__icontains',
                'partie__professions__nom__icontains',
                'partie__professions__nom_pluriel__icontains',)


class TypeDeParenteDOeuvres(CustomModel):
    nom = CharField(max_length=100, help_text=LOWER_MSG, unique=True)
    nom_relatif = CharField(max_length=100, help_text=LOWER_MSG, unique=True)
    nom_relatif_pluriel = CharField(max_length=130, blank=True,
        verbose_name=_('nom relatif (au pluriel)'), help_text=PLURAL_MSG)
    classement = FloatField(default=1.0)

    class Meta:
        verbose_name = ungettext_lazy(u'type de parenté d’œuvres',
                                      u'types de parentés d’œuvres', 1)
        verbose_name_plural = ungettext_lazy(u'type de parenté d’œuvres',
                                             u'types de parentés d’œuvres', 2)
        ordering = ['classement']
        app_label = 'catalogue'

    def relatif_pluriel(self):
        return calc_pluriel(self, attr_base='nom_relatif')

    def __unicode__(self):
        return '< %s | %s >' % (self.nom, self.nom_relatif)


class ParenteDOeuvres(CustomModel):
    type = ForeignKey('TypeDeParenteDOeuvres', related_name='parentes')
    mere = ForeignKey('Oeuvre', related_name='parentes_filles',
                      verbose_name=_(u'œuvre mère'))
    fille = ForeignKey('Oeuvre', related_name='parentes_meres',
                       verbose_name=_(u'œuvre fille'))

    class Meta:
        verbose_name = ungettext_lazy(u'parenté d’œuvres',
                                      u'parentés d’œuvres', 1)
        verbose_name_plural = ungettext_lazy(u'parenté d’œuvres',
                                             u'parentés d’œuvres', 2)
        ordering = ['type']
        app_label = 'catalogue'
        unique_together = ('type', 'mere', 'fille',)

    def __unicode__(self):
        return u'%s %s %s' % (self.fille, self.type.nom, self.mere)

    def clean(self):
        try:
            type, mere, fille = self.type, self.mere, self.fille
            if mere == fille:
                raise ValidationError(_(u'Les deux champs de parenté ne '
                                        u'peuvent pas être identiques'))
            if ParenteDOeuvres.objects.filter(mere=fille,
                                              fille=mere).exists():
                raise ValidationError(_(u'Une relation entre ces deux objets '
                                        u'existe déjà dans le sens inverse'))
        except Oeuvre.DoesNotExist:
            pass


class AuteurQuerySet(CustomQuerySet):
    def individus(self):
        return get_model('catalogue', 'Individu').objects.filter(
                                                   auteurs__in=self).distinct()

    def professions(self):
        return get_model('catalogue', 'Profession').objects.filter(
                                                   auteurs__in=self).distinct()

    def oeuvres(self):
        return get_model('catalogue', 'Oeuvre').objects.filter(
                                                   auteurs__in=self).distinct()

    def sources(self):
        return get_model('catalogue', 'Source').objects.filter(
                                                   auteurs__in=self).distinct()

    def html(self, tags=True):
        auteurs = self
        d = defaultdict(list)
        for auteur in auteurs:
            d[auteur.profession].append(auteur.individu)
        return str_list(
            '%s [%s]' % (str_list_w_last(i.html(tags) for i in ins),
                         p.short_html(tags))
                for p, ins in d.iteritems())


class AuteurManager(CustomManager):
    def get_query_set(self):
        return AuteurQuerySet(self.model, using=self._db)

    def individus(self):
        return self.get_query_set().individus()

    def professions(self):
        return self.get_query_set().professions()

    def oeuvres(self):
        return self.get_query_set().oeuvres()

    def sources(self):
        return self.get_query_set().sources()

    def html(self, tags=True):
        return self.get_query_set().html(tags)


class Auteur(CustomModel):
    content_type = ForeignKey(ContentType)
    object_id = PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')
    individu = ForeignKey('Individu', related_name='auteurs',
                          verbose_name=_('individu'))
    profession = ForeignKey('Profession', related_name='auteurs',
                            verbose_name=_('profession'))
    objects = AuteurManager()

    def html(self, tags=True):
        return Auteur.objects.filter(pk=self.pk).html(tags)
    html.short_description = _('rendu HTML')
    html.allow_tags = True

    def clean(self):
        try:
            self.individu.professions.add(self.profession)
        except (get_model('catalogue', 'Individu').DoesNotExist,
                get_model('catalogue', 'Profession').DoesNotExist):
            pass

    class Meta:
        verbose_name = ungettext_lazy('auteur', 'auteurs', 1)
{'fraction_non_alphanumeric': 0.1038442336495257, 'fraction_numerical': 0.0048260941920452655, 'mean_word_length': 2.416773276474769, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 52, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7455879', 'n_tokens_mistral': 7585, 'n_tokens_neox': 7320, 'n_words': 1456}