Completed
Pull Request — master (#53)
by
unknown
01:10
created

CapakeyGateway.list_percelen_by_sectie()   D

Complexity

Conditions 6

Size

Total Lines 35

Duplication

Lines 1
Ratio 2.86 %

Importance

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