Completed
Push — master ( 6a4f63...67cefa )
by Koen
02:45
created

CapakeyRestGateway.creator()   A

Complexity

Conditions 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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