Completed
Push — master ( 4a2911...b3e8a5 )
by Koen
16s
created

CapakeyRestGateway._parse_bounding_box()   A

Complexity

Conditions 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

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