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

crabpy/gateway/capakey.py (6 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.gateway.exception import (
16
    GatewayRuntimeException,
17
    GatewayResourceNotFoundException
18
)
19
20
from dogpile.cache import make_region
21
22
import requests
23
24
25
def capakey_rest_gateway_request(url, headers={}, params={}):
26
    '''
27
    Utility function that helps making requests to the CAPAKEY REST service.
28
29
    :param string url: URL to request.
30
    :param dict headers: Headers to send with the URL.
31
    :param dict params: Parameters to send with the URL.
32
    :returns: Result of the call.
33
    '''
34
    try:
35
        res = requests.get(url, headers=headers, params=params)
36
        res.raise_for_status()
37
        return res
38
    except requests.ConnectionError as ce:
39
        raise GatewayRuntimeException(
40
            'Could not execute request due to connection problems:\n%s' % repr(ce),
41
            ce
42
        )
43
    except requests.HTTPError as he:
44
        raise GatewayResourceNotFoundException()
45
    except requests.RequestException as re:
46
        raise GatewayRuntimeException(
47
            'Could not execute request due to:\n%s' % repr(re),
48
            re
49
        )
50
51
52
class CapakeyRestGateway(object):
53
    '''
54
    A REST gateway to the capakey webservice.
55
56
    .. versionadded:: 0.8.0
57
    '''
58
59
    caches = {}
60
61
    def __init__(self, **kwargs):
62
        self.base_url = kwargs.get(
63
            'base_url',
64
            'https://geoservices.informatievlaanderen.be/capakey/api/v1'
65
        )
66
        self.base_headers = {
67
            'Accept': 'application/json'
68
        }
69
        cache_regions = ['permanent', 'long', 'short']
70
        for cr in cache_regions:
71
            self.caches[cr] = make_region(key_mangler=str)
72
        if 'cache_config' in kwargs:
73
            for cr in cache_regions:
74
                if ('%s.backend' % cr) in kwargs['cache_config']:
75
                    log.debug('Configuring %s region on CapakeyRestGateway', cr)
76
                    self.caches[cr].configure_from_config(
77
                        kwargs['cache_config'],
78
                        '%s.' % cr
79
                    )
80
81
    @staticmethod
82
    def _parse_centroid(center):
83
        '''
84
        Parse response center from the CapakeyRestGateway to (CenterX, CenterY)
85
        
86
        :param center: response center from the CapakeyRestGateway
87
        :return: (CenterX, CenterY)
88
        '''
89
        coordinates = json.loads(center)["coordinates"]
90
        return coordinates[0], coordinates[1]
91
92
    @staticmethod
93
    def _parse_bounding_box(bounding_box):
94
        '''
95
        Parse response bounding box from the CapakeyRestGateway to (MinimumX, MinimumY, MaximumX, MaximumY)
96
        
97
        :param bounding_box: response bounding box from the CapakeyRestGateway
98
        :return: (MinimumX, MinimumY, MaximumX, MaximumY)
99
        '''
100
        coordinates = json.loads(bounding_box)["coordinates"]
101
        x_coords = [x for x, y in coordinates[0]]
102
        y_coords = [y for x, y in coordinates[0]]
103
        return min(x_coords), min(y_coords), max(x_coords), max(y_coords)
104
105
    def list_gemeenten(self, sort=1):
106 View Code Duplication
        '''
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
107
        List all `gemeenten` in Vlaanderen.
108
109
        :param integer sort: What field to sort on.
110
        :rtype: A :class:`list` of :class:`Gemeente`.
111
        '''
112
        def creator():
113
            url = self.base_url + '/municipality'
114
            h = self.base_headers
115
            p = {
116
                'orderbyCode': sort == 1
117
            }
118
            res = capakey_rest_gateway_request(url, h, p).json()
119
            return [
120
                Gemeente(r['municipalityCode'], r['municipalityName'])
121
                for r in res['municipalities']
122
            ]
123
        if self.caches['permanent'].is_configured:
124
            key = 'list_gemeenten_rest#%s' % sort
125
            gemeente = self.caches['permanent'].get_or_create(key, creator)
126
        else:
127
            gemeente = creator()
128
        for g in gemeente:
129
            g.set_gateway(self)
130
        return gemeente
131
132
    def get_gemeente_by_id(self, id):
133
        '''
134
        Retrieve a `gemeente` by id (the NIScode).
135
136
        :rtype: :class:`Gemeente`
137
        '''
138
        def creator():
139 View Code Duplication
            url = self.base_url + '/municipality/%s' % id
140
            h = self.base_headers
141
            p = {
142
                'geometry': 'bbox',
143
                'srs': '31370'
144
            }
145
            res = capakey_rest_gateway_request(url, h, p).json()
146
            return Gemeente(
147
                res['municipalityCode'],
148
                res['municipalityName'],
149
                self._parse_centroid(res['geometry']['center']),
150
                self._parse_bounding_box(res['geometry']['boundingBox'])
151
            )
152
        if self.caches['long'].is_configured:
153
            key = 'get_gemeente_by_id_rest#%s' % id
154
            gemeente = self.caches['long'].get_or_create(key, creator)
155
        else:
156
            gemeente = creator()
157
        gemeente.set_gateway(self)
158
        return gemeente
159
160
    def list_kadastrale_afdelingen(self):
161
        '''
162
        List all `kadastrale afdelingen` in Flanders.
163
164
        :param integer sort: Field to sort on.
165
        :rtype: A :class:`list` of :class:`Afdeling`.
166
        '''
167
        def creator():
168
            gemeentes = self.list_gemeenten()
169
            res = []
170
            for g in gemeentes:
171
                res += self.list_kadastrale_afdelingen_by_gemeente(g)
172
            return res
173
        if self.caches['permanent'].is_configured:
174
            key = 'list_afdelingen_rest'
175
            afdelingen = self.caches['permanent'].get_or_create(key, creator)
176
        else:
177
            afdelingen = creator()
178
        return afdelingen
179
180
    def list_kadastrale_afdelingen_by_gemeente(self, gemeente, sort=1):
181
        '''
182
        List all `kadastrale afdelingen` in a `gemeente`.
183
184
        :param gemeente: The :class:`Gemeente` for which the \
185
            `afdelingen` are wanted.
186
        :param integer sort: Field to sort on.
187
        :rtype: A :class:`list` of :class:`Afdeling`.
188
        '''
189
        try:
190
            gid = gemeente.id
191
        except AttributeError:
192
            gid = gemeente
193
            gemeente = self.get_gemeente_by_id(gid)
194
        gemeente.clear_gateway()
195
196
        def creator():
197
            url = self.base_url + '/municipality/%s/department' % gid
198
            h = self.base_headers
199
            p = {
200
                'orderbyCode': sort == 1
201
            }
202
            res = capakey_rest_gateway_request(url, h, p).json()
203
            return [
204
                Afdeling(
205
                    id=r['departmentCode'],
206
                    naam=r['departmentName'],
207
                    gemeente=gemeente
208
                ) for r in res['departments']]
209
        if self.caches['permanent'].is_configured:
210
            key = 'list_kadastrale_afdelingen_by_gemeente_rest#%s#%s' % (gid, sort)
211
            afdelingen = self.caches['permanent'].get_or_create(key, creator)
212
        else:
213
            afdelingen = creator()
214
        for a in afdelingen:
215
            a.set_gateway(self)
216
        return afdelingen
217
218
    def get_kadastrale_afdeling_by_id(self, aid):
219
        '''
220
        Retrieve a 'kadastrale afdeling' by id.
221
222
        :param aid: An id of a `kadastrale afdeling`.
223
        :rtype: A :class:`Afdeling`.
224
        '''
225
        def creator():
226
            url = self.base_url + '/department/%s' % (aid)
227
            h = self.base_headers
228
            p = {
229
                'geometry': 'bbox',
230
                'srs': '31370'
231
            }
232
            res = capakey_rest_gateway_request(url, h, p).json()
233
            return Afdeling(
234
                id=res['departmentCode'],
235
                naam=res['departmentName'],
236
                gemeente=Gemeente(res['municipalityCode'], res['municipalityName']),
237
                centroid=self._parse_centroid(res['geometry']['center']),
238
                bounding_box=self._parse_bounding_box(res['geometry']['boundingBox'])
239
            )
240
        if self.caches['long'].is_configured:
241
            key = 'get_kadastrale_afdeling_by_id_rest#%s' % aid
242
            afdeling = self.caches['long'].get_or_create(key, creator)
243
        else:
244
            afdeling = creator()
245
        afdeling.set_gateway(self)
246
        return afdeling
247
248
    def list_secties_by_afdeling(self, afdeling):
249
        '''
250
        List all `secties` in a `kadastrale afdeling`.
251
252
        :param afdeling: The :class:`Afdeling` for which the `secties` are \
253
            wanted. Can also be the id of and `afdeling`.
254
        :rtype: A :class:`list` of `Sectie`.
255
        '''
256
        try:
257
            aid = afdeling.id
258
            gid = afdeling.gemeente.id
259
        except AttributeError:
260
            aid = afdeling
261
            afdeling = self.get_kadastrale_afdeling_by_id(aid)
262
            gid = afdeling.gemeente.id
263
        afdeling.clear_gateway()
264
265
        def creator():
266
            url = self.base_url + '/municipality/%s/department/%s/section' % (gid, aid)
267
            h = self.base_headers
268
            res = capakey_rest_gateway_request(url, h).json()
269
            return [
270
                Sectie(
271
                    r['sectionCode'],
272
                    afdeling
273
                ) for r in res['sections']
274
            ]
275
        if self.caches['long'].is_configured:
276
            key = 'list_secties_by_afdeling_rest#%s' % aid
277
            secties = self.caches['long'].get_or_create(key, creator)
278
        else:
279
            secties = creator()
280
        for s in secties:
281
            s.set_gateway(self)
282
        return secties
283
284
    def get_sectie_by_id_and_afdeling(self, id, afdeling):
285
        '''
286
        Get a `sectie`.
287
288
        :param id: An id of a sectie. eg. "A"
289
        :param afdeling: The :class:`Afdeling` for in which the `sectie` can \
290
            be found. Can also be the id of and `afdeling`.
291
        :rtype: A :class:`Sectie`.
292
        '''
293
        try:
294
            aid = afdeling.id
295
        except AttributeError:
296
            aid = afdeling
297
            afdeling = self.get_kadastrale_afdeling_by_id(aid)
298
        afdeling.clear_gateway()
299
300
        def creator():
301 View Code Duplication
            url = self.base_url + '/municipality/%s/department/%s/section/%s' % (afdeling.gemeente.id, afdeling.id, id)
302
            h = self.base_headers
303
            p = {
304
                'geometry': 'bbox',
305
                'srs': '31370'
306
            }
307
            res = capakey_rest_gateway_request(url, h, p).json()
308
            return Sectie(
309
                res['sectionCode'],
310
                afdeling,
311
                self._parse_centroid(res['geometry']['center']),
312
                self._parse_bounding_box(res['geometry']['boundingBox'])
313
            )
314
        if self.caches['long'].is_configured:
315
            key = 'get_sectie_by_id_and_afdeling_rest#%s#%s' % (id, aid)
316
            sectie = self.caches['long'].get_or_create(key, creator)
317
        else:
318
            sectie = creator()
319
        sectie.set_gateway(self)
320
        return sectie
321
322
    def parse_percid(self, capakey):
323
        import re
324
        match = re.match(
325
            r"^([0-9]{5})([A-Z]{1})([0-9]{4})\/([0-9]{2})([A-Z\_]{1})([0-9]{3})$",
326
            capakey
327
        )
328
        if match:
329
            percid = match.group(1) + '_' + match.group(2) +\
330
                '_' + match.group(3) + '_' + match.group(5) + '_' +\
331
                match.group(6) + '_' + match.group(4)
332
            return percid
333
        else:
334
            raise ValueError(
335
                "Invalid Capakey %s can't be parsed" % capakey
336
            )
337
338
    def parse_capakey(self, percid):
339
        import re
340
        match = re.match(
341
            r"^([0-9]{5})_([A-Z]{1})_([0-9]{4})_([A-Z\_]{1})_([0-9]{3})_([0-9]{2})$",
342
            percid
343
        )
344
        if match:
345
            capakey = match.group(1) + match.group(2) +\
346
                match.group(3) + '/' + match.group(5) + '_' +\
347
                match.group(6) + '_' + match.group(4)
348
            return capakey
349
        else:
350
            raise ValueError(
351
                "Invalid percid %s can't be parsed" % percid
352
            )
353
354
    def list_percelen_by_sectie(self, sectie):
355
        '''
356
        List all percelen in a `sectie`.
357
358
        :param sectie: The :class:`Sectie` for which the percelen are wanted.
359
        :param integer sort: Field to sort on.
360
        :rtype: A :class:`list` of :class:`Perceel`.
361
        '''
362
        sid = sectie.id
363
        aid = sectie.afdeling.id
364
        gid = sectie.afdeling.gemeente.id
365
        sectie.clear_gateway()
366
        def creator():
367
            url = self.base_url + '/municipality/%s/department/%s/section/%s/parcel' % (gid, aid, sid)
368
            h = self.base_headers
369
            p = {
370
                'data': 'cadmap'
371
            }
372
            res = capakey_rest_gateway_request(url, h, p).json()
373
            return [
374
                Perceel(
375
                    r['perceelnummer'],
376
                    sectie,
377
                    r['capakey'],
378
                    self.parse_percid(r['capakey']),
379
                ) for r in res['parcels']
380
            ]
381
        if self.caches['short'].is_configured:
382
            key = 'list_percelen_by_sectie_rest#%s#%s#%s' % (gid, aid, sid)
383
            percelen = self.caches['short'].get_or_create(key, creator)
384
        else:
385
            percelen = creator()
386
        for p in percelen:
387
            p.set_gateway(self)
388
        return percelen
389
390
    def get_perceel_by_id_and_sectie(self, id, sectie):
391
        '''
392
        Get a `perceel`.
393
394
        :param id: An id for a `perceel`.
395
        :param sectie: The :class:`Sectie` that contains the perceel.
396
        :rtype: :class:`Perceel`
397
        '''
398
        sid = sectie.id
399
        aid = sectie.afdeling.id
400
        gid = sectie.afdeling.gemeente.id
401
        sectie.clear_gateway()
402
        def creator():
403 View Code Duplication
            url = self.base_url + '/municipality/%s/department/%s/section/%s/parcel/%s' % (gid, aid, sid, id)
404
            h = self.base_headers
405
            p = {
406
                'geometry': 'bbox',
407
                'srs': '31370',
408
                'data': 'cadmap'
409
            }
410
            res = capakey_rest_gateway_request(url, p, h).json()
411
            return Perceel(
412
                res['perceelnummer'],
413
                sectie,
414
                res['capakey'],
415
                Perceel.get_percid_from_capakey(res['capakey']),
416
                None,
417
                None,
418
                self._parse_centroid(res['geometry']['center']),
419
                self._parse_bounding_box(res['geometry']['boundingBox'])
420
            )
421
        if self.caches['short'].is_configured:
422
            key = 'get_perceel_by_id_and_sectie_rest#%s#%s#%s' % (id, sectie.id, sectie.afdeling.id)
423
            perceel = self.caches['short'].get_or_create(key, creator)
424
        else:
425
            perceel = creator()
426
        perceel.set_gateway(self)
427
        return perceel
428
429
    def get_perceel_by_capakey(self, capakey):
430
        '''
431
        Get a `perceel`.
432
433
        :param capakey: An capakey for a `perceel`.
434
        :rtype: :class:`Perceel`
435
        '''
436
        def creator():
437
            url = self.base_url + '/parcel/%s' % capakey
438
            h = self.base_headers
439
            p = {
440
                'geometry': 'bbox',
441
                'srs': '31370',
442
                'data': 'cadmap'
443
            }
444
            res = capakey_rest_gateway_request(url, p, h).json()
445
            return Perceel(
446
                res['perceelnummer'],
447
                Sectie(
448
                    res['sectionCode'],
449
                    Afdeling(
450
                        res['departmentCode'],
451
                        res['departmentName'],
452
                        Gemeente(res['municipalityCode'], res['municipalityName'])
453
                    )
454
                ),
455
                res['capakey'],
456
                Perceel.get_percid_from_capakey(res['capakey']),
457
                None,
458
                None,
459
                self._parse_centroid(res['geometry']['center']),
460
                self._parse_bounding_box(res['geometry']['boundingBox'])
461
            )
462
        if self.caches['short'].is_configured:
463
            key = 'get_perceel_by_capakey_rest#%s' % capakey
464
            perceel = self.caches['short'].get_or_create(key, creator)
465
        else:
466
            perceel = creator()
467
        perceel.set_gateway(self)
468
        return perceel
469
470
    def get_perceel_by_percid(self, percid):
471
        '''
472
        Get a `perceel`.
473
474
        :param percid: A percid for a `perceel`.
475
        :rtype: :class:`Perceel`
476
        '''
477
        return self.get_perceel_by_capakey(
478
            Perceel.get_capakey_from_percid(percid)
479
        )
480
481
482
class GatewayObject(object):
483
    '''
484
    Abstract class for all objects being returned from the Gateway.
485
    '''
486
487
    gateway = None
488
    '''
489
    The :class:`crabpy.gateway.capakey.CapakeyGateway` to use when making
490
    further calls to the Capakey service.
491
    '''
492
493
    def __init__(self, **kwargs):
494
        if 'gateway' in kwargs:
495
            self.set_gateway(kwargs['gateway'])
496
497
    def set_gateway(self, gateway):
498
        '''
499
        :param crabpy.gateway.capakey.CapakeyGateway gateway: Gateway to use.
500
        '''
501
        self.gateway = gateway
502
503
    def clear_gateway(self):
504
        '''
505
        Clear the currently set CapakeyGateway.
506
        '''
507
        self.gateway = None
508
509
    def check_gateway(self):
510
        '''
511
        Check to see if a gateway was set on this object.
512
        '''
513
        if not self.gateway:
514
            raise RuntimeError("There's no Gateway I can use")
515
516
    if six.PY2:
517
        def __str__(self):
518
            return self.__unicode__().encode('utf-8')
519
    else:
520
        def __str__(self):
521
            return self.__unicode__()
522
523
524
def check_lazy_load_gemeente(f):
525 View Code Duplication
    '''
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
526
    Decorator function to lazy load a :class:`Gemeente`.
527
    '''
528
    def wrapper(self):
529
        gemeente = self
530
        if (getattr(gemeente, '_%s' % f.__name__, None) is None):
531
            log.debug('Lazy loading Gemeente %d', gemeente.id)
532
            gemeente.check_gateway()
533
            g = gemeente.gateway.get_gemeente_by_id(gemeente.id)
534
            gemeente._naam = g._naam
535
            gemeente._centroid = g._centroid
536
            gemeente._bounding_box = g._bounding_box
537
        return f(self)
538
    return wrapper
539
540
541
class Gemeente(GatewayObject):
542
    '''
543
    The smallest administrative unit in Belgium.
544
    '''
545
546
    def __init__(
547
            self, id, naam=None,
548
            centroid=None, bounding_box=None,
549
            **kwargs
550
    ):
551
        self.id = int(id)
552
        self._naam = naam
553
        self._centroid = centroid
554
        self._bounding_box = bounding_box
555
        super(Gemeente, self).__init__(**kwargs)
556
557
    @property
558
    @check_lazy_load_gemeente
559
    def naam(self):
560
        return self._naam
561
562
    @property
563
    @check_lazy_load_gemeente
564
    def centroid(self):
565
        return self._centroid
566
567
    @property
568
    @check_lazy_load_gemeente
569
    def bounding_box(self):
570
        return self._bounding_box
571
572
    @property
573
    def afdelingen(self):
574
        self.check_gateway()
575
        return self.gateway.list_kadastrale_afdelingen_by_gemeente(self)
576
577
    def __unicode__(self):
578
        return '%s (%s)' % (self.naam, self.id)
579
580
    def __repr__(self):
581
        return "Gemeente(%s, '%s')" % (self.id, self.naam)
582
583
584
def check_lazy_load_afdeling(f):
585 View Code Duplication
    '''
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
586
    Decorator function to lazy load a :class:`Afdeling`.
587
    '''
588
    def wrapper(self):
589
        afdeling = self
590
        if (getattr(afdeling, '_%s' % f.__name__, None) is None):
591
            log.debug('Lazy loading Afdeling %d', afdeling.id)
592
            afdeling.check_gateway()
593
            a = afdeling.gateway.get_kadastrale_afdeling_by_id(afdeling.id)
594
            afdeling._naam = a._naam
595
            afdeling._gemeente = a._gemeente
596
            afdeling._centroid = a._centroid
597
            afdeling._bounding_box = a._bounding_box
598
        return f(self)
599
    return wrapper
600
601
602
class Afdeling(GatewayObject):
603
    '''
604
    A Cadastral Division of a :class:`Gemeente`.
605
    '''
606
607
    def __init__(
608
        self, id, naam=None, gemeente=None,
609
        centroid=None, bounding_box=None,
610
        **kwargs
611
    ):
612
        self.id = int(id)
613
        self._naam = naam
614
        self._gemeente = gemeente
615
        self._centroid = centroid
616
        self._bounding_box = bounding_box
617
        super(Afdeling, self).__init__(**kwargs)
618
619
    def set_gateway(self, gateway):
620
        '''
621
        :param crabpy.gateway.capakey.CapakeyGateway gateway: Gateway to use.
622
        '''
623
        self.gateway = gateway
624
        if (self._gemeente is not None):
625
            self._gemeente.set_gateway(gateway)
626
627
    def clear_gateway(self):
628
        '''
629
        Clear the currently set CapakeyGateway.
630
        '''
631
        self.gateway = None
632
        if (self._gemeente is not None):
633
            self._gemeente.clear_gateway()
634
635
    @property
636
    @check_lazy_load_afdeling
637
    def naam(self):
638
        return self._naam
639
640
    @property
641
    @check_lazy_load_afdeling
642
    def gemeente(self):
643
        return self._gemeente
644
645
    @property
646
    @check_lazy_load_afdeling
647
    def centroid(self):
648
        return self._centroid
649
650
    @property
651
    @check_lazy_load_afdeling
652
    def bounding_box(self):
653
        return self._bounding_box
654
655
    @property
656
    def secties(self):
657
        self.check_gateway()
658
        return self.gateway.list_secties_by_afdeling(self)
659
660
    def __unicode__(self):
661
        if self._naam is not None:
662
            return '%s (%s)' % (self._naam, self.id)
663
        else:
664
            return 'Afdeling %s' % (self.id)
665
666
    def __repr__(self):
667
        if self._naam is not None:
668
            return "Afdeling(%s, '%s')" % (self.id, self._naam)
669
        else:
670
            return 'Afdeling(%s)' % (self.id)
671
672
673
def check_lazy_load_sectie(f):
674 View Code Duplication
    '''
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
675
    Decorator function to lazy load a :class:`Sectie`.
676
    '''
677
    def wrapper(self):
678
        sectie = self
679
        if (getattr(sectie, '_%s' % f.__name__, None) is None):
680
            log.debug('Lazy loading Sectie %s in Afdeling %d', sectie.id, sectie.afdeling.id)
681
            sectie.check_gateway()
682
            s = sectie.gateway.get_sectie_by_id_and_afdeling(
683
                sectie.id, sectie.afdeling.id
684
            )
685
            sectie._centroid = s._centroid
686
            sectie._bounding_box = s._bounding_box
687
        return f(self)
688
    return wrapper
689
690
691
class Sectie(GatewayObject):
692
    '''
693
    A subdivision of a :class:`Afdeling`.
694
    '''
695
696
    def __init__(
697
        self, id, afdeling,
698
        centroid=None, bounding_box=None,
699
        **kwargs
700
    ):
701
        self.id = id
702
        self.afdeling = afdeling
703
        self._centroid = centroid
704
        self._bounding_box = bounding_box
705
        super(Sectie, self).__init__(**kwargs)
706
707
    def set_gateway(self, gateway):
708
        '''
709
        :param crabpy.gateway.capakey.CapakeyGateway gateway: Gateway to use.
710 View Code Duplication
        '''
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
711
        self.gateway = gateway
712
        self.afdeling.set_gateway(gateway)
713
714
    def clear_gateway(self):
715
        '''
716
        Clear the currently set CapakeyGateway.
717
        '''
718
        self.gateway = None
719
        self.afdeling.clear_gateway()
720
721
    @property
722
    @check_lazy_load_sectie
723
    def centroid(self):
724
        return self._centroid
725
726
    @property
727
    @check_lazy_load_sectie
728
    def bounding_box(self):
729
        return self._bounding_box
730
731
    @property
732
    def percelen(self):
733
        self.check_gateway()
734
        return self.gateway.list_percelen_by_sectie(self)
735
736
    def __unicode__(self):
737
        return '%s, Sectie %s' % (self.afdeling, self.id)
738
739
    def __repr__(self):
740
        return "Sectie('%s', %s)" % (self.id, repr(self.afdeling))
741
742
743
def check_lazy_load_perceel(f):
744
    '''
745
    Decorator function to lazy load a :class:`Perceel`.
746
    '''
747
    def wrapper(self):
748
        perceel = self
749
        if (getattr(perceel, '_%s' % f.__name__, None) is None):
750
            log.debug(
751
                'Lazy loading Perceel %s in Sectie %s in Afdeling %d',
752
                perceel.id,
753
                perceel.sectie.id,
754
                perceel.sectie.afdeling.id
755
            )
756
            perceel.check_gateway()
757
            p = perceel.gateway.get_perceel_by_id_and_sectie(
758
                perceel.id,
759
                perceel.sectie
760
            )
761
            perceel._centroid = p._centroid
762
            perceel._bounding_box = p._bounding_box
763
            perceel._capatype = p._capatype
764
            perceel._cashkey = p._cashkey
765
        return f(self)
766
    return wrapper
767
768
769
class Perceel(GatewayObject):
770
    '''
771
    A Cadastral Parcel.
772
    '''
773
774
    def __init__(
775
        self, id, sectie, capakey, percid,
776
        capatype=None, cashkey=None,
777
        centroid=None, bounding_box=None,
778
        **kwargs
779
    ):
780 View Code Duplication
        self.id = id
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
781
        self.sectie = sectie
782
        self.capakey = capakey
783
        self.percid = percid
784
        self._capatype = capatype
785
        self._cashkey = cashkey
786
        self._centroid = centroid
787
        self._bounding_box = bounding_box
788
        super(Perceel, self).__init__(**kwargs)
789
        self._split_capakey()
790
791
    def set_gateway(self, gateway):
792
        '''
793
        :param crabpy.gateway.capakey.CapakeyGateway gateway: Gateway to use.
794
        '''
795
        self.gateway = gateway
796
        self.sectie.set_gateway(gateway)
797
798
    def clear_gateway(self):
799
        '''
800
        Clear the currently set CapakeyGateway.
801
        '''
802
        self.gateway = None
803
        self.sectie.clear_gateway()
804
805
    @staticmethod
806
    def get_percid_from_capakey(capakey):
807
        import re
808
        match = re.match(
809
            r"^([0-9]{5})([A-Z]{1})([0-9]{4})\/([0-9]{2})([A-Z\_]{1})([0-9]{3})$",
810
            capakey
811
        )
812
        if match:
813
            percid = match.group(1) + '_' + match.group(2) +\
814
                '_' + match.group(3) + '_' + match.group(5) + '_' +\
815
                match.group(6) + '_' + match.group(4)
816
            return percid
817
        else:
818
            raise ValueError(
819
                "Invalid Capakey %s can't be parsed" % capakey
820
            )
821
822
    @staticmethod
823
    def get_capakey_from_percid(percid):
824
        import re
825
        match = re.match(
826
            r"^([0-9]{5})_([A-Z]{1})_([0-9]{4})_([A-Z\_]{1})_([0-9]{3})_([0-9]{2})$",
827
            percid
828
        )
829
        if match:
830
            capakey = match.group(1) + match.group(2) +\
831
                match.group(3) + '/' + match.group(6) +\
832
                match.group(4) + match.group(5)
833
            return capakey
834
        else:
835
            raise ValueError(
836
                "Invalid percid %s can't be parsed" % percid
837
            )
838
839
    def _split_capakey(self):
840
        '''
841
        Split a capakey into more readable elements.
842
843
        Splits a capakey into it's grondnummer, bisnummer, exponent and macht.
844
        '''
845
        import re
846
        match = re.match(
847
            r"^[0-9]{5}[A-Z]{1}([0-9]{4})\/([0-9]{2})([A-Z\_]{1})([0-9]{3})$",
848
            self.capakey
849
        )
850
        if match:
851
            self.grondnummer = match.group(1)
852
            self.bisnummer = match.group(2)
853
            self.exponent = match.group(3)
854
            self.macht = match.group(4)
855
        else:
856
            raise ValueError(
857
                "Invalid Capakey %s can't be parsed" % self.capakey
858
            )
859
860
    @property
861
    @check_lazy_load_perceel
862
    def centroid(self):
863
        return self._centroid
864
865
    @property
866
    @check_lazy_load_perceel
867
    def bounding_box(self):
868
        return self._bounding_box
869
870
    @property
871
    @check_lazy_load_perceel
872
    def capatype(self):
873
        return self._capatype
874
875
    @property
876
    @check_lazy_load_perceel
877
    def cashkey(self):
878
        return self._cashkey
879
880
    def __unicode__(self):
881
        return self.capakey
882
883
    def __repr__(self):
884
        return "Perceel('%s', %s, '%s', '%s')" % (
885
            self.id, repr(self.sectie), self.capakey, self.percid
886
        )
887