Completed
Pull Request — master (#93)
by Koen
31s
created

CapakeyGateway.get_sectie_by_id_and_afdeling()   B

Complexity

Conditions 5

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

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