Completed
Push — master ( be9a59...193e73 )
by Koen
9s
created

crabpy/gateway/capakey.py (10 issues)

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 View Code Duplication
    @deprecate(DEPRECATIONWARNING.format(''))
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
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
        for g in gemeente:
111
            g.set_gateway(self)
112
        return gemeente
113
114 View Code Duplication
    @deprecate(DEPRECATIONWARNING.format('.get_gemeente_by_id'))
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
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
            afdeling = creator()
238
        afdeling.set_gateway(self)
239
        return afdeling
240
241 View Code Duplication
    @deprecate(DEPRECATIONWARNING.format('.list_secties_by_afdeling'))
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
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
        for p in percelen:
352
            p.set_gateway(self)
353
        return percelen
354
355 View Code Duplication
    @deprecate(DEPRECATIONWARNING.format('.get_perceel_by_id_and_sectie'))
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
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
            perceel = creator()
389
        perceel.set_gateway(self)
390
        return perceel
391
392 View Code Duplication
    @deprecate(DEPRECATIONWARNING.format('.get_perceel_by_capakey'))
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
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 View Code Duplication
    @deprecate(DEPRECATIONWARNING.format('.get_perceel_by_percid'))
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
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
    '''
484
485
    caches = {}
486
487 View Code Duplication
    def __init__(self, **kwargs):
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
488
        self.base_url = kwargs.get(
489
            'base_url',
490
            'https://geoservices.informatievlaanderen.be/capakey/api/v1'
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
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
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 View Code Duplication
class GatewayObject(object):
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
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
        :param crabpy.gateway.capakey.CapakeyGateway gateway: Gateway to use.
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
def check_lazy_load_gemeente(f):
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
        self._bounding_box = bounding_box
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
def check_lazy_load_afdeling(f):
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
    def naam(self):
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
def check_lazy_load_sectie(f):
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
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
def check_lazy_load_perceel(f):
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