Completed
Pull Request — master (#53)
by Koen
01:14
created

Perceel.get_percid_from_capakey()   A

Complexity

Conditions 2

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 15
rs 9.4285
c 0
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' % ce.message,
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' % re.message,
452
            re
453
        )
454
455
456
class CapakeyRestGateway(CapakeyGateway):
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
            'http://geoservices.beta.informatievlaanderen.be:80/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_gemeente_for_kadastrale_afdeling(self, afdeling):
597
        try:
598
            aid = afdeling.id
599
        except AttributeError:
600
            aid = afdeling
601
602
        afdelingen = self.list_kadastrale_afdelingen()
603
604
        for a in afdelingen:
605
            if a.id == aid:
606
                return a.gemeente
607
608
        raise GatewayResourceNotFoundException()
609
610
    def get_kadastrale_afdeling_by_id(self, aid):
611
        '''
612
        Retrieve a 'kadastrale afdeling' by id.
613
614
        :param aid: An id of a `kadastrale afdeling`.
615
        :rtype: A :class:`Afdeling`.
616
        '''
617
        def creator():
618
            g = self.get_gemeente_for_kadastrale_afdeling(aid)
619
            url = self.base_url + '/municipality/%s/department/%s' % (g.id, aid)
620
            h = self.base_headers
621
            p = {
622
                'geometry': 'bbox',
623
                'srs': 31370
624
            }
625
            res = capakey_rest_gateway_request(url, h, p).json()
626
            return Afdeling(
627
                id=res['departmentCode'],
628
                naam=res['departmentName'],
629
                gemeente=g,
630
                centroid=res['geometry']['center'],
631
                bounding_box=res['geometry']['boundingBox']
632
            )
633
        if self.caches['long'].is_configured:
634
            key = 'get_kadastrale_afdeling_by_id_rest#%s' % id
635
            afdeling = self.caches['long'].get_or_create(key, creator)
636
        else:
637
            afdeling = creator()
638
        afdeling.set_gateway(self)
639
        return afdeling
640
641
    def list_secties_by_afdeling(self, afdeling):
642
        '''
643
        List all `secties` in a `kadastrale afdeling`.
644
645
        :param afdeling: The :class:`Afdeling` for which the `secties` are \
646
            wanted. Can also be the id of and `afdeling`.
647
        :rtype: A :class:`list` of `Sectie`.
648
        '''
649
        try:
650
            aid = afdeling.id
651
        except AttributeError:
652
            aid = afdeling
653
            afdeling = self.get_kadastrale_afdeling_by_id(aid)
654
        afdeling.clear_gateway()
655
656
        def creator():
657
            url = self.base_url + '/municipality/%s/department/%s/section' % (afdeling.gemeente.id, afdeling.id)
658
            h = self.base_headers
659
            p = {
660
                'geometry': 'bbox',
661
                'srs': 31370
662
            }
663
            res = capakey_rest_gateway_request(url, h, p).json()
664
            return [
665
                Sectie(
666
                    r['sectionCode'],
667
                    afdeling
668
                ) for r in res['sections']
669
            ]
670
        if self.caches['long'].is_configured:
671
            key = 'list_secties_by_afdeling_rest#%s' % aid
672
            secties = self.caches['long'].get_or_create(key, creator)
673
        else:
674
            secties = creator()
675
        for s in secties:
676
            s.set_gateway(self)
677
        return secties
678
679
    def get_sectie_by_id_and_afdeling(self, id, afdeling):
680
        '''
681
        Get a `sectie`.
682
683
        :param id: An id of a sectie. eg. "A"
684
        :param afdeling: The :class:`Afdeling` for in which the `sectie` can \
685
            be found. Can also be the id of and `afdeling`.
686
        :rtype: A :class:`Sectie`.
687
        '''
688
        try:
689
            aid = afdeling.id
690
        except AttributeError:
691
            aid = afdeling
692
            afdeling = self.get_kadastrale_afdeling_by_id(aid)
693
        afdeling.clear_gateway()
694
695
        def creator():
696
            url = self.base_url + '/municipality/%s/department/%s/section/%s' % (afdeling.gemeente.id, afdeling.id, id)
697
            h = self.base_headers
698
            p = {
699
                'geometry': 'bbox',
700
                'srs': 31370
701
            }
702
            res = capakey_rest_gateway_request(url, h, p).json()
703
            return Sectie(
704
                res['sectionCode'],
705
                afdeling,
706
                res['geometry']['center'],
707
                res['geometry']['boundingBox'],
708
            )
709
        if self.caches['long'].is_configured:
710
            key = 'get_sectie_by_id_and_afdeling_rest#%s#%s' % (id, aid)
711
            sectie = self.caches['long'].get_or_create(key, creator)
712
        else:
713
            sectie = creator()
714
        sectie.set_gateway(self)
715
        return sectie
716
717
    def parse_percid(self, capakey):
718
        import re
719
        match = re.match(
720
            r"^([0-9]{5})([A-Z]{1})([0-9]{4})\/([0-9]{2})([A-Z\_]{1})([0-9]{3})$",
721
            capakey
722
        )
723
        if match:
724
            percid = match.group(1) + '_' + match.group(2) +\
725
                '_' + match.group(3) + '_' + match.group(5) + '_' +\
726
                match.group(6) + '_' + match.group(4)
727
            return percid
728
        else:
729
            raise ValueError(
730
                "Invalid Capakey %s can't be parsed" % capakey
731
            )
732
733
    def parse_capakey(self, percid):
734
        import re
735
        match = re.match(
736
            r"^([0-9]{5})_([A-Z]{1})_([0-9]{4})_([A-Z\_]{1})_([0-9]{3})_([0-9]{2})$",
737
            percid
738
        )
739
        if match:
740
            capakey = match.group(1) + match.group(2) +\
741
                match.group(3) + '/' + match.group(5) + '_' +\
742
                match.group(6) + '_' + match.group(4)
743
            return capakey
744
        else:
745
            raise ValueError(
746
                "Invalid percid %s can't be parsed" % percid
747
            )
748
749
    def list_percelen_by_sectie(self, sectie, sort=1):
750
        '''
751
        List all percelen in a `sectie`.
752
753
        :param sectie: The :class:`Sectie` for which the percelen are wanted.
754
        :param integer sort: Field to sort on.
755
        :rtype: A :class:`list` of :class:`Perceel`.
756
        '''
757
        sid = sectie.id
758
        aid = sectie.afdeling.id
759
        gid = sectie.afdeling.gemeente.id
760
        sectie.clear_gateway()
761
        def creator():
762
            url = self.base_url + '/municipality/%s/department/%s/section/%s/parcel' % (gid, aid, sid)
763
            h = self.base_headers
764
            res = capakey_rest_gateway_request(url, h).json()
765
            return [
766
                Perceel(
767
                    r['perceelnummer'],
768
                    sectie,
769
                    r['capakey'],
770
                    self.parse_percid(r['capakey']),
771
                ) for r in res['parcels']
772
            ]
773
        if self.caches['short'].is_configured:
774
            key = 'list_percelen_by_sectie_rest#%s#%s#%s' % (gid, aid, sid)
775
            percelen = self.caches['short'].get_or_create(key, creator)
776
        else:
777
            percelen = creator()
778
        for p in percelen:
779
            p.set_gateway(self)
780
        return percelen
781
782
    def get_perceel_by_id_and_sectie(self, id, sectie):
783
        '''
784
        Get a `perceel`.
785
786
        :param id: An id for a `perceel`.
787
        :param sectie: The :class:`Sectie` that contains the perceel.
788
        :rtype: :class:`Perceel`
789
        '''
790
        sid = sectie.id
791
        aid = sectie.afdeling.id
792
        gid = sectie.afdeling.gemeente.id
793
        sectie.clear_gateway()
794
        def creator():
795
            url = self.base_url + '/municipality/%s/department/%s/section/%s/parcel/%s' % (gid, aid, sid, id)
796
            h = self.base_headers
797
            p = {
798
                'geometry': 'bbox',
799
                'srs': 31370
800
            }
801
            res = capakey_rest_gateway_request(url, p, h).json()
802
            return Perceel(
803
                res['perceelnummer'],
804
                sectie,
805
                res['capakey'],
806
                Perceel.get_percid_from_capakey(res['capakey']),
807
                None,
808
                None,
809
                res['geometry']['center'],
810
                res['geometry']['boundingBox']
811
            )
812
        if self.caches['short'].is_configured:
813
            key = 'get_perceel_by_id_and_sectie_rest#%s#%s#%s' % (id, sectie.id, sectie.afdeling.id)
814
            perceel = self.caches['short'].get_or_create(key, creator)
815
        else:
816
            perceel = creator()
817
        perceel.set_gateway(self)
818
        return perceel
819
820
    def get_perceel_by_capakey(self, capakey):
821
        '''
822
        Get a `perceel`.
823
824
        :param capakey: An capakey for a `perceel`.
825
        :rtype: :class:`Perceel`
826
        '''
827
        def creator():
828
            url = self.base_url + '/parcel/%s' % capakey
829
            h = self.base_headers
830
            p = {
831
                'geometry': 'bbox',
832
                'srs': 31370
833
            }
834
            res = capakey_rest_gateway_request(url, p, h).json()
835
            return Perceel(
836
                res['perceelnummer'],
837
                Sectie(
838
                    res['sectionCode'],
839
                    Afdeling(
840
                        res['departmentCode'],
841
                        res['departmentName'],
842
                        Gemeente(res['municipalityCode'], res['municipalityName'])
843
                    )
844
                ),
845
                res['capakey'],
846
                Perceel.get_percid_from_capakey(res['capakey']),
847
                None,
848
                None,
849
                res['geometry']['center'],
850
                res['geometry']['boundingBox']
851
            )
852
        if self.caches['short'].is_configured:
853
            key = 'get_perceel_by_capakey_rest#%s' % capakey
854
            perceel = self.caches['short'].get_or_create(key, creator)
855
        else:
856
            perceel = creator()
857
        perceel.set_gateway(self)
858
        return perceel
859
860
    def get_perceel_by_percid(self, percid):
861
        '''
862
        Get a `perceel`.
863
864
        :param percid: A percid for a `perceel`.
865
        :rtype: :class:`Perceel`
866
        '''
867
        return self.get_perceel_by_capakey(
868
            Perceel.get_capakey_from_percid(percid)
869
        )
870
871
872
class GatewayObject(object):
873
    '''
874
    Abstract class for all objects being returned from the Gateway.
875
    '''
876
877
    gateway = None
878
    '''
879
    The :class:`crabpy.gateway.capakey.CapakeyGateway` to use when making
880
    further calls to the Capakey service.
881
    '''
882
883
    def __init__(self, **kwargs):
884
        if 'gateway' in kwargs:
885
            self.set_gateway(kwargs['gateway'])
886
887
    def set_gateway(self, gateway):
888
        '''
889
        :param crabpy.gateway.capakey.CapakeyGateway gateway: Gateway to use.
890
        '''
891
        self.gateway = gateway
892
893
    def clear_gateway(self):
894
        '''
895
        Clear the currently set CapakeyGateway.
896
        '''
897
        self.gateway = None
898
899
    def check_gateway(self):
900
        '''
901
        Check to see if a gateway was set on this object.
902
        '''
903
        if not self.gateway:
904
            raise RuntimeError("There's no Gateway I can use")
905
906
    if six.PY2:
907
        def __str__(self):
908
            return self.__unicode__().encode('utf-8')
909
    else:
910
        def __str__(self):
911
            return self.__unicode__()
912
913
914
def check_lazy_load_gemeente(f):
915
    '''
916
    Decorator function to lazy load a :class:`Gemeente`.
917
    '''
918
    def wrapper(self):
919
        gemeente = self
920
        if (getattr(gemeente, '_%s' % f.__name__, None) is None):
921
            log.debug('Lazy loading Gemeente %d', gemeente.id)
922
            gemeente.check_gateway()
923
            g = gemeente.gateway.get_gemeente_by_id(gemeente.id)
924
            gemeente._naam = g._naam
925
            gemeente._centroid = g._centroid
926
            gemeente._bounding_box = g._bounding_box
927
        return f(self)
928
    return wrapper
929
930
931
class Gemeente(GatewayObject):
932
    '''
933
    The smallest administrative unit in Belgium.
934
    '''
935
936
    def __init__(
937
            self, id, naam=None,
938
            centroid=None, bounding_box=None,
939
            **kwargs
940
    ):
941
        self.id = int(id)
942
        self._naam = naam
943
        self._centroid = centroid
944
        self._bounding_box = bounding_box
945
        super(Gemeente, self).__init__(**kwargs)
946
947
    @property
948
    @check_lazy_load_gemeente
949
    def naam(self):
950
        return self._naam
951
952
    @property
953
    @check_lazy_load_gemeente
954
    def centroid(self):
955
        return self._centroid
956
957
    @property
958
    @check_lazy_load_gemeente
959
    def bounding_box(self):
960
        return self._bounding_box
961
962
    @property
963
    def afdelingen(self):
964
        self.check_gateway()
965
        return self.gateway.list_kadastrale_afdelingen_by_gemeente(self)
966
967
    def __unicode__(self):
968
        return '%s (%s)' % (self.naam, self.id)
969
970
    def __repr__(self):
971
        return "Gemeente(%s, '%s')" % (self.id, self.naam)
972
973
974 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...
975
    '''
976
    Decorator function to lazy load a :class:`Afdeling`.
977
    '''
978
    def wrapper(self):
979
        afdeling = self
980
        if (getattr(afdeling, '_%s' % f.__name__, None) is None):
981
            log.debug('Lazy loading Afdeling %d', afdeling.id)
982
            afdeling.check_gateway()
983
            a = afdeling.gateway.get_kadastrale_afdeling_by_id(afdeling.id)
984
            afdeling._naam = a._naam
985
            afdeling._gemeente = a._gemeente
986
            afdeling._centroid = a._centroid
987
            afdeling._bounding_box = a._bounding_box
988
        return f(self)
989
    return wrapper
990
991
992
class Afdeling(GatewayObject):
993
    '''
994
    A Cadastral Division of a :class:`Gemeente`.
995
    '''
996
997
    def __init__(
998
        self, id, naam=None, gemeente=None,
999
        centroid=None, bounding_box=None,
1000
        **kwargs
1001
    ):
1002
        self.id = int(id)
1003
        self._naam = naam
1004
        self._gemeente = gemeente
1005
        self._centroid = centroid
1006
        self._bounding_box = bounding_box
1007
        super(Afdeling, self).__init__(**kwargs)
1008
1009
    def set_gateway(self, gateway):
1010
        '''
1011
        :param crabpy.gateway.capakey.CapakeyGateway gateway: Gateway to use.
1012
        '''
1013
        self.gateway = gateway
1014
        if (self._gemeente is not None):
1015
            self._gemeente.set_gateway(gateway)
1016
1017
    def clear_gateway(self):
1018
        '''
1019
        Clear the currently set CapakeyGateway.
1020
        '''
1021
        self.gateway = None
1022
        if (self._gemeente is not None):
1023
            self._gemeente.clear_gateway()
1024
1025
    @property
1026
    @check_lazy_load_afdeling
1027
    def naam(self):
1028
        return self._naam
1029
1030
    @property
1031
    @check_lazy_load_afdeling
1032
    def gemeente(self):
1033
        return self._gemeente
1034
1035
    @property
1036
    @check_lazy_load_afdeling
1037
    def centroid(self):
1038
        return self._centroid
1039
1040
    @property
1041
    @check_lazy_load_afdeling
1042
    def bounding_box(self):
1043
        return self._bounding_box
1044
1045
    @property
1046
    def secties(self):
1047
        self.check_gateway()
1048
        return self.gateway.list_secties_by_afdeling(self)
1049
1050
    def __unicode__(self):
1051
        if self._naam is not None:
1052
            return '%s (%s)' % (self._naam, self.id)
1053
        else:
1054
            return 'Afdeling %s' % (self.id)
1055
1056
    def __repr__(self):
1057
        if self._naam is not None:
1058
            return "Afdeling(%s, '%s')" % (self.id, self._naam)
1059
        else:
1060
            return 'Afdeling(%s)' % (self.id)
1061
1062
1063 View Code Duplication
def check_lazy_load_sectie(f):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1064
    '''
1065
    Decorator function to lazy load a :class:`Sectie`.
1066
    '''
1067
    def wrapper(self):
1068
        sectie = self
1069
        if (getattr(sectie, '_%s' % f.__name__, None) is None):
1070
            log.debug('Lazy loading Sectie %s in Afdeling %d', sectie.id, sectie.afdeling.id)
1071
            sectie.check_gateway()
1072
            s = sectie.gateway.get_sectie_by_id_and_afdeling(
1073
                sectie.id, sectie.afdeling.id
1074
            )
1075
            sectie._centroid = s._centroid
1076
            sectie._bounding_box = s._bounding_box
1077
        return f(self)
1078
    return wrapper
1079
1080
1081
class Sectie(GatewayObject):
1082
    '''
1083
    A subdivision of a :class:`Afdeling`.
1084
    '''
1085
1086
    def __init__(
1087
        self, id, afdeling,
1088
        centroid=None, bounding_box=None,
1089
        **kwargs
1090
    ):
1091
        self.id = id
1092
        self.afdeling = afdeling
1093
        self._centroid = centroid
1094
        self._bounding_box = bounding_box
1095
        super(Sectie, self).__init__(**kwargs)
1096
1097
    def set_gateway(self, gateway):
1098
        '''
1099
        :param crabpy.gateway.capakey.CapakeyGateway gateway: Gateway to use.
1100
        '''
1101
        self.gateway = gateway
1102
        self.afdeling.set_gateway(gateway)
1103
1104
    def clear_gateway(self):
1105
        '''
1106
        Clear the currently set CapakeyGateway.
1107
        '''
1108
        self.gateway = None
1109
        self.afdeling.clear_gateway()
1110
1111
    @property
1112
    @check_lazy_load_sectie
1113
    def centroid(self):
1114
        return self._centroid
1115
1116
    @property
1117
    @check_lazy_load_sectie
1118
    def bounding_box(self):
1119
        return self._bounding_box
1120
1121
    @property
1122
    def percelen(self):
1123
        self.check_gateway()
1124
        return self.gateway.list_percelen_by_sectie(self)
1125
1126
    def __unicode__(self):
1127
        return '%s, Sectie %s' % (self.afdeling, self.id)
1128
1129
    def __repr__(self):
1130
        return "Sectie('%s', %s)" % (self.id, repr(self.afdeling))
1131
1132
1133 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...
1134
    '''
1135
    Decorator function to lazy load a :class:`Perceel`.
1136
    '''
1137
    def wrapper(self):
1138
        perceel = self
1139
        if (getattr(perceel, '_%s' % f.__name__, None) is None):
1140
            log.debug(
1141
                'Lazy loading Perceel %s in Sectie %s in Afdeling %d',
1142
                perceel.id,
1143
                perceel.sectie.id,
1144
                perceel.sectie.afdeling.id
1145
            )
1146
            perceel.check_gateway()
1147
            p = perceel.gateway.get_perceel_by_id_and_sectie(
1148
                perceel.id,
1149
                perceel.sectie
1150
            )
1151
            perceel._centroid = p._centroid
1152
            perceel._bounding_box = p._bounding_box
1153
            perceel._capatype = p._capatype
1154
            perceel._cashkey = p._cashkey
1155
        return f(self)
1156
    return wrapper
1157
1158
1159
class Perceel(GatewayObject):
1160
    '''
1161
    A Cadastral Parcel.
1162
    '''
1163
1164
    def __init__(
1165
        self, id, sectie, capakey, percid,
1166
        capatype=None, cashkey=None,
1167
        centroid=None, bounding_box=None,
1168
        **kwargs
1169
    ):
1170
        self.id = id
1171
        self.sectie = sectie
1172
        self.capakey = capakey
1173
        self.percid = percid
1174
        self._capatype = capatype
1175
        self._cashkey = cashkey
1176
        self._centroid = centroid
1177
        self._bounding_box = bounding_box
1178
        super(Perceel, self).__init__(**kwargs)
1179
        self._split_capakey()
1180
1181
    def set_gateway(self, gateway):
1182
        '''
1183
        :param crabpy.gateway.capakey.CapakeyGateway gateway: Gateway to use.
1184
        '''
1185
        self.gateway = gateway
1186
        self.sectie.set_gateway(gateway)
1187
1188
    def clear_gateway(self):
1189
        '''
1190
        Clear the currently set CapakeyGateway.
1191
        '''
1192
        self.gateway = None
1193
        self.sectie.clear_gateway()
1194
1195
    @staticmethod
1196
    def get_percid_from_capakey(capakey):
1197
        import re
1198
        match = re.match(
1199
            r"^([0-9]{5})([A-Z]{1})([0-9]{4})\/([0-9]{2})([A-Z\_]{1})([0-9]{3})$",
1200
            capakey
1201
        )
1202
        if match:
1203
            percid = match.group(1) + '_' + match.group(2) +\
1204
                '_' + match.group(3) + '_' + match.group(5) + '_' +\
1205
                match.group(6) + '_' + match.group(4)
1206
            return percid
1207
        else:
1208
            raise ValueError(
1209
                "Invalid Capakey %s can't be parsed" % capakey
1210
            )
1211
1212
    @staticmethod
1213
    def get_capakey_from_percid(percid):
1214
        import re
1215
        match = re.match(
1216
            r"^([0-9]{5})_([A-Z]{1})_([0-9]{4})_([A-Z\_]{1})_([0-9]{3})_([0-9]{2})$",
1217
            percid
1218
        )
1219
        if match:
1220
            capakey = match.group(1) + match.group(2) +\
1221
                match.group(3) + '/' + match.group(6) +\
1222
                match.group(4) + match.group(5)
1223
            return capakey
1224
        else:
1225
            raise ValueError(
1226
                "Invalid percid %s can't be parsed" % percid
1227
            )
1228
1229
    def _split_capakey(self):
1230
        '''
1231
        Split a capakey into more readable elements.
1232
1233
        Splits a capakey into it's grondnummer, bisnummer, exponent and macht.
1234
        '''
1235
        import re
1236
        match = re.match(
1237
            r"^[0-9]{5}[A-Z]{1}([0-9]{4})\/([0-9]{2})([A-Z\_]{1})([0-9]{3})$",
1238
            self.capakey
1239
        )
1240
        if match:
1241
            self.grondnummer = match.group(1)
1242
            self.bisnummer = match.group(2)
1243
            self.exponent = match.group(3)
1244
            self.macht = match.group(4)
1245
        else:
1246
            raise ValueError(
1247
                "Invalid Capakey %s can't be parsed" % self.capakey
1248
            )
1249
1250
    @property
1251
    @check_lazy_load_perceel
1252
    def centroid(self):
1253
        return self._centroid
1254
1255
    @property
1256
    @check_lazy_load_perceel
1257
    def bounding_box(self):
1258
        return self._bounding_box
1259
1260
    @property
1261
    @check_lazy_load_perceel
1262
    def capatype(self):
1263
        return self._capatype
1264
1265
    @property
1266
    @check_lazy_load_perceel
1267
    def cashkey(self):
1268
        return self._cashkey
1269
1270
    def __unicode__(self):
1271
        return self.capakey
1272
1273
    def __repr__(self):
1274
        return "Perceel('%s', %s, '%s', '%s')" % (
1275
            self.id, repr(self.sectie), self.capakey, self.percid
1276
        )
1277