Completed
Push — master ( edf034...176adb )
by
unknown
10s
created

crabpy/gateway/capakey.py (3 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
        '''
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
            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 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...
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
            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 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...
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
            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 View Code Duplication
class GatewayObject(object):
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
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
    '''
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
    '''
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
    '''
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
        '''
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
        self.id = id
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