diff options
| -rw-r--r-- | archaeological_operations/ishtar_menu.py | 222 | ||||
| -rw-r--r-- | archaeological_operations/lookups.py | 55 | ||||
| -rw-r--r-- | archaeological_operations/models.py | 2974 | ||||
| -rw-r--r-- | archaeological_operations/serializers.py | 162 | ||||
| -rw-r--r-- | archaeological_operations/tests.py | 3004 | ||||
| -rw-r--r-- | archaeological_operations/urls.py | 501 | ||||
| -rw-r--r-- | archaeological_operations/utils.py | 241 | ||||
| -rw-r--r-- | archaeological_operations/views.py | 864 | ||||
| -rw-r--r-- | archaeological_operations/widgets.py | 29 | ||||
| -rw-r--r-- | archaeological_operations/wizards.py | 336 | 
10 files changed, 4824 insertions, 3564 deletions
| diff --git a/archaeological_operations/ishtar_menu.py b/archaeological_operations/ishtar_menu.py index 6a5ae1d46..2ad6dc259 100644 --- a/archaeological_operations/ishtar_menu.py +++ b/archaeological_operations/ishtar_menu.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3  # -*- coding: utf-8 -*-  # Copyright (C) 2012-2014 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> @@ -28,102 +28,140 @@ from archaeological_operations import models  MENU_SECTIONS = [ -    (30, SectionItem( -        'operation_management', _("Operation"), -        css='menu-operation', -        childs=[ -            MenuItem( -                'operation_search', _("Search"), -                model=models.Operation, -                access_controls=['view_operation', -                                 'view_own_operation']), -            MenuItem( -                'operation_creation', _("Creation"), -                model=models.Operation, -                access_controls=['add_operation', -                                 'add_own_operation']), -            MenuItem( -                'operation_modification', _("Modification"), -                model=models.Operation, -                access_controls=['change_operation', -                                 'change_own_operation']), -            MenuItem( -                'operation_closing', _("Closing"), -                model=models.Operation, -                access_controls=['close_operation']), -            MenuItem( -                'operation_deletion', _("Deletion"), -                model=models.Operation, -                access_controls=['change_operation', -                                 'change_own_operation']), -            SectionItem( -                'admin_act_operations', -                _("Administrative act"), -                profile_restriction='files', -                childs=[ -                    MenuItem( -                        'operation_administrativeactop_search', -                        _("Search"), -                        model=models.AdministrativeAct, -                        access_controls=[ -                            'change_administrativeact']), -                    MenuItem( -                        'operation_administrativeactop', -                        _("Creation"), -                        model=models.AdministrativeAct, -                        access_controls=['change_administrativeact']), -                    MenuItem( -                        'operation_administrativeactop_modification', -                        _("Modification"), -                        model=models.AdministrativeAct, -                        access_controls=['change_administrativeact']), -                    MenuItem( -                        'operation_administrativeactop_deletion', -                        _("Deletion"), -                        model=models.AdministrativeAct, -                        access_controls=['change_administrativeact']), -                ],), -        ]), -     ),      ( -        35, SectionItem( -            'administrativact_management', _("Administrative Act"), -            profile_restriction='files', -            css='menu-file', +        30, +        SectionItem( +            "operation_management", +            _("Operation"), +            css="menu-operation",              childs=[                  MenuItem( -                    'administrativact_register', -                    pgettext_lazy('admin act register', "Register"), +                    "operation_search", +                    _("Search"), +                    model=models.Operation, +                    access_controls=["view_operation", "view_own_operation"], +                ), +                MenuItem( +                    "operation_creation", +                    _("Creation"), +                    model=models.Operation, +                    access_controls=["add_operation", "add_own_operation"], +                ), +                MenuItem( +                    "operation_modification", +                    _("Modification"), +                    model=models.Operation, +                    access_controls=["change_operation", "change_own_operation"], +                ), +                MenuItem( +                    "operation_closing", +                    _("Closing"), +                    model=models.Operation, +                    access_controls=["close_operation"], +                ), +                MenuItem( +                    "operation_deletion", +                    _("Deletion"), +                    model=models.Operation, +                    access_controls=["change_operation", "change_own_operation"], +                ), +                SectionItem( +                    "admin_act_operations", +                    _("Administrative act"), +                    profile_restriction="files", +                    childs=[ +                        MenuItem( +                            "operation_administrativeactop_search", +                            _("Search"), +                            model=models.AdministrativeAct, +                            access_controls=["change_administrativeact"], +                        ), +                        MenuItem( +                            "operation_administrativeactop", +                            _("Creation"), +                            model=models.AdministrativeAct, +                            access_controls=["change_administrativeact"], +                        ), +                        MenuItem( +                            "operation_administrativeactop_modification", +                            _("Modification"), +                            model=models.AdministrativeAct, +                            access_controls=["change_administrativeact"], +                        ), +                        MenuItem( +                            "operation_administrativeactop_deletion", +                            _("Deletion"), +                            model=models.AdministrativeAct, +                            access_controls=["change_administrativeact"], +                        ), +                    ], +                ), +            ], +        ), +    ), +    ( +        35, +        SectionItem( +            "administrativact_management", +            _("Administrative Act"), +            profile_restriction="files", +            css="menu-file", +            childs=[ +                MenuItem( +                    "administrativact_register", +                    pgettext_lazy("admin act register", "Register"),                      model=models.AdministrativeAct, -                    access_controls=['view_administrativeact', -                                     'view_own_administrativeact']), -            ]) +                    access_controls=[ +                        "view_administrativeact", +                        "view_own_administrativeact", +                    ], +                ), +            ], +        ),      ), -    (37, SectionItem( -        'site_management', IshtarSiteProfile.get_default_site_label, -        css='menu-site', -        profile_restriction='archaeological_site', -        childs=[ -            MenuItem( -                'site_search', _("Search"), -                model=models.ArchaeologicalSite, -                access_controls=['view_archaeologicalsite', -                                 'view_own_archaeologicalsite']), -            MenuItem( -                'site_creation', _("Creation"), -                model=models.ArchaeologicalSite, -                access_controls=['add_archaeologicalsite', -                                 'add_own_archaeologicalsite']), -            MenuItem( -                'site_modification', _("Modification"), -                model=models.ArchaeologicalSite, -                access_controls=['change_archaeologicalsite', -                                 'change_own_archaeologicalsite']), -            MenuItem('site_deletion', -                     _("Deletion"), -                     model=models.ArchaeologicalSite, -                     access_controls=['change_archaeologicalsite']), -        ]), +    ( +        37, +        SectionItem( +            "site_management", +            IshtarSiteProfile.get_default_site_label, +            css="menu-site", +            profile_restriction="archaeological_site", +            childs=[ +                MenuItem( +                    "site_search", +                    _("Search"), +                    model=models.ArchaeologicalSite, +                    access_controls=[ +                        "view_archaeologicalsite", +                        "view_own_archaeologicalsite", +                    ], +                ), +                MenuItem( +                    "site_creation", +                    _("Creation"), +                    model=models.ArchaeologicalSite, +                    access_controls=[ +                        "add_archaeologicalsite", +                        "add_own_archaeologicalsite", +                    ], +                ), +                MenuItem( +                    "site_modification", +                    _("Modification"), +                    model=models.ArchaeologicalSite, +                    access_controls=[ +                        "change_archaeologicalsite", +                        "change_own_archaeologicalsite", +                    ], +                ), +                MenuItem( +                    "site_deletion", +                    _("Deletion"), +                    model=models.ArchaeologicalSite, +                    access_controls=["change_archaeologicalsite"], +                ), +            ], +        ),      ),  ]  """ diff --git a/archaeological_operations/lookups.py b/archaeological_operations/lookups.py index 66bcf0831..0b590374e 100644 --- a/archaeological_operations/lookups.py +++ b/archaeological_operations/lookups.py @@ -6,70 +6,69 @@ from django.db.models import Q  from django.utils.encoding import force_text  from django.utils.html import escape -from archaeological_operations.models import Operation, ArchaeologicalSite, \ -    Parcel, CulturalAttributionType +from archaeological_operations.models import ( +    Operation, +    ArchaeologicalSite, +    Parcel, +    CulturalAttributionType, +) -@register('operation') +@register("operation")  class OperationLookup(LookupChannel):      model = Operation      def get_query(self, q, request):          query = Q() -        for term in q.strip().split(' '): -            subquery = ( -                Q(cached_label__icontains=term) -            ) +        for term in q.strip().split(" "): +            subquery = Q(cached_label__icontains=term)              query &= subquery -        return self.model.objects.filter(query).order_by('cached_label')[:20] +        return self.model.objects.filter(query).order_by("cached_label")[:20]      def format_item_display(self, item):          return "<span class='ajax-label'>%s</span>" % item.cached_label -@register('archaeological_site') +@register("archaeological_site")  class ArchaeologicalSiteLookup(LookupChannel):      model = ArchaeologicalSite      def get_query(self, q, request):          query = Q() -        for term in q.strip().split(' '): -            subquery = ( -                Q(reference__icontains=term) | -                Q(name__icontains=term) -            ) +        for term in q.strip().split(" "): +            subquery = Q(reference__icontains=term) | Q(name__icontains=term)              query &= subquery -        return self.model.objects.filter(query).order_by('reference', -                                                         'name')[:20] +        return self.model.objects.filter(query).order_by("reference", "name")[:20]      def format_item_display(self, item):          return "<span class='ajax-label'>%s</span>".format(item) -@register('parcel') +@register("parcel")  class ParcelLookup(LookupChannel):      model = Parcel      def get_query(self, q, request):          query = Q() -        for term in q.strip().split(' '): +        for term in q.strip().split(" "):              subquery = ( -                Q(associated_file__cached_label__icontains=term) | -                Q(operation__cached_label__icontains=term) | -                Q(section__icontains=term) | -                Q(parcel_number__icontains=term) | -                Q(town__name__icontains=term) +                Q(associated_file__cached_label__icontains=term) +                | Q(operation__cached_label__icontains=term) +                | Q(section__icontains=term) +                | Q(parcel_number__icontains=term) +                | Q(town__name__icontains=term)              )              try:                  subquery |= Q(year=int(term))              except ValueError:                  pass              query &= subquery -        return self.model.objects.filter( -            query).order_by('-associated_file__cached_label', -                            '-operation__cached_label', -                            'section', -                            'parcel_number')[:20] +        return self.model.objects.filter(query).order_by( +            "-associated_file__cached_label", +            "-operation__cached_label", +            "section", +            "parcel_number", +        )[:20]      def format_match(self, obj):          return escape(force_text(obj.long_label())) diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index 653c8d495..128b04496 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -35,27 +35,57 @@ from django.db.models.signals import post_save, m2m_changed, post_delete  from django.forms import ValidationError  from ishtar_common.utils import ugettext_lazy as _, pgettext_lazy -from ishtar_common.models import BaseHistorizedItem, Dashboard, \ -    DashboardFormItem, Document, DocumentTemplate, \ -    GeneralRecordRelations, GeneralRelationType, GeneralType, \ -    IshtarUser, LightHistorizedItem, \ -    OperationType, Organization, OwnPerms, Person, PersonType, \ -    post_delete_record_relation, post_save_cache, RelationItem, \ -    ShortMenuItem, SourceType, Town, ValueGetter, get_current_profile, \ -    document_attached_changed, HistoryModel, SearchAltName, \ -    GeoItem, CompleteIdentifierItem, SearchVectorConfig, DocumentItem, QuickAction, \ -    MainItem, HierarchicalType +from ishtar_common.models import ( +    BaseHistorizedItem, +    Dashboard, +    DashboardFormItem, +    Document, +    DocumentTemplate, +    GeneralRecordRelations, +    GeneralRelationType, +    GeneralType, +    IshtarUser, +    LightHistorizedItem, +    OperationType, +    Organization, +    OwnPerms, +    Person, +    PersonType, +    post_delete_record_relation, +    post_save_cache, +    RelationItem, +    ShortMenuItem, +    SourceType, +    Town, +    ValueGetter, +    get_current_profile, +    document_attached_changed, +    HistoryModel, +    SearchAltName, +    GeoItem, +    CompleteIdentifierItem, +    SearchVectorConfig, +    DocumentItem, +    QuickAction, +    MainItem, +    HierarchicalType, +)  from ishtar_common.models_common import Department, HistoricalRecords  from ishtar_common.model_managers import UUIDModelManager -from ishtar_common.utils import cached_label_changed, \ -    force_cached_label_changed, mode, m2m_historization_changed, post_save_geo +from ishtar_common.utils import ( +    cached_label_changed, +    force_cached_label_changed, +    mode, +    m2m_historization_changed, +    post_save_geo, +)  class RemainType(GeneralType):      class Meta:          verbose_name = _("Remain type")          verbose_name_plural = _("Remain types") -        ordering = ('label',) +        ordering = ("label",)  post_save.connect(post_save_cache, sender=RemainType) @@ -66,14 +96,18 @@ class Period(GeneralType):      order = models.IntegerField(_("Order"))      start_date = models.IntegerField(_("Start date"), null=True, blank=True)      end_date = models.IntegerField(_("End date"), null=True, blank=True) -    parent = models.ForeignKey("Period", verbose_name=_("Parent period"), -                               on_delete=models.SET_NULL, -                               blank=True, null=True) +    parent = models.ForeignKey( +        "Period", +        verbose_name=_("Parent period"), +        on_delete=models.SET_NULL, +        blank=True, +        null=True, +    )      class Meta:          verbose_name = _("Type Period")          verbose_name_plural = _("Types Period") -        ordering = ('order',) +        ordering = ("order",)      def __str__(self):          return self.label @@ -89,7 +123,7 @@ class ReportState(GeneralType):      class Meta:          verbose_name = _("Type of report state")          verbose_name_plural = _("Types of report state") -        ordering = ('order',) +        ordering = ("order",)  post_save.connect(post_save_cache, sender=ReportState) @@ -107,7 +141,7 @@ class RecordQualityType(GeneralType):      class Meta:          verbose_name = _("Type of record quality")          verbose_name_plural = _("Types of record quality") -        ordering = ('order',) +        ordering = ("order",)  class CulturalAttributionType(HierarchicalType): @@ -116,45 +150,58 @@ class CulturalAttributionType(HierarchicalType):      class Meta:          verbose_name = _("Cultural attribution type")          verbose_name_plural = _("Cultural attribution types") -        ordering = ('order',) +        ordering = ("order",)  post_save.connect(post_save_cache, sender=RecordQualityType)  post_delete.connect(post_save_cache, sender=RecordQualityType) -class ArchaeologicalSite(DocumentItem, BaseHistorizedItem, CompleteIdentifierItem, -                         GeoItem, OwnPerms, ValueGetter, MainItem): -    SLUG = 'site' +class ArchaeologicalSite( +    DocumentItem, +    BaseHistorizedItem, +    CompleteIdentifierItem, +    GeoItem, +    OwnPerms, +    ValueGetter, +    MainItem, +): +    SLUG = "site"      APP = "archaeological-operations"      MODEL = "archaeological-site" -    SHOW_URL = 'show-site' -    DELETE_URL = 'delete-site' -    TABLE_COLS = ['reference', 'name', 'cached_towns_label', -                  'cached_periods', 'cached_remains'] +    SHOW_URL = "show-site" +    DELETE_URL = "delete-site" +    TABLE_COLS = [ +        "reference", +        "name", +        "cached_towns_label", +        "cached_periods", +        "cached_remains", +    ]      NEW_QUERY_ENGINE = True      COL_LABELS = { -        'cached_towns_label': _("Towns"), -        'cached_periods': _("Periods"), -        'cached_remains': _("Remains"), +        "cached_towns_label": _("Towns"), +        "cached_periods": _("Periods"), +        "cached_remains": _("Remains"),      } -    LONG_SLUG = 'archaeologicalsite' - -    STATISTIC_MODALITIES_OPTIONS = OrderedDict([ -        ("towns__areas__label", _("Area")), -        ("towns__areas__parent__label", _("Extended area")), -        ("periods__label", _("Periods")), -        ("remains__label", _("Remains")), -        ("documents__source_type__label", _("Associated document type")), -    ]) -    STATISTIC_MODALITIES = [ -        key for key, lbl in STATISTIC_MODALITIES_OPTIONS.items()] +    LONG_SLUG = "archaeologicalsite" + +    STATISTIC_MODALITIES_OPTIONS = OrderedDict( +        [ +            ("towns__areas__label", _("Area")), +            ("towns__areas__parent__label", _("Extended area")), +            ("periods__label", _("Periods")), +            ("remains__label", _("Remains")), +            ("documents__source_type__label", _("Associated document type")), +        ] +    ) +    STATISTIC_MODALITIES = [key for key, lbl in STATISTIC_MODALITIES_OPTIONS.items()]      BASE_SEARCH_VECTORS = [ -        SearchVectorConfig("comment", 'local'), -        SearchVectorConfig("discovery_area", 'local'), -        SearchVectorConfig("locality_cadastral", 'local'), -        SearchVectorConfig("locality_ngi", 'local'), +        SearchVectorConfig("comment", "local"), +        SearchVectorConfig("discovery_area", "local"), +        SearchVectorConfig("locality_cadastral", "local"), +        SearchVectorConfig("locality_ngi", "local"),          SearchVectorConfig("name"),          SearchVectorConfig("oceanographic_service_localisation"),          SearchVectorConfig("reference"), @@ -169,207 +216,222 @@ class ArchaeologicalSite(DocumentItem, BaseHistorizedItem, CompleteIdentifierIte          SearchVectorConfig("remains__label", "local"),          SearchVectorConfig("towns__name"),      ] -    PARENT_SEARCH_VECTORS = ['operations'] +    PARENT_SEARCH_VECTORS = ["operations"] -    DATED_FIELDS = ['sinking_date'] +    DATED_FIELDS = ["sinking_date"]      EXTRA_REQUEST_KEYS = { -        'towns_label': 'towns', -        'collaborators__pk': 'collaborators__pk',  # dynamic_table_documents -        'cached_towns_label': 'cached_towns_label', -        'cached_periods': 'cached_periods', -        'cached_remains': 'remains', +        "towns_label": "towns", +        "collaborators__pk": "collaborators__pk",  # dynamic_table_documents +        "cached_towns_label": "cached_towns_label", +        "cached_periods": "cached_periods", +        "cached_remains": "remains",      }      # alternative names of fields for searches      REVERSED_BOOL_FIELDS = [ -        'documents__image__isnull', -        'documents__associated_file__isnull', -        'documents__associated_url__isnull', +        "documents__image__isnull", +        "documents__associated_file__isnull", +        "documents__associated_url__isnull",      ]      ALT_NAMES = { -        'reference': SearchAltName( -            pgettext_lazy("key for text search", "reference"), -            'reference__iexact' +        "reference": SearchAltName( +            pgettext_lazy("key for text search", "reference"), "reference__iexact"          ), -        'name': SearchAltName( -            pgettext_lazy("key for text search", "name"), -            'name__iexact' +        "name": SearchAltName( +            pgettext_lazy("key for text search", "name"), "name__iexact"          ), -        'other_reference': SearchAltName( +        "other_reference": SearchAltName(              pgettext_lazy("key for text search", "other-reference"), -            'other_reference__iexact' +            "other_reference__iexact",          ), -        'periods': SearchAltName( -            pgettext_lazy("key for text search", "period"), -            'periods__label__iexact' +        "periods": SearchAltName( +            pgettext_lazy("key for text search", "period"), "periods__label__iexact"          ), -        'remains': SearchAltName( -            pgettext_lazy("key for text search", "remain"), -            'remains__label__iexact' +        "remains": SearchAltName( +            pgettext_lazy("key for text search", "remain"), "remains__label__iexact"          ), -        'towns': SearchAltName( -            pgettext_lazy("key for text search", "town"), -            'towns__cached_label__iexact' +        "towns": SearchAltName( +            pgettext_lazy("key for text search", "town"), "towns__cached_label__iexact"          ), -        'towns__areas': SearchAltName( -            pgettext_lazy("key for text search", "area"), -            'towns__areas__label__iexact' +        "towns__areas": SearchAltName( +            pgettext_lazy("key for text search", "area"), "towns__areas__label__iexact"          ), -        'comment': SearchAltName( -            pgettext_lazy("key for text search", "comment"), -            'comment__iexact' +        "comment": SearchAltName( +            pgettext_lazy("key for text search", "comment"), "comment__iexact"          ), -        'locality_ngi': SearchAltName( -            pgettext_lazy("key for text search", "locality-ngi"), -            'locality_ngi__iexact' +        "locality_ngi": SearchAltName( +            pgettext_lazy("key for text search", "locality-ngi"), "locality_ngi__iexact"          ), -        'locality_cadastral': SearchAltName( +        "locality_cadastral": SearchAltName(              pgettext_lazy("key for text search", "locality-cadastral"), -            'locality_cadastral__iexact' +            "locality_cadastral__iexact",          ), -        'shipwreck_name': SearchAltName( +        "shipwreck_name": SearchAltName(              pgettext_lazy("key for text search", "shipwreck-name"), -            'shipwreck_name__iexact' +            "shipwreck_name__iexact",          ), -        'oceanographic_service_localisation': SearchAltName( -            pgettext_lazy("key for text search", -                          "oceanographic-service-localisation"), -            'oceanographic_service_localisation__iexact' +        "oceanographic_service_localisation": SearchAltName( +            pgettext_lazy("key for text search", "oceanographic-service-localisation"), +            "oceanographic_service_localisation__iexact",          ), -        'shipwreck_code': SearchAltName( +        "shipwreck_code": SearchAltName(              pgettext_lazy("key for text search", "shipwreck-code"), -            'shipwreck_code__iexact' +            "shipwreck_code__iexact",          ), -        'sinking_date': SearchAltName( -            pgettext_lazy("key for text search", "sinking-date"), -            'sinking_date' +        "sinking_date": SearchAltName( +            pgettext_lazy("key for text search", "sinking-date"), "sinking_date"          ), -        'discovery_area': SearchAltName( +        "discovery_area": SearchAltName(              pgettext_lazy("key for text search", "discovery-area"), -            'discovery_area__iexact' +            "discovery_area__iexact",          ), -        'operation': SearchAltName( +        "operation": SearchAltName(              pgettext_lazy("key for text search", "operation"), -            'operations__cached_label__icontains' +            "operations__cached_label__icontains",          ), -        'top_operation': SearchAltName( +        "top_operation": SearchAltName(              pgettext_lazy("key for text search", "top-operation"), -            'top_operations__cached_label__icontains' +            "top_operations__cached_label__icontains",          ), -        'drassm_number': SearchAltName( +        "drassm_number": SearchAltName(              pgettext_lazy("key for text search", "numero-drassm"), -            'drassm_number__iexact' +            "drassm_number__iexact",          ), -        'affmar_number': SearchAltName( +        "affmar_number": SearchAltName(              pgettext_lazy("key for text search", "numero-affmar"), -            'affmar_number__iexact' +            "affmar_number__iexact",          ), -        'cultural_attributions': SearchAltName( +        "cultural_attributions": SearchAltName(              pgettext_lazy("key for text search", "cultural-attribution"), -            'cultural_attributions__label__iexact' +            "cultural_attributions__label__iexact",          ),      }      ALT_NAMES.update(BaseHistorizedItem.ALT_NAMES)      ALT_NAMES.update(DocumentItem.ALT_NAMES)      UP_MODEL_QUERY = { -        "operation": (pgettext_lazy("key for text search", "operation"), -                      'cached_label'), +        "operation": ( +            pgettext_lazy("key for text search", "operation"), +            "cached_label", +        ),      }      RELATIVE_SESSION_NAMES = [ -        ('operation', 'operations__pk'), +        ("operation", "operations__pk"), +    ] +    HISTORICAL_M2M = ["periods", "remains", "towns", "cultural_attributions"] +    CACHED_LABELS = [ +        "cached_label", +        "cached_towns_label", +        "cached_periods", +        "cached_remains",      ] -    HISTORICAL_M2M = ['periods', 'remains', 'towns', 'cultural_attributions'] -    CACHED_LABELS = ['cached_label', 'cached_towns_label', 'cached_periods', -                     'cached_remains']      DOWN_MODEL_UPDATE = ["context_records"]      QA_LOCK = QuickAction( -        url="site-qa-lock", icon_class="fa fa-lock", -        text=_("Lock/Unlock"), target="many", -        rights=['change_archaeologicalsite', -                'change_own_archaeologicalsite'] +        url="site-qa-lock", +        icon_class="fa fa-lock", +        text=_("Lock/Unlock"), +        target="many", +        rights=["change_archaeologicalsite", "change_own_archaeologicalsite"],      )      QA_EDIT = QuickAction( -        url="site-qa-bulk-update", icon_class="fa fa-pencil", -        text=_("Bulk update"), target="many", -        rights=['change_archaeologicalsite', -                'change_own_archaeologicalsite'] +        url="site-qa-bulk-update", +        icon_class="fa fa-pencil", +        text=_("Bulk update"), +        target="many", +        rights=["change_archaeologicalsite", "change_own_archaeologicalsite"],      )      QUICK_ACTIONS = [          QA_EDIT,          QA_LOCK,          QuickAction( -            url="site-qa-duplicate", icon_class="fa fa-clone", -            text=_("Duplicate"), target="one", -            rights=['change_archaeologicalsite', -                    'change_own_archaeologicalsite']), +            url="site-qa-duplicate", +            icon_class="fa fa-clone", +            text=_("Duplicate"), +            target="one", +            rights=["change_archaeologicalsite", "change_own_archaeologicalsite"], +        ),      ]      objects = SiteManager()      reference = models.CharField(_("Reference"), max_length=200, unique=True) -    other_reference = models.TextField(_("Other reference"), blank=True, -                                       default="") -    name = models.CharField(_("Name"), max_length=200, -                            null=True, blank=True) -    periods = models.ManyToManyField(Period, verbose_name=_("Periods"), -                                     blank=True) -    remains = models.ManyToManyField("RemainType", verbose_name=_('Remains'), -                                     blank=True) +    other_reference = models.TextField(_("Other reference"), blank=True, default="") +    name = models.CharField(_("Name"), max_length=200, null=True, blank=True) +    periods = models.ManyToManyField(Period, verbose_name=_("Periods"), blank=True) +    remains = models.ManyToManyField( +        "RemainType", verbose_name=_("Remains"), blank=True +    )      cultural_attributions = models.ManyToManyField( -        "CulturalAttributionType", verbose_name=_("Cultural attribution"), -        blank=True) -    towns = models.ManyToManyField(Town, verbose_name=_("Towns"), -                                   related_name='sites', blank=True) +        "CulturalAttributionType", verbose_name=_("Cultural attribution"), blank=True +    ) +    towns = models.ManyToManyField( +        Town, verbose_name=_("Towns"), related_name="sites", blank=True +    )      comment = models.TextField(_("Comment"), blank=True, default="")      locality_ngi = models.TextField( -        _("National Geographic Institute locality"), blank=True, default="") -    locality_cadastral = models.TextField(_("Cadastral locality"), blank=True, -                                          default="") +        _("National Geographic Institute locality"), blank=True, default="" +    ) +    locality_cadastral = models.TextField( +        _("Cadastral locality"), blank=True, default="" +    )      collaborators = models.ManyToManyField( -        Person, blank=True, verbose_name=_("Collaborators"), -        related_name='site_collaborator' +        Person, +        blank=True, +        verbose_name=_("Collaborators"), +        related_name="site_collaborator",      )      # underwater -    shipwreck_name = models.TextField( -        _("Shipwreck name"), blank=True, default="") +    shipwreck_name = models.TextField(_("Shipwreck name"), blank=True, default="")      oceanographic_service_localisation = models.TextField( -        _("Oceanographic service localisation"), blank=True, default="") -    shipwreck_code = models.TextField( -        _("Shipwreck code"), blank=True, default="") -    sinking_date = models.DateField( -        _("Sinking date"), null=True, blank=True) -    discovery_area = models.TextField( -        _("Discovery area"), blank=True, default="") -    affmar_number = models.CharField(_("AffMar number"), max_length=100, -                                     null=True, blank=True) -    drassm_number = models.CharField(_("DRASSM number"), max_length=100, -                                     null=True, blank=True) +        _("Oceanographic service localisation"), blank=True, default="" +    ) +    shipwreck_code = models.TextField(_("Shipwreck code"), blank=True, default="") +    sinking_date = models.DateField(_("Sinking date"), null=True, blank=True) +    discovery_area = models.TextField(_("Discovery area"), blank=True, default="") +    affmar_number = models.CharField( +        _("AffMar number"), max_length=100, null=True, blank=True +    ) +    drassm_number = models.CharField( +        _("DRASSM number"), max_length=100, null=True, blank=True +    )      documents = models.ManyToManyField( -        Document, related_name="sites", verbose_name=_("Documents"), -        blank=True) +        Document, related_name="sites", verbose_name=_("Documents"), blank=True +    )      main_image = models.ForeignKey( -        Document, related_name='main_image_sites', +        Document, +        related_name="main_image_sites",          on_delete=models.SET_NULL, -        verbose_name=_("Main image"), blank=True, null=True) +        verbose_name=_("Main image"), +        blank=True, +        null=True, +    )      cached_label = models.TextField( -        _("Cached name"), blank=True, default="", db_index=True, -        help_text=_("Generated automatically - do not edit") +        _("Cached name"), +        blank=True, +        default="", +        db_index=True, +        help_text=_("Generated automatically - do not edit"),      )      cached_towns_label = models.TextField( -        _("Cached town label"), blank=True, default="", -        help_text=_("Generated automatically - do not edit") +        _("Cached town label"), +        blank=True, +        default="", +        help_text=_("Generated automatically - do not edit"),      ) -    cached_periods =  models.TextField( -        _("Cached periods label"), blank=True, default="", -        help_text=_("Generated automatically - do not edit") +    cached_periods = models.TextField( +        _("Cached periods label"), +        blank=True, +        default="", +        help_text=_("Generated automatically - do not edit"),      ) -    cached_remains =  models.TextField( -        _("Cached remains label"), blank=True, default="", -        help_text=_("Generated automatically - do not edit") +    cached_remains = models.TextField( +        _("Cached remains label"), +        blank=True, +        default="", +        help_text=_("Generated automatically - do not edit"),      )      history = HistoricalRecords(bases=[HistoryModel]) @@ -378,23 +440,18 @@ class ArchaeologicalSite(DocumentItem, BaseHistorizedItem, CompleteIdentifierIte          verbose_name = _("Archaeological site")          verbose_name_plural = _("Archaeological sites")          permissions = ( -            ("view_archaeologicalsite", -             "Can view all Archaeological sites"), -            ("view_own_archaeologicalsite", -             "Can view own Archaeological site"), -            ("add_own_archaeologicalsite", -             "Can add own Archaeological site"), -            ("change_own_archaeologicalsite", -             "Can change own Archaeological site"), -            ("delete_own_archaeologicalsite", -             "Can delete own Archaeological site"), +            ("view_archaeologicalsite", "Can view all Archaeological sites"), +            ("view_own_archaeologicalsite", "Can view own Archaeological site"), +            ("add_own_archaeologicalsite", "Can add own Archaeological site"), +            ("change_own_archaeologicalsite", "Can change own Archaeological site"), +            ("delete_own_archaeologicalsite", "Can delete own Archaeological site"),          )          indexes = [ -            GinIndex(fields=['data']), +            GinIndex(fields=["data"]),          ]      def __str__(self): -        return self.cached_label or '' +        return self.cached_label or ""      @property      def short_class_name(self): @@ -408,15 +465,17 @@ class ArchaeologicalSite(DocumentItem, BaseHistorizedItem, CompleteIdentifierIte      def public_representation(self):          dct = super(ArchaeologicalSite, self).public_representation() -        dct.update({ -            "reference": self.reference, -            "name": self.name, -            "periods": [str(p) for p in self.periods.all()], -            "remains": [str(r) for r in self.remains.all()], -            "towns": [t.label_with_areas for t in self.towns.all()], -            "comment": self.comment, -            "locality": self.locality_ngi or self.locality_cadastral, -        }) +        dct.update( +            { +                "reference": self.reference, +                "name": self.name, +                "periods": [str(p) for p in self.periods.all()], +                "remains": [str(r) for r in self.remains.all()], +                "towns": [t.label_with_areas for t in self.towns.all()], +                "comment": self.comment, +                "locality": self.locality_ngi or self.locality_cadastral, +            } +        )          profile = get_current_profile()          if profile.underwater:              dct["shipwreck-name"] = self.shipwreck_name @@ -427,8 +486,10 @@ class ArchaeologicalSite(DocumentItem, BaseHistorizedItem, CompleteIdentifierIte      @property      def finds(self):          from archaeological_finds.models import Find +          return Find.objects.filter( -            base_finds__context_record__archaeological_site__pk=self.pk) +            base_finds__context_record__archaeological_site__pk=self.pk +        )      def get_extra_actions(self, request):          """ @@ -438,11 +499,17 @@ class ArchaeologicalSite(DocumentItem, BaseHistorizedItem, CompleteIdentifierIte          actions = super(ArchaeologicalSite, self).get_extra_actions(request)          # is_locked = self.is_locked(request.user) -        can_edit_site = self.can_do(request, 'change_archaeologicalsite') +        can_edit_site = self.can_do(request, "change_archaeologicalsite")          if can_edit_site:              actions += [ -                (reverse("site-qa-duplicate", args=[self.pk]), -                 _("Duplicate"), "fa fa-clone", "", "", True), +                ( +                    reverse("site-qa-duplicate", args=[self.pk]), +                    _("Duplicate"), +                    "fa fa-clone", +                    "", +                    "", +                    True, +                ),              ]          return actions @@ -451,13 +518,12 @@ class ArchaeologicalSite(DocumentItem, BaseHistorizedItem, CompleteIdentifierIte          profile = ishtaruser.current_profile          town_ids = []          if profile: -            town_ids = [town['pk'] -                        for town in profile.query_towns.values('pk').all()] +            town_ids = [town["pk"] for town in profile.query_towns.values("pk").all()]          query_owns = [              { -                'collaborators__pk': ishtaruser.person.pk, -                'history_creator': ishtaruser.user_ptr, -                'towns__pk__in': town_ids, +                "collaborators__pk": ishtaruser.person.pk, +                "history_creator": ishtaruser.user_ptr, +                "towns__pk__in": town_ids,              }          ]          return query_owns @@ -465,55 +531,63 @@ class ArchaeologicalSite(DocumentItem, BaseHistorizedItem, CompleteIdentifierIte      @classmethod      def get_query_owns(cls, ishtaruser):          from archaeological_warehouse.models import Warehouse -        q = cls._construct_query_own( -            'operations__context_record__base_finds__find__container__responsible__', -            Warehouse._get_query_owns_dicts(ishtaruser) -        ) | cls._construct_query_own( -            'operations__context_record__base_finds__find__basket__', -            [{"shared_with": ishtaruser, "shared_write_with": ishtaruser}] -        ) | cls._construct_query_own( -            'operations__context_record__base_finds__find__container__location__', -            Warehouse._get_query_owns_dicts(ishtaruser) -        ) | cls._construct_query_own( -            'top_operations__context_record__base_finds__find__container__responsible__', -            Warehouse._get_query_owns_dicts(ishtaruser) -        ) | cls._construct_query_own( -            'top_operations__context_record__base_finds__find__container__location__', -            Warehouse._get_query_owns_dicts(ishtaruser) -        ) | cls._construct_query_own( -            'operations__', Operation._get_query_owns_dicts(ishtaruser, -                                                            no_rel=True) -        ) | cls._construct_query_own( -            'top_operations__', Operation._get_query_owns_dicts(ishtaruser) -        ) | cls._construct_query_own( -            '', cls._get_query_owns_dicts(ishtaruser) + +        q = ( +            cls._construct_query_own( +                "operations__context_record__base_finds__find__container__responsible__", +                Warehouse._get_query_owns_dicts(ishtaruser), +            ) +            | cls._construct_query_own( +                "operations__context_record__base_finds__find__basket__", +                [{"shared_with": ishtaruser, "shared_write_with": ishtaruser}], +            ) +            | cls._construct_query_own( +                "operations__context_record__base_finds__find__container__location__", +                Warehouse._get_query_owns_dicts(ishtaruser), +            ) +            | cls._construct_query_own( +                "top_operations__context_record__base_finds__find__container__responsible__", +                Warehouse._get_query_owns_dicts(ishtaruser), +            ) +            | cls._construct_query_own( +                "top_operations__context_record__base_finds__find__container__location__", +                Warehouse._get_query_owns_dicts(ishtaruser), +            ) +            | cls._construct_query_own( +                "operations__", Operation._get_query_owns_dicts(ishtaruser, no_rel=True) +            ) +            | cls._construct_query_own( +                "top_operations__", Operation._get_query_owns_dicts(ishtaruser) +            ) +            | cls._construct_query_own("", cls._get_query_owns_dicts(ishtaruser))          )          return q      @classmethod -    def get_owns(cls, user, menu_filtr=None, limit=None, values=None, -                 get_short_menu_class=None): +    def get_owns( +        cls, user, menu_filtr=None, limit=None, values=None, get_short_menu_class=None +    ):          replace_query = None -        if menu_filtr and 'operation' in menu_filtr: -            replace_query = Q(operations=menu_filtr['operation']) +        if menu_filtr and "operation" in menu_filtr: +            replace_query = Q(operations=menu_filtr["operation"])          owns = super(ArchaeologicalSite, cls).get_owns( -            user, replace_query=replace_query, -            limit=limit, values=values, -            get_short_menu_class=get_short_menu_class) +            user, +            replace_query=replace_query, +            limit=limit, +            values=values, +            get_short_menu_class=get_short_menu_class, +        )          return cls._return_get_owns(owns, values, get_short_menu_class)      def _generate_cached_label(self):          name = self.reference          if self.name:              name += " %s %s" % (settings.JOINT, self.name) -        keys = [('towns', " - {}"), ('remains', " - {}"), -                ('periods', " [{}]")] +        keys = [("towns", " - {}"), ("remains", " - {}"), ("periods", " [{}]")]          for k, lbl in keys:              if getattr(self, k).count(): -                name += lbl.format(", ".join([ -                    str(v) for v in getattr(self, k).all() -                ])) +                name += lbl.format(", ".join([str(v) for v in getattr(self, k).all()]))          return name      def _generate_cached_towns_label(self): @@ -526,7 +600,7 @@ class ArchaeologicalSite(DocumentItem, BaseHistorizedItem, CompleteIdentifierIte          return " & ".join([str(period) for period in self.periods.all()]) or "-"      def natural_key(self): -        return (self.reference, ) +        return (self.reference,)      @property      def external_id(self): @@ -539,15 +613,17 @@ class ArchaeologicalSite(DocumentItem, BaseHistorizedItem, CompleteIdentifierIte          return " & ".join(self.towns_codes())      def get_town_centroid(self): -        q = self.towns.filter(center__isnull=False).annotate( -                centroid=Centroid(Union('center'))).all() +        q = ( +            self.towns.filter(center__isnull=False) +            .annotate(centroid=Centroid(Union("center"))) +            .all() +        )          if not q.count():              return          return q.all()[0].centroid, self._meta.verbose_name      def get_town_polygons(self): -        q = self.towns.filter(limit__isnull=False).annotate( -            poly=Union('limit')).all() +        q = self.towns.filter(limit__isnull=False).annotate(poly=Union("limit")).all()          if not q.count():              return          return q.all()[0].poly, self._meta.verbose_name @@ -566,39 +642,32 @@ class ArchaeologicalSite(DocumentItem, BaseHistorizedItem, CompleteIdentifierIte              if not create:                  return              operation_type, created = OperationType.objects.get_or_create( -                txt_idx='unknown', -                defaults={'label': _("Unknown"), 'available': True, -                          'order': 999}) -            name = str( -                _("Virtual operation of site: {}") -            ).format(self.reference) +                txt_idx="unknown", +                defaults={"label": _("Unknown"), "available": True, "order": 999}, +            ) +            name = str(_("Virtual operation of site: {}")).format(self.reference)              if self.towns.count(): -                name += ' - ' + ", ".join( -                    [town.name for town in self.towns.all()]) +                name += " - " + ", ".join([town.name for town in self.towns.all()])              operation = Operation.objects.create( -                operation_type=operation_type, -                common_name=name, -                virtual_operation=True +                operation_type=operation_type, common_name=name, virtual_operation=True              )              operation.top_sites.add(self)          top_operation = self.top_operations.all()[0]          current_operations = dict( -            [(ope.pk, ope) -             for ope in self.operations.exclude( -                pk=top_operation.pk -            ).all() -             ] +            [ +                (ope.pk, ope) +                for ope in self.operations.exclude(pk=top_operation.pk).all() +            ]          )          q = RecordRelations.objects.filter( -            left_record=top_operation, -            relation_type__txt_idx='has_got' +            left_record=top_operation, relation_type__txt_idx="has_got"          )          for relation in q.all():              if relation.right_record.pk not in current_operations:                  relation.delete()              else:                  current_operations.pop(relation.right_record.pk) -        rel_type = RelationType.get_cache('has_got') +        rel_type = RelationType.get_cache("has_got")          for missing, value in current_operations.items():              RecordRelations.objects.create(                  left_record=top_operation, @@ -614,45 +683,51 @@ def site_post_save(sender, **kwargs):  post_save.connect(site_post_save, sender=ArchaeologicalSite) -m2m_changed.connect(document_attached_changed, -                    sender=ArchaeologicalSite.documents.through) +m2m_changed.connect( +    document_attached_changed, sender=ArchaeologicalSite.documents.through +)  for attr in ArchaeologicalSite.HISTORICAL_M2M: -    m2m_changed.connect(m2m_historization_changed, -                        sender=getattr(ArchaeologicalSite, attr).through) +    m2m_changed.connect( +        m2m_historization_changed, sender=getattr(ArchaeologicalSite, attr).through +    )  def get_values_town_related(item, prefix, values, filtr=None): -    if not filtr or prefix + 'parcellist' in filtr: -        values[prefix + 'parcellist'] = item.render_parcels() -    if not filtr or prefix + 'towns_count' in filtr: -        values[prefix + 'towns_count'] = str(item.towns.count()) -    get_towns = not filtr or prefix + 'towns' in filtr -    get_dpt = not filtr or prefix + 'departments' in filtr -    get_dpt_nb = not filtr or prefix + 'departments_number' in filtr +    if not filtr or prefix + "parcellist" in filtr: +        values[prefix + "parcellist"] = item.render_parcels() +    if not filtr or prefix + "towns_count" in filtr: +        values[prefix + "towns_count"] = str(item.towns.count()) +    get_towns = not filtr or prefix + "towns" in filtr +    get_dpt = not filtr or prefix + "departments" in filtr +    get_dpt_nb = not filtr or prefix + "departments_number" in filtr      if not get_towns and not get_dpt and not get_dpt_nb:          return values      if get_towns: -        values[prefix + 'towns'] = '' +        values[prefix + "towns"] = ""      if get_dpt: -        values[prefix + 'departments'] = '' +        values[prefix + "departments"] = ""      if get_dpt_nb: -        values[prefix + 'departments_number'] = '' +        values[prefix + "departments_number"] = ""      if item.towns.count():          if get_towns: -            values[prefix + 'towns'] = ", ".join([ -               town.name for town in item.towns.all().order_by('name')]) -        if settings.COUNTRY == 'fr' and (get_dpt_nb or get_dpt_nb): -            dpts_num = set( -                [town.numero_insee[:2] for town in item.towns.all()]) +            values[prefix + "towns"] = ", ".join( +                [town.name for town in item.towns.all().order_by("name")] +            ) +        if settings.COUNTRY == "fr" and (get_dpt_nb or get_dpt_nb): +            dpts_num = set([town.numero_insee[:2] for town in item.towns.all()])              if get_dpt_nb: -                values[prefix + 'departments_number'] = ", ".join( -                    list(sorted(dpts_num))) +                values[prefix + "departments_number"] = ", ".join( +                    list(sorted(dpts_num)) +                )              if get_dpt: -                values[prefix + 'departments'] = ", ".join( -                    [Department.objects.get(number=dpt).label -                     for dpt in sorted(dpts_num) if Department.objects.filter( -                        number=dpt).count()]) +                values[prefix + "departments"] = ", ".join( +                    [ +                        Department.objects.get(number=dpt).label +                        for dpt in sorted(dpts_num) +                        if Department.objects.filter(number=dpt).count() +                    ] +                )      return values @@ -663,8 +738,7 @@ class ClosedItem(object):          in_history = False          date = self.end_date          # last action is closing? -        for idx, item in enumerate( -                self.history.order_by('-history_date').all()): +        for idx, item in enumerate(self.history.order_by("-history_date").all()):              if not idx:                  # last action                  continue @@ -681,123 +755,143 @@ class ClosedItem(object):              q = IshtarUser.objects.filter(pk=self.history_modifier_id)              if q.count():                  user = q.all()[0] -        return {'date': date, 'user': user} +        return {"date": date, "user": user}  class ParcelItem:      def clean_parcel_duplicates(self):          parcels = {} -        for p in self.parcels.order_by('pk').all(): +        for p in self.parcels.order_by("pk").all():              if p.associated_file:                  continue -            key = (p.section, p.parcel_number, p.year, p.town.pk, -                   p.public_domain) +            key = (p.section, p.parcel_number, p.year, p.town.pk, p.public_domain)              if key in parcels:                  parcels[key].merge(p)              else:                  parcels[key] = p -class Operation(ClosedItem, DocumentItem, BaseHistorizedItem, -                CompleteIdentifierItem, GeoItem, OwnPerms, ValueGetter, -                MainItem, DashboardFormItem, RelationItem, ParcelItem): -    SLUG = 'operation' +class Operation( +    ClosedItem, +    DocumentItem, +    BaseHistorizedItem, +    CompleteIdentifierItem, +    GeoItem, +    OwnPerms, +    ValueGetter, +    MainItem, +    DashboardFormItem, +    RelationItem, +    ParcelItem, +): +    SLUG = "operation"      APP = "archaeological-operations"      MODEL = "operation" -    SHOW_URL = 'show-operation' -    DELETE_URL = 'delete-operation' -    TABLE_COLS = ['code_patriarche', 'year', 'cached_towns_label', -                  'common_name', 'operation_type__label', 'start_date', -                  'excavation_end_date', 'cached_remains'] +    SHOW_URL = "show-operation" +    DELETE_URL = "delete-operation" +    TABLE_COLS = [ +        "code_patriarche", +        "year", +        "cached_towns_label", +        "common_name", +        "operation_type__label", +        "start_date", +        "excavation_end_date", +        "cached_remains", +    ]      NEW_QUERY_ENGINE = True      # statistics -    STATISTIC_MODALITIES_OPTIONS = OrderedDict([ -        ("operation_type__label",  _("Operation type")), -        ('year', _("Year")), -        ("towns__areas__label", _("Area")), -        ("towns__areas__parent__label", _("Extended area")), -        ("remains__label", _("Remains")), -        ("periods__label", _("Periods")), -        ("record_quality_type__label", _("Record quality")), -        ("documentation_received", _("Documentation received")), -        ("finds_received", _("Finds received")), -        ("documents__source_type__label", _("Associated document type")), -    ]) -    STATISTIC_MODALITIES = [ -        key for key, lbl in STATISTIC_MODALITIES_OPTIONS.items()] +    STATISTIC_MODALITIES_OPTIONS = OrderedDict( +        [ +            ("operation_type__label", _("Operation type")), +            ("year", _("Year")), +            ("towns__areas__label", _("Area")), +            ("towns__areas__parent__label", _("Extended area")), +            ("remains__label", _("Remains")), +            ("periods__label", _("Periods")), +            ("record_quality_type__label", _("Record quality")), +            ("documentation_received", _("Documentation received")), +            ("finds_received", _("Finds received")), +            ("documents__source_type__label", _("Associated document type")), +        ] +    ) +    STATISTIC_MODALITIES = [key for key, lbl in STATISTIC_MODALITIES_OPTIONS.items()]      # search parameters -    BOOL_FIELDS = ['end_date__isnull', 'virtual_operation', -                   'documentation_received', 'finds_received'] -    MANY_COUNTED_FIELDS = ['context_record__base_finds'] +    BOOL_FIELDS = [ +        "end_date__isnull", +        "virtual_operation", +        "documentation_received", +        "finds_received", +    ] +    MANY_COUNTED_FIELDS = ["context_record__base_finds"]      REVERSED_BOOL_FIELDS = [ -        'documents__image__isnull', -        'documents__associated_file__isnull', -        'documents__associated_url__isnull', +        "documents__image__isnull", +        "documents__associated_file__isnull", +        "documents__associated_url__isnull",      ]      DATED_FIELDS = [ -        'start_date__lte', 'start_date__gte', 'excavation_end_date__lte', -        'excavation_end_date__gte', 'documentation_deadline__lte', -        'documentation_deadline__gte', 'finds_deadline__lte', -        'finds_deadline__gte'] +        "start_date__lte", +        "start_date__gte", +        "excavation_end_date__lte", +        "excavation_end_date__gte", +        "documentation_deadline__lte", +        "documentation_deadline__gte", +        "finds_deadline__lte", +        "finds_deadline__gte", +    ]      EXTRA_REQUEST_KEYS = { -        'operation_type__label': 'operation_type__label', -        'common_name': 'common_name__icontains', -        'cached_label': 'cached_label__icontains', -        'comment': 'comment__icontains', -        'scientific_documentation_comment': -        'scientific_documentation_comment__icontains', -        'abstract': 'abstract__icontains', -        'end_date': 'end_date__isnull', -        'start_before': 'start_date__lte', -        'start_after': 'start_date__gte', -        'end_before': 'excavation_end_date__lte', -        'end_after': 'excavation_end_date__gte', -        'towns__numero_insee__startswith': -        'towns__numero_insee__startswith', -        'parcel': 'parcels__cached_label__iexact', -        'history_creator': -        'history_creator__ishtaruser__person__pk', -        'history_modifier': -        'history_modifier__ishtaruser__person__pk', -        'documentation_deadline_before': 'documentation_deadline__lte', -        'documentation_deadline_after': 'documentation_deadline__gte', -        'finds_deadline_before': 'finds_deadline__lte', -        'finds_deadline_after': 'finds_deadline__gte', -        'related_treatment': -        'context_record__base_finds__find__upstream_treatment__id', -        'towns_label': 'towns', -        'scientist__pk': 'scientist__pk',  # dynamic_table_documents -        'in_charge__pk': 'in_charge__pk',  # dynamic_table_documents -        'collaborators__pk': 'collaborators__pk',  # dynamic_table_documents -        'cira_rapporteur__pk': 'cira_rapporteur__pk'  # dynamic_table_documents +        "operation_type__label": "operation_type__label", +        "common_name": "common_name__icontains", +        "cached_label": "cached_label__icontains", +        "comment": "comment__icontains", +        "scientific_documentation_comment": "scientific_documentation_comment__icontains", +        "abstract": "abstract__icontains", +        "end_date": "end_date__isnull", +        "start_before": "start_date__lte", +        "start_after": "start_date__gte", +        "end_before": "excavation_end_date__lte", +        "end_after": "excavation_end_date__gte", +        "towns__numero_insee__startswith": "towns__numero_insee__startswith", +        "parcel": "parcels__cached_label__iexact", +        "history_creator": "history_creator__ishtaruser__person__pk", +        "history_modifier": "history_modifier__ishtaruser__person__pk", +        "documentation_deadline_before": "documentation_deadline__lte", +        "documentation_deadline_after": "documentation_deadline__gte", +        "finds_deadline_before": "finds_deadline__lte", +        "finds_deadline_after": "finds_deadline__gte", +        "related_treatment": "context_record__base_finds__find__upstream_treatment__id", +        "towns_label": "towns", +        "scientist__pk": "scientist__pk",  # dynamic_table_documents +        "in_charge__pk": "in_charge__pk",  # dynamic_table_documents +        "collaborators__pk": "collaborators__pk",  # dynamic_table_documents +        "cira_rapporteur__pk": "cira_rapporteur__pk",  # dynamic_table_documents      }      COL_LABELS = { -        'code_patriarche': "Code patriarche", -        'associated_file_short_label': _("Associated file (label)"), -        'operator__name': _("Operator name"), -        'scientist__raw_name': _("Scientist (full name)"), -        'associated_file__external_id': _("Associated file (external ID)"), -        'scientist__title': _("Scientist (title)"), -        'scientist__surname': _("Scientist (surname)"), -        'scientist__name': _("Scientist (name)"), -        'scientist__attached_to__name': _("Scientist - Organization (name)"), -        'in_charge__title': _("In charge (title)"), -        'in_charge__surname': _("In charge (surname)"), -        'in_charge__name': _("In charge (name)"), -        'in_charge__attached_to__name': _("In charge - Organization (name)"), -        'cira_rapporteur__surname': "Rapporteur CTRA/CIRA (prénom)", -        'cira_rapporteur__name': "Rapporteur CTRA/CIRA (nom)", -        'cira_rapporteur__attached_to__name': "Rapporteur CTRA/CIRA - " -                                              "Organisation (nom)", -        'archaeological_sites__reference': -        _("Archaeological sites (reference)"), -        'towns_label': _("Towns"), -        'operation_type__label': _("Operation type"), -        'cached_towns_label': _("Towns"), -        'cached_periods': _("Periods"), -        'cached_remains': _("Remains"), +        "code_patriarche": "Code patriarche", +        "associated_file_short_label": _("Associated file (label)"), +        "operator__name": _("Operator name"), +        "scientist__raw_name": _("Scientist (full name)"), +        "associated_file__external_id": _("Associated file (external ID)"), +        "scientist__title": _("Scientist (title)"), +        "scientist__surname": _("Scientist (surname)"), +        "scientist__name": _("Scientist (name)"), +        "scientist__attached_to__name": _("Scientist - Organization (name)"), +        "in_charge__title": _("In charge (title)"), +        "in_charge__surname": _("In charge (surname)"), +        "in_charge__name": _("In charge (name)"), +        "in_charge__attached_to__name": _("In charge - Organization (name)"), +        "cira_rapporteur__surname": "Rapporteur CTRA/CIRA (prénom)", +        "cira_rapporteur__name": "Rapporteur CTRA/CIRA (nom)", +        "cira_rapporteur__attached_to__name": "Rapporteur CTRA/CIRA - " +        "Organisation (nom)", +        "archaeological_sites__reference": _("Archaeological sites (reference)"), +        "towns_label": _("Towns"), +        "operation_type__label": _("Operation type"), +        "cached_towns_label": _("Towns"), +        "cached_periods": _("Periods"), +        "cached_remains": _("Remains"),      }      BASE_SEARCH_VECTORS = [          SearchVectorConfig("abstract", "local"), @@ -834,368 +928,427 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,      PARENT_SEARCH_VECTORS = ["associated_file"]      PARENT_ONLY_SEARCH_VECTORS = ["archaeological_sites"]      ASSOCIATED = { -        "scientist": { -            ('person_types', PersonType): ( -                'head_scientist', -                'sra_agent' -            ) -        }, +        "scientist": {("person_types", PersonType): ("head_scientist", "sra_agent")},      } -    CACHED_LABELS = ['cached_label', 'cached_towns_label', 'cached_periods', -                     'cached_remains'] +    CACHED_LABELS = [ +        "cached_label", +        "cached_towns_label", +        "cached_periods", +        "cached_remains", +    ]      objects = UUIDModelManager()      # alternative names of fields for searches      ALT_NAMES = { -        'year': SearchAltName( -            pgettext_lazy("key for text search", "year"), -            'year' +        "year": SearchAltName(pgettext_lazy("key for text search", "year"), "year"), +        "operation_code": SearchAltName( +            pgettext_lazy("key for text search", "operation-code"), "operation_code"          ), -        'operation_code': SearchAltName( -            pgettext_lazy("key for text search", "operation-code"), -            'operation_code' -        ), -        'code_patriarche': SearchAltName( +        "code_patriarche": SearchAltName(              pgettext_lazy("key for text search", "patriarche"), -            'code_patriarche__iexact' +            "code_patriarche__iexact",          ), -        'towns': SearchAltName( -            pgettext_lazy("key for text search", "town"), -            'towns__cached_label__iexact' +        "towns": SearchAltName( +            pgettext_lazy("key for text search", "town"), "towns__cached_label__iexact"          ), -        'towns__areas': SearchAltName( -            pgettext_lazy("key for text search", "area"), -            'towns__areas__label__iexact' +        "towns__areas": SearchAltName( +            pgettext_lazy("key for text search", "area"), "towns__areas__label__iexact"          ), -        'parcel': SearchAltName( +        "parcel": SearchAltName(              pgettext_lazy("key for text search", "parcel"), -            'parcels__cached_label__iexact' +            "parcels__cached_label__iexact",          ), -        'towns__numero_insee__startswith': SearchAltName( +        "towns__numero_insee__startswith": SearchAltName(              pgettext_lazy("key for text search", "department"), -            'towns__numero_insee__startswith' +            "towns__numero_insee__startswith",          ), -        'common_name': SearchAltName( -            pgettext_lazy("key for text search", "name"), -            'common_name__iexact' +        "common_name": SearchAltName( +            pgettext_lazy("key for text search", "name"), "common_name__iexact"          ), -        'address': SearchAltName( -            pgettext_lazy("key for text search", "address"), -            'address__iexact' +        "address": SearchAltName( +            pgettext_lazy("key for text search", "address"), "address__iexact"          ), -        'operation_type': SearchAltName( +        "operation_type": SearchAltName(              pgettext_lazy("key for text search", "type"), -            'operation_type__label__iexact' +            "operation_type__label__iexact",          ), -        'end_date': SearchAltName( -            pgettext_lazy("key for text search", "is-open"), -            'end_date__isnull' +        "end_date": SearchAltName( +            pgettext_lazy("key for text search", "is-open"), "end_date__isnull"          ), -        'in_charge': SearchAltName( +        "in_charge": SearchAltName(              pgettext_lazy("key for text search", "in-charge"), -            'in_charge__cached_label__iexact' +            "in_charge__cached_label__iexact",          ), -        'scientist': SearchAltName( +        "scientist": SearchAltName(              pgettext_lazy("key for text search", "scientist"), -            'scientist__cached_label__iexact' +            "scientist__cached_label__iexact",          ), -        'operator': SearchAltName( +        "operator": SearchAltName(              pgettext_lazy("key for text search", "operator"), -            'operator__cached_label__iexact' +            "operator__cached_label__iexact",          ), -        'remains': SearchAltName( -            pgettext_lazy("key for text search", "remain"), -            'remains__label__iexact' +        "remains": SearchAltName( +            pgettext_lazy("key for text search", "remain"), "remains__label__iexact"          ), -        'periods': SearchAltName( -            pgettext_lazy("key for text search", "period"), -            'periods__label__iexact' +        "periods": SearchAltName( +            pgettext_lazy("key for text search", "period"), "periods__label__iexact"          ), -        'start_before': SearchAltName( -            pgettext_lazy("key for text search", "start-before"), -            'start_date__lte' +        "start_before": SearchAltName( +            pgettext_lazy("key for text search", "start-before"), "start_date__lte"          ), -        'start_after': SearchAltName( -            pgettext_lazy("key for text search", "start-after"), -            'start_date__gte' +        "start_after": SearchAltName( +            pgettext_lazy("key for text search", "start-after"), "start_date__gte"          ), -        'end_before': SearchAltName( +        "end_before": SearchAltName(              pgettext_lazy("key for text search", "end-before"), -            'excavation_end_date__lte' +            "excavation_end_date__lte",          ), -        'end_after': SearchAltName( +        "end_after": SearchAltName(              pgettext_lazy("key for text search", "end-after"), -            'excavation_end_date__gte' +            "excavation_end_date__gte",          ), -        'relation_types': SearchAltName( -            pgettext_lazy("key for text search", "relation-types"), -            'relation_types' +        "relation_types": SearchAltName( +            pgettext_lazy("key for text search", "relation-types"), "relation_types"          ), -        'comment': SearchAltName( -            pgettext_lazy("key for text search", "comment"), -            'comment__iexact' +        "comment": SearchAltName( +            pgettext_lazy("key for text search", "comment"), "comment__iexact"          ), -        'abstract': SearchAltName( -            pgettext_lazy("key for text search", "abstract"), -            'abstract__iexact' +        "abstract": SearchAltName( +            pgettext_lazy("key for text search", "abstract"), "abstract__iexact"          ), -        'scientific_documentation_comment': SearchAltName( -            pgettext_lazy("key for text search", -                          "scientific-documentation-comment"), -            'scientific_documentation_comment__iexact' +        "scientific_documentation_comment": SearchAltName( +            pgettext_lazy("key for text search", "scientific-documentation-comment"), +            "scientific_documentation_comment__iexact",          ), -        'record_quality_type': SearchAltName( +        "record_quality_type": SearchAltName(              pgettext_lazy("key for text search", "record-quality"), -            'record_quality_type__label__iexact' +            "record_quality_type__label__iexact",          ), -        'report_processing': SearchAltName( -            pgettext_lazy("key for text search", -                          "report-processing"), -            'report_processing__label__iexact' +        "report_processing": SearchAltName( +            pgettext_lazy("key for text search", "report-processing"), +            "report_processing__label__iexact",          ), -        'virtual_operation': SearchAltName( -            pgettext_lazy("key for text search", -                          "virtual-operation"), -            'virtual_operation' +        "virtual_operation": SearchAltName( +            pgettext_lazy("key for text search", "virtual-operation"), +            "virtual_operation",          ), -        'archaeological_sites': SearchAltName( -            pgettext_lazy("key for text search", -                          "site"), -            'archaeological_sites__cached_label__icontains' +        "archaeological_sites": SearchAltName( +            pgettext_lazy("key for text search", "site"), +            "archaeological_sites__cached_label__icontains",          ), -        'documentation_received': SearchAltName( +        "documentation_received": SearchAltName(              pgettext_lazy("key for text search", "documentation-received"), -            'documentation_received' +            "documentation_received",          ), -        'documentation_deadline_before': SearchAltName( +        "documentation_deadline_before": SearchAltName(              pgettext_lazy("key for text search", "documentation-deadline-before"), -            'documentation_deadline__lte' +            "documentation_deadline__lte",          ), -        'documentation_deadline_after': SearchAltName( +        "documentation_deadline_after": SearchAltName(              pgettext_lazy("key for text search", "documentation-deadline-after"), -            'documentation_deadline__gte' +            "documentation_deadline__gte",          ), -        'finds_received': SearchAltName( -            pgettext_lazy("key for text search", "finds-received"), -            'finds_received' +        "finds_received": SearchAltName( +            pgettext_lazy("key for text search", "finds-received"), "finds_received"          ), -        'has_finds': SearchAltName( +        "has_finds": SearchAltName(              pgettext_lazy("key for text search", "has-finds"), -            'context_record__base_finds' +            "context_record__base_finds",          ), -        'finds_deadline_before': SearchAltName( +        "finds_deadline_before": SearchAltName(              pgettext_lazy("key for text search", "finds-deadline-before"), -            'finds_deadline__lte' +            "finds_deadline__lte",          ), -        'finds_deadline_after': SearchAltName( +        "finds_deadline_after": SearchAltName(              pgettext_lazy("key for text search", "finds-deadline-after"), -            'finds_deadline__gte' +            "finds_deadline__gte",          ), -        'drassm_code': SearchAltName( -            pgettext_lazy("key for text search", "code-drassm"), -            'drassm_code__iexact' +        "drassm_code": SearchAltName( +            pgettext_lazy("key for text search", "code-drassm"), "drassm_code__iexact"          ),      }      ALT_NAMES.update(BaseHistorizedItem.ALT_NAMES)      ALT_NAMES.update(DocumentItem.ALT_NAMES)      QA_EDIT = QuickAction( -        url="operation-qa-bulk-update", icon_class="fa fa-pencil", -        text=_("Bulk update"), target="many", -        rights=['change_operation', 'change_own_operation'] +        url="operation-qa-bulk-update", +        icon_class="fa fa-pencil", +        text=_("Bulk update"), +        target="many", +        rights=["change_operation", "change_own_operation"],      )      QA_LOCK = QuickAction( -        url="operation-qa-lock", icon_class="fa fa-lock", -        text=_("Lock/Unlock"), target="many", -        rights=['change_operation', 'change_own_operation'] +        url="operation-qa-lock", +        icon_class="fa fa-lock", +        text=_("Lock/Unlock"), +        target="many", +        rights=["change_operation", "change_own_operation"],      )      QUICK_ACTIONS = [ -        QA_EDIT, QA_LOCK, +        QA_EDIT, +        QA_LOCK,          QuickAction( -            url="operation-qa-duplicate", icon_class="fa fa-clone", -            text=_("Duplicate"), target="one", -            rights=['change_operation', 'change_own_operation']), +            url="operation-qa-duplicate", +            icon_class="fa fa-clone", +            text=_("Duplicate"), +            target="one", +            rights=["change_operation", "change_own_operation"], +        ),      ]      UP_MODEL_QUERY = { -        "site": (pgettext_lazy("key for text search", "site"), -                 'cached_label'), -        "file": (pgettext_lazy("key for text search", "file"), -                 'cached_label'), +        "site": (pgettext_lazy("key for text search", "site"), "cached_label"), +        "file": (pgettext_lazy("key for text search", "file"), "cached_label"),      }      RELATIVE_SESSION_NAMES = [ -        ('file', 'associated_file__pk'), -        ('site', 'archaeological_sites__pk'), +        ("file", "associated_file__pk"), +        ("site", "archaeological_sites__pk"),      ]      POST_PROCESS_REQUEST = { -        'towns__numero_insee__startswith': '_get_department_code', +        "towns__numero_insee__startswith": "_get_department_code",      }      DOWN_MODEL_UPDATE = ["context_record"]      HISTORICAL_M2M = [ -        'remains', 'towns', 'periods', +        "remains", +        "towns", +        "periods",      ]      # fields definition      uuid = models.UUIDField(default=uuid.uuid4) -    creation_date = models.DateField(_("Creation date"), -                                     default=datetime.date.today) +    creation_date = models.DateField(_("Creation date"), default=datetime.date.today)      end_date = models.DateField(_("Closing date"), null=True, blank=True)      start_date = models.DateField(_("Start date"), null=True, blank=True)      excavation_end_date = models.DateField( -        _("Excavation end date"), null=True, blank=True) -    report_delivery_date = models.DateField(_("Report delivery date"), -                                            null=True, blank=True) +        _("Excavation end date"), null=True, blank=True +    ) +    report_delivery_date = models.DateField( +        _("Report delivery date"), null=True, blank=True +    )      scientist = models.ForeignKey( -        Person, blank=True, null=True, verbose_name=_("In charge scientist"), +        Person, +        blank=True, +        null=True, +        verbose_name=_("In charge scientist"),          on_delete=models.SET_NULL, -        related_name='operation_scientist_responsability') +        related_name="operation_scientist_responsability", +    )      operator = models.ForeignKey( -        Organization, blank=True, null=True, related_name='operator', -        verbose_name=_("Operator"), on_delete=models.SET_NULL) -    in_charge = models.ForeignKey(Person, blank=True, null=True, -                                  verbose_name=_("In charge"), -                                  on_delete=models.SET_NULL, -                                  related_name='operation_responsability') +        Organization, +        blank=True, +        null=True, +        related_name="operator", +        verbose_name=_("Operator"), +        on_delete=models.SET_NULL, +    ) +    in_charge = models.ForeignKey( +        Person, +        blank=True, +        null=True, +        verbose_name=_("In charge"), +        on_delete=models.SET_NULL, +        related_name="operation_responsability", +    )      collaborators = models.ManyToManyField( -        Person, blank=True, verbose_name=_("Collaborators"), -        related_name='operation_collaborator' +        Person, +        blank=True, +        verbose_name=_("Collaborators"), +        related_name="operation_collaborator",      )      year = models.IntegerField(_("Year"), null=True, blank=True) -    operation_code = models.IntegerField(_("Numeric reference"), null=True, -                                         blank=True) +    operation_code = models.IntegerField(_("Numeric reference"), null=True, blank=True)      associated_file = models.ForeignKey( -        'archaeological_files.File', -        related_name='operations', verbose_name=_("File"), +        "archaeological_files.File", +        related_name="operations", +        verbose_name=_("File"),          on_delete=models.SET_NULL, -        blank=True, null=True) -    operation_type = models.ForeignKey(OperationType, related_name='+', -                                       verbose_name=_("Operation type")) +        blank=True, +        null=True, +    ) +    operation_type = models.ForeignKey( +        OperationType, related_name="+", verbose_name=_("Operation type") +    )      surface = models.IntegerField(_("Surface (m2)"), blank=True, null=True) -    remains = models.ManyToManyField("RemainType", verbose_name=_('Remains'), -                                     blank=True) -    towns = models.ManyToManyField(Town, verbose_name=_("Towns"), -                                   related_name='operations') -    cost = models.IntegerField(_("Cost (euros)"), -                               blank=True, null=True)  # preventive -    periods = models.ManyToManyField(Period, verbose_name=_("Periods"), -                                     blank=True) +    remains = models.ManyToManyField( +        "RemainType", verbose_name=_("Remains"), blank=True +    ) +    towns = models.ManyToManyField( +        Town, verbose_name=_("Towns"), related_name="operations" +    ) +    cost = models.IntegerField(_("Cost (euros)"), blank=True, null=True)  # preventive +    periods = models.ManyToManyField(Period, verbose_name=_("Periods"), blank=True)      # preventive -    scheduled_man_days = models.IntegerField(_("Scheduled man-days"), -                                             blank=True, null=True) +    scheduled_man_days = models.IntegerField( +        _("Scheduled man-days"), blank=True, null=True +    )      # preventive -    optional_man_days = models.IntegerField(_("Optional man-days"), -                                            blank=True, null=True) +    optional_man_days = models.IntegerField( +        _("Optional man-days"), blank=True, null=True +    )      # preventive -    effective_man_days = models.IntegerField(_("Effective man-days"), -                                             blank=True, null=True) +    effective_man_days = models.IntegerField( +        _("Effective man-days"), blank=True, null=True +    )      report_processing = models.ForeignKey( -        ReportState, verbose_name=_("Report processing"), +        ReportState, +        verbose_name=_("Report processing"),          on_delete=models.SET_NULL, -        blank=True, null=True) -    old_code = models.CharField(_("Old code"), max_length=200, null=True, -                                blank=True) +        blank=True, +        null=True, +    ) +    old_code = models.CharField(_("Old code"), max_length=200, null=True, blank=True)      ## fr      code_patriarche = models.TextField( -        "Code PATRIARCHE", blank=True, default="", unique=True) +        "Code PATRIARCHE", blank=True, default="", unique=True +    )      # preventive -    fnap_financing = models.FloatField("Financement FNAP (%)", -                                       blank=True, null=True) +    fnap_financing = models.FloatField("Financement FNAP (%)", blank=True, null=True)      # preventive -    fnap_cost = models.IntegerField("Financement FNAP (€)", -                                    blank=True, null=True) +    fnap_cost = models.IntegerField("Financement FNAP (€)", blank=True, null=True)      # preventive diag      zoning_prescription = models.NullBooleanField( -        _("Prescription on zoning"), blank=True, null=True) +        _("Prescription on zoning"), blank=True, null=True +    )      # preventive diag      large_area_prescription = models.NullBooleanField( -        _("Prescription on large area"), blank=True, null=True) +        _("Prescription on large area"), blank=True, null=True +    )      geoarchaeological_context_prescription = models.NullBooleanField( -        _("Prescription on geoarchaeological context"), blank=True, -        null=True)  # preventive diag +        _("Prescription on geoarchaeological context"), blank=True, null=True +    )  # preventive diag      cira_rapporteur = models.ForeignKey( -        Person, related_name='cira_rapporteur', null=True, blank=True, -        on_delete=models.SET_NULL, verbose_name="Rapporteur CTRA/CIRA") +        Person, +        related_name="cira_rapporteur", +        null=True, +        blank=True, +        on_delete=models.SET_NULL, +        verbose_name="Rapporteur CTRA/CIRA", +    )      negative_result = models.NullBooleanField( -        "Résultat considéré comme négatif", blank=True, null=True) +        "Résultat considéré comme négatif", blank=True, null=True +    )      cira_date = models.DateField("Date avis CTRA/CIRA", null=True, blank=True) -    eas_number = models.CharField("Numéro de l'EA", max_length=20, -                                  null=True, blank=True) +    eas_number = models.CharField( +        "Numéro de l'EA", max_length=20, null=True, blank=True +    )      ## end fr      operator_reference = models.CharField( -        _("Operator reference"), max_length=20, null=True, blank=True) +        _("Operator reference"), max_length=20, null=True, blank=True +    )      common_name = models.TextField(_("Generic name"), blank=True, default="")      address = models.TextField(_("Address / Locality"), blank=True, default="")      comment = models.TextField(_("Comment"), blank=True, default="")      scientific_documentation_comment = models.TextField( -        _("Comment about scientific documentation"), blank=True, default="") +        _("Comment about scientific documentation"), blank=True, default="" +    )      documents = models.ManyToManyField( -        Document, related_name='operations', verbose_name=_("Documents"), -        blank=True) +        Document, related_name="operations", verbose_name=_("Documents"), blank=True +    )      main_image = models.ForeignKey( -        Document, related_name='main_image_operations', +        Document, +        related_name="main_image_operations",          on_delete=models.SET_NULL, -        verbose_name=_("Main image"), blank=True, null=True) +        verbose_name=_("Main image"), +        blank=True, +        null=True, +    )      cached_label = models.CharField( -        _("Cached name"), max_length=500, -        help_text=_( "Generated automatically - do not edit"), -        null=True, blank=True, db_index=True) +        _("Cached name"), +        max_length=500, +        help_text=_("Generated automatically - do not edit"), +        null=True, +        blank=True, +        db_index=True, +    )      archaeological_sites = models.ManyToManyField( -        ArchaeologicalSite, verbose_name=_("Archaeological sites"), -        blank=True, related_name='operations') +        ArchaeologicalSite, +        verbose_name=_("Archaeological sites"), +        blank=True, +        related_name="operations", +    )      top_sites = models.ManyToManyField(          ArchaeologicalSite,          verbose_name=_("Sites for which this operation is top operation"), -        related_name="top_operations", blank=True) +        related_name="top_operations", +        blank=True, +    )      virtual_operation = models.BooleanField(          _("Virtual operation"), -        default=False, help_text=_( +        default=False, +        help_text=_(              "If checked, it means that this operation have not been " -            "officialy registered.")) +            "officialy registered." +        ), +    )      record_quality_type = models.ForeignKey( -        RecordQualityType, verbose_name=_("Record quality"), +        RecordQualityType, +        verbose_name=_("Record quality"),          on_delete=models.SET_NULL, -        null=True, blank=True,) +        null=True, +        blank=True, +    )      abstract = models.TextField(_("Abstract"), blank=True, default="")      documentation_deadline = models.DateField( -        _("Deadline for submission of the documentation"), blank=True, -        null=True) +        _("Deadline for submission of the documentation"), blank=True, null=True +    )      documentation_received = models.NullBooleanField( -        _("Documentation received"), blank=True, null=True) +        _("Documentation received"), blank=True, null=True +    )      finds_deadline = models.DateField( -        _("Deadline for submission of the finds"), blank=True, null=True) -    finds_received = models.NullBooleanField( -        _("Finds received"), blank=True, null=True) +        _("Deadline for submission of the finds"), blank=True, null=True +    ) +    finds_received = models.NullBooleanField(_("Finds received"), blank=True, null=True)      # underwater -    drassm_code = models.CharField(_("DRASSM code"), max_length=100, -                                   null=True, blank=True) +    drassm_code = models.CharField( +        _("DRASSM code"), max_length=100, null=True, blank=True +    )      # judiciary      seizure_name = models.TextField(_("Seizure name"), blank=True, default="") -    official_report_number = models.TextField(_("Official report number"), -                                              blank=True, default="") +    official_report_number = models.TextField( +        _("Official report number"), blank=True, default="" +    )      protagonist = models.ForeignKey( -        Person, verbose_name=_("Name of the protagonist"), -        blank=True, null=True, related_name="operation_protagonist") +        Person, +        verbose_name=_("Name of the protagonist"), +        blank=True, +        null=True, +        related_name="operation_protagonist", +    )      applicant_authority = models.ForeignKey( -        Organization, verbose_name=_("Applicant authority"), -        blank=True, null=True, related_name="operation_applicant_authority") +        Organization, +        verbose_name=_("Applicant authority"), +        blank=True, +        null=True, +        related_name="operation_applicant_authority", +    )      minutes_writer = models.ForeignKey( -        Person, verbose_name=_("Writer of the minutes"), -        blank=True, null=True, related_name="minutes_writer") +        Person, +        verbose_name=_("Writer of the minutes"), +        blank=True, +        null=True, +        related_name="minutes_writer", +    )      cached_towns_label = models.TextField( -        _("Cached town label"), blank=True, default="", -        help_text=_("Generated automatically - do not edit") +        _("Cached town label"), +        blank=True, +        default="", +        help_text=_("Generated automatically - do not edit"),      )      cached_periods = models.TextField( -        _("Cached periods label"), blank=True, default="", -        help_text=_("Generated automatically - do not edit") +        _("Cached periods label"), +        blank=True, +        default="", +        help_text=_("Generated automatically - do not edit"),      )      cached_remains = models.TextField( -        _("Cached remains label"), blank=True, default="", -        help_text=_("Generated automatically - do not edit") +        _("Cached remains label"), +        blank=True, +        default="", +        help_text=_("Generated automatically - do not edit"),      )      history = HistoricalRecords(bases=[HistoryModel]) @@ -1211,25 +1364,29 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,              ("delete_own_operation", "Can delete own Operation"),              ("close_operation", "Can close Operation"),          ) -        ordering = ('cached_label',) +        ordering = ("cached_label",)          indexes = [ -            GinIndex(fields=['data']), +            GinIndex(fields=["data"]),          ]      def natural_key(self): -        return (self.uuid, ) +        return (self.uuid,)      @classmethod -    def get_owns(cls, user, menu_filtr=None, limit=None, values=None, -                 get_short_menu_class=None): +    def get_owns( +        cls, user, menu_filtr=None, limit=None, values=None, get_short_menu_class=None +    ):          replace_query = None -        if menu_filtr and 'file' in menu_filtr: -            replace_query = Q(associated_file=menu_filtr['file']) +        if menu_filtr and "file" in menu_filtr: +            replace_query = Q(associated_file=menu_filtr["file"])          owns = super(Operation, cls).get_owns( -            user, replace_query=replace_query, -            limit=limit, values=values, -            get_short_menu_class=get_short_menu_class) +            user, +            replace_query=replace_query, +            limit=limit, +            values=values, +            get_short_menu_class=get_short_menu_class, +        )          return cls._return_get_owns(owns, values, get_short_menu_class)      def __str__(self): @@ -1245,48 +1402,53 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,          Container = apps.get_model("archaeological_warehouse", "Container")          containers = []          q = Container.objects.filter( -            finds__base_finds__context_record__operation=self).distinct("index") +            finds__base_finds__context_record__operation=self +        ).distinct("index")          exclude += ["operation", "context_record"]          for c in q.order_by("index").all():              containers.append(c.get_values(filtr=filtr, exclude=exclude))          return containers -    def get_values(self, prefix='', no_values=False, filtr=None, **kwargs): +    def get_values(self, prefix="", no_values=False, filtr=None, **kwargs):          values = super(Operation, self).get_values( -            prefix=prefix, no_values=no_values, filtr=filtr, **kwargs) +            prefix=prefix, no_values=no_values, filtr=filtr, **kwargs +        )          values = get_values_town_related(self, prefix, values, filtr=filtr)          exclude = kwargs.get("exclude", [])          if prefix:              return values -        if (not filtr or 'context_records' in filtr) and \ -                "context_records" not in exclude: +        if ( +            not filtr or "context_records" in filtr +        ) and "context_records" not in exclude:              kwargs["no_base_finds"] = False -            values['context_records'] = [ -                cr.get_values(prefix=prefix, no_values=True, filtr=None, -                              **kwargs) +            values["context_records"] = [ +                cr.get_values(prefix=prefix, no_values=True, filtr=None, **kwargs)                  for cr in self.context_record.all()              ] -        if (not filtr or "containers" in filtr) \ -                and "context_records" not in exclude: +        if (not filtr or "containers" in filtr) and "context_records" not in exclude:              values["containers"] = self.get_containers_values(filtr, exclude)          return values      def public_representation(self):          dct = super(Operation, self).public_representation() -        year = self.year \ -            if self.year and self.year != settings.ISHTAR_DEFAULT_YEAR \ +        year = ( +            self.year +            if self.year and self.year != settings.ISHTAR_DEFAULT_YEAR              else None -        dct.update({ -            "year": year, -            "common-name": self.common_name, -            "operation-type": self.operation_type and str(self.operation_type), -            "remains": [str(r) for r in self.remains.all()], -            "periods": [str(p) for p in self.periods.all()], -            "excavation-start-date": self.start_date, -            "excavation-end-date": self.excavation_end_date, -            "address": self.address, -            "comment": self.comment, -        }) +        ) +        dct.update( +            { +                "year": year, +                "common-name": self.common_name, +                "operation-type": self.operation_type and str(self.operation_type), +                "remains": [str(r) for r in self.remains.all()], +                "periods": [str(p) for p in self.periods.all()], +                "excavation-start-date": self.start_date, +                "excavation-end-date": self.excavation_end_date, +                "address": self.address, +                "comment": self.comment, +            } +        )          return dct      @classmethod @@ -1308,7 +1470,7 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,      @property      def short_label(self): -        if settings.COUNTRY == 'fr': +        if settings.COUNTRY == "fr":              return self.reference          return str(self) @@ -1322,7 +1484,7 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,      @property      def show_url(self): -        return reverse('show-operation', args=[self.pk, '']) +        return reverse("show-operation", args=[self.pk, ""])      def towns_codes(self):          return [town.label_with_areas for town in self.towns.all()] @@ -1332,10 +1494,12 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,      def has_finds(self):          from archaeological_finds.models import BaseFind +          return BaseFind.objects.filter(context_record__operation=self).count()      def finds(self):          from archaeological_finds.models import BaseFind +          return BaseFind.objects.filter(context_record__operation=self)      def get_reference(self, full=False): @@ -1349,8 +1513,7 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,              if ref:                  ref += " - "              ref += profile.default_operation_prefix -            ref += "-".join((str(self.year), -                              str(self.operation_code))) +            ref += "-".join((str(self.year), str(self.operation_code)))          return ref or "00"      @property @@ -1360,11 +1523,11 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,          if isinstance(self.code_patriarche, int):              self.code_patriarche = str(self.code_patriarche)          profile = get_current_profile() -        if not profile.operation_region_code or \ -                not self.code_patriarche.startswith( -                    profile.operation_region_code): +        if not profile.operation_region_code or not self.code_patriarche.startswith( +            profile.operation_region_code +        ):              return self.code_patriarche -        return self.code_patriarche[len(profile.operation_region_code):] +        return self.code_patriarche[len(profile.operation_region_code) :]      @property      def reference(self): @@ -1408,15 +1571,15 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,          return "{}/{}/{}".format(self.SLUG, self.year, self.reference)      def get_town_label(self): -        lbl = str(_('Intercommunal')) +        lbl = str(_("Intercommunal"))          if self.towns.count() == 1: -            lbl = self.towns.values('name').all()[0]['name'] +            lbl = self.towns.values("name").all()[0]["name"]          return lbl      def get_department(self):          if not self.towns.count(): -            return '00' -        return self.towns.values('numero_insee').all()[0]['numero_insee'][:2] +            return "00" +        return self.towns.values("numero_insee").all()[0]["numero_insee"][:2]      def grouped_parcels(self):          return Parcel.grouped_parcels(list(self.parcels.distinct().all())) @@ -1425,34 +1588,37 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,          return Parcel.render_parcels(list(self.parcels.distinct().all()))      def get_town_centroid(self): -        q = self.towns.filter(center__isnull=False).annotate( -            centroid=Centroid(Union('center'))).all() +        q = ( +            self.towns.filter(center__isnull=False) +            .annotate(centroid=Centroid(Union("center"))) +            .all() +        )          if not q.count():              return          return q.all()[0].centroid, self._meta.verbose_name      def get_town_polygons(self): -        q = self.towns.filter(limit__isnull=False).annotate( -            poly=Union('limit')).all() +        q = self.towns.filter(limit__isnull=False).annotate(poly=Union("limit")).all()          if not q.count():              return None          return q.all()[0].poly, self._meta.verbose_name      def context_record_relations_q(self): -        from archaeological_context_records.models \ -            import RecordRelations as CRRL +        from archaeological_context_records.models import RecordRelations as CRRL +          return CRRL.objects.filter(left_record__operation=self)      def context_record_docs_q(self): -        return Document.objects.filter( -            context_records__operation=self) +        return Document.objects.filter(context_records__operation=self)      def find_docs_q(self):          return Document.objects.filter( -            finds__base_finds__context_record__operation=self) +            finds__base_finds__context_record__operation=self +        )      def containers_q(self):          from archaeological_warehouse.models import Container +          return Container.objects.filter(              finds__base_finds__context_record__operation=self          ) @@ -1465,18 +1631,29 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,          actions = super(Operation, self).get_extra_actions(request)          is_locked = self.is_locked(request.user) -        can_edit_operation = self.can_do(request, 'change_operation') +        can_edit_operation = self.can_do(request, "change_operation")          if can_edit_operation:              actions += [ -                (reverse("operation-qa-duplicate", args=[self.pk]), -                 _("Duplicate"), "fa fa-clone", "", "", True), +                ( +                    reverse("operation-qa-duplicate", args=[self.pk]), +                    _("Duplicate"), +                    "fa fa-clone", +                    "", +                    "", +                    True, +                ),              ] -        can_add_cr = self.can_do(request, 'add_contextrecord') +        can_add_cr = self.can_do(request, "add_contextrecord")          if can_add_cr and not is_locked:              actions += [ -                (reverse('operation-qa-contextrecord', args=[self.pk]), -                 _("Add context record"), "fa fa-plus", -                 _("context record"), "", True), +                ( +                    reverse("operation-qa-contextrecord", args=[self.pk]), +                    _("Add context record"), +                    "fa fa-plus", +                    _("context record"), +                    "", +                    True, +                ),              ]          return actions @@ -1491,8 +1668,9 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,      @classmethod      def get_available_operation_code(cls, year=None): -        max_val = cls.objects.filter(year=year).aggregate( -            Max('operation_code'))["operation_code__max"] +        max_val = cls.objects.filter(year=year).aggregate(Max("operation_code"))[ +            "operation_code__max" +        ]          return (max_val + 1) if max_val else 1      year_index_lbl = _("Operation code") @@ -1504,14 +1682,17 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,          lbl = str(self.operation_code)          year = self.year or 0          profile = get_current_profile() -        lbl = profile.default_operation_prefix \ -            + "%d-%s%s" % (year, (3 - len(lbl)) * "0", lbl) +        lbl = profile.default_operation_prefix + "%d-%s%s" % ( +            year, +            (3 - len(lbl)) * "0", +            lbl, +        )          return lbl      @property      def full_code_patriarche(self):          if not self.code_patriarche: -            return '' +            return ""          profile = get_current_profile()          return profile.operation_prefix + self.code_patriarche @@ -1519,12 +1700,14 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,          if not self.operation_code:              return          objs = self.__class__.objects.filter( -            year=self.year, operation_code=self.operation_code) +            year=self.year, operation_code=self.operation_code +        )          if self.pk:              objs = objs.exclude(pk=self.pk)          if objs.count(): -            raise ValidationError(_("This operation code already exists for " -                                    "this year")) +            raise ValidationError( +                _("This operation code already exists for " "this year") +            )      @property      def surface_ha(self): @@ -1542,39 +1725,41 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,          profile = ishtaruser.current_profile          town_ids = []          if profile: -            town_ids = [town['pk'] -                        for town in profile.query_towns.values('pk').all()] +            town_ids = [town["pk"] for town in profile.query_towns.values("pk").all()]          query_owns = [              { -                'in_charge': ishtaruser.person, -                'scientist': ishtaruser.person, -                'collaborators__pk': ishtaruser.person.pk, -                'history_creator': ishtaruser.user_ptr, -                'towns__pk__in': town_ids, +                "in_charge": ishtaruser.person, +                "scientist": ishtaruser.person, +                "collaborators__pk": ishtaruser.person.pk, +                "history_creator": ishtaruser.user_ptr, +                "towns__pk__in": town_ids,              }, -            { -                'end_date__isnull': True -            } +            {"end_date__isnull": True},          ]          if not no_rel: -            query_owns[0]['archaeological_sites__collaborators__pk'] = \ -                ishtaruser.person.pk +            query_owns[0][ +                "archaeological_sites__collaborators__pk" +            ] = ishtaruser.person.pk          return query_owns      @classmethod      def get_query_owns(cls, ishtaruser):          from archaeological_warehouse.models import Warehouse -        q = cls._construct_query_own( -            'context_record__base_finds__find__container__responsible__', -            Warehouse._get_query_owns_dicts(ishtaruser) -        ) | cls._construct_query_own( -            'context_record__base_finds__find__container__location__', -            Warehouse._get_query_owns_dicts(ishtaruser) -        ) | cls._construct_query_own( -            'context_record__base_finds__find__basket__', -            [{"shared_with": ishtaruser, "shared_write_with": ishtaruser}] -        ) | cls._construct_query_own( -            '', cls._get_query_owns_dicts(ishtaruser) + +        q = ( +            cls._construct_query_own( +                "context_record__base_finds__find__container__responsible__", +                Warehouse._get_query_owns_dicts(ishtaruser), +            ) +            | cls._construct_query_own( +                "context_record__base_finds__find__container__location__", +                Warehouse._get_query_owns_dicts(ishtaruser), +            ) +            | cls._construct_query_own( +                "context_record__base_finds__find__basket__", +                [{"shared_with": ishtaruser, "shared_write_with": ishtaruser}], +            ) +            | cls._construct_query_own("", cls._get_query_owns_dicts(ishtaruser))          )          return q @@ -1594,7 +1779,7 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,      @property      def nb_acts(self, update=False):          _("Number of administrative acts") -        return self._get_or_set_stats('_nb_acts', update) +        return self._get_or_set_stats("_nb_acts", update)      def _nb_acts(self):          return self.administrative_act.count() @@ -1602,7 +1787,7 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,      @property      def nb_indexed_acts(self, update=False):          _("Number of indexed administrative acts") -        return self._get_or_set_stats('_nb_indexed_acts', update) +        return self._get_or_set_stats("_nb_indexed_acts", update)      def _nb_indexed_acts(self):          return self.administrative_act.filter(act_type__indexed=True).count() @@ -1610,136 +1795,182 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,      @property      def nb_context_records(self, update=False):          _("Number of context records") -        return self._get_or_set_stats('_nb_context_records', update) +        return self._get_or_set_stats("_nb_context_records", update)      def _nb_context_records(self):          return self.context_record.count()      @property      def nb_context_records_by_type(self, update=False): -        return self._get_or_set_stats('_nb_context_records_by_type', update, -                                      expected_type=list) +        return self._get_or_set_stats( +            "_nb_context_records_by_type", update, expected_type=list +        )      def _nb_context_records_by_type(self):          nbs = [] -        q = self.context_record.values( -            'unit', 'unit__label').distinct().order_by('label') +        q = ( +            self.context_record.values("unit", "unit__label") +            .distinct() +            .order_by("label") +        )          for res in q.all(): -            nbs.append((str(res['unit__label'] or "-"), -                        self.context_record.filter(unit=res['unit']).count())) +            nbs.append( +                ( +                    str(res["unit__label"] or "-"), +                    self.context_record.filter(unit=res["unit"]).count(), +                ) +            )          return list(set(nbs))      @property      def nb_context_records_by_periods(self, update=False): -        return self._get_or_set_stats('_nb_context_records_by_periods', update, -                                      expected_type=list) +        return self._get_or_set_stats( +            "_nb_context_records_by_periods", update, expected_type=list +        )      def _nb_context_records_by_periods(self):          nbs = [] -        q = self.context_record.values( -            'datings__period', 'datings__period__label').distinct().order_by( -                'datings__period__order') +        q = ( +            self.context_record.values("datings__period", "datings__period__label") +            .distinct() +            .order_by("datings__period__order") +        )          for res in q.all(): -            nbs.append((str(res['datings__period__label'] or "-"), -                        self.context_record.filter( -                            datings__period=res['datings__period']).count())) +            nbs.append( +                ( +                    str(res["datings__period__label"] or "-"), +                    self.context_record.filter( +                        datings__period=res["datings__period"] +                    ).count(), +                ) +            )          return nbs      @property      def nb_finds(self, update=False):          _("Number of finds") -        return self._get_or_set_stats('_nb_finds', update) +        return self._get_or_set_stats("_nb_finds", update)      def _nb_finds(self):          from archaeological_finds.models import Find +          q = Find.objects.filter(              base_finds__context_record__operation=self, -            upstream_treatment_id__isnull=True).distinct() +            upstream_treatment_id__isnull=True, +        ).distinct()          return q.count()      @property      def nb_finds_by_material_type(self, update=False): -        return self._get_or_set_stats('_nb_finds_by_material_type', update, -                                      expected_type=list) +        return self._get_or_set_stats( +            "_nb_finds_by_material_type", update, expected_type=list +        )      def _nb_finds_by_material_type(self):          from archaeological_finds.models import Find +          nbs = [] -        q = Find.objects.filter( -            upstream_treatment_id__isnull=True, -            base_finds__context_record__operation=self).distinct().values( -            'material_types__pk', 'material_types__label').distinct().order_by( -            'material_types__label') +        q = ( +            Find.objects.filter( +                upstream_treatment_id__isnull=True, +                base_finds__context_record__operation=self, +            ) +            .distinct() +            .values("material_types__pk", "material_types__label") +            .distinct() +            .order_by("material_types__label") +        )          for res in q.all():              nbs.append( -                (str(res['material_types__label'] or "-"), -                 Find.objects.filter( -                    base_finds__context_record__operation=self, -                    upstream_treatment_id__isnull=True, -                    material_types__pk=res['material_types__pk']).count())) +                ( +                    str(res["material_types__label"] or "-"), +                    Find.objects.filter( +                        base_finds__context_record__operation=self, +                        upstream_treatment_id__isnull=True, +                        material_types__pk=res["material_types__pk"], +                    ).count(), +                ) +            )          return nbs      @property      def nb_finds_by_types(self, update=False): -        return self._get_or_set_stats('_nb_finds_by_types', update, -                                      expected_type=list) +        return self._get_or_set_stats("_nb_finds_by_types", update, expected_type=list)      def _nb_finds_by_types(self):          from archaeological_finds.models import Find +          nbs = [] -        q = Find.objects.filter( -            base_finds__context_record__operation=self).values( -            'object_types', 'object_types__label').distinct().order_by( -                'object_types__label') +        q = ( +            Find.objects.filter(base_finds__context_record__operation=self) +            .values("object_types", "object_types__label") +            .distinct() +            .order_by("object_types__label") +        )          for res in q.all(): -            label = str(res['object_types__label']) -            if label == 'None': +            label = str(res["object_types__label"]) +            if label == "None":                  label = str(_("No type"))              nbs.append( -                (label, -                 Find.objects.filter( -                     base_finds__context_record__operation=self, -                     upstream_treatment_id__isnull=True, -                     object_types=res['object_types']).count())) +                ( +                    label, +                    Find.objects.filter( +                        base_finds__context_record__operation=self, +                        upstream_treatment_id__isnull=True, +                        object_types=res["object_types"], +                    ).count(), +                ) +            )          return nbs      @property      def nb_finds_by_periods(self, update=False): -        return self._get_or_set_stats('_nb_finds_by_periods', update, -                                      expected_type=list) +        return self._get_or_set_stats( +            "_nb_finds_by_periods", update, expected_type=list +        )      def _nb_finds_by_periods(self):          from archaeological_finds.models import Find +          nbs = [] -        q = Find.objects.filter( -            base_finds__context_record__operation=self).values( -            'datings__period', 'datings__period__label').distinct().order_by( -                'datings__period__order') +        q = ( +            Find.objects.filter(base_finds__context_record__operation=self) +            .values("datings__period", "datings__period__label") +            .distinct() +            .order_by("datings__period__order") +        )          for res in q.all():              nbs.append( -                (str(res['datings__period__label'] or "-"), -                 Find.objects.filter( -                    base_finds__context_record__operation=self, -                    upstream_treatment_id__isnull=True, -                    datings__period=res['datings__period']).count())) +                ( +                    str(res["datings__period__label"] or "-"), +                    Find.objects.filter( +                        base_finds__context_record__operation=self, +                        upstream_treatment_id__isnull=True, +                        datings__period=res["datings__period"], +                    ).count(), +                ) +            )          return nbs      @property      def nb_documents(self, update=False):          _("Number of sources") -        return self._get_or_set_stats('_nb_documents', update) +        return self._get_or_set_stats("_nb_documents", update)      def _nb_documents(self): -        return self.documents.count() + \ -            Document.objects.filter( -                context_records__operation=self).count() + \ -            Document.objects.filter( -                finds__base_finds__context_record__operation=self).count() +        return ( +            self.documents.count() +            + Document.objects.filter(context_records__operation=self).count() +            + Document.objects.filter( +                finds__base_finds__context_record__operation=self +            ).count() +        )      @property      def nb_documents_by_types(self, update=False): -        return self._get_or_set_stats('_nb_documents_by_types', update, -                                      expected_type=list) +        return self._get_or_set_stats( +            "_nb_documents_by_types", update, expected_type=list +        )      def _nb_documents_by_types(self):          docs = {} @@ -1749,20 +1980,23 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,              Document.objects.filter(context_records__operation=self),              Document.objects.filter(                  finds__upstream_treatment_id__isnull=True, -                finds__base_finds__context_record__operation=self)] +                finds__base_finds__context_record__operation=self, +            ), +        ]          for q in qs: -            for st in set(q.values_list('source_type_id', -                                        flat=True).distinct()): +            for st in set(q.values_list("source_type_id", flat=True).distinct()):                  if st not in docs:                      docs[st] = 0                  docs[st] += q.filter(source_type_id=st).count() -        docs = [(str(SourceType.objects.get(pk=k)) -                 if k else str(_("No type")), docs[k]) for k in docs] +        docs = [ +            (str(SourceType.objects.get(pk=k)) if k else str(_("No type")), docs[k]) +            for k in docs +        ]          return list(sorted(docs, key=lambda x: x[0]))      @property      def nb_stats_finds_by_ue(self, update=False): -        return self._get_or_set_stats('_nb_stats_finds_by_ue', update) +        return self._get_or_set_stats("_nb_stats_finds_by_ue", update)      def _nb_stats_finds_by_ue(self):          _("Mean") @@ -1771,10 +2005,10 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,              finds.append(cr.base_finds.count())          if not finds:              return res -        res['mean'] = float(sum(finds)) / max(len(finds), 1) -        res['min'] = min(finds) -        res['max'] = max(finds) -        res['mode'] = " ; ".join([str(m) for m in mode(finds)]) +        res["mean"] = float(sum(finds)) / max(len(finds), 1) +        res["min"] = min(finds) +        res["max"] = max(finds) +        res["mode"] = " ; ".join([str(m) for m in mode(finds)])          return res      def save(self, *args, **kwargs): @@ -1783,7 +2017,7 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,              self.year = self.start_date.year          if self.operation_code is None:              self.operation_code = self.get_available_operation_code(self.year) -        if hasattr(self, 'code_patriarche'): +        if hasattr(self, "code_patriarche"):              self.code_patriarche = self.code_patriarche or ""          item = super(Operation, self).save(*args, **kwargs)          self.clean_parcel_duplicates() @@ -1791,20 +2025,20 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem,  m2m_changed.connect(force_cached_label_changed, sender=Operation.towns.through) -m2m_changed.connect(document_attached_changed, -                    sender=Operation.documents.through) +m2m_changed.connect(document_attached_changed, sender=Operation.documents.through)  for attr in Operation.HISTORICAL_M2M: -    m2m_changed.connect(m2m_historization_changed, -                        sender=getattr(Operation, attr).through) +    m2m_changed.connect( +        m2m_historization_changed, sender=getattr(Operation, attr).through +    )  def operation_post_save(sender, **kwargs): -    if not kwargs['instance']: +    if not kwargs["instance"]:          return      post_save_geo(sender=sender, **kwargs) -    operation = kwargs['instance'] +    operation = kwargs["instance"]      operation.skip_history_when_saving = True      if operation.fnap_financing and operation.cost:          fnap_cost = int(float(operation.cost) / 100 * operation.fnap_financing) @@ -1835,11 +2069,10 @@ post_save.connect(operation_post_save, sender=Operation)  class RelationType(GeneralRelationType): -      class Meta:          verbose_name = _("Operation relation type")          verbose_name_plural = _("Operation relation types") -        ordering = ('order', 'label') +        ordering = ("order", "label")  class OperationRecordRelationManager(models.Manager): @@ -1847,30 +2080,35 @@ class OperationRecordRelationManager(models.Manager):          return self.get(              left_record__uuid=left_record,              right_record__uuid=right_record, -            relation_type__txt_idx=relation_type) +            relation_type__txt_idx=relation_type, +        )  class RecordRelations(GeneralRecordRelations, models.Model): -    MAIN_ATTR = 'left_record' -    left_record = models.ForeignKey(Operation, -                                    related_name='right_relations') -    right_record = models.ForeignKey(Operation, -                                     related_name='left_relations') +    MAIN_ATTR = "left_record" +    left_record = models.ForeignKey(Operation, related_name="right_relations") +    right_record = models.ForeignKey(Operation, related_name="left_relations")      relation_type = models.ForeignKey(RelationType)      objects = OperationRecordRelationManager()      class Meta:          verbose_name = _("Operation record relation")          verbose_name_plural = _("Operation record relations") -        ordering = ('left_record__cached_label', 'relation_type', -                    'right_record__cached_label') +        ordering = ( +            "left_record__cached_label", +            "relation_type", +            "right_record__cached_label", +        )          permissions = [              ("view_operationrelation", "Can view all Operation relations"),          ]      def natural_key(self): -        return (self.left_record.uuid, -                self.right_record.uuid, self.relation_type.txt_idx) +        return ( +            self.left_record.uuid, +            self.right_record.uuid, +            self.relation_type.txt_idx, +        )  post_delete.connect(post_delete_record_relation, sender=RecordRelations) @@ -1880,6 +2118,7 @@ class OperationByDepartment(models.Model):      """      Database view for dashboard      """ +      CREATE_SQL = """      CREATE VIEW operation_department (id, department_id, operation_id) as          select town."id", town."departement_id", @@ -1897,257 +2136,279 @@ class OperationByDepartment(models.Model):      """      operation = models.ForeignKey(Operation, verbose_name=_("Operation")) -    department = models.ForeignKey(Department, verbose_name=_("Department"), -                                   on_delete=models.DO_NOTHING, -                                   blank=True, null=True) +    department = models.ForeignKey( +        Department, +        verbose_name=_("Department"), +        on_delete=models.DO_NOTHING, +        blank=True, +        null=True, +    )      class Meta:          managed = False -        db_table = 'operation_department' +        db_table = "operation_department"  class ActType(GeneralType): -    TYPE = (('F', _('Archaeological file')), -            ('O', _('Operation')), -            ('TF', _('Treatment request')), -            ('T', _('Treatment')), -            ) +    TYPE = ( +        ("F", _("Archaeological file")), +        ("O", _("Operation")), +        ("TF", _("Treatment request")), +        ("T", _("Treatment")), +    )      SERIALIZATION_EXCLUDE = ["associated_template"] -    intented_to = models.CharField(_("Intended to"), max_length=2, -                                   choices=TYPE) +    intented_to = models.CharField(_("Intended to"), max_length=2, choices=TYPE)      code = models.CharField(_("Code"), max_length=10, blank=True, null=True)      associated_template = models.ManyToManyField( -        DocumentTemplate, blank=True, -        verbose_name=_("Associated template"), related_name='acttypes') +        DocumentTemplate, +        blank=True, +        verbose_name=_("Associated template"), +        related_name="acttypes", +    )      indexed = models.BooleanField(_("Indexed"), default=False)      class Meta:          verbose_name = _("Act type")          verbose_name_plural = _("Act types") -        ordering = ('label',) +        ordering = ("label",)  post_save.connect(post_save_cache, sender=ActType)  post_delete.connect(post_save_cache, sender=ActType) -class AdministrativeAct(DocumentItem, BaseHistorizedItem, OwnPerms, -                        ValueGetter): -    TABLE_COLS = ['full_ref', 'signature_date__year', 'index', 'act_type', -                  'act_object', 'signature_date', -                  'associated_file__cached_label', -                  'operation__cached_label', 'towns_label'] +class AdministrativeAct(DocumentItem, BaseHistorizedItem, OwnPerms, ValueGetter): +    TABLE_COLS = [ +        "full_ref", +        "signature_date__year", +        "index", +        "act_type", +        "act_object", +        "signature_date", +        "associated_file__cached_label", +        "operation__cached_label", +        "towns_label", +    ]      SLUG = "administrativeact"      TABLE_COLS_FILE = [ -        'full_ref', 'year', 'index', 'act_type', -        'act_object', 'associated_file', 'towns_label', +        "full_ref", +        "year", +        "index", +        "act_type", +        "act_object", +        "associated_file", +        "towns_label", +    ] +    TABLE_COLS_OPE = [ +        "full_ref", +        "year", +        "index", +        "act_type", +        "operation", +        "act_object", +        "towns_label",      ] -    TABLE_COLS_OPE = ['full_ref', 'year', 'index', 'act_type', 'operation', -                      'act_object', 'towns_label'] -    if settings.COUNTRY == 'fr': -        TABLE_COLS.append('departments_label') -        TABLE_COLS_FILE.append('departments_label') -        TABLE_COLS_OPE.append('departments_label') +    if settings.COUNTRY == "fr": +        TABLE_COLS.append("departments_label") +        TABLE_COLS_FILE.append("departments_label") +        TABLE_COLS_OPE.append("departments_label")      # search parameters -    DATED_FIELDS = ['signature_date__lte', 'signature_date__gte'] +    DATED_FIELDS = ["signature_date__lte", "signature_date__gte"]      ASSOCIATED_MODELS = [ -        ('File', 'associated_file'), -        (Person, 'associated_file__general_contractor')] +        ("File", "associated_file"), +        (Person, "associated_file__general_contractor"), +    ]      EXTRA_REQUEST_KEYS = { -        'act_object': 'act_object__icontains', -        'act_type__intented_to': 'act_type__intented_to', -        'associated_file__general_contractor__attached_to': -            'associated_file__general_contractor__attached_to__pk', -        'associated_file__name': 'associated_file__name__icontains', -        'associated_file__operations__code_patriarche': -        'associated_file__operations__code_patriarche', -        'associated_file__permit_reference': -            'associated_file__permit_reference__icontains', -        'associated_file__towns': 'associated_file__towns__pk', -        'associated_file__towns__numero_insee__startswith': -        'associated_file__towns__numero_insee__startswith', -        'indexed': 'index__isnull', -        'history_creator': -        'history_creator__ishtaruser__person__pk', -        'history_modifier': -        'history_modifier__ishtaruser__person__pk', -        'operation__code_patriarche': 'operation__code_patriarche', -        'operation__towns': 'operation__towns__pk', -        'operation__towns__numero_insee__startswith': -        'operation__towns__numero_insee__startswith', -        'parcel_0': ('associated_file__parcels__section', -                     'operation__parcels__section', -                     'operation__associated_file__parcels__section'), -        'parcel_1': ( -            'associated_file__parcels__parcel_number' -            'operation__parcels__parcel_number', -            'operation__associated_file__parcels__parcel_number'), -        'parcel_2': ( -            'associated_file__parcels__public_domain', -            'operation__parcels__public_domain', -            'operation__associated_file__parcels__public_domain'), -        'signature_date_before': 'signature_date__lte', -        'signature_date_after': 'signature_date__gte', -        'year': 'signature_date__year', +        "act_object": "act_object__icontains", +        "act_type__intented_to": "act_type__intented_to", +        "associated_file__general_contractor__attached_to": "associated_file__general_contractor__attached_to__pk", +        "associated_file__name": "associated_file__name__icontains", +        "associated_file__operations__code_patriarche": "associated_file__operations__code_patriarche", +        "associated_file__permit_reference": "associated_file__permit_reference__icontains", +        "associated_file__towns": "associated_file__towns__pk", +        "associated_file__towns__numero_insee__startswith": "associated_file__towns__numero_insee__startswith", +        "indexed": "index__isnull", +        "history_creator": "history_creator__ishtaruser__person__pk", +        "history_modifier": "history_modifier__ishtaruser__person__pk", +        "operation__code_patriarche": "operation__code_patriarche", +        "operation__towns": "operation__towns__pk", +        "operation__towns__numero_insee__startswith": "operation__towns__numero_insee__startswith", +        "parcel_0": ( +            "associated_file__parcels__section", +            "operation__parcels__section", +            "operation__associated_file__parcels__section", +        ), +        "parcel_1": ( +            "associated_file__parcels__parcel_number" +            "operation__parcels__parcel_number", +            "operation__associated_file__parcels__parcel_number", +        ), +        "parcel_2": ( +            "associated_file__parcels__public_domain", +            "operation__parcels__public_domain", +            "operation__associated_file__parcels__public_domain", +        ), +        "signature_date_before": "signature_date__lte", +        "signature_date_after": "signature_date__gte", +        "year": "signature_date__year",      }      REVERSED_BOOL_FIELDS = [ -        'index__isnull', 'documents__image__isnull', -        'documents__associated_url__isnull', -        'documents__associated_file__isnull', +        "index__isnull", +        "documents__image__isnull", +        "documents__associated_url__isnull", +        "documents__associated_file__isnull", +    ] +    RELATIVE_SESSION_NAMES = [ +        ("operation", "operation__pk"), +        ("file", "associated_file__pk"),      ] -    RELATIVE_SESSION_NAMES = [('operation', 'operation__pk'), -                              ('file', 'associated_file__pk')]      COL_LABELS = { -        'full_ref': _("Ref."), 'signature_date__year': _("Year"), -        'associated_file__cached_label': _("Archaeological file"), -        'operation__cached_label': _("Operation"), +        "full_ref": _("Ref."), +        "signature_date__year": _("Year"), +        "associated_file__cached_label": _("Archaeological file"), +        "operation__cached_label": _("Operation"),      }      BASE_SEARCH_VECTORS = [          SearchVectorConfig("act_type__label"), -        SearchVectorConfig("act_object", 'local'), +        SearchVectorConfig("act_object", "local"),          SearchVectorConfig("towns_label"),      ]      INT_SEARCH_VECTORS = [          SearchVectorConfig("year"),          SearchVectorConfig("index"),      ] -    PARENT_SEARCH_VECTORS = ['operator', 'scientist', 'signatory', -                             'associated_file', 'operation', 'treatment_file', -                             'treatment'] +    PARENT_SEARCH_VECTORS = [ +        "operator", +        "scientist", +        "signatory", +        "associated_file", +        "operation", +        "treatment_file", +        "treatment", +    ]      # alternative names of fields for searches      ALT_NAMES = { -        'year': SearchAltName( -            pgettext_lazy("key for text search", "year"), -            'signature_date__year' -        ), -        'index': SearchAltName( -            pgettext_lazy("key for text search", "index"), -            'index' +        "year": SearchAltName( +            pgettext_lazy("key for text search", "year"), "signature_date__year"          ), -        'ref_sra': SearchAltName( -            pgettext_lazy("key for text search", "other-ref"), -            'ref_sra__iexact' +        "index": SearchAltName(pgettext_lazy("key for text search", "index"), "index"), +        "ref_sra": SearchAltName( +            pgettext_lazy("key for text search", "other-ref"), "ref_sra__iexact"          ), -        'operation__code_patriarche': SearchAltName( +        "operation__code_patriarche": SearchAltName(              pgettext_lazy("key for text search", "patriarche"), -            'operation__code_patriarche' +            "operation__code_patriarche",          ), -        'act_type': SearchAltName( -            pgettext_lazy("key for text search", "type"), -            'act_type__label__iexact' +        "act_type": SearchAltName( +            pgettext_lazy("key for text search", "type"), "act_type__label__iexact"          ), -        'indexed': SearchAltName( -            pgettext_lazy("key for text search", "indexed"), -            'index__isnull' +        "indexed": SearchAltName( +            pgettext_lazy("key for text search", "indexed"), "index__isnull"          ), -        'operation__towns': SearchAltName( +        "operation__towns": SearchAltName(              pgettext_lazy("key for text search", "operation-town"), -            'operation__towns__cached_label__iexact' +            "operation__towns__cached_label__iexact",          ), -        'associated_file__towns': SearchAltName( +        "associated_file__towns": SearchAltName(              pgettext_lazy("key for text search", "file-town"), -            'associated_file__towns__cached_label__iexact' +            "associated_file__towns__cached_label__iexact",          ), -        'parcel': SearchAltName( +        "parcel": SearchAltName(              pgettext_lazy("key for text search", "parcel"), -            ('associated_file__parcels__cached_label__iexact', -             'operation__parcels__cached_label__iexact', -             'operation__associated_file__parcels__cached_label__iexact'), +            ( +                "associated_file__parcels__cached_label__iexact", +                "operation__parcels__cached_label__iexact", +                "operation__associated_file__parcels__cached_label__iexact", +            ),          ), -        'operation__towns__numero_insee__startswith': SearchAltName( +        "operation__towns__numero_insee__startswith": SearchAltName(              pgettext_lazy("key for text search", "operation-department"), -            'operation__towns__numero_insee__startswith' +            "operation__towns__numero_insee__startswith",          ), -        'associated_file__towns__numero_insee__startswith': SearchAltName( +        "associated_file__towns__numero_insee__startswith": SearchAltName(              pgettext_lazy("key for text search", "file-department"), -            'associated_file__towns__numero_insee__startswith' +            "associated_file__towns__numero_insee__startswith",          ), -        'act_object': SearchAltName( -            pgettext_lazy("key for text search", "object"), -            'act_object__icontains' +        "act_object": SearchAltName( +            pgettext_lazy("key for text search", "object"), "act_object__icontains"          ), -        'signature_date_before': SearchAltName( +        "signature_date_before": SearchAltName(              pgettext_lazy("key for text search", "signature-before"), -            'signature_date__lte' +            "signature_date__lte",          ), -        'signature_date_after': SearchAltName( +        "signature_date_after": SearchAltName(              pgettext_lazy("key for text search", "signature-after"), -            'signature_date__gte' +            "signature_date__gte",          ), -        'associated_file__name': SearchAltName( +        "associated_file__name": SearchAltName(              pgettext_lazy("key for text search", "file-name"), -            'associated_file__name__icontains' +            "associated_file__name__icontains",          ), -        'associated_file__general_contractor': SearchAltName( +        "associated_file__general_contractor": SearchAltName(              pgettext_lazy("key for text search", "general-contractor"), -            'associated_file__general_contractor__cached_label__iexact' +            "associated_file__general_contractor__cached_label__iexact",          ), -        'associated_file__general_contractor__attached_to': SearchAltName( -            pgettext_lazy("key for text search", -                          "general-contractor-organization"), -            'associated_file__general_contractor__attached_to' -            '__cached_label__iexact' +        "associated_file__general_contractor__attached_to": SearchAltName( +            pgettext_lazy("key for text search", "general-contractor-organization"), +            "associated_file__general_contractor__attached_to" "__cached_label__iexact",          ), -        'associated_file__numeric_reference': SearchAltName( +        "associated_file__numeric_reference": SearchAltName(              pgettext_lazy("key for text search", "file-reference"), -            'associated_file__numeric_reference' +            "associated_file__numeric_reference",          ), -        'associated_file__year': SearchAltName( -            pgettext_lazy("key for text search", "file-year"), -            'associated_file__year' +        "associated_file__year": SearchAltName( +            pgettext_lazy("key for text search", "file-year"), "associated_file__year"          ), -        'associated_file__internal_reference': SearchAltName( +        "associated_file__internal_reference": SearchAltName(              pgettext_lazy("key for text search", "file-other-reference"), -            'associated_file__internal_reference__iexact' +            "associated_file__internal_reference__iexact",          ), -        'associated_file__in_charge': SearchAltName( +        "associated_file__in_charge": SearchAltName(              pgettext_lazy("key for text search", "file-in-charge"), -            'associated_file__in_charge__cached_label__iexact' +            "associated_file__in_charge__cached_label__iexact",          ), -        'associated_file__permit_reference': SearchAltName( +        "associated_file__permit_reference": SearchAltName(              pgettext_lazy("key for text search", "file-permit-reference"), -            'associated_file__permit_reference__iexact' +            "associated_file__permit_reference__iexact",          ), -        'treatment__name': SearchAltName( +        "treatment__name": SearchAltName(              pgettext_lazy("key for text search", "treatment-name"), -            'treatment__label__icontains' +            "treatment__label__icontains",          ), -        'treatment__other_reference': SearchAltName( +        "treatment__other_reference": SearchAltName(              pgettext_lazy("key for text search", "treatment-reference"), -            'treatment__other_reference__icontains' +            "treatment__other_reference__icontains",          ), -        'treatment__year': SearchAltName( -            pgettext_lazy("key for text search", "treatment-year"), -            'treatment__year' +        "treatment__year": SearchAltName( +            pgettext_lazy("key for text search", "treatment-year"), "treatment__year"          ), -        'treatment__index': SearchAltName( -            pgettext_lazy("key for text search", "treatment-index"), -            'treatment__index' +        "treatment__index": SearchAltName( +            pgettext_lazy("key for text search", "treatment-index"), "treatment__index"          ), -        'treatment__treatment_types': SearchAltName( +        "treatment__treatment_types": SearchAltName(              pgettext_lazy("key for text search", "treatment-type"), -            'treatment__treatment_types__label__iexact' +            "treatment__treatment_types__label__iexact",          ), -        'treatment_file__name': SearchAltName( +        "treatment_file__name": SearchAltName(              pgettext_lazy("key for text search", "treatment-file-name"), -            'treatment_file__name__icontains' +            "treatment_file__name__icontains",          ), -        'treatment_file__internal_reference': SearchAltName( +        "treatment_file__internal_reference": SearchAltName(              pgettext_lazy("key for text search", "treatment-file-reference"), -            'treatment_file__internal_reference__icontains' +            "treatment_file__internal_reference__icontains",          ), -        'treatment_file__year': SearchAltName( +        "treatment_file__year": SearchAltName(              pgettext_lazy("key for text search", "treatment-file-year"), -            'treatment_file__year' +            "treatment_file__year",          ), -        'treatment_file__index': SearchAltName( +        "treatment_file__index": SearchAltName(              pgettext_lazy("key for text search", "treatment-file-index"), -            'treatment_file__index' +            "treatment_file__index",          ), -        'treatment_file__type': SearchAltName( +        "treatment_file__type": SearchAltName(              pgettext_lazy("key for text search", "treatment-file-type"), -            'treatment_file__type__label__iexact' +            "treatment_file__type__label__iexact",          ),      }      ALT_NAMES.update(BaseHistorizedItem.ALT_NAMES) @@ -2156,102 +2417,134 @@ class AdministrativeAct(DocumentItem, BaseHistorizedItem, OwnPerms,      UP_MODEL_QUERY = {}      POST_PROCESS_REQUEST = { -        'operation__towns__numero_insee__startswith': '_get_department_code', -        'associated_file__towns__numero_insee__startswith': -            '_get_department_code', +        "operation__towns__numero_insee__startswith": "_get_department_code", +        "associated_file__towns__numero_insee__startswith": "_get_department_code",      }      # fields      act_type = models.ForeignKey(ActType, verbose_name=_("Act type"))      in_charge = models.ForeignKey( -        Person, blank=True, null=True, -        related_name='adminact_operation_in_charge', +        Person, +        blank=True, +        null=True, +        related_name="adminact_operation_in_charge",          verbose_name=_("Person in charge of the operation"), -        on_delete=models.SET_NULL,) -    index = models.IntegerField(verbose_name=_("Index"), blank=True, -                                null=True) +        on_delete=models.SET_NULL, +    ) +    index = models.IntegerField(verbose_name=_("Index"), blank=True, null=True)      operator = models.ForeignKey( -        Organization, blank=True, null=True, +        Organization, +        blank=True, +        null=True,          verbose_name=_("Archaeological preventive operator"), -        related_name='adminact_operator', on_delete=models.SET_NULL) +        related_name="adminact_operator", +        on_delete=models.SET_NULL, +    )      scientist = models.ForeignKey( -        Person, blank=True, null=True, -        related_name='adminact_scientist', on_delete=models.SET_NULL, -        verbose_name=_("Scientist in charge")) +        Person, +        blank=True, +        null=True, +        related_name="adminact_scientist", +        on_delete=models.SET_NULL, +        verbose_name=_("Scientist in charge"), +    )      signatory = models.ForeignKey( -        Person, blank=True, null=True, related_name='signatory', -        verbose_name=_("Signatory"), on_delete=models.SET_NULL,) +        Person, +        blank=True, +        null=True, +        related_name="signatory", +        verbose_name=_("Signatory"), +        on_delete=models.SET_NULL, +    )      operation = models.ForeignKey( -        Operation, blank=True, null=True, -        related_name='administrative_act', verbose_name=_("Operation")) +        Operation, +        blank=True, +        null=True, +        related_name="administrative_act", +        verbose_name=_("Operation"), +    )      associated_file = models.ForeignKey( -        'archaeological_files.File', -        blank=True, null=True, -        related_name='administrative_act', -        verbose_name=_("Archaeological file")) +        "archaeological_files.File", +        blank=True, +        null=True, +        related_name="administrative_act", +        verbose_name=_("Archaeological file"), +    )      treatment_file = models.ForeignKey( -        'archaeological_finds.TreatmentFile', -        blank=True, null=True, -        related_name='administrative_act', -        verbose_name=_("Treatment request")) +        "archaeological_finds.TreatmentFile", +        blank=True, +        null=True, +        related_name="administrative_act", +        verbose_name=_("Treatment request"), +    )      treatment = models.ForeignKey( -        'archaeological_finds.Treatment', -        blank=True, null=True, -        related_name='administrative_act', -        verbose_name=_("Treatment")) -    signature_date = models.DateField(_("Signature date"), blank=True, -                                      null=True) +        "archaeological_finds.Treatment", +        blank=True, +        null=True, +        related_name="administrative_act", +        verbose_name=_("Treatment"), +    ) +    signature_date = models.DateField(_("Signature date"), blank=True, null=True)      year = models.IntegerField(_("Year"), blank=True, null=True)      act_object = models.TextField(_("Object"), blank=True, default="") -    if settings.COUNTRY == 'fr': -        ref_sra = models.CharField("Référence SRA", max_length=15, -                                   blank=True, null=True) +    if settings.COUNTRY == "fr": +        ref_sra = models.CharField( +            "Référence SRA", max_length=15, blank=True, null=True +        )          departments_label = models.TextField( -            _("Departments"), blank=True, default="", -            help_text=_("Cached values get from associated departments")) +            _("Departments"), +            blank=True, +            default="", +            help_text=_("Cached values get from associated departments"), +        )      towns_label = models.TextField( -        _("Towns"), blank=True, default="", -        help_text=_("Cached values get from associated towns")) +        _("Towns"), +        blank=True, +        default="", +        help_text=_("Cached values get from associated towns"), +    )      documents = models.ManyToManyField( -        Document, related_name="administrativeacts", -        verbose_name=_("Documents"), blank=True) +        Document, +        related_name="administrativeacts", +        verbose_name=_("Documents"), +        blank=True, +    )      main_image = models.ForeignKey( -        Document, related_name='main_image_administrativeacts', +        Document, +        related_name="main_image_administrativeacts",          on_delete=models.SET_NULL, -        verbose_name=_("Main image"), blank=True, null=True) +        verbose_name=_("Main image"), +        blank=True, +        null=True, +    )      history = HistoricalRecords() -    _prefix = 'adminact_' +    _prefix = "adminact_"      class Meta: -        ordering = ('year', 'signature_date', 'index', 'act_type') +        ordering = ("year", "signature_date", "index", "act_type")          verbose_name = _("Administrative act")          verbose_name_plural = _("Administrative acts")          permissions = ( -            ("view_administrativeact", -             "Can view all Administrative acts"), -            ("view_own_administrativeact", -             "Can view own Administrative act"), -            ("add_own_administrativeact", -             "Can add own Administrative act"), -            ("change_own_administrativeact", -             "Can change own Administrative act"), -            ("delete_own_administrativeact", -             "Can delete own Administrative act"), +            ("view_administrativeact", "Can view all Administrative acts"), +            ("view_own_administrativeact", "Can view own Administrative act"), +            ("add_own_administrativeact", "Can add own Administrative act"), +            ("change_own_administrativeact", "Can change own Administrative act"), +            ("delete_own_administrativeact", "Can delete own Administrative act"),          )          indexes = [ -            GinIndex(fields=['data']), +            GinIndex(fields=["data"]),          ]      @property      def DELETE_URL(self):          if self.operation: -            return 'delete-administrativeact-operation' +            return "delete-administrativeact-operation"          if self.associated_file: -            return 'delete-administrativeact-file' +            return "delete-administrativeact-file"          if self.treatment: -            return 'delete-administrativeact-treatment' +            return "delete-administrativeact-treatment"          if self.treatment_file: -            return 'delete-administrativeact-treatmentfile' +            return "delete-administrativeact-treatmentfile"      def __str__(self):          lbl = "" @@ -2263,9 +2556,8 @@ class AdministrativeAct(DocumentItem, BaseHistorizedItem, OwnPerms,              lbl += " - "          lbl += self.act_type.label + " - "          return lbl + settings.JOINT.join( -            [str(item) for item in [ -                self.related_item, self.act_object] -             if item]) +            [str(item) for item in [self.related_item, self.act_object] if item] +        )      full_ref_lbl = _("Ref.") @@ -2281,7 +2573,7 @@ class AdministrativeAct(DocumentItem, BaseHistorizedItem, OwnPerms,              lbl.append(str(self.year))          if self.index:              lbl.append("n°%d" % self.index) -        if settings.COUNTRY == 'fr' and self.ref_sra: +        if settings.COUNTRY == "fr" and self.ref_sra:              lbl.append("[%s]" % self.ref_sra)          return " ".join(lbl) @@ -2299,21 +2591,21 @@ class AdministrativeAct(DocumentItem, BaseHistorizedItem, OwnPerms,      @property      def departments(self): -        if settings.COUNTRY != 'fr': -            return '' +        if settings.COUNTRY != "fr": +            return ""          q = None          if self.associated_file:              q = self.associated_file.towns.all()          elif self.operation:              q = self.operation.towns.all()          if not q: -            return '' +            return ""          dpts = []          for town in q:              dpt = town.numero_insee[:2]              if dpt not in dpts:                  dpts.append(dpt) -        return ', '.join(list(sorted(dpts))) +        return ", ".join(list(sorted(dpts)))      @classmethod      def _get_department_code(cls, value): @@ -2344,13 +2636,13 @@ class AdministrativeAct(DocumentItem, BaseHistorizedItem, OwnPerms,      def get_filename(self):          filename = self.related_item.associated_filename -        filename = "-".join(filename.split('-')[:-1])  # remove date +        filename = "-".join(filename.split("-")[:-1])  # remove date          if self.act_type.code:              filename += "-" + self.act_type.code          if self.signature_date and self.index:              filename += "-%d-%d" % (self.signature_date.year, self.index)          if self.signature_date: -            filename += "-" + self.signature_date.strftime('%Y%m%d') +            filename += "-" + self.signature_date.strftime("%Y%m%d")          return filename      def publish(self, template_pk=None): @@ -2369,20 +2661,21 @@ class AdministrativeAct(DocumentItem, BaseHistorizedItem, OwnPerms,          if not self.index:              c_index = 1              q = AdministrativeAct.objects.filter( -                act_type__indexed=True, signature_date__year=self.year, -                index__isnull=False).order_by("-index") +                act_type__indexed=True, +                signature_date__year=self.year, +                index__isnull=False, +            ).order_by("-index")              if q.count():                  c_index = q.all()[0].index + 1              self.index = c_index          conflict = AdministrativeAct.objects.filter( -            act_type__indexed=True, signature_date__year=self.year, -            index=self.index) +            act_type__indexed=True, signature_date__year=self.year, index=self.index +        )          if self.pk:              conflict = conflict.exclude(pk=self.pk)          if conflict.count():              if self.pk: -                raise ValidationError(_("This index already exists for " -                                        "this year")) +                raise ValidationError(_("This index already exists for " "this year"))              else:                  self._get_index() @@ -2396,14 +2689,13 @@ class AdministrativeAct(DocumentItem, BaseHistorizedItem, OwnPerms,          super(AdministrativeAct, self).clean(*args, **kwargs)      def save(self, *args, **kwargs): -        if settings.COUNTRY == 'fr': +        if settings.COUNTRY == "fr":              self.departments_label = self.departments -        self.towns_label = ", ".join( -            list(sorted([str(town) for town in self.towns]))) +        self.towns_label = ", ".join(list(sorted([str(town) for town in self.towns])))          force = False -        if 'force' in kwargs: -            force = kwargs.pop('force') +        if "force" in kwargs: +            force = kwargs.pop("force")          if self.signature_date:              self.year = self.signature_date.year @@ -2416,7 +2708,7 @@ class AdministrativeAct(DocumentItem, BaseHistorizedItem, OwnPerms,                      except:                          pass          super(AdministrativeAct, self).save(*args, **kwargs) -        if hasattr(self, 'associated_file') and self.associated_file: +        if hasattr(self, "associated_file") and self.associated_file:              self.associated_file.update_has_admin_act()              self.associated_file.update_short_menu_class()          updated = self.update_search_vector() @@ -2426,57 +2718,67 @@ class AdministrativeAct(DocumentItem, BaseHistorizedItem, OwnPerms,  def strip_zero(value):      for idx, nb in enumerate(value): -        if nb != '0': +        if nb != "0":              return value[idx:]      return value  class Parcel(LightHistorizedItem): -    EXTERNAL_ID_KEY = 'parcel_external_id' +    EXTERNAL_ID_KEY = "parcel_external_id"      BASE_SEARCH_VECTORS = [          SearchVectorConfig("section"),          SearchVectorConfig("parcel_number"),          SearchVectorConfig("cached_label"),      ] -    PARENT_SEARCH_VECTORS = ['operation'] +    PARENT_SEARCH_VECTORS = ["operation"]      objects = UUIDModelManager()      uuid = models.UUIDField(default=uuid.uuid4)      associated_file = models.ForeignKey( -        'archaeological_files.File', -        related_name='parcels', verbose_name=_("File"), -        blank=True, null=True, on_delete=models.SET_NULL) +        "archaeological_files.File", +        related_name="parcels", +        verbose_name=_("File"), +        blank=True, +        null=True, +        on_delete=models.SET_NULL, +    )      operation = models.ForeignKey( -        Operation, related_name='parcels', blank=True, null=True, -        verbose_name=_("Operation"), on_delete=models.SET_NULL) +        Operation, +        related_name="parcels", +        blank=True, +        null=True, +        verbose_name=_("Operation"), +        on_delete=models.SET_NULL, +    )      year = models.IntegerField(_("Year"), blank=True, null=True) -    town = models.ForeignKey(Town, related_name='parcels', -                             verbose_name=_("Town")) -    section = models.CharField(_("Section"), max_length=4, -                               null=True, blank=True) -    parcel_number = models.CharField(_("Parcel number"), max_length=6, -                                     null=True, blank=True) +    town = models.ForeignKey(Town, related_name="parcels", verbose_name=_("Town")) +    section = models.CharField(_("Section"), max_length=4, null=True, blank=True) +    parcel_number = models.CharField( +        _("Parcel number"), max_length=6, null=True, blank=True +    )      public_domain = models.BooleanField(_("Public domain"), default=False) -    external_id = models.CharField(_("External ID"), max_length=100, -                                   null=True, blank=True) +    external_id = models.CharField( +        _("External ID"), max_length=100, null=True, blank=True +    )      auto_external_id = models.BooleanField( -        _("External ID is set automatically"), default=False) +        _("External ID is set automatically"), default=False +    )      address = models.TextField(_("Address - Locality"), blank=True, default="") -    cached_label = models.TextField(_("Cached name"), blank=True, default="", -                                    db_index=True) +    cached_label = models.TextField( +        _("Cached name"), blank=True, default="", db_index=True +    )      class Meta:          verbose_name = _("Parcel")          verbose_name_plural = _("Parcels") -        ordering = ('year', 'section', 'parcel_number') +        ordering = ("year", "section", "parcel_number")          indexes = [ -            GinIndex(fields=['data']), +            GinIndex(fields=["data"]),          ]      @property      def short_label(self): -        items = [str(item) for item in [self.section, self.parcel_number] -                 if item] +        items = [str(item) for item in [self.section, self.parcel_number] if item]          if self.public_domain:              items.append(str(_("Public domain")))          return settings.JOINT.join(items) @@ -2485,7 +2787,7 @@ class Parcel(LightHistorizedItem):          return self.short_label      def natural_key(self): -        return (self.uuid, ) +        return (self.uuid,)      """      def merge(self, parcel): @@ -2519,9 +2821,11 @@ class Parcel(LightHistorizedItem):      @classmethod      def grouped_parcels(cls, parcels): -        sortkeyfn = lambda s: (getattr(s, 'town_id'), -                               getattr(s, 'section') or "", -                               getattr(s, 'year') or 0) +        sortkeyfn = lambda s: ( +            getattr(s, "town_id"), +            getattr(s, "section") or "", +            getattr(s, "year") or 0, +        )          parcels = sorted(parcels, key=sortkeyfn)          grouped = []          for keys, parcel_grp in groupby(parcels, key=sortkeyfn): @@ -2534,45 +2838,46 @@ class Parcel(LightHistorizedItem):                      if parcel.parcel_number == "0":                          nb = "0"                      else: -                        nb = "0" * (12 - len(parcel.parcel_number)) + \ -                            parcel.parcel_number +                        nb = ( +                            "0" * (12 - len(parcel.parcel_number)) +                            + parcel.parcel_number +                        )                  if parcel.public_domain:                      if nb:                          nb += " "                      nb += str(_("Public domain"))                  grouped[-1].parcel_numbers.append(nb)              grouped[-1].parcel_numbers.sort() -            grouped[-1].parcel_numbers = [strip_zero(n) -                                          for n in grouped[-1].parcel_numbers] +            grouped[-1].parcel_numbers = [ +                strip_zero(n) for n in grouped[-1].parcel_numbers +            ]          return grouped      @classmethod      def render_parcels(cls, parcels):          parcels = cls.grouped_parcels(parcels) -        res = '' -        c_town, c_section = '', '' +        res = "" +        c_town, c_section = "", ""          for idx, parcels in enumerate(parcels):              if c_town != str(parcels.town):                  c_town = str(parcels.town)                  if idx:                      res += " ; " -                res += str(parcels.town) + ' : ' +                res += str(parcels.town) + " : "              elif c_section:                  res += " / "              else:  # public domain                  res += " & "              c_section = parcels.section -            res += parcels.section + ' ' +            res += parcels.section + " "              res += ", ".join(parcels.parcel_numbers)              if parcels.year:                  res += " ({})".format(parcels.year)          return res      def long_label(self): -        items = [str(self.operation) or -                 str(self.associated_file) or ""] -        items += [str(item) for item in [self.section, self.parcel_number] -                  if item] +        items = [str(self.operation) or str(self.associated_file) or ""] +        items += [str(item) for item in [self.section, self.parcel_number] if item]          return settings.JOINT.join(items)      def copy_to_file(self): @@ -2582,20 +2887,26 @@ class Parcel(LightHistorizedItem):          if not self.operation or not self.operation.associated_file:              # not concerned              return -        keys = {'town': self.town, 'section': self.section, -                'parcel_number': self.parcel_number} +        keys = { +            "town": self.town, +            "section": self.section, +            "parcel_number": self.parcel_number, +        }          if self.operation.associated_file.parcels.filter(**keys).count():              # everything is OK              return -        keys['address'] = self.address -        keys['year'] = self.year -        keys['associated_file'] = self.operation.associated_file +        keys["address"] = self.address +        keys["year"] = self.year +        keys["associated_file"] = self.operation.associated_file          new_p = Parcel.objects.create(**keys)          # also copy owning          for owning in self.owners.all():              ParcelOwner.objects.create( -                owner=owning.owner, parcel=new_p, -                start_date=owning.start_date, end_date=owning.end_date) +                owner=owning.owner, +                parcel=new_p, +                start_date=owning.start_date, +                end_date=owning.end_date, +            )      def copy_to_operation(self):          """ @@ -2605,19 +2916,24 @@ class Parcel(LightHistorizedItem):          if not (self.operation and self.associated_file):              # everything is OK              return -        keys = {'town': self.town, 'section': self.section, -                'parcel_number': self.parcel_number, -                'operation': self.operation, -                'associated_file': None, -                'defaults': {'address': self.address, 'year': self.year} -                } +        keys = { +            "town": self.town, +            "section": self.section, +            "parcel_number": self.parcel_number, +            "operation": self.operation, +            "associated_file": None, +            "defaults": {"address": self.address, "year": self.year}, +        }          new_p, created = Parcel.objects.get_or_create(**keys)          # copy owning only if created          if created:              for owning in self.owners.all():                  ParcelOwner.objects.create( -                    owner=owning.owner, parcel=new_p, -                    start_date=owning.start_date, end_date=owning.end_date) +                    owner=owning.owner, +                    parcel=new_p, +                    start_date=owning.start_date, +                    end_date=owning.end_date, +                )          self.operation = None          self.save() @@ -2637,34 +2953,41 @@ class Parcel(LightHistorizedItem):  def parcel_post_save(sender, **kwargs): -    if not kwargs['instance']: +    if not kwargs["instance"]:          return -    parcel = kwargs['instance'] +    parcel = kwargs["instance"]      cached_label_changed(sender, **kwargs) -    if not getattr(parcel, '_updated_id', None) \ -            and not parcel.operation and not parcel.associated_file \ -            and parcel.context_record.count(): +    if ( +        not getattr(parcel, "_updated_id", None) +        and not parcel.operation +        and not parcel.associated_file +        and parcel.context_record.count() +    ):          # trying to restore a lost parcel          parcel.operation = parcel.context_record.all()[0].operation          parcel.save()          return      if parcel.context_record.count(): -        parcel.context_record.model.cached_label_bulk_update( -            parcel_id=parcel.id) +        parcel.context_record.model.cached_label_bulk_update(parcel_id=parcel.id) -    if parcel.operation and parcel.operation.pk and \ -            parcel.town not in list(parcel.operation.towns.all()): +    if ( +        parcel.operation +        and parcel.operation.pk +        and parcel.town not in list(parcel.operation.towns.all()) +    ):          try:              # multiple save can cause multiple add              with transaction.atomic():                  parcel.operation.towns.add(parcel.town)          except IntegrityError:              pass -    if parcel.associated_file and \ -            parcel.associated_file.pk and \ -            parcel.town not in list(parcel.associated_file.towns.all()): +    if ( +        parcel.associated_file +        and parcel.associated_file.pk +        and parcel.town not in list(parcel.associated_file.towns.all()) +    ):          try:              # multiple save can cause multiple add              with transaction.atomic(): @@ -2681,10 +3004,10 @@ post_save.connect(parcel_post_save, sender=Parcel)  class ParcelOwner(LightHistorizedItem):      uuid = models.UUIDField(default=uuid.uuid4) -    owner = models.ForeignKey(Person, verbose_name=_("Owner"), -                              related_name="parcel_owner") -    parcel = models.ForeignKey(Parcel, verbose_name=_("Parcel"), -                               related_name='owners') +    owner = models.ForeignKey( +        Person, verbose_name=_("Owner"), related_name="parcel_owner" +    ) +    parcel = models.ForeignKey(Parcel, verbose_name=_("Parcel"), related_name="owners")      start_date = models.DateField(_("Start date"))      end_date = models.DateField(_("End date"))      objects = UUIDModelManager() @@ -2693,14 +3016,14 @@ class ParcelOwner(LightHistorizedItem):          verbose_name = _("Parcel owner")          verbose_name_plural = _("Parcel owners")          indexes = [ -            GinIndex(fields=['data']), +            GinIndex(fields=["data"]),          ]      def __str__(self):          return "{}{}{}".format(self.owner, settings.JOINT, self.parcel)      def natural_key(self): -        return (self.uuid, ) +        return (self.uuid,)      @property      def operation(self): @@ -2718,26 +3041,34 @@ class OperationDashboard:          self.total_number = main_dashboard.total_number          self.filters_keys = [ -            'recorded', 'effective', 'active', 'field', -            'documented', 'closed', 'documented_closed'] +            "recorded", +            "effective", +            "active", +            "field", +            "documented", +            "closed", +            "documented_closed", +        ]          filters = { -            'recorded': {}, -            'effective': {'scientist__isnull': False}, -            'active': {'scientist__isnull': False, 'end_date__isnull': True}, -            'field': {'excavation_end_date__isnull': True}, -            'documented': {'documents__isnull': False}, -            'documented_closed': {'documents__isnull': False, -                                  'end_date__isnull': False}, -            'closed': {'end_date__isnull': False} +            "recorded": {}, +            "effective": {"scientist__isnull": False}, +            "active": {"scientist__isnull": False, "end_date__isnull": True}, +            "field": {"excavation_end_date__isnull": True}, +            "documented": {"documents__isnull": False}, +            "documented_closed": { +                "documents__isnull": False, +                "end_date__isnull": False, +            }, +            "closed": {"end_date__isnull": False},          }          filters_label = { -            'recorded': _("Recorded"), -            'effective': _("Effective"), -            'active': _("Active"), -            'field': _("Field completed"), -            'documented': _("Associated report"), -            'closed': _("Closed"), -            'documented_closed': _("Documented and closed"), +            "recorded": _("Recorded"), +            "effective": _("Effective"), +            "active": _("Active"), +            "field": _("Field completed"), +            "documented": _("Associated report"), +            "closed": _("Closed"), +            "documented_closed": _("Documented and closed"),          }          self.filters_label = [filters_label[k] for k in self.filters_keys]          self.total = [] @@ -2746,22 +3077,25 @@ class OperationDashboard:              nb = Operation.objects.filter(**fltr).count()              self.total.append((lbl, nb)) -        self.surface_by_type = Operation.objects\ -            .values('operation_type__label')\ -            .annotate(number=Sum('surface'))\ -            .order_by('-number', 'operation_type__label') +        self.surface_by_type = ( +            Operation.objects.values("operation_type__label") +            .annotate(number=Sum("surface")) +            .order_by("-number", "operation_type__label") +        )          self.by_type = []          self.types = OperationType.objects.filter(available=True).all()          for fltr_key in self.filters_keys:              fltr, lbl = filters[fltr_key], filters_label[fltr_key] -            type_res = Operation.objects.filter(**fltr).\ -                values('operation_type', 'operation_type__label').\ -                annotate(number=Count('pk')).\ -                order_by('operation_type') +            type_res = ( +                Operation.objects.filter(**fltr) +                .values("operation_type", "operation_type__label") +                .annotate(number=Count("pk")) +                .order_by("operation_type") +            )              types_dct = {}              for typ in type_res.all(): -                types_dct[typ['operation_type']] = typ["number"] +                types_dct[typ["operation_type"]] = typ["number"]              types = []              for typ in self.types:                  if typ.pk in types_dct: @@ -2771,17 +3105,21 @@ class OperationDashboard:              self.by_type.append((lbl, types))          self.by_year = [] -        self.years = [res['year'] for res in Operation.objects.values('year') -                      .order_by('-year').distinct()] +        self.years = [ +            res["year"] +            for res in Operation.objects.values("year").order_by("-year").distinct() +        ]          for fltr_key in self.filters_keys:              fltr, lbl = filters[fltr_key], filters_label[fltr_key] -            year_res = Operation.objects.filter(**fltr)\ -                                        .values('year')\ -                                        .annotate(number=Count('pk'))\ -                                        .order_by('year') +            year_res = ( +                Operation.objects.filter(**fltr) +                .values("year") +                .annotate(number=Count("pk")) +                .order_by("year") +            )              years_dct = {}              for yr in year_res.all(): -                years_dct[yr['year']] = yr["number"] +                years_dct[yr["year"]] = yr["number"]              years = []              for yr in self.years:                  if yr in years_dct: @@ -2792,19 +3130,29 @@ class OperationDashboard:          self.by_realisation_year = []          self.realisation_years = [ -            res['date'] for res in Operation.objects.extra( -                {'date': "date_trunc('year', start_date)"}).values('date') -            .filter(start_date__isnull=False).order_by('-date').distinct()] +            res["date"] +            for res in Operation.objects.extra( +                {"date": "date_trunc('year', start_date)"} +            ) +            .values("date") +            .filter(start_date__isnull=False) +            .order_by("-date") +            .distinct() +        ]          for fltr_key in self.filters_keys:              fltr, lbl = filters[fltr_key], filters_label[fltr_key] -            year_res = Operation.objects.filter(**fltr).extra( -                {'date': "date_trunc('year', start_date)"}).values('date')\ -                .values('date').filter(start_date__isnull=False)\ -                .annotate(number=Count('pk'))\ -                .order_by('-date') +            year_res = ( +                Operation.objects.filter(**fltr) +                .extra({"date": "date_trunc('year', start_date)"}) +                .values("date") +                .values("date") +                .filter(start_date__isnull=False) +                .annotate(number=Count("pk")) +                .order_by("-date") +            )              years_dct = {}              for yr in year_res.all(): -                years_dct[yr['date']] = yr["number"] +                years_dct[yr["date"]] = yr["number"]              years = []              for yr in self.realisation_years:                  if yr in years_dct: @@ -2815,14 +3163,18 @@ class OperationDashboard:          self.effective = []          for typ in self.types: -            year_res = Operation.objects.filter(**{'scientist__isnull': False, -                                                   'operation_type': typ})\ -                                        .values('year')\ -                                        .annotate(number=Count('pk'))\ -                                        .order_by('-year').distinct() +            year_res = ( +                Operation.objects.filter( +                    **{"scientist__isnull": False, "operation_type": typ} +                ) +                .values("year") +                .annotate(number=Count("pk")) +                .order_by("-year") +                .distinct() +            )              years_dct = {}              for yr in year_res.all(): -                years_dct[yr['year']] = yr["number"] +                years_dct[yr["year"]] = yr["number"]              years = []              for yr in self.years:                  if yr in years_dct: @@ -2835,8 +3187,8 @@ class OperationDashboard:          now = datetime.date.today()          limit = datetime.date(now.year, now.month, 1) - datetime.timedelta(365)          by_realisation_month = Operation.objects.filter( -            start_date__gt=limit, start_date__isnull=False).extra( -                {'date': "date_trunc('month', start_date)"}) +            start_date__gt=limit, start_date__isnull=False +        ).extra({"date": "date_trunc('month', start_date)"})          self.last_months = []          date = datetime.datetime(now.year, now.month, 1)          for mt_idx in range(12): @@ -2848,8 +3200,11 @@ class OperationDashboard:          self.by_realisation_month = []          for fltr_key in self.filters_keys:              fltr, lbl = filters[fltr_key], filters_label[fltr_key] -            month_res = by_realisation_month.filter(**fltr)\ -                .annotate(number=Count('pk')).order_by('-date') +            month_res = ( +                by_realisation_month.filter(**fltr) +                .annotate(number=Count("pk")) +                .order_by("-date") +            )              month_dct = {}              for mt in month_res.all():                  month_dct[mt.date] = mt.number @@ -2864,151 +3219,161 @@ class OperationDashboard:          # survey and excavations          self.survey, self.excavation = {}, {} -        for dct_res, ope_types in ((self.survey, ('arch_diagnostic',)), -                                   (self.excavation, ('prev_excavation', -                                                      'prog_excavation'))): -            dct_res['total'] = [] -            operation_type = {'operation_type__txt_idx__in': ope_types} +        for dct_res, ope_types in ( +            (self.survey, ("arch_diagnostic",)), +            (self.excavation, ("prev_excavation", "prog_excavation")), +        ): +            dct_res["total"] = [] +            operation_type = {"operation_type__txt_idx__in": ope_types}              for fltr_key in self.filters_keys:                  fltr, lbl = filters[fltr_key], filters_label[fltr_key]                  fltr.update(operation_type)                  nb = Operation.objects.filter(**fltr).count() -                dct_res['total'].append((lbl, nb)) +                dct_res["total"].append((lbl, nb)) -            dct_res['by_year'] = [] +            dct_res["by_year"] = []              for fltr_key in self.filters_keys:                  fltr, lbl = filters[fltr_key], filters_label[fltr_key]                  fltr.update(operation_type) -                year_res = Operation.objects.filter(**fltr)\ -                                            .values('year')\ -                                            .annotate(number=Count('pk'))\ -                                            .order_by('year') +                year_res = ( +                    Operation.objects.filter(**fltr) +                    .values("year") +                    .annotate(number=Count("pk")) +                    .order_by("year") +                )                  years_dct = {}                  for yr in year_res.all(): -                    years_dct[yr['year']] = yr["number"] +                    years_dct[yr["year"]] = yr["number"]                  years = []                  for yr in self.years:                      if yr in years_dct:                          years.append(years_dct[yr])                      else:                          years.append(0) -                dct_res['by_year'].append((lbl, years)) +                dct_res["by_year"].append((lbl, years)) -            dct_res['by_realisation_year'] = [] +            dct_res["by_realisation_year"] = []              for fltr_key in self.filters_keys:                  fltr, lbl = filters[fltr_key], filters_label[fltr_key]                  fltr.update(operation_type) -                year_res = Operation.objects.filter(**fltr).extra( -                    {'date': "date_trunc('year', start_date)"})\ -                    .values('date')\ -                    .filter(start_date__isnull=False)\ -                    .annotate(number=Count('pk'))\ -                    .order_by('-date') +                year_res = ( +                    Operation.objects.filter(**fltr) +                    .extra({"date": "date_trunc('year', start_date)"}) +                    .values("date") +                    .filter(start_date__isnull=False) +                    .annotate(number=Count("pk")) +                    .order_by("-date") +                )                  years_dct = {}                  for yr in year_res.all(): -                    years_dct[yr['date']] = yr["number"] +                    years_dct[yr["date"]] = yr["number"]                  years = []                  for yr in self.realisation_years:                      if yr in years_dct:                          years.append(years_dct[yr])                      else:                          years.append(0) -                dct_res['by_realisation_year'].append((lbl, years)) - -            current_year_ope = Operation.objects.filter(**operation_type)\ -                                        .filter( -                                            year=datetime.date.today().year) -            current_realisation_year_ope = Operation.objects\ -                .filter(**operation_type)\ -                .filter(start_date__year=datetime.date.today().year) -            res_keys = [('area_realised', current_realisation_year_ope)] +                dct_res["by_realisation_year"].append((lbl, years)) + +            current_year_ope = Operation.objects.filter(**operation_type).filter( +                year=datetime.date.today().year +            ) +            current_realisation_year_ope = Operation.objects.filter( +                **operation_type +            ).filter(start_date__year=datetime.date.today().year) +            res_keys = [("area_realised", current_realisation_year_ope)]              if dct_res == self.survey: -                res_keys.append(('area', -                                 current_year_ope)) +                res_keys.append(("area", current_year_ope))              for res_key, base_ope in res_keys:                  dct_res[res_key] = []                  for fltr_key in self.filters_keys:                      fltr, lbl = filters[fltr_key], filters_label[fltr_key] -                    area_res = base_ope.filter(**fltr)\ -                        .annotate(number=Sum('surface')).all() +                    area_res = ( +                        base_ope.filter(**fltr).annotate(number=Sum("surface")).all() +                    )                      val = 0                      if area_res:                          val = (area_res[0].number or 0) / 10000.0                      dct_res[res_key].append(val)              # TODO... -            res_keys = [('manday_realised', current_realisation_year_ope)] +            res_keys = [("manday_realised", current_realisation_year_ope)]              if dct_res == self.survey: -                res_keys.append(('manday', -                                 current_year_ope)) +                res_keys.append(("manday", current_year_ope))              for res_key, base_ope in res_keys:                  dct_res[res_key] = []                  for fltr_key in self.filters_keys: -                    dct_res[res_key].append('-') +                    dct_res[res_key].append("-")              # TODO... -            res_keys = [('mandayhect_realised', current_realisation_year_ope)] +            res_keys = [("mandayhect_realised", current_realisation_year_ope)]              if dct_res == self.survey: -                res_keys.append(('mandayhect', -                                 current_year_ope)) +                res_keys.append(("mandayhect", current_year_ope))              for res_key, base_ope in res_keys:                  dct_res[res_key] = []                  for fltr_key in self.filters_keys: -                    dct_res[res_key].append('-') +                    dct_res[res_key].append("-")              # TODO... -            dct_res['mandayhect_real_effective'] = '-' +            dct_res["mandayhect_real_effective"] = "-"              if dct_res == self.survey: -                dct_res['mandayhect_effective'] = '-' +                dct_res["mandayhect_effective"] = "-" -            res_keys = [('org_realised', current_realisation_year_ope)] +            res_keys = [("org_realised", current_realisation_year_ope)]              if dct_res == self.survey: -                res_keys.append(('org', current_year_ope)) +                res_keys.append(("org", current_year_ope))              for res_key, base_ope in res_keys: -                org_res = base_ope.filter(scientist__attached_to__isnull=False)\ -                    .values('scientist__attached_to', -                            'scientist__attached_to__name')\ -                    .annotate(area=Sum('surface'))\ -                    .order_by('scientist__attached_to__name').all() +                org_res = ( +                    base_ope.filter(scientist__attached_to__isnull=False) +                    .values("scientist__attached_to", "scientist__attached_to__name") +                    .annotate(area=Sum("surface")) +                    .order_by("scientist__attached_to__name") +                    .all() +                )                  # TODO: man-days, man-days/hectare                  dct_res[res_key] = []                  for vals in org_res: -                    vals['area'] = (vals['area'] or 0) / 10000.0 +                    vals["area"] = (vals["area"] or 0) / 10000.0                      dct_res[res_key].append(vals)              year_ope = Operation.objects.filter(**operation_type) -            res_keys = ['org_by_year'] +            res_keys = ["org_by_year"]              if dct_res == self.survey: -                res_keys.append('org_by_year_realised') -            q = year_ope.values('scientist__attached_to', -                                'scientist__attached_to__name')\ -                .filter(scientist__attached_to__isnull=False)\ -                .order_by('scientist__attached_to__name').distinct() -            org_list = [(org['scientist__attached_to'], -                         org['scientist__attached_to__name']) for org in q] +                res_keys.append("org_by_year_realised") +            q = ( +                year_ope.values( +                    "scientist__attached_to", "scientist__attached_to__name" +                ) +                .filter(scientist__attached_to__isnull=False) +                .order_by("scientist__attached_to__name") +                .distinct() +            ) +            org_list = [ +                (org["scientist__attached_to"], org["scientist__attached_to__name"]) +                for org in q +            ]              # org_list_dct = dict(org_list)              for res_key in res_keys:                  dct_res[res_key] = []                  years = self.years -                if res_key == 'org_by_year_realised': +                if res_key == "org_by_year_realised":                      years = self.realisation_years                  for org_id, org_label in org_list: -                    org_res = year_ope.filter( -                        scientist__attached_to__pk=org_id) -                    key_date = '' -                    if res_key == 'org_by_year': -                        org_res = org_res.values('year') -                        key_date = 'year' +                    org_res = year_ope.filter(scientist__attached_to__pk=org_id) +                    key_date = "" +                    if res_key == "org_by_year": +                        org_res = org_res.values("year") +                        key_date = "year"                      else: -                        org_res = org_res\ -                            .extra({'date': "date_trunc('year', start_date)"})\ -                            .values('date')\ +                        org_res = ( +                            org_res.extra({"date": "date_trunc('year', start_date)"}) +                            .values("date")                              .filter(start_date__isnull=False) -                        key_date = 'date' -                    org_res = org_res.annotate(area=Sum('surface'), -                                               cost=Sum('cost')) +                        ) +                        key_date = "date" +                    org_res = org_res.annotate(area=Sum("surface"), cost=Sum("cost"))                      years_dct = {}                      for yr in org_res.all(): -                        area = (yr['area'] if yr['area'] else 0) / 10000.0 -                        cost = yr['cost'] if yr['cost'] else 0 +                        area = (yr["area"] if yr["area"] else 0) / 10000.0 +                        cost = yr["cost"] if yr["cost"] else 0                          years_dct[yr[key_date]] = (area, cost)                      r_years = []                      for yr in years: @@ -3029,35 +3394,37 @@ class OperationDashboard:                      area_sums.append(sum_area)                      cost_means.append(sum_cost / len(vals))                      cost_sums.append(sum_cost) -                dct_res[res_key + '_area_mean'] = area_means -                dct_res[res_key + '_area_sum'] = area_sums -                dct_res[res_key + '_cost_mean'] = cost_means -                dct_res[res_key + '_cost_mean'] = cost_sums +                dct_res[res_key + "_area_mean"] = area_means +                dct_res[res_key + "_area_sum"] = area_sums +                dct_res[res_key + "_cost_mean"] = cost_means +                dct_res[res_key + "_cost_mean"] = cost_sums              if dct_res == self.survey: -                self.survey['effective'] = [] +                self.survey["effective"] = []                  for yr in self.years: -                    year_res = Operation.objects\ -                        .filter(scientist__isnull=False, year=yr, -                                operation_type__txt_idx__in=ope_types)\ -                        .annotate(number=Sum('surface'), mean=Avg('surface')) +                    year_res = Operation.objects.filter( +                        scientist__isnull=False, +                        year=yr, +                        operation_type__txt_idx__in=ope_types, +                    ).annotate(number=Sum("surface"), mean=Avg("surface"))                      nb = year_res[0].number if year_res.count() else 0                      nb = nb if nb else 0                      mean = year_res[0].mean if year_res.count() else 0                      mean = mean if mean else 0 -                    self.survey['effective'].append((nb, mean)) +                    self.survey["effective"].append((nb, mean))              # TODO:Man-Days/hectare by Year              # CHECK: month of realisation or month? -            dct_res['by_month'] = [] +            dct_res["by_month"] = []              for fltr_key in self.filters_keys:                  fltr, lbl = filters[fltr_key], filters_label[fltr_key]                  fltr.update(operation_type) -                month_res = by_realisation_month\ -                    .filter(**fltr)\ -                    .annotate(number=Count('pk'))\ -                    .order_by('-date') +                month_res = ( +                    by_realisation_month.filter(**fltr) +                    .annotate(number=Count("pk")) +                    .order_by("-date") +                )                  month_dct = {}                  for mt in month_res.all():                      month_dct[mt.date] = mt.number @@ -3068,26 +3435,30 @@ class OperationDashboard:                          months.append(month_dct[date])                      else:                          months.append(0) -                dct_res['by_month'].append((lbl, months)) +                dct_res["by_month"].append((lbl, months)) -            operation_type = {'operation_type__txt_idx__in': ope_types} +            operation_type = {"operation_type__txt_idx__in": ope_types}              self.departments = [ -                (fd['department__pk'], fd['department__label']) -                for fd in OperationByDepartment -                .objects.filter(department__isnull=False) -                .values('department__label', 'department__pk') -                .order_by('department__label').distinct()] -            dct_res['by_dpt'] = [] +                (fd["department__pk"], fd["department__label"]) +                for fd in OperationByDepartment.objects.filter(department__isnull=False) +                .values("department__label", "department__pk") +                .order_by("department__label") +                .distinct() +            ] +            dct_res["by_dpt"] = []              for dpt_id, dpt_label in self.departments: -                vals = OperationByDepartment.objects\ -                    .filter(department__pk=dpt_id, -                            operation__operation_type__txt_idx__in=ope_types)\ -                    .values('department__pk', 'operation__year')\ -                    .annotate(number=Count('operation'))\ -                    .order_by('operation__year') +                vals = ( +                    OperationByDepartment.objects.filter( +                        department__pk=dpt_id, +                        operation__operation_type__txt_idx__in=ope_types, +                    ) +                    .values("department__pk", "operation__year") +                    .annotate(number=Count("operation")) +                    .order_by("operation__year") +                )                  dct_years = {}                  for v in vals: -                    dct_years[v['operation__year']] = v['number'] +                    dct_years[v["operation__year"]] = v["number"]                  years = []                  for y in self.years:                      if y in dct_years: @@ -3095,29 +3466,34 @@ class OperationDashboard:                      else:                          years.append(0)                  years.append(sum(years)) -                dct_res['by_dpt'].append((dpt_label, years)) -            dct_res['effective_by_dpt'] = [] +                dct_res["by_dpt"].append((dpt_label, years)) +            dct_res["effective_by_dpt"] = []              for dpt_id, dpt_label in self.departments: -                vals = OperationByDepartment.objects\ -                    .filter(department__pk=dpt_id, -                            operation__scientist__isnull=False, -                            operation__operation_type__txt_idx__in=ope_types)\ -                    .values('department__pk', 'operation__year')\ -                    .annotate(number=Count('operation'), -                              area=Sum('operation__surface'), -                              fnap=Sum('operation__fnap_cost'), -                              cost=Sum('operation__cost'))\ -                    .order_by('operation__year') +                vals = ( +                    OperationByDepartment.objects.filter( +                        department__pk=dpt_id, +                        operation__scientist__isnull=False, +                        operation__operation_type__txt_idx__in=ope_types, +                    ) +                    .values("department__pk", "operation__year") +                    .annotate( +                        number=Count("operation"), +                        area=Sum("operation__surface"), +                        fnap=Sum("operation__fnap_cost"), +                        cost=Sum("operation__cost"), +                    ) +                    .order_by("operation__year") +                )                  dct_years = {}                  for v in vals:                      values = [] -                    for k in ('number', 'area', 'cost', 'fnap'): +                    for k in ("number", "area", "cost", "fnap"):                          value = v[k] or 0 -                        if k == 'area': +                        if k == "area":                              value /= 10000.0                          values.append(value) -                    dct_years[v['operation__year']] = values +                    dct_years[v["operation__year"]] = values                  years = []                  for y in self.years:                      if y in dct_years: @@ -3126,47 +3502,67 @@ class OperationDashboard:                          years.append((0, 0, 0, 0))                  nbs, areas, costs, fnaps = zip(*years)                  years.append((sum(nbs), sum(areas), sum(costs), sum(fnaps))) -                dct_res['effective_by_dpt'].append((dpt_label, years)) +                dct_res["effective_by_dpt"].append((dpt_label, years))              OperationTown = Operation.towns.through -            query = OperationTown.objects\ -                .filter(operation__scientist__isnull=False, -                        operation__operation_type__txt_idx__in=ope_types)\ -                .values('town__name', 'town__departement__number')\ -                .annotate(nb=Count('operation'))\ -                .order_by('-nb', 'town__name')[:10] -            dct_res['towns'] = [] +            query = ( +                OperationTown.objects.filter( +                    operation__scientist__isnull=False, +                    operation__operation_type__txt_idx__in=ope_types, +                ) +                .values("town__name", "town__departement__number") +                .annotate(nb=Count("operation")) +                .order_by("-nb", "town__name")[:10] +            ) +            dct_res["towns"] = []              for r in query: -                dct_res['towns'].append(("%s (%s)" % (r['town__name'], -                                         r['town__departement__number']), -                                         r['nb'])) +                dct_res["towns"].append( +                    ( +                        "%s (%s)" % (r["town__name"], r["town__departement__number"]), +                        r["nb"], +                    ) +                )              if dct_res == self.survey: -                query = OperationTown.objects\ -                    .filter(operation__scientist__isnull=False, -                            operation__operation_type__txt_idx__in=ope_types, -                            operation__surface__isnull=False)\ -                    .values('town__name', 'town__departement__number')\ -                    .annotate(nb=Sum('operation__surface'))\ -                    .order_by('-nb', 'town__name')[:10] -                dct_res['towns_surface'] = [] +                query = ( +                    OperationTown.objects.filter( +                        operation__scientist__isnull=False, +                        operation__operation_type__txt_idx__in=ope_types, +                        operation__surface__isnull=False, +                    ) +                    .values("town__name", "town__departement__number") +                    .annotate(nb=Sum("operation__surface")) +                    .order_by("-nb", "town__name")[:10] +                ) +                dct_res["towns_surface"] = []                  for r in query: -                    dct_res['towns_surface'].append(("%s (%s)" % ( -                        r['town__name'], r['town__departement__number']), -                        r['nb'])) +                    dct_res["towns_surface"].append( +                        ( +                            "%s (%s)" +                            % (r["town__name"], r["town__departement__number"]), +                            r["nb"], +                        ) +                    )              else: -                query = OperationTown.objects\ -                    .filter(operation__scientist__isnull=False, -                            operation__operation_type__txt_idx__in=ope_types, -                            operation__cost__isnull=False)\ -                    .values('town__name', 'town__departement__number')\ -                    .annotate(nb=Sum('operation__cost'))\ -                    .order_by('-nb', 'town__name')[:10] -                dct_res['towns_cost'] = [] +                query = ( +                    OperationTown.objects.filter( +                        operation__scientist__isnull=False, +                        operation__operation_type__txt_idx__in=ope_types, +                        operation__cost__isnull=False, +                    ) +                    .values("town__name", "town__departement__number") +                    .annotate(nb=Sum("operation__cost")) +                    .order_by("-nb", "town__name")[:10] +                ) +                dct_res["towns_cost"] = []                  for r in query: -                    dct_res['towns_cost'].append(("%s (%s)" % ( -                        r['town__name'], r['town__departement__number']), -                        r['nb'])) +                    dct_res["towns_cost"].append( +                        ( +                            "%s (%s)" +                            % (r["town__name"], r["town__departement__number"]), +                            r["nb"], +                        ) +                    )  class OperationTypeOld(GeneralType): @@ -3176,4 +3572,4 @@ class OperationTypeOld(GeneralType):      class Meta:          verbose_name = _("Operation type old")          verbose_name_plural = _("Operation types old") -        ordering = ['-preventive', 'order', 'label'] +        ordering = ["-preventive", "order", "label"] diff --git a/archaeological_operations/serializers.py b/archaeological_operations/serializers.py index 91b0b1b0f..5fee27a4e 100644 --- a/archaeological_operations/serializers.py +++ b/archaeological_operations/serializers.py @@ -1,13 +1,15 @@  from django.db.models import Q -from ishtar_common.serializers_utils import generic_get_results, \ -    archive_serialization +from ishtar_common.serializers_utils import generic_get_results, archive_serialization  from archaeological_operations import models  OPERATION_MODEL_LIST = [ -    models.ArchaeologicalSite, models.Operation, models.RecordRelations, -    models.Parcel, models.ParcelOwner +    models.ArchaeologicalSite, +    models.Operation, +    models.RecordRelations, +    models.Parcel, +    models.ParcelOwner,  ]  # TODO: administrativ acts, associated documents @@ -20,17 +22,30 @@ def generate_warehouse_queryset(ids):      for container_key in ("container", "container_ref"):          for warehouse_key in ("location", "responsible"): -            q_s = Q(** -                    {"operations__{}__{}__{}__id__in".format( -                        base_query_key, container_key, warehouse_key): ids}) -            q_o = Q(** -                    {"{}__{}__{}__id__in".format( -                        base_query_key, container_key, warehouse_key): ids}) -            q_r = Q(** -                    {"left_record__{}__{}__{}__id__in".format( -                        base_query_key, container_key, warehouse_key): ids, -                     "right_record__{}__{}__{}__id__in".format( -                         base_query_key, container_key, warehouse_key): ids}) +            q_s = Q( +                **{ +                    "operations__{}__{}__{}__id__in".format( +                        base_query_key, container_key, warehouse_key +                    ): ids +                } +            ) +            q_o = Q( +                **{ +                    "{}__{}__{}__id__in".format( +                        base_query_key, container_key, warehouse_key +                    ): ids +                } +            ) +            q_r = Q( +                **{ +                    "left_record__{}__{}__{}__id__in".format( +                        base_query_key, container_key, warehouse_key +                    ): ids, +                    "right_record__{}__{}__{}__id__in".format( +                        base_query_key, container_key, warehouse_key +                    ): ids, +                } +            )          if not q_archaeological_site:              q_archaeological_site = q_s              q_operation = q_o @@ -41,81 +56,83 @@ def generate_warehouse_queryset(ids):              q_record_relation |= q_r      result_queryset = { -        models.ArchaeologicalSite.__name__: -            models.ArchaeologicalSite.objects.filter( -                q_archaeological_site -            ), -        models.Operation.__name__: models.Operation.objects.filter( -            q_operation), -        models.RecordRelations.__name__: -            models.RecordRelations.objects.filter(q_record_relation), +        models.ArchaeologicalSite.__name__: models.ArchaeologicalSite.objects.filter( +            q_archaeological_site +        ), +        models.Operation.__name__: models.Operation.objects.filter(q_operation), +        models.RecordRelations.__name__: models.RecordRelations.objects.filter( +            q_record_relation +        ),      }      return result_queryset -def operation_serialization(archive=False, return_empty_types=False, -                            archive_name=None, operation_queryset=None, -                            site_queryset=None, cr_queryset=None, -                            find_queryset=None, warehouse_queryset=None, -                            get_queryset=False, no_geo=True, -                            put_locks=False, lock_user=None): +def operation_serialization( +    archive=False, +    return_empty_types=False, +    archive_name=None, +    operation_queryset=None, +    site_queryset=None, +    cr_queryset=None, +    find_queryset=None, +    warehouse_queryset=None, +    get_queryset=False, +    no_geo=True, +    put_locks=False, +    lock_user=None, +):      result_queryset = {}      if operation_queryset:          operation_ids = operation_queryset.values_list("id", flat=True)          result_queryset = {              models.Operation.__name__: operation_queryset, -            models.RecordRelations.__name__: -                models.RecordRelations.objects.filter( -                    left_record__id__in=operation_ids, -                    right_record__id__in=operation_ids, -                ), -            models.ArchaeologicalSite.__name__: -                models.ArchaeologicalSite.objects.filter( -                    operations__id__in=operation_ids -                    ) +            models.RecordRelations.__name__: models.RecordRelations.objects.filter( +                left_record__id__in=operation_ids, +                right_record__id__in=operation_ids, +            ), +            models.ArchaeologicalSite.__name__: models.ArchaeologicalSite.objects.filter( +                operations__id__in=operation_ids +            ),          }      elif site_queryset:          site_ids = site_queryset.values_list("id", flat=True)          result_queryset = {              models.ArchaeologicalSite.__name__: site_queryset,              models.Operation.__name__: models.Operation.objects.filter( -                archaeological_sites__id__in=site_ids), -            models.RecordRelations.__name__: -                models.RecordRelations.objects.filter( -                    left_record__archaeological_sites__id__in=site_ids, -                    right_record__archaeological_sites__id__in=site_ids, -                ), +                archaeological_sites__id__in=site_ids +            ), +            models.RecordRelations.__name__: models.RecordRelations.objects.filter( +                left_record__archaeological_sites__id__in=site_ids, +                right_record__archaeological_sites__id__in=site_ids, +            ),          }      elif cr_queryset:          cr_ids = cr_queryset.values_list("id", flat=True)          result_queryset = { -            models.ArchaeologicalSite.__name__: -                models.ArchaeologicalSite.objects.filter( -                    operations__context_record__id__in=cr_ids), +            models.ArchaeologicalSite.__name__: models.ArchaeologicalSite.objects.filter( +                operations__context_record__id__in=cr_ids +            ),              models.Operation.__name__: models.Operation.objects.filter( -                context_record__id__in=cr_ids), -            models.RecordRelations.__name__: -                models.RecordRelations.objects.filter( -                    left_record__context_record__id__in=cr_ids, -                    right_record__context_record__id__in=cr_ids, -                ), +                context_record__id__in=cr_ids +            ), +            models.RecordRelations.__name__: models.RecordRelations.objects.filter( +                left_record__context_record__id__in=cr_ids, +                right_record__context_record__id__in=cr_ids, +            ),          }      elif find_queryset:          find_ids = find_queryset.values_list("id", flat=True)          result_queryset = { -            models.ArchaeologicalSite.__name__: -                models.ArchaeologicalSite.objects.filter( -                    operations__context_record__base_finds__find__id__in -                    =find_ids), +            models.ArchaeologicalSite.__name__: models.ArchaeologicalSite.objects.filter( +                operations__context_record__base_finds__find__id__in=find_ids +            ),              models.Operation.__name__: models.Operation.objects.filter( -                context_record__base_finds__find__id__in=find_ids), -            models.RecordRelations.__name__: -                models.RecordRelations.objects.filter( -                    left_record__context_record__base_finds__find__id__in= -                    find_ids, -                    right_record__context_record__base_finds__find__id__in= -                    find_ids, -                ), +                context_record__base_finds__find__id__in=find_ids +            ), +            models.RecordRelations.__name__: models.RecordRelations.objects.filter( +                left_record__context_record__base_finds__find__id__in=find_ids, +                right_record__context_record__base_finds__find__id__in=find_ids, +            ),          }      elif warehouse_queryset:          warehouse_ids = warehouse_queryset.values_list("id", flat=True) @@ -123,8 +140,12 @@ def operation_serialization(archive=False, return_empty_types=False,      if get_queryset:          return result_queryset -    result = generic_get_results(OPERATION_MODEL_LIST, "operations", -                                 result_queryset=result_queryset, no_geo=no_geo) +    result = generic_get_results( +        OPERATION_MODEL_LIST, +        "operations", +        result_queryset=result_queryset, +        no_geo=no_geo, +    )      if put_locks:          for model in OPERATION_MODEL_LIST: @@ -136,7 +157,10 @@ def operation_serialization(archive=False, return_empty_types=False,              q.update(locked=True, lock_user=lock_user)      full_archive = archive_serialization( -        result, archive_dir="operations", archive=archive, -        return_empty_types=return_empty_types, archive_name=archive_name, +        result, +        archive_dir="operations", +        archive=archive, +        return_empty_types=return_empty_types, +        archive_name=archive_name,      )      return full_archive diff --git a/archaeological_operations/tests.py b/archaeological_operations/tests.py index 1e85b4f5a..3f4e73639 100644 --- a/archaeological_operations/tests.py +++ b/archaeological_operations/tests.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3  # -*- coding: utf-8 -*-  # Copyright (C) 2012-2017 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> @@ -42,55 +42,102 @@ from ishtar_common.views import document_deletion_steps  from ishtar_common.serializers import document_serialization  from archaeological_operations import views, serializers -from ishtar_common.models import OrganizationType, Organization, ItemKey, \ -    ImporterType, IshtarUser, TargetKey, ImporterModel, IshtarSiteProfile, \ -    Town, ImporterColumn, Person, Author, SourceType, AuthorType, \ -    DocumentTemplate, PersonType, TargetKeyGroup, JsonDataField, \ -    JsonDataSection, ImportTarget, FormaterType, CustomForm, ExcludedField, \ -    UserProfile, ProfileType, Area, CustomFormJsonField, get_current_profile, \ -    Document, ValueFormater, Regexp +from ishtar_common.models import ( +    OrganizationType, +    Organization, +    ItemKey, +    ImporterType, +    IshtarUser, +    TargetKey, +    ImporterModel, +    IshtarSiteProfile, +    Town, +    ImporterColumn, +    Person, +    Author, +    SourceType, +    AuthorType, +    DocumentTemplate, +    PersonType, +    TargetKeyGroup, +    JsonDataField, +    JsonDataSection, +    ImportTarget, +    FormaterType, +    CustomForm, +    ExcludedField, +    UserProfile, +    ProfileType, +    Area, +    CustomFormJsonField, +    get_current_profile, +    Document, +    ValueFormater, +    Regexp, +)  from archaeological_files.models import File, FileType  from archaeological_context_records.models import Unit, ContextRecord  from ishtar_common import forms_common -from ishtar_common.tests import WizardTest, WizardTestFormData as FormData, \ -    create_superuser, create_user, TestCase, OPERATION_FIXTURES, \ -    AutocompleteTestBase, AcItem, OPERATION_TOWNS_FIXTURES, FILE_FIXTURES, \ -    COMMON_FIXTURES, GenericSerializationTest, WAREHOUSE_FIXTURES, SearchText +from ishtar_common.tests import ( +    WizardTest, +    WizardTestFormData as FormData, +    create_superuser, +    create_user, +    TestCase, +    OPERATION_FIXTURES, +    AutocompleteTestBase, +    AcItem, +    OPERATION_TOWNS_FIXTURES, +    FILE_FIXTURES, +    COMMON_FIXTURES, +    GenericSerializationTest, +    WAREHOUSE_FIXTURES, +    SearchText, +)  from ishtar_common.serializers import restore_serialized  class FileInit(object):      def login_as_superuser(self): -        self.client.login(username='username', password='tralala') +        self.client.login(username="username", password="tralala")      def create_file(self):          self.extra_models, self.model_list = {}, [] -        self.user, created = User.objects.get_or_create(username='username', -                                                        is_superuser=True) -        self.user.set_password('tralala') +        self.user, created = User.objects.get_or_create( +            username="username", is_superuser=True +        ) +        self.user.set_password("tralala")          self.user.save() -        self.o_user, created = User.objects.get_or_create(username='ousername') +        self.o_user, created = User.objects.get_or_create(username="ousername")          person_type, created = PersonType.objects.get_or_create( -            label='Test person type', txt_idx='test_person', -            available=True) -        self.extra_models['person_type'] = person_type +            label="Test person type", txt_idx="test_person", available=True +        ) +        self.extra_models["person_type"] = person_type          self.model_list.append(person_type) -        person = models.Person(surname='Surname', name='Name', -                               history_modifier=self.o_user) +        person = models.Person( +            surname="Surname", name="Name", history_modifier=self.o_user +        )          person.save() -        self.extra_models['person'] = person +        self.extra_models["person"] = person          self.model_list.append(person)          file_type, created = FileType.objects.get_or_create( -            label='Test file type', txt_idx='test_file', available=True) -        self.extra_models['file_type'] = file_type +            label="Test file type", txt_idx="test_file", available=True +        ) +        self.extra_models["file_type"] = file_type          self.model_list.append(file_type) -        dct = {'year': 2010, 'numeric_reference': 1000, 'file_type': file_type, -               'internal_reference': 'UNIT_testÉ ?', 'in_charge': person, -               'history_modifier': self.o_user, 'total_surface': 10000} +        dct = { +            "year": 2010, +            "numeric_reference": 1000, +            "file_type": file_type, +            "internal_reference": "UNIT_testÉ ?", +            "in_charge": person, +            "history_modifier": self.o_user, +            "total_surface": 10000, +        }          self.item = File(**dct)          self.item.save() @@ -101,29 +148,36 @@ class ImportTest(object):          self.ishtar_user = IshtarUser.objects.get(pk=self.user.pk)      def set_target_key(self, target, key, value, imp=None): -        keys = {'target__target': target, 'key': key} +        keys = {"target__target": target, "key": key}          if imp: -            keys['associated_import'] = imp +            keys["associated_import"] = imp          tg = TargetKey.objects.get(**keys)          tg.value = value          tg.is_set = True          tg.save() -    def init_ope_import(self, filename='MCC-operations-example.csv', -                        sep=","): +    def init_ope_import(self, filename="MCC-operations-example.csv", sep=","):          mcc_operation = ImporterType.objects.get(name="MCC - Opérations")          mcc_operation_file = open( -            settings.ROOT_PATH + -            '../archaeological_operations/tests/' + filename, -            'rb') -        file_dict = {'imported_file': SimpleUploadedFile( -            mcc_operation_file.name, mcc_operation_file.read())} +            settings.ROOT_PATH + "../archaeological_operations/tests/" + filename, "rb" +        ) +        file_dict = { +            "imported_file": SimpleUploadedFile( +                mcc_operation_file.name, mcc_operation_file.read() +            ) +        }          group, c = TargetKeyGroup.objects.get_or_create(name="My group") -        post_dict = {'importer_type': mcc_operation.pk, 'skip_lines': 1, -                     "encoding": 'utf-8', "name": 'init_ope_import', -                     "associated_group": group.pk, "csv_sep": sep} -        form = forms_common.NewImportForm(data=post_dict, files=file_dict, -                                          user=self.user) +        post_dict = { +            "importer_type": mcc_operation.pk, +            "skip_lines": 1, +            "encoding": "utf-8", +            "name": "init_ope_import", +            "associated_group": group.pk, +            "csv_sep": sep, +        } +        form = forms_common.NewImportForm( +            data=post_dict, files=file_dict, user=self.user +        )          form.is_valid()          return mcc_operation, form @@ -136,20 +190,22 @@ class ImportTest(object):              ik.delete()          # target for this import -        target = TargetKey.objects.filter( -            target__target='operation_type').order_by('-pk').all()[0] -        target.value = models.OperationType.objects.get( -            txt_idx='prog_excavation').pk +        target = ( +            TargetKey.objects.filter(target__target="operation_type") +            .order_by("-pk") +            .all()[0] +        ) +        target.value = models.OperationType.objects.get(txt_idx="prog_excavation").pk          target.is_set = True          target.associated_import = imp          target.save()          # target for all users -        tgs = list(TargetKey.objects.filter(key='gallo-romain').all()) +        tgs = list(TargetKey.objects.filter(key="gallo-romain").all())          for tg in tgs[1:]:              tg.delete()          target2 = tgs[0] -        gallo = models.Period.objects.get(txt_idx='gallo-roman') +        gallo = models.Period.objects.get(txt_idx="gallo-roman")          target2.value = gallo.pk          target2.is_set = True          target2.associated_import = None @@ -158,11 +214,11 @@ class ImportTest(object):          target2.save()          # target for this user -        tgs = list(TargetKey.objects.filter(key='age-du-fer').all()) +        tgs = list(TargetKey.objects.filter(key="age-du-fer").all())          for tg in tgs[1:]:              tg.delete()          target3 = tgs[0] -        iron = models.Period.objects.get(txt_idx='iron-age') +        iron = models.Period.objects.get(txt_idx="iron-age")          target3.value = iron.pk          target3.is_set = True          target3.associated_import = None @@ -173,11 +229,11 @@ class ImportTest(object):          # target for another user          username, password, user = create_user()          another_user = IshtarUser.objects.get(pk=user.pk) -        tgs = list(TargetKey.objects.filter(key='neolithik').all()) +        tgs = list(TargetKey.objects.filter(key="neolithik").all())          for tg in tgs[1:]:              tg.delete()          target4 = tgs[0] -        neo = models.Period.objects.get(txt_idx='neolithic') +        neo = models.Period.objects.get(txt_idx="neolithic")          target4.value = neo.pk          target4.is_set = True          target4.associated_import = None @@ -186,11 +242,11 @@ class ImportTest(object):          target4.save()          # target for the current group -        tgs = list(TargetKey.objects.filter(key='moderne').all()) +        tgs = list(TargetKey.objects.filter(key="moderne").all())          for tg in tgs[1:]:              tg.delete()          target5 = tgs[0] -        modern = models.Period.objects.get(txt_idx='modern') +        modern = models.Period.objects.get(txt_idx="modern")          target5.value = modern.pk          target5.is_set = True          target5.associated_import = None @@ -211,16 +267,23 @@ class ImportTest(object):          self.init_ope()          mcc_parcel = ImporterType.objects.get(name="MCC - Parcelles")          mcc_file = open( -            settings.ROOT_PATH + -            '../archaeological_operations/tests/MCC-parcelles-example.csv', -            'rb') -        file_dict = {'imported_file': SimpleUploadedFile(mcc_file.name, -                                                         mcc_file.read())} -        post_dict = {'importer_type': mcc_parcel.pk, 'skip_lines': 1, -                     "encoding": 'utf-8', "name": 'init_parcel_import', -                     "csv_sep": ","} -        form = forms_common.NewImportForm(data=post_dict, files=file_dict, -                                          user=self.user) +            settings.ROOT_PATH +            + "../archaeological_operations/tests/MCC-parcelles-example.csv", +            "rb", +        ) +        file_dict = { +            "imported_file": SimpleUploadedFile(mcc_file.name, mcc_file.read()) +        } +        post_dict = { +            "importer_type": mcc_parcel.pk, +            "skip_lines": 1, +            "encoding": "utf-8", +            "name": "init_parcel_import", +            "csv_sep": ",", +        } +        form = forms_common.NewImportForm( +            data=post_dict, files=file_dict, user=self.user +        )          form.is_valid()          return mcc_parcel, form @@ -234,25 +297,32 @@ class ImportTest(object):          self.init_parcel()          mcc = ImporterType.objects.get(name="MCC - UE")          mcc_file = open( -            settings.ROOT_PATH + -            '../archaeological_context_records/tests/' -            'MCC-context-records-example.csv', 'rb') -        file_dict = {'imported_file': SimpleUploadedFile(mcc_file.name, -                                                         mcc_file.read())} -        post_dict = {'importer_type': mcc.pk, 'skip_lines': 1, -                     "encoding": 'utf-8', "name": 'init_context_record_import', -                     'csv_sep': ","} -        form = forms_common.NewImportForm(data=post_dict, files=file_dict, -                                          user=self.user) +            settings.ROOT_PATH + "../archaeological_context_records/tests/" +            "MCC-context-records-example.csv", +            "rb", +        ) +        file_dict = { +            "imported_file": SimpleUploadedFile(mcc_file.name, mcc_file.read()) +        } +        post_dict = { +            "importer_type": mcc.pk, +            "skip_lines": 1, +            "encoding": "utf-8", +            "name": "init_context_record_import", +            "csv_sep": ",", +        } +        form = forms_common.NewImportForm( +            data=post_dict, files=file_dict, user=self.user +        )          form.is_valid()          return mcc, form      def init_cr_targetkey(self, imp): -        hc = Unit.objects.get(txt_idx='not_in_context').pk -        self.set_target_key('unit', 'hc', hc, imp=imp) -        self.set_target_key('unit', 'hors-contexte', hc, imp=imp) -        layer = Unit.objects.get(txt_idx='negative').pk -        self.set_target_key('unit', 'couche', layer, imp=imp) +        hc = Unit.objects.get(txt_idx="not_in_context").pk +        self.set_target_key("unit", "hc", hc, imp=imp) +        self.set_target_key("unit", "hors-contexte", hc, imp=imp) +        layer = Unit.objects.get(txt_idx="negative").pk +        self.set_target_key("unit", "couche", layer, imp=imp)      def init_context_record(self):          mcc, form = self.init_context_record_import() @@ -294,31 +364,31 @@ class ImportOperationTest(ImportTest, TestCase):          current_person_nb = Person.objects.count()          self.assertEqual(current_person_nb, first_person_nb + 1)          # and well imported -        last_ope = models.Operation.objects.order_by('-pk').all()[0] +        last_ope = models.Operation.objects.order_by("-pk").all()[0]          self.assertEqual(last_ope.name, "Oppìdum de Paris") -        self.assertEqual(last_ope.code_patriarche, '4200') -        self.assertEqual(last_ope.operation_type.txt_idx, 'prog_excavation') +        self.assertEqual(last_ope.code_patriarche, "4200") +        self.assertEqual(last_ope.operation_type.txt_idx, "prog_excavation")          self.assertEqual(last_ope.periods.count(), 3)          periods = [period.txt_idx for period in last_ope.periods.all()] -        self.assertIn('iron-age', periods) -        self.assertIn('gallo-roman', periods) +        self.assertIn("iron-age", periods) +        self.assertIn("gallo-roman", periods)          # target key set for another user -        self.assertNotIn('neolithic', periods) +        self.assertNotIn("neolithic", periods)          # a second importation will be not possible: no two same patriarche          # code          impt.importation() -        self.assertEqual(last_ope, -                         models.Operation.objects.order_by('-pk').all()[0]) +        self.assertEqual(last_ope, models.Operation.objects.order_by("-pk").all()[0])      def test_import_bad_encoding(self): -        self.init_ope_import('MCC-operations-example-bad-encoding.csv') +        self.init_ope_import("MCC-operations-example-bad-encoding.csv")      def test_import_semi_colon_sep(self):          first_ope_nb = models.Operation.objects.count()          importer, form = self.init_ope_import( -            'MCC-operations-example-semi-colon.csv', sep=";") +            "MCC-operations-example-semi-colon.csv", sep=";" +        )          self.assertTrue(form.is_valid())          impt = form.save(self.ishtar_user)          impt.initialize() @@ -331,18 +401,22 @@ class ImportOperationTest(ImportTest, TestCase):      def test_import_multi_column_concat(self):          first_ope_nb = models.Operation.objects.count()          importer, form = self.init_ope_import( -            'MCC-operations-example-multi-col-periods.csv') -        col = ImporterColumn.objects.create(col_number=12, -                                            importer_type_id=importer.pk) +            "MCC-operations-example-multi-col-periods.csv" +        ) +        col = ImporterColumn.objects.create(col_number=12, importer_type_id=importer.pk)          period_imp = ImporterColumn.objects.get( -            col_number=9, -            importer_type_id=importer.pk) +            col_number=9, importer_type_id=importer.pk +        )          period_target = period_imp.targets.all()[0]          target = ImportTarget.objects.create( -            column=col, target=period_target.target, -            formater_type=period_target.formater_type, concat=True) +            column=col, +            target=period_target.target, +            formater_type=period_target.formater_type, +            concat=True, +        )          importer, form = self.init_ope_import( -            'MCC-operations-example-multi-col-periods.csv') +            "MCC-operations-example-multi-col-periods.csv" +        )          self.assertTrue(form.is_valid())          impt = form.save(self.ishtar_user) @@ -352,7 +426,7 @@ class ImportOperationTest(ImportTest, TestCase):          current_ope_nb = models.Operation.objects.count()          self.assertEqual(current_ope_nb, first_ope_nb + 2) -        modern = models.Period.objects.get(txt_idx='modern') +        modern = models.Period.objects.get(txt_idx="modern")          for ope in models.Operation.objects.order_by("-pk")[0:2]:              self.assertIn(modern, list(ope.periods.all()))          target.delete() @@ -361,8 +435,7 @@ class ImportOperationTest(ImportTest, TestCase):      def test_import_value_format(self):          importer, form = self.init_ope_import()          column = importer.columns.get(col_number=1) -        f = ValueFormater.objects.create(name="-", slug="-", -                                         format_string="oa-{}") +        f = ValueFormater.objects.create(name="-", slug="-", format_string="oa-{}")          column.value_format = f          column.save() @@ -372,11 +445,11 @@ class ImportOperationTest(ImportTest, TestCase):          self.init_ope_targetkey(imp=impt)          impt.importation()          self.assertEqual( -            models.Operation.objects.filter(code_patriarche='oa-4201').count(), -            1) +            models.Operation.objects.filter(code_patriarche="oa-4201").count(), 1 +        )          self.assertEqual( -            models.Operation.objects.filter(code_patriarche='oa-4200').count(), -            1) +            models.Operation.objects.filter(code_patriarche="oa-4200").count(), 1 +        )          f.delete()      def test_keys_limitation(self): @@ -428,13 +501,10 @@ class ImportOperationTest(ImportTest, TestCase):          self.init_ope_targetkey(imp=impt)          impt.importation()          self.assertEqual(len(impt.errors), 2) +        self.assertTrue("cody" in impt.errors[0]["error"])          self.assertTrue( -            "cody" in impt.errors[0]['error'] -        ) -        self.assertTrue( -            "Importer configuration error" in impt.errors[0]['error'] or -            "Erreur de configuration de l\'importeur" in -            impt.errors[0]['error'] +            "Importer configuration error" in impt.errors[0]["error"] +            or "Erreur de configuration de l'importeur" in impt.errors[0]["error"]          )      def test_model_limitation(self): @@ -450,15 +520,15 @@ class ImportOperationTest(ImportTest, TestCase):          current_ope_nb = models.Operation.objects.count()          self.assertEqual(current_ope_nb, init_ope_number + 2) -        for ope in models.Operation.objects.order_by('-pk').all()[:2]: +        for ope in models.Operation.objects.order_by("-pk").all()[:2]:              ope.delete()          importer, form = self.init_ope_import()          # add an inadequate model to make created_models non empty          importer.created_models.clear() -        importer.created_models.add(ImporterModel.objects.get( -            klass='ishtar_common.models.Organization' -        )) +        importer.created_models.add( +            ImporterModel.objects.get(klass="ishtar_common.models.Organization") +        )          impt = form.save(self.ishtar_user)          impt.initialize()          self.init_ope_targetkey(imp=impt) @@ -471,9 +541,11 @@ class ImportOperationTest(ImportTest, TestCase):          importer, form = self.init_ope_import()          # add operation model to allow creation          importer.created_models.clear() -        importer.created_models.add(ImporterModel.objects.get( -            klass='archaeological_operations.models.Operation' -        )) +        importer.created_models.add( +            ImporterModel.objects.get( +                klass="archaeological_operations.models.Operation" +            ) +        )          impt = form.save(self.ishtar_user)          impt.initialize()          self.init_ope_targetkey(imp=impt) @@ -489,23 +561,25 @@ class ImportOperationTest(ImportTest, TestCase):          mcc_operation = ImporterType.objects.get(name="MCC - Opérations")          generated_file = mcc_operation.get_libreoffice_template()          zip_file = zipfile.ZipFile(generated_file) -        self.assertIsNone(zip_file.testzip(), "Libreoffice template generated " -                                              "is not a correct zip file.") +        self.assertIsNone( +            zip_file.testzip(), +            "Libreoffice template generated " "is not a correct zip file.", +        )          filename = None          for name in zip_file.namelist(): -            if name == 'content.xml': +            if name == "content.xml":                  filename = name                  break          self.assertIsNotNone(filename)          # only check that all operation types are listed in the source file -        with tempfile.TemporaryDirectory(prefix='tmp-ishtar-') as tmpdir: +        with tempfile.TemporaryDirectory(prefix="tmp-ishtar-") as tmpdir:              imported_file = zip_file.extract(filename, tmpdir)              with open(imported_file) as content_file:                  content = content_file.read()                  for ope_type in models.OperationType.objects.all(): -                    ope_type = str(ope_type).replace("'", ''') +                    ope_type = str(ope_type).replace("'", "'")                      self.assertIn(ope_type, content)      def test_mcc_import_parcels(self): @@ -519,18 +593,16 @@ class ImportOperationTest(ImportTest, TestCase):          self.assertEqual(current_nb, old_nb + 3)          # and well imported -        last_parcels = models.Parcel.objects.order_by('-pk').all()[0:3] -        external_ids = sorted(['4200-59350-YY55', '4200-75101-XXXX', -                               '4201-59350-YY55']) -        parcel_numbers = sorted(['42', '55', '55']) -        sections = sorted(['ZX', 'YY', 'YY']) -        self.assertEqual(external_ids, -                         sorted([p.external_id for p in last_parcels])) -        self.assertEqual(parcel_numbers, -                         sorted([p.parcel_number for p in last_parcels])) -        self.assertEqual(sections, -                         sorted([p.section for p in last_parcels])) -        ope1 = models.Operation.objects.get(code_patriarche='4200') +        last_parcels = models.Parcel.objects.order_by("-pk").all()[0:3] +        external_ids = sorted(["4200-59350-YY55", "4200-75101-XXXX", "4201-59350-YY55"]) +        parcel_numbers = sorted(["42", "55", "55"]) +        sections = sorted(["ZX", "YY", "YY"]) +        self.assertEqual(external_ids, sorted([p.external_id for p in last_parcels])) +        self.assertEqual( +            parcel_numbers, sorted([p.parcel_number for p in last_parcels]) +        ) +        self.assertEqual(sections, sorted([p.section for p in last_parcels])) +        ope1 = models.Operation.objects.get(code_patriarche="4200")          towns_ope = ope1.towns.all()          imported = [imp for acc, imp in impt.get_all_imported()]          for p in last_parcels: @@ -539,13 +611,14 @@ class ImportOperationTest(ImportTest, TestCase):          self.assertEqual(len(imported), len(last_parcels))          self.assertEqual(              models.Parcel.objects.get( -                parcel_number='55', section='YY', -                operation_id=ope1.pk).external_id, -            '4200-59350-YY55') +                parcel_number="55", section="YY", operation_id=ope1.pk +            ).external_id, +            "4200-59350-YY55", +        )          # cached_label update -        ope2 = models.Operation.objects.get(code_patriarche='4201') +        ope2 = models.Operation.objects.get(code_patriarche="4201")          self.assertIsNotNone(ope2.cached_label) -        self.assertIn('LILLE', ope2.cached_label.upper()) +        self.assertIn("LILLE", ope2.cached_label.upper())          # delete associated parcel with the import deletion          parcel_count = models.Parcel.objects.count()          impt.delete() @@ -553,105 +626,113 @@ class ImportOperationTest(ImportTest, TestCase):      def test_json_fields(self):          importer, form = self.init_ope_import("operations-with-json-fields.csv") -        col = ImporterColumn.objects.create(importer_type=importer, -                                            col_number=11) -        formater_type = FormaterType.objects.get( -            formater_type='IntegerFormater') +        col = ImporterColumn.objects.create(importer_type=importer, col_number=11) +        formater_type = FormaterType.objects.get(formater_type="IntegerFormater")          it = ImportTarget.objects.create( -            column=col, target='data__autre_refs__arbitraire', -            formater_type=formater_type) +            column=col, +            target="data__autre_refs__arbitraire", +            formater_type=formater_type, +        )          impt = form.save(self.ishtar_user)          impt.initialize()          self.init_ope_targetkey(imp=impt)          impt.importation() -        ope1 = models.Operation.objects.get(code_patriarche='4200') -        self.assertEqual(ope1.data, {'autre_refs': {'arbitraire': 789}}) -        ope2 = models.Operation.objects.get(code_patriarche='4201') -        self.assertEqual(ope2.data, {'autre_refs': {'arbitraire': 456}}) +        ope1 = models.Operation.objects.get(code_patriarche="4200") +        self.assertEqual(ope1.data, {"autre_refs": {"arbitraire": 789}}) +        ope2 = models.Operation.objects.get(code_patriarche="4201") +        self.assertEqual(ope2.data, {"autre_refs": {"arbitraire": 456}})          # #4292: Import of new JSON fields erase all precedent JSON fields          it.delete() -        col2 = ImporterColumn.objects.create(importer_type=importer, -                                             col_number=12) +        col2 = ImporterColumn.objects.create(importer_type=importer, col_number=12)          ImportTarget.objects.create( -            column=col2, target='data__autre', -            formater_type=formater_type) +            column=col2, target="data__autre", formater_type=formater_type +        )          impt = form.save(self.ishtar_user)          impt.initialize()          self.init_ope_targetkey(imp=impt)          impt.importation() -        ope1 = models.Operation.objects.get(code_patriarche='4200') -        self.assertEqual(ope1.data, {'autre_refs': {'arbitraire': 789}, -                                     "autre": 666}) -        ope2 = models.Operation.objects.get(code_patriarche='4201') -        self.assertEqual(ope2.data, {'autre_refs': {'arbitraire': 456}, -                                     "autre": 333}) +        ope1 = models.Operation.objects.get(code_patriarche="4200") +        self.assertEqual(ope1.data, {"autre_refs": {"arbitraire": 789}, "autre": 666}) +        ope2 = models.Operation.objects.get(code_patriarche="4201") +        self.assertEqual(ope2.data, {"autre_refs": {"arbitraire": 456}, "autre": 333})      def test_regexp(self):          importer, form = self.init_ope_import("operations-with-json-fields.csv")          r, __ = Regexp.objects.get_or_create( -            name="Code INSEE", -            regexp='([0-9]{0,1}[0-9A-B]) *([0-9]{3})' +            name="Code INSEE", regexp="([0-9]{0,1}[0-9A-B]) *([0-9]{3})"          )          col = ImporterColumn.objects.create( -            importer_type=importer, col_number=13, regexp_pre_filter=r) +            importer_type=importer, col_number=13, regexp_pre_filter=r +        )          formater_type = FormaterType.objects.get( -            formater_type='UnicodeFormater', options="") +            formater_type="UnicodeFormater", options="" +        )          ImportTarget.objects.create( -            column=col, target='data__code_insee', -            formater_type=formater_type) +            column=col, target="data__code_insee", formater_type=formater_type +        )          impt = form.save(self.ishtar_user)          impt.initialize()          self.init_ope_targetkey(imp=impt)          impt.importation() -        ope1 = models.Operation.objects.get(code_patriarche='4200') +        ope1 = models.Operation.objects.get(code_patriarche="4200")          self.assertEqual(ope1.data, {"code_insee": "45123"}) -        ope2 = models.Operation.objects.get(code_patriarche='4201') +        ope2 = models.Operation.objects.get(code_patriarche="4201")          self.assertEqual(ope2.data, {"code_insee": "6456"})  class ImportDocumentTest(ImportTest, TestCase):      fixtures = OPERATION_TOWNS_FIXTURES -    def init_doc_import(self, filename='document-example.csv'): +    def init_doc_import(self, filename="document-example.csv"):          model, __ = ImporterModel.objects.get_or_create( -            klass="ishtar_common.models.Document", -            defaults={ -                "name": "Documentation" -            } +            klass="ishtar_common.models.Document", defaults={"name": "Documentation"}          )          doc_import, __ = ImporterType.objects.get_or_create( -            name="Doc import", slug="doc-import", associated_models=model) - -        col = ImporterColumn.objects.create(col_number=1, -                                            importer_type_id=doc_import.pk) -        formater = FormaterType.objects.filter( -            formater_type='IntegerFormater').all()[0] -        ImportTarget.objects.create(target='import_get_next_index', -                                    formater_type_id=formater.pk, -                                    column_id=col.pk) -        col = ImporterColumn.objects.create(col_number=2, -                                            importer_type_id=doc_import.pk) +            name="Doc import", slug="doc-import", associated_models=model +        ) + +        col = ImporterColumn.objects.create( +            col_number=1, importer_type_id=doc_import.pk +        ) +        formater = FormaterType.objects.filter(formater_type="IntegerFormater").all()[0] +        ImportTarget.objects.create( +            target="import_get_next_index", +            formater_type_id=formater.pk, +            column_id=col.pk, +        ) +        col = ImporterColumn.objects.create( +            col_number=2, importer_type_id=doc_import.pk +        )          formater, __ = FormaterType.objects.get_or_create( -            formater_type='UnicodeFormater', options=None) -        ImportTarget.objects.create(target='title', -                                    formater_type_id=formater.pk, -                                    column_id=col.pk) +            formater_type="UnicodeFormater", options=None +        ) +        ImportTarget.objects.create( +            target="title", formater_type_id=formater.pk, column_id=col.pk +        )          doc_import_file = open( -            settings.ROOT_PATH + -            '../archaeological_operations/tests/' + filename, -            'rb') +            settings.ROOT_PATH + "../archaeological_operations/tests/" + filename, "rb" +        ) -        file_dict = {'imported_file': SimpleUploadedFile( -            doc_import_file.name, doc_import_file.read())} +        file_dict = { +            "imported_file": SimpleUploadedFile( +                doc_import_file.name, doc_import_file.read() +            ) +        }          group, c = TargetKeyGroup.objects.get_or_create(name="My group") -        post_dict = {'importer_type': doc_import.pk, 'skip_lines': 1, -                     "encoding": 'utf-8', "name": 'init_ope_import', -                     "associated_group": group.pk, "csv_sep": ","} -        form = forms_common.NewImportForm(data=post_dict, files=file_dict, -                                          user=self.user) +        post_dict = { +            "importer_type": doc_import.pk, +            "skip_lines": 1, +            "encoding": "utf-8", +            "name": "init_ope_import", +            "associated_group": group.pk, +            "csv_sep": ",", +        } +        form = forms_common.NewImportForm( +            data=post_dict, files=file_dict, user=self.user +        )          form.is_valid()          return doc_import, form @@ -681,8 +762,9 @@ class ImportStepByStepTest(ImportTest, TestCase):          first_person_nb = Person.objects.count()          first_ope_nb = models.Operation.objects.count() -        import_url = reverse('import_step_by_step', -                             kwargs={'pk': impt.pk, 'line_number': 2}) +        import_url = reverse( +            "import_step_by_step", kwargs={"pk": impt.pk, "line_number": 2} +        )          response = c.get(import_url)          # no login redirect          self.assertEqual(response.status_code, 302) @@ -692,12 +774,13 @@ class ImportStepByStepTest(ImportTest, TestCase):          response = c.get(import_url)          self.assertEqual(response.status_code, 200)          # verify pagination for next link is OK -        self.assertIn('href="/import-step-by-step/{}/3/"'.format(impt.pk), -                      response.content.decode()) +        self.assertIn( +            'href="/import-step-by-step/{}/3/"'.format(impt.pk), +            response.content.decode(), +        )          # creation have been evaluated          self.assertIn( -            str(_("New objects will be created.")), -            response.content.decode('utf-8') +            str(_("New objects will be created.")), response.content.decode("utf-8")          )          # import this line @@ -705,8 +788,9 @@ class ImportStepByStepTest(ImportTest, TestCase):          response = c.post(import_url, posted)          self.assertEqual(response.status_code, 302)          # successful import - go to the next line -        new_import_url = reverse('import_step_by_step', -                                 kwargs={'pk': impt.pk, 'line_number': 3}) +        new_import_url = reverse( +            "import_step_by_step", kwargs={"pk": impt.pk, "line_number": 3} +        )          self.assertRedirects(response, new_import_url)          current_ope_nb = models.Operation.objects.count()          self.assertEqual(current_ope_nb, first_ope_nb + 1) @@ -727,12 +811,13 @@ class ImportStepByStepTest(ImportTest, TestCase):          self.assertEqual(response.status_code, 200)          self.assertIn(              str(_("This line have been already imported.")), -            response.content.decode('utf-8') +            response.content.decode("utf-8"),          )          # import next page          next_import_url = reverse( -            'import_step_by_step', kwargs={'pk': impt.pk, 'line_number': 3}) +            "import_step_by_step", kwargs={"pk": impt.pk, "line_number": 3} +        )          posted = {"valid": "import"}          c.post(next_import_url, posted)          current_ope_nb = models.Operation.objects.count() @@ -761,11 +846,13 @@ class ImportStepByStepTest(ImportTest, TestCase):              imported_line = fle.readline()              self.assertIn("2000/01/32", imported_line)          # error detected on the source file -        error = str(_( -            "The following error(s) has been encountered while parsing " -            "the source file:") +        error = str( +            _( +                "The following error(s) has been encountered while parsing " +                "the source file:" +            )          ) -        self.assertIn(error, response.content.decode('utf-8')) +        self.assertIn(error, response.content.decode("utf-8"))  class SerializationTest(GenericSerializationTest, TestCase): @@ -773,69 +860,73 @@ class SerializationTest(GenericSerializationTest, TestCase):      def setUp(self):          self.username, self.password, self.user = create_superuser() -        operation = create_operation(self.user, -                                     values={"code_patriarche": "66666"}) +        operation = create_operation(self.user, values={"code_patriarche": "66666"})          ope2 = create_operation(self.user, values={"code_patriarche": "66667"})          self.operations = [operation, ope2]          models.RecordRelations.objects.create( -            left_record=operation, right_record=ope2, -            relation_type=models.RelationType.objects.all()[0] -        ) -        site = models.ArchaeologicalSite.objects.create( -            reference="ref-site" +            left_record=operation, +            right_record=ope2, +            relation_type=models.RelationType.objects.all()[0],          ) +        site = models.ArchaeologicalSite.objects.create(reference="ref-site")          operation.archaeological_sites.add(site)          operation.top_sites.add(site) -        default = {"town": Town.objects.create(numero_insee="66666"), -                   "section": 'A', 'parcel_number': '1', "operation": operation} +        default = { +            "town": Town.objects.create(numero_insee="66666"), +            "section": "A", +            "parcel_number": "1", +            "operation": operation, +        }          parcel = models.Parcel.objects.create(**default)          models.ParcelOwner.objects.create( -            parcel=parcel, owner=Person.objects.create(), -            start_date=datetime.date.today(), end_date=datetime.date.today()) +            parcel=parcel, +            owner=Person.objects.create(), +            start_date=datetime.date.today(), +            end_date=datetime.date.today(), +        )      def test_serialization(self): -        res = self.generic_serialization_test( -            serializers.operation_serialization) +        res = self.generic_serialization_test(serializers.operation_serialization)          ope_json = json.loads( -            res[('operations', 'archaeological_operations__Operation')] +            res[("operations", "archaeological_operations__Operation")]          )          self.assertEqual(len(ope_json), 2) -        result_queryset = models.Operation.objects.filter( -            code_patriarche="66666") +        result_queryset = models.Operation.objects.filter(code_patriarche="66666")          res = self.generic_serialization_test( -            serializers.operation_serialization, no_test=True, -            kwargs={"operation_queryset": result_queryset} +            serializers.operation_serialization, +            no_test=True, +            kwargs={"operation_queryset": result_queryset},          )          ope_json = json.loads( -            res[('operations', 'archaeological_operations__Operation')] +            res[("operations", "archaeological_operations__Operation")]          )          self.assertEqual(len(ope_json), 1)          site_json = json.loads( -            res[('operations', 'archaeological_operations__ArchaeologicalSite')] +            res[("operations", "archaeological_operations__ArchaeologicalSite")]          )          self.assertEqual(len(site_json), 1)          rel_json = json.loads( -            res[('operations', 'archaeological_operations__RecordRelations')] +            res[("operations", "archaeological_operations__RecordRelations")]          )          self.assertEqual(len(rel_json), 0) -        result_queryset = models.Operation.objects.filter( -            code_patriarche="66667") +        result_queryset = models.Operation.objects.filter(code_patriarche="66667")          res = self.generic_serialization_test( -            serializers.operation_serialization, no_test=True, -            kwargs={"operation_queryset": result_queryset} +            serializers.operation_serialization, +            no_test=True, +            kwargs={"operation_queryset": result_queryset},          )          ope_json = json.loads( -            res[('operations', 'archaeological_operations__Operation')] +            res[("operations", "archaeological_operations__Operation")]          )          self.assertEqual(len(ope_json), 1)          site_json = json.loads( -            res[('operations', 'archaeological_operations__ArchaeologicalSite')] +            res[("operations", "archaeological_operations__ArchaeologicalSite")]          )          self.assertEqual(len(site_json), 0)          rel_json = json.loads( -            res[('operations', 'archaeological_operations__RecordRelations')] +            res[("operations", "archaeological_operations__RecordRelations")]          )          self.assertEqual(len(rel_json), 0) @@ -849,8 +940,10 @@ class SerializationTest(GenericSerializationTest, TestCase):      def test_lock(self):          self.reinit_lock()          self.generic_serialization_test( -            serializers.operation_serialization, no_test=True, -            kwargs={"put_locks": False}) +            serializers.operation_serialization, +            no_test=True, +            kwargs={"put_locks": False}, +        )          for operation in self.operations:              operation = models.Operation.objects.get(pk=operation.pk)              self.assertFalse(operation.locked) @@ -858,8 +951,10 @@ class SerializationTest(GenericSerializationTest, TestCase):          self.reinit_lock()          self.generic_serialization_test( -            serializers.operation_serialization, no_test=True, -            kwargs={"put_locks": True}) +            serializers.operation_serialization, +            no_test=True, +            kwargs={"put_locks": True}, +        )          for operation in self.operations:              operation = models.Operation.objects.get(pk=operation.pk)              self.assertTrue(operation.locked) @@ -867,8 +962,10 @@ class SerializationTest(GenericSerializationTest, TestCase):          self.reinit_lock()          self.generic_serialization_test( -            serializers.operation_serialization, no_test=True, -            kwargs={"put_locks": True, "lock_user": self.user}) +            serializers.operation_serialization, +            no_test=True, +            kwargs={"put_locks": True, "lock_user": self.user}, +        )          for operation in self.operations:              operation = models.Operation.objects.get(pk=operation.pk)              self.assertTrue(operation.locked) @@ -876,40 +973,50 @@ class SerializationTest(GenericSerializationTest, TestCase):      def test_restore(self):          current_number, zip_filename = self.generic_restore_test_genzip( -            serializers.OPERATION_MODEL_LIST, -            serializers.operation_serialization) -        self.generic_restore_test(zip_filename, current_number, -                                  serializers.OPERATION_MODEL_LIST) +            serializers.OPERATION_MODEL_LIST, serializers.operation_serialization +        ) +        self.generic_restore_test( +            zip_filename, current_number, serializers.OPERATION_MODEL_LIST +        )      def test_unlock_on_restore(self):          current_number, zip_filename = self.generic_restore_test_genzip(              serializers.OPERATION_MODEL_LIST,              serializers.operation_serialization, -            kwargs={"put_locks": True, "lock_user": self.user}) +            kwargs={"put_locks": True, "lock_user": self.user}, +        ) -        self.generic_restore_test(zip_filename, current_number, -                                  serializers.OPERATION_MODEL_LIST, -                                  delete_existing=False) +        self.generic_restore_test( +            zip_filename, +            current_number, +            serializers.OPERATION_MODEL_LIST, +            delete_existing=False, +        )          for operation in self.operations:              operation = models.Operation.objects.get( -                code_patriarche=operation.code_patriarche) +                code_patriarche=operation.code_patriarche +            )              self.assertTrue(operation.locked)              self.assertEqual(operation.lock_user, self.user) -        self.generic_restore_test(zip_filename, current_number, -                                  serializers.OPERATION_MODEL_LIST, -                                  delete_existing=False, -                                  release_locks=True) +        self.generic_restore_test( +            zip_filename, +            current_number, +            serializers.OPERATION_MODEL_LIST, +            delete_existing=False, +            release_locks=True, +        )          for operation in self.operations:              operation = models.Operation.objects.get( -                code_patriarche=operation.code_patriarche) +                code_patriarche=operation.code_patriarche +            )              self.assertFalse(operation.locked)              self.assertIsNone(operation.lock_user)      def test_historization_on_restore(self):          current_number, zip_filename = self.generic_restore_test_genzip( -            serializers.OPERATION_MODEL_LIST, -            serializers.operation_serialization) +            serializers.OPERATION_MODEL_LIST, serializers.operation_serialization +        )          operation = models.Operation.objects.get(code_patriarche="66666")          version_nb = operation.history.count() @@ -941,191 +1048,516 @@ class ParcelTest(ImportTest, TestCase):      def test_parse_parcels(self):          # the database needs to be initialised before importing          from archaeological_operations.utils import parse_parcels +          # default_town = Town.objects.create(numero_insee="12345",          #                                    name="default_town")          test_values = ( -            ("1996 : XT:53,54,56,57,59,60,61,62", -             {1996: [ -                 ("XT", "53"), ("XT", "54"), ("XT", "56"), ("XT", "57"), -                 ("XT", "59"), ("XT", "60"), ("XT", "61"), ("XT", "62"), -             ]} -             ), -            ("AD:23", -             {None: [ -                 ("AD", "23") -             ]}), -            ("1961 :B1:227;", -             {1961: [ -                 ("B1", '227') -             ]}), -            ("1982 CV:35;CV:36", -             {1982: [ -                 ("CV", "35"), ("CV", "36"), -             ]}), -            ("E:24;E:25", -             {None: [ -                 ("E", "24"), ("E", "25"), -             ]}), -            ("B : 375, 376, 386, 387, 645, 646 / C : 412 à 415, 432 à 435, " -             "622 / F : 120, 149, 150, 284, 287, 321 à 323", -             {None: [ -                 ("B", "375"), ("B", "376"), ("B", "386"), ("B", "387"), -                 ("B", "645"), ("B", "646"), -                 ("C", "412"), ("C", "413"), ("C", "414"), ("C", "415"), -                 ("C", "432"), ("C", "433"), ("C", "434"), ("C", "435"), -                 ("C", "622"), -                 ("F", "120"), ("F", "149"), ("F", "150"), ("F", "284"), -                 ("F", "287"), ("F", "321"), ("F", "322"), ("F", "323"), -             ]}), -            ("AD : 95, 96, 86, 87, 81, 252, AE : 58, AD : 115 à 132", -             {None: [ -                 ("AD", "95"), ("AD", "96"), ("AD", "86"), ("AD", "87"), -                 ("AD", "81"), ("AD", "252"), ("AD", "115"), ("AD", "116"), -                 ("AD", "117"), ("AD", "118"), ("AD", "119"), ("AD", "120"), -                 ("AD", "121"), ("AD", "122"), ("AD", "123"), ("AD", "124"), -                 ("AD", "125"), ("AD", "126"), ("AD", "127"), ("AD", "128"), -                 ("AD", "129"), ("AD", "130"), ("AD", "131"), ("AD", "132"), -                 ("AE", "58"), -             ]}), -            ("XD:1 à 13, 24 à 28, 33 à 39, 50 à 52, 80, 83, 84 à 86, 259 à " -             "261, 182, 225 ; XH:5 ; P:1640, 1888, 1889, 1890 ; R:1311, " -             "1312, 1314,1342, 1343, 1559 à 1569", -             {None: [ -                 ('XD', "1"), ('XD', "2"), ('XD', "3"), ('XD', "4"), -                 ('XD', "5"), ('XD', "6"), ('XD', "7"), ('XD', "8"), -                 ('XD', "9"), ('XD', "10"), ('XD', "11"), ('XD', "12"), -                 ('XD', "13"), ("XD", "24"), ("XD", "25"), ("XD", "26"), -                 ("XD", "27"), ("XD", "28"), ("XD", "33"), ("XD", "34"), -                 ("XD", "35"), ("XD", "36"), ("XD", "37"), ("XD", "38"), -                 ("XD", "39"), ("XD", "50"), ("XD", "51"), ("XD", "52"), -                 ("XD", "80"), ("XD", "83"), ("XD", "84"), ("XD", "85"), -                 ("XD", "86"), ("XD", "259"), ("XD", "260"), ("XD", "261"), -                 ("XD", "182"), ("XD", "225"), ("XH", "5"), -                 ("P", "1640"), ("P", "1888"), ("P", "1889"), ("P", "1890"), -                 ("R", "1311"), ("R", "1312"), ("R", "1314"), ("R", "1342"), -                 ("R", "1343"), ("R", "1559"), ("R", "1560"), ("R", "1561"), -                 ("R", "1562"), ("R", "1563"), ("R", "1564"), ("R", "1565"), -                 ("R", "1566"), ("R", "1567"), ("R", "1568"), ("R", "1569"), -             ]}), -            ("BZ:2 à 5, 365 ; CD:88 à 104, 106, 108, 326", -             {None: [ -                 ('BZ', '2'), ('BZ', '3'), ('BZ', '4'), ('BZ', '5'), -                 ('BZ', '365'), ('CD', '88'), ('CD', '89'), ('CD', '90'), -                 ('CD', '91'), ('CD', '92'), ('CD', '93'), ('CD', '94'), -                 ('CD', '95'), ('CD', '96'), ('CD', '97'), ('CD', '98'), -                 ('CD', '99'), ('CD', '100'), ('CD', '101'), ('CD', '102'), -                 ('CD', '103'), ('CD', '104'), ('CD', '106'), ('CD', '326'), -                 ('CD', '108') -             ]}), -            ("AV 118 à 125, 127, 132 à 137, 153, 398p, 399, 402; BI 27, 30, " -             "32, 33, 188, 255, 256 à 258, 260, 284p, 294; BL 297", -             {None: [ -                 ('AV', '118'), ('AV', '119'), ('AV', '120'), ('AV', '121'), -                 ('AV', '122'), ('AV', '123'), ('AV', '124'), ('AV', '125'), -                 ('AV', '127'), ('AV', '132'), ('AV', '133'), ('AV', '134'), -                 ('AV', '135'), ('AV', '136'), ('AV', '137'), ('AV', '153'), -                 ('AV', '398p'), ('AV', '399'), ('AV', '402'), -                 ('BI', '27'), ('BI', '30'), ('BI', '32'), ('BI', '33'), -                 ('BI', '188'), ('BI', '255'), ('BI', '256'), ('BI', '257'), -                 ('BI', '258'), ('BI', '260'), ('BI', '284p'), ('BI', '294'), -                 ('BL', '297'), -             ]}), -            ("A : 904 à 906, 911 ; E:40, 41", -             {None: [ -                 ("A", '904'), ("A", '905'), ("A", '906'), ("A", '911'), -                 ("E", '40'), ("E", "41") -             ]}), -            ("1991 : BE:8, 12", -             {"1991": [ -                 ('BE', '8'), ('BE', '12'), -             ]}), -            ("1979 : EM:1", -             {"1979": [ -                 ('EM', '1') -             ]},), -            ("B:448;B:449;B:450;B:451;B:452;B:455;B:456;B:457;B:458;B:459;" -             "B:1486;", -             {None: [ -                 ("B", "448"), ("B", "449"), ("B", "450"), ("B", "451"), -                 ("B", "452"), ("B", "455"), ("B", "456"), ("B", "457"), -                 ("B", "458"), ("B", "459"), ("B", "1486"), -             ]}), -            ("AC : 72 à 81, 91 à 100, 197 / ZC:180 à 189", -             {None: [ -                 ('AC', '72'), ('AC', '73'), ('AC', '74'), ('AC', '75'), -                 ('AC', '76'), ('AC', '77'), ('AC', '78'), ('AC', '79'), -                 ('AC', '80'), ('AC', '81'), ('AC', '91'), ('AC', '92'), -                 ('AC', '93'), ('AC', '94'), ('AC', '95'), ('AC', '96'), -                 ('AC', '97'), ('AC', '98'), ('AC', '99'), ('AC', '100'), -                 ('AC', '197'), ('ZC', '180'), ('ZC', '181'), ('ZC', '182'), -                 ('ZC', '183'), ('ZC', '184'), ('ZC', '185'), ('ZC', '186'), -                 ('ZC', '187'), ('ZC', '188'), ('ZC', '189'), -             ]}), -            ("AB 37 et 308", -             {None: [ -                 ('AB', '37'), ('AB', '308'), -             ]}), -            ("1983  D2 n° 458 et 459", -             {"1983": [ -                 ('D2', '458'), ('D2', '459'), -             ]}), -            ("ZS : 21p, 66", -             {None: [ -              ('ZS', '21p'), ('ZS', '66'), -              ]}), -            ("VV:166, 167, domaine public", -             {None: [ -                 ('VV', '166'), ('VV', '167'), -             ]}), -            (" AS:13 à 15, 17 à 19, 21 à 32, 34 à 45, 47 à 53, 69, 70, 82, " -             "84 / CK:1, 24, 25, 29, 30, 37 à 43", -             {None: [ -              ("AS", "13"), ("AS", "14"), ("AS", "15"), ("AS", "17"), -              ("AS", "18"), ("AS", "19"), ("AS", "21"), ("AS", "22"), -              ("AS", "23"), ("AS", "24"), ("AS", "25"), ("AS", "26"), -              ("AS", "27"), ("AS", "28"), ("AS", "29"), ("AS", "30"), -              ("AS", "31"), ("AS", "32"), ("AS", "34"), ("AS", "35"), -              ("AS", "36"), ("AS", "37"), ("AS", "38"), ("AS", "39"), -              ("AS", "40"), ("AS", "41"), ("AS", "42"), ("AS", "43"), -              ("AS", "44"), ("AS", "45"), ("AS", "47"), ("AS", "48"), -              ("AS", "49"), ("AS", "50"), ("AS", "51"), ("AS", "52"), -              ("AS", "53"), ('AS', "69"), ('AS', "70"), ('AS', "82"), -              ('AS', "84"), ('CK', "1"), ('CK', "24"), ('CK', "25"), -              ('CK', "29"), ('CK', "30"), ('CK', "37"), ('CK', "38"), -              ('CK', "39"), ('CK', "40"), ('CK', "41"), ('CK', "42"), -              ('CK', "43"), ]}), -            (" ZN:37, 15, 35, 28, 29 / ZM:9, 73", -             {None: [ -                 ("ZN", "37"), ("ZN", "15"), ("ZN", "35"), ("ZN", "28"), -                 ("ZN", "29"), ("ZM", "9"), ("ZM", "73"), -             ]}), -            (" Tranche n°1 : YP:243, 12, 14 à 16, 18 à 26, DP / Tranche n°2 :" -             "YP:17, 307, 27, 308, 44 à 46, 683, BM:1, 250, 488 à 492", -             {None: [ -                 ('YP', '243'), ('YP', '12'), ('YP', '14'), ('YP', '15'), -                 ('YP', '16'), ('YP', '18'), ('YP', '19'), ('YP', '20'), -                 ('YP', '21'), ('YP', '22'), ('YP', '23'), ('YP', '24'), -                 ('YP', '25'), ('YP', '26'), ('YP', '17'), ('YP', '27'), -                 ('YP', '308'), ('YP', '44'), ('YP', '45'), ('YP', '46'), -                 ('YP', '683'), ('YP', '307'), ('BM', '1'), ('BM', '250'), -                 ('BM', '488'), ('BM', '489'), ('BM', '490'), ('BM', '491'), -                 ('BM', '492'), -             ]}), -            (" H : 106, 156, 158", -             {None: [ -                 ('H', '106'), ('H', '156'), ('H', '158'), -             ]}), -            ("Section YO : parcelles n° 19; 20", -             {None: [ -                 ('YO', '19'), ('YO', '20'), -             ]}), -            ("1991 :AI:23;19;20;21;22;181;AM:116;214;215;233;235", -             {"1991": [ -                 ("AI", "19"), ("AI", "20"), ("AI", "21"), ("AI", "22"), -                 ("AI", "23"), ("AI", "181"), -                 ("AM", "116"), ("AM", "214"), ("AM", "215"), -                 ("AM", "233"), ("AM", "235"), -             ]}) +            ( +                "1996 : XT:53,54,56,57,59,60,61,62", +                { +                    1996: [ +                        ("XT", "53"), +                        ("XT", "54"), +                        ("XT", "56"), +                        ("XT", "57"), +                        ("XT", "59"), +                        ("XT", "60"), +                        ("XT", "61"), +                        ("XT", "62"), +                    ] +                }, +            ), +            ("AD:23", {None: [("AD", "23")]}), +            ("1961 :B1:227;", {1961: [("B1", "227")]}), +            ( +                "1982 CV:35;CV:36", +                { +                    1982: [ +                        ("CV", "35"), +                        ("CV", "36"), +                    ] +                }, +            ), +            ( +                "E:24;E:25", +                { +                    None: [ +                        ("E", "24"), +                        ("E", "25"), +                    ] +                }, +            ), +            ( +                "B : 375, 376, 386, 387, 645, 646 / C : 412 à 415, 432 à 435, " +                "622 / F : 120, 149, 150, 284, 287, 321 à 323", +                { +                    None: [ +                        ("B", "375"), +                        ("B", "376"), +                        ("B", "386"), +                        ("B", "387"), +                        ("B", "645"), +                        ("B", "646"), +                        ("C", "412"), +                        ("C", "413"), +                        ("C", "414"), +                        ("C", "415"), +                        ("C", "432"), +                        ("C", "433"), +                        ("C", "434"), +                        ("C", "435"), +                        ("C", "622"), +                        ("F", "120"), +                        ("F", "149"), +                        ("F", "150"), +                        ("F", "284"), +                        ("F", "287"), +                        ("F", "321"), +                        ("F", "322"), +                        ("F", "323"), +                    ] +                }, +            ), +            ( +                "AD : 95, 96, 86, 87, 81, 252, AE : 58, AD : 115 à 132", +                { +                    None: [ +                        ("AD", "95"), +                        ("AD", "96"), +                        ("AD", "86"), +                        ("AD", "87"), +                        ("AD", "81"), +                        ("AD", "252"), +                        ("AD", "115"), +                        ("AD", "116"), +                        ("AD", "117"), +                        ("AD", "118"), +                        ("AD", "119"), +                        ("AD", "120"), +                        ("AD", "121"), +                        ("AD", "122"), +                        ("AD", "123"), +                        ("AD", "124"), +                        ("AD", "125"), +                        ("AD", "126"), +                        ("AD", "127"), +                        ("AD", "128"), +                        ("AD", "129"), +                        ("AD", "130"), +                        ("AD", "131"), +                        ("AD", "132"), +                        ("AE", "58"), +                    ] +                }, +            ), +            ( +                "XD:1 à 13, 24 à 28, 33 à 39, 50 à 52, 80, 83, 84 à 86, 259 à " +                "261, 182, 225 ; XH:5 ; P:1640, 1888, 1889, 1890 ; R:1311, " +                "1312, 1314,1342, 1343, 1559 à 1569", +                { +                    None: [ +                        ("XD", "1"), +                        ("XD", "2"), +                        ("XD", "3"), +                        ("XD", "4"), +                        ("XD", "5"), +                        ("XD", "6"), +                        ("XD", "7"), +                        ("XD", "8"), +                        ("XD", "9"), +                        ("XD", "10"), +                        ("XD", "11"), +                        ("XD", "12"), +                        ("XD", "13"), +                        ("XD", "24"), +                        ("XD", "25"), +                        ("XD", "26"), +                        ("XD", "27"), +                        ("XD", "28"), +                        ("XD", "33"), +                        ("XD", "34"), +                        ("XD", "35"), +                        ("XD", "36"), +                        ("XD", "37"), +                        ("XD", "38"), +                        ("XD", "39"), +                        ("XD", "50"), +                        ("XD", "51"), +                        ("XD", "52"), +                        ("XD", "80"), +                        ("XD", "83"), +                        ("XD", "84"), +                        ("XD", "85"), +                        ("XD", "86"), +                        ("XD", "259"), +                        ("XD", "260"), +                        ("XD", "261"), +                        ("XD", "182"), +                        ("XD", "225"), +                        ("XH", "5"), +                        ("P", "1640"), +                        ("P", "1888"), +                        ("P", "1889"), +                        ("P", "1890"), +                        ("R", "1311"), +                        ("R", "1312"), +                        ("R", "1314"), +                        ("R", "1342"), +                        ("R", "1343"), +                        ("R", "1559"), +                        ("R", "1560"), +                        ("R", "1561"), +                        ("R", "1562"), +                        ("R", "1563"), +                        ("R", "1564"), +                        ("R", "1565"), +                        ("R", "1566"), +                        ("R", "1567"), +                        ("R", "1568"), +                        ("R", "1569"), +                    ] +                }, +            ), +            ( +                "BZ:2 à 5, 365 ; CD:88 à 104, 106, 108, 326", +                { +                    None: [ +                        ("BZ", "2"), +                        ("BZ", "3"), +                        ("BZ", "4"), +                        ("BZ", "5"), +                        ("BZ", "365"), +                        ("CD", "88"), +                        ("CD", "89"), +                        ("CD", "90"), +                        ("CD", "91"), +                        ("CD", "92"), +                        ("CD", "93"), +                        ("CD", "94"), +                        ("CD", "95"), +                        ("CD", "96"), +                        ("CD", "97"), +                        ("CD", "98"), +                        ("CD", "99"), +                        ("CD", "100"), +                        ("CD", "101"), +                        ("CD", "102"), +                        ("CD", "103"), +                        ("CD", "104"), +                        ("CD", "106"), +                        ("CD", "326"), +                        ("CD", "108"), +                    ] +                }, +            ), +            ( +                "AV 118 à 125, 127, 132 à 137, 153, 398p, 399, 402; BI 27, 30, " +                "32, 33, 188, 255, 256 à 258, 260, 284p, 294; BL 297", +                { +                    None: [ +                        ("AV", "118"), +                        ("AV", "119"), +                        ("AV", "120"), +                        ("AV", "121"), +                        ("AV", "122"), +                        ("AV", "123"), +                        ("AV", "124"), +                        ("AV", "125"), +                        ("AV", "127"), +                        ("AV", "132"), +                        ("AV", "133"), +                        ("AV", "134"), +                        ("AV", "135"), +                        ("AV", "136"), +                        ("AV", "137"), +                        ("AV", "153"), +                        ("AV", "398p"), +                        ("AV", "399"), +                        ("AV", "402"), +                        ("BI", "27"), +                        ("BI", "30"), +                        ("BI", "32"), +                        ("BI", "33"), +                        ("BI", "188"), +                        ("BI", "255"), +                        ("BI", "256"), +                        ("BI", "257"), +                        ("BI", "258"), +                        ("BI", "260"), +                        ("BI", "284p"), +                        ("BI", "294"), +                        ("BL", "297"), +                    ] +                }, +            ), +            ( +                "A : 904 à 906, 911 ; E:40, 41", +                { +                    None: [ +                        ("A", "904"), +                        ("A", "905"), +                        ("A", "906"), +                        ("A", "911"), +                        ("E", "40"), +                        ("E", "41"), +                    ] +                }, +            ), +            ( +                "1991 : BE:8, 12", +                { +                    "1991": [ +                        ("BE", "8"), +                        ("BE", "12"), +                    ] +                }, +            ), +            ( +                "1979 : EM:1", +                {"1979": [("EM", "1")]}, +            ), +            ( +                "B:448;B:449;B:450;B:451;B:452;B:455;B:456;B:457;B:458;B:459;" +                "B:1486;", +                { +                    None: [ +                        ("B", "448"), +                        ("B", "449"), +                        ("B", "450"), +                        ("B", "451"), +                        ("B", "452"), +                        ("B", "455"), +                        ("B", "456"), +                        ("B", "457"), +                        ("B", "458"), +                        ("B", "459"), +                        ("B", "1486"), +                    ] +                }, +            ), +            ( +                "AC : 72 à 81, 91 à 100, 197 / ZC:180 à 189", +                { +                    None: [ +                        ("AC", "72"), +                        ("AC", "73"), +                        ("AC", "74"), +                        ("AC", "75"), +                        ("AC", "76"), +                        ("AC", "77"), +                        ("AC", "78"), +                        ("AC", "79"), +                        ("AC", "80"), +                        ("AC", "81"), +                        ("AC", "91"), +                        ("AC", "92"), +                        ("AC", "93"), +                        ("AC", "94"), +                        ("AC", "95"), +                        ("AC", "96"), +                        ("AC", "97"), +                        ("AC", "98"), +                        ("AC", "99"), +                        ("AC", "100"), +                        ("AC", "197"), +                        ("ZC", "180"), +                        ("ZC", "181"), +                        ("ZC", "182"), +                        ("ZC", "183"), +                        ("ZC", "184"), +                        ("ZC", "185"), +                        ("ZC", "186"), +                        ("ZC", "187"), +                        ("ZC", "188"), +                        ("ZC", "189"), +                    ] +                }, +            ), +            ( +                "AB 37 et 308", +                { +                    None: [ +                        ("AB", "37"), +                        ("AB", "308"), +                    ] +                }, +            ), +            ( +                "1983  D2 n° 458 et 459", +                { +                    "1983": [ +                        ("D2", "458"), +                        ("D2", "459"), +                    ] +                }, +            ), +            ( +                "ZS : 21p, 66", +                { +                    None: [ +                        ("ZS", "21p"), +                        ("ZS", "66"), +                    ] +                }, +            ), +            ( +                "VV:166, 167, domaine public", +                { +                    None: [ +                        ("VV", "166"), +                        ("VV", "167"), +                    ] +                }, +            ), +            ( +                " AS:13 à 15, 17 à 19, 21 à 32, 34 à 45, 47 à 53, 69, 70, 82, " +                "84 / CK:1, 24, 25, 29, 30, 37 à 43", +                { +                    None: [ +                        ("AS", "13"), +                        ("AS", "14"), +                        ("AS", "15"), +                        ("AS", "17"), +                        ("AS", "18"), +                        ("AS", "19"), +                        ("AS", "21"), +                        ("AS", "22"), +                        ("AS", "23"), +                        ("AS", "24"), +                        ("AS", "25"), +                        ("AS", "26"), +                        ("AS", "27"), +                        ("AS", "28"), +                        ("AS", "29"), +                        ("AS", "30"), +                        ("AS", "31"), +                        ("AS", "32"), +                        ("AS", "34"), +                        ("AS", "35"), +                        ("AS", "36"), +                        ("AS", "37"), +                        ("AS", "38"), +                        ("AS", "39"), +                        ("AS", "40"), +                        ("AS", "41"), +                        ("AS", "42"), +                        ("AS", "43"), +                        ("AS", "44"), +                        ("AS", "45"), +                        ("AS", "47"), +                        ("AS", "48"), +                        ("AS", "49"), +                        ("AS", "50"), +                        ("AS", "51"), +                        ("AS", "52"), +                        ("AS", "53"), +                        ("AS", "69"), +                        ("AS", "70"), +                        ("AS", "82"), +                        ("AS", "84"), +                        ("CK", "1"), +                        ("CK", "24"), +                        ("CK", "25"), +                        ("CK", "29"), +                        ("CK", "30"), +                        ("CK", "37"), +                        ("CK", "38"), +                        ("CK", "39"), +                        ("CK", "40"), +                        ("CK", "41"), +                        ("CK", "42"), +                        ("CK", "43"), +                    ] +                }, +            ), +            ( +                " ZN:37, 15, 35, 28, 29 / ZM:9, 73", +                { +                    None: [ +                        ("ZN", "37"), +                        ("ZN", "15"), +                        ("ZN", "35"), +                        ("ZN", "28"), +                        ("ZN", "29"), +                        ("ZM", "9"), +                        ("ZM", "73"), +                    ] +                }, +            ), +            ( +                " Tranche n°1 : YP:243, 12, 14 à 16, 18 à 26, DP / Tranche n°2 :" +                "YP:17, 307, 27, 308, 44 à 46, 683, BM:1, 250, 488 à 492", +                { +                    None: [ +                        ("YP", "243"), +                        ("YP", "12"), +                        ("YP", "14"), +                        ("YP", "15"), +                        ("YP", "16"), +                        ("YP", "18"), +                        ("YP", "19"), +                        ("YP", "20"), +                        ("YP", "21"), +                        ("YP", "22"), +                        ("YP", "23"), +                        ("YP", "24"), +                        ("YP", "25"), +                        ("YP", "26"), +                        ("YP", "17"), +                        ("YP", "27"), +                        ("YP", "308"), +                        ("YP", "44"), +                        ("YP", "45"), +                        ("YP", "46"), +                        ("YP", "683"), +                        ("YP", "307"), +                        ("BM", "1"), +                        ("BM", "250"), +                        ("BM", "488"), +                        ("BM", "489"), +                        ("BM", "490"), +                        ("BM", "491"), +                        ("BM", "492"), +                    ] +                }, +            ), +            ( +                " H : 106, 156, 158", +                { +                    None: [ +                        ("H", "106"), +                        ("H", "156"), +                        ("H", "158"), +                    ] +                }, +            ), +            ( +                "Section YO : parcelles n° 19; 20", +                { +                    None: [ +                        ("YO", "19"), +                        ("YO", "20"), +                    ] +                }, +            ), +            ( +                "1991 :AI:23;19;20;21;22;181;AM:116;214;215;233;235", +                { +                    "1991": [ +                        ("AI", "19"), +                        ("AI", "20"), +                        ("AI", "21"), +                        ("AI", "22"), +                        ("AI", "23"), +                        ("AI", "181"), +                        ("AM", "116"), +                        ("AM", "214"), +                        ("AM", "215"), +                        ("AM", "233"), +                        ("AM", "235"), +                    ] +                }, +            ),          )          # ),("Domaine public", {}          # ),("Tranche 1 : AV:4 à 6, 18, 80, 104 / partiellement : 5 et 18", {} @@ -1135,52 +1567,63 @@ class ParcelTest(ImportTest, TestCase):              parcels = parse_parcels(value)              if not parcels and not result:                  continue -            self.assertTrue(parcels != [], -                            msg="No parcel parsed for \"%s\"" % value) +            self.assertTrue(parcels != [], msg='No parcel parsed for "%s"' % value)              parcels_copy = parcels[:]              for year in result.keys():                  for values in parcels_copy: -                    if values['year'] != year and \ -                       values['year'] != str(year): +                    if values["year"] != year and values["year"] != str(year):                          continue                      self.assertTrue( -                        (values['section'], values['parcel_number']) -                        in result[year], -                        msg="Section - Parcel number: \"%s - %s\" is not " -                        "in \"%s\"" % ( -                            values['section'], values['parcel_number'], -                            str(result[year]))) +                        (values["section"], values["parcel_number"]) in result[year], +                        msg='Section - Parcel number: "%s - %s" is not ' +                        'in "%s"' +                        % ( +                            values["section"], +                            values["parcel_number"], +                            str(result[year]), +                        ), +                    )                      parcels.pop(parcels.index(values)) -                    result[year].pop(result[year].index( -                        (values['section'], values['parcel_number']))) +                    result[year].pop( +                        result[year].index((values["section"], values["parcel_number"])) +                    )              # all parcels have been imported -            self.assertEqual(parcels, [], msg="Parcel(s): \"%s\" haven't be " -                             "recognized in \"%s\"" % (str(parcels), value)) +            self.assertEqual( +                parcels, +                [], +                msg='Parcel(s): "%s" haven\'t be ' +                'recognized in "%s"' % (str(parcels), value), +            )              not_imported = [data for data in result.values() if data]              self.assertEqual( -                not_imported, [], msg="Parcel(s): \"%s\" haven't be " -                "recognized in \"%s\"" % (str(not_imported), value)) +                not_imported, +                [], +                msg='Parcel(s): "%s" haven\'t be ' +                'recognized in "%s"' % (str(not_imported), value), +            )  def create_orga(user): -    orga_type, created = OrganizationType.objects.get_or_create( -        txt_idx='operator') +    orga_type, created = OrganizationType.objects.get_or_create(txt_idx="operator")      orga, created = Organization.objects.get_or_create( -        name='Operator', organization_type=orga_type, history_modifier=user) +        name="Operator", organization_type=orga_type, history_modifier=user +    )      return orga  def create_operation(user, orga=None, values=None): -    operation_type = models.OperationType.objects.get( -        txt_idx="arch_diagnostic") +    operation_type = models.OperationType.objects.get(txt_idx="arch_diagnostic")      if not values:          values = {} -    dct = {'year': 2010, 'operation_type_id': operation_type.pk, -           'history_modifier': user} +    dct = { +        "year": 2010, +        "operation_type_id": operation_type.pk, +        "history_modifier": user, +    }      dct.update(values)      if orga: -        dct['operator'] = orga -    if 'code_patriarche' not in dct: +        dct["operator"] = orga +    if "code_patriarche" not in dct:          idx = 1          while models.Operation.objects.filter(code_patriarche=str(idx)).count():              idx += 1 @@ -1206,36 +1649,39 @@ class OperationInitTest(object):          return self.orgas      def get_default_orga(self, user=None): -        if not hasattr(self, 'orgas') or not self.orgas: +        if not hasattr(self, "orgas") or not self.orgas:              self.create_orgas(user)          return self.orgas[0]      def create_towns(self, datas=None):          if not datas:              datas = {} -        default = {'numero_insee': '12345', 'name': 'default_town'} +        default = {"numero_insee": "12345", "name": "default_town"}          default.update(datas)          town = models.Town.objects.create(**default) -        if not hasattr(self, 'towns') or not self.towns: +        if not hasattr(self, "towns") or not self.towns:              self.towns = []          self.towns.append(town)          return self.towns      def get_default_town(self): -        towns = getattr(self, 'towns', None) +        towns = getattr(self, "towns", None)          if not towns:              self.create_towns()          return self.towns[0]      def create_parcel(self, data=None): -        default = {'town': self.get_default_town(), -                   'section': 'A', 'parcel_number': '1'} -        if not hasattr(self, 'operations'): +        default = { +            "town": self.get_default_town(), +            "section": "A", +            "parcel_number": "1", +        } +        if not hasattr(self, "operations"):              self.create_operation() -        default['operation'] = self.operations[0] +        default["operation"] = self.operations[0]          if data:              default.update(data) -        if not getattr(self, 'parcels', None): +        if not getattr(self, "parcels", None):              self.parcels = []          self.parcels.append(models.Parcel.objects.create(**default))          return self.parcels @@ -1254,7 +1700,7 @@ class OperationInitTest(object):              self.get_default_orga(user)          if not user:              self.get_default_user() -        if not getattr(self, 'operations', None): +        if not getattr(self, "operations", None):              self.operations = []          self.operations.append(create_operation(user, orga))          return self.operations @@ -1270,19 +1716,19 @@ class OperationInitTest(object):      def tearDown(self):          # cleanup for further test -        if hasattr(self, 'user'): +        if hasattr(self, "user"):              self.user.delete()              self.user = None          # all try/except is necessary for bad migrations on main...          # should be removed at the next big version -        if hasattr(self, 'operations'): +        if hasattr(self, "operations"):              for ope in self.operations:                  try:                      ope.delete()                  except:                      pass              self.operations = [] -        if hasattr(self, 'parcels'): +        if hasattr(self, "parcels"):              for p in self.parcels:                  try:                      p.delete() @@ -1295,93 +1741,105 @@ class OperationTest(TestCase, OperationInitTest):      fixtures = FILE_FIXTURES      def setUp(self): -        IshtarSiteProfile.objects.get_or_create( -            slug='default', active=True) +        IshtarSiteProfile.objects.get_or_create(slug="default", active=True)          self.username, self.password, self.user = create_superuser()          self.alt_username, self.alt_password, self.alt_user = create_user() -        self.alt_user.user_permissions.add(Permission.objects.get( -            codename='view_own_operation')) +        self.alt_user.user_permissions.add( +            Permission.objects.get(codename="view_own_operation") +        )          self.orgas = self.create_orgas(self.user)          self.operations = self.create_operation(self.user, self.orgas[0])          self.operations += self.create_operation(self.alt_user, self.orgas[0])          self.item = self.operations[0]          for idx in range(15): -            ContextRecord.objects.create(label='CR-{}'.format(idx), -                                         operation=self.item) +            ContextRecord.objects.create(label="CR-{}".format(idx), operation=self.item)      def test_external_id(self): -        self.item.code_patriarche = '123456789' +        self.item.code_patriarche = "123456789"          self.item.save()          parcel = self.get_default_parcel()          parcel.operation = self.item          parcel.save()          correct_ext_id = "{}-{}-{}{}".format( -            self.item.code_patriarche, parcel.town.numero_insee, -            parcel.section, parcel.parcel_number) +            self.item.code_patriarche, +            parcel.town.numero_insee, +            parcel.section, +            parcel.parcel_number, +        )          self.assertEqual(parcel.external_id, correct_ext_id)          # auto has been previously set -        parcel.external_id = 'blabla' +        parcel.external_id = "blabla"          parcel.save()          self.assertEqual(parcel.external_id, correct_ext_id)          # deactivate auto          parcel.auto_external_id = False -        parcel.external_id = 'blabla' +        parcel.external_id = "blabla"          parcel.save() -        self.assertEqual(parcel.external_id, 'blabla') +        self.assertEqual(parcel.external_id, "blabla")      def test_complete_identifier(self):          profile = get_current_profile() -        profile.operation_complete_identifier = \ +        profile.operation_complete_identifier = (              "{code_patriarche}-{towns__numero_insee}" +        )          profile.save()          self.item = models.Operation.objects.get(pk=self.item.pk)          t = Town.objects.create(numero_insee="12345", name="OK town")          self.item.towns.add(t)          self.item = models.Operation.objects.get(pk=self.item.pk) -        self.item.code_patriarche = '123456789' +        self.item.code_patriarche = "123456789"          self.item.year = 2020          self.item.save()          self.item = models.Operation.objects.get(pk=self.item.pk) -        self.assertEqual(self.item.complete_identifier, -                         '{}-{}'.format(self.item.code_patriarche, -                                        t.numero_insee)) +        self.assertEqual( +            self.item.complete_identifier, +            "{}-{}".format(self.item.code_patriarche, t.numero_insee), +        ) -        profile.operation_complete_identifier = \ -            "{year}-{towns__numero_insee}" +        profile.operation_complete_identifier = "{year}-{towns__numero_insee}"          profile.save()          self.item.save()          self.item = models.Operation.objects.get(pk=self.item.pk) -        self.assertEqual(self.item.complete_identifier, -                         '{}-{}'.format(self.item.year, -                                        t.numero_insee)) +        self.assertEqual( +            self.item.complete_identifier, +            "{}-{}".format(self.item.year, t.numero_insee), +        )      def test_associated(self):          scientist = Person.objects.create(name="C-3PO")          self.item.scientist = scientist          self.item.save()          scientist = Person.objects.get(pk=scientist.pk) -        self.assertIn(PersonType.objects.get(txt_idx='head_scientist'), -                      scientist.person_types.all()) +        self.assertIn( +            PersonType.objects.get(txt_idx="head_scientist"), +            scientist.person_types.all(), +        )          # do not change if in the list          sra = Person.objects.create(name="R2D2") -        sra.person_types.add(PersonType.objects.get(txt_idx='sra_agent')) +        sra.person_types.add(PersonType.objects.get(txt_idx="sra_agent"))          self.item.scientist = sra          self.item.save() -        self.assertNotIn(PersonType.objects.get(txt_idx='head_scientist'), -                         sra.person_types.all()) +        self.assertNotIn( +            PersonType.objects.get(txt_idx="head_scientist"), sra.person_types.all() +        )      def create_relations(self):          rel1 = models.RelationType.objects.create( -            symmetrical=True, label='Include', txt_idx='include') +            symmetrical=True, label="Include", txt_idx="include" +        )          rel2 = models.RelationType.objects.create( -            symmetrical=False, label='Included', txt_idx='included', -            inverse_relation=rel1) +            symmetrical=False, +            label="Included", +            txt_idx="included", +            inverse_relation=rel1, +        )          models.RecordRelations.objects.create(              left_record=self.operations[0],              right_record=self.operations[1], -            relation_type=rel1) +            relation_type=rel1, +        )          return rel1, rel2      def testPostDeleteRelations(self): @@ -1390,7 +1848,7 @@ class OperationTest(TestCase, OperationInitTest):      def testPostDeleteParcels(self):          ope = self.operations[0] -        town = Town.objects.create(name='plouf', numero_insee='20000') +        town = Town.objects.create(name="plouf", numero_insee="20000")          parcel = models.Parcel.objects.create(town=town)          parcel_nb = models.Parcel.objects.count()          ope.parcels.add(parcel) @@ -1407,38 +1865,37 @@ class OperationTest(TestCase, OperationInitTest):          self.assertEqual(parcel_nb, models.Parcel.objects.count())      def testIndex(self): -        ope = create_operation(self.user, values={'year': 2042}) +        ope = create_operation(self.user, values={"year": 2042})          self.assertEqual(ope.operation_code, 1) -        ope2 = create_operation(self.user, values={'year': 2042}) +        ope2 = create_operation(self.user, values={"year": 2042})          self.assertEqual(ope2.operation_code, 2) -        ope = create_operation(self.user, values={'year': 0}) +        ope = create_operation(self.user, values={"year": 0})          self.assertEqual(ope.operation_code, 1) -        ope2 = create_operation(self.user, values={'year': 0}) +        ope2 = create_operation(self.user, values={"year": 0})          self.assertEqual(ope2.operation_code, 2)      def test_cache_update(self):          self.create_towns()          operation = self.operations[0]          self.assertIsNotNone(operation.cached_label) -        town, ope_id = operation.cached_label.split(' | ') -        self.assertIn(town, ('Intercommunal', "Multi-town")) -        self.assertEqual(ope_id, 'OA1 - OP2010-1') +        town, ope_id = operation.cached_label.split(" | ") +        self.assertIn(town, ("Intercommunal", "Multi-town")) +        self.assertEqual(ope_id, "OA1 - OP2010-1")          operation = models.Operation.objects.get(pk=operation.pk)          operation.year = 2011          operation.save()          operation.towns.add(self.towns[0])          operation = models.Operation.objects.get(pk=operation.pk)          self.assertIsNotNone(operation.cached_label) -        town, ope_id = operation.cached_label.split(' | ') -        self.assertEqual(ope_id, 'OA1 - OP2011-1') +        town, ope_id = operation.cached_label.split(" | ") +        self.assertEqual(ope_id, "OA1 - OP2011-1")          self.assertEqual(town, self.towns[0].name)      def test_search_vector_update(self):          operation = self.operations[0] -        town = self.create_towns({'numero_insee': '12346', 'name': 'Daisy'})[-1] +        town = self.create_towns({"numero_insee": "12346", "name": "Daisy"})[-1]          operation.towns.add(town) -        town = self.create_towns( -            {'numero_insee': '12347', 'name': 'Dirty old'})[-1] +        town = self.create_towns({"numero_insee": "12347", "name": "Dirty old"})[-1]          operation.towns.add(town)          operation = models.Operation.objects.get(pk=operation.pk)          operation.comment = "Zardoz" @@ -1449,9 +1906,15 @@ class OperationTest(TestCase, OperationInitTest):          operation.save()          self.assertIsNotNone(operation.search_vector)          for key in ( -                'old', 'dirty', 'daisy', "'2010'", "zardoz", "huiaaa5", -                "{}42huiaaa5".format(profile.operation_prefix.lower()), -                "42huiaaa5"): +            "old", +            "dirty", +            "daisy", +            "'2010'", +            "zardoz", +            "huiaaa5", +            "{}42huiaaa5".format(profile.operation_prefix.lower()), +            "42huiaaa5", +        ):              self.assertIn(key, operation.search_vector)      def test_cache_bulk_update(self): @@ -1460,24 +1923,30 @@ class OperationTest(TestCase, OperationInitTest):          operation.parcels.add(init_parcel)          from archaeological_context_records.models import ContextRecord -        cr_data = {'label': "Context record", "operation": operation, -                   'parcel': init_parcel, -                   'history_modifier': self.get_default_user()} + +        cr_data = { +            "label": "Context record", +            "operation": operation, +            "parcel": init_parcel, +            "history_modifier": self.get_default_user(), +        }          cr = ContextRecord.objects.create(**cr_data)          from archaeological_finds.models import BaseFind, Find, MaterialType +          bf_data = { -            'label': "Base find", 'history_modifier': self.get_default_user(), -            'context_record': cr +            "label": "Base find", +            "history_modifier": self.get_default_user(), +            "context_record": cr,          }          base_find = BaseFind.objects.create(**bf_data)          find = Find.objects.create( -            history_modifier=self.get_default_user(), -            label='Find me' +            history_modifier=self.get_default_user(), label="Find me"          )          find.base_finds.add(base_find)          mat = MaterialType.objects.create( -            label='Adamentium', txt_idx='admentium', code='ADA') +            label="Adamentium", txt_idx="admentium", code="ADA" +        )          find.material_types.add(mat)          class TestObj(object): @@ -1485,7 +1954,7 @@ class OperationTest(TestCase, OperationInitTest):                  self.context_record_reached = []              def reached(self, sender, **kwargs): -                instance = kwargs.get('instance') +                instance = kwargs.get("instance")                  if sender == ContextRecord:                      self.context_record_reached.append(instance) @@ -1501,73 +1970,70 @@ class OperationTest(TestCase, OperationInitTest):          # verify the relevance of the update          cr = ContextRecord.objects.get(pk=cr.pk)          self.assertIsNotNone(cr.cached_label) -        ope_id, parcel_sec, parcel_nb, cr_label = cr.cached_label.split(' | ') +        ope_id, parcel_sec, parcel_nb, cr_label = cr.cached_label.split(" | ")          profile = get_current_profile() -        self.assertEqual(ope_id, 'OA1') +        self.assertEqual(ope_id, "OA1")          base_find = BaseFind.objects.get(pk=base_find.pk) -        op_code, idx = base_find.cache_short_id.split(' | ') -        self.assertEqual(op_code, 'OA1') -        self.assertEqual(idx, '00001') +        op_code, idx = base_find.cache_short_id.split(" | ") +        self.assertEqual(op_code, "OA1") +        self.assertEqual(idx, "00001")          self.assertIsNotNone(base_find.cache_complete_id) -        op_code, mat_code, lbl, idx = base_find.cache_complete_id.split(' | ') -        self.assertEqual(op_code, 'OA1') -        self.assertEqual(mat_code, 'ADA') -        self.assertEqual(lbl, 'Context record') -        self.assertEqual(idx, '00001') +        op_code, mat_code, lbl, idx = base_find.cache_complete_id.split(" | ") +        self.assertEqual(op_code, "OA1") +        self.assertEqual(mat_code, "ADA") +        self.assertEqual(lbl, "Context record") +        self.assertEqual(idx, "00001")          find = Find.objects.get(pk=find.pk)          self.assertIsNotNone(find.cached_label) -        op_code_idx, lbl = find.cached_label.split(' | ') -        self.assertEqual(op_code_idx, 'OA1-00001') -        self.assertEqual(lbl, 'Find me') +        op_code_idx, lbl = find.cached_label.split(" | ") +        self.assertEqual(op_code_idx, "OA1-00001") +        self.assertEqual(lbl, "Find me")          operation = models.Operation.objects.get(pk=operation.pk) -        operation.code_patriarche = '666' +        operation.code_patriarche = "666"          operation.save()          cr = ContextRecord.objects.get(pk=cr.pk)          self.assertIsNotNone(cr.cached_label) -        ope_id, parcel_sec, parcel_nb, cr_label = cr.cached_label.split(' | ') +        ope_id, parcel_sec, parcel_nb, cr_label = cr.cached_label.split(" | ") -        self.assertEqual(ope_id, '{}666'.format(profile.operation_prefix)) +        self.assertEqual(ope_id, "{}666".format(profile.operation_prefix))          base_find = BaseFind.objects.get(pk=base_find.pk)          self.assertIsNotNone(base_find.cache_short_id) -        op_code, idx = base_find.cache_short_id.split(' | ') -        self.assertEqual(op_code, 'OA666') +        op_code, idx = base_find.cache_short_id.split(" | ") +        self.assertEqual(op_code, "OA666")          self.assertIsNotNone(base_find.cache_complete_id) -        op_code, mat_code, lbl, idx = base_find.cache_complete_id.split(' | ') -        self.assertEqual(op_code, 'OA666') +        op_code, mat_code, lbl, idx = base_find.cache_complete_id.split(" | ") +        self.assertEqual(op_code, "OA666")          find = Find.objects.get(pk=find.pk)          self.assertIsNotNone(find.cached_label) -        op_code_idx, lbl = find.cached_label.split(' | ') -        self.assertEqual(op_code_idx, 'OA666-00001') +        op_code_idx, lbl = find.cached_label.split(" | ") +        self.assertEqual(op_code_idx, "OA666-00001")      def test_show(self):          operation = self.operations[0]          source = models.Document.objects.create( -            title="Source title", -            source_type=models.SourceType.objects.all()[0] +            title="Source title", source_type=models.SourceType.objects.all()[0]          )          operation.documents.add(source)          c = Client() -        response = c.get(reverse('show-operation', kwargs={'pk': operation.pk})) +        response = c.get(reverse("show-operation", kwargs={"pk": operation.pk}))          self.assertEqual(response.status_code, 200)          # empty content when not allowed          self.assertEqual(response.content, b"") -        response = c.get(reverse('show-document', -                                 kwargs={'pk': source.pk})) +        response = c.get(reverse("show-document", kwargs={"pk": source.pk}))          self.assertRedirects(response, "/")          c.login(username=self.username, password=self.password) -        response = c.get(reverse('show-operation', kwargs={'pk': operation.pk})) +        response = c.get(reverse("show-operation", kwargs={"pk": operation.pk}))          self.assertEqual(response.status_code, 200)          self.assertIn(b'class="card sheet"', response.content) -        response = c.get(reverse('show-document', -                                 kwargs={'pk': source.pk})) +        response = c.get(reverse("show-document", kwargs={"pk": source.pk}))          self.assertEqual(response.status_code, 200)          self.assertIn(b'class="card sheet"', response.content) @@ -1582,46 +2048,53 @@ class OperationTest(TestCase, OperationInitTest):          operation.save()          c.login(username=self.username, password=self.password) -        response = c.get(reverse('show-operation', kwargs={'pk': operation.pk})) +        response = c.get(reverse("show-operation", kwargs={"pk": operation.pk}))          self.assertEqual(response.status_code, 200)          self.assertIn(b'class="card sheet"', response.content) -        self.assertIn(b'/show-historized-operation/', response.content) +        self.assertIn(b"/show-historized-operation/", response.content)          c.login(username=self.alt_username, password=self.alt_password) -        response = c.get(reverse('show-operation', kwargs={'pk': operation.pk})) +        response = c.get(reverse("show-operation", kwargs={"pk": operation.pk}))          self.assertEqual(response.status_code, 200)          self.assertIn(b'class="card sheet"', response.content) -        self.assertNotIn(b'/show-historized-operation/', response.content) +        self.assertNotIn(b"/show-historized-operation/", response.content)      def test_show_pdf(self):          operation = self.operations[0]          c = Client() -        response = c.get(reverse('show-operation', -                                 kwargs={'pk': operation.pk, 'type': 'pdf'})) +        response = c.get( +            reverse("show-operation", kwargs={"pk": operation.pk, "type": "pdf"}) +        )          self.assertEqual(response.status_code, 200)          # empty content when not allowed          self.assertEqual(response.content, b"")          c.login(username=self.username, password=self.password) -        response = c.get(reverse('show-operation', -                                 kwargs={'pk': operation.pk, 'type': 'pdf'})) +        response = c.get( +            reverse("show-operation", kwargs={"pk": operation.pk, "type": "pdf"}) +        )          self.assertEqual(response.status_code, 200)          f = BytesIO(response.content) -        filetype = Popen("/usr/bin/file -b --mime -", shell=True, stdout=PIPE, -                         stdin=PIPE).communicate(f.read(1024))[0].strip() -        self.assertTrue(filetype.startswith(b'application/pdf')) +        filetype = ( +            Popen("/usr/bin/file -b --mime -", shell=True, stdout=PIPE, stdin=PIPE) +            .communicate(f.read(1024))[0] +            .strip() +        ) +        self.assertTrue(filetype.startswith(b"application/pdf"))      def test_show_odt(self): -        locale.setlocale(locale.LC_ALL, 'fr_FR.UTF-8') +        locale.setlocale(locale.LC_ALL, "fr_FR.UTF-8")          operation = self.operations[0]          c = Client() -        response = c.get(reverse('show-operation', -                                 kwargs={'pk': operation.pk, 'type': 'odt'})) +        response = c.get( +            reverse("show-operation", kwargs={"pk": operation.pk, "type": "odt"}) +        )          self.assertEqual(response.status_code, 200)          # empty content when not allowed          self.assertEqual(response.content, b"")          c.login(username=self.username, password=self.password) -        response = c.get(reverse('show-operation', kwargs={'pk': operation.pk, -                                                           'type': 'odt'})) +        response = c.get( +            reverse("show-operation", kwargs={"pk": operation.pk, "type": "odt"}) +        )          self.assertEqual(response.status_code, 200)          f = BytesIO(response.content)          z = zipfile.ZipFile(f) @@ -1629,12 +2102,12 @@ class OperationTest(TestCase, OperationInitTest):          filename = None          for name in z.namelist(): -            if name == 'content.xml': +            if name == "content.xml":                  filename = name                  break          self.assertIsNotNone(filename) -        tmpdir = tempfile.mkdtemp(prefix='tmp-ishtar-') +        tmpdir = tempfile.mkdtemp(prefix="tmp-ishtar-")          imported_file = z.extract(filename, tmpdir)          with open(imported_file) as content_file:              content = content_file.read() @@ -1645,34 +2118,45 @@ class OperationTest(TestCase, OperationInitTest):      def test_json(self):          operation = self.operations[0] -        operation.data = {"groundhog": {"number": 53444, -                                        "awake_state": "réveillée", -                                        "with_feather": "Oui"}, -                          "frog_number": 32303} +        operation.data = { +            "groundhog": { +                "number": 53444, +                "awake_state": "réveillée", +                "with_feather": "Oui", +            }, +            "frog_number": 32303, +        }          operation.save()          content_type = ContentType.objects.get_for_model(operation)          groundhog_section = JsonDataSection.objects.create( -            name="Marmotte", content_type=content_type) -        JsonDataField.objects.create(name="État d'éveil", -                                     key='groundhog__awake_state', -                                     content_type=content_type, -                                     section=groundhog_section) -        JsonDataField.objects.create(name="Avec plume", -                                     key='groundhog__with_feather', -                                     content_type=content_type, -                                     section=groundhog_section) -        JsonDataField.objects.create(name="Zzzzzzzz", -                                     key='groundhog__zzz', -                                     content_type=content_type, -                                     section=groundhog_section) -        JsonDataField.objects.create(name="Grenouille", -                                     key='frog_number', -                                     content_type=content_type) +            name="Marmotte", content_type=content_type +        ) +        JsonDataField.objects.create( +            name="État d'éveil", +            key="groundhog__awake_state", +            content_type=content_type, +            section=groundhog_section, +        ) +        JsonDataField.objects.create( +            name="Avec plume", +            key="groundhog__with_feather", +            content_type=content_type, +            section=groundhog_section, +        ) +        JsonDataField.objects.create( +            name="Zzzzzzzz", +            key="groundhog__zzz", +            content_type=content_type, +            section=groundhog_section, +        ) +        JsonDataField.objects.create( +            name="Grenouille", key="frog_number", content_type=content_type +        )          c = Client()          c.login(username=self.username, password=self.password) -        response = c.get(reverse('show-operation', kwargs={'pk': operation.pk})) +        response = c.get(reverse("show-operation", kwargs={"pk": operation.pk}))          self.assertEqual(response.status_code, 200)          content = response.content.decode()          self.assertIn('class="card sheet"', content) @@ -1686,7 +2170,7 @@ class OperationTest(TestCase, OperationInitTest):          operation.data = {}          operation.save() -        response = c.get(reverse('show-operation', kwargs={'pk': operation.pk})) +        response = c.get(reverse("show-operation", kwargs={"pk": operation.pk}))          self.assertEqual(response.status_code, 200)          self.assertIn(b'class="card sheet"', response.content)          self.assertNotIn(b"Marmotte", response.content) @@ -1694,30 +2178,33 @@ class OperationTest(TestCase, OperationInitTest):      def test_json_search_vector_update(self):          operation = self.operations[0]          content_type = ContentType.objects.get_for_model(operation) -        JsonDataField.objects.create(name="Nom de marmotte", -                                     key='groundhog__name', -                                     content_type=content_type, -                                     search_index=True) -        JsonDataField.objects.create(name="Numéro grenouille", -                                     key='frog_number', -                                     content_type=content_type) +        JsonDataField.objects.create( +            name="Nom de marmotte", +            key="groundhog__name", +            content_type=content_type, +            search_index=True, +        ) +        JsonDataField.objects.create( +            name="Numéro grenouille", key="frog_number", content_type=content_type +        )          operation = models.Operation.objects.get(pk=operation.pk) -        operation.data = {"groundhog": {"name": "La Marmotte héhé", -                                        "color": "Red"}, -                          "frog_number": 32303} +        operation.data = { +            "groundhog": {"name": "La Marmotte héhé", "color": "Red"}, +            "frog_number": 32303, +        }          operation.save()          operation = models.Operation.objects.get(pk=operation.pk)          self.assertIsNotNone(operation.search_vector) -        for key in ('marmott',): +        for key in ("marmott",):              self.assertIn(key, operation.search_vector) -        for key in ('32303', 'red', 'Red'): +        for key in ("32303", "red", "Red"):              self.assertNotIn(key, operation.search_vector)      def test_document(self):          operation = self.operations[0] -        q = Document.objects.values('index').order_by('-index') +        q = Document.objects.values("index").order_by("-index")          if q.count(): -            c_index = q.all()[0]['index'] +            c_index = q.all()[0]["index"]          else:              c_index = 0          doc = Document.objects.create(title="Image!") @@ -1737,23 +2224,19 @@ class OperationTest(TestCase, OperationInitTest):          Find = apps.get_model("archaeological_finds", "Find")          BaseFind = apps.get_model("archaeological_finds", "BaseFind")          Warehouse = apps.get_model("archaeological_warehouse", "Warehouse") -        WarehouseType = apps.get_model("archaeological_warehouse", -                                       "WarehouseType") +        WarehouseType = apps.get_model("archaeological_warehouse", "WarehouseType")          Container = apps.get_model("archaeological_warehouse", "Container") -        ContainerType = apps.get_model("archaeological_warehouse", -                                       "ContainerType") +        ContainerType = apps.get_model("archaeological_warehouse", "ContainerType")          operation = self.operations[0] -        hc, __ = Unit.objects.get_or_create(txt_idx='not-in-context', order=10) -        cr = ContextRecord.objects.create( -            operation=operation, unit=hc) +        hc, __ = Unit.objects.get_or_create(txt_idx="not-in-context", order=10) +        cr = ContextRecord.objects.create(operation=operation, unit=hc)          bf = BaseFind.objects.create(context_record=cr)          f = Find.objects.create()          f.base_finds.add(bf) -        wt = WarehouseType.objects.create(label='WT') +        wt = WarehouseType.objects.create(label="WT")          w = Warehouse.objects.create(name="Warehouse", warehouse_type=wt) -        ct = ContainerType.objects.create(label='CT') -        c = Container.objects.create(reference="Test", location=w, -                                     container_type=ct) +        ct = ContainerType.objects.create(label="CT") +        c = Container.objects.create(reference="Test", location=w, container_type=ct)          f.container = c          f.save() @@ -1765,8 +2248,7 @@ class LockTest(TestCase, OperationInitTest):      fixtures = FILE_FIXTURES      def setUp(self): -        IshtarSiteProfile.objects.get_or_create( -            slug='default', active=True) +        IshtarSiteProfile.objects.get_or_create(slug="default", active=True)          self.username, self.password, self.user = create_superuser()          self.orgas = self.create_orgas(self.user)          self.operations = self.create_operation(self.user, self.orgas[0]) @@ -1781,39 +2263,39 @@ class LockTest(TestCase, OperationInitTest):          cls_wiz = OperationWizardModifTest()          url = reverse(cls_wiz.url_name)          # first wizard step -        step = 'selec-operation_modification' +        step = "selec-operation_modification"          response = cls_wiz.wizard_post( -            self.client, url, step, {'pk': self.operation.pk}) -        msg = str(_("This item is locked for edition.") -                  ).replace("'", "'") -        self.assertIn(msg, response.content.decode(), -                      msg="wizard lock for edition not effective") +            self.client, url, step, {"pk": self.operation.pk} +        ) +        msg = str(_("This item is locked for edition.")).replace("'", "'") +        self.assertIn( +            msg, response.content.decode(), msg="wizard lock for edition not effective" +        )      def test_qa_lock(self): -        url = reverse('operation-qa-bulk-update', args=[self.operation.pk]) +        url = reverse("operation-qa-bulk-update", args=[self.operation.pk])          response = self.client.get(url) -        self.assertRedirects(response, reverse('qa-not-available', -                                               args=["locked"])) +        self.assertRedirects(response, reverse("qa-not-available", args=["locked"]))      def test_sheet_lock(self): -        url = reverse('show-operation', kwargs={'pk': self.operation.pk}) +        url = reverse("show-operation", kwargs={"pk": self.operation.pk})          response = self.client.get(url) -        msg = str(_("This item has been locked. Edition is disabled.") -                  ).replace("'", "\'") -        self.assertIn(msg, response.content.decode(), -                      msg="lock not displayed on sheet") +        msg = str(_("This item has been locked. Edition is disabled.")).replace( +            "'", "'" +        ) +        self.assertIn(msg, response.content.decode(), msg="lock not displayed on sheet")  class CustomFormTest(TestCase, OperationInitTest):      fixtures = FILE_FIXTURES      def setUp(self): -        IshtarSiteProfile.objects.get_or_create( -            slug='default', active=True) +        IshtarSiteProfile.objects.get_or_create(slug="default", active=True)          self.username, self.password, self.user = create_superuser()          self.alt_username, self.alt_password, self.alt_user = create_user() -        self.alt_user.user_permissions.add(Permission.objects.get( -            codename='view_own_operation')) +        self.alt_user.user_permissions.add( +            Permission.objects.get(codename="view_own_operation") +        )          self.orgas = self.create_orgas(self.user)          self.operations = self.create_operation(self.user, self.orgas[0])          self.operations += self.create_operation(self.alt_user, self.orgas[0]) @@ -1826,42 +2308,46 @@ class CustomFormTest(TestCase, OperationInitTest):          cls_wiz = OperationWizardModifTest()          url = reverse(cls_wiz.url_name)          # first wizard step -        step = 'selec-operation_modification' -        cls_wiz.wizard_post(c, url, step, {'pk': self.operations[0].pk}) +        step = "selec-operation_modification" +        cls_wiz.wizard_post(c, url, step, {"pk": self.operations[0].pk}) -        step = 'general-operation_modification' +        step = "general-operation_modification"          data = { -            '{}{}-current_step'.format(cls_wiz.url_name, -                                       cls_wiz.wizard_name): [step], +            "{}{}-current_step".format(cls_wiz.url_name, cls_wiz.wizard_name): [step],          } -        MSG_FOUND = " - '{}' field found on the modification "\ -                    "wizard. It should have been filtered." -        MSG_NOT_FOUND = " - '{}' field not found on the modification "\ -                        "wizard. It shouldn't have been filtered." +        MSG_FOUND = ( +            " - '{}' field found on the modification " +            "wizard. It should have been filtered." +        ) +        MSG_NOT_FOUND = ( +            " - '{}' field not found on the modification " +            "wizard. It shouldn't have been filtered." +        )          key_in_charge = "in_charge"          response = c.post(url, data)          content = response.content.decode()          res = key_in_charge in content -        self.assertTrue(res, -                        msg="filter all" + MSG_NOT_FOUND.format(key_in_charge)) +        self.assertTrue(res, msg="filter all" + MSG_NOT_FOUND.format(key_in_charge))          f = CustomForm.objects.create( -            name="Test - all", form="operation-010-general", -            available=True, apply_to_all=True) +            name="Test - all", +            form="operation-010-general", +            available=True, +            apply_to_all=True, +        )          ExcludedField.objects.create(custom_form=f, field="in_charge")          response = c.post(url, data)          content = response.content.decode()          res = key_in_charge not in content -        self.assertTrue(res, -                        msg="filter all" + MSG_FOUND.format(key_in_charge)) +        self.assertTrue(res, msg="filter all" + MSG_FOUND.format(key_in_charge))          # user type form prevail on "all"          f_scientist = CustomForm.objects.create( -            name="Test - user type", form="operation-010-general", -            available=True) -        tpe = PersonType.objects.get(txt_idx='head_scientist') +            name="Test - user type", form="operation-010-general", available=True +        ) +        tpe = PersonType.objects.get(txt_idx="head_scientist")          key_address = "address"          f_scientist.user_types.add(tpe)          self.user.ishtaruser.person.person_types.add(tpe) @@ -1871,60 +2357,53 @@ class CustomFormTest(TestCase, OperationInitTest):          content = response.content.decode()          res = key_in_charge in content          self.assertTrue( -            res, -            msg="filter profile type" + MSG_NOT_FOUND.format(key_in_charge) +            res, msg="filter profile type" + MSG_NOT_FOUND.format(key_in_charge)          )          res = key_address not in content -        self.assertTrue( -            res, -            msg="filter profile type" + MSG_FOUND.format(key_address)) +        self.assertTrue(res, msg="filter profile type" + MSG_FOUND.format(key_address))          # profile type form prevail on "all" and "user types"          f_scientist2 = CustomForm.objects.create( -            name="Test - profile type", form="operation-010-general", -            available=True) +            name="Test - profile type", form="operation-010-general", available=True +        )          key_scientific = "scientific_documentation_comment" -        ExcludedField.objects.create(custom_form=f_scientist2, -                                     field=key_scientific) +        ExcludedField.objects.create(custom_form=f_scientist2, field=key_scientific) -        collaborator = ProfileType.objects.get(txt_idx='collaborator') +        collaborator = ProfileType.objects.get(txt_idx="collaborator")          UserProfile.objects.create( -            profile_type=collaborator, -            person=self.user.ishtaruser.person, -            current=True) +            profile_type=collaborator, person=self.user.ishtaruser.person, current=True +        )          f_scientist2.profile_types.add(collaborator)          response = c.post(url, data)          content = response.content.decode()          res = key_in_charge in content          self.assertTrue( -            res, -            msg="filter profile type" + MSG_NOT_FOUND.format(key_in_charge)) +            res, msg="filter profile type" + MSG_NOT_FOUND.format(key_in_charge) +        )          res = key_address in content          self.assertTrue( -            res, -            msg="filter profile type" + MSG_NOT_FOUND.format(key_address)) +            res, msg="filter profile type" + MSG_NOT_FOUND.format(key_address) +        )          res = key_scientific not in content          self.assertTrue( -            res, -            msg="filter profile type" + MSG_FOUND.format(key_scientific)) +            res, msg="filter profile type" + MSG_FOUND.format(key_scientific) +        )          # user prevail on "all", "profile_type" and "user_types"          f_user = CustomForm.objects.create( -            name="Test - user", form="operation-010-general", available=True) +            name="Test - user", form="operation-010-general", available=True +        )          f_user.users.add(self.user.ishtaruser)          response = c.post(url, data)          content = response.content.decode()          res = key_in_charge in content -        self.assertTrue(res, -                        msg="filter user" + MSG_NOT_FOUND.format(key_in_charge)) +        self.assertTrue(res, msg="filter user" + MSG_NOT_FOUND.format(key_in_charge))          res = key_scientific in content -        self.assertTrue(res, -                        msg="filter user" + MSG_NOT_FOUND.format(key_scientific)) +        self.assertTrue(res, msg="filter user" + MSG_NOT_FOUND.format(key_scientific))          res = key_address in content -        self.assertTrue(res, -                        msg="filter user" + MSG_FOUND.format(key_address)) +        self.assertTrue(res, msg="filter user" + MSG_FOUND.format(key_address))      def test_enabled(self):          c = Client() @@ -1933,37 +2412,47 @@ class CustomFormTest(TestCase, OperationInitTest):          cls_wiz = OperationWizardModifTest()          url = reverse(cls_wiz.url_name)          # first wizard step -        step = 'selec-operation_modification' -        cls_wiz.wizard_post(c, url, step, {'pk': self.operations[0].pk}) +        step = "selec-operation_modification" +        cls_wiz.wizard_post(c, url, step, {"pk": self.operations[0].pk}) -        step = 'collaborators-operation_modification' +        step = "collaborators-operation_modification"          data = { -            '{}{}-current_step'.format(cls_wiz.url_name, -                                       cls_wiz.wizard_name): [step], +            "{}{}-current_step".format(cls_wiz.url_name, cls_wiz.wizard_name): [step],          }          response = c.post(url, data)          self.assertNotEqual(response.status_code, 404)          CustomForm.objects.create( -            name="Test2", form="operation-020-collaborators", available=True, -            apply_to_all=True, enabled=False) +            name="Test2", +            form="operation-020-collaborators", +            available=True, +            apply_to_all=True, +            enabled=False, +        )          response = c.post(url, data)          self.assertEqual(response.status_code, 404)      def test_json(self):          operation = self.operations[0] -        operation.data = {"groundhog": {"number": 53444, -                                        "awake_state": "réveillée", -                                        "with_feather": "Oui"}, -                          "frog_number": 32303} +        operation.data = { +            "groundhog": { +                "number": 53444, +                "awake_state": "réveillée", +                "with_feather": "Oui", +            }, +            "frog_number": 32303, +        }          operation.save()          content_type = ContentType.objects.get_for_model(operation)          field = JsonDataField.objects.create( -            name="État d'éveil", key='groundhog__awake_state', -            content_type=content_type, value_type='C') +            name="État d'éveil", +            key="groundhog__awake_state", +            content_type=content_type, +            value_type="C", +        )          form = CustomForm.objects.create( -            name="Test", form="operation-010-general", available=True, -            apply_to_all=True) +            name="Test", form="operation-010-general", available=True, apply_to_all=True +        )          CustomFormJsonField.objects.create(              custom_form=form,              json_field=field, @@ -1976,50 +2465,52 @@ class CustomFormTest(TestCase, OperationInitTest):          cls_wiz = OperationWizardModifTest()          url = reverse(cls_wiz.url_name)          # first wizard step -        step = 'selec-operation_modification' -        cls_wiz.wizard_post(c, url, step, {'pk': self.operations[0].pk}) +        step = "selec-operation_modification" +        cls_wiz.wizard_post(c, url, step, {"pk": self.operations[0].pk}) -        step = 'general-operation_modification' +        step = "general-operation_modification"          data = { -            '{}{}-current_step'.format(cls_wiz.url_name, -                                       cls_wiz.wizard_name): [step], +            "{}{}-current_step".format(cls_wiz.url_name, cls_wiz.wizard_name): [step],          }          response = c.post(url, data)          self.assertIn( -            b"Le beau", response.content, -            msg="json field not displayed on modification wizard" +            b"Le beau", +            response.content, +            msg="json field not displayed on modification wizard",          ) -        cls_wiz.wizard_post(c, url, step, {'pk': self.operations[1].pk}) +        cls_wiz.wizard_post(c, url, step, {"pk": self.operations[1].pk})          response = c.post(url, data)          self.assertIn( -            b"Le beau", response.content, -            msg="json field form: existing value should be presented in select" +            b"Le beau", +            response.content, +            msg="json field form: existing value should be presented in select",          )  class OperationSearchTest(TestCase, OperationInitTest, SearchText):      fixtures = FILE_FIXTURES -    SEARCH_URL = 'get-operation' +    SEARCH_URL = "get-operation"      def setUp(self): -        IshtarSiteProfile.objects.get_or_create( -            slug='default', active=True) +        IshtarSiteProfile.objects.get_or_create(slug="default", active=True)          self.username, self.password, self.user = create_superuser()          self.alt_username, self.alt_password, self.alt_user = create_user() -        self.alt_user.user_permissions.add(Permission.objects.get( -            codename='view_own_operation')) -        self.alt_user.user_permissions.add(Permission.objects.get( -            codename='change_own_operation')) +        self.alt_user.user_permissions.add( +            Permission.objects.get(codename="view_own_operation") +        ) +        self.alt_user.user_permissions.add( +            Permission.objects.get(codename="change_own_operation") +        )          self.alt_username2, self.alt_password2, self.alt_user2 = create_user( -            username='luke', password='iamyourfather' +            username="luke", password="iamyourfather"          )          profile = UserProfile.objects.create( -            profile_type=ProfileType.objects.get(txt_idx='collaborator'), -            person=self.alt_user2.ishtaruser.person +            profile_type=ProfileType.objects.get(txt_idx="collaborator"), +            person=self.alt_user2.ishtaruser.person,          ) -        town = Town.objects.create(name='Tatouine', numero_insee='66000') -        area = Area.objects.create(label='Galaxie', txt_idx='galaxie') +        town = Town.objects.create(name="Tatouine", numero_insee="66000") +        area = Area.objects.create(label="Galaxie", txt_idx="galaxie")          area.towns.add(town)          profile.areas.add(area) @@ -2033,23 +2524,22 @@ class OperationSearchTest(TestCase, OperationInitTest, SearchText):      def test_base_search(self):          c = Client() -        response = c.get(reverse('get-operation'), {'year': '2010'}) +        response = c.get(reverse("get-operation"), {"year": "2010"})          # no result when no authentication          self.assertTrue(not json.loads(response.content.decode()))          c.login(username=self.username, password=self.password) -        response = c.get(reverse('get-operation'), {'year': '2010'}) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         2) +        response = c.get(reverse("get-operation"), {"year": "2010"}) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 2)          response = c.get( -            reverse('get-operation'), -            {pgettext_lazy("key for text search", "operator"): -             self.orgas[0].name}) +            reverse("get-operation"), +            {pgettext_lazy("key for text search", "operator"): self.orgas[0].name}, +        )          result = json.loads(response.content.decode()) -        self.assertEqual(result['recordsTotal'], 3) +        self.assertEqual(result["recordsTotal"], 3)      def test_base_search_vector(self):          c = Client() -        response = c.get(reverse('get-operation'), {'search_vector': 'chaTEAU'}) +        response = c.get(reverse("get-operation"), {"search_vector": "chaTEAU"})          # no result when no authentication          self.assertTrue(not json.loads(response.content.decode()))          c.login(username=self.username, password=self.password) @@ -2057,17 +2547,16 @@ class OperationSearchTest(TestCase, OperationInitTest, SearchText):          operation = models.Operation.objects.get(pk=self.operations[0].pk)          operation.common_name = "Opération : Château de Fougères"          operation.save() -        response = c.get(reverse('get-operation'), {'search_vector': 'chaTEAU'}) +        response = c.get(reverse("get-operation"), {"search_vector": "chaTEAU"})          result = json.loads(response.content.decode()) -        self.assertEqual(result['recordsTotal'], 1) -        response = c.get(reverse('get-operation'), {'search_vector': 'château'}) +        self.assertEqual(result["recordsTotal"], 1) +        response = c.get(reverse("get-operation"), {"search_vector": "château"})          result = json.loads(response.content.decode()) -        self.assertEqual(result['recordsTotal'], 1) +        self.assertEqual(result["recordsTotal"], 1)          # test search with inappropriate minus sign -        response = c.get(reverse('get-operation'), -                         {'search_vector': 'chaTEAU - '}) +        response = c.get(reverse("get-operation"), {"search_vector": "chaTEAU - "})          result = json.loads(response.content.decode()) -        self.assertEqual(result['recordsTotal'], 1) +        self.assertEqual(result["recordsTotal"], 1)      def test_complex_search_vector(self):          c = Client() @@ -2077,33 +2566,34 @@ class OperationSearchTest(TestCase, OperationInitTest, SearchText):          operation_3 = models.Operation.objects.get(pk=self.operations[2].pk)          operation_1.common_name = "Opération : Château de Fougères"          operation_1.save() -        operation_2.common_name = "Opération : Fougère filicophyta et " \ -                                  "herbe à chat" +        operation_2.common_name = "Opération : Fougère filicophyta et " "herbe à chat"          operation_2.save()          operation_3.common_name = "Opération : Château Filicophyta"          operation_3.save()          # simple separation -        response = c.get(reverse('get-operation'), -                         {'search_vector': 'chaTEAU fougeres'}) +        response = c.get( +            reverse("get-operation"), {"search_vector": "chaTEAU fougeres"} +        )          result = json.loads(response.content.decode()) -        self.assertEqual(result['recordsTotal'], 1) -        response = c.get(reverse('get-operation'), -                         {'search_vector': 'chaTEAU fougere'}) +        self.assertEqual(result["recordsTotal"], 1) +        response = c.get(reverse("get-operation"), {"search_vector": "chaTEAU fougere"})          result = json.loads(response.content.decode()) -        self.assertEqual(result['recordsTotal'], 1) +        self.assertEqual(result["recordsTotal"], 1)          # explicit AND -        response = c.get(reverse('get-operation'), -                         {'search_vector': 'chaTEAU & fougere'}) +        response = c.get( +            reverse("get-operation"), {"search_vector": "chaTEAU & fougere"} +        )          result = json.loads(response.content.decode()) -        self.assertEqual(result['recordsTotal'], 1) +        self.assertEqual(result["recordsTotal"], 1)          # explicit OR -        response = c.get(reverse('get-operation'), -                         {'search_vector': 'chaTEAU | fougere'}) +        response = c.get( +            reverse("get-operation"), {"search_vector": "chaTEAU | fougere"} +        )          result = json.loads(response.content.decode()) -        self.assertEqual(result['recordsTotal'], 3) +        self.assertEqual(result["recordsTotal"], 3)          # query with parenthesis          # response = c.get(reverse('get-operation'), @@ -2112,21 +2602,22 @@ class OperationSearchTest(TestCase, OperationInitTest, SearchText):          # self.assertEqual(result['recordsTotal'], 2)          # query with mistmatch parenthesis -        response = c.get(reverse('get-operation'), -                         {'search_vector': '))   2010 &) ((chaTEAU | fougere)'}) +        response = c.get( +            reverse("get-operation"), +            {"search_vector": "))   2010 &) ((chaTEAU | fougere)"}, +        )          result = json.loads(response.content.decode()) -        self.assertEqual(result['recordsTotal'], 2) +        self.assertEqual(result["recordsTotal"], 2)          # open search -        response = c.get(reverse('get-operation'), {'search_vector': 'cha*'}) +        response = c.get(reverse("get-operation"), {"search_vector": "cha*"})          result = json.loads(response.content.decode()) -        self.assertEqual(result['recordsTotal'], 3) +        self.assertEqual(result["recordsTotal"], 3)          # exclude -        response = c.get(reverse('get-operation'), -                         {'search_vector': '-fougere'}) +        response = c.get(reverse("get-operation"), {"search_vector": "-fougere"})          result = json.loads(response.content.decode()) -        self.assertEqual(result['recordsTotal'], 1) +        self.assertEqual(result["recordsTotal"], 1)      def test_facet_search_vector(self):          ope1 = self.operations[0] @@ -2141,13 +2632,13 @@ class OperationSearchTest(TestCase, OperationInitTest, SearchText):          ope2.year = 2020          ope2.save() -        data = {'numero_insee': '05000', 'name': 'Champoleon (test)'} +        data = {"numero_insee": "05000", "name": "Champoleon (test)"}          town = self.create_towns(datas=data)[-1]          ope1.towns.add(town) -        neo = models.Period.objects.get(txt_idx='neolithic') -        final_neo = models.Period.objects.get(txt_idx='final-neolithic') +        neo = models.Period.objects.get(txt_idx="neolithic") +        final_neo = models.Period.objects.get(txt_idx="final-neolithic")          gallo = models.Period.objects.get(txt_idx="gallo-roman")          ope1.periods.add(final_neo) @@ -2155,7 +2646,7 @@ class OperationSearchTest(TestCase, OperationInitTest, SearchText):          ope2.periods.add(neo)          ope3.periods.add(gallo) -        villa = models.RemainType.objects.get(txt_idx='villa') +        villa = models.RemainType.objects.get(txt_idx="villa")          ope1.remains.add(villa)          search_period_q = str(pgettext("key for text search", "period")) @@ -2180,8 +2671,7 @@ class OperationSearchTest(TestCase, OperationInitTest, SearchText):          result = [              ('{}="{}"'.format(search_town_q, town.cached_label), 1),          ] -        self._test_search(c, result, -                          context="String search with parenthesis and minus") +        self._test_search(c, result, context="String search with parenthesis and minus")          result = [              ('{}="{}"'.format(search_period_q, str(neo)), 2),          ] @@ -2193,10 +2683,18 @@ class OperationSearchTest(TestCase, OperationInitTest, SearchText):          self._test_search(c, result, context="Period exclude")          result = [ -            ('{}="{}"'.format(search_period_q, -                              '{}";"{}'.format(neo.label, gallo.label)), 3), -            ('{}="{}" {}="{}"'.format(search_period_q, neo.label, -                                         search_period_q, gallo.label), 3), +            ( +                '{}="{}"'.format( +                    search_period_q, '{}";"{}'.format(neo.label, gallo.label) +                ), +                3, +            ), +            ( +                '{}="{}" {}="{}"'.format( +                    search_period_q, neo.label, search_period_q, gallo.label +                ), +                3, +            ),          ]          self._test_search(c, result, context="Period OR") @@ -2215,8 +2713,7 @@ class OperationSearchTest(TestCase, OperationInitTest, SearchText):          result = [              ('{}="{}"'.format(search_remain_q, str(villa)), 1),          ] -        self._test_search(c, result, -                          context="Non hierarchic remain search") +        self._test_search(c, result, context="Non hierarchic remain search")          # boolean search          search_open_q = str(pgettext("key for text search", "is-open")) @@ -2236,20 +2733,25 @@ class OperationSearchTest(TestCase, OperationInitTest, SearchText):          search_year_q = str(pgettext("key for text search", "year"))          q = '"chateau fougere" {}="2042"'.format(search_year_q) -        response = c.get(reverse('get-operation'), {'search_vector': q}) +        response = c.get(reverse("get-operation"), {"search_vector": q})          result = json.loads(response.content.decode()) -        self.assertEqual(result['recordsTotal'], 1) +        self.assertEqual(result["recordsTotal"], 1)      def create_relations(self):          rel1 = models.RelationType.objects.create( -            symmetrical=True, label='Include', txt_idx='include') +            symmetrical=True, label="Include", txt_idx="include" +        )          rel2 = models.RelationType.objects.create( -            symmetrical=False, label='Included', txt_idx='included', -            inverse_relation=rel1) +            symmetrical=False, +            label="Included", +            txt_idx="included", +            inverse_relation=rel1, +        )          models.RecordRelations.objects.create(              left_record=self.operations[0],              right_record=self.operations[1], -            relation_type=rel1) +            relation_type=rel1, +        )          return rel1, rel2      def test_related_search(self): @@ -2258,17 +2760,13 @@ class OperationSearchTest(TestCase, OperationInitTest, SearchText):          self.operations[1].year = 2011          self.operations[1].save()          reltype_key = pgettext_lazy("key for text search", "relation-types") -        search = { -            'search_vector': 'year=2010 {}="{}"'.format( -                reltype_key, rel2.name) -        } -        response = c.get(reverse('get-operation'), search) +        search = {"search_vector": 'year=2010 {}="{}"'.format(reltype_key, rel2.name)} +        response = c.get(reverse("get-operation"), search)          # no result when no authentication          self.assertTrue(not json.loads(response.content.decode()))          c.login(username=self.username, password=self.password) -        response = c.get(reverse('get-operation'), search) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         2) +        response = c.get(reverse("get-operation"), search) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 2)      def test_search_with_problematic_characters(self):          c = Client() @@ -2281,63 +2779,59 @@ class OperationSearchTest(TestCase, OperationInitTest, SearchText):          result = [              ('{}="{}"'.format(search_name_q, lbl), 1),          ] -        self._test_search(c, result, -                          context="Facet search with = and | characters") +        self._test_search(c, result, context="Facet search with = and | characters")      def test_search_with_asterisk_inside_names(self):          c = Client()          c.login(username=self.username, password=self.password)          ope = self.operations[0]          ope_type = ope.operation_type -        ope_type.label = 'label*with*asterisk' +        ope_type.label = "label*with*asterisk"          ope_type.save()          search_name_q = str(pgettext("key for text search", "type"))          nb = models.Operation.objects.filter(operation_type=ope_type).count()          result = [              ('{}="{}"'.format(search_name_q, ope_type.label), nb),          ] -        self._test_search(c, result, -                          context="Facet search with * characters") +        self._test_search(c, result, context="Facet search with * characters")      def test_hierarchic_search(self):          ope = self.operations[1]          c = Client() -        neo = models.Period.objects.get(txt_idx='neolithic') -        final_neo = models.Period.objects.get(txt_idx='final-neolithic') -        recent_neo = models.Period.objects.get(txt_idx='recent-neolithic') +        neo = models.Period.objects.get(txt_idx="neolithic") +        final_neo = models.Period.objects.get(txt_idx="final-neolithic") +        recent_neo = models.Period.objects.get(txt_idx="recent-neolithic")          ope.periods.add(final_neo) -        search = {'periods': final_neo.pk} +        search = {"periods": final_neo.pk}          # no result when no authentication -        response = c.get(reverse('get-operation'), search) +        response = c.get(reverse("get-operation"), search)          self.assertEqual(response.status_code, 200)          self.assertTrue(not json.loads(response.content.decode()))          c.login(username=self.username, password=self.password)          # one result for exact search -        response = c.get(reverse('get-operation'), search) +        response = c.get(reverse("get-operation"), search)          self.assertEqual(response.status_code, 200)          res = json.loads(response.content.decode()) -        self.assertTrue(res['recordsTotal'] == 1) +        self.assertTrue(res["recordsTotal"] == 1)          # no result for the brother -        search = {'periods': recent_neo.pk} -        response = c.get(reverse('get-operation'), search) +        search = {"periods": recent_neo.pk} +        response = c.get(reverse("get-operation"), search)          self.assertEqual(response.status_code, 200) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         0) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 0)          # one result for the father -        search = {'periods': neo.pk} -        response = c.get(reverse('get-operation'), search) +        search = {"periods": neo.pk} +        response = c.get(reverse("get-operation"), search)          self.assertEqual(response.status_code, 200) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         1) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 1)          # test on text search -        period_key = str(pgettext_lazy("key for text search", 'period')) +        period_key = str(pgettext_lazy("key for text search", "period"))          result = [              ('{}="{}"'.format(period_key, str(final_neo)), 1),              ('{}="{}"'.format(period_key, str(recent_neo)), 0), @@ -2349,14 +2843,14 @@ class OperationSearchTest(TestCase, OperationInitTest, SearchText):          c = Client()          c.login(username=self.username, password=self.password) -        data = {'numero_insee': '98989', 'name': 'base_town'} +        data = {"numero_insee": "98989", "name": "base_town"}          base_town = self.create_towns(datas=data)[-1] -        data = {'numero_insee': '56789', 'name': 'parent_town'} +        data = {"numero_insee": "56789", "name": "parent_town"}          parent_town = self.create_towns(datas=data)[-1]          parent_town.children.add(base_town) -        data = {'numero_insee': '01234', 'name': 'child_town'} +        data = {"numero_insee": "01234", "name": "child_town"}          child_town = self.create_towns(datas=data)[-1]          base_town.children.add(child_town) @@ -2364,32 +2858,28 @@ class OperationSearchTest(TestCase, OperationInitTest, SearchText):          ope.towns.add(base_town)          # simple search -        search = {'towns': base_town.pk} -        response = c.get(reverse('get-operation'), search) +        search = {"towns": base_town.pk} +        response = c.get(reverse("get-operation"), search)          self.assertEqual(response.status_code, 200) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         1) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 1)          # parent search -        search = {'towns': parent_town.pk} -        response = c.get(reverse('get-operation'), search) +        search = {"towns": parent_town.pk} +        response = c.get(reverse("get-operation"), search)          self.assertEqual(response.status_code, 200) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         1) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 1)          # child search -        search = {'towns': child_town.pk} -        response = c.get(reverse('get-operation'), search) +        search = {"towns": child_town.pk} +        response = c.get(reverse("get-operation"), search)          self.assertEqual(response.status_code, 200) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         1) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 1)      def test_statistics(self):          c = Client()          c.login(username=self.username, password=self.password) -        q = {"stats_modality_1": "year", -             "stats_modality_2": "operation_type__label"} -        response = c.get(reverse('get-operation', args=['json-stats']), q) +        q = {"stats_modality_1": "year", "stats_modality_2": "operation_type__label"} +        response = c.get(reverse("get-operation", args=["json-stats"]), q)          self.assertEqual(response.status_code, 200)          expected_result = [] @@ -2411,32 +2901,33 @@ class OperationSearchTest(TestCase, OperationInitTest, SearchText):              current_values[val_idx][1] += 1          values = json.loads(response.content.decode()) -        self.assertEqual(values['data'], expected_result) +        self.assertEqual(values["data"], expected_result)  class OperationPermissionTest(TestCase, OperationInitTest):      fixtures = FILE_FIXTURES      def setUp(self): -        IshtarSiteProfile.objects.get_or_create( -            slug='default', active=True) +        IshtarSiteProfile.objects.get_or_create(slug="default", active=True)          self.username, self.password, self.user = create_superuser()          self.alt_username, self.alt_password, self.alt_user = create_user() -        self.alt_user.user_permissions.add(Permission.objects.get( -            codename='view_own_operation')) -        self.alt_user.user_permissions.add(Permission.objects.get( -            codename='change_own_operation')) +        self.alt_user.user_permissions.add( +            Permission.objects.get(codename="view_own_operation") +        ) +        self.alt_user.user_permissions.add( +            Permission.objects.get(codename="change_own_operation") +        )          self.alt_username2, self.alt_password2, self.alt_user2 = create_user( -            username='luke', password='iamyourfather' +            username="luke", password="iamyourfather"          ) -        profile_type = ProfileType.objects.get(txt_idx='collaborator') +        profile_type = ProfileType.objects.get(txt_idx="collaborator")          profile = UserProfile.objects.create(              profile_type=profile_type,              person=self.alt_user2.ishtaruser.person, -            current=True +            current=True,          ) -        town = Town.objects.create(name='Tatouine', numero_insee='66000') -        area = Area.objects.create(label='Galaxie', txt_idx='galaxie') +        town = Town.objects.create(name="Tatouine", numero_insee="66000") +        area = Area.objects.create(label="Galaxie", txt_idx="galaxie")          area.towns.add(town)          profile.areas.add(area) @@ -2449,86 +2940,76 @@ class OperationPermissionTest(TestCase, OperationInitTest):      def test_own_search(self):          # no result when no authentification          c = Client() -        response = c.get(reverse('get-operation'), {'year': '2010'}) +        response = c.get(reverse("get-operation"), {"year": "2010"})          self.assertTrue(not json.loads(response.content.decode()))          # possession          c = Client()          c.login(username=self.alt_username, password=self.alt_password) -        response = c.get(reverse('get-operation'), {'year': '2010'}) +        response = c.get(reverse("get-operation"), {"year": "2010"})          # only one "own" operation available          self.assertTrue(json.loads(response.content.decode())) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         1) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 1)          operator_key = pgettext_lazy("key for text search", "operator") -        response = c.get(reverse('get-operation'), -                         {operator_key: self.orgas[0].name}) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         1) -        response = c.get(reverse('get-operation'), -                         {'search_vector': '{}="{}"'.format( -                          operator_key, self.orgas[0].name)}) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         1) +        response = c.get(reverse("get-operation"), {operator_key: self.orgas[0].name}) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 1) +        response = c.get( +            reverse("get-operation"), +            {"search_vector": '{}="{}"'.format(operator_key, self.orgas[0].name)}, +        ) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 1)          # area filter          c = Client()          c.login(username=self.alt_username2, password=self.alt_password2) -        response = c.get(reverse('get-operation'), -                         {'year': '2010'}) +        response = c.get(reverse("get-operation"), {"year": "2010"})          # only one "own" operation available          self.assertTrue(json.loads(response.content.decode())) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         1) -        response = c.get(reverse('get-operation'), -                         {operator_key: self.orgas[0].name}) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         1) -        response = c.get(reverse('get-operation'), -                         {'search_vector': '{}="{}"'.format( -                          operator_key, self.orgas[0].name)}) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         1) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 1) +        response = c.get(reverse("get-operation"), {operator_key: self.orgas[0].name}) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 1) +        response = c.get( +            reverse("get-operation"), +            {"search_vector": '{}="{}"'.format(operator_key, self.orgas[0].name)}, +        ) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 1)      def test_own_modify(self):          operation_pk1 = self.operations[0].pk          operation_pk2 = self.operations[1].pk -        modif_url = '/operation_modification/general-operation_modification' +        modif_url = "/operation_modification/general-operation_modification"          # no result when no authentification          c = Client() -        response = c.get(reverse('operation_modify', args=[operation_pk2])) +        response = c.get(reverse("operation_modify", args=[operation_pk2]))          self.assertRedirects(response, "/")          # possession          c = Client()          c.login(username=self.alt_username, password=self.alt_password) -        response = c.get(reverse('operation_modify', args=[operation_pk2]), -                         follow=True) +        response = c.get(reverse("operation_modify", args=[operation_pk2]), follow=True)          self.assertRedirects(response, modif_url)          response = c.get(modif_url)          self.assertEqual(response.status_code, 200) -        response = c.get(reverse('operation_modify', args=[operation_pk1]), -                         follow=True) +        response = c.get(reverse("operation_modify", args=[operation_pk1]), follow=True)          self.assertRedirects(response, "/") -        profile_type = ProfileType.objects.get(txt_idx='collaborator') +        profile_type = ProfileType.objects.get(txt_idx="collaborator")          profile_type.groups.add( -            Group.objects.get(name="Opérations rattachées : " -                                   "modification/suppression") +            Group.objects.get( +                name="Opérations rattachées : " "modification/suppression" +            )          )          # area filter          c = Client()          c.login(username=self.alt_username2, password=self.alt_password2) -        response = c.get(reverse('operation_modify', args=[operation_pk2]), -                         follow=True) +        response = c.get(reverse("operation_modify", args=[operation_pk2]), follow=True)          self.assertRedirects(response, modif_url)          response = c.get(modif_url)          self.assertEqual(response.status_code, 200) -        response = c.get(reverse('operation_modify', args=[operation_pk1]), -                         follow=True) +        response = c.get(reverse("operation_modify", args=[operation_pk1]), follow=True)          self.assertRedirects(response, "/") @@ -2536,8 +3017,7 @@ class LabelTest(TestCase, OperationInitTest):      fixtures = FILE_FIXTURES      def setUp(self): -        IshtarSiteProfile.objects.get_or_create( -            slug='default', active=True) +        IshtarSiteProfile.objects.get_or_create(slug="default", active=True)          self.username, self.password, self.user = create_superuser()          self.orgas = self.create_orgas(self.user)          self.operations = self.create_operation(self.user, self.orgas[0]) @@ -2548,12 +3028,11 @@ class LabelTest(TestCase, OperationInitTest):          ope.save()          tpl = open( -            settings.ROOT_PATH + -            '../archaeological_operations/tests/labels-8.odt', -            'rb') +            settings.ROOT_PATH + "../archaeological_operations/tests/labels-8.odt", "rb" +        )          template = SimpleUploadedFile(tpl.name, tpl.read())          model, __ = ImporterModel.objects.get_or_create( -            klass='archaeological_operations.models.Operation' +            klass="archaeological_operations.models.Operation"          )          doc = DocumentTemplate.objects.create(              name="Labels", @@ -2562,7 +3041,7 @@ class LabelTest(TestCase, OperationInitTest):              available=True,              for_labels=True,              label_per_page=8, -            template=template +            template=template,          )          c = Client()          url = reverse("generate-labels", args=[doc.slug]) @@ -2577,9 +3056,9 @@ class LabelTest(TestCase, OperationInitTest):              f = BytesIO(response.content)              z = zipfile.ZipFile(f)              self.assertIsNone(z.testzip()) -            content = z.open('content.xml') +            content = z.open("content.xml")              full_content = content.read() -            self.assertIn(b'1789', full_content) +            self.assertIn(b"1789", full_content)              # jpe file are added for missing pictures / must be filtered              self.assertNotIn(b'.jpe"', full_content)          finally: @@ -2595,14 +3074,13 @@ class DashboardTest(TestCase, OperationInitTest):      fixtures = FILE_FIXTURES      def setUp(self): -        IshtarSiteProfile.objects.get_or_create( -            slug='default', active=True) +        IshtarSiteProfile.objects.get_or_create(slug="default", active=True)          self.username, self.password, self.user = create_superuser()          self.orgas = self.create_orgas(self.user)          self.operations = self.create_operation(self.user, self.orgas[0])      def test_dashboard(self): -        url = 'dashboard-operation' +        url = "dashboard-operation"          c = Client()          c.login(username=self.username, password=self.password) @@ -2612,12 +3090,15 @@ class DashboardTest(TestCase, OperationInitTest):  def create_administrativact(user, operation):      act_type, created = models.ActType.objects.get_or_create( -        txt_idx='act_type_O', intented_to='O') -    dct = {'history_modifier': user, -           'act_type': act_type, -           'operation': operation, -           'signature_date': datetime.date(2014, 5, 12), -           'index': 322} +        txt_idx="act_type_O", intented_to="O" +    ) +    dct = { +        "history_modifier": user, +        "act_type": act_type, +        "operation": operation, +        "signature_date": datetime.date(2014, 5, 12), +        "index": 322, +    }      adminact, created = models.AdministrativeAct.objects.get_or_create(**dct)      return [act_type], [adminact] @@ -2629,53 +3110,53 @@ class RegisterTest(TestCase, OperationInitTest):          self.username, self.password, self.user = create_superuser()          self.operations = self.create_operation(self.user)          self.act_types, self.admin_acts = create_administrativact( -            self.user, self.operations[0]) +            self.user, self.operations[0] +        )      def test_search(self):          c = Client() -        response = c.get(reverse('get-administrativeact'), {'year': '2014'}) +        response = c.get(reverse("get-administrativeact"), {"year": "2014"})          # no result when no authentication          self.assertTrue(not json.loads(response.content.decode()))          c.login(username=self.username, password=self.password) -        response = c.get(reverse('get-administrativeact'), {'year': '2014'}) -        self.assertEqual( -            json.loads(response.content.decode())['recordsTotal'], 1) -        response = c.get(reverse('get-administrativeact'), {'indexed': '2'}) -        self.assertEqual( -            json.loads(response.content.decode())['recordsTotal'], 1) +        response = c.get(reverse("get-administrativeact"), {"year": "2014"}) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 1) +        response = c.get(reverse("get-administrativeact"), {"indexed": "2"}) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 1)      def test_document_generation(self):          tpl = open( -            settings.ROOT_PATH + -            '../archaeological_operations/tests/document_reference.odt', -            'rb') +            settings.ROOT_PATH +            + "../archaeological_operations/tests/document_reference.odt", +            "rb", +        )          template = SimpleUploadedFile(tpl.name, tpl.read())          model, __ = ImporterModel.objects.get_or_create( -            klass='archaeological_operations.models.AdministrativeAct' +            klass="archaeological_operations.models.AdministrativeAct"          )          doc = DocumentTemplate.objects.create(              name="Test",              slug=True,              associated_model=model,              available=True, -            template=template +            template=template,          )          self.act_types[0].associated_template.add(doc)          c = Client() -        data = {'pk': self.admin_acts[0].pk, 'document_template': doc.pk} -        response = c.post(reverse('operation-administrativeact-document'), data) +        data = {"pk": self.admin_acts[0].pk, "document_template": doc.pk} +        response = c.post(reverse("operation-administrativeact-document"), data)          # no result when no authentication          self.assertEqual(response.content, b"")          c.login(username=self.username, password=self.password) -        response = c.post(reverse('operation-administrativeact-document'), data) +        response = c.post(reverse("operation-administrativeact-document"), data)          content, z, f = None, None, None          try:              f = BytesIO(response.content)              z = zipfile.ZipFile(f)              self.assertIsNone(z.testzip()) -            content = z.open('content.xml') -            self.assertIn(b'2014-05-12', content.read()) +            content = z.open("content.xml") +            self.assertIn(b"2014-05-12", content.read())          finally:              if content:                  content.close() @@ -2687,204 +3168,209 @@ class RegisterTest(TestCase, OperationInitTest):  class OperationWizardCreationTest(WizardTest, OperationInitTest, TestCase):      fixtures = FILE_FIXTURES -    url_name = 'operation_creation' -    wizard_name = 'operation_wizard' +    url_name = "operation_creation" +    wizard_name = "operation_wizard"      steps = views.wizard_steps -    redirect_url = "/operation_modification/selec-operation_modification"\ -                   "?open_item={last_id}" +    redirect_url = ( +        "/operation_modification/selec-operation_modification" "?open_item={last_id}" +    )      model = models.Operation      form_datas = [          FormData(              "Create a preventive diag",              form_datas={ -                'filechoice': {}, -                'general': { -                    'code_patriarche': 'codeope1', -                    'operation_type': None, -                    'year': 2016}, -                'townsgeneral': [], -                'parcelsgeneral': [], +                "filechoice": {}, +                "general": { +                    "code_patriarche": "codeope1", +                    "operation_type": None, +                    "year": 2016, +                }, +                "townsgeneral": [], +                "parcelsgeneral": [],              }, -            ignored=('towns-operation_creation', -                     'parcels-operation_creation', -                     'judiciary-operation_creation', -                     'preventive-operation_creation') +            ignored=( +                "towns-operation_creation", +                "parcels-operation_creation", +                "judiciary-operation_creation", +                "preventive-operation_creation", +            ),          ),          FormData(              "Create another preventive diag with same parcel name",              form_datas={ -                'filechoice': {}, -                'general': { -                    'code_patriarche': 'codeope2', -                    'operation_type': None, -                    'year': 2016}, -                'townsgeneral': [], -                'parcelsgeneral': [], +                "filechoice": {}, +                "general": { +                    "code_patriarche": "codeope2", +                    "operation_type": None, +                    "year": 2016, +                }, +                "townsgeneral": [], +                "parcelsgeneral": [],              }, -            ignored=('towns-operation_creation', -                     'parcels-operation_creation', -                     'judiciary-operation_creation', -                     'preventive-operation_creation') +            ignored=( +                "towns-operation_creation", +                "parcels-operation_creation", +                "judiciary-operation_creation", +                "preventive-operation_creation", +            ),          ),          FormData(              "Create an operation related to a file",              form_datas={ -                'filechoice': {}, -                'general': { -                    'code_patriarche': 'codeope3', -                    'operation_type': None, -                    'year': 2016}, -                'towns': [], -                'parcels': [], +                "filechoice": {}, +                "general": { +                    "code_patriarche": "codeope3", +                    "operation_type": None, +                    "year": 2016, +                }, +                "towns": [], +                "parcels": [],              }, -            ignored=('townsgeneral-operation_creation', -                     'parcelsgeneral-operation_creation', -                     'judiciary-operation_creation', -                     'preventive-operation_creation') +            ignored=( +                "townsgeneral-operation_creation", +                "parcelsgeneral-operation_creation", +                "judiciary-operation_creation", +                "preventive-operation_creation", +            ),          ),      ]      def pre_wizard(self):          profile, created = IshtarSiteProfile.objects.get_or_create( -            slug='default', active=True) +            slug="default", active=True +        )          profile.files = True          profile.save() -        if 'townsgeneral' not in \ -                self.form_datas[0].form_datas: +        if "townsgeneral" not in self.form_datas[0].form_datas:              return super(OperationWizardCreationTest, self).pre_wizard()          town = self.create_towns()[0] -        town_data = {'town': town.pk} +        town_data = {"town": town.pk}          parcel_data = { -            'town': town.pk, 'year': 2017, 'section': 'S', -            'parcel_number': '42'} +            "town": town.pk, +            "year": 2017, +            "section": "S", +            "parcel_number": "42", +        }          for idx in range(2): -            self.form_datas[idx].append('townsgeneral', town_data) -            self.form_datas[idx].append('parcelsgeneral', parcel_data) +            self.form_datas[idx].append("townsgeneral", town_data) +            self.form_datas[idx].append("parcelsgeneral", parcel_data)          FI = FileInit()          FI.create_file()          file = FI.item          file.towns.add(town)          parcel = models.Parcel.objects.create( -            town=town, year=2017, section='G', parcel_number='43' +            town=town, year=2017, section="G", parcel_number="43"          )          file.parcels.add(parcel) -        self.form_datas[2].set('filechoice', 'associated_file', file.pk) -        self.form_datas[2].append('parcelsgeneral', {'parcel': parcel.pk}) -        self.form_datas[2].append('towns', town_data) -        self.form_datas[2].append('parcels', {'parcel': parcel.pk}) +        self.form_datas[2].set("filechoice", "associated_file", file.pk) +        self.form_datas[2].append("parcelsgeneral", {"parcel": parcel.pk}) +        self.form_datas[2].append("towns", town_data) +        self.form_datas[2].append("parcels", {"parcel": parcel.pk})          # diagnostic -        ope_type = models.OperationType.objects.get(txt_idx='arch_diagnostic') -        self.form_datas[0].set('general', 'operation_type', ope_type.pk) -        self.form_datas[1].set('general', 'operation_type', ope_type.pk) -        self.form_datas[2].set('general', 'operation_type', ope_type.pk) +        ope_type = models.OperationType.objects.get(txt_idx="arch_diagnostic") +        self.form_datas[0].set("general", "operation_type", ope_type.pk) +        self.form_datas[1].set("general", "operation_type", ope_type.pk) +        self.form_datas[2].set("general", "operation_type", ope_type.pk)          self.operation_number = models.Operation.objects.count()          self.parcel_number = models.Parcel.objects.count()          super(OperationWizardCreationTest, self).pre_wizard()      def post_wizard(self): -        self.assertEqual(models.Operation.objects.count(), -                         self.operation_number + 3) +        self.assertEqual(models.Operation.objects.count(), self.operation_number + 3)          operations = models.Operation.objects.order_by("-pk").all()[:3]          parcel_ids = []          for operation in operations:              for parcel in operation.parcels.all():                  parcel_ids.append(parcel.external_id) -        self.assertEqual(list(sorted(parcel_ids)), -                         ['codeope1-12345-S42', 'codeope2-12345-S42', -                          'codeope3-12345-G43']) -        self.assertEqual(models.Parcel.objects.count(), -                         self.parcel_number + 3) +        self.assertEqual( +            list(sorted(parcel_ids)), +            ["codeope1-12345-S42", "codeope2-12345-S42", "codeope3-12345-G43"], +        ) +        self.assertEqual(models.Parcel.objects.count(), self.parcel_number + 3)  class OperationWizardModifTest(WizardTest, OperationInitTest, TestCase):      fixtures = FILE_FIXTURES -    url_name = 'operation_modification' -    wizard_name = url_name + '_wizard' +    url_name = "operation_modification" +    wizard_name = url_name + "_wizard"      steps = views.operation_modif_wizard_steps      redirect_url = "/{url_name}/selec-{url_name}?open_item={current_id}"      model = models.Operation      base_ignored_steps = ( -        'archaeologicalsite-operation_modification', -        'preventive-operation_modification', -        'preventivediag-operation_modification', -        'judiciary-operation_modification', -        'towns-operation_modification', -        'parcels-operation_modification', -        'remains-operation_modification', -        'periods-operation_modification', -        'relations-operation_modification', -        'abstract-operation_modification',) +        "archaeologicalsite-operation_modification", +        "preventive-operation_modification", +        "preventivediag-operation_modification", +        "judiciary-operation_modification", +        "towns-operation_modification", +        "parcels-operation_modification", +        "remains-operation_modification", +        "periods-operation_modification", +        "relations-operation_modification", +        "abstract-operation_modification", +    )      form_datas = [          FormData(              "Update an operation",              form_datas={ -                'selec': {}, -                'general': { -                    'operation_type': 2, -                    'year': 2017}, -                'townsgeneral': [], -                'parcelsgeneral': [], +                "selec": {}, +                "general": {"operation_type": 2, "year": 2017}, +                "townsgeneral": [], +                "parcelsgeneral": [],              }, -            ignored=base_ignored_steps +            ignored=base_ignored_steps,          ),          FormData(              "Operation: try to remove a parcel with attached context record",              form_datas={ -                'selec': {}, -                'general': { -                    'code_patriarche': "codeope42", -                    'operation_type': 2, -                    'year': 2017}, -                'townsgeneral': [], -                'parcelsgeneral': [], +                "selec": {}, +                "general": { +                    "code_patriarche": "codeope42", +                    "operation_type": 2, +                    "year": 2017, +                }, +                "townsgeneral": [], +                "parcelsgeneral": [],              }, -            ignored=base_ignored_steps +            ignored=base_ignored_steps,          ),          FormData(              "Operation: remove a parcel with no attached context record",              form_datas={ -                'selec': {}, -                'general': { -                    'operation_type': 2, -                    'year': 2017}, -                'townsgeneral': [], -                'parcelsgeneral': [], +                "selec": {}, +                "general": {"operation_type": 2, "year": 2017}, +                "townsgeneral": [], +                "parcelsgeneral": [],              }, -            ignored=base_ignored_steps +            ignored=base_ignored_steps,          ),          FormData(              "Set an operation to an exiting operation code for this year",              form_datas={ -                'selec': {}, -                'general': { -                    'operation_type': 2, -                    'operation_code': 42, -                    'year': 2017}, -                'townsgeneral': [], -                'parcelsgeneral': [], +                "selec": {}, +                "general": {"operation_type": 2, "operation_code": 42, "year": 2017}, +                "townsgeneral": [], +                "parcelsgeneral": [],              },              ignored=base_ignored_steps, -            error_expected='general' +            error_expected="general",          ),          FormData(              "Operation: change a parcel",              form_datas={ -                'selec': {}, -                'general': { -                    'operation_type': 2, -                    'year': 2017}, -                'townsgeneral': [], -                'parcelsgeneral': [], +                "selec": {}, +                "general": {"operation_type": 2, "year": 2017}, +                "townsgeneral": [], +                "parcelsgeneral": [],              }, -            ignored=base_ignored_steps +            ignored=base_ignored_steps,          ),      ] @@ -2903,19 +3389,22 @@ class OperationWizardModifTest(WizardTest, OperationInitTest, TestCase):          operation2.save()          from archaeological_context_records.models import ContextRecord -        cr_data = {'label': "Context record", "operation": operation, -                   'parcel': init_parcel, -                   'history_modifier': self.get_default_user()} + +        cr_data = { +            "label": "Context record", +            "operation": operation, +            "parcel": init_parcel, +            "history_modifier": self.get_default_user(), +        }          self.cr = ContextRecord.objects.create(**cr_data)          # diagnostic -        self.ope_type = models.OperationType.objects.get( -            txt_idx='prev_excavation') -        self.form_datas[0].set('general', 'operation_type', self.ope_type.pk) -        self.form_datas[1].set('general', 'operation_type', self.ope_type.pk) -        self.form_datas[2].set('general', 'operation_type', self.ope_type.pk) -        self.form_datas[3].set('general', 'operation_type', self.ope_type.pk) -        self.form_datas[4].set('general', 'operation_type', self.ope_type.pk) +        self.ope_type = models.OperationType.objects.get(txt_idx="prev_excavation") +        self.form_datas[0].set("general", "operation_type", self.ope_type.pk) +        self.form_datas[1].set("general", "operation_type", self.ope_type.pk) +        self.form_datas[2].set("general", "operation_type", self.ope_type.pk) +        self.form_datas[3].set("general", "operation_type", self.ope_type.pk) +        self.form_datas[4].set("general", "operation_type", self.ope_type.pk)          data = self.form_datas[0].form_datas          data2 = self.form_datas[1].form_datas @@ -2923,116 +3412,124 @@ class OperationWizardModifTest(WizardTest, OperationInitTest, TestCase):          data4 = self.form_datas[3].form_datas          data5 = self.form_datas[4].form_datas -        data['selec']['pk'] = operation.pk -        data2['selec']['pk'] = operation.pk -        data3['selec']['pk'] = operation.pk -        data4['selec']['pk'] = operation.pk -        data5['selec']['pk'] = operation.pk +        data["selec"]["pk"] = operation.pk +        data2["selec"]["pk"] = operation.pk +        data3["selec"]["pk"] = operation.pk +        data4["selec"]["pk"] = operation.pk +        data5["selec"]["pk"] = operation.pk -        town = self.create_towns( -            datas={'numero_insee': '67890', 'name': 'Twin Peaks'})[-1] -        towns = [{'town': town.pk}, {'town': init_town.pk}] +        town = self.create_towns(datas={"numero_insee": "67890", "name": "Twin Peaks"})[ +            -1 +        ] +        towns = [{"town": town.pk}, {"town": init_town.pk}]          parcel_data = { -            'town': town.pk, 'year': 2017, 'section': 'S', -            'parcel_number': '42'} +            "town": town.pk, +            "year": 2017, +            "section": "S", +            "parcel_number": "42", +        }          for idx in range(0, 5):              for t in towns: -                self.form_datas[idx].append('townsgeneral', t) +                self.form_datas[idx].append("townsgeneral", t)              if idx != 4: -                self.form_datas[idx].append('parcelsgeneral', parcel_data) +                self.form_datas[idx].append("parcelsgeneral", parcel_data)          parcel_data_2 = { -            'town': init_parcel.town.pk, 'year': init_parcel.year or '', -            'section': init_parcel.section, -            'pk': init_parcel.pk, -            'parcel_number': init_parcel.parcel_number} -        data['parcelsgeneral'].append(parcel_data_2) +            "town": init_parcel.town.pk, +            "year": init_parcel.year or "", +            "section": init_parcel.section, +            "pk": init_parcel.pk, +            "parcel_number": init_parcel.parcel_number, +        } +        data["parcelsgeneral"].append(parcel_data_2)          p = parcel_data.copy() -        p['parcel_number'] = '43' -        self.form_datas[4].form_datas['parcelsgeneral'] = [p] +        p["parcel_number"] = "43" +        self.form_datas[4].form_datas["parcelsgeneral"] = [p]          self.operation_number = models.Operation.objects.count()          self.parcel_number = models.Parcel.objects.count()          def post_first_wizard(test_object, final_step_response): -            test_object.assertEqual(models.Operation.objects.count(), -                                    test_object.operation_number) -            operation = models.Operation.objects.get( -                pk=test_object.operations[0].pk) -            test_object.assertEqual(operation.operation_type.pk, -                                    self.ope_type.pk) +            test_object.assertEqual( +                models.Operation.objects.count(), test_object.operation_number +            ) +            operation = models.Operation.objects.get(pk=test_object.operations[0].pk) +            test_object.assertEqual(operation.operation_type.pk, self.ope_type.pk)              test_object.assertEqual(operation.year, 2017) -            test_object.assertEqual(models.Parcel.objects.count(), -                                    test_object.parcel_number + 1) -            test_object.assertEqual(operation.parcels.count(), -                                    test_object.parcel_number + 1) +            test_object.assertEqual( +                models.Parcel.objects.count(), test_object.parcel_number + 1 +            ) +            test_object.assertEqual( +                operation.parcels.count(), test_object.parcel_number + 1 +            )          def pre_second_wizard(test_object):              test_object.form_datas[1].form_datas[ -                      'parcelsgeneral-operation_modification'][0]["pk"] = \ -                models.Parcel.objects.get(parcel_number="42").pk +                "parcelsgeneral-operation_modification" +            ][0]["pk"] = models.Parcel.objects.get(parcel_number="42").pk          def post_second_wizard(test_object, final_step_response): -            test_object.assertEqual(models.Operation.objects.count(), -                                    test_object.operation_number) -            operation = models.Operation.objects.get( -                pk=test_object.operations[0].pk) -            test_object.assertEqual(operation.operation_type.pk, -                                    self.ope_type.pk) +            test_object.assertEqual( +                models.Operation.objects.count(), test_object.operation_number +            ) +            operation = models.Operation.objects.get(pk=test_object.operations[0].pk) +            test_object.assertEqual(operation.operation_type.pk, self.ope_type.pk)              test_object.assertEqual(operation.year, 2017) -            test_object.assertEqual(models.Parcel.objects.count(), -                                    test_object.parcel_number + 1) +            test_object.assertEqual( +                models.Parcel.objects.count(), test_object.parcel_number + 1 +            )              # the init parcel is not submited but have a context record              # the init parcel is not detached from the operation -            test_object.assertEqual(operation.parcels.count(), -                                    test_object.parcel_number + 1) +            test_object.assertEqual( +                operation.parcels.count(), test_object.parcel_number + 1 +            )              # update the external id on update              cr = ContextRecord.objects.get(pk=self.cr.pk) -            test_object.assertEqual(cr.external_id, -                                    "codeope42-12345-A1-Context record") +            test_object.assertEqual(cr.external_id, "codeope42-12345-A1-Context record")          def pre_third_wizard(test_object):              parcel_nb = models.Parcel.objects.count()              test_object.cr.delete() -            test_object.assertEqual( -                parcel_nb, models.Parcel.objects.count()) +            test_object.assertEqual(parcel_nb, models.Parcel.objects.count())          def post_third_wizard(test_object, final_step_response): -            test_object.assertEqual(models.Operation.objects.count(), -                                    test_object.operation_number) -            operation = models.Operation.objects.get( -                pk=test_object.operations[0].pk) -            test_object.assertEqual(operation.operation_type.pk, -                                    self.ope_type.pk) +            test_object.assertEqual( +                models.Operation.objects.count(), test_object.operation_number +            ) +            operation = models.Operation.objects.get(pk=test_object.operations[0].pk) +            test_object.assertEqual(operation.operation_type.pk, self.ope_type.pk)              test_object.assertEqual(operation.year, 2017)              # with no attach the parcel is deleted -            test_object.assertEqual(operation.parcels.count(), -                                    test_object.parcel_number) +            test_object.assertEqual( +                operation.parcels.count(), test_object.parcel_number +            )              # the parcel object is no more automatically deleted -            test_object.assertEqual(models.Parcel.objects.count(), -                                    test_object.parcel_number + 1) +            test_object.assertEqual( +                models.Parcel.objects.count(), test_object.parcel_number + 1 +            )          def pre_fifth_wizard(test_object):              test_object.parcel_number = models.Parcel.objects.count() -            operation = models.Operation.objects.get( -                pk=test_object.operations[0].pk) +            operation = models.Operation.objects.get(pk=test_object.operations[0].pk)              test_object.operation_parcel_number = operation.parcels.count()              test_object.form_datas[4].form_datas[ -                'parcelsgeneral-operation_modification'][0]["pk"] = \ -                models.Parcel.objects.get(parcel_number="42").pk +                "parcelsgeneral-operation_modification" +            ][0]["pk"] = models.Parcel.objects.get(parcel_number="42").pk          def post_fifth_wizard(test_object, final_step_response): -            test_object.assertEqual(models.Operation.objects.count(), -                                    test_object.operation_number) -            operation = models.Operation.objects.get( -                pk=test_object.operations[0].pk) -            test_object.assertEqual(models.Parcel.objects.count(), -                                    test_object.parcel_number) -            test_object.assertEqual(operation.parcels.count(), -                                    test_object.operation_parcel_number) +            test_object.assertEqual( +                models.Operation.objects.count(), test_object.operation_number +            ) +            operation = models.Operation.objects.get(pk=test_object.operations[0].pk) +            test_object.assertEqual( +                models.Parcel.objects.count(), test_object.parcel_number +            ) +            test_object.assertEqual( +                operation.parcels.count(), test_object.operation_parcel_number +            )          self.form_datas[0].extra_tests = [post_first_wizard]          self.form_datas[1].pre_tests = [pre_second_wizard] @@ -3046,16 +3543,16 @@ class OperationWizardModifTest(WizardTest, OperationInitTest, TestCase):  class OperationWizardDeleteTest(OperationWizardCreationTest):      fixtures = FILE_FIXTURES -    url_name = 'operation_deletion' -    wizard_name = 'operation_deletion_wizard' +    url_name = "operation_deletion" +    wizard_name = "operation_deletion_wizard"      steps = views.operation_deletion_steps      redirect_url = "/{}/selec-{}".format(url_name, url_name)      form_datas = [          FormData(              "Wizard deletion test",              form_datas={ -                'selec-operation_deletion': {'pks': None}, -            } +                "selec-operation_deletion": {"pks": None}, +            },          )      ] @@ -3068,38 +3565,35 @@ class OperationWizardDeleteTest(OperationWizardCreationTest):          self.ope = self.get_default_operation(force=True)          self.ope.parcels.add(self.create_parcel()[0])          self.parcel_nb = models.Parcel.objects.count() -        self.form_datas[0].form_datas['selec-operation_deletion']['pks'] = \ -            self.ope.pk +        self.form_datas[0].form_datas["selec-operation_deletion"]["pks"] = self.ope.pk          self.operation_number = models.Operation.objects.count()          super(OperationWizardDeleteTest, self).pre_wizard()      def post_wizard(self): -        self.assertEqual(self.operation_number - 1, -                         models.Operation.objects.count()) +        self.assertEqual(self.operation_number - 1, models.Operation.objects.count())          # associated parcel is... no more removed          self.assertEqual(self.parcel_nb, models.Parcel.objects.count())  class OperationWizardClosingTest(OperationWizardCreationTest):      fixtures = FILE_FIXTURES -    url_name = 'operation_closing' -    wizard_name = 'operation_closing_wizard' +    url_name = "operation_closing" +    wizard_name = "operation_closing_wizard"      steps = views.operation_closing_steps      redirect_url = "/operation_closing/done"      form_datas = [          FormData(              "Wizard closing test",              form_datas={ -                'selec-operation_closing': {'pk': None}, -                'date-operation_closing': {'end_date': '2016-01-01'}, -            } +                "selec-operation_closing": {"pk": None}, +                "date-operation_closing": {"end_date": "2016-01-01"}, +            },          )      ]      def pre_wizard(self):          self.ope = self.get_default_operation() -        self.form_datas[0].form_datas['selec-operation_closing']['pk'] = \ -            self.ope.pk +        self.form_datas[0].form_datas["selec-operation_closing"]["pk"] = self.ope.pk          self.assertTrue(self.ope.is_active())          super(OperationWizardClosingTest, self).pre_wizard() @@ -3107,25 +3601,24 @@ class OperationWizardClosingTest(OperationWizardCreationTest):          ope = models.Operation.objects.get(pk=self.ope.pk)          self.assertFalse(ope.is_active())          self.assertEqual( -            ope.closing()['date'].strftime('%Y-%d-%m'), -            self.form_datas[0].form_datas['date-operation_closing']['end_date'] +            ope.closing()["date"].strftime("%Y-%d-%m"), +            self.form_datas[0].form_datas["date-operation_closing"]["end_date"],          ) -class OperationAdminActWizardCreationTest(WizardTest, OperationInitTest, -                                          TestCase): +class OperationAdminActWizardCreationTest(WizardTest, OperationInitTest, TestCase):      fixtures = FILE_FIXTURES -    url_name = 'operation_administrativeactop' -    wizard_name = 'operation_administrative_act_wizard' +    url_name = "operation_administrativeactop" +    wizard_name = "operation_administrative_act_wizard"      steps = views.administrativeactop_steps      form_datas = [          FormData(              "Admin act creation",              form_datas={ -                'selec-operation_administrativeactop': {}, -                'administrativeact-operation_administrativeactop': { -                    'signature_date': str(datetime.date.today()) -                } +                "selec-operation_administrativeactop": {}, +                "administrativeact-operation_administrativeactop": { +                    "signature_date": str(datetime.date.today()) +                },              },          )      ] @@ -3135,38 +3628,34 @@ class OperationAdminActWizardCreationTest(WizardTest, OperationInitTest,          self.number = models.AdministrativeAct.objects.count()          data = self.form_datas[0].form_datas -        data['selec-operation_administrativeactop']['pk'] = ope.pk -        act = models.ActType.objects.filter(intented_to='O').all()[0].pk +        data["selec-operation_administrativeactop"]["pk"] = ope.pk +        act = models.ActType.objects.filter(intented_to="O").all()[0].pk -        data['administrativeact-operation_administrativeactop'][ -            'act_type'] = act +        data["administrativeact-operation_administrativeactop"]["act_type"] = act          super(OperationAdminActWizardCreationTest, self).pre_wizard()      def post_wizard(self): -        self.assertEqual(models.AdministrativeAct.objects.count(), -                         self.number + 1) +        self.assertEqual(models.AdministrativeAct.objects.count(), self.number + 1)  class SiteTest(TestCase, OperationInitTest):      fixtures = FILE_FIXTURES      def setUp(self): -        IshtarSiteProfile.objects.get_or_create( -            slug='default', active=True) +        IshtarSiteProfile.objects.get_or_create(slug="default", active=True)          self.username, self.password, self.user = create_superuser()          self.alt_username, self.alt_password, self.alt_user = create_user() -        self.alt_user.user_permissions.add(Permission.objects.get( -            codename='view_own_operation')) +        self.alt_user.user_permissions.add( +            Permission.objects.get(codename="view_own_operation") +        )          self.orgas = self.create_orgas(self.user)      def test_create_or_update_top_operations(self):          operation_0 = self.create_operation(self.user, self.orgas[0])[0]          operation_1 = self.create_operation(self.alt_user, self.orgas[0])[1] -        site = models.ArchaeologicalSite.objects.create( -            reference="ref-site" -        ) +        site = models.ArchaeologicalSite.objects.create(reference="ref-site")          site.create_or_update_top_operation() -        q = models.ArchaeologicalSite.objects.filter(reference='ref-site') +        q = models.ArchaeologicalSite.objects.filter(reference="ref-site")          site = q.all()[0]          # creation not forced - no creation          self.assertEqual(site.top_operations.count(), 0) @@ -3188,8 +3677,7 @@ class SiteTest(TestCase, OperationInitTest):          self.assertTrue(site.top_operation.virtual_operation)          self.assertEqual(site.top_operation.right_relations.count(), 1)          self.assertEqual( -            site.top_operation.right_relations.all()[0].right_record, -            operation_0 +            site.top_operation.right_relations.all()[0].right_record, operation_0          )          # create with two operations attached @@ -3203,8 +3691,7 @@ class SiteTest(TestCase, OperationInitTest):          self.assertTrue(site.top_operation.virtual_operation)          self.assertEqual(site.top_operation.right_relations.count(), 2)          attached = [ -            rel.right_record -            for rel in site.top_operation.right_relations.all() +            rel.right_record for rel in site.top_operation.right_relations.all()          ]          self.assertIn(operation_0, attached)          self.assertIn(operation_1, attached) @@ -3217,8 +3704,7 @@ class SiteTest(TestCase, OperationInitTest):          self.assertTrue(site.top_operation.virtual_operation)          self.assertEqual(site.top_operation.right_relations.count(), 1)          self.assertEqual( -            site.top_operation.right_relations.all()[0].right_record, -            operation_0 +            site.top_operation.right_relations.all()[0].right_record, operation_0          )          # reattach it @@ -3229,35 +3715,29 @@ class SiteTest(TestCase, OperationInitTest):          self.assertTrue(site.top_operation.virtual_operation)          self.assertEqual(site.top_operation.right_relations.count(), 2)          attached = [ -            rel.right_record -            for rel in site.top_operation.right_relations.all() +            rel.right_record for rel in site.top_operation.right_relations.all()          ]          self.assertIn(operation_0, attached)          self.assertIn(operation_1, attached)      def test_search(self): -        site = models.ArchaeologicalSite.objects.create( -            reference="reference-site" -        ) +        site = models.ArchaeologicalSite.objects.create(reference="reference-site")          c = Client() -        search = {'search_vector': 'reference="reference-site"'} -        response = c.get(reverse('get-site'), search) +        search = {"search_vector": 'reference="reference-site"'} +        response = c.get(reverse("get-site"), search)          # no result when no authentication          self.assertTrue(not json.loads(response.content.decode()))          c.login(username=self.username, password=self.password) -        response = c.get(reverse('get-site'), search) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         1) +        response = c.get(reverse("get-site"), search) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 1) -        search = {'search_vector': 'reference="reference"'} -        response = c.get(reverse('get-site'), search) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         0) +        search = {"search_vector": 'reference="reference"'} +        response = c.get(reverse("get-site"), search) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 0) -        search = {'search_vector': 'reference="reference*"'} -        response = c.get(reverse('get-site'), search) -        self.assertEqual(json.loads(response.content.decode())['recordsTotal'], -                         1) +        search = {"search_vector": 'reference="reference*"'} +        response = c.get(reverse("get-site"), search) +        self.assertEqual(json.loads(response.content.decode())["recordsTotal"], 1)  class GenerateQRCode(OperationInitTest, TestCase): @@ -3274,14 +3754,15 @@ class GenerateQRCode(OperationInitTest, TestCase):          operation = models.Operation.objects.get(pk=self.operation.pk)          self.assertIn(operation.qrcode.name, ["", None])          c = Client() -        url = reverse('qrcode-item', args=[ -            'archaeological-operations', 'operation', operation.pk]) +        url = reverse( +            "qrcode-item", args=["archaeological-operations", "operation", operation.pk] +        )          response = c.get(url)          self.assertEqual(response.status_code, 302)          c.login(username=self.username, password=self.password)          response = c.get(url)          self.assertEqual(response.status_code, 200) -        self.assertEqual(response['Content-Type'], "image/png") +        self.assertEqual(response["Content-Type"], "image/png")          operation = models.Operation.objects.get(pk=self.operation.pk)          self.assertIsNotNone(operation.qrcode.name) @@ -3290,9 +3771,7 @@ class GenerateQRCode(OperationInitTest, TestCase):          self.operation.generate_qrcode()          self.assertIsNotNone(self.operation.qrcode.name)          self.assertTrue( -            self.operation.qrcode.name.startswith( -                "operation/2010/OA1/qrcode" -            ) +            self.operation.qrcode.name.startswith("operation/2010/OA1/qrcode")          ) @@ -3305,7 +3784,7 @@ class DocumentTest(OperationInitTest, TestCase):      def test_create(self):          c = Client() -        url = reverse('create-document') +        url = reverse("create-document")          nb_doc = models.Document.objects.count()          nb_doc_ope = self.operation.documents.count() @@ -3315,10 +3794,12 @@ class DocumentTest(OperationInitTest, TestCase):          c.login(username=self.username, password=self.password)          response = c.get(url, {"operation": self.operation.pk})          self.assertEqual(response.status_code, 200) -        self.assertIn('option value="{}" selected'.format(self.operation.pk), -                      response.content.decode()) +        self.assertIn( +            'option value="{}" selected'.format(self.operation.pk), +            response.content.decode(), +        ) -        posted = {'authors': []} +        posted = {"authors": []}          for related_key in models.Document.RELATED_MODELS:              posted[related_key] = []          posted["operations"] = [str(self.operation.pk)] @@ -3333,15 +3814,17 @@ class DocumentTest(OperationInitTest, TestCase):          self.assertEqual(nb_doc + 1, models.Document.objects.count())          self.assertEqual(nb_doc_ope + 1, self.operation.documents.count())          self.assertRedirects( -            response, '/document/edit/?open_item={}'.format( -            self.operation.documents.order_by('-pk').all()[0].pk -        )) +            response, +            "/document/edit/?open_item={}".format( +                self.operation.documents.order_by("-pk").all()[0].pk +            ), +        )      def test_edit(self):          doc = models.Document.objects.create(title="hop2")          doc.operations.add(self.operation)          c = Client() -        url = reverse('edit-document', args=[doc.pk]) +        url = reverse("edit-document", args=[doc.pk])          response = c.get(url)          self.assertEqual(response.status_code, 302) @@ -3349,35 +3832,33 @@ class DocumentTest(OperationInitTest, TestCase):          c.login(username=self.username, password=self.password)          response = c.get(url)          self.assertEqual(response.status_code, 200) -        self.assertIn('option value="{}" selected'.format(self.operation.pk), -                      response.content.decode()) +        self.assertIn( +            'option value="{}" selected'.format(self.operation.pk), +            response.content.decode(), +        ) -        posted = { -            'authors': [], -            'title': "hop2-is-back" -        } +        posted = {"authors": [], "title": "hop2-is-back"}          for related_key in models.Document.RELATED_MODELS:              posted[related_key] = []          posted["operations"] = [str(self.operation.pk)]          response = c.post(url, posted) -        self.assertRedirects( -            response, '/document/edit/?open_item={}'.format(doc.pk)) -        response = c.get('/show-document/{}/'.format(doc.pk)) +        self.assertRedirects(response, "/document/edit/?open_item={}".format(doc.pk)) +        response = c.get("/show-document/{}/".format(doc.pk))          self.assertIn(posted["title"], response.content.decode())  class DocumentWizardDeleteTest(WizardTest, OperationInitTest, TestCase):      fixtures = FILE_FIXTURES -    url_name = 'document_deletion' +    url_name = "document_deletion"      url_uri = "document/delete" -    wizard_name = 'document_deletion_wizard' +    wizard_name = "document_deletion_wizard"      redirect_url = "/{}/selec-{}".format(url_uri, url_name)      steps = document_deletion_steps      form_datas = [          FormData(              "Delete document",              form_datas={ -                'selec': {'pks': None}, +                "selec": {"pks": None},              },          ),      ] @@ -3387,41 +3868,44 @@ class DocumentWizardDeleteTest(WizardTest, OperationInitTest, TestCase):          document = Document.objects.create(title="testy")          document.operations.add(ope)          self.ope_id = ope.pk -        self.form_datas[0].set('selec', 'pks', document.pk) +        self.form_datas[0].set("selec", "pks", document.pk)          self.doc_nb = Document.objects.count()          super(DocumentWizardDeleteTest, self).pre_wizard()      def post_wizard(self): -        self.assertEqual(Document.objects.count(), -                         self.doc_nb - 1) +        self.assertEqual(Document.objects.count(), self.doc_nb - 1)          # operation not deleted with the document -        self.assertEqual(models.Operation.objects.filter( -            pk=self.ope_id).count(), 1) +        self.assertEqual(models.Operation.objects.filter(pk=self.ope_id).count(), 1)  class AutocompleteTest(AutocompleteTestBase, TestCase):      fixtures = OPERATION_FIXTURES      models = [ -        AcItem(models.Operation, 'autocomplete-operation', -               prepare_func="create_operation"), -        AcItem(models.ArchaeologicalSite, 'autocomplete-archaeologicalsite', -               "reference"), -        AcItem(models.Operation, 'autocomplete-patriarche', -               prepare_func="create_operation_patriarche", -               id_key="code_patriarche", one_word_search=True), +        AcItem( +            models.Operation, "autocomplete-operation", prepare_func="create_operation" +        ), +        AcItem( +            models.ArchaeologicalSite, "autocomplete-archaeologicalsite", "reference" +        ), +        AcItem( +            models.Operation, +            "autocomplete-patriarche", +            prepare_func="create_operation_patriarche", +            id_key="code_patriarche", +            one_word_search=True, +        ),      ]      def create_operation(self, base_name):          item, __ = models.Operation.objects.get_or_create( -            common_name=base_name, -            operation_type=models.OperationType.objects.all()[0] +            common_name=base_name, operation_type=models.OperationType.objects.all()[0]          )          return item, None      def create_operation_patriarche(self, base_name):          item, __ = models.Operation.objects.get_or_create(              code_patriarche=base_name, -            operation_type=models.OperationType.objects.all()[0] +            operation_type=models.OperationType.objects.all()[0],          )          return item, None @@ -3436,25 +3920,26 @@ class OperationQATest(OperationInitTest, TestCase):          self.create_operation(self.user, self.orgas[0])          self.create_operation(self.user, self.orgas[0])          self.alt_username, self.alt_password, self.alt_user = create_user() -        self.alt_user.user_permissions.add(Permission.objects.get( -            codename='change_operation')) +        self.alt_user.user_permissions.add( +            Permission.objects.get(codename="change_operation") +        )      def test_lock(self):          c = Client()          op0, op1 = self.operations[0], self.operations[1]          pks = "{}-{}".format(op0.pk, op1.pk) -        url = reverse('operation-qa-lock', args=[pks]) +        url = reverse("operation-qa-lock", args=[pks])          response = c.get(url)          self.assertEqual(response.status_code, 404)          c.login(username=self.username, password=self.password) -        response = c.get(reverse('operation-qa-lock', args=[pks])) +        response = c.get(reverse("operation-qa-lock", args=[pks]))          self.assertEqual(response.status_code, 200)          response = c.post(url, {"action": "lock"})          if response.status_code != 200: -            self.assertRedirects(response, '/success/') +            self.assertRedirects(response, "/success/")          for ope in (op0, op1):              ope = models.Operation.objects.get(pk=ope.pk)              self.assertEqual(ope.locked, True) @@ -3462,7 +3947,7 @@ class OperationQATest(OperationInitTest, TestCase):          response = c.post(url, {"action": "unlock"})          if response.status_code != 200: -            self.assertRedirects(response, '/success/') +            self.assertRedirects(response, "/success/")          for ope in (op0, op1):              ope = models.Operation.objects.get(pk=ope.pk)              self.assertEqual(ope.locked, False) @@ -3470,12 +3955,12 @@ class OperationQATest(OperationInitTest, TestCase):          c = Client()          c.login(username=self.alt_username, password=self.alt_password) -        response = c.get(reverse('operation-qa-lock', args=[pks])) +        response = c.get(reverse("operation-qa-lock", args=[pks]))          self.assertEqual(response.status_code, 200)          response = c.post(url, {"action": "lock"})          if response.status_code != 200: -            self.assertRedirects(response, '/success/') +            self.assertRedirects(response, "/success/")          for ope in (op0, op1):              ope = models.Operation.objects.get(pk=ope.pk)              self.assertEqual(ope.locked, True) @@ -3483,7 +3968,7 @@ class OperationQATest(OperationInitTest, TestCase):          response = c.post(url, {"action": "unlock"})          if response.status_code != 200: -            self.assertRedirects(response, '/success/') +            self.assertRedirects(response, "/success/")          for ope in (op0, op1):              ope = models.Operation.objects.get(pk=ope.pk)              self.assertEqual(ope.locked, False) @@ -3500,7 +3985,7 @@ class OperationQATest(OperationInitTest, TestCase):          op1.save()          response = c.post(url, {"action": "unlock"}) -        self.assertRedirects(response, '/qa-not-available/locked-by-others/') +        self.assertRedirects(response, "/qa-not-available/locked-by-others/")          op0 = models.Operation.objects.get(pk=op0.pk)          self.assertEqual(op0.locked, True) @@ -3513,17 +3998,17 @@ class OperationQATest(OperationInitTest, TestCase):      def test_bulk_update(self):          c = Client()          pks = "{}-{}".format(self.operations[0].pk, self.operations[1].pk) -        response = c.get(reverse('operation-qa-bulk-update', args=[pks])) -        self.assertRedirects(response, '/') +        response = c.get(reverse("operation-qa-bulk-update", args=[pks])) +        self.assertRedirects(response, "/")          c = Client()          c.login(username=self.username, password=self.password) -        response = c.get(reverse('operation-qa-bulk-update', args=[pks])) +        response = c.get(reverse("operation-qa-bulk-update", args=[pks]))          self.assertEqual(response.status_code, 200)          c = Client()          c.login(username=self.alt_username, password=self.alt_password) -        response = c.get(reverse('operation-qa-bulk-update', args=[pks])) +        response = c.get(reverse("operation-qa-bulk-update", args=[pks]))          self.assertEqual(response.status_code, 200)          operation_0 = self.operations[0] @@ -3536,30 +4021,31 @@ class OperationQATest(OperationInitTest, TestCase):          operation_1.save()          operation_type = models.OperationType.objects.exclude( -            txt_idx="arch_diagnostic").all()[0] +            txt_idx="arch_diagnostic" +        ).all()[0]          self.assertNotEqual(              models.Operation.objects.get(pk=operation_0.pk).operation_type, -            operation_type +            operation_type,          )          self.assertNotEqual(              models.Operation.objects.get(pk=operation_1.pk).operation_type, -            operation_type +            operation_type,          )          response = c.post( -            reverse('operation-qa-bulk-update-confirm', args=[pks]), -            {'qa_operation_type': operation_type.pk} +            reverse("operation-qa-bulk-update-confirm", args=[pks]), +            {"qa_operation_type": operation_type.pk},          )          if response.status_code != 200: -            self.assertRedirects(response, '/success/') +            self.assertRedirects(response, "/success/")          self.assertEqual(              models.Operation.objects.get(pk=operation_0.pk).operation_type, -            operation_type +            operation_type,          )          self.assertEqual(              models.Operation.objects.get(pk=operation_1.pk).operation_type, -            operation_type +            operation_type,          )          # one item lock by another user @@ -3569,10 +4055,10 @@ class OperationQATest(OperationInitTest, TestCase):          op0.save()          response = c.post( -            reverse('operation-qa-bulk-update-confirm', args=[pks]), -            {'qa_operation_type': operation_type.pk} +            reverse("operation-qa-bulk-update-confirm", args=[pks]), +            {"qa_operation_type": operation_type.pk},          ) -        self.assertRedirects(response, '/qa-not-available/locked/') +        self.assertRedirects(response, "/qa-not-available/locked/")  class DocumentQATest(OperationInitTest, TestCase): @@ -3582,58 +4068,54 @@ class DocumentQATest(OperationInitTest, TestCase):      def setUp(self):          self.username, self.password, self.user = create_superuser()          self.alt_username, self.alt_password, self.alt_user = create_user() -        self.alt_user.user_permissions.add(Permission.objects.get( -            codename='change_document')) +        self.alt_user.user_permissions.add( +            Permission.objects.get(codename="change_document") +        )          self.source_1 = models.Document.objects.create( -            title="Source title", -            source_type=models.SourceType.objects.all()[0] +            title="Source title", source_type=models.SourceType.objects.all()[0]          )          self.source_2 = models.Document.objects.create( -            title="Source title2", -            source_type=models.SourceType.objects.all()[0] +            title="Source title2", source_type=models.SourceType.objects.all()[0]          )      def test_bulk_update(self):          c = Client()          pks = "{}-{}".format(self.source_1.pk, self.source_2.pk) -        response = c.get(reverse('document-qa-bulk-update', args=[pks])) -        self.assertRedirects(response, '/') +        response = c.get(reverse("document-qa-bulk-update", args=[pks])) +        self.assertRedirects(response, "/")          c = Client()          c.login(username=self.username, password=self.password) -        response = c.get(reverse('document-qa-bulk-update', args=[pks])) +        response = c.get(reverse("document-qa-bulk-update", args=[pks]))          self.assertEqual(response.status_code, 200)          c = Client()          c.login(username=self.alt_username, password=self.alt_password) -        response = c.get(reverse('document-qa-bulk-update', args=[pks])) +        response = c.get(reverse("document-qa-bulk-update", args=[pks]))          self.assertEqual(response.status_code, 200)          document_0 = self.source_1          document_1 = self.source_2          source_type = models.SourceType.objects.exclude( -            txt_idx=self.source_1.source_type.txt_idx).all()[0] +            txt_idx=self.source_1.source_type.txt_idx +        ).all()[0]          self.assertNotEqual( -            models.Document.objects.get(pk=document_0.pk).source_type, -            source_type +            models.Document.objects.get(pk=document_0.pk).source_type, source_type          )          self.assertNotEqual( -            models.Document.objects.get(pk=document_1.pk).source_type, -            source_type +            models.Document.objects.get(pk=document_1.pk).source_type, source_type          )          response = c.post( -            reverse('document-qa-bulk-update-confirm', args=[pks]), -            {'qa_source_type': source_type.pk} +            reverse("document-qa-bulk-update-confirm", args=[pks]), +            {"qa_source_type": source_type.pk},          )          if response.status_code != 200: -            self.assertRedirects(response, '/success/') +            self.assertRedirects(response, "/success/")          self.assertEqual( -            models.Document.objects.get(pk=document_0.pk).source_type, -            source_type +            models.Document.objects.get(pk=document_0.pk).source_type, source_type          )          self.assertEqual( -            models.Document.objects.get(pk=document_1.pk).source_type, -            source_type +            models.Document.objects.get(pk=document_1.pk).source_type, source_type          ) diff --git a/archaeological_operations/urls.py b/archaeological_operations/urls.py index 6961af39a..85a650216 100644 --- a/archaeological_operations/urls.py +++ b/archaeological_operations/urls.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3  # -*- coding: utf-8 -*-  # Copyright (C) 2010-2016 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> @@ -27,196 +27,333 @@ from archaeological_operations import models  # forms  urlpatterns = [ -    url(r'operation_administrativeactop_search/(?P<step>.+)?$', -        check_rights(['change_administrativeact'])( -            views.operation_administrativeactop_search_wizard), -        name='operation_administrativeactop_search'), -    url(r'operation_administrativeactop/(?P<step>.+)?$', -        check_rights(['change_administrativeact'])( -            views.operation_administrativeactop_wizard), -        name='operation_administrativeactop'), -    url(r'operation_administrativeactop_modification/(?P<step>.+)?$', -        check_rights(['change_administrativeact'])( -            views.operation_administrativeactop_modification_wizard), -        name='operation_administrativeactop_modification'), -    url(r'operation_administrativeactop_modify/(?P<pk>.+)/$', +    url( +        r"operation_administrativeactop_search/(?P<step>.+)?$", +        check_rights(["change_administrativeact"])( +            views.operation_administrativeactop_search_wizard +        ), +        name="operation_administrativeactop_search", +    ), +    url( +        r"operation_administrativeactop/(?P<step>.+)?$", +        check_rights(["change_administrativeact"])( +            views.operation_administrativeactop_wizard +        ), +        name="operation_administrativeactop", +    ), +    url( +        r"operation_administrativeactop_modification/(?P<step>.+)?$", +        check_rights(["change_administrativeact"])( +            views.operation_administrativeactop_modification_wizard +        ), +        name="operation_administrativeactop_modification", +    ), +    url( +        r"operation_administrativeactop_modify/(?P<pk>.+)/$",          views.operation_administrativeactop_modify, -        name='operation_administrativeactop_modify'), -    url(r'operation_administrativeactop_deletion/(?P<step>.+)?$', -        check_rights(['change_administrativeact'])( -            views.operation_administrativeactop_deletion_wizard), -        name='operation_administrativeactop_deletion'), -    url(r'operation_administrativeactop_delete/(?P<pk>.+)/$', +        name="operation_administrativeactop_modify", +    ), +    url( +        r"operation_administrativeactop_deletion/(?P<step>.+)?$", +        check_rights(["change_administrativeact"])( +            views.operation_administrativeactop_deletion_wizard +        ), +        name="operation_administrativeactop_deletion", +    ), +    url( +        r"operation_administrativeactop_delete/(?P<pk>.+)/$",          views.operation_administrativeactop_delete, -        name='delete-administrativeact-operation'), - -    url(r'operation_search/(?P<step>.+)?$', -        check_rights(['view_operation', 'view_own_operation'])( -            views.operation_search_wizard), name='operation_search'), -    url(r'operation_creation/(?P<step>.+)?$', -        check_rights(['add_operation', 'add_own_operation'])( -            views.operation_creation_wizard), -        name='operation_creation'), -    url(r'operation_add/(?P<file_id>\d+)$', -        views.operation_add, name='operation_add'), -    url(r'operation_modification/(?P<step>.+)?$', -        check_rights(['change_operation', 'change_own_operation'])( -            views.operation_modification_wizard), -        name='operation_modification'), -    url(r'operation_modify/(?P<pk>.+)/$', -        views.operation_modify, name='operation_modify'), -    url(r'operation_closing/(?P<step>.+)?$', -        check_rights(['change_operation'])( -            views.operation_closing_wizard), name='operation_closing'), -    url(r'operation_deletion/(?P<step>.+)?$', -        check_rights(['change_operation', 'change_own_operation'])( -            views.operation_deletion_wizard), name='operation_deletion'), -    url(r'operation_delete/(?P<pk>.+)/$', -        views.operation_delete, name='delete-operation'), - -    url(r'administrativact_register/(?P<step>.+)?$', -        check_rights(['view_administrativeact', 'view_own_administrativeact'])( -            views.administrativact_register_wizard), -        name='administrativact_register'), - -    url(r'autocomplete-operation/$', views.autocomplete_operation, -        name='autocomplete-operation'), -    url(r'get-operation/own/(?P<type>.+)?$', -        views.get_operation, name='get-own-operation', -        kwargs={'force_own': True}), -    url(r'get-operation/(?P<type>.+)?$', views.get_operation, -        name='get-operation'), -    url(r'get-operation-full/own/(?P<type>.+)?$', -        views.get_operation, name='get-own-operation-full', -        kwargs={'full': True, 'force_own': True}), -    url(r'get-operation-full/(?P<type>.+)?$', views.get_operation, -        name='get-operation-full', kwargs={'full': True}), -    url(r'get-operation-shortcut/(?P<type>.+)?$', -        views.get_operation, name='get-operation-shortcut', -        kwargs={'full': 'shortcut'}), -    url(r'get-available-operation-code/(?P<year>.+)?$', +        name="delete-administrativeact-operation", +    ), +    url( +        r"operation_search/(?P<step>.+)?$", +        check_rights(["view_operation", "view_own_operation"])( +            views.operation_search_wizard +        ), +        name="operation_search", +    ), +    url( +        r"operation_creation/(?P<step>.+)?$", +        check_rights(["add_operation", "add_own_operation"])( +            views.operation_creation_wizard +        ), +        name="operation_creation", +    ), +    url(r"operation_add/(?P<file_id>\d+)$", views.operation_add, name="operation_add"), +    url( +        r"operation_modification/(?P<step>.+)?$", +        check_rights(["change_operation", "change_own_operation"])( +            views.operation_modification_wizard +        ), +        name="operation_modification", +    ), +    url( +        r"operation_modify/(?P<pk>.+)/$", +        views.operation_modify, +        name="operation_modify", +    ), +    url( +        r"operation_closing/(?P<step>.+)?$", +        check_rights(["change_operation"])(views.operation_closing_wizard), +        name="operation_closing", +    ), +    url( +        r"operation_deletion/(?P<step>.+)?$", +        check_rights(["change_operation", "change_own_operation"])( +            views.operation_deletion_wizard +        ), +        name="operation_deletion", +    ), +    url( +        r"operation_delete/(?P<pk>.+)/$", +        views.operation_delete, +        name="delete-operation", +    ), +    url( +        r"administrativact_register/(?P<step>.+)?$", +        check_rights(["view_administrativeact", "view_own_administrativeact"])( +            views.administrativact_register_wizard +        ), +        name="administrativact_register", +    ), +    url( +        r"autocomplete-operation/$", +        views.autocomplete_operation, +        name="autocomplete-operation", +    ), +    url( +        r"get-operation/own/(?P<type>.+)?$", +        views.get_operation, +        name="get-own-operation", +        kwargs={"force_own": True}, +    ), +    url(r"get-operation/(?P<type>.+)?$", views.get_operation, name="get-operation"), +    url( +        r"get-operation-full/own/(?P<type>.+)?$", +        views.get_operation, +        name="get-own-operation-full", +        kwargs={"full": True, "force_own": True}, +    ), +    url( +        r"get-operation-full/(?P<type>.+)?$", +        views.get_operation, +        name="get-operation-full", +        kwargs={"full": True}, +    ), +    url( +        r"get-operation-shortcut/(?P<type>.+)?$", +        views.get_operation, +        name="get-operation-shortcut", +        kwargs={"full": "shortcut"}, +    ), +    url( +        r"get-available-operation-code/(?P<year>.+)?$",          views.get_available_operation_code, -        name='get_available_operation_code'), -    url(r'revert-operation/(?P<pk>.+)/(?P<date>.+)$', -        views.revert_operation, name='revert-operation'), -    url(r'show-operation(?:/(?P<pk>.+))?/(?P<type>.+)?$', -        views.show_operation, name=models.Operation.SHOW_URL), -    url(r'show-historized-operation/(?P<pk>.+)?/(?P<date>.+)?$', -        views.show_operation, name='show-historized-operation'), -    url(r'get-administrativeactop/(?P<type>.+)?$', -        views.get_administrativeactop, name='get-administrativeactop'), -    url(r'get-administrativeact/(?P<type>.+)?$', -        views.get_administrativeact, name='get-administrativeact'), -    url(r'get-administrativeact-full/(?P<type>.+)?$', -        views.get_administrativeact, name='get-administrativeact-full', -        kwargs={'full': True}), -    url(r'show-administrativeact(?:/(?P<pk>.+))?/(?P<type>.+)?$', -        views.show_administrativeact, name='show-administrativeact'), +        name="get_available_operation_code", +    ), +    url( +        r"revert-operation/(?P<pk>.+)/(?P<date>.+)$", +        views.revert_operation, +        name="revert-operation", +    ), +    url( +        r"show-operation(?:/(?P<pk>.+))?/(?P<type>.+)?$", +        views.show_operation, +        name=models.Operation.SHOW_URL, +    ), +    url( +        r"show-historized-operation/(?P<pk>.+)?/(?P<date>.+)?$", +        views.show_operation, +        name="show-historized-operation", +    ), +    url( +        r"get-administrativeactop/(?P<type>.+)?$", +        views.get_administrativeactop, +        name="get-administrativeactop", +    ), +    url( +        r"get-administrativeact/(?P<type>.+)?$", +        views.get_administrativeact, +        name="get-administrativeact", +    ), +    url( +        r"get-administrativeact-full/(?P<type>.+)?$", +        views.get_administrativeact, +        name="get-administrativeact-full", +        kwargs={"full": True}, +    ), +    url( +        r"show-administrativeact(?:/(?P<pk>.+))?/(?P<type>.+)?$", +        views.show_administrativeact, +        name="show-administrativeact", +    ),      # allow specialization for operations -    url(r'show-administrativeact(?:/(?P<pk>.+))?/(?P<type>.+)?$', -        views.show_administrativeact, name='show-administrativeactop'), +    url( +        r"show-administrativeact(?:/(?P<pk>.+))?/(?P<type>.+)?$", +        views.show_administrativeact, +        name="show-administrativeactop", +    ),      # allow specialization for files, treatment, treatment request -    url(r'show-administrativeact(?:/(?P<pk>.+))?/(?P<type>.+)?$', -        views.show_administrativeact, name='show-administrativeactfile'), -    url(r'show-administrativeact(?:/(?P<pk>.+))?/(?P<type>.+)?$', -        views.show_administrativeact, name='show-administrativeacttreatment'), -    url(r'show-administrativeact(?:/(?P<pk>.+))?/(?P<type>.+)?$', +    url( +        r"show-administrativeact(?:/(?P<pk>.+))?/(?P<type>.+)?$", +        views.show_administrativeact, +        name="show-administrativeactfile", +    ), +    url( +        r"show-administrativeact(?:/(?P<pk>.+))?/(?P<type>.+)?$", +        views.show_administrativeact, +        name="show-administrativeacttreatment", +    ), +    url( +        r"show-administrativeact(?:/(?P<pk>.+))?/(?P<type>.+)?$",          views.show_administrativeact, -        name='show-administrativeacttreatmentfile'), -    url(r'generatedoc-administrativeactop/(?P<pk>.+)?/(?P<template_pk>.+)?$', +        name="show-administrativeacttreatmentfile", +    ), +    url( +        r"generatedoc-administrativeactop/(?P<pk>.+)?/(?P<template_pk>.+)?$",          views.generatedoc_administrativeactop, -        name='generatedoc-administrativeactop'), -    url(r'dashboard_operation/$', views.dashboard_operation, -        name='dashboard-operation'), -    url(r'autocomplete-administrativeact/$', +        name="generatedoc-administrativeactop", +    ), +    url( +        r"dashboard_operation/$", views.dashboard_operation, name="dashboard-operation" +    ), +    url( +        r"autocomplete-administrativeact/$",          views.autocomplete_administrativeact, -        name='autocomplete-administrativeact'), - -    url(r'autocomplete-archaeologicalsite/$', +        name="autocomplete-administrativeact", +    ), +    url( +        r"autocomplete-archaeologicalsite/$",          views.autocomplete_archaeologicalsite, -        name='autocomplete-archaeologicalsite'), -    url(r'new-archaeologicalsite/(?:(?P<parent_name>[^/]+)/)?' -        r'(?:(?P<limits>[^/]+)/)?$', -        views.new_archaeologicalsite, name='new-archaeologicalsite'), -    url(r'get-site/(?P<type>.+)?$', -        views.get_site, name='get-site'), -    url(r'get-site-full/(?P<type>.+)?$', -        views.get_site, name='get-site-full', kwargs={'full': True}), -    url(r'get-site-shortcut/(?P<type>.+)?$', -        views.get_site, name='get-site-shortcut', -        kwargs={'full': 'shortcut'}), -    url(r'revert-site/(?P<pk>.+)/(?P<date>.+)$', -        views.revert_site, name='revert-site'), -    url(r'show-site(?:/(?P<pk>.+))?/(?P<type>.+)?$', -        views.show_site, name=models.ArchaeologicalSite.SHOW_URL), -    url(r'show-historized-site/(?P<pk>.+)?/(?P<date>.+)?$', -        views.show_site, name='show-historized-site'), -    url(r'site_search/(?P<step>.+)?$', -        check_rights(['view_archaeologicalsite', -                      'view_own_archaeologicalsite'])( -            views.site_search_wizard), name='site_search'), -    url(r'site_creation/(?P<step>.+)?$', -        check_rights(['add_archaeologicalsite', -                      'add_own_archaeologicalsite'])( -            views.site_creation_wizard), -        name='site_creation'), -    url(r'site_modification/(?P<step>.+)?$', -        check_rights(['change_archaeologicalsite', -                      'change_own_archaeologicalsite'])( -            views.site_modification_wizard), -        name='site_modification'), -    url(r'site_modify/(?P<pk>.+)/$', -        views.site_modify, name='site_modify'), -    url(r'site_deletion/(?P<step>.+)?$', -        check_rights(['change_archaeologicalsite'])( -            views.site_deletion_wizard), -        name='site_deletion'), -    url(r'site_delete/(?P<pk>.+)/$', -        views.site_delete, name='delete-site'), - -    url(r'autocomplete-patriarche/$', views.autocomplete_patriarche, -        name='autocomplete-patriarche'), -    url(r'operation_administrativeact_document/$', +        name="autocomplete-archaeologicalsite", +    ), +    url( +        r"new-archaeologicalsite/(?:(?P<parent_name>[^/]+)/)?" +        r"(?:(?P<limits>[^/]+)/)?$", +        views.new_archaeologicalsite, +        name="new-archaeologicalsite", +    ), +    url(r"get-site/(?P<type>.+)?$", views.get_site, name="get-site"), +    url( +        r"get-site-full/(?P<type>.+)?$", +        views.get_site, +        name="get-site-full", +        kwargs={"full": True}, +    ), +    url( +        r"get-site-shortcut/(?P<type>.+)?$", +        views.get_site, +        name="get-site-shortcut", +        kwargs={"full": "shortcut"}, +    ), +    url(r"revert-site/(?P<pk>.+)/(?P<date>.+)$", views.revert_site, name="revert-site"), +    url( +        r"show-site(?:/(?P<pk>.+))?/(?P<type>.+)?$", +        views.show_site, +        name=models.ArchaeologicalSite.SHOW_URL, +    ), +    url( +        r"show-historized-site/(?P<pk>.+)?/(?P<date>.+)?$", +        views.show_site, +        name="show-historized-site", +    ), +    url( +        r"site_search/(?P<step>.+)?$", +        check_rights(["view_archaeologicalsite", "view_own_archaeologicalsite"])( +            views.site_search_wizard +        ), +        name="site_search", +    ), +    url( +        r"site_creation/(?P<step>.+)?$", +        check_rights(["add_archaeologicalsite", "add_own_archaeologicalsite"])( +            views.site_creation_wizard +        ), +        name="site_creation", +    ), +    url( +        r"site_modification/(?P<step>.+)?$", +        check_rights(["change_archaeologicalsite", "change_own_archaeologicalsite"])( +            views.site_modification_wizard +        ), +        name="site_modification", +    ), +    url(r"site_modify/(?P<pk>.+)/$", views.site_modify, name="site_modify"), +    url( +        r"site_deletion/(?P<step>.+)?$", +        check_rights(["change_archaeologicalsite"])(views.site_deletion_wizard), +        name="site_deletion", +    ), +    url(r"site_delete/(?P<pk>.+)/$", views.site_delete, name="delete-site"), +    url( +        r"autocomplete-patriarche/$", +        views.autocomplete_patriarche, +        name="autocomplete-patriarche", +    ), +    url( +        r"operation_administrativeact_document/$",          views.administrativeactfile_document, -        name='operation-administrativeact-document'), - -    url(r'^operation-qa-bulk-update/(?P<pks>[0-9-]+)?/$', -        check_rights(['change_operation', 'change_own_operation'])( -            views.QAOperationForm.as_view()), -        name='operation-qa-bulk-update'), -    url(r'^operation-qa-bulk-update/(?P<pks>[0-9-]+)?/confirm/$', -        check_rights(['change_operation', 'change_own_operation'])( -            views.QAOperationForm.as_view()), -        name='operation-qa-bulk-update-confirm', kwargs={"confirm": True}), -    url(r'^operation-qa-duplicate/(?P<pks>[0-9-]+)?/$', -        check_rights(['change_operation', 'change_own_operation'])( -            views.QAOperationdDuplicateFormView.as_view()), -        name='operation-qa-duplicate'), - -    url(r'^operation-qa-lock/(?P<pks>[0-9-]+)?/$', -        views.QAOperationLockView.as_view(), name='operation-qa-lock', -        kwargs={"model": models.Operation}), - -    url(r'^site-qa-duplicate/(?P<pks>[0-9-]+)?/$', -        check_rights(['change_archaeologicalsite', -                      'change_own_archaeologicalsite'])( -            views.QAArchaeologicalSiteDuplicateFormView.as_view()), -        name='site-qa-duplicate'), -    url(r'^site-qa-lock/(?P<pks>[0-9-]+)?/$', -        views.QASiteLockView.as_view(), name='site-qa-lock', -        kwargs={"model": models.ArchaeologicalSite}), -    url(r'^site-qa-bulk-update/(?P<pks>[0-9-]+)?/$', -        check_rights(['change_archaeologicalsite', -                      'change_own_archaeologicalsite'])( -            views.QAArchaeologicalSiteForm.as_view()), -        name='site-qa-bulk-update'), -    url(r'^site-qa-bulk-update/(?P<pks>[0-9-]+)?/confirm/$', -        check_rights(['change_archaeologicalsite', -                      'change_own_archaeologicalsite'])( -            views.QAArchaeologicalSiteForm.as_view()), -        name='site-qa-bulk-update-confirm', kwargs={"confirm": True}), - -    url(r'generate-stats-operation/(?P<pk>.+)/', +        name="operation-administrativeact-document", +    ), +    url( +        r"^operation-qa-bulk-update/(?P<pks>[0-9-]+)?/$", +        check_rights(["change_operation", "change_own_operation"])( +            views.QAOperationForm.as_view() +        ), +        name="operation-qa-bulk-update", +    ), +    url( +        r"^operation-qa-bulk-update/(?P<pks>[0-9-]+)?/confirm/$", +        check_rights(["change_operation", "change_own_operation"])( +            views.QAOperationForm.as_view() +        ), +        name="operation-qa-bulk-update-confirm", +        kwargs={"confirm": True}, +    ), +    url( +        r"^operation-qa-duplicate/(?P<pks>[0-9-]+)?/$", +        check_rights(["change_operation", "change_own_operation"])( +            views.QAOperationdDuplicateFormView.as_view() +        ), +        name="operation-qa-duplicate", +    ), +    url( +        r"^operation-qa-lock/(?P<pks>[0-9-]+)?/$", +        views.QAOperationLockView.as_view(), +        name="operation-qa-lock", +        kwargs={"model": models.Operation}, +    ), +    url( +        r"^site-qa-duplicate/(?P<pks>[0-9-]+)?/$", +        check_rights(["change_archaeologicalsite", "change_own_archaeologicalsite"])( +            views.QAArchaeologicalSiteDuplicateFormView.as_view() +        ), +        name="site-qa-duplicate", +    ), +    url( +        r"^site-qa-lock/(?P<pks>[0-9-]+)?/$", +        views.QASiteLockView.as_view(), +        name="site-qa-lock", +        kwargs={"model": models.ArchaeologicalSite}, +    ), +    url( +        r"^site-qa-bulk-update/(?P<pks>[0-9-]+)?/$", +        check_rights(["change_archaeologicalsite", "change_own_archaeologicalsite"])( +            views.QAArchaeologicalSiteForm.as_view() +        ), +        name="site-qa-bulk-update", +    ), +    url( +        r"^site-qa-bulk-update/(?P<pks>[0-9-]+)?/confirm/$", +        check_rights(["change_archaeologicalsite", "change_own_archaeologicalsite"])( +            views.QAArchaeologicalSiteForm.as_view() +        ), +        name="site-qa-bulk-update-confirm", +        kwargs={"confirm": True}, +    ), +    url( +        r"generate-stats-operation/(?P<pk>.+)/",          views.GenerateStatsOperation.as_view(), -        name='generate-stats-operation'), +        name="generate-stats-operation", +    ),  ] diff --git a/archaeological_operations/utils.py b/archaeological_operations/utils.py index bf38a675a..ba4f17358 100644 --- a/archaeological_operations/utils.py +++ b/archaeological_operations/utils.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3  # -*- coding: utf-8 -*-  # Copyright (C) 2013  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> @@ -28,35 +28,43 @@ from django.core.exceptions import ObjectDoesNotExist  from django.template.defaultfilters import slugify  from django.contrib.auth.models import User -from ishtar_common.models import Town, Person, PersonType, OrganizationType, \ -    Organization, SourceType +from ishtar_common.models import ( +    Town, +    Person, +    PersonType, +    OrganizationType, +    Organization, +    SourceType, +)  from archaeological_files.models import PermitType -from archaeological_operations.models import OperationType, Period, \ -    ActType +from archaeological_operations.models import OperationType, Period, ActType  def get_default_person(): -    return User.objects.order_by('pk').all()[0] +    return User.objects.order_by("pk").all()[0]  def _get_parse_string(trunc_number=None):      def parse_string(value):          value = value.strip() -        if value == '#EMPTY': -            value = '' -        value = value.replace('  ', ' ') +        if value == "#EMPTY": +            value = "" +        value = value.replace("  ", " ")          if trunc_number:              value = value[:trunc_number]          return value +      return parse_string +  parse_string = _get_parse_string()  def parse_multivalue(value): -    s1 = re.sub('(.)([A-Z][a-z]+)', r'\1 \2', value) -    s1 = re.sub('([a-z0-9])([A-Z])', r'\1 \2', s1) -    return re.sub('([0-9])([a-z])', r'\1 \2', s1) +    s1 = re.sub("(.)([A-Z][a-z]+)", r"\1 \2", value) +    s1 = re.sub("([a-z0-9])([A-Z])", r"\1 \2", s1) +    return re.sub("([0-9])([a-z])", r"\1 \2", s1) +  ope_types = {} @@ -65,8 +73,11 @@ def _init_ope_types():      for k in settings.ISHTAR_OPE_TYPES.keys():          ot, created = OperationType.objects.get_or_create(              txt_idx=settings.ISHTAR_OPE_TYPES[k][0], -            defaults={'label': settings.ISHTAR_OPE_TYPES[k][1], -                      'preventive': k[0] == 'préventive'}) +            defaults={ +                "label": settings.ISHTAR_OPE_TYPES[k][1], +                "preventive": k[0] == "préventive", +            }, +        )          ope_types[k] = ot @@ -78,6 +89,7 @@ def parse_operationtype(value, preventive, owner):          return None      return ope_types[value] +  periods = {}  periods_keys = [] @@ -102,25 +114,26 @@ def _init_period():  def parse_period(value):      value = parse_string(value) -    value = value[3:] if value.startswith('EUR') else value -    while value.endswith('-'): +    value = value[3:] if value.startswith("EUR") else value +    while value.endswith("-"):          value = value[:-1] -    value = value[3:] if value.startswith('EUR') else value +    value = value[3:] if value.startswith("EUR") else value      if not periods:          _init_period()      if not value: -        return [periods['']] -    period, old_val = [], '' +        return [periods[""]] +    period, old_val = [], ""      while value and old_val != value:          old_val = value          for k in periods_keys:              if value.startswith(k):                  period.append(periods[k]) -                value = value[len(k):] +                value = value[len(k) :]                  break      return period -_REPLACED_PERIOD = [('deuxieme', 'second')] + +_REPLACED_PERIOD = [("deuxieme", "second")]  _REPLACED_PERIOD += [(y, x) for x, y in _REPLACED_PERIOD]  REPLACED_PERIOD_DCT = dict(_REPLACED_PERIOD) @@ -133,18 +146,19 @@ def parse_period_name(value):          _init_period()      value = parse_string(value)      if not value: -        return [period_names['']] -    period, old_val = [], '' +        return [period_names[""]] +    period, old_val = [], ""      value = slugify(value)      while value and old_val != value:          old_val = value          for k in period_names_keys:              if value.startswith(k):                  period.append(period_names[k]) -                value = value[len(k):] +                value = value[len(k) :]                  break      return period +  _CACHED_PERMIT_TYPES = {} @@ -152,8 +166,8 @@ def _init_permit_type():      for k in settings.ISHTAR_PERMIT_TYPES:          txt_idx, label = settings.ISHTAR_PERMIT_TYPES[k]          permit_type, created = PermitType.objects.get_or_create( -            txt_idx=txt_idx, defaults={'label': label, -                                       'available': True}) +            txt_idx=txt_idx, defaults={"label": label, "available": True} +        )          _CACHED_PERMIT_TYPES[k] = permit_type @@ -167,6 +181,7 @@ def parse_permittype(value):          value = ""      return _CACHED_PERMIT_TYPES[value] +  _CACHED_ADMIN_ACT_TYPES = {} @@ -177,15 +192,16 @@ def parse_admin_act_typ(value, code, owner):          return      if code not in _CACHED_ADMIN_ACT_TYPES:          act_type, created = ActType.objects.get_or_create( -            txt_idx=code, defaults={'label': value}) +            txt_idx=code, defaults={"label": value} +        )          _CACHED_ADMIN_ACT_TYPES[code] = act_type      return _CACHED_ADMIN_ACT_TYPES[code]  def parse_fileref(value): -    value = parse_string(value).split('/')[0] -    value = value.split('.')[0] -    match = re.search('[0-9].[0-9]*', value) +    value = parse_string(value).split("/")[0] +    value = value.split(".")[0] +    match = re.search("[0-9].[0-9]*", value)      if not match:          return None      return int(match.group()) @@ -203,18 +219,18 @@ def parse_orga(value, alternate_value, owner):      try:          organization_type = OrganizationType.objects.get(label__iexact=value)      except ObjectDoesNotExist: -        organization_type = OrganizationType.objects.get(txt_idx='undefined') -    orga = Organization.objects.create(name=value, -                                       organization_type=organization_type, -                                       history_modifier=owner) +        organization_type = OrganizationType.objects.get(txt_idx="undefined") +    orga = Organization.objects.create( +        name=value, organization_type=organization_type, history_modifier=owner +    )      return orga  def parse_bool(value):      value = parse_string(value) -    if value.lower() in ('yes', 'oui'): +    if value.lower() in ("yes", "oui"):          value = True -    elif value.lower() in ('no', 'non'): +    elif value.lower() in ("no", "non"):          value = False      else:          value = None @@ -222,16 +238,16 @@ def parse_bool(value):  def parse_date(value): -    value = parse_string(value).split(' ')[0] +    value = parse_string(value).split(" ")[0]      try: -        return datetime.datetime.strptime(value, '%d/%m/%Y') +        return datetime.datetime.strptime(value, "%d/%m/%Y")      except:          return None  def parse_yearref(value): -    value = parse_string(value).split('.')[0] -    match = re.search('[0-9].[0-9]*', value) +    value = parse_string(value).split(".")[0] +    match = re.search("[0-9].[0-9]*", value)      if not match:          return None      return int(match.group()) @@ -239,7 +255,7 @@ def parse_yearref(value):  def parse_surface(value):      value = parse_string(value) -    value = value.replace(',', '.') +    value = value.replace(",", ".")      try:          # hectare en metre carrés          value = float(value) * 10000 @@ -265,17 +281,17 @@ def parse_trunc_patriarche(value):      value = parse_string(value)      if not value:          return -    value = value.replace(' ', '') +    value = value.replace(" ", "")      try:          int(value)      except ValueError:          return -    return '18' + str(value) +    return "18" + str(value)  def parse_operation_code(value):      value = parse_string(value) -    code = value.split('.')[-1] +    code = value.split(".")[-1]      try:          return int(code)      except: @@ -291,44 +307,38 @@ def parse_title(value):  def parse_name_surname(value, owner):      value = parse_string(value) -    items = value.split(' ') +    items = value.split(" ")      name = items[0]      surname = ""      if len(items) > 1:          name = " ".join(items[:-1])          surname = items[-1] -    values = {"surname": parse_title(surname)[:30], -              "name": parse_title(name)[:30]} -    if not values['surname'] and not values['name']: +    values = {"surname": parse_title(surname)[:30], "name": parse_title(name)[:30]} +    if not values["surname"] and not values["name"]:          return      q = Person.objects.filter(**values)      if q.count():          return q.all()[0]      else: -        defaults = {'history_modifier': owner, -                    'title': ''} +        defaults = {"history_modifier": owner, "title": ""}          defaults.update(values)          p = Person.objects.create(**defaults) -        p.person_types.add(PersonType.objects.get( -            txt_idx='head_scientist')) +        p.person_types.add(PersonType.objects.get(txt_idx="head_scientist"))          return p  def parse_person(surname, name, old_ref, owner): -    values = {"surname": parse_title(surname), -              "name": parse_title(name)} -    if not values['surname'] and not values['name']: +    values = {"surname": parse_title(surname), "name": parse_title(name)} +    if not values["surname"] and not values["name"]:          return      q = Person.objects.filter(**values)      if q.count():          return q.all()[0]      else: -        defaults = {'history_modifier': owner, -                    'title': ''} +        defaults = {"history_modifier": owner, "title": ""}          defaults.update(values)          p = Person.objects.create(**defaults) -        p.person_types.add(PersonType.objects.get( -            txt_idx='head_scientist')) +        p.person_types.add(PersonType.objects.get(txt_idx="head_scientist"))          return p @@ -344,48 +354,38 @@ def parse_comment_addr_nature(nature, addr, owner):          return ""      return "\n".join(comments) +  # si pas de start date : premier janvier de year  ope_types = { -    'AET': ('other_study', -            'Autre étude', True), -    'APP': ('assistance_preparation_help', -            'Aide à la préparation de publication', True), -    'DOC': ('documents_study', -            'Étude documentaire', True), -    'EV': ('evaluation', -           "Fouille d'évaluation", True), -    'FOU': ('ancient_excavation', -            "Fouille ancienne", True), -    'FP': ('prog_excavation', -           "Fouille programmée", False), -    'MH': ('building_study', "Fouille avant MH", True), -    'OPD': ('arch_diagnostic', -            "Diagnostic archéologique", True), -    'PAN': ('analysis_program', -            "Programme d'analyses", False), -    'PCR': ('collective_research_project', -            "Projet collectif de recherche", False), -    'PMS': ('specialized_eqp_prospection', -            "Prospection avec matériel spécialisé", False), -    'PRD': ('diachronic_prospection', -            "Prospection diachronique", False), -    'PI': ('diachronic_prospection', -           "Prospection diachronique", False), -    'PRM': ('metal_detector_prospection', -            "Prospection détecteur de métaux", False), -    'PRT': ('thematic_prospection', -            "Prospection thématique", False), -    'PT': ('thematic_prospection', -           "Prospection thématique", False), -    'RAR': ('cave_art_record', -            "Relevé d'art rupestre", False), -    'SD': ('sampling_research', -           "Sondage", False), -    'SP': ('prev_excavation', -           "Fouille préventive", True), -    'SU': ('emergency_excavation', -           "Fouille préventive d'urgence", True), +    "AET": ("other_study", "Autre étude", True), +    "APP": ( +        "assistance_preparation_help", +        "Aide à la préparation de publication", +        True, +    ), +    "DOC": ("documents_study", "Étude documentaire", True), +    "EV": ("evaluation", "Fouille d'évaluation", True), +    "FOU": ("ancient_excavation", "Fouille ancienne", True), +    "FP": ("prog_excavation", "Fouille programmée", False), +    "MH": ("building_study", "Fouille avant MH", True), +    "OPD": ("arch_diagnostic", "Diagnostic archéologique", True), +    "PAN": ("analysis_program", "Programme d'analyses", False), +    "PCR": ("collective_research_project", "Projet collectif de recherche", False), +    "PMS": ( +        "specialized_eqp_prospection", +        "Prospection avec matériel spécialisé", +        False, +    ), +    "PRD": ("diachronic_prospection", "Prospection diachronique", False), +    "PI": ("diachronic_prospection", "Prospection diachronique", False), +    "PRM": ("metal_detector_prospection", "Prospection détecteur de métaux", False), +    "PRT": ("thematic_prospection", "Prospection thématique", False), +    "PT": ("thematic_prospection", "Prospection thématique", False), +    "RAR": ("cave_art_record", "Relevé d'art rupestre", False), +    "SD": ("sampling_research", "Sondage", False), +    "SP": ("prev_excavation", "Fouille préventive", True), +    "SU": ("emergency_excavation", "Fouille préventive d'urgence", True),  }  _CACHED_OPE_TYPES = {} @@ -395,8 +395,8 @@ def _prepare_ope_types():      for k in ope_types.keys():          txt_idx, label, preventive = ope_types[k]          ot, created = OperationType.objects.get_or_create( -            txt_idx=txt_idx, defaults={'label': label, -                                       'preventive': preventive}) +            txt_idx=txt_idx, defaults={"label": label, "preventive": preventive} +        )          if k not in _CACHED_OPE_TYPES.keys():              _CACHED_OPE_TYPES[k] = ot @@ -406,16 +406,17 @@ def parse_patriarche_operationtype(value):          return None      return _CACHED_OPE_TYPES[value] -_dpt_re_filter = re.compile('^\([0-9]*\) ') + +_dpt_re_filter = re.compile("^\([0-9]*\) ")  def parse_ope_name(value):      if not value: -        return '' +        return ""      value = value.strip() -    if value.lower() == 'null': -        return '' -    value = _dpt_re_filter.sub('', value) +    if value.lower() == "null": +        return "" +    value = _dpt_re_filter.sub("", value)      return value @@ -430,10 +431,11 @@ def parse_ha(value):  def parse_rapp_index(value):      value = parse_string(value) -    items = re.findall(r'[0-9]+$', value) +    items = re.findall(r"[0-9]+$", value)      if items:          return int(items[-1]) +  _CACHED_DOC_TYPES = {} @@ -443,8 +445,8 @@ def parse_doc_types(value):          if value not in settings.ISHTAR_DOC_TYPES:              return          _CACHED_DOC_TYPES[value], created = SourceType.objects.get_or_create( -            txt_idx=value, -            defaults={"label": settings.ISHTAR_DOC_TYPES[value]}) +            txt_idx=value, defaults={"label": settings.ISHTAR_DOC_TYPES[value]} +        )      return _CACHED_DOC_TYPES[value] @@ -469,10 +471,10 @@ def parse_insee(value):  PARCEL_YEAR_REGEXP = re.compile(r"^([0-9]{4})[ :]+")  PARCEL_SECTION_REGEXP = re.compile(      r"(?: )*(?:[Ss]ection(?:s)?)?(?: )*([A-Z][A-Z0-9]{0,3})[ :]*" -    r"((?:(?: |;|,|[Pp]arcelle(?:s)?|n°|et|à|to)*[0-9]+[p]?)+)") -PARCEL_NB_RANGE_REGEXP = re.compile(r'([0-9]+[p]?) (?:à|to) ([0-9]+[p]?)') -PARCEL_NB_REGEXP = re.compile( -    r'(?: |;|,|[Pp]arcelle(?:s)?|n°|et|à|to)*([0-9]+[p]?)') +    r"((?:(?: |;|,|[Pp]arcelle(?:s)?|n°|et|à|to)*[0-9]+[p]?)+)" +) +PARCEL_NB_RANGE_REGEXP = re.compile(r"([0-9]+[p]?) (?:à|to) ([0-9]+[p]?)") +PARCEL_NB_REGEXP = re.compile(r"(?: |;|,|[Pp]arcelle(?:s)?|n°|et|à|to)*([0-9]+[p]?)")  def parse_parcels(parcel_str, insee_code=None, owner=None): @@ -488,17 +490,17 @@ def parse_parcels(parcel_str, insee_code=None, owner=None):      year = None      if m:          year = m.groups()[0] -        parcel_str = parcel_str[m.span()[1]:] +        parcel_str = parcel_str[m.span()[1] :]      for parcel in PARCEL_SECTION_REGEXP.findall(parcel_str):          sector, nums = parcel[0], parcel[1]          for num in PARCEL_NB_REGEXP.findall(nums):              if len(str(num)) > 6:                  continue -            dct = {'year': year, 'section': sector, 'parcel_number': num} +            dct = {"year": year, "section": sector, "parcel_number": num}              if town: -                dct['town'] = town +                dct["town"] = town              if owner: -                dct['history_modifier'] = owner +                dct["history_modifier"] = owner              parcels.append(dct)          for parcel_ranges in PARCEL_NB_RANGE_REGEXP.findall(nums):              lower_range, higher_range = parcel_ranges @@ -509,11 +511,10 @@ def parse_parcels(parcel_str, insee_code=None, owner=None):              except ValueError:                  continue              for num in range(lower_range, higher_range): -                dct = {'year': year, 'section': sector, -                       'parcel_number': str(num)} +                dct = {"year": year, "section": sector, "parcel_number": str(num)}                  if town: -                    dct['town'] = town +                    dct["town"] = town                  if owner: -                    dct['history_modifier'] = owner +                    dct["history_modifier"] = owner                  parcels.append(dct)      return parcels diff --git a/archaeological_operations/views.py b/archaeological_operations/views.py index 86e5b7f52..51cedbc9c 100644 --- a/archaeological_operations/views.py +++ b/archaeological_operations/views.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3  # -*- coding: utf-8 -*-  # Copyright (C) 2010-2017  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> @@ -31,94 +31,114 @@ from ishtar_common.utils import ugettext_lazy as _, pgettext_lazy  from archaeological_operations import models  from archaeological_operations import forms  from archaeological_operations import wizards -from ishtar_common.forms import ClosingDateFormSelection, FinalForm, \ -    FinalDeleteForm -from ishtar_common.models import get_current_profile, IshtarSiteProfile, \ -    DocumentTemplate +from ishtar_common.forms import ClosingDateFormSelection, FinalForm, FinalDeleteForm +from ishtar_common.models import ( +    get_current_profile, +    IshtarSiteProfile, +    DocumentTemplate, +)  from ishtar_common.utils import put_session_message, check_rights_condition -from ishtar_common.views import gen_generate_doc, QAItemEditForm, \ -    QABaseLockView, wizard_is_available, QAItemForm, IshtarMixin, \ -    LoginRequiredMixin -from ishtar_common.views_item import get_item, show_item, revert_item, \ -    new_qa_item +from ishtar_common.views import ( +    gen_generate_doc, +    QAItemEditForm, +    QABaseLockView, +    wizard_is_available, +    QAItemForm, +    IshtarMixin, +    LoginRequiredMixin, +) +from ishtar_common.views_item import get_item, show_item, revert_item, new_qa_item  from ishtar_common.wizards import SearchWizard  def autocomplete_patriarche(request): -    if (not request.user.has_perm('ishtar_common.view_operation', -                                  models.Operation) -            and not request.user.has_perm('ishtar_common.view_own_operation', -                                          models.Operation) -            and not request.user.ishtaruser.has_right( -                'operation_search', session=request.session)): -        return HttpResponse(content_type='text/plain') -    if not request.GET.get('term'): -        return HttpResponse(content_type='text/plain') -    q = request.GET.get('term') +    if ( +        not request.user.has_perm("ishtar_common.view_operation", models.Operation) +        and not request.user.has_perm( +            "ishtar_common.view_own_operation", models.Operation +        ) +        and not request.user.ishtaruser.has_right( +            "operation_search", session=request.session +        ) +    ): +        return HttpResponse(content_type="text/plain") +    if not request.GET.get("term"): +        return HttpResponse(content_type="text/plain") +    q = request.GET.get("term")      query = Q() -    for q in q.split(' '): +    for q in q.split(" "):          query &= Q(code_patriarche__startswith=q)      limit = 15 -    operations = models.Operation.objects\ -        .filter(query).order_by('code_patriarche')[:limit] -    data = json.dumps([{'id': operation.code_patriarche, -                        'value': operation.code_patriarche} -                       for operation in operations]) -    return HttpResponse(data, content_type='text/plain') +    operations = models.Operation.objects.filter(query).order_by("code_patriarche")[ +        :limit +    ] +    data = json.dumps( +        [ +            {"id": operation.code_patriarche, "value": operation.code_patriarche} +            for operation in operations +        ] +    ) +    return HttpResponse(data, content_type="text/plain")  def autocomplete_archaeologicalsite(request): -    if (not request.user.has_perm( -            'archaeological_operations.view_archaeologicalsite', -            models.ArchaeologicalSite) -        and not request.user.has_perm( -            'archaeological_operations.view_own_archaeologicalsite', -            models.ArchaeologicalSite)): -        return HttpResponse(content_type='text/plain') -    if not request.GET.get('term'): -        return HttpResponse(content_type='text/plain') -    q = request.GET.get('term') +    if not request.user.has_perm( +        "archaeological_operations.view_archaeologicalsite", models.ArchaeologicalSite +    ) and not request.user.has_perm( +        "archaeological_operations.view_own_archaeologicalsite", +        models.ArchaeologicalSite, +    ): +        return HttpResponse(content_type="text/plain") +    if not request.GET.get("term"): +        return HttpResponse(content_type="text/plain") +    q = request.GET.get("term")      query = Q() -    for q in q.split(' '): +    for q in q.split(" "):          qt = Q(reference__icontains=q) | Q(name__icontains=q)          query = query & qt      limit = 15 -    sites = models.ArchaeologicalSite.objects.filter( -        query).distinct().order_by('reference')[:limit] -    data = json.dumps([{'id': site.pk, -                        'value': str(site)[:60]} -                       for site in sites]) -    return HttpResponse(data, content_type='text/plain') +    sites = ( +        models.ArchaeologicalSite.objects.filter(query) +        .distinct() +        .order_by("reference")[:limit] +    ) +    data = json.dumps([{"id": site.pk, "value": str(site)[:60]} for site in sites]) +    return HttpResponse(data, content_type="text/plain")  new_archaeologicalsite = new_qa_item( -    models.ArchaeologicalSite, forms.ArchaeologicalSiteForm, many=True, -    page_name=_("New archaeological site") +    models.ArchaeologicalSite, +    forms.ArchaeologicalSiteForm, +    many=True, +    page_name=_("New archaeological site"),  )  def autocomplete_operation(request):      # person_types = request.user.ishtaruser.person.person_type -    if (not request.user.has_perm('ishtar_common.view_operation', -                                  models.Operation) +    if ( +        not request.user.has_perm("ishtar_common.view_operation", models.Operation)          and not request.user.has_perm( -            'ishtar_common.view_own_operation', models.Operation) -            and not request.user.ishtaruser.has_right( -                'operation_search', session=request.session)): -        return HttpResponse(content_type='text/plain') -    if not request.GET.get('term'): -        return HttpResponse(content_type='text/plain') -    q = request.GET.get('term') +            "ishtar_common.view_own_operation", models.Operation +        ) +        and not request.user.ishtaruser.has_right( +            "operation_search", session=request.session +        ) +    ): +        return HttpResponse(content_type="text/plain") +    if not request.GET.get("term"): +        return HttpResponse(content_type="text/plain") +    q = request.GET.get("term")      query = Q() -    for q in q.split(' '): +    for q in q.split(" "):          extra = Q(towns__name__icontains=q) | Q(common_name__icontains=q)          try:              int(q)              extra = extra | Q(year=q) | Q(operation_code=q)          except ValueError:              pass -        if settings.COUNTRY == 'fr': -            if q.startswith('OA'): +        if settings.COUNTRY == "fr": +            if q.startswith("OA"):                  q = q[2:]              try:                  int(q) @@ -128,80 +148,89 @@ def autocomplete_operation(request):          query = query & extra      limit = 15      operations = models.Operation.objects.filter(query).distinct()[:limit] -    data = json.dumps([{'id': operation.pk, 'value': str(operation)} -                       for operation in operations]) -    return HttpResponse(data, content_type='text/plain') +    data = json.dumps( +        [{"id": operation.pk, "value": str(operation)} for operation in operations] +    ) +    return HttpResponse(data, content_type="text/plain")  def get_available_operation_code(request, year=None):      if not request.user.has_perm( -        'ishtar_common.view_operation', models.Operation)\ -        and not request.user.has_perm( -            'ishtar_common.view_own_operation', models.Operation): -        return HttpResponse(content_type='text/plain') -    data = json.dumps({'id': -                       models.Operation.get_available_operation_code(year)}) -    return HttpResponse(data, content_type='text/plain') +        "ishtar_common.view_operation", models.Operation +    ) and not request.user.has_perm( +        "ishtar_common.view_own_operation", models.Operation +    ): +        return HttpResponse(content_type="text/plain") +    data = json.dumps({"id": models.Operation.get_available_operation_code(year)}) +    return HttpResponse(data, content_type="text/plain") -get_operation = get_item(models.Operation, 'get_operation', 'operation', -                         search_form=forms.OperationSelect) +get_operation = get_item( +    models.Operation, "get_operation", "operation", search_form=forms.OperationSelect +) -show_operation = show_item(models.Operation, 'operation') +show_operation = show_item(models.Operation, "operation")  revert_operation = revert_item(models.Operation)  get_administrativeactop = get_item( -    models.AdministrativeAct, 'get_administrativeactop', 'administrativeactop', -    base_request={"operation__pk__isnull": False}) +    models.AdministrativeAct, +    "get_administrativeactop", +    "administrativeactop", +    base_request={"operation__pk__isnull": False}, +)  get_administrativeact = get_item( -    models.AdministrativeAct, 'get_administrativeact', 'administrativeact') +    models.AdministrativeAct, "get_administrativeact", "administrativeact" +) -show_administrativeact = show_item(models.AdministrativeAct, -                                   'administrativeact') +show_administrativeact = show_item(models.AdministrativeAct, "administrativeact")  def dashboard_operation(request, *args, **kwargs):      """      Operation dashboard      """ -    dct = {'dashboard': models.OperationDashboard()} -    return render(request, 'ishtar/dashboards/dashboard_operation.html', dct) +    dct = {"dashboard": models.OperationDashboard()} +    return render(request, "ishtar/dashboards/dashboard_operation.html", dct)  operation_search_wizard = wizards.OperationSearch.as_view( -    [('general-operation_search', forms.OperationFormSelection)], +    [("general-operation_search", forms.OperationFormSelection)],      label=_("Operation search"), -    url_name='operation_search',) +    url_name="operation_search", +)  wizard_steps = [ -    ('filechoice-operation_creation', forms.OperationFormFileChoice), -    ('general-operation_creation', forms.OperationFormGeneral), -    ('judiciary-operation_creation', forms.CourtOrderedSeizureForm), -    ('collaborators-operation_creation', forms.CollaboratorForm), -    ('archaeologicalsite-operation_creation', forms.ArchaeologicalSiteFormSet), -    ('preventive-operation_creation', forms.OperationFormPreventive), -    ('preventivediag-operation_creation', forms.OperationFormPreventiveDiag), -    ('townsgeneral-operation_creation', forms.TownFormset), -    ('towns-operation_creation', forms.SelectedTownFormset), -    ('parcelsgeneral-operation_creation', forms.SelectedParcelGeneralFormSet), -    ('parcels-operation_creation', forms.SelectedParcelFormSet), -    ('remains-operation_creation', forms.RemainForm), -    ('periods-operation_creation', forms.PeriodForm), -    ('relations-operation_creation', forms.RecordRelationsFormSet), -    ('abstract-operation_creation', forms.OperationFormAbstract), -    ('final-operation_creation', FinalForm)] +    ("filechoice-operation_creation", forms.OperationFormFileChoice), +    ("general-operation_creation", forms.OperationFormGeneral), +    ("judiciary-operation_creation", forms.CourtOrderedSeizureForm), +    ("collaborators-operation_creation", forms.CollaboratorForm), +    ("archaeologicalsite-operation_creation", forms.ArchaeologicalSiteFormSet), +    ("preventive-operation_creation", forms.OperationFormPreventive), +    ("preventivediag-operation_creation", forms.OperationFormPreventiveDiag), +    ("townsgeneral-operation_creation", forms.TownFormset), +    ("towns-operation_creation", forms.SelectedTownFormset), +    ("parcelsgeneral-operation_creation", forms.SelectedParcelGeneralFormSet), +    ("parcels-operation_creation", forms.SelectedParcelFormSet), +    ("remains-operation_creation", forms.RemainForm), +    ("periods-operation_creation", forms.PeriodForm), +    ("relations-operation_creation", forms.RecordRelationsFormSet), +    ("abstract-operation_creation", forms.OperationFormAbstract), +    ("final-operation_creation", FinalForm), +]  def get_check_files_for_operation(other_check=None):      def func(self): -        if not get_current_profile().files or \ -                not check_rights_condition(['view_file'])(self): +        if not get_current_profile().files or not check_rights_condition(["view_file"])( +            self +        ):              return False          if not other_check:              return True          return other_check(self) +      return func @@ -209,378 +238,456 @@ check_files_for_operation = get_check_files_for_operation()  ope_crea_condition_dict = { -    'filechoice-operation_creation': check_files_for_operation, -    'judiciary-operation_creation': wizards.is_judiciary( -        'general-operation_creation', models.OperationType, 'operation_type', +    "filechoice-operation_creation": check_files_for_operation, +    "judiciary-operation_creation": wizards.is_judiciary( +        "general-operation_creation", +        models.OperationType, +        "operation_type", +    ), +    "preventive-operation_creation": get_check_files_for_operation( +        wizards.is_preventive( +            "general-operation_creation", +            models.OperationType, +            "operation_type", +            "prev_excavation", +        ) +    ), +    "preventivediag-operation_creation": get_check_files_for_operation( +        wizards.is_preventive( +            "general-operation_creation", +            models.OperationType, +            "operation_type", +            "arch_diagnostic", +        ) +    ), +    "townsgeneral-operation_creation": wizards.has_associated_file( +        "filechoice-operation_creation", negate=True +    ), +    "towns-operation_creation": wizards.has_associated_file( +        "filechoice-operation_creation" +    ), +    "parcelsgeneral-operation_creation": wizards.has_associated_file( +        "filechoice-operation_creation", negate=True +    ), +    "parcels-operation_creation": wizards.has_associated_file( +        "filechoice-operation_creation"      ), -    'preventive-operation_creation': -    get_check_files_for_operation( -        wizards.is_preventive('general-operation_creation', -                              models.OperationType, 'operation_type', -                              'prev_excavation')), -    'preventivediag-operation_creation': -    get_check_files_for_operation( -        wizards.is_preventive('general-operation_creation', -                              models.OperationType, 'operation_type', -                              'arch_diagnostic')), -    'townsgeneral-operation_creation': wizards.has_associated_file( -        'filechoice-operation_creation', negate=True), -    'towns-operation_creation': wizards.has_associated_file( -        'filechoice-operation_creation'), -    'parcelsgeneral-operation_creation': wizards.has_associated_file( -        'filechoice-operation_creation', negate=True), -    'parcels-operation_creation': wizards.has_associated_file( -        'filechoice-operation_creation'),  }  operation_creation_wizard = wizards.OperationWizard.as_view(      wizard_steps,      label=_("New operation"),      condition_dict=ope_crea_condition_dict, -    url_name='operation_creation',) +    url_name="operation_creation", +)  operation_modif_wizard_steps = [ -    ('selec-operation_modification', forms.OperationFormSelection), -    ('general-operation_modification', forms.OperationFormModifGeneral), -    ('judiciary-operation_modification', forms.CourtOrderedSeizureForm), -    ('collaborators-operation_modification', forms.CollaboratorForm), -    ('archaeologicalsite-operation_modification', forms.ArchaeologicalSiteFormSet), -    ('preventive-operation_modification', forms.OperationFormPreventive), -    ('preventivediag-operation_modification', forms.OperationFormPreventiveDiag), -    ('towns-operation_modification', forms.SelectedTownFormset), -    ('townsgeneral-operation_modification', forms.TownFormset), -    ('parcels-operation_modification', forms.SelectedParcelFormSet), -    ('parcelsgeneral-operation_modification', forms.SelectedParcelGeneralFormSet), -    ('remains-operation_modification', forms.RemainForm), -    ('periods-operation_modification', forms.PeriodForm), -    ('relations-operation_modification', forms.RecordRelationsFormSet), -    ('abstract-operation_modification', forms.OperationFormAbstract), -    ('final-operation_modification', FinalForm) +    ("selec-operation_modification", forms.OperationFormSelection), +    ("general-operation_modification", forms.OperationFormModifGeneral), +    ("judiciary-operation_modification", forms.CourtOrderedSeizureForm), +    ("collaborators-operation_modification", forms.CollaboratorForm), +    ("archaeologicalsite-operation_modification", forms.ArchaeologicalSiteFormSet), +    ("preventive-operation_modification", forms.OperationFormPreventive), +    ("preventivediag-operation_modification", forms.OperationFormPreventiveDiag), +    ("towns-operation_modification", forms.SelectedTownFormset), +    ("townsgeneral-operation_modification", forms.TownFormset), +    ("parcels-operation_modification", forms.SelectedParcelFormSet), +    ("parcelsgeneral-operation_modification", forms.SelectedParcelGeneralFormSet), +    ("remains-operation_modification", forms.RemainForm), +    ("periods-operation_modification", forms.PeriodForm), +    ("relations-operation_modification", forms.RecordRelationsFormSet), +    ("abstract-operation_modification", forms.OperationFormAbstract), +    ("final-operation_modification", FinalForm),  ]  ope_modif_condition_dict = { -    'preventive-operation_modification': -    get_check_files_for_operation( -        wizards.is_preventive('general-operation_modification', -                              models.OperationType, 'operation_type', -                              'prev_excavation')), -    'preventivediag-operation_modification': -    get_check_files_for_operation( -        wizards.is_preventive('general-operation_modification', -                              models.OperationType, 'operation_type', -                              'arch_diagnostic')), -    'judiciary-operation_modification': wizards.is_judiciary( -        'general-operation_modification', models.OperationType, 'operation_type', +    "preventive-operation_modification": get_check_files_for_operation( +        wizards.is_preventive( +            "general-operation_modification", +            models.OperationType, +            "operation_type", +            "prev_excavation", +        ) +    ), +    "preventivediag-operation_modification": get_check_files_for_operation( +        wizards.is_preventive( +            "general-operation_modification", +            models.OperationType, +            "operation_type", +            "arch_diagnostic", +        ) +    ), +    "judiciary-operation_modification": wizards.is_judiciary( +        "general-operation_modification", +        models.OperationType, +        "operation_type", +    ), +    "townsgeneral-operation_modification": wizards.has_associated_file( +        "general-operation_modification", negate=True +    ), +    "towns-operation_modification": wizards.has_associated_file( +        "general-operation_modification" +    ), +    "parcelsgeneral-operation_modification": wizards.has_associated_file( +        "general-operation_modification", negate=True +    ), +    "parcels-operation_modification": wizards.has_associated_file( +        "general-operation_modification"      ), -    'townsgeneral-operation_modification': wizards.has_associated_file( -        'general-operation_modification', negate=True), -    'towns-operation_modification': wizards.has_associated_file( -        'general-operation_modification'), -    'parcelsgeneral-operation_modification': wizards.has_associated_file( -        'general-operation_modification', negate=True), -    'parcels-operation_modification': wizards.has_associated_file( -        'general-operation_modification'), -  }  operation_modification_wizard = wizards.OperationModificationWizard.as_view(      operation_modif_wizard_steps,      label=_("Operation modification"),      condition_dict=ope_modif_condition_dict, -    url_name='operation_modification',) +    url_name="operation_modification", +)  def operation_modify(request, pk): -    if not wizard_is_available(operation_modification_wizard, request, -                               models.Operation, pk): +    if not wizard_is_available( +        operation_modification_wizard, request, models.Operation, pk +    ):          return HttpResponseRedirect("/") -    wizard_url = 'operation_modification' +    wizard_url = "operation_modification"      wizards.OperationModificationWizard.session_set_value( -        request, 'selec-' + wizard_url, 'pk', pk, reset=True) -    return redirect(reverse(wizard_url, -                            kwargs={'step': 'general-' + wizard_url})) +        request, "selec-" + wizard_url, "pk", pk, reset=True +    ) +    return redirect(reverse(wizard_url, kwargs={"step": "general-" + wizard_url}))  def operation_add(request, file_id):      operation_creation_wizard(request)      wizards.OperationWizard.session_set_value( -        request, 'filechoice-operation_creation', 'associated_file', -        file_id, reset=True) -    return redirect(reverse('operation_creation', -                            kwargs={'step': 'general-operation_creation'})) +        request, "filechoice-operation_creation", "associated_file", file_id, reset=True +    ) +    return redirect( +        reverse("operation_creation", kwargs={"step": "general-operation_creation"}) +    ) +  operation_closing_steps = [ -    ('selec-operation_closing', forms.OperationFormSelection), -    ('date-operation_closing', ClosingDateFormSelection), -    ('final-operation_closing', forms.FinalOperationClosingForm)] +    ("selec-operation_closing", forms.OperationFormSelection), +    ("date-operation_closing", ClosingDateFormSelection), +    ("final-operation_closing", forms.FinalOperationClosingForm), +]  operation_closing_wizard = wizards.OperationClosingWizard.as_view(      operation_closing_steps,      label=_("Operation closing"), -    url_name='operation_closing',) +    url_name="operation_closing", +)  operation_deletion_steps = [ -    ('selec-operation_deletion', forms.OperationFormMultiSelection), -    ('final-operation_deletion', forms.OperationDeletionForm) +    ("selec-operation_deletion", forms.OperationFormMultiSelection), +    ("final-operation_deletion", forms.OperationDeletionForm),  ]  operation_deletion_wizard = wizards.OperationDeletionWizard.as_view(      operation_deletion_steps,      label=_("Operation deletion"), -    url_name='operation_deletion',) +    url_name="operation_deletion", +)  def operation_delete(request, pk): -    if not wizard_is_available(operation_deletion_wizard, request, -                               models.Operation, pk): +    if not wizard_is_available( +        operation_deletion_wizard, request, models.Operation, pk +    ):          return HttpResponseRedirect("/") -    wizard_url = 'operation_deletion' +    wizard_url = "operation_deletion"      wizards.OperationDeletionWizard.session_set_value( -        request, 'selec-' + wizard_url, 'pks', pk, reset=True) -    return redirect(reverse(wizard_url, -                            kwargs={'step': 'final-' + wizard_url})) +        request, "selec-" + wizard_url, "pks", pk, reset=True +    ) +    return redirect(reverse(wizard_url, kwargs={"step": "final-" + wizard_url}))  # archaeological sites +  def site_extra_context(request, item): -    return {'SITE_LABEL': IshtarSiteProfile.get_default_site_label()} +    return {"SITE_LABEL": IshtarSiteProfile.get_default_site_label()} -get_site = get_item(models.ArchaeologicalSite, 'get_site', 'site', -                    search_form=forms.SiteSelect) -show_site = show_item( -    models.ArchaeologicalSite, 'site', -    extra_dct=site_extra_context +get_site = get_item( +    models.ArchaeologicalSite, "get_site", "site", search_form=forms.SiteSelect  ) +show_site = show_item(models.ArchaeologicalSite, "site", extra_dct=site_extra_context)  revert_site = revert_item(models.ArchaeologicalSite)  site_search_wizard = wizards.SiteSearch.as_view( -    [('general-site_search', forms.SiteFormSelection)], -    url_name='site_search', +    [("general-site_search", forms.SiteFormSelection)], +    url_name="site_search",  )  site_creation_steps = [ -    ('general-site_creation', forms.SiteForm), -    ('towns-site_creation', forms.SiteTownFormset), -    ('underwater-site_creation', forms.SiteUnderwaterForm), -    ('final-site_creation', FinalForm) +    ("general-site_creation", forms.SiteForm), +    ("towns-site_creation", forms.SiteTownFormset), +    ("underwater-site_creation", forms.SiteUnderwaterForm), +    ("final-site_creation", FinalForm),  ]  site_creation_wizard = wizards.SiteWizard.as_view(      site_creation_steps, -    condition_dict={'underwater-site_creation': forms.check_underwater_module}, -    url_name='site_creation', +    condition_dict={"underwater-site_creation": forms.check_underwater_module}, +    url_name="site_creation",  )  site_modification_steps = [ -    ('selec-site_modification', forms.SiteFormSelection), -    ('general-site_modification', forms.SiteForm), -    ('towns-site_modification', forms.SiteTownFormset), -    ('underwater-site_modification', forms.SiteUnderwaterForm), -    ('final-site_modification', FinalForm) +    ("selec-site_modification", forms.SiteFormSelection), +    ("general-site_modification", forms.SiteForm), +    ("towns-site_modification", forms.SiteTownFormset), +    ("underwater-site_modification", forms.SiteUnderwaterForm), +    ("final-site_modification", FinalForm),  ]  site_modification_wizard = wizards.SiteModificationWizard.as_view(      site_modification_steps, -    condition_dict={ -        'underwater-site_modification': forms.check_underwater_module}, -    url_name='site_modification', +    condition_dict={"underwater-site_modification": forms.check_underwater_module}, +    url_name="site_modification",  )  def site_modify(request, pk): -    if not wizard_is_available(site_modification_wizard, request, -                               models.ArchaeologicalSite, pk): +    if not wizard_is_available( +        site_modification_wizard, request, models.ArchaeologicalSite, pk +    ):          return HttpResponseRedirect("/") -    wizard_url = 'site_modification' +    wizard_url = "site_modification"      wizards.SiteModificationWizard.session_set_value( -        request, 'selec-' + wizard_url, 'pk', pk, reset=True) -    return redirect(reverse(wizard_url, -                            kwargs={'step': 'general-' + wizard_url})) +        request, "selec-" + wizard_url, "pk", pk, reset=True +    ) +    return redirect(reverse(wizard_url, kwargs={"step": "general-" + wizard_url}))  site_deletion_steps = [ -    ('selec-site_deletion', forms.SiteFormMultiSelection), -    ('final-site_deletion', FinalDeleteForm) +    ("selec-site_deletion", forms.SiteFormMultiSelection), +    ("final-site_deletion", FinalDeleteForm),  ]  site_deletion_wizard = wizards.SiteDeletionWizard.as_view(      site_deletion_steps,      label=_("Site deletion"), -    url_name='site_deletion',) +    url_name="site_deletion", +)  def site_delete(request, pk): -    if not wizard_is_available(site_deletion_wizard, request, -                               models.ArchaeologicalSite, pk): +    if not wizard_is_available( +        site_deletion_wizard, request, models.ArchaeologicalSite, pk +    ):          return HttpResponseRedirect("/") -    wizard_url = 'site_deletion' +    wizard_url = "site_deletion"      wizards.SiteDeletionWizard.session_set_value( -        request, 'selec-' + wizard_url, 'pks', pk, reset=True) -    return redirect(reverse(wizard_url, -                            kwargs={'step': 'final-' + wizard_url})) - -operation_administrativeactop_search_wizard = wizards.SearchWizard.as_view([ -    ('general-operation_administrativeactop_search', -     forms.AdministrativeActOpeFormSelection)], +        request, "selec-" + wizard_url, "pks", pk, reset=True +    ) +    return redirect(reverse(wizard_url, kwargs={"step": "final-" + wizard_url})) + + +operation_administrativeactop_search_wizard = wizards.SearchWizard.as_view( +    [ +        ( +            "general-operation_administrativeactop_search", +            forms.AdministrativeActOpeFormSelection, +        ) +    ],      label=_("Administrative act search"), -    url_name='operation_administrativeactop_search',) +    url_name="operation_administrativeactop_search", +)  administrativeactop_steps = [ -    ('selec-operation_administrativeactop', forms.OperationFormSelection), -    ('administrativeact-operation_administrativeactop', -     forms.AdministrativeActOpeForm), -    ('final-operation_administrativeactop', FinalForm)] - - -operation_administrativeactop_wizard = \ -    wizards.OperationAdministrativeActWizard.as_view( -        administrativeactop_steps, -        label=_("Operation: new administrative act"), -        url_name='operation_administrativeactop',) - -operation_administrativeactop_modification_wizard = \ -    wizards.OperationEditAdministrativeActWizard.as_view([ -        ('selec-operation_administrativeactop_modification', -         forms.AdministrativeActOpeFormSelection), -        ('administrativeact-operation_administrativeactop_modification', -         forms.AdministrativeActOpeModifForm), -        ('final-operation_administrativeactop_modification', FinalForm)], +    ("selec-operation_administrativeactop", forms.OperationFormSelection), +    ("administrativeact-operation_administrativeactop", forms.AdministrativeActOpeForm), +    ("final-operation_administrativeactop", FinalForm), +] + + +operation_administrativeactop_wizard = wizards.OperationAdministrativeActWizard.as_view( +    administrativeactop_steps, +    label=_("Operation: new administrative act"), +    url_name="operation_administrativeactop", +) + +operation_administrativeactop_modification_wizard = ( +    wizards.OperationEditAdministrativeActWizard.as_view( +        [ +            ( +                "selec-operation_administrativeactop_modification", +                forms.AdministrativeActOpeFormSelection, +            ), +            ( +                "administrativeact-operation_administrativeactop_modification", +                forms.AdministrativeActOpeModifForm, +            ), +            ("final-operation_administrativeactop_modification", FinalForm), +        ],          label=_("Operation: administrative act modification"), -        url_name='operation_administrativeactop_modification',) +        url_name="operation_administrativeactop_modification", +    ) +)  def operation_administrativeactop_modify(request, pk):      if not wizard_is_available( -            operation_administrativeactop_modification_wizard, request, -            models.AdministrativeAct, pk): +        operation_administrativeactop_modification_wizard, +        request, +        models.AdministrativeAct, +        pk, +    ):          return HttpResponseRedirect("/") -    wizard_url = 'operation_administrativeactop_modification' +    wizard_url = "operation_administrativeactop_modification"      wizards.OperationEditAdministrativeActWizard.session_set_value( -        request, 'selec-' + wizard_url, 'pk', pk, reset=True) +        request, "selec-" + wizard_url, "pk", pk, reset=True +    )      return redirect( -        reverse(wizard_url, kwargs={'step': 'administrativeact-' + wizard_url})) - - -operation_administrativeactop_deletion_wizard = \ -    wizards.AdministrativeActDeletionWizard.as_view([ -        ('selec-operation_administrativeactop_deletion', -         forms.AdministrativeActOpeFormSelection), -        ('final-operation_administrativeactop_deletion', -         forms.FinalAdministrativeActDeleteForm)], +        reverse(wizard_url, kwargs={"step": "administrativeact-" + wizard_url}) +    ) + + +operation_administrativeactop_deletion_wizard = ( +    wizards.AdministrativeActDeletionWizard.as_view( +        [ +            ( +                "selec-operation_administrativeactop_deletion", +                forms.AdministrativeActOpeFormSelection, +            ), +            ( +                "final-operation_administrativeactop_deletion", +                forms.FinalAdministrativeActDeleteForm, +            ), +        ],          label=_("Operation: administrative act deletion"), -        url_name='operation_administrativeactop_deletion',) +        url_name="operation_administrativeactop_deletion", +    ) +)  def operation_administrativeactop_delete(request, pk):      if not wizard_is_available( -            operation_administrativeactop_deletion_wizard, request, -            models.AdministrativeAct, pk): +        operation_administrativeactop_deletion_wizard, +        request, +        models.AdministrativeAct, +        pk, +    ):          return HttpResponseRedirect("/") -    wizard_url = 'operation_administrativeactop_deletion' +    wizard_url = "operation_administrativeactop_deletion"      wizards.AdministrativeActDeletionWizard.session_set_value( -        request, 'selec-' + wizard_url, 'pk', pk, reset=True) -    return redirect( -        reverse(wizard_url, kwargs={'step': 'final-' + wizard_url})) - - -administrativact_register_wizard = SearchWizard.as_view([ -    ('general-administrativact_register', -     forms.AdministrativeActRegisterFormSelection)], -    label=pgettext_lazy('admin act register', "Register"), -    url_name='administrativact_register',) +        request, "selec-" + wizard_url, "pk", pk, reset=True +    ) +    return redirect(reverse(wizard_url, kwargs={"step": "final-" + wizard_url})) + + +administrativact_register_wizard = SearchWizard.as_view( +    [ +        ( +            "general-administrativact_register", +            forms.AdministrativeActRegisterFormSelection, +        ) +    ], +    label=pgettext_lazy("admin act register", "Register"), +    url_name="administrativact_register", +)  generatedoc_administrativeactop = gen_generate_doc(models.AdministrativeAct)  def administrativeactfile_document( -        request, file=False, treatment=False, treatment_file=False): +    request, file=False, treatment=False, treatment_file=False +):      search_form = forms.AdministrativeActOpeFormSelection -    document_type = 'O' +    document_type = "O"      if file: -        from archaeological_files.forms import \ -            AdministrativeActFileFormSelection +        from archaeological_files.forms import AdministrativeActFileFormSelection +          search_form = AdministrativeActFileFormSelection -        document_type = 'F' +        document_type = "F"      elif treatment: -        from archaeological_finds.forms import \ -            AdministrativeActTreatmentFormSelection +        from archaeological_finds.forms import AdministrativeActTreatmentFormSelection +          search_form = AdministrativeActTreatmentFormSelection -        document_type = 'T' +        document_type = "T"      elif treatment_file: -        from archaeological_finds.forms import \ -            AdministrativeActTreatmentFileFormSelection +        from archaeological_finds.forms import ( +            AdministrativeActTreatmentFileFormSelection, +        ) +          search_form = AdministrativeActTreatmentFileFormSelection -        document_type = 'TF' +        document_type = "TF" -    if not request.user.has_perm('view_administrativeact', -                                 models.AdministrativeAct): -        return HttpResponse(content_type='text/plain') +    if not request.user.has_perm("view_administrativeact", models.AdministrativeAct): +        return HttpResponse(content_type="text/plain")      dct = {}      DocumentGenerationAdminActForm = forms.DocumentGenerationAdminActForm      if request.POST: -        dct['search_form'] = search_form(request.POST) -        dct['template_form'] = DocumentGenerationAdminActForm( -            document_type=document_type) +        dct["search_form"] = search_form(request.POST) +        dct["template_form"] = DocumentGenerationAdminActForm( +            document_type=document_type +        )          c_object = None          try: -            if dct['search_form'].is_valid(): -                c_object = \ -                    DocumentGenerationAdminActForm._associated_model\ -                    .objects.get(pk=dct['search_form'].cleaned_data.get('pk')) +            if dct["search_form"].is_valid(): +                c_object = DocumentGenerationAdminActForm._associated_model.objects.get( +                    pk=dct["search_form"].cleaned_data.get("pk") +                )          except DocumentGenerationAdminActForm._associated_model.DoesNotExist:              pass          if c_object: -            dct['template_form'] = DocumentGenerationAdminActForm( -                request.POST, document_type=document_type, obj=c_object) -            if dct['template_form'].is_valid(): +            dct["template_form"] = DocumentGenerationAdminActForm( +                request.POST, document_type=document_type, obj=c_object +            ) +            if dct["template_form"].is_valid():                  try:                      return generatedoc_administrativeactop(                          request, -                        dct['search_form'].cleaned_data.get('pk'), -                        dct['template_form'].cleaned_data.get( -                            'document_template')) +                        dct["search_form"].cleaned_data.get("pk"), +                        dct["template_form"].cleaned_data.get("document_template"), +                    )                  except TemplateSyntaxError: -                    dct['search_form'] = search_form() +                    dct["search_form"] = search_form()                      try: -                        template = DocumentTemplate.objects.get(pk=dct[ -                            'template_form'].cleaned_data.get( -                                'document_template')).name +                        template = DocumentTemplate.objects.get( +                            pk=dct["template_form"].cleaned_data.get( +                                "document_template" +                            ) +                        ).name                      except DocumentTemplate.DoesNotExist:                          template = "" -                    dct['template_form'] = DocumentGenerationAdminActForm( -                        document_type=document_type) -                    dct['template_error'] = str(_( -                        "Syntax error on the source template \"{}\" - " -                        "contact your administrator and ask him to check " -                        "the syntax of this document.")).format(template) +                    dct["template_form"] = DocumentGenerationAdminActForm( +                        document_type=document_type +                    ) +                    dct["template_error"] = str( +                        _( +                            'Syntax error on the source template "{}" - ' +                            "contact your administrator and ask him to check " +                            "the syntax of this document." +                        ) +                    ).format(template)      else: -        dct['search_form'] = search_form() -        dct['template_form'] = DocumentGenerationAdminActForm( -            document_type=document_type) -    return render(request, 'ishtar/administrativeact_document.html', dct) +        dct["search_form"] = search_form() +        dct["template_form"] = DocumentGenerationAdminActForm( +            document_type=document_type +        ) +    return render(request, "ishtar/administrativeact_document.html", dct)  def autocomplete_administrativeact(request): -    if (not request.user.has_perm( -            'archaeological_operations.view_administrativeact', -            models.AdministrativeAct) -            and not request.user.has_perm( -                'archaeological_operations.view_own_administrativeact', -                models.AdministrativeAct)): -        return HttpResponse(content_type='text/plain') -    if not request.GET.get('term'): -        return HttpResponse(content_type='text/plain') -    q = request.GET.get('term') +    if not request.user.has_perm( +        "archaeological_operations.view_administrativeact", models.AdministrativeAct +    ) and not request.user.has_perm( +        "archaeological_operations.view_own_administrativeact", models.AdministrativeAct +    ): +        return HttpResponse(content_type="text/plain") +    if not request.GET.get("term"): +        return HttpResponse(content_type="text/plain") +    q = request.GET.get("term")      query = Q() -    for q in q.split(' '): +    for q in q.split(" "):          qt = Q(act_type__label__icontains=q) | Q(towns_label=q)          try:              if len(q) == 4: @@ -590,25 +697,33 @@ def autocomplete_administrativeact(request):              pass          query = query & qt      limit = 15 -    items = models.AdministrativeAct.objects.filter( -        query).order_by('year', 'index').distinct()[:limit] -    data = json.dumps([{'id': item.pk, 'value': str(item)[:80] + " (...)"} -                       for item in items]) -    return HttpResponse(data, content_type='text/plain') +    items = ( +        models.AdministrativeAct.objects.filter(query) +        .order_by("year", "index") +        .distinct()[:limit] +    ) +    data = json.dumps( +        [{"id": item.pk, "value": str(item)[:80] + " (...)"} for item in items] +    ) +    return HttpResponse(data, content_type="text/plain")  def reset_wizards(request):      for wizard_class, url_name in ( -            (wizards.OperationWizard, 'operation_creation'), -            (wizards.OperationModificationWizard, 'operation_modification'), -            (wizards.OperationClosingWizard, 'operation_closing'), -            (wizards.OperationDeletionWizard, 'operation_deletion_wizard'), -            (wizards.OperationAdministrativeActWizard, -             'operation_administrativeactop'), -            (wizards.OperationEditAdministrativeActWizard, -             'operation_administrativeactop_modification'), -            (wizards.AdministrativeActDeletionWizard, -             'operation_administrativeactop_deletion'),): +        (wizards.OperationWizard, "operation_creation"), +        (wizards.OperationModificationWizard, "operation_modification"), +        (wizards.OperationClosingWizard, "operation_closing"), +        (wizards.OperationDeletionWizard, "operation_deletion_wizard"), +        (wizards.OperationAdministrativeActWizard, "operation_administrativeactop"), +        ( +            wizards.OperationEditAdministrativeActWizard, +            "operation_administrativeactop_modification", +        ), +        ( +            wizards.AdministrativeActDeletionWizard, +            "operation_administrativeactop_deletion", +        ), +    ):          wizard_class.session_reset(request, url_name) @@ -628,7 +743,7 @@ class QASiteLockView(QABaseLockView):  class QAOperationdDuplicateFormView(QAItemForm): -    template_name = 'ishtar/forms/qa_operation_duplicate.html' +    template_name = "ishtar/forms/qa_operation_duplicate.html"      model = models.Operation      page_name = _("Duplicate")      form_class = forms.QAOperationDuplicateForm @@ -636,7 +751,7 @@ class QAOperationdDuplicateFormView(QAItemForm):      def get_form_kwargs(self):          kwargs = super(QAOperationdDuplicateFormView, self).get_form_kwargs() -        kwargs['user'] = self.request.user +        kwargs["user"] = self.request.user          return kwargs      def form_valid(self, form): @@ -644,23 +759,21 @@ class QAOperationdDuplicateFormView(QAItemForm):          return HttpResponseRedirect(reverse("success"))      def get_context_data(self, **kwargs): -        data = super(QAOperationdDuplicateFormView, self).get_context_data( -            **kwargs) -        data['action_name'] = _("Duplicate") +        data = super(QAOperationdDuplicateFormView, self).get_context_data(**kwargs) +        data["action_name"] = _("Duplicate")          return data  class QAArchaeologicalSiteDuplicateFormView(QAItemForm): -    template_name = 'ishtar/forms/qa_site_duplicate.html' +    template_name = "ishtar/forms/qa_site_duplicate.html"      model = models.ArchaeologicalSite      page_name = _("Duplicate")      form_class = forms.QAArchaeologicalSiteDuplicateForm      base_url = "site-qa-duplicate"      def get_form_kwargs(self): -        kwargs = super(QAArchaeologicalSiteDuplicateFormView, -                       self).get_form_kwargs() -        kwargs['user'] = self.request.user +        kwargs = super(QAArchaeologicalSiteDuplicateFormView, self).get_form_kwargs() +        kwargs["user"] = self.request.user          return kwargs      def form_valid(self, form): @@ -668,9 +781,10 @@ class QAArchaeologicalSiteDuplicateFormView(QAItemForm):          return HttpResponseRedirect(reverse("success"))      def get_context_data(self, **kwargs): -        data = super(QAArchaeologicalSiteDuplicateFormView, -                     self).get_context_data(**kwargs) -        data['action_name'] = _("Duplicate") +        data = super(QAArchaeologicalSiteDuplicateFormView, self).get_context_data( +            **kwargs +        ) +        data["action_name"] = _("Duplicate")          return data @@ -683,30 +797,36 @@ class GenerateStatsOperation(IshtarMixin, LoginRequiredMixin, RedirectView):      model = models.Operation      def get_redirect_url(self, *args, **kwargs): -        return reverse('display-item', -                       args=[self.model.SLUG, self.item.pk]) + "#statistics" +        return ( +            reverse("display-item", args=[self.model.SLUG, self.item.pk]) +            + "#statistics" +        )      def get(self, request, *args, **kwargs): -        self.item = self.model.objects.get(pk=kwargs['pk']) -        self.item._get_or_set_stats('_nb_acts', update=True) -        self.item._get_or_set_stats('_nb_indexed_acts', update=True) -        self.item._get_or_set_stats('_nb_context_records', update=True) -        self.item._get_or_set_stats('_nb_context_records_by_type', update=True, -                                    expected_type=list) -        self.item._get_or_set_stats('_nb_context_records_by_periods', -                                    update=True, expected_type=list) -        self.item._get_or_set_stats('_nb_finds', update=True) -        self.item._get_or_set_stats('_nb_finds_by_material_type', update=True, -                                    expected_type=list) -        self.item._get_or_set_stats('_nb_finds_by_types', update=True, -                                    expected_type=list) -        self.item._get_or_set_stats('_nb_finds_by_periods', update=True, -                                    expected_type=list) -        self.item._get_or_set_stats('_nb_documents', update=True) -        self.item._get_or_set_stats('_nb_documents_by_types', update=True, -                                    expected_type=list) -        self.item._get_or_set_stats('_nb_stats_finds_by_ue', update=True) +        self.item = self.model.objects.get(pk=kwargs["pk"]) +        self.item._get_or_set_stats("_nb_acts", update=True) +        self.item._get_or_set_stats("_nb_indexed_acts", update=True) +        self.item._get_or_set_stats("_nb_context_records", update=True) +        self.item._get_or_set_stats( +            "_nb_context_records_by_type", update=True, expected_type=list +        ) +        self.item._get_or_set_stats( +            "_nb_context_records_by_periods", update=True, expected_type=list +        ) +        self.item._get_or_set_stats("_nb_finds", update=True) +        self.item._get_or_set_stats( +            "_nb_finds_by_material_type", update=True, expected_type=list +        ) +        self.item._get_or_set_stats( +            "_nb_finds_by_types", update=True, expected_type=list +        ) +        self.item._get_or_set_stats( +            "_nb_finds_by_periods", update=True, expected_type=list +        ) +        self.item._get_or_set_stats("_nb_documents", update=True) +        self.item._get_or_set_stats( +            "_nb_documents_by_types", update=True, expected_type=list +        ) +        self.item._get_or_set_stats("_nb_stats_finds_by_ue", update=True)          return super(GenerateStatsOperation, self).get(request, *args, **kwargs) - - diff --git a/archaeological_operations/widgets.py b/archaeological_operations/widgets.py index 247fafba5..1494d0c14 100644 --- a/archaeological_operations/widgets.py +++ b/archaeological_operations/widgets.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3  # -*- coding: utf-8 -*-  # Copyright (C) 2013-2016 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> @@ -28,11 +28,11 @@ from ishtar_common.utils import ugettext_lazy as _  class ParcelWidget(widgets.MultiWidget):      def __init__(self, attrs=None):          if not attrs: -            attrs = {'class': 'widget-parcel'} -        elif 'class' not in attrs: -            attrs['class'] = 'widget-parcel' +            attrs = {"class": "widget-parcel"} +        elif "class" not in attrs: +            attrs["class"] = "widget-parcel"          else: -            attrs['class'] += ' widget-parcel' +            attrs["class"] += " widget-parcel"          _widgets = (              widgets.TextInput(attrs=attrs),              widgets.TextInput(attrs=attrs), @@ -46,7 +46,7 @@ class ParcelWidget(widgets.MultiWidget):          return [None, None]      def format_output(self, rendered_widgets): -        return ' / '.join(rendered_widgets) +        return " / ".join(rendered_widgets)  class SelectParcelWidget(widgets.TextInput): @@ -56,7 +56,9 @@ class SelectParcelWidget(widgets.TextInput):      <div class="input-group-append">          <button class='input-group-text btn btn-success' name='formset_add'              value='add'>{}</button> -    </div>""".format(render,  _("Add")) +    </div>""".format( +            render, _("Add") +        )          return mark_safe(html) @@ -64,11 +66,12 @@ class OAWidget(forms.TextInput):      def render(self, name, value, attrs=None, renderer=None):          if not value:              value = "" -        final_attrs = flatatt( -            self.build_attrs(attrs, {'name': name, 'value': value})) -        dct = {'final_attrs': final_attrs, -               'id': attrs['id'], -               "safe_id": attrs['id'].replace('-', '_')} -        t = loader.get_template('ishtar/blocks/OAWidget.html') +        final_attrs = flatatt(self.build_attrs(attrs, {"name": name, "value": value})) +        dct = { +            "final_attrs": final_attrs, +            "id": attrs["id"], +            "safe_id": attrs["id"].replace("-", "_"), +        } +        t = loader.get_template("ishtar/blocks/OAWidget.html")          rendered = t.render(dct)          return mark_safe(rendered) diff --git a/archaeological_operations/wizards.py b/archaeological_operations/wizards.py index c76bbd313..a58e7437d 100644 --- a/archaeological_operations/wizards.py +++ b/archaeological_operations/wizards.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3  # -*- coding: utf-8 -*-  # Copyright (C) 2012-2017  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> @@ -31,8 +31,13 @@ from archaeological_operations import models  from .forms import GenerateDocForm  from ishtar_common.forms import reverse_lazy  from ishtar_common.models import get_current_profile -from ishtar_common.wizards import Wizard, ClosingWizard, DeletionWizard, \ -    SearchWizard, MultipleDeletionWizard +from ishtar_common.wizards import ( +    Wizard, +    ClosingWizard, +    DeletionWizard, +    SearchWizard, +    MultipleDeletionWizard, +)  logger = logging.getLogger(__name__) @@ -43,67 +48,63 @@ class OperationSearch(SearchWizard):  class OperationWizard(Wizard):      model = models.Operation -    object_parcel_type = 'operation' -    parcel_step_key = 'parcels' -    relations_step_key = 'relations' +    object_parcel_type = "operation" +    parcel_step_key = "parcels" +    relations_step_key = "relations"      # step including the current(s) town(s) -    town_step_keys = ['towns-', 'townsgeneral-'] -    town_input_id = 'town'  # input id of the current(s) town(s) +    town_step_keys = ["towns-", "townsgeneral-"] +    town_input_id = "town"  # input id of the current(s) town(s)      multi_towns = False  # true if current town are multi valued      towns_formset = True  # true if towns are managed with formset -    wizard_done_window = reverse_lazy('show-operation') +    wizard_done_window = reverse_lazy("show-operation")      redirect_url = "operation_modification"      def get_template_names(self):          templates = super(OperationWizard, self).get_template_names()          current_step = self.steps.current          if current_step.startswith(self.parcel_step_key): -            templates = ['ishtar/wizard/parcels_wizard.html'] + templates +            templates = ["ishtar/wizard/parcels_wizard.html"] + templates          elif current_step.startswith(self.relations_step_key): -            templates = ['ishtar/wizard/relations_wizard.html'] + templates +            templates = ["ishtar/wizard/relations_wizard.html"] + templates          return templates      def get_current_file(self):          step = self.steps.current          if not step:              return -        file_form_key = 'general-' + self.url_name -        if self.url_name == 'operation_creation': -            file_form_key = 'filechoice-' + self.url_name +        file_form_key = "general-" + self.url_name +        if self.url_name == "operation_creation": +            file_form_key = "filechoice-" + self.url_name          file_id = self.session_get_value(file_form_key, "associated_file")          try:              idx = int(file_id)              current_file = File.objects.get(pk=idx)              return current_file -        except(TypeError, ValueError, ObjectDoesNotExist): +        except (TypeError, ValueError, ObjectDoesNotExist):              pass      def get_reminder(self):          archaeological_file = self.get_current_file()          if archaeological_file: -            return ((_("Archaeological file"), -                     str(archaeological_file)),) +            return ((_("Archaeological file"), str(archaeological_file)),)      def get_context_data(self, form, **kwargs):          """          Return extra context for templates          """ -        context = super(OperationWizard, self).get_context_data(form, -                                                                **kwargs) +        context = super(OperationWizard, self).get_context_data(form, **kwargs)          step = self.steps.current -        if step.startswith('towns'): -            context['TOWNS'] = self.get_towns() -        elif step.startswith('parcels-') and self.get_current_file(): +        if step.startswith("towns"): +            context["TOWNS"] = self.get_towns() +        elif step.startswith("parcels-") and self.get_current_file():              # if a file is associated to the operation add the button "Add all" -            context['add_all'] = True -        if step.startswith('parcels') and \ -           hasattr(self, 'automatic_parcel_association'): -            context['automatic_parcel_association'] = \ -                self.automatic_parcel_association +            context["add_all"] = True +        if step.startswith("parcels") and hasattr(self, "automatic_parcel_association"): +            context["automatic_parcel_association"] = self.automatic_parcel_association          # reminder of the current file          reminder = self.get_reminder()          if reminder: -            context['reminders'] = reminder +            context["reminders"] = reminder          return context      def get_towns(self): @@ -127,8 +128,9 @@ class OperationWizard(Wizard):          operation = self.get_current_object()          if operation:              for parcel in operation.parcels.all(): -                current_parcels.append((parcel.town, parcel.section, -                                        parcel.parcel_number)) +                current_parcels.append( +                    (parcel.town, parcel.section, parcel.parcel_number) +                )                  parcels.append((parcel.pk, parcel.short_label))          try:              for parcel in file.parcels.all(): @@ -159,27 +161,31 @@ class OperationWizard(Wizard):          except KeyError:              raise Http404()          # manage the dynamic choice of towns -        if step.startswith('towns') and hasattr(form, 'management_form'): -            data['TOWNS'] = self.get_towns() -        elif step.startswith(self.parcel_step_key) \ -                and hasattr(form, 'management_form'): +        if step.startswith("towns") and hasattr(form, "management_form"): +            data["TOWNS"] = self.get_towns() +        elif step.startswith(self.parcel_step_key) and hasattr(form, "management_form"):              file = self.get_current_file()              if file: -                data['PARCELS'] = self.get_available_parcels(file) +                data["PARCELS"] = self.get_available_parcels(file)              else:                  town_ids = []                  for town_step_key in self.town_step_keys:                      town_form_key = town_step_key + self.url_name -                    town_ids = self.session_get_value( -                        town_form_key, self.town_input_id, -                        multi=self.towns_formset, -                        multi_value=self.multi_towns) or [] +                    town_ids = ( +                        self.session_get_value( +                            town_form_key, +                            self.town_input_id, +                            multi=self.towns_formset, +                            multi_value=self.multi_towns, +                        ) +                        or [] +                    )                      if town_ids:                          towns = []                          if type(town_ids) == str:                              town_ids = [town_ids]                          for ids in town_ids: -                            for d in ids.split(','): +                            for d in ids.split(","):                                  if d:                                      towns.append(d)                          town_ids = towns @@ -193,7 +199,7 @@ class OperationWizard(Wizard):                          towns.append((town.pk, str(town)))                      except (ValueError, ObjectDoesNotExist):                          pass -                data['TOWNS'] = sorted(towns, key=lambda x: x[1]) +                data["TOWNS"] = sorted(towns, key=lambda x: x[1])          data = data or None          form = super(OperationWizard, self).get_form(step, data, files)          return form @@ -204,18 +210,24 @@ class OperationWizard(Wizard):          """          datas = super(OperationWizard, self).get_formated_datas(forms)          # if the general town form is used the advertissement is relevant -        has_no_af = [form.prefix for form in forms -                     if form.prefix == 'townsgeneral-operation'] and True +        has_no_af = [ +            form.prefix for form in forms if form.prefix == "townsgeneral-operation" +        ] and True          if has_no_af: -            datas = [[ -                _("Warning: No Archaeological File is provided. " -                  "If you have forget it return to the first step."), []]]\ -                + datas +            datas = [ +                [ +                    _( +                        "Warning: No Archaeological File is provided. " +                        "If you have forget it return to the first step." +                    ), +                    [], +                ] +            ] + datas          return datas      def get_form_initial(self, step, data=None):          initial = super(OperationWizard, self).get_form_initial(step) -        if step == 'general-operation_creation': +        if step == "general-operation_creation":              initial.update(self._copy_from_associated_field())          return initial @@ -239,17 +251,19 @@ class OperationWizard(Wizard):          file = self.get_current_file()          if not file:              return initial -        keys = ((('in_charge', 'pk'), 'in_charge'), -                (('name',), 'common_name'), -                (('total_surface',), 'surface'), -                ) +        keys = ( +            (("in_charge", "pk"), "in_charge"), +            (("name",), "common_name"), +            (("total_surface",), "surface"), +        )          initial.update(self.__copy_fields(file, keys))          if file.is_preventive():              return initial -        keys = ((('scientist', 'pk'), 'scientist'), -                (('requested_operation_type', 'pk'), 'operation_type'), -                (('organization', 'pk'), 'operator'), -                ) +        keys = ( +            (("scientist", "pk"), "scientist"), +            (("requested_operation_type", "pk"), "operation_type"), +            (("organization", "pk"), "operator"), +        )          initial.update(self.__copy_fields(file, keys))          return initial @@ -258,7 +272,7 @@ class OperationWizard(Wizard):          post_data = request.POST.copy()          # add all parcel from available in the archaeological file -        if not post_data.get('add_all_parcels', None): +        if not post_data.get("add_all_parcels", None):              return super(OperationWizard, self).post(*args, **kwargs)          file = self.get_current_file() @@ -269,12 +283,12 @@ class OperationWizard(Wizard):          idx = -1          # remove non relevant deleted keys          for k in post_data.keys(): -            if k.startswith(parcel_form_key) and k.endswith('-DELETE'): +            if k.startswith(parcel_form_key) and k.endswith("-DELETE"):                  post_data.pop(k)          for idx, parcel in enumerate(self.get_available_parcels(file)):              parcel_pk, parcel_name = parcel              post_data["%s-%d-parcel" % (parcel_form_key, idx)] = parcel_pk -        post_data[parcel_form_key + '-TOTAL_FORMS'] = idx + 2 +        post_data[parcel_form_key + "-TOTAL_FORMS"] = idx + 2          request.POST = post_data          return super(OperationWizard, self).post(*args, **kwargs) @@ -284,11 +298,12 @@ class OperationWizard(Wizard):  class OperationModificationWizard(OperationWizard):      modification = True -    filter_owns = {'selec-operation_modification': ['pk']} +    filter_owns = {"selec-operation_modification": ["pk"]}      def get_form_kwargs(self, step, **kwargs):          kwargs = super(OperationModificationWizard, self).get_form_kwargs( -            step, **kwargs) +            step, **kwargs +        )          if step != "relations-operation_modification":              return kwargs          kwargs["left_record"] = self.get_current_object() @@ -297,35 +312,47 @@ class OperationModificationWizard(OperationWizard):  class OperationClosingWizard(ClosingWizard):      model = models.Operation -    fields = ['year', 'operation_code', 'operation_type', 'associated_file', -              'in_charge', 'scientist', 'start_date', 'excavation_end_date', -              'comment', 'towns', 'remains'] +    fields = [ +        "year", +        "operation_code", +        "operation_type", +        "associated_file", +        "in_charge", +        "scientist", +        "start_date", +        "excavation_end_date", +        "comment", +        "towns", +        "remains", +    ]  class OperationDeletionWizard(MultipleDeletionWizard):      model = models.Operation      fields = OperationClosingWizard.fields -    filter_owns = {'selec-operation_deletion': ['pks']} +    filter_owns = {"selec-operation_deletion": ["pks"]}      redirect_url = "operation_deletion"  class OperationAdministrativeActWizard(OperationWizard):      edit = False -    wizard_done_window = reverse_lazy('show-administrativeact') -    current_obj_slug = 'administrativeactop' -    ref_object_key = 'operation' +    wizard_done_window = reverse_lazy("show-administrativeact") +    current_obj_slug = "administrativeactop" +    ref_object_key = "operation"      redirect_url = "operation_administrativeactop_modification"      def get_reminder(self): -        form_key = 'selec-' + self.url_name -        if self.url_name.endswith('_administrativeactop'): +        form_key = "selec-" + self.url_name +        if self.url_name.endswith("_administrativeactop"):              # modification and deletion are suffixed with '_modification'              # and '_deletion' so it is creation              operation_id = self.session_get_value(form_key, "pk")              try:                  return ( -                    (_("Operation"), -                     str(models.Operation.objects.get(pk=operation_id))), +                    ( +                        _("Operation"), +                        str(models.Operation.objects.get(pk=operation_id)), +                    ),                  )              except models.Operation.DoesNotExist:                  return @@ -340,35 +367,37 @@ class OperationAdministrativeActWizard(OperationWizard):                  return      def get_extra_model(self, dct, m2m, form_list): -        dct['history_modifier'] = self.request.user +        dct["history_modifier"] = self.request.user          return dct      def get_context_data(self, form, **kwargs):          # manage document generation -        context = super(OperationAdministrativeActWizard, -                        self).get_context_data(form, **kwargs) +        context = super(OperationAdministrativeActWizard, self).get_context_data( +            form, **kwargs +        )          step = self.steps.current -        if step.startswith('final-'): -            general_form_key = 'administrativeact-' + self.url_name +        if step.startswith("final-"): +            general_form_key = "administrativeact-" + self.url_name              act_type = None              try:                  act_type = models.ActType.objects.get( -                    pk=self.session_get_value(general_form_key, "act_type")) +                    pk=self.session_get_value(general_form_key, "act_type") +                )              except models.ActType.DoesNotExist:                  pass              if act_type and act_type.associated_template.count(): -                context['extra_form'] = GenerateDocForm( -                    choices=act_type.associated_template.all()) +                context["extra_form"] = GenerateDocForm( +                    choices=act_type.associated_template.all() +                )          return context      def get_associated_item(self, dct):          return self.get_current_object() -    def save_model(self, dct, m2m, whole_associated_models, form_list, -                   return_object): -        dct['history_modifier'] = self.request.user -        if 'pk' in dct: -            dct.pop('pk') +    def save_model(self, dct, m2m, whole_associated_models, form_list, return_object): +        dct["history_modifier"] = self.request.user +        if "pk" in dct: +            dct.pop("pk")          if self.edit:              admact = self.get_current_object()              for k in dct: @@ -382,11 +411,15 @@ class OperationAdministrativeActWizard(OperationWizard):              dct[self.ref_object_key] = associated_item              admact = models.AdministrativeAct(**dct)          admact.save() -        dct['item'] = admact +        dct["item"] = admact          # check if a doc generation is required -        keys = [self.storage.prefix, 'step_data', 'final-' + self.url_name, -                'doc_generation'] +        keys = [ +            self.storage.prefix, +            "step_data", +            "final-" + self.url_name, +            "doc_generation", +        ]          r = self.request.session          for k in keys:              if k in r and r[k]: @@ -396,21 +429,27 @@ class OperationAdministrativeActWizard(OperationWizard):          if k == keys[-1]:  # the whole list as been traversed              wizard_done_window = str(self.wizard_done_window)              if wizard_done_window: -                dct['wizard_done_window'] = wizard_done_window +                dct["wizard_done_window"] = wizard_done_window              # redirect to the generated doc              if r and type(r) in (tuple, list) and r[0]: -                dct['redirect'] = reverse('generatedoc-administrativeactop', -                                          args=[admact.pk, r[0]]) +                dct["redirect"] = reverse( +                    "generatedoc-administrativeactop", args=[admact.pk, r[0]] +                )          # make the new object a default -        ishtaruser = self.request.user.ishtaruser \ -            if hasattr(self.request.user, 'ishtaruser') else None -        if ishtaruser and ishtaruser.current_profile \ -                and ishtaruser.current_profile.auto_pin: +        ishtaruser = ( +            self.request.user.ishtaruser +            if hasattr(self.request.user, "ishtaruser") +            else None +        ) +        if ( +            ishtaruser +            and ishtaruser.current_profile +            and ishtaruser.current_profile.auto_pin +        ):              self.request.session[self.current_obj_slug] = str(admact.pk) -            self.request.session[self.get_object_name(admact)] = str( -                admact.pk) +            self.request.session[self.get_object_name(admact)] = str(admact.pk) -        res = render(self.request, 'ishtar/wizard/wizard_done.html', dct) +        res = render(self.request, "ishtar/wizard/wizard_done.html", dct)          return res @@ -421,6 +460,7 @@ class OperationEditAdministrativeActWizard(OperationAdministrativeActWizard):      def get_associated_item(self, dct):          return self.get_current_object().operation +  ########  # Site #  ######## @@ -439,110 +479,130 @@ class SiteSearch(SiteLabel, SearchWizard):  class SiteWizard(SiteLabel, Wizard): -    SITE_KEY = 'new' +    SITE_KEY = "new"      model = models.ArchaeologicalSite -    wizard_done_window = reverse_lazy('show-site') +    wizard_done_window = reverse_lazy("show-site")      redirect_url = "site_modification"  class SiteModificationWizard(SiteWizard): -    SITE_KEY = 'modification' +    SITE_KEY = "modification"      modification = True  class SiteDeletionWizard(SiteLabel, MultipleDeletionWizard): -    SITE_KEY = 'deletion' +    SITE_KEY = "deletion"      model = models.ArchaeologicalSite -    fields = models.ArchaeologicalSite.TABLE_COLS + ['operations'] +    fields = models.ArchaeologicalSite.TABLE_COLS + ["operations"]      redirect_url = "site_deletion"  class AdministrativeActDeletionWizard(ClosingWizard):      model = models.AdministrativeAct      wizard_templates = { -        'final-operation_administrativeactop_deletion': -            'ishtar/wizard/wizard_adminact_deletion.html', -        'final-file_administrativeactfile_deletion': -            'ishtar/wizard/wizard_adminact_deletion.html'} -    fields = ['act_type', 'in_charge', 'operator', 'scientist', 'signatory', -              'operation', 'associated_file', 'signature_date', 'act_object'] -    if settings.COUNTRY == 'fr': -        fields += ['ref_sra'] +        "final-operation_administrativeactop_deletion": "ishtar/wizard/wizard_adminact_deletion.html", +        "final-file_administrativeactfile_deletion": "ishtar/wizard/wizard_adminact_deletion.html", +    } +    fields = [ +        "act_type", +        "in_charge", +        "operator", +        "scientist", +        "signatory", +        "operation", +        "associated_file", +        "signature_date", +        "act_object", +    ] +    if settings.COUNTRY == "fr": +        fields += ["ref_sra"]      def done(self, form_list, **kwargs):          obj = self.get_current_object()          obj.delete() -        return render( -            self.request, 'ishtar/wizard/wizard_delete_done.html', {}) +        return render(self.request, "ishtar/wizard/wizard_delete_done.html", {}) -def is_preventive(form_name, model, type_key='operation_type', key=''): +def is_preventive(form_name, model, type_key="operation_type", key=""):      def func(self):          request = self.request          storage = self.storage -        if storage.prefix not in request.session or \ -           'step_data' not in request.session[storage.prefix] or \ -           form_name not in request.session[storage.prefix]['step_data'] or\ -           form_name + '-' + type_key not in \ -           request.session[storage.prefix]['step_data'][form_name]: +        if ( +            storage.prefix not in request.session +            or "step_data" not in request.session[storage.prefix] +            or form_name not in request.session[storage.prefix]["step_data"] +            or form_name + "-" + type_key +            not in request.session[storage.prefix]["step_data"][form_name] +        ):              return False          try: -            typ = request.session[storage.prefix][ -                'step_data'][form_name][form_name + '-' + type_key] +            typ = request.session[storage.prefix]["step_data"][form_name][ +                form_name + "-" + type_key +            ]              if type(typ) in (list, tuple):                  typ = typ[0]              typ = int(typ)              return model.is_preventive(typ, key)          except ValueError:              return False +      return func -def is_not_preventive(form_name, model, type_key='operation_type', key=''): +def is_not_preventive(form_name, model, type_key="operation_type", key=""):      def func(self):          return not is_preventive(form_name, model, type_key, key)(self) +      return func -def is_judiciary(form_name, model, type_key='operation_type'): +def is_judiciary(form_name, model, type_key="operation_type"):      def func(self):          request = self.request          storage = self.storage -        if storage.prefix not in request.session or \ -                'step_data' not in request.session[storage.prefix] or \ -                form_name not in request.session[storage.prefix]['step_data'] \ -                or form_name + '-' + type_key not in \ -                request.session[storage.prefix]['step_data'][form_name]: +        if ( +            storage.prefix not in request.session +            or "step_data" not in request.session[storage.prefix] +            or form_name not in request.session[storage.prefix]["step_data"] +            or form_name + "-" + type_key +            not in request.session[storage.prefix]["step_data"][form_name] +        ):              return False          try: -            typ = request.session[storage.prefix][ -                'step_data'][form_name][form_name + '-' + type_key] +            typ = request.session[storage.prefix]["step_data"][form_name][ +                form_name + "-" + type_key +            ]              if type(typ) in (list, tuple):                  typ = typ[0]              typ = int(typ)              return model.is_judiciary(typ)          except ValueError:              return False +      return func -def has_associated_file(form_name, file_key='associated_file', negate=False): +def has_associated_file(form_name, file_key="associated_file", negate=False):      def func(self):          request = self.request          storage = self.storage -        if storage.prefix not in request.session or \ -           'step_data' not in request.session[storage.prefix] or \ -           form_name not in request.session[storage.prefix]['step_data'] or\ -           form_name + '-' + file_key not in \ -           request.session[storage.prefix]['step_data'][form_name]: +        if ( +            storage.prefix not in request.session +            or "step_data" not in request.session[storage.prefix] +            or form_name not in request.session[storage.prefix]["step_data"] +            or form_name + "-" + file_key +            not in request.session[storage.prefix]["step_data"][form_name] +        ):              return negate          try: -            file_id = request.session[storage.prefix][ -                'step_data'][form_name][form_name + '-' + file_key] +            file_id = request.session[storage.prefix]["step_data"][form_name][ +                form_name + "-" + file_key +            ]              if type(file_id) in (list, tuple):                  file_id = file_id[0]              int(file_id)              return not negate          except ValueError:              return negate +      return func | 
