CrabAdresSchemaNode.validator()   F
last analyzed

Complexity

Conditions 25

Size

Total Lines 99

Duplication

Lines 50
Ratio 50.51 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 25
c 3
b 0
f 0
dl 50
loc 99
rs 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like CrabAdresSchemaNode.validator() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
"""
3
This module validates an address.
4
For an address in Belgium the validation uses the CRAB principles.
5
"""
6
7
import colander
8
from crabpy.gateway.exception import GatewayRuntimeException, GatewayResourceNotFoundException
9
import pycountry
10
from colander import null
11
12
13
def process_straat(adres, straat, gemeente, crab_gateway):
14
    # It is possible to have a street with the same name in one municipality with different postal codes.
15
    # In this case, if postal code is given, determine the correct street crab id by:
16
    # - looking up all possible streets with the same name in the given municipality
17
    # - using the first house number to determine the current postal code and
18
    # - compare it to the given one.
19
    postcode = adres.get('postcode')
20
    if not postcode:
21
        return next((s for s in gemeente.straten if s.label.lower() == straat.lower()), None)
22
    else:
23
        straat_vals = [s for s in gemeente.straten if s.label.lower() == straat.lower()]
24
        straat_val = straat_vals[0] if straat_vals else None
25
        if len(straat_vals) > 1:
26
            for straat_val_x in straat_vals:
27
                reference_id = straat_val_x.huisnummers[0].id if straat_val_x.huisnummers else None
28
                postkanton = crab_gateway.get_postkanton_by_huisnummer(reference_id) if reference_id else None
29
                if postkanton and postcode == str(postkanton.id):
30
                    straat_val = straat_val_x
31
                    break
32
        return straat_val
33
34
35
def process_huisnummer(adres, huisnummer_id, huisnummer, straat_val):
36
    num_val = None
37
    if straat_val:
38
        if huisnummer_id:
39
            num_val = next((n for n in straat_val.huisnummers if n.id == huisnummer_id), None)
40
            if num_val:
41
                adres['huisnummer'] = "" + num_val.huisnummer
42
        if not huisnummer_id and huisnummer:
43
            num_val = next(
44
                (n for n in straat_val.huisnummers if n.huisnummer.lower() == huisnummer.lower()),
45
                None)
46
            if num_val:
47
                adres['huisnummer_id'] = num_val.id
48
    return num_val
49
50
51
def process_subadres(adres, subadres_id, subadres, num_val):
52
    subadres_val = None
53
    if num_val:
54
        if subadres_id:
55
            subadres_val = next((sa for sa in num_val.subadressen if sa.id == subadres_id),
56
                                None)
57
            if subadres_val:
58
                adres['subadres'] = "" + subadres_val.subadres
59
        if not subadres_id and subadres:
60
            subadres_val = next(
61
                (sa for sa in num_val.subadressen if sa.subadres.lower() == subadres.lower()),
62
                None)
63
            if subadres_val:
64
                adres['subadres_id'] = subadres_val.id
65
    return subadres_val
66
67
68
class CrabAdresSchemaNode(colander.MappingSchema):
69
    id = colander.SchemaNode(
70
        colander.Integer(),
71
        missing=None
72
    )
73
74
    straat = colander.SchemaNode(
75
        colander.String(),
76
        validator=colander.Length(1, 100),
77
        missing=None
78
    )
79
80
    straat_id = colander.SchemaNode(
81
        colander.Integer(),
82
        missing=None
83
    )
84
85
    huisnummer = colander.SchemaNode(
86
        colander.String(),
87
        validator=colander.Length(1, 20),
88
        missing=None
89
    )
90
91
    huisnummer_id = colander.SchemaNode(
92
        colander.Integer(),
93
        missing=None
94
    )
95
96
    subadres = colander.SchemaNode(
97
        colander.String(),
98
        validator=colander.Length(1, 20),
99
        missing=None
100
    )
101
102
    subadres_id = colander.SchemaNode(
103
        colander.Integer(),
104
        missing=None
105
    )
106
107
    postcode = colander.SchemaNode(
108
        colander.String(),
109
        validator=colander.Length(1, 20),
110
        missing=None
111
    )
112
113
    gemeente = colander.SchemaNode(
114
        colander.String(),
115
        validator=colander.Length(1, 50),
116
        missing=None
117
    )
118
119
    gemeente_id = colander.SchemaNode(
120
        colander.Integer(),
121
        missing=None
122
    )
123
124
    land = colander.SchemaNode(
125
        colander.String(),
126
        validator=colander.Length(1, 100),
127
        missing='BE'
128
    )
129
130
    def preparer(self, adres):
131
        if adres is None or not adres:
132
            return null  # pragma: no cover
133
        request = self.bindings['request']
134
        crab_gateway = request.crab_gateway()
135
        if 'land' in adres and adres.get('land').upper() == 'BE':
136
            if adres.get('gemeente_id', None) is None:
137
                if adres.get('gemeente', None) is None:
138
                    return None
139
                gemeente = adres.get('gemeente')
140
                gewest_ids = [2, 1, 3]
141
                for gewest_id in gewest_ids:
142
                    gemeenten = crab_gateway.list_gemeenten(gewest_id)
143
                    gemeente_val = next((g for g in gemeenten if g.naam.lower() == gemeente.lower()), None)
144
                    if gemeente_val:
145
                        adres['gemeente'] = "" + gemeente_val.naam
146
                        adres['gemeente_id'] = gemeente_val.id
147
                        break
148
                if adres.get('gemeente_id', None) is None:
149
                    return adres
150
            gemeente_id = adres.get('gemeente_id')
151
            straat_id = adres.get('straat_id', None)
152
            straat = adres.get('straat', None)
153
            huisnummer_id = adres.get('huisnummer_id', None)
154
            huisnummer = adres.get('huisnummer', None)
155
            subadres_id = adres.get('subadres_id', None)
156
            subadres = adres.get('subadres', None)
157
            try:
158
                gemeente = crab_gateway.get_gemeente_by_id(gemeente_id)
159
            except (GatewayRuntimeException, GatewayResourceNotFoundException, AttributeError):
160
                adres['gemeente'] = None
161
                return adres
162
            if gemeente:
163
                adres['gemeente'] = "" + gemeente.naam
164
                if straat_id:
165
                    straat_val = next((s for s in gemeente.straten if s.id == straat_id), None)
166
                    if straat_val:
167
                        adres['straat'] = "" + straat_val.label
168
                        num_val = process_huisnummer(adres, huisnummer_id, huisnummer, straat_val)
169
                        if num_val:
170
                            process_subadres(adres, subadres_id, subadres, num_val)
171
                if not straat_id and straat:
172
                    straat_val = process_straat(adres, straat, gemeente, crab_gateway)
173
                    if straat_val:
174
                        adres['straat_id'] = straat_val.id
175
                        num_val = process_huisnummer(adres, huisnummer_id, huisnummer, straat_val)
176
                        if num_val:
177
                            process_subadres(adres, subadres_id, subadres, num_val)
178
179
        else:
180
            adres['gemeente_id'] = None
181
            adres['straat_id'] = None
182
            adres['huisnummer_id'] = None
183
            adres['subadres_id'] = None
184
        if 'land' in adres:
185
            adres['land'] = adres.get('land').upper()
186
        return adres
187
188
    def validator(self, node, adres):
189
        if not adres:
190
            return
191
        request = self.bindings['request']
192
        crab_gateway = request.crab_gateway()
193
        if 'land' in adres:
194
            land = adres.get('land')
195
            try:
196
                try:
197
                    pycountry.countries.get(alpha2=land)
198
                except KeyError:
199
                    pycountry.countries.get(alpha_2=land)
200
            except KeyError:
201
                raise colander.Invalid(
202
                    node,
203
                    'ongeldige landcode %s, dit is geen ISO 3166 code' %
204
                    land
205
                )
206
            if land == 'BE':
207
                gemeente = adres.get('gemeente', None)
208
                gemeente_id = adres.get('gemeente_id', None)
209
                straat_id = adres.get('straat_id', None)
210
                huisnummer_id = adres.get('huisnummer_id', None)
211
                postcode = adres.get('postcode', None)
212
                subadres_id = adres.get('subadres_id', None)
213
                if gemeente_id is None:
214
                    raise colander.Invalid(
215
                        node,
216
                        'geen correcte gemeente_id gevonden voor de gemeente {0}'.format(gemeente)
217
                    )
218
                if gemeente is None:
219
                    raise colander.Invalid(
220
                        node,
221
                        'ongeldig gemeente_id {0}'.format(gemeente_id)
222
                    )
223 View Code Duplication
                if straat_id is not None:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
224
                    gemeente = crab_gateway.get_gemeente_by_id(gemeente_id)
225
                    try:
226
                        straat = crab_gateway.get_straat_by_id(straat_id)
227
                    except (GatewayRuntimeException, GatewayResourceNotFoundException, AttributeError):
228
                        raise colander.Invalid(
229
                            node,
230
                            'ongeldig straat_id'
231
                        )
232
                    if straat.gemeente_id != gemeente_id:
233
                        raise colander.Invalid(
234
                            node,
235
                            'de straat %s met id %s ligt niet in gemeente %s' %
236
                            (adres.get('straat', ''), straat_id, gemeente.naam)
237
                        )
238
                    if huisnummer_id is not None:
239
                        try:
240
                            huisnummer = crab_gateway.get_huisnummer_by_id(huisnummer_id)
241
                        except (GatewayRuntimeException, GatewayResourceNotFoundException, AttributeError):
242
                            raise colander.Invalid(
243
                                node,
244
                                'ongeldig huisnummer_id'
245
                            )
246
                        if huisnummer.straat_id != straat_id:
247
                            raise colander.Invalid(
248
                                node,
249
                                'het huisnummer %s met id %s ligt niet in straat %s' %
250
                                (adres.get('huisnummer', ''), huisnummer_id, straat.label)
251
                            )
252
                        if postcode is not None:
253
                            postkanton = crab_gateway.get_postkanton_by_huisnummer(huisnummer_id)
254
                            if postcode != str(postkanton.id):
255
                                raise colander.Invalid(
256
                                    node,
257
                                    'postcode %s is niet correct voor dit adres, mogelijke postcode is %s' %
258
                                    (postcode, postkanton.id)
259
                                )
260
                        if subadres_id is not None:
261
                            try:
262
                                subadres = crab_gateway.get_subadres_by_id(subadres_id)
263
                            except (GatewayRuntimeException, GatewayResourceNotFoundException, AttributeError):
264
                                raise colander.Invalid(
265
                                    node,
266
                                    'ongeldig subadres_id'
267
                                )
268
                            if subadres.huisnummer_id != huisnummer_id:
269
                                raise colander.Invalid(
270
                                    node,
271
                                    'het subadres %s met id %s ligt niet op huisnummer %s' %
272
                                    (adres.get('subadres', ''), subadres_id, huisnummer.huisnummer)
273
                                )
274
                if straat_id is None and huisnummer_id is not None:
275
                    raise colander.Invalid(
276
                        node,
277
                        'als er een huisnummer_id wordt gegeven, moet men ook het straat_id invullen'
278
                    )
279
                if huisnummer_id is None and postcode is not None:
280
                    postkantons = crab_gateway.list_postkantons_by_gemeente(gemeente_id)
281
                    postkantons = [str(pk.id) for pk in postkantons]
282
                    if postcode not in postkantons:
283
                        raise colander.Invalid(
284
                            node,
285
                            'postcode %s is niet correct voor dit adres, mogelijke postcode(s) zijn %s' %
286
                            (postcode, postkantons)
287
                        )
288
289