Projet

Général

Profil

0001-toulouse_axel-bool-mapping-38464.patch

Lauréline Guérin, 17 décembre 2019 18:26

Télécharger (7,61 ko)

Voir les différences:

Subject: [PATCH] toulouse_axel: bool mapping (#38464)

 passerelle/contrib/toulouse_axel/models.py |  58 ++++++++++-
 tests/test_toulouse_axel_schema.py         | 111 +++++++++++++++++++++
 2 files changed, 166 insertions(+), 3 deletions(-)
 create mode 100644 tests/test_toulouse_axel_schema.py
passerelle/contrib/toulouse_axel/models.py
43 43
class AxelSchema(JSONSchemaFromXMLSchema):
44 44
    type_map = {
45 45
        '{urn:AllAxelTypes}DATEREQUIREDType': 'date',
46
        '{urn:AllAxelTypes}DATEType': 'date',
46
        '{urn:AllAxelTypes}DATEType': 'date_optional',
47
        '{urn:AllAxelTypes}OUINONREQUIREDType': 'bool',
48
        '{urn:AllAxelTypes}OUINONType': 'bool_optional',
47 49
    }
48 50

  
49 51
    @classmethod
......
54 56
        }
55 57

  
56 58
    def encode_date(self, obj):
57
        return datetime.datetime.strptime(obj, '%Y-%m-%d').strftime('%d/%m/%Y')
59
        try:
60
            return datetime.datetime.strptime(obj, '%Y-%m-%d').strftime('%d/%m/%Y')
61
        except ValueError:
62
            return obj
63

  
64
    def encode_date_optional(self, obj):
65
        if not obj:
66
            return obj
67
        return self.encode_date(obj)
58 68

  
59 69
    def decode_date(self, data):
70
        value = datetime.datetime.strptime(data.text, '%d/%m/%Y').strftime('%Y-%m-%d')
71
        return xmlschema.ElementData(tag=data.tag, text=value, content=data.content, attributes=data.attributes)
72

  
73
    def decode_date_optional(self, data):
60 74
        if not data.text:
61 75
            return data
62
        value = datetime.datetime.strptime(data.text, '%d/%m/%Y').strftime('%Y-%m-%d')
76
        return self.decode_date(data)
77

  
78
    @classmethod
79
    def schema_bool(cls):
80
        return {
81
            'oneOf': [
82
                {'type': 'boolean'},
83
                {
84
                    'type': 'string',
85
                    'pattern': '[Oo][Uu][Ii]|[Nn][Oo][Nn]|[Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee]|1|0',
86
                }
87
            ]
88
        }
89

  
90
    def encode_bool(self, obj):
91
        if obj is True or str(obj).lower() in ['true', 'oui', '1']:
92
            return 'OUI'
93
        if obj is False or str(obj).lower() in ['false', 'non', '0']:
94
            return 'NON'
95
        return obj
96

  
97
    def decode_bool(self, data):
98
        value = False
99
        if data.text.lower() == 'oui':
100
            value = True
63 101
        return xmlschema.ElementData(tag=data.tag, text=value, content=data.content, attributes=data.attributes)
64 102

  
103
    @classmethod
104
    def schema_bool_optional(cls):
105
        schema_bool_optional = cls.schema_bool()
106
        schema_bool_optional['oneOf'].append({'type': 'string', 'enum': ['']})
107
        return schema_bool_optional
108

  
109
    def encode_bool_optional(self, obj):
110
        return self.encode_bool(obj)
111

  
112
    def decode_bool_optional(self, data):
113
        if not data.text:
114
            return data
115
        return self.decode_bool(data)
116

  
65 117

  
66 118
class AxelError(Exception):
67 119
    pass
tests/test_toulouse_axel_schema.py
1
# passerelle - uniform access to multiple data sources and services
2
# Copyright (C) 2019 Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
import os
18

  
19
from passerelle.contrib.toulouse_axel.models import AxelSchema
20

  
21
import pytest
22
import xmlschema
23

  
24
XSD_BASE_DIR = os.path.join(
25
    os.path.dirname(os.path.abspath(__file__)),
26
    '../passerelle/contrib/toulouse_axel/xsd')
27

  
28

  
29
@pytest.mark.parametrize('date_type', ['DATEREQUIREDType', 'DATEType'])
30
def test_date_mapping(date_type):
31
    xsd = """<?xml version="1.0" encoding="utf-8" ?>
32
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:all="urn:AllAxelTypes">
33
    <xsd:import schemaLocation="{path}/AllAxelTypes.xsd" namespace="urn:AllAxelTypes"  />
34
    <xsd:complexType name="PORTAILType">
35
        <xsd:sequence>
36
            <xsd:element name="DATE" type="all:{date_type}"/>
37
        </xsd:sequence>
38
    </xsd:complexType>
39
    <xsd:element name="PORTAIL" type="PORTAILType"/>
40
</xsd:schema>""".format(path=XSD_BASE_DIR, date_type=date_type)
41

  
42
    schema = AxelSchema(xsd, 'PORTAIL')
43
    xml_data = schema.encode({'PORTAIL': {'DATE': '2019-12-12'}})
44
    assert xml_data.find('DATE').text == '12/12/2019'
45

  
46
    json_data = schema.decode(xml_data)
47
    assert json_data['DATE'] == '2019-12-12'
48

  
49
    xml_data = schema.encode({'PORTAIL': {'DATE': 'foobar'}})
50
    assert xml_data.find('DATE').text == 'foobar'
51

  
52
    with pytest.raises(xmlschema.XMLSchemaValidationError):
53
        schema.decode(xml_data)
54

  
55
    if date_type == 'DATEType':
56
        xml_data = schema.encode({'PORTAIL': {'DATE': ''}})
57
        assert xml_data.find('DATE').text == ''
58

  
59
        json_data = schema.decode(xml_data)
60
        assert json_data['DATE'] is None
61

  
62

  
63
@pytest.mark.parametrize('bool_type', ['OUINONREQUIREDType', 'OUINONType'])
64
@pytest.mark.parametrize('value, expected, py_expected', [
65
    ('OUI', 'OUI', True),
66
    ('oui', 'OUI', True),
67
    ('Oui', 'OUI', True),
68
    ('TRUE', 'OUI', True),
69
    ('true', 'OUI', True),
70
    ('True', 'OUI', True),
71
    (True, 'OUI', True),
72
    ('1', 'OUI', True),
73
    ('NON', 'NON', False),
74
    ('non', 'NON', False),
75
    ('Non', 'NON', False),
76
    ('FALSE', 'NON', False),
77
    ('false', 'NON', False),
78
    ('False', 'NON', False),
79
    (False, 'NON', False),
80
    ('0', 'NON', False),
81
    ('FOOBAR', 'FOOBAR', None),
82
    ('42', '42', None),
83
    ('OUIFOOBAR', 'OUIFOOBAR', None),
84
    ('FOONONBAR', 'FOONONBAR', None),
85
])
86
def test_bool_mapping(bool_type, value, expected, py_expected):
87
    if expected == '' and bool_type == 'OUINONREQUIREDType':
88
        # required, can't be empty
89
        return
90

  
91
    xsd = """<?xml version="1.0" encoding="utf-8" ?>
92
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:all="urn:AllAxelTypes">
93
    <xsd:import schemaLocation="{path}/AllAxelTypes.xsd" namespace="urn:AllAxelTypes"  />
94
    <xsd:complexType name="PORTAILType">
95
        <xsd:sequence>
96
            <xsd:element name="BOOL" type="all:{bool_type}"/>
97
        </xsd:sequence>
98
    </xsd:complexType>
99
    <xsd:element name="PORTAIL" type="PORTAILType"/>
100
</xsd:schema>""".format(path=XSD_BASE_DIR, bool_type=bool_type)
101

  
102
    schema = AxelSchema(xsd, 'PORTAIL')
103
    xml_data = schema.encode({'PORTAIL': {'BOOL': value}})
104
    assert xml_data.find('BOOL').text == expected
105

  
106
    if py_expected is None:
107
        with pytest.raises(xmlschema.XMLSchemaValidationError):
108
            schema.decode(xml_data)
109
    else:
110
        json_data = schema.decode(xml_data)
111
        assert json_data['BOOL'] is py_expected
0
-