| Total Complexity | 56 |
| Total Lines | 427 |
| Duplicated Lines | 16.39 % |
| Changes | 6 | ||
| Bugs | 0 | Features | 2 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like CapakeyRestGateway often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | # -*- coding: utf-8 -*- |
||
| 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 | ''' |
|
|
|
|||
| 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 | ) |
||
| 887 |