From d80f1c93294400549d9de07542965d943914e280 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Thu, 26 Sep 2019 22:38:52 +0200 Subject: [PATCH 2/2] mdel: improve code style (#36471) --- passerelle/apps/mdel/mdel.py | 52 +++++++++++++++++++--------------- passerelle/apps/mdel/models.py | 16 +++++++---- passerelle/apps/mdel/utils.py | 11 ++++--- tests/test_mdel.py | 2 +- 4 files changed, 46 insertions(+), 35 deletions(-) diff --git a/passerelle/apps/mdel/mdel.py b/passerelle/apps/mdel/mdel.py index 02bc4ac4..61323e73 100644 --- a/passerelle/apps/mdel/mdel.py +++ b/passerelle/apps/mdel/mdel.py @@ -1,5 +1,6 @@ -# Passerelle - uniform access to data and services -# Copyright (C) 2016 Entr'ouvert +# coding: utf-8 +# passerelle - uniform access to data and services- +# Copyright (C) 2019 Entr'ouvert # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU Affero General Public License as published @@ -14,6 +15,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from __future__ import unicode_literals + import os import base64 import datetime @@ -51,7 +54,6 @@ class AttachedFile(object): class MDELBase(object): - def to_string(self): raw_string = etree.tostring(self.xml, encoding='utf-8') parsed_string = minidom.parseString(raw_string) @@ -247,23 +249,43 @@ class Data(MDELBase): return data + @classmethod + def path_to_xml(cls, path, value, parent): + '''Resolve an XML `path` starting from `parent` and the target node content to `value`.''' + + if isinstance(path, list) and len(path) > 1: + parent_child = parent.find(path[0]) + if parent_child is not None: + element = parent_child + path.pop(0) + else: + element = ElementFactory(path.pop(0)) + element.append(cls.path_to_xml(path, value, element), allow_new=False) + else: + element = ElementFactory(path[0], text=value) + return element + @property def xml(self): - elements = [] + '''Generate an XML document applying values from `self.data` to `self.mapping`''' + # extract text content from data for each path in mapping + elements = [] for key, path in self.mapping: if key in self.data: elements.append((path, self.data[key])) + # recursively create XML nodes using self.path_to_xml() root = ElementFactory(self.root_element, **self.root_attributes) - for path, value in elements: path_splitted = path.split('_') - root.append(json_to_xml(path_splitted, value, root), allow_new=False) + root.append(self.path_to_xml(path_splitted, value, root), allow_new=False) return root + class ILEData(Data): + '''Démarche inscription sur les listes électorales''' mapping = [ ('nom_famille', 'Inscription_Electeur_Noms_NomFamille'), @@ -359,6 +381,7 @@ class ILEData(Data): class AECData(Data): + '''Démarche acte d'état civil''' mapping = [ ('aec_type_raw', 'DemandeActe_TypeActe_Code'), @@ -444,20 +467,3 @@ class AECData(Data): self.root_attributes = {'canal_utilise': '0'} super(AECData, self).__init__(demand_id, data) - - -def json_to_xml(path, value, parent): - - if isinstance(path, list) and len(path) > 1: - parent_child = parent.find(path[0]) - if parent_child is not None: - element = parent_child - path.pop(0) - else: - element = ElementFactory(path.pop(0)) - - element.append(json_to_xml(path, value, element), allow_new=False) - else: - element = ElementFactory(path[0], text=value) - - return element diff --git a/passerelle/apps/mdel/models.py b/passerelle/apps/mdel/models.py index 7ef8a9db..6261dfc5 100644 --- a/passerelle/apps/mdel/models.py +++ b/passerelle/apps/mdel/models.py @@ -1,5 +1,5 @@ -# -*- coding: utf-8 -*- -# Passerelle - uniform access to data and services +# coding: utf-8 +# passerelle - uniform access to data and services # Copyright (C) 2016 Entr'ouvert # # This program is free software: you can redistribute it and/or modify it @@ -15,11 +15,13 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from __future__ import unicode_literals import os import json from django.db import models from django.utils.translation import ugettext_lazy as _ +from django.utils import six from passerelle.base.models import BaseResource from passerelle.utils.api import endpoint @@ -101,7 +103,7 @@ class MDEL(BaseResource): demand_type = formdata.pop('demand_type', '').upper() if demand_type not in DEMAND_TYPES: - raise APIError('demand_type must be : %r' % DEMAND_TYPES) + raise APIError('demand_type must be one of : %s' % ', '.join(DEMAND_TYPES)) if 'display_id' not in formdata: raise APIError('display_id is required') @@ -151,6 +153,7 @@ class MDEL(BaseResource): if item.get('id') not in without.split(',')]} +@six.python_2_unicode_compatible class Demand(models.Model): created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) @@ -162,7 +165,7 @@ class Demand(models.Model): step = models.IntegerField(default=0) demand_id = models.CharField(max_length=128, null=True) - def __unicode__(self): + def __str__(self): return '%s - %s - %s' % (self.resource.slug, self.demand_id, self.status) class Meta: @@ -203,7 +206,10 @@ class Demand(models.Model): for proof_code, proof_attribute in proofs: documents = [value for key, value in formdata.items() - if key.startswith(proof_attribute) and isinstance(value, dict) and 'filename' in value and 'content' in value] + if (key.startswith(proof_attribute) + and isinstance(value, dict) + and 'filename' in value + and 'content' in value)] if not documents: raise APIError('%s and all its attributes are required' % proof_attribute) for document in documents: diff --git a/passerelle/apps/mdel/utils.py b/passerelle/apps/mdel/utils.py index 4fc5589e..ad8b4ed9 100644 --- a/passerelle/apps/mdel/utils.py +++ b/passerelle/apps/mdel/utils.py @@ -1,4 +1,4 @@ -# Passerelle - uniform access to data and services +# passerelle - uniform access to data and services # Copyright (C) 2016 Entr'ouvert # # This program is free software: you can redistribute it and/or modify it @@ -14,6 +14,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from __future__ import unicode_literals + import os import zipfile from xml.etree import ElementTree as etree @@ -22,18 +24,18 @@ from django.utils.dateparse import parse_date as django_parse_date from passerelle.utils.jsonresponse import APIError + def parse_date(date): try: parsed_date = django_parse_date(date) except ValueError as e: - raise APIError('Invalid date: %r (%r)' % ( date, e)) + raise APIError('invalid date: %s (%s)' % (date, e)) if not parsed_date: raise APIError('date %r not iso-formated' % date) return parsed_date.isoformat() class ElementFactory(etree.Element): - def __init__(self, *args, **kwargs): self.text = kwargs.pop('text', None) namespace = kwargs.pop('namespace', None) @@ -46,16 +48,13 @@ class ElementFactory(etree.Element): super(ElementFactory, self).__init__(*args, **kwargs) def append(self, element, allow_new=True): - if not allow_new: if isinstance(element.tag, etree.QName): found = self.find(element.tag.text) else: found = self.find(element.tag) - if found is not None: return self - super(ElementFactory, self).append(element) return self diff --git a/tests/test_mdel.py b/tests/test_mdel.py index c16b64a9..aa0a9f21 100644 --- a/tests/test_mdel.py +++ b/tests/test_mdel.py @@ -109,7 +109,7 @@ def test_invalid_demand_type(app, ile_payload): ILE_PAYLOAD_INVALID = copy.deepcopy(ile_payload) ILE_PAYLOAD_INVALID['extra']['demand_type'] = 'whatever' resp = app.post_json('/mdel/test/create', params=ILE_PAYLOAD_INVALID, status=200) - assert resp.json['err_desc'] == "demand_type must be : ['ILE-LA', 'RCO-LA', 'AEC-LA']" + assert resp.json['err_desc'] == "demand_type must be one of : ILE-LA, RCO-LA, AEC-LA" def test_invalid_demand_no_form_number(app, ile_payload): -- 2.23.0