| Total Complexity | 56 |
| Total Lines | 427 |
| Duplicated Lines | 22.95 % |
| 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 -*- |
||
| 478 | class CapakeyRestGateway(object): |
||
| 479 | ''' |
||
| 480 | A REST gateway to the capakey webservice. |
||
| 481 | |||
| 482 | .. versionadded:: 0.8.0 |
||
| 483 | View Code Duplication | ''' |
|
| 484 | |||
| 485 | caches = {} |
||
| 486 | |||
| 487 | def __init__(self, **kwargs): |
||
| 488 | self.base_url = kwargs.get( |
||
| 489 | 'base_url', |
||
| 490 | 'https://geoservices.informatievlaanderen.be/capakey/api/v0.1' |
||
| 491 | ) |
||
| 492 | self.base_headers = { |
||
| 493 | 'Accept': 'application/json' |
||
| 494 | } |
||
| 495 | cache_regions = ['permanent', 'long', 'short'] |
||
| 496 | for cr in cache_regions: |
||
| 497 | self.caches[cr] = make_region(key_mangler=str) |
||
| 498 | if 'cache_config' in kwargs: |
||
| 499 | for cr in cache_regions: |
||
| 500 | if ('%s.backend' % cr) in kwargs['cache_config']: |
||
| 501 | log.debug('Configuring %s region on CapakeyRestGateway', cr) |
||
| 502 | self.caches[cr].configure_from_config( |
||
| 503 | kwargs['cache_config'], |
||
| 504 | '%s.' % cr |
||
| 505 | ) |
||
| 506 | |||
| 507 | @staticmethod |
||
| 508 | def _parse_centroid(center): |
||
| 509 | ''' |
||
| 510 | Parse response center from the CapakeyRestGateway to (CenterX, CenterY) |
||
| 511 | |||
| 512 | :param center: response center from the CapakeyRestGateway |
||
| 513 | :return: (CenterX, CenterY) |
||
| 514 | ''' |
||
| 515 | coordinates = json.loads(center)["coordinates"] |
||
| 516 | return coordinates[0], coordinates[1] |
||
| 517 | |||
| 518 | @staticmethod |
||
| 519 | def _parse_bounding_box(bounding_box): |
||
| 520 | ''' |
||
| 521 | Parse response bounding box from the CapakeyRestGateway to (MinimumX, MinimumY, MaximumX, MaximumY) |
||
| 522 | |||
| 523 | :param bounding_box: response bounding box from the CapakeyRestGateway |
||
| 524 | :return: (MinimumX, MinimumY, MaximumX, MaximumY) |
||
| 525 | ''' |
||
| 526 | coordinates = json.loads(bounding_box)["coordinates"] |
||
| 527 | x_coords = [x for x, y in coordinates[0]] |
||
| 528 | y_coords = [y for x, y in coordinates[0]] |
||
| 529 | return min(x_coords), min(y_coords), max(x_coords), max(y_coords) |
||
| 530 | |||
| 531 | def list_gemeenten(self, sort=1): |
||
| 532 | ''' |
||
| 533 | List all `gemeenten` in Vlaanderen. |
||
| 534 | |||
| 535 | :param integer sort: What field to sort on. |
||
| 536 | :rtype: A :class:`list` of :class:`Gemeente`. |
||
| 537 | ''' |
||
| 538 | def creator(): |
||
| 539 | url = self.base_url + '/municipality' |
||
| 540 | h = self.base_headers |
||
| 541 | p = { |
||
| 542 | 'orderbyCode': sort == 1 |
||
| 543 | } |
||
| 544 | res = capakey_rest_gateway_request(url, h, p).json() |
||
| 545 | return [ |
||
| 546 | Gemeente(r['municipalityCode'], r['municipalityName']) |
||
| 547 | for r in res['municipalities'] |
||
| 548 | ] |
||
| 549 | if self.caches['permanent'].is_configured: |
||
| 550 | key = 'list_gemeenten_rest#%s' % sort |
||
| 551 | gemeente = self.caches['permanent'].get_or_create(key, creator) |
||
| 552 | else: |
||
| 553 | gemeente = creator() |
||
| 554 | for g in gemeente: |
||
| 555 | g.set_gateway(self) |
||
| 556 | return gemeente |
||
| 557 | |||
| 558 | def get_gemeente_by_id(self, id): |
||
| 559 | ''' |
||
| 560 | Retrieve a `gemeente` by id (the NIScode). |
||
| 561 | |||
| 562 | :rtype: :class:`Gemeente` |
||
| 563 | ''' |
||
| 564 | def creator(): |
||
| 565 | url = self.base_url + '/municipality/%s' % id |
||
| 566 | h = self.base_headers |
||
| 567 | p = { |
||
| 568 | 'geometry': 'bbox', |
||
| 569 | 'srs': '31370' |
||
| 570 | } |
||
| 571 | res = capakey_rest_gateway_request(url, h, p).json() |
||
| 572 | return Gemeente( |
||
| 573 | res['municipalityCode'], |
||
| 574 | res['municipalityName'], |
||
| 575 | self._parse_centroid(res['geometry']['center']), |
||
| 576 | self._parse_bounding_box(res['geometry']['boundingBox']) |
||
| 577 | ) |
||
| 578 | if self.caches['long'].is_configured: |
||
| 579 | key = 'get_gemeente_by_id_rest#%s' % id |
||
| 580 | gemeente = self.caches['long'].get_or_create(key, creator) |
||
| 581 | else: |
||
| 582 | gemeente = creator() |
||
| 583 | gemeente.set_gateway(self) |
||
| 584 | return gemeente |
||
| 585 | |||
| 586 | def list_kadastrale_afdelingen(self): |
||
| 587 | ''' |
||
| 588 | List all `kadastrale afdelingen` in Flanders. |
||
| 589 | |||
| 590 | :param integer sort: Field to sort on. |
||
| 591 | :rtype: A :class:`list` of :class:`Afdeling`. |
||
| 592 | ''' |
||
| 593 | def creator(): |
||
| 594 | gemeentes = self.list_gemeenten() |
||
| 595 | res = [] |
||
| 596 | for g in gemeentes: |
||
| 597 | res += self.list_kadastrale_afdelingen_by_gemeente(g) |
||
| 598 | return res |
||
| 599 | if self.caches['permanent'].is_configured: |
||
| 600 | key = 'list_afdelingen_rest' |
||
| 601 | afdelingen = self.caches['permanent'].get_or_create(key, creator) |
||
| 602 | else: |
||
| 603 | afdelingen = creator() |
||
| 604 | return afdelingen |
||
| 605 | |||
| 606 | def list_kadastrale_afdelingen_by_gemeente(self, gemeente, sort=1): |
||
| 607 | ''' |
||
| 608 | List all `kadastrale afdelingen` in a `gemeente`. |
||
| 609 | |||
| 610 | :param gemeente: The :class:`Gemeente` for which the \ |
||
| 611 | `afdelingen` are wanted. |
||
| 612 | :param integer sort: Field to sort on. |
||
| 613 | :rtype: A :class:`list` of :class:`Afdeling`. |
||
| 614 | ''' |
||
| 615 | try: |
||
| 616 | gid = gemeente.id |
||
| 617 | except AttributeError: |
||
| 618 | gid = gemeente |
||
| 619 | gemeente = self.get_gemeente_by_id(gid) |
||
| 620 | gemeente.clear_gateway() |
||
| 621 | |||
| 622 | def creator(): |
||
| 623 | url = self.base_url + '/municipality/%s/department' % gid |
||
| 624 | h = self.base_headers |
||
| 625 | p = { |
||
| 626 | 'orderbyCode': sort == 1 |
||
| 627 | } |
||
| 628 | res = capakey_rest_gateway_request(url, h, p).json() |
||
| 629 | return [ |
||
| 630 | Afdeling( |
||
| 631 | id=r['departmentCode'], |
||
| 632 | naam=r['departmentName'], |
||
| 633 | gemeente=gemeente |
||
| 634 | ) for r in res['departments']] |
||
| 635 | if self.caches['permanent'].is_configured: |
||
| 636 | key = 'list_kadastrale_afdelingen_by_gemeente_rest#%s#%s' % (gid, sort) |
||
| 637 | afdelingen = self.caches['permanent'].get_or_create(key, creator) |
||
| 638 | else: |
||
| 639 | afdelingen = creator() |
||
| 640 | for a in afdelingen: |
||
| 641 | a.set_gateway(self) |
||
| 642 | return afdelingen |
||
| 643 | |||
| 644 | def get_kadastrale_afdeling_by_id(self, aid): |
||
| 645 | ''' |
||
| 646 | Retrieve a 'kadastrale afdeling' by id. |
||
| 647 | |||
| 648 | :param aid: An id of a `kadastrale afdeling`. |
||
| 649 | :rtype: A :class:`Afdeling`. |
||
| 650 | ''' |
||
| 651 | def creator(): |
||
| 652 | url = self.base_url + '/department/%s' % (aid) |
||
| 653 | h = self.base_headers |
||
| 654 | p = { |
||
| 655 | 'geometry': 'bbox', |
||
| 656 | 'srs': '31370' |
||
| 657 | } |
||
| 658 | res = capakey_rest_gateway_request(url, h, p).json() |
||
| 659 | return Afdeling( |
||
| 660 | id=res['departmentCode'], |
||
| 661 | naam=res['departmentName'], |
||
| 662 | gemeente=Gemeente(res['municipalityCode'], res['municipalityName']), |
||
| 663 | centroid=self._parse_centroid(res['geometry']['center']), |
||
| 664 | bounding_box=self._parse_bounding_box(res['geometry']['boundingBox']) |
||
| 665 | ) |
||
| 666 | if self.caches['long'].is_configured: |
||
| 667 | key = 'get_kadastrale_afdeling_by_id_rest#%s' % aid |
||
| 668 | afdeling = self.caches['long'].get_or_create(key, creator) |
||
| 669 | else: |
||
| 670 | afdeling = creator() |
||
| 671 | afdeling.set_gateway(self) |
||
| 672 | return afdeling |
||
| 673 | |||
| 674 | def list_secties_by_afdeling(self, afdeling): |
||
| 675 | ''' |
||
| 676 | List all `secties` in a `kadastrale afdeling`. |
||
| 677 | |||
| 678 | :param afdeling: The :class:`Afdeling` for which the `secties` are \ |
||
| 679 | wanted. Can also be the id of and `afdeling`. |
||
| 680 | :rtype: A :class:`list` of `Sectie`. |
||
| 681 | ''' |
||
| 682 | try: |
||
| 683 | aid = afdeling.id |
||
| 684 | gid = afdeling.gemeente.id |
||
| 685 | except AttributeError: |
||
| 686 | aid = afdeling |
||
| 687 | afdeling = self.get_kadastrale_afdeling_by_id(aid) |
||
| 688 | gid = afdeling.gemeente.id |
||
| 689 | afdeling.clear_gateway() |
||
| 690 | |||
| 691 | def creator(): |
||
| 692 | url = self.base_url + '/municipality/%s/department/%s/section' % (gid, aid) |
||
| 693 | h = self.base_headers |
||
| 694 | res = capakey_rest_gateway_request(url, h).json() |
||
| 695 | return [ |
||
| 696 | Sectie( |
||
| 697 | r['sectionCode'], |
||
| 698 | afdeling |
||
| 699 | ) for r in res['sections'] |
||
| 700 | ] |
||
| 701 | if self.caches['long'].is_configured: |
||
| 702 | key = 'list_secties_by_afdeling_rest#%s' % aid |
||
| 703 | secties = self.caches['long'].get_or_create(key, creator) |
||
| 704 | else: |
||
| 705 | secties = creator() |
||
| 706 | for s in secties: |
||
| 707 | s.set_gateway(self) |
||
| 708 | return secties |
||
| 709 | |||
| 710 | View Code Duplication | def get_sectie_by_id_and_afdeling(self, id, afdeling): |
|
| 711 | ''' |
||
| 712 | Get a `sectie`. |
||
| 713 | |||
| 714 | :param id: An id of a sectie. eg. "A" |
||
| 715 | :param afdeling: The :class:`Afdeling` for in which the `sectie` can \ |
||
| 716 | be found. Can also be the id of and `afdeling`. |
||
| 717 | :rtype: A :class:`Sectie`. |
||
| 718 | ''' |
||
| 719 | try: |
||
| 720 | aid = afdeling.id |
||
| 721 | except AttributeError: |
||
| 722 | aid = afdeling |
||
| 723 | afdeling = self.get_kadastrale_afdeling_by_id(aid) |
||
| 724 | afdeling.clear_gateway() |
||
| 725 | |||
| 726 | def creator(): |
||
| 727 | url = self.base_url + '/municipality/%s/department/%s/section/%s' % (afdeling.gemeente.id, afdeling.id, id) |
||
| 728 | h = self.base_headers |
||
| 729 | p = { |
||
| 730 | 'geometry': 'bbox', |
||
| 731 | 'srs': '31370' |
||
| 732 | } |
||
| 733 | res = capakey_rest_gateway_request(url, h, p).json() |
||
| 734 | return Sectie( |
||
| 735 | res['sectionCode'], |
||
| 736 | afdeling, |
||
| 737 | self._parse_centroid(res['geometry']['center']), |
||
| 738 | self._parse_bounding_box(res['geometry']['boundingBox']) |
||
| 739 | ) |
||
| 740 | if self.caches['long'].is_configured: |
||
| 741 | key = 'get_sectie_by_id_and_afdeling_rest#%s#%s' % (id, aid) |
||
| 742 | sectie = self.caches['long'].get_or_create(key, creator) |
||
| 743 | else: |
||
| 744 | sectie = creator() |
||
| 745 | sectie.set_gateway(self) |
||
| 746 | return sectie |
||
| 747 | |||
| 748 | def parse_percid(self, capakey): |
||
| 749 | import re |
||
| 750 | match = re.match( |
||
| 751 | r"^([0-9]{5})([A-Z]{1})([0-9]{4})\/([0-9]{2})([A-Z\_]{1})([0-9]{3})$", |
||
| 752 | capakey |
||
| 753 | ) |
||
| 754 | if match: |
||
| 755 | percid = match.group(1) + '_' + match.group(2) +\ |
||
| 756 | '_' + match.group(3) + '_' + match.group(5) + '_' +\ |
||
| 757 | match.group(6) + '_' + match.group(4) |
||
| 758 | return percid |
||
| 759 | else: |
||
| 760 | raise ValueError( |
||
| 761 | "Invalid Capakey %s can't be parsed" % capakey |
||
| 762 | ) |
||
| 763 | |||
| 764 | def parse_capakey(self, percid): |
||
| 765 | import re |
||
| 766 | match = re.match( |
||
| 767 | r"^([0-9]{5})_([A-Z]{1})_([0-9]{4})_([A-Z\_]{1})_([0-9]{3})_([0-9]{2})$", |
||
| 768 | percid |
||
| 769 | ) |
||
| 770 | if match: |
||
| 771 | capakey = match.group(1) + match.group(2) +\ |
||
| 772 | match.group(3) + '/' + match.group(5) + '_' +\ |
||
| 773 | match.group(6) + '_' + match.group(4) |
||
| 774 | return capakey |
||
| 775 | else: |
||
| 776 | raise ValueError( |
||
| 777 | "Invalid percid %s can't be parsed" % percid |
||
| 778 | ) |
||
| 779 | |||
| 780 | View Code Duplication | def list_percelen_by_sectie(self, sectie): |
|
| 781 | ''' |
||
| 782 | List all percelen in a `sectie`. |
||
| 783 | |||
| 784 | :param sectie: The :class:`Sectie` for which the percelen are wanted. |
||
| 785 | :param integer sort: Field to sort on. |
||
| 786 | :rtype: A :class:`list` of :class:`Perceel`. |
||
| 787 | ''' |
||
| 788 | sid = sectie.id |
||
| 789 | aid = sectie.afdeling.id |
||
| 790 | gid = sectie.afdeling.gemeente.id |
||
| 791 | sectie.clear_gateway() |
||
| 792 | def creator(): |
||
| 793 | url = self.base_url + '/municipality/%s/department/%s/section/%s/parcel' % (gid, aid, sid) |
||
| 794 | h = self.base_headers |
||
| 795 | p = { |
||
| 796 | 'data': 'cadmap' |
||
| 797 | } |
||
| 798 | res = capakey_rest_gateway_request(url, h, p).json() |
||
| 799 | return [ |
||
| 800 | Perceel( |
||
| 801 | r['perceelnummer'], |
||
| 802 | sectie, |
||
| 803 | r['capakey'], |
||
| 804 | self.parse_percid(r['capakey']), |
||
| 805 | ) for r in res['parcels'] |
||
| 806 | ] |
||
| 807 | if self.caches['short'].is_configured: |
||
| 808 | key = 'list_percelen_by_sectie_rest#%s#%s#%s' % (gid, aid, sid) |
||
| 809 | percelen = self.caches['short'].get_or_create(key, creator) |
||
| 810 | else: |
||
| 811 | percelen = creator() |
||
| 812 | for p in percelen: |
||
| 813 | p.set_gateway(self) |
||
| 814 | return percelen |
||
| 815 | |||
| 816 | def get_perceel_by_id_and_sectie(self, id, sectie): |
||
| 817 | ''' |
||
| 818 | Get a `perceel`. |
||
| 819 | |||
| 820 | :param id: An id for a `perceel`. |
||
| 821 | :param sectie: The :class:`Sectie` that contains the perceel. |
||
| 822 | :rtype: :class:`Perceel` |
||
| 823 | ''' |
||
| 824 | sid = sectie.id |
||
| 825 | aid = sectie.afdeling.id |
||
| 826 | gid = sectie.afdeling.gemeente.id |
||
| 827 | sectie.clear_gateway() |
||
| 828 | def creator(): |
||
| 829 | url = self.base_url + '/municipality/%s/department/%s/section/%s/parcel/%s' % (gid, aid, sid, id) |
||
| 830 | h = self.base_headers |
||
| 831 | p = { |
||
| 832 | 'geometry': 'bbox', |
||
| 833 | 'srs': '31370', |
||
| 834 | 'data': 'cadmap' |
||
| 835 | } |
||
| 836 | res = capakey_rest_gateway_request(url, p, h).json() |
||
| 837 | return Perceel( |
||
| 838 | res['perceelnummer'], |
||
| 839 | sectie, |
||
| 840 | res['capakey'], |
||
| 841 | Perceel.get_percid_from_capakey(res['capakey']), |
||
| 842 | None, |
||
| 843 | None, |
||
| 844 | self._parse_centroid(res['geometry']['center']), |
||
| 845 | self._parse_bounding_box(res['geometry']['boundingBox']) |
||
| 846 | ) |
||
| 847 | if self.caches['short'].is_configured: |
||
| 848 | key = 'get_perceel_by_id_and_sectie_rest#%s#%s#%s' % (id, sectie.id, sectie.afdeling.id) |
||
| 849 | perceel = self.caches['short'].get_or_create(key, creator) |
||
| 850 | else: |
||
| 851 | perceel = creator() |
||
| 852 | perceel.set_gateway(self) |
||
| 853 | return perceel |
||
| 854 | |||
| 855 | def get_perceel_by_capakey(self, capakey): |
||
| 856 | ''' |
||
| 857 | Get a `perceel`. |
||
| 858 | |||
| 859 | :param capakey: An capakey for a `perceel`. |
||
| 860 | :rtype: :class:`Perceel` |
||
| 861 | ''' |
||
| 862 | def creator(): |
||
| 863 | url = self.base_url + '/parcel/%s' % capakey |
||
| 864 | h = self.base_headers |
||
| 865 | p = { |
||
| 866 | 'geometry': 'bbox', |
||
| 867 | 'srs': '31370', |
||
| 868 | 'data': 'cadmap' |
||
| 869 | } |
||
| 870 | res = capakey_rest_gateway_request(url, p, h).json() |
||
| 871 | return Perceel( |
||
| 872 | res['perceelnummer'], |
||
| 873 | Sectie( |
||
| 874 | res['sectionCode'], |
||
| 875 | Afdeling( |
||
| 876 | res['departmentCode'], |
||
| 877 | res['departmentName'], |
||
| 878 | Gemeente(res['municipalityCode'], res['municipalityName']) |
||
| 879 | ) |
||
| 880 | ), |
||
| 881 | res['capakey'], |
||
| 882 | Perceel.get_percid_from_capakey(res['capakey']), |
||
| 883 | None, |
||
| 884 | None, |
||
| 885 | self._parse_centroid(res['geometry']['center']), |
||
| 886 | self._parse_bounding_box(res['geometry']['boundingBox']) |
||
| 887 | ) |
||
| 888 | if self.caches['short'].is_configured: |
||
| 889 | key = 'get_perceel_by_capakey_rest#%s' % capakey |
||
| 890 | perceel = self.caches['short'].get_or_create(key, creator) |
||
| 891 | else: |
||
| 892 | perceel = creator() |
||
| 893 | perceel.set_gateway(self) |
||
| 894 | return perceel |
||
| 895 | |||
| 896 | def get_perceel_by_percid(self, percid): |
||
| 897 | ''' |
||
| 898 | Get a `perceel`. |
||
| 899 | |||
| 900 | :param percid: A percid for a `perceel`. |
||
| 901 | :rtype: :class:`Perceel` |
||
| 902 | ''' |
||
| 903 | return self.get_perceel_by_capakey( |
||
| 904 | Perceel.get_capakey_from_percid(percid) |
||
| 905 | ) |
||
| 1313 |