Completed
Push — master ( 49e956...6a4f63 )
by Koen
13s
created

CapakeyRestGateway.creator()   D

Complexity

Conditions 1

Size

Total Lines 10

Duplication

Lines 1
Ratio 10 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
cc 1
c 3
b 0
f 1
dl 1
loc 10
rs 4.8292
1
# -*- coding: utf-8 -*-
2
'''
3
This module contains an opionated gateway for the capakey webservice.
4
5
.. versionadded:: 0.2.0
6
'''
7
8
from __future__ import unicode_literals
9
import six
10
11
import logging
12
log = logging.getLogger(__name__)
13
14
from crabpy.client import capakey_request
15
16
from suds import WebFault
17
18
from crabpy.gateway.exception import (
19
    GatewayRuntimeException,
20
    GatewayAuthenticationException,
21
    GatewayResourceNotFoundException
22
)
23
24
from dogpile.cache import make_region
25
26
import requests
27
from zope.deprecation import deprecate
28
import warnings
29
warnings.simplefilter('always', DeprecationWarning)
30
logging.captureWarnings(True)
31
32
DEPRECATIONWARNING = 'CapakeyGateway{0} (SOAP) is deprecated, use CapakeyRestGateway{0} (REST) instead.'
33
34
35
def capakey_gateway_request(client, method, *args):
36
    '''
37
    Utility function that helps making requests to the CAPAKEY service.
38
39
    This is a specialised version of :func:`crabpy.client.capakey_request` that
40
    allows adding extra functionality like general error handling for the
41
    calls made by the gateway.
42
43
    :param client: A :class:`suds.client.Client` for the CAPAKEY service.
44
    :param string action: Which method to call, eg. `ListAdmGemeenten`.
45
    :returns: Result of the SOAP call.
46
    '''
47
    try:
48
        return capakey_request(client, method, *args)
49
    except WebFault as wf:
50
        if wf.fault['faultcode'] == 'q0:FailedAuthentication':
51
            err = GatewayAuthenticationException(
52
                'Could not authenticate with capakey service. Message from server:\n%s' % wf.fault['faultstring'],
53
                wf
54
            )
55
        else:
56
            err = GatewayRuntimeException(
57
                'Could not execute request. Message from server:\n%s' % wf.fault['faultstring'],
58
                wf
59
            )
60
        raise err
61
62
63
class CapakeyGateway(object):
64
    '''
65
    A gateway to the capakey webservice.
66
    '''
67
68
    caches = {}
69
70
    @deprecate(DEPRECATIONWARNING.format(''))
71
    def __init__(self, client, **kwargs):
72
        self.client = client
73
        cache_regions = ['permanent', 'long', 'short']
74
        for cr in cache_regions:
75
            self.caches[cr] = make_region(key_mangler=str)
76
        if 'cache_config' in kwargs:
77
            for cr in cache_regions:
78
                if ('%s.backend' % cr) in kwargs['cache_config']:
79
                    log.debug('Configuring %s region on CapakeyGateway', cr)
80
                    self.caches[cr].configure_from_config(
81
                        kwargs['cache_config'],
82
                        '%s.' % cr
83
                    )
84
85
    @deprecate(DEPRECATIONWARNING.format('.list_gemeenten'))
86
    def list_gemeenten(self, sort=1):
87
        '''
88
        List all `gemeenten` in Vlaanderen.
89
90
        :param integer sort: What field to sort on.
91
        :rtype: A :class:`list` of :class:`Gemeente`.
92
        '''
93
        def creator():
94
            res = capakey_gateway_request(
95
                self.client, 'ListAdmGemeenten', sort
96
            )
97
            return [
98
                Gemeente(r.Niscode, r.AdmGemeentenaam)
99
                for r in res.AdmGemeenteItem
100
            ]
101
        if self.caches['permanent'].is_configured:
102
            key = 'ListAdmGemeenten#%s' % sort
103
            gemeente = self.caches['permanent'].get_or_create(key, creator)
104
        else:
105
            gemeente = creator()
106
        for g in gemeente:
107
            g.set_gateway(self)
108
        return gemeente
109
110 View Code Duplication
    @deprecate(DEPRECATIONWARNING.format('.get_gemeente_by_id'))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
111
    def get_gemeente_by_id(self, id):
112
        '''
113
        Retrieve a `gemeente` by id (the NIScode).
114
115
        :rtype: :class:`Gemeente`
116
        '''
117
        def creator():
118
            try:
119
                res = capakey_gateway_request(
120
                    self.client, 'GetAdmGemeenteByNiscode', id
121
                )
122
            except GatewayRuntimeException:
123
                raise GatewayResourceNotFoundException()
124
            return Gemeente(
125
                res.Niscode,
126
                res.AdmGemeentenaam,
127
                (res.CenterX, res.CenterY),
128
                (res.MinimumX, res.MinimumY, res.MaximumX, res.MaximumY)
129
            )
130
        if self.caches['long'].is_configured:
131
            key = 'GetAdmGemeenteByNiscode#%s' % id
132
            gemeente = self.caches['long'].get_or_create(key, creator)
133
        else:
134
            gemeente = creator()
135
        gemeente.set_gateway(self)
136
        return gemeente
137
138
    @deprecate(DEPRECATIONWARNING.format('.list_kadastrale_afdelingen'))
139
    def list_kadastrale_afdelingen(self, sort=1):
140
        '''
141
        List all `kadastrale afdelingen` in Flanders.
142
143
        :param integer sort: Field to sort on.
144
        :rtype: A :class:`list` of :class:`Afdeling`.
145
        '''
146
        def creator():
147
            res = capakey_gateway_request(
148
                self.client, 'ListKadAfdelingen', sort
149
            )
150
            return [
151
                Afdeling(
152
                    id=r.KadAfdelingcode,
153
                    naam=r.KadAfdelingnaam,
154
                    gemeente=Gemeente(r.Niscode)
155
                ) for r in res.KadAfdelingItem]
156
        if self.caches['permanent'].is_configured:
157
            key = 'ListKadAfdelingen#%s' % sort
158
            afdelingen = self.caches['permanent'].get_or_create(key, creator)
159
        else:
160
            afdelingen = creator()
161
        for a in afdelingen:
162
            a.set_gateway(self)
163
        return afdelingen
164
165
    @deprecate(DEPRECATIONWARNING.format('.list_kadastrale_afdelingen_by_gemeente'))
166
    def list_kadastrale_afdelingen_by_gemeente(self, gemeente, sort=1):
167
        '''
168
        List all `kadastrale afdelingen` in a `gemeente`.
169
170
        :param gemeente: The :class:`Gemeente` for which the \
171
            `afdelingen` are wanted.
172
        :param integer sort: Field to sort on.
173
        :rtype: A :class:`list` of :class:`Afdeling`.
174
        '''
175
        try:
176
            gid = gemeente.id
177
        except AttributeError:
178
            gid = gemeente
179
            gemeente = self.get_gemeente_by_id(gid)
180
        gemeente.clear_gateway()
181
182
        def creator():
183
            res = capakey_gateway_request(
184
                self.client, 'ListKadAfdelingenByNiscode', gid, sort
185
            )
186
            try:
187
                return [
188
                    Afdeling(
189
                        id=r.KadAfdelingcode,
190
                        naam=r.KadAfdelingnaam,
191
                        gemeente=gemeente
192
                    ) for r in res.KadAfdelingItem]
193
            except AttributeError:
194
                # Handle bad error handling on the CAPAKEY side
195
                return []
196
        if self.caches['permanent'].is_configured:
197
            key = 'ListKadAfdelingenByNiscode#%s#%s' % (gid, sort)
198
            afdelingen = self.caches['permanent'].get_or_create(key, creator)
199
        else:
200
            afdelingen = creator()
201
        for a in afdelingen:
202
            a.set_gateway(self)
203
        return afdelingen
204
205
    @deprecate(DEPRECATIONWARNING.format('.get_kadastrale_afdeling_by_id'))
206
    def get_kadastrale_afdeling_by_id(self, id):
207
        '''
208
        Retrieve a 'kadastrale afdeling' by id.
209
210
        :param id: An id of a `kadastrale afdeling`.
211
        :rtype: A :class:`Afdeling`.
212
        '''
213
        def creator():
214
            try:
215
                res = capakey_gateway_request(
216
                    self.client, 'GetKadAfdelingByKadAfdelingcode', id
217
                )
218
            except GatewayRuntimeException:
219
                raise GatewayResourceNotFoundException()
220
            return Afdeling(
221
                id=res.KadAfdelingcode,
222
                naam=res.KadAfdelingnaam,
223
                gemeente=Gemeente(res.Niscode, res.AdmGemeentenaam),
224
                centroid=(res.CenterX, res.CenterY),
225
                bounding_box=(
226
                    res.MinimumX, res.MinimumY, res.MaximumX, res.MaximumY
227
                )
228
            )
229
        if self.caches['long'].is_configured:
230
            key = 'GetKadAfdelingByKadAfdelingcode#%s' % id
231
            afdeling = self.caches['long'].get_or_create(key, creator)
232
        else:
233
            afdeling = creator()
234
        afdeling.set_gateway(self)
235
        return afdeling
236
237 View Code Duplication
    @deprecate(DEPRECATIONWARNING.format('.list_secties_by_afdeling'))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
238
    def list_secties_by_afdeling(self, afdeling):
239
        '''
240
        List all `secties` in a `kadastrale afdeling`.
241
242
        :param afdeling: The :class:`Afdeling` for which the `secties` are \
243
            wanted. Can also be the id of and `afdeling`.
244
        :rtype: A :class:`list` of `Sectie`.
245
        '''
246
        try:
247
            aid = afdeling.id
248
        except AttributeError:
249
            aid = afdeling
250
            afdeling = self.get_kadastrale_afdeling_by_id(aid)
251
        afdeling.clear_gateway()
252
253
        def creator():
254
            res = capakey_gateway_request(
255
                self.client, 'ListKadSectiesByKadAfdelingcode', aid
256
            )
257
            try:
258
                return [
259
                    Sectie(
260
                        r.KadSectiecode,
261
                        afdeling
262
                    ) for r in res.KadSectieItem
263
                ]
264
            except AttributeError:
265
                # Handle bad error handling on the CAPAKEY side
266
                return []
267
        if self.caches['long'].is_configured:
268
            key = 'ListKadSectiesByKadAfdelingcode#%s' % aid
269
            secties = self.caches['long'].get_or_create(key, creator)
270
        else:
271
            secties = creator()
272
        for s in secties:
273
            s.set_gateway(self)
274
        return secties
275
276
    @deprecate(DEPRECATIONWARNING.format('.get_sectie_by_id_and_afdeling'))
277
    def get_sectie_by_id_and_afdeling(self, id, afdeling):
278
        '''
279
        Get a `sectie`.
280
281
        :param id: An id of a sectie. eg. "A"
282
        :param afdeling: The :class:`Afdeling` for in which the `sectie` can \
283
            be found. Can also be the id of and `afdeling`.
284
        :rtype: A :class:`Sectie`.
285
        '''
286
        try:
287
            aid = afdeling.id
288
        except AttributeError:
289
            aid = afdeling
290
            afdeling = self.get_kadastrale_afdeling_by_id(aid)
291
        afdeling.clear_gateway()
292
293
        def creator():
294
            try:
295
                res = capakey_gateway_request(
296
                    self.client, 'GetKadSectieByKadSectiecode', aid, id
297
                )
298
            except GatewayRuntimeException:
299
                raise GatewayResourceNotFoundException()
300
            return Sectie(
301
                res.KadSectiecode,
302
                afdeling,
303
                (res.CenterX, res.CenterY),
304
                (res.MinimumX, res.MinimumY, res.MaximumX, res.MaximumY),
305
            )
306
        if self.caches['long'].is_configured:
307
            key = 'GetKadSectieByKadSectiecode#%s#%s' % (aid, id)
308
            sectie = self.caches['long'].get_or_create(key, creator)
309
        else:
310
            sectie = creator()
311
        sectie.set_gateway(self)
312
        return sectie
313
314
    @deprecate(DEPRECATIONWARNING.format('.list_percelen_by_sectie'))
315
    def list_percelen_by_sectie(self, sectie, sort=1):
316
        '''
317
        List all percelen in a `sectie`.
318
319
        :param sectie: The :class:`Sectie` for which the percelen are wanted.
320
        :param integer sort: Field to sort on.
321
        :rtype: A :class:`list` of :class:`Perceel`.
322
        '''
323
        sectie.clear_gateway()
324
325
        def creator():
326
            res = capakey_gateway_request(
327
                self.client, 'ListKadPerceelsnummersByKadSectiecode',
328
                sectie.afdeling.id, sectie.id, sort
329
            )
330
            try:
331
                return [
332
                    Perceel(
333
                        r.KadPerceelsnummer,
334
                        sectie,
335
                        r.CaPaKey,
336
                        r.PERCID,
337
                    ) for r in res.KadPerceelsnummerItem
338
                ]
339
            except AttributeError:
340
                # Handle bad error handling on the CAPAKEY side
341
                return []
342
        if self.caches['short'].is_configured:
343
            key = 'ListKadPerceelsnummersByKadSectiecode#%s#%s#%s' % (sectie.afdeling.id, sectie.id, sort)
344
            percelen = self.caches['short'].get_or_create(key, creator)
345
        else:
346
            percelen = creator()
347
        for p in percelen:
348
            p.set_gateway(self)
349
        return percelen
350
351 View Code Duplication
    @deprecate(DEPRECATIONWARNING.format('.get_perceel_by_id_and_sectie'))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
352
    def get_perceel_by_id_and_sectie(self, id, sectie):
353
        '''
354
        Get a `perceel`.
355
356
        :param id: An id for a `perceel`.
357
        :param sectie: The :class:`Sectie` that contains the perceel.
358
        :rtype: :class:`Perceel`
359
        '''
360
        sectie.clear_gateway()
361
362
        def creator():
363
            try:
364
                res = capakey_gateway_request(
365
                    self.client, 'GetKadPerceelsnummerByKadPerceelsnummer',
366
                    sectie.afdeling.id, sectie.id, id
367
                )
368
            except GatewayRuntimeException:
369
                raise GatewayResourceNotFoundException()
370
            return Perceel(
371
                res.KadPerceelsnummer,
372
                sectie,
373
                res.CaPaKey,
374
                res.PERCID,
375
                res.CaPaTy,
376
                res.CaShKey,
377
                (res.CenterX, res.CenterY),
378
                (res.MinimumX, res.MinimumY, res.MaximumX, res.MaximumY)
379
            )
380
        if self.caches['short'].is_configured:
381
            key = 'GetKadPerceelsnummerByKadPerceelsnummer#%s#%s#%s' % (sectie.afdeling.id, sectie.id, id)
382
            perceel = self.caches['short'].get_or_create(key, creator)
383
        else:
384
            perceel = creator()
385
        perceel.set_gateway(self)
386
        return perceel
387
388 View Code Duplication
    @deprecate(DEPRECATIONWARNING.format('.get_perceel_by_capakey'))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
389
    def get_perceel_by_capakey(self, capakey):
390
        '''
391
        Get a `perceel`.
392
393
        :param capakey: An capakey for a `perceel`.
394
        :rtype: :class:`Perceel`
395
        '''
396
        def creator():
397
            try:
398
                res = capakey_gateway_request(
399
                    self.client, 'GetKadPerceelsnummerByCaPaKey', capakey
400
                )
401
            except GatewayRuntimeException:
402
                raise GatewayResourceNotFoundException()
403
            return Perceel(
404
                res.KadPerceelsnummer,
405
                Sectie(res.KadSectiecode, Afdeling(res.KadAfdelingcode)),
406
                res.CaPaKey,
407
                res.PERCID,
408
                res.CaPaTy,
409
                res.CaShKey,
410
                (res.CenterX, res.CenterY),
411
                (res.MinimumX, res.MinimumY, res.MaximumX, res.MaximumY)
412
            )
413
        if self.caches['short'].is_configured:
414
            key = 'GetKadPerceelsnummerByCaPaKey#%s' % capakey
415
            perceel = self.caches['short'].get_or_create(key, creator)
416
        else:
417
            perceel = creator()
418
        perceel.set_gateway(self)
419
        return perceel
420
421 View Code Duplication
    @deprecate(DEPRECATIONWARNING.format('.get_perceel_by_percid'))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
422
    def get_perceel_by_percid(self, percid):
423
        '''
424
        Get a `perceel`.
425
426
        :param percid: A percid for a `perceel`.
427
        :rtype: :class:`Perceel`
428
        '''
429
        def creator():
430
            try:
431
                res = capakey_gateway_request(
432
                    self.client, 'GetKadPerceelsnummerByPERCID', percid
433
                )
434
            except GatewayRuntimeException:
435
                raise GatewayResourceNotFoundException()
436
            return Perceel(
437
                res.KadPerceelsnummer,
438
                Sectie(res.KadSectiecode, Afdeling(res.KadAfdelingcode)),
439
                res.CaPaKey,
440
                res.PERCID,
441
                res.CaPaTy,
442
                res.CaShKey,
443
                (res.CenterX, res.CenterY),
444
                (res.MinimumX, res.MinimumY, res.MaximumX, res.MaximumY)
445
            )
446
        if self.caches['short'].is_configured:
447
            key = 'GetKadPerceelsnummerByPERCID#%s' % percid
448
            perceel = self.caches['short'].get_or_create(key, creator)
449
        else:
450
            perceel = creator()
451
        perceel.set_gateway(self)
452
        return perceel
453
454
455
def capakey_rest_gateway_request(url, headers={}, params={}):
456
    try:
457
        res = requests.get(url, headers=headers, params=params)
458
        res.raise_for_status()
459
        return res
460
    except requests.ConnectionError as ce:
461
        raise GatewayRuntimeException(
462
            'Could not execute request due to connection problems:\n%s' % repr(ce),
463
            ce
464
        )
465
    except requests.HTTPError as he:
466
        raise GatewayResourceNotFoundException()
467
    except requests.RequestException as re:
468
        raise GatewayRuntimeException(
469
            'Could not execute request due to:\n%s' % repr(re),
470
            re
471
        )
472
473
474
class CapakeyRestGateway(object):
475
    '''
476
    A REST gateway to the capakey webservice.
477
    '''
478
479
    caches = {}
480
481
    def __init__(self, **kwargs):
482
        self.base_url = kwargs.get(
483 View Code Duplication
            'base_url',
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
484
            'https://geoservices.informatievlaanderen.be/capakey/api/v0.1'
485
        )
486
        self.base_headers = {
487
            'Accept': 'application/json'
488
        }
489
        cache_regions = ['permanent', 'long', 'short']
490
        for cr in cache_regions:
491
            self.caches[cr] = make_region(key_mangler=str)
492
        if 'cache_config' in kwargs:
493
            for cr in cache_regions:
494
                if ('%s.backend' % cr) in kwargs['cache_config']:
495
                    log.debug('Configuring %s region on CapakeyRestGateway', cr)
496
                    self.caches[cr].configure_from_config(
497
                        kwargs['cache_config'],
498
                        '%s.' % cr
499
                    )
500
501
    def list_gemeenten(self, sort=1):
502
        '''
503
        List all `gemeenten` in Vlaanderen.
504
505
        :param integer sort: What field to sort on.
506
        :rtype: A :class:`list` of :class:`Gemeente`.
507
        '''
508
        def creator():
509
            url = self.base_url + '/municipality'
510
            h = self.base_headers
511
            p = {
512
                'orderbyCode': sort == 1
513
            }
514
            res = capakey_rest_gateway_request(url, h, p).json()
515
            return [
516
                Gemeente(r['municipalityCode'], r['municipalityName'])
517
                for r in res['municipalities']
518
            ]
519
        if self.caches['permanent'].is_configured:
520
            key = 'list_gemeenten_rest#%s' % sort
521
            gemeente = self.caches['permanent'].get_or_create(key, creator)
522
        else:
523
            gemeente = creator()
524
        for g in gemeente:
525
            g.set_gateway(self)
526
        return gemeente
527
528
    def get_gemeente_by_id(self, id):
529
        '''
530
        Retrieve a `gemeente` by id (the NIScode).
531
532
        :rtype: :class:`Gemeente`
533
        '''
534
        def creator():
535
            url = self.base_url + '/municipality/%s' % id
536
            h = self.base_headers
537
            p = {
538
                'geometry': 'bbox',
539
                'srs': '31370'
540
            }
541
            res = capakey_rest_gateway_request(url, h, p).json()
542
            return Gemeente(
543
                res['municipalityCode'],
544
                res['municipalityName'],
545
                res['geometry']['center'],
546
                res['geometry']['boundingBox']
547
            )
548
        if self.caches['long'].is_configured:
549
            key = 'get_gemeente_by_id_rest#%s' % id
550
            gemeente = self.caches['long'].get_or_create(key, creator)
551
        else:
552
            gemeente = creator()
553
        gemeente.set_gateway(self)
554
        return gemeente
555
556
    def list_kadastrale_afdelingen(self):
557
        '''
558
        List all `kadastrale afdelingen` in Flanders.
559
560
        :param integer sort: Field to sort on.
561
        :rtype: A :class:`list` of :class:`Afdeling`.
562
        '''
563
        def creator():
564
            gemeentes = self.list_gemeenten()
565
            res = []
566
            for g in gemeentes:
567
                res += self.list_kadastrale_afdelingen_by_gemeente(g)
568
            return res
569
        if self.caches['permanent'].is_configured:
570
            key = 'list_afdelingen_rest'
571
            afdelingen = self.caches['permanent'].get_or_create(key, creator)
572
        else:
573
            afdelingen = creator()
574
        return afdelingen
575
576
    def list_kadastrale_afdelingen_by_gemeente(self, gemeente, sort=1):
577
        '''
578
        List all `kadastrale afdelingen` in a `gemeente`.
579
580
        :param gemeente: The :class:`Gemeente` for which the \
581
            `afdelingen` are wanted.
582
        :param integer sort: Field to sort on.
583
        :rtype: A :class:`list` of :class:`Afdeling`.
584
        '''
585
        try:
586
            gid = gemeente.id
587
        except AttributeError:
588
            gid = gemeente
589
            gemeente = self.get_gemeente_by_id(gid)
590
        gemeente.clear_gateway()
591
592
        def creator():
593
            url = self.base_url + '/municipality/%s/department' % gid
594
            h = self.base_headers
595
            p = {
596
                'orderbyCode': sort == 1
597
            }
598
            res = capakey_rest_gateway_request(url, h, p).json()
599
            return [
600
                Afdeling(
601
                    id=r['departmentCode'],
602
                    naam=r['departmentName'],
603
                    gemeente=gemeente
604
                ) for r in res['departments']]
605
        if self.caches['permanent'].is_configured:
606
            key = 'list_kadastrale_afdelingen_by_gemeente_rest#%s#%s' % (gid, sort)
607
            afdelingen = self.caches['permanent'].get_or_create(key, creator)
608
        else:
609
            afdelingen = creator()
610
        for a in afdelingen:
611
            a.set_gateway(self)
612
        return afdelingen
613
614
    def get_kadastrale_afdeling_by_id(self, aid):
615
        '''
616
        Retrieve a 'kadastrale afdeling' by id.
617
618
        :param aid: An id of a `kadastrale afdeling`.
619
        :rtype: A :class:`Afdeling`.
620
        '''
621
        def creator():
622
            url = self.base_url + '/department/%s' % (aid)
623
            h = self.base_headers
624
            p = {
625
                'geometry': 'bbox',
626
                'srs': '31370'
627
            }
628
            res = capakey_rest_gateway_request(url, h, p).json()
629
            return Afdeling(
630
                id=res['departmentCode'],
631
                naam=res['departmentName'],
632
                gemeente=Gemeente(res['municipalityCode'], res['municipalityName']),
633
                centroid=res['geometry']['center'],
634
                bounding_box=res['geometry']['boundingBox']
635
            )
636
        if self.caches['long'].is_configured:
637
            key = 'get_kadastrale_afdeling_by_id_rest#%s' % aid
638
            afdeling = self.caches['long'].get_or_create(key, creator)
639
        else:
640
            afdeling = creator()
641
        afdeling.set_gateway(self)
642
        return afdeling
643
644
    def list_secties_by_afdeling(self, afdeling):
645
        '''
646
        List all `secties` in a `kadastrale afdeling`.
647
648
        :param afdeling: The :class:`Afdeling` for which the `secties` are \
649
            wanted. Can also be the id of and `afdeling`.
650
        :rtype: A :class:`list` of `Sectie`.
651
        '''
652
        try:
653
            aid = afdeling.id
654
            gid = afdeling.gemeente.id
655
        except AttributeError:
656
            aid = afdeling
657
            afdeling = self.get_kadastrale_afdeling_by_id(aid)
658
            gid = afdeling.gemeente.id
659
        afdeling.clear_gateway()
660
661
        def creator():
662 View Code Duplication
            url = self.base_url + '/municipality/%s/department/%s/section' % (gid, aid)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
663
            h = self.base_headers
664
            res = capakey_rest_gateway_request(url, h).json()
665
            return [
666
                Sectie(
667
                    r['sectionCode'],
668
                    afdeling
669
                ) for r in res['sections']
670
            ]
671
        if self.caches['long'].is_configured:
672
            key = 'list_secties_by_afdeling_rest#%s' % aid
673
            secties = self.caches['long'].get_or_create(key, creator)
674
        else:
675
            secties = creator()
676
        for s in secties:
677
            s.set_gateway(self)
678
        return secties
679
680
    def get_sectie_by_id_and_afdeling(self, id, afdeling):
681
        '''
682
        Get a `sectie`.
683
684
        :param id: An id of a sectie. eg. "A"
685
        :param afdeling: The :class:`Afdeling` for in which the `sectie` can \
686
            be found. Can also be the id of and `afdeling`.
687
        :rtype: A :class:`Sectie`.
688
        '''
689
        try:
690
            aid = afdeling.id
691
        except AttributeError:
692
            aid = afdeling
693
            afdeling = self.get_kadastrale_afdeling_by_id(aid)
694
        afdeling.clear_gateway()
695
696
        def creator():
697
            url = self.base_url + '/municipality/%s/department/%s/section/%s' % (afdeling.gemeente.id, afdeling.id, id)
698
            h = self.base_headers
699
            p = {
700
                'geometry': 'bbox',
701
                'srs': '31370'
702
            }
703
            res = capakey_rest_gateway_request(url, h, p).json()
704
            return Sectie(
705
                res['sectionCode'],
706
                afdeling,
707
                res['geometry']['center'],
708
                res['geometry']['boundingBox'],
709
            )
710
        if self.caches['long'].is_configured:
711
            key = 'get_sectie_by_id_and_afdeling_rest#%s#%s' % (id, aid)
712
            sectie = self.caches['long'].get_or_create(key, creator)
713
        else:
714
            sectie = creator()
715
        sectie.set_gateway(self)
716
        return sectie
717
718
    def parse_percid(self, capakey):
719
        import re
720
        match = re.match(
721
            r"^([0-9]{5})([A-Z]{1})([0-9]{4})\/([0-9]{2})([A-Z\_]{1})([0-9]{3})$",
722
            capakey
723
        )
724
        if match:
725
            percid = match.group(1) + '_' + match.group(2) +\
726
                '_' + match.group(3) + '_' + match.group(5) + '_' +\
727
                match.group(6) + '_' + match.group(4)
728
            return percid
729
        else:
730
            raise ValueError(
731
                "Invalid Capakey %s can't be parsed" % capakey
732 View Code Duplication
            )
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
733
734
    def parse_capakey(self, percid):
735
        import re
736
        match = re.match(
737
            r"^([0-9]{5})_([A-Z]{1})_([0-9]{4})_([A-Z\_]{1})_([0-9]{3})_([0-9]{2})$",
738
            percid
739
        )
740
        if match:
741
            capakey = match.group(1) + match.group(2) +\
742
                match.group(3) + '/' + match.group(5) + '_' +\
743
                match.group(6) + '_' + match.group(4)
744
            return capakey
745
        else:
746
            raise ValueError(
747
                "Invalid percid %s can't be parsed" % percid
748
            )
749
750
    def list_percelen_by_sectie(self, sectie):
751
        '''
752
        List all percelen in a `sectie`.
753
754
        :param sectie: The :class:`Sectie` for which the percelen are wanted.
755
        :param integer sort: Field to sort on.
756
        :rtype: A :class:`list` of :class:`Perceel`.
757
        '''
758
        sid = sectie.id
759
        aid = sectie.afdeling.id
760
        gid = sectie.afdeling.gemeente.id
761
        sectie.clear_gateway()
762
        def creator():
763
            url = self.base_url + '/municipality/%s/department/%s/section/%s/parcel' % (gid, aid, sid)
764
            h = self.base_headers
765
            p = {
766
                'data': 'cadmap'
767
            }
768
            res = capakey_rest_gateway_request(url, h, p).json()
769
            return [
770
                Perceel(
771
                    r['perceelnummer'],
772
                    sectie,
773
                    r['capakey'],
774
                    self.parse_percid(r['capakey']),
775
                ) for r in res['parcels']
776
            ]
777
        if self.caches['short'].is_configured:
778
            key = 'list_percelen_by_sectie_rest#%s#%s#%s' % (gid, aid, sid)
779
            percelen = self.caches['short'].get_or_create(key, creator)
780
        else:
781
            percelen = creator()
782
        for p in percelen:
783
            p.set_gateway(self)
784
        return percelen
785
786
    def get_perceel_by_id_and_sectie(self, id, sectie):
787
        '''
788
        Get a `perceel`.
789
790
        :param id: An id for a `perceel`.
791
        :param sectie: The :class:`Sectie` that contains the perceel.
792
        :rtype: :class:`Perceel`
793
        '''
794
        sid = sectie.id
795
        aid = sectie.afdeling.id
796
        gid = sectie.afdeling.gemeente.id
797
        sectie.clear_gateway()
798
        def creator():
799
            url = self.base_url + '/municipality/%s/department/%s/section/%s/parcel/%s' % (gid, aid, sid, id)
800
            h = self.base_headers
801
            p = {
802
                'geometry': 'bbox',
803
                'srs': '31370',
804
                'data': 'cadmap'
805
            }
806
            res = capakey_rest_gateway_request(url, p, h).json()
807
            return Perceel(
808
                res['perceelnummer'],
809
                sectie,
810
                res['capakey'],
811
                Perceel.get_percid_from_capakey(res['capakey']),
812
                None,
813
                None,
814
                res['geometry']['center'],
815
                res['geometry']['boundingBox']
816
            )
817
        if self.caches['short'].is_configured:
818
            key = 'get_perceel_by_id_and_sectie_rest#%s#%s#%s' % (id, sectie.id, sectie.afdeling.id)
819
            perceel = self.caches['short'].get_or_create(key, creator)
820
        else:
821
            perceel = creator()
822
        perceel.set_gateway(self)
823
        return perceel
824
825
    def get_perceel_by_capakey(self, capakey):
826
        '''
827
        Get a `perceel`.
828
829
        :param capakey: An capakey for a `perceel`.
830
        :rtype: :class:`Perceel`
831
        '''
832
        def creator():
833
            url = self.base_url + '/parcel/%s' % capakey
834
            h = self.base_headers
835
            p = {
836
                'geometry': 'bbox',
837
                'srs': '31370',
838
                'data': 'cadmap'
839
            }
840
            res = capakey_rest_gateway_request(url, p, h).json()
841
            return Perceel(
842
                res['perceelnummer'],
843
                Sectie(
844
                    res['sectionCode'],
845
                    Afdeling(
846
                        res['departmentCode'],
847
                        res['departmentName'],
848
                        Gemeente(res['municipalityCode'], res['municipalityName'])
849
                    )
850
                ),
851
                res['capakey'],
852
                Perceel.get_percid_from_capakey(res['capakey']),
853
                None,
854
                None,
855
                res['geometry']['center'],
856
                res['geometry']['boundingBox']
857
            )
858
        if self.caches['short'].is_configured:
859
            key = 'get_perceel_by_capakey_rest#%s' % capakey
860
            perceel = self.caches['short'].get_or_create(key, creator)
861
        else:
862
            perceel = creator()
863
        perceel.set_gateway(self)
864
        return perceel
865
866
    def get_perceel_by_percid(self, percid):
867
        '''
868
        Get a `perceel`.
869
870
        :param percid: A percid for a `perceel`.
871
        :rtype: :class:`Perceel`
872
        '''
873
        return self.get_perceel_by_capakey(
874
            Perceel.get_capakey_from_percid(percid)
875
        )
876
877
878
class GatewayObject(object):
879
    '''
880
    Abstract class for all objects being returned from the Gateway.
881
    '''
882
883
    gateway = None
884
    '''
885
    The :class:`crabpy.gateway.capakey.CapakeyGateway` to use when making
886
    further calls to the Capakey service.
887
    '''
888
889
    def __init__(self, **kwargs):
890
        if 'gateway' in kwargs:
891
            self.set_gateway(kwargs['gateway'])
892
893
    def set_gateway(self, gateway):
894
        '''
895
        :param crabpy.gateway.capakey.CapakeyGateway gateway: Gateway to use.
896
        '''
897
        self.gateway = gateway
898
899
    def clear_gateway(self):
900
        '''
901
        Clear the currently set CapakeyGateway.
902
        '''
903
        self.gateway = None
904
905
    def check_gateway(self):
906
        '''
907
        Check to see if a gateway was set on this object.
908
        '''
909
        if not self.gateway:
910
            raise RuntimeError("There's no Gateway I can use")
911
912
    if six.PY2:
913
        def __str__(self):
914
            return self.__unicode__().encode('utf-8')
915
    else:
916
        def __str__(self):
917
            return self.__unicode__()
918
919
920
def check_lazy_load_gemeente(f):
921
    '''
922
    Decorator function to lazy load a :class:`Gemeente`.
923
    '''
924
    def wrapper(self):
925
        gemeente = self
926
        if (getattr(gemeente, '_%s' % f.__name__, None) is None):
927
            log.debug('Lazy loading Gemeente %d', gemeente.id)
928
            gemeente.check_gateway()
929
            g = gemeente.gateway.get_gemeente_by_id(gemeente.id)
930
            gemeente._naam = g._naam
931
            gemeente._centroid = g._centroid
932
            gemeente._bounding_box = g._bounding_box
933
        return f(self)
934
    return wrapper
935
936
937
class Gemeente(GatewayObject):
938
    '''
939
    The smallest administrative unit in Belgium.
940
    '''
941
942
    def __init__(
943
            self, id, naam=None,
944
            centroid=None, bounding_box=None,
945
            **kwargs
946
    ):
947
        self.id = int(id)
948
        self._naam = naam
949
        self._centroid = centroid
950
        self._bounding_box = bounding_box
951
        super(Gemeente, self).__init__(**kwargs)
952
953
    @property
954
    @check_lazy_load_gemeente
955
    def naam(self):
956
        return self._naam
957
958
    @property
959
    @check_lazy_load_gemeente
960
    def centroid(self):
961
        return self._centroid
962
963
    @property
964
    @check_lazy_load_gemeente
965
    def bounding_box(self):
966
        return self._bounding_box
967
968
    @property
969
    def afdelingen(self):
970
        self.check_gateway()
971
        return self.gateway.list_kadastrale_afdelingen_by_gemeente(self)
972
973
    def __unicode__(self):
974
        return '%s (%s)' % (self.naam, self.id)
975
976
    def __repr__(self):
977
        return "Gemeente(%s, '%s')" % (self.id, self.naam)
978
979
980 View Code Duplication
def check_lazy_load_afdeling(f):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
981
    '''
982
    Decorator function to lazy load a :class:`Afdeling`.
983
    '''
984
    def wrapper(self):
985
        afdeling = self
986
        if (getattr(afdeling, '_%s' % f.__name__, None) is None):
987
            log.debug('Lazy loading Afdeling %d', afdeling.id)
988
            afdeling.check_gateway()
989
            a = afdeling.gateway.get_kadastrale_afdeling_by_id(afdeling.id)
990
            afdeling._naam = a._naam
991
            afdeling._gemeente = a._gemeente
992
            afdeling._centroid = a._centroid
993
            afdeling._bounding_box = a._bounding_box
994
        return f(self)
995
    return wrapper
996
997
998
class Afdeling(GatewayObject):
999
    '''
1000
    A Cadastral Division of a :class:`Gemeente`.
1001
    '''
1002
1003
    def __init__(
1004
        self, id, naam=None, gemeente=None,
1005
        centroid=None, bounding_box=None,
1006
        **kwargs
1007
    ):
1008
        self.id = int(id)
1009
        self._naam = naam
1010
        self._gemeente = gemeente
1011
        self._centroid = centroid
1012
        self._bounding_box = bounding_box
1013
        super(Afdeling, self).__init__(**kwargs)
1014
1015
    def set_gateway(self, gateway):
1016
        '''
1017
        :param crabpy.gateway.capakey.CapakeyGateway gateway: Gateway to use.
1018
        '''
1019
        self.gateway = gateway
1020
        if (self._gemeente is not None):
1021
            self._gemeente.set_gateway(gateway)
1022
1023
    def clear_gateway(self):
1024
        '''
1025
        Clear the currently set CapakeyGateway.
1026
        '''
1027
        self.gateway = None
1028
        if (self._gemeente is not None):
1029
            self._gemeente.clear_gateway()
1030
1031
    @property
1032
    @check_lazy_load_afdeling
1033
    def naam(self):
1034
        return self._naam
1035
1036
    @property
1037
    @check_lazy_load_afdeling
1038
    def gemeente(self):
1039
        return self._gemeente
1040
1041
    @property
1042
    @check_lazy_load_afdeling
1043
    def centroid(self):
1044
        return self._centroid
1045
1046
    @property
1047
    @check_lazy_load_afdeling
1048
    def bounding_box(self):
1049
        return self._bounding_box
1050
1051
    @property
1052
    def secties(self):
1053
        self.check_gateway()
1054
        return self.gateway.list_secties_by_afdeling(self)
1055
1056
    def __unicode__(self):
1057
        if self._naam is not None:
1058
            return '%s (%s)' % (self._naam, self.id)
1059
        else:
1060
            return 'Afdeling %s' % (self.id)
1061
1062
    def __repr__(self):
1063 View Code Duplication
        if self._naam is not None:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1064
            return "Afdeling(%s, '%s')" % (self.id, self._naam)
1065
        else:
1066
            return 'Afdeling(%s)' % (self.id)
1067
1068
1069
def check_lazy_load_sectie(f):
1070
    '''
1071
    Decorator function to lazy load a :class:`Sectie`.
1072
    '''
1073
    def wrapper(self):
1074
        sectie = self
1075
        if (getattr(sectie, '_%s' % f.__name__, None) is None):
1076
            log.debug('Lazy loading Sectie %s in Afdeling %d', sectie.id, sectie.afdeling.id)
1077
            sectie.check_gateway()
1078
            s = sectie.gateway.get_sectie_by_id_and_afdeling(
1079
                sectie.id, sectie.afdeling.id
1080
            )
1081
            sectie._centroid = s._centroid
1082
            sectie._bounding_box = s._bounding_box
1083
        return f(self)
1084
    return wrapper
1085
1086
1087
class Sectie(GatewayObject):
1088
    '''
1089
    A subdivision of a :class:`Afdeling`.
1090
    '''
1091
1092
    def __init__(
1093
        self, id, afdeling,
1094
        centroid=None, bounding_box=None,
1095
        **kwargs
1096
    ):
1097
        self.id = id
1098
        self.afdeling = afdeling
1099
        self._centroid = centroid
1100
        self._bounding_box = bounding_box
1101
        super(Sectie, self).__init__(**kwargs)
1102
1103
    def set_gateway(self, gateway):
1104
        '''
1105
        :param crabpy.gateway.capakey.CapakeyGateway gateway: Gateway to use.
1106
        '''
1107
        self.gateway = gateway
1108
        self.afdeling.set_gateway(gateway)
1109
1110
    def clear_gateway(self):
1111
        '''
1112
        Clear the currently set CapakeyGateway.
1113
        '''
1114
        self.gateway = None
1115
        self.afdeling.clear_gateway()
1116
1117
    @property
1118
    @check_lazy_load_sectie
1119
    def centroid(self):
1120
        return self._centroid
1121
1122
    @property
1123
    @check_lazy_load_sectie
1124
    def bounding_box(self):
1125
        return self._bounding_box
1126
1127
    @property
1128
    def percelen(self):
1129
        self.check_gateway()
1130
        return self.gateway.list_percelen_by_sectie(self)
1131
1132
    def __unicode__(self):
1133
        return '%s, Sectie %s' % (self.afdeling, self.id)
1134
1135
    def __repr__(self):
1136
        return "Sectie('%s', %s)" % (self.id, repr(self.afdeling))
1137
1138
1139 View Code Duplication
def check_lazy_load_perceel(f):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1140
    '''
1141
    Decorator function to lazy load a :class:`Perceel`.
1142
    '''
1143
    def wrapper(self):
1144
        perceel = self
1145
        if (getattr(perceel, '_%s' % f.__name__, None) is None):
1146
            log.debug(
1147
                'Lazy loading Perceel %s in Sectie %s in Afdeling %d',
1148
                perceel.id,
1149
                perceel.sectie.id,
1150
                perceel.sectie.afdeling.id
1151
            )
1152
            perceel.check_gateway()
1153
            p = perceel.gateway.get_perceel_by_id_and_sectie(
1154
                perceel.id,
1155
                perceel.sectie
1156
            )
1157
            perceel._centroid = p._centroid
1158
            perceel._bounding_box = p._bounding_box
1159
            perceel._capatype = p._capatype
1160
            perceel._cashkey = p._cashkey
1161
        return f(self)
1162
    return wrapper
1163
1164
1165
class Perceel(GatewayObject):
1166
    '''
1167
    A Cadastral Parcel.
1168
    '''
1169
1170
    def __init__(
1171
        self, id, sectie, capakey, percid,
1172
        capatype=None, cashkey=None,
1173
        centroid=None, bounding_box=None,
1174
        **kwargs
1175
    ):
1176
        self.id = id
1177
        self.sectie = sectie
1178
        self.capakey = capakey
1179
        self.percid = percid
1180
        self._capatype = capatype
1181
        self._cashkey = cashkey
1182
        self._centroid = centroid
1183
        self._bounding_box = bounding_box
1184
        super(Perceel, self).__init__(**kwargs)
1185
        self._split_capakey()
1186
1187
    def set_gateway(self, gateway):
1188
        '''
1189
        :param crabpy.gateway.capakey.CapakeyGateway gateway: Gateway to use.
1190
        '''
1191
        self.gateway = gateway
1192
        self.sectie.set_gateway(gateway)
1193
1194
    def clear_gateway(self):
1195
        '''
1196
        Clear the currently set CapakeyGateway.
1197
        '''
1198
        self.gateway = None
1199
        self.sectie.clear_gateway()
1200
1201
    @staticmethod
1202
    def get_percid_from_capakey(capakey):
1203
        import re
1204
        match = re.match(
1205
            r"^([0-9]{5})([A-Z]{1})([0-9]{4})\/([0-9]{2})([A-Z\_]{1})([0-9]{3})$",
1206
            capakey
1207
        )
1208
        if match:
1209
            percid = match.group(1) + '_' + match.group(2) +\
1210
                '_' + match.group(3) + '_' + match.group(5) + '_' +\
1211
                match.group(6) + '_' + match.group(4)
1212
            return percid
1213
        else:
1214
            raise ValueError(
1215
                "Invalid Capakey %s can't be parsed" % capakey
1216
            )
1217
1218
    @staticmethod
1219
    def get_capakey_from_percid(percid):
1220
        import re
1221
        match = re.match(
1222
            r"^([0-9]{5})_([A-Z]{1})_([0-9]{4})_([A-Z\_]{1})_([0-9]{3})_([0-9]{2})$",
1223
            percid
1224
        )
1225
        if match:
1226
            capakey = match.group(1) + match.group(2) +\
1227
                match.group(3) + '/' + match.group(6) +\
1228
                match.group(4) + match.group(5)
1229
            return capakey
1230
        else:
1231
            raise ValueError(
1232
                "Invalid percid %s can't be parsed" % percid
1233
            )
1234
1235
    def _split_capakey(self):
1236
        '''
1237
        Split a capakey into more readable elements.
1238
1239
        Splits a capakey into it's grondnummer, bisnummer, exponent and macht.
1240
        '''
1241
        import re
1242
        match = re.match(
1243
            r"^[0-9]{5}[A-Z]{1}([0-9]{4})\/([0-9]{2})([A-Z\_]{1})([0-9]{3})$",
1244
            self.capakey
1245
        )
1246
        if match:
1247
            self.grondnummer = match.group(1)
1248
            self.bisnummer = match.group(2)
1249
            self.exponent = match.group(3)
1250
            self.macht = match.group(4)
1251
        else:
1252
            raise ValueError(
1253
                "Invalid Capakey %s can't be parsed" % self.capakey
1254
            )
1255
1256
    @property
1257
    @check_lazy_load_perceel
1258
    def centroid(self):
1259
        return self._centroid
1260
1261
    @property
1262
    @check_lazy_load_perceel
1263
    def bounding_box(self):
1264
        return self._bounding_box
1265
1266
    @property
1267
    @check_lazy_load_perceel
1268
    def capatype(self):
1269
        return self._capatype
1270
1271
    @property
1272
    @check_lazy_load_perceel
1273
    def cashkey(self):
1274
        return self._cashkey
1275
1276
    def __unicode__(self):
1277
        return self.capakey
1278
1279
    def __repr__(self):
1280
        return "Perceel('%s', %s, '%s', '%s')" % (
1281
            self.id, repr(self.sectie), self.capakey, self.percid
1282
        )
1283