Example #1
0
    def test_subdivision_derived_fields(self):
        address = Address(line1='31, place du Théatre',
                          postal_code='59000',
                          city_name='Lille',
                          subdivision_code='FR-59')

        self.assertEquals(address.subdivision, subdivisions.get(code='FR-59'))
        self.assertEquals(address.subdivision_code, 'FR-59')
        self.assertEquals(address.subdivision_name, 'Nord')
        self.assertEquals(address.subdivision_type_name,
                          'Metropolitan department')
        self.assertEquals(address.subdivision_type_id,
                          'metropolitan_department')

        self.assertEquals(address.metropolitan_department,
                          subdivisions.get(code='FR-59'))
        self.assertEquals(address.metropolitan_department_area_code, 'FR-59')
        self.assertEquals(address.metropolitan_department_name, 'Nord')
        self.assertEquals(address.metropolitan_department_type_name,
                          'Metropolitan department')

        self.assertEquals(address.metropolitan_region,
                          subdivisions.get(code='FR-HDF'))
        self.assertEquals(address.metropolitan_region_area_code, 'FR-HDF')
        self.assertEquals(address.metropolitan_region_name, 'Hauts-de-France')
        self.assertEquals(address.metropolitan_region_type_name,
                          'Metropolitan region')

        self.assertEquals(address.country, countries.get(alpha_2='FR'))
        self.assertEquals(address.country_code, 'FR')
        self.assertEquals(address.country_name, 'France')
Example #2
0
def territory_parents(territory_code, include_country=True):
    """ Return the whole hierarchy of territories, up to the country.

    Values returned by the generator are either subdivisions or country
    objects, starting from the provided territory and up its way to the top
    administrative territory (i.e. country).
    """
    tree = []

    # If the provided territory code is a country, return it right away.
    territory_code = normalize_territory_code(territory_code)
    if territory_code in supported_country_codes():
        if include_country:
            tree.append(countries.get(alpha2=territory_code))
        return tree

    # Else, resolve the territory as if it's a subdivision code.
    subdivision_code = territory_code
    while subdivision_code:
        subdiv = subdivisions.get(code=subdivision_code)
        tree.append(subdiv)
        if not subdiv.parent_code:
            break
        subdivision_code = subdiv.parent_code

    # Return country
    if include_country:
        tree.append(subdivisions.get(code=subdivision_code).country)

    return tree
Example #3
0
    def test_subdivision_derived_fields(self) -> None:
        address = Address(
            line1="31, place du Théatre",
            postal_code="59000",
            city_name="Lille",
            subdivision_code="FR-59",
        )

        assert address.subdivision == subdivisions.get(code="FR-59")
        assert address.subdivision_code == "FR-59"
        assert address.subdivision_name == "Nord"
        assert address.subdivision_type_name == "Metropolitan department"
        assert address.subdivision_type_id == "metropolitan_department"

        assert address.metropolitan_department == subdivisions.get(
            code="FR-59")
        assert address.metropolitan_department_area_code == "FR-59"
        assert address.metropolitan_department_name == "Nord"
        assert address.metropolitan_department_type_name == "Metropolitan department"

        assert address.metropolitan_region == subdivisions.get(code="FR-HDF")
        assert address.metropolitan_region_area_code == "FR-HDF"
        assert address.metropolitan_region_name == "Hauts-de-France"
        assert address.metropolitan_region_type_name == "Metropolitan region"

        assert address.country == countries.get(alpha_2="FR")
        assert address.country_code == "FR"
        assert address.country_name == "France"
Example #4
0
    def test_subdivision_derived_city_fields(self):
        address = Address(
            line1='2 King Edward Street',
            postal_code='EC1A 1HQ',
            subdivision_code='GB-LND')

        self.assertEquals(
            address.subdivision, subdivisions.get(code='GB-LND'))
        self.assertEquals(
            address.subdivision_code, 'GB-LND')
        self.assertEquals(
            address.subdivision_name, 'London, City of')
        self.assertEquals(
            address.subdivision_type_name, 'City corporation')
        self.assertEquals(
            address.subdivision_type_id, 'city')

        self.assertEquals(
            address.city, subdivisions.get(code='GB-LND'))
        self.assertEquals(
            address.city_code, 'GB-LND')
        self.assertEquals(
            address.city_name, 'London, City of')
        self.assertEquals(
            address.city_type_name, 'City corporation')

        self.assertEquals(address.country_code, 'GB')
Example #5
0
def territory_parents(territory_code, include_country=True):
    """ Return the whole hierarchy of territories, up to the country.

    Values returned by the generator are either subdivisions or country
    objects, starting from the provided territory and up its way to the top
    administrative territory (i.e. country).
    """
    tree = []

    # Retrieving subdivision from alias to get full paternity
    territory_code = COUNTRY_ALIAS_TO_SUBDIVISION.get(territory_code,
                                                      territory_code)
    # If the provided territory code is a country, return it right away.
    territory_code = normalize_territory_code(territory_code)
    if territory_code in supported_country_codes():
        if include_country:
            tree.append(countries.get(alpha_2=territory_code))
        return tree

    # Else, resolve the territory as if it's a subdivision code.
    subdivision_code = territory_code
    while subdivision_code:
        subdiv = subdivisions.get(code=subdivision_code)
        tree.append(subdiv)
        if not subdiv.parent_code:
            break
        subdivision_code = subdiv.parent_code

    # Return country
    if include_country:
        tree.append(subdivisions.get(code=subdivision_code).country)

    return tree
Example #6
0
 def test_country_from_subdivision(self):
     # Test reconciliation of ISO 3166-2 and ISO 3166-1 country codes.
     for subdiv_code in SUBDIVISION_COUNTRIES.keys():
         target_code = SUBDIVISION_COUNTRIES[subdiv_code]
         if len(target_code) != 2:
             target_code = subdivisions.get(code=target_code).country_code
         self.assertEquals(country_from_subdivision(subdiv_code),
                           target_code)
     for subdiv_code in PYCOUNTRY_SUB.difference(SUBDIVISION_COUNTRIES):
         self.assertEquals(country_from_subdivision(subdiv_code),
                           subdivisions.get(code=subdiv_code).country_code)
 def test_country_from_subdivision(self):
     # Test reconciliation of ISO 3166-2 and ISO 3166-1 country codes.
     for subdiv_code in SUBDIVISION_COUNTRIES.keys():
         target_code = SUBDIVISION_COUNTRIES[subdiv_code]
         if len(target_code) != 2:
             target_code = subdivisions.get(code=target_code).country_code
         self.assertEquals(
             country_from_subdivision(subdiv_code), target_code)
     for subdiv_code in PYCOUNTRY_SUB.difference(SUBDIVISION_COUNTRIES):
         self.assertEquals(
             country_from_subdivision(subdiv_code),
             subdivisions.get(code=subdiv_code).country_code)
Example #8
0
 def test_country_from_subdivision(self):
     # Test reconciliation of ISO 3166-2 and ISO 3166-1 country codes.
     for subdiv_code in SUBDIVISION_ALIASES.keys():
         target_code = SUBDIVISION_ALIASES[subdiv_code]
         if len(target_code) != 2:
             target_code = subdivisions.get(code=target_code).country_code
         self.assertEquals(country_from_subdivision(subdiv_code),
                           target_code)
     for subdiv_code in set(
             map(attrgetter('code'),
                 subdivisions)).difference(SUBDIVISION_ALIASES):
         self.assertEquals(country_from_subdivision(subdiv_code),
                           subdivisions.get(code=subdiv_code).country_code)
 def test_country_from_subdivision(self):
     # Test reconciliation of ISO 3166-2 and ISO 3166-1 country codes.
     for subdiv_code in SUBDIVISION_ALIASES.keys():
         target_code = SUBDIVISION_ALIASES[subdiv_code]
         if len(target_code) != 2:
             target_code = subdivisions.get(code=target_code).country_code
         self.assertEquals(
             country_from_subdivision(subdiv_code), target_code)
     for subdiv_code in set(
             imap(attrgetter('code'), subdivisions)).difference(
                 SUBDIVISION_ALIASES):
         self.assertEquals(
             country_from_subdivision(subdiv_code),
             subdivisions.get(code=subdiv_code).country_code)
Example #10
0
def get_names(locations):
    """Returns a set of possible location names from the Mapquest results"""
    names = {"street": set(),
             "adminArea6": set(),
             "adminArea5": set(),
             "adminArea4": set(),
             "adminArea3": set(),
             "adminArea2": set(),
             "adminArea1": set(),
             "name": set()}
    
    for location in locations:
        for field in names:
            if field in location and location[field] != "":
                if field == "adminArea1":
                    names[field].add(countries.get(alpha_2=location[field]).name)
                elif field == "adminArea3":
                    names[field].add(subdivisions.get(code = "{0}-{1}".format(
                        countries.get(alpha_2 = location["adminArea1"]),
                        location[field]
                    )))
                else:
                    names[field].add(location[field])

    return names
Example #11
0
    def get(self, country_alpha2: str, subdivision_code: str, city_id: int):
        """
        Returns a city record.
        :param country_alpha2: The unique two character identifier of the country record.
        :type country_alpha2: str
        :param subdivision_code: The unique two character identifier of the subdivision record.
        :type subdivision_code: str
        :param city_id: The unique identifier of the city record.
        :type city_id: int
        :return:
        """
        # Validate the country_alpha2 and subdivision_code are valid
        code = '{country_alpha2}-{subdivision_code}'.format(
            country_alpha2=country_alpha2, subdivision_code=subdivision_code)

        try:
            if subdivisions.get(code=code) is None:
                abort(
                    400,
                    'Bad request: country_alpha2 and subdivision_code are invalid'
                )
        except KeyError:
            abort(
                400,
                'Bad request: country_alpha2 and subdivision_code are invalid')

        return City.query.filter(City.id == city_id).one()
Example #12
0
def country_aliases(territory_code):
    """ List valid country code aliases of a territory.

    Mainly used to check if a non-normalized country code can safely be
    replaced by its normalized form.
    """
    country_codes = set()

    # Add a country code right away in our aliases.
    if territory_code in supported_country_codes():
        country_codes.add(territory_code)

    # A subdivision code triggers a walk along the non-normalized parent tree
    # and look for aliases at each level.
    else:
        subdiv = subdivisions.get(code=territory_code)
        parent_code = subdiv.parent_code
        if not parent_code:
            parent_code = subdiv.country.alpha2
        country_codes.update(country_aliases(parent_code))

    # Hunt for aliases
    for mapped_code in REVERSE_MAPPING.get(territory_code, []):
        country_codes.update(country_aliases(mapped_code))

    return country_codes
Example #13
0
    def delete(self, country_alpha2: str, subdivision_code: str, city_id: int):
        """
        Deletes a city record.

        :param country_alpha2: The unique two character identifier of the country record.
        :type country_alpha2: str
        :param subdivision_code: The unique two character identifier of the subdivision record.
        :type subdivision_code: str
        :param city_id: The unique identifier of the city record.
        :type city_id: int
        """
        # Validate the country_alpha2 and subdivision_code are valid
        code = '{country_alpha2}-{subdivision_code}'.format(
            country_alpha2=country_alpha2, subdivision_code=subdivision_code)

        try:
            if subdivisions.get(code=code) is None:
                abort(
                    400,
                    'Bad request: country_alpha2 and subdivision_code are invalid'
                )
        except KeyError:
            abort(
                400,
                'Bad request: country_alpha2 and subdivision_code are invalid')

        delete_city(city_id)
        return None, 204
Example #14
0
def country_aliases(territory_code: str) -> Set[str]:
    """List valid country code aliases of a territory.

    Mainly used to check if a non-normalized country code can safely be
    replaced by its normalized form.
    """
    country_codes = set()

    # Add a country code right away in our aliases.
    if territory_code in supported_country_codes():
        country_codes.add(territory_code)

    # A subdivision code triggers a walk along the non-normalized parent tree
    # and look for aliases at each level.
    else:
        subdiv = subdivisions.get(code=territory_code)
        parent_code = subdiv.parent_code
        if not parent_code:
            parent_code = subdiv.country.alpha_2
        country_codes.update(country_aliases(parent_code))
        # Adding subdivision's country alias
        if territory_code in SUBDIVISION_COUNTRIES:
            subdiv_country = SUBDIVISION_COUNTRIES.get(territory_code)
            if subdiv_country:
                country_codes.add(subdiv_country)

    # Hunt for aliases
    for mapped_code in REVERSE_MAPPING.get(territory_code, []):
        country_codes.update(country_aliases(mapped_code))

    return country_codes
Example #15
0
    def validate(self):
        """ Check fields consistency and requirements in one go.

        Properly check that fields are consistent between themselves, and only
        raise an exception at the end, for the whole address object. Our custom
        exception will provide a detailed status of bad fields.
        """
        # Keep a classification of bad fields along the validation process.
        required_fields = set()
        invalid_fields = set()
        inconsistent_fields = set()

        # Check that all required fields are set.
        for field_id in self.REQUIRED_FIELDS:
            if not getattr(self, field_id):
                required_fields.add(field_id)

        # Check all fields for invalidity, only if not previously flagged as
        # required.
        if 'country_code' not in required_fields:
            # Check that the country code exists.
            try:
                countries.get(alpha2=self.country_code)
            except KeyError:
                invalid_fields.add('country_code')
        if self.subdivision_code and 'subdivision_code' not in required_fields:
            # Check that the country code exists.
            try:
                subdivisions.get(code=self.subdivision_code)
            except KeyError:
                invalid_fields.add('subdivision_code')

        # Check country consistency against subdivision, only if none of the
        # two fields were previously flagged as required or invalid.
        if self.subdivision_code and not set(
                ['country_code', 'subdivision_code']).intersection(
                    required_fields.union(invalid_fields)) and \
                country_from_subdivision(
                    self.subdivision_code) != self.country_code:
            inconsistent_fields.add(
                tuple(sorted(('country_code', 'subdivision_code'))))

        # Raise our custom exception at last.
        if required_fields or invalid_fields or inconsistent_fields:
            raise InvalidAddress(
                required_fields, invalid_fields, inconsistent_fields)
    def validate(self):
        """ Check fields consistency and requirements in one go.

        Properly check that fields are consistent between themselves, and only
        raise an exception at the end, for the whole address object. Our custom
        exception will provide a detailed status of bad fields.
        """
        # Keep a classification of bad fields along the validation process.
        required_fields = set()
        invalid_fields = dict()
        inconsistent_fields = set()

        # Check that all required fields are set.
        for field_id in self.REQUIRED_FIELDS:
            if not getattr(self, field_id):
                required_fields.add(field_id)

        # Check all fields for invalidity, only if not previously flagged as
        # required.
        if 'country_code' not in required_fields:
            # Check that the country code exists.
            try:
                countries.get(alpha_2=self.country_code)
            except KeyError:
                invalid_fields['country_code'] = self.country_code
        if self.subdivision_code and 'subdivision_code' not in required_fields:
            # Check that the country code exists.
            try:
                subdivisions.get(code=self.subdivision_code)
            except KeyError:
                invalid_fields['subdivision_code'] = self.subdivision_code

        # Check country consistency against subdivision, only if none of the
        # two fields were previously flagged as required or invalid.
        if self.subdivision_code and not set(
                ['country_code', 'subdivision_code']).intersection(
                    required_fields.union(invalid_fields)) and \
                country_from_subdivision(
                    self.subdivision_code) != self.country_code:
            inconsistent_fields.add(
                tuple(sorted(('country_code', 'subdivision_code'))))

        # Raise our custom exception at last.
        if required_fields or invalid_fields or inconsistent_fields:
            raise InvalidAddress(required_fields, invalid_fields,
                                 inconsistent_fields)
Example #17
0
    def test_subdivision_derived_city_fields(self):
        address = Address(line1='2 King Edward Street',
                          postal_code='EC1A 1HQ',
                          subdivision_code='GB-LND')

        self.assertEquals(address.subdivision, subdivisions.get(code='GB-LND'))
        self.assertEquals(address.subdivision_code, 'GB-LND')
        self.assertEquals(address.subdivision_name, 'London, City of')
        self.assertEquals(address.subdivision_type_name, 'City corporation')
        self.assertEquals(address.subdivision_type_id, 'city')

        self.assertEquals(address.city, subdivisions.get(code='GB-LND'))
        self.assertEquals(address.city_area_code, 'GB-LND')
        self.assertEquals(address.city_name, 'London, City of')
        self.assertEquals(address.city_type_name, 'City corporation')

        self.assertEquals(address.country_code, 'GB')
Example #18
0
 def __init__(self, user_id, number_max, number_regex, number_help, country_code, id=None, *args, **kwargs):
     super(AddLicensePlateForm, self).__init__(*args, **kwargs)
     self.region.choices = [(x.code.split('-')[1], x.code.split('-')[1]) for x in subdivisions.get(country_code=country_code)]
     self.id = id
     self.user_id = user_id
     self.number_max = number_max
     self.number_regex = number_regex
     self.number.description = number_help
Example #19
0
    def test_subdivision_derived_fields(self):
        address = Address(
            line1='31, place du Théatre',
            postal_code='59000',
            city_name='Lille',
            subdivision_code='FR-59')

        self.assertEquals(
            address.subdivision, subdivisions.get(code='FR-59'))
        self.assertEquals(
            address.subdivision_code, 'FR-59')
        self.assertEquals(
            address.subdivision_name, 'Nord')
        self.assertEquals(
            address.subdivision_type_name, 'Metropolitan department')
        self.assertEquals(
            address.subdivision_type_id, 'metropolitan_department')

        self.assertEquals(
            address.metropolitan_department, subdivisions.get(code='FR-59'))
        self.assertEquals(
            address.metropolitan_department_code, 'FR-59')
        self.assertEquals(
            address.metropolitan_department_name, 'Nord')
        self.assertEquals(
            address.metropolitan_department_type_name,
            'Metropolitan department')

        self.assertEquals(
            address.metropolitan_region, subdivisions.get(code='FR-O'))
        self.assertEquals(
            address.metropolitan_region_code, 'FR-O')
        self.assertEquals(
            address.metropolitan_region_name, 'Nord - Pas-de-Calais')
        self.assertEquals(
            address.metropolitan_region_type_name,
            'Metropolitan region')

        self.assertEquals(
            address.country, countries.get(alpha2='FR'))
        self.assertEquals(
            address.country_code, 'FR')
        self.assertEquals(
            address.country_name, 'France')
Example #20
0
 def validate_code(code):
     """
     Validate that code is valid
     :param code: code from IS O3166-2
     """
     if subdivisions.get(code=code):
         return code
     else:
         raise serializers.ValidationError(
             'Invalid country subdivision code')
Example #21
0
 def get(self, country_alpha2: str):
     """
     Returns list of subdivision records for the country.
     :param country_alpha2: The unique two character identifier of the country record.
     :type country_alpha2: str
     :return:
     """
     try:
         return list(subdivisions.get(country_code=country_alpha2))
     except KeyError:
         abort(404, 'Subdivisions not found')
Example #22
0
    def test_subdivision_derived_city_fields(self,
                                             replace_city_name: bool) -> None:
        address = Address(
            line1="2 King Edward Street",
            postal_code="EC1A 1HQ",
            subdivision_code="GB-LND",
            replace_city_name=replace_city_name,
        )

        assert address.subdivision == subdivisions.get(code="GB-LND")
        assert address.subdivision_code == "GB-LND"
        assert address.subdivision_name == "London, City of"
        assert address.subdivision_type_name == "City corporation"
        assert address.subdivision_type_id == "city"

        assert address.city == subdivisions.get(code="GB-LND")
        assert address.city_area_code == "GB-LND"
        assert address.city_name == "London, City of"
        assert address.city_type_name == "City corporation"

        assert address.country_code == "GB"
Example #23
0
def include_country_and_states():

    hu3 = "BR"
    states_br = subdivisions.get(country_code=hu3)
    for state in states_br:
        new_code = state.code.split("-")[-1].lower()
        aux = {
            "code": new_code,
            "name": state.name
        }
        CONNECTION.states.insert(aux)

    return True
Example #24
0
    def check_invalid_fields(self, required_fields):
        """Check all fields for invalidity, only if not previously flagged as
        required.

        :param required_fields:
        :return:
        """
        invalid_fields = dict()
        if 'country_code' not in required_fields:
            # Check that the country code exists.
            try:
                countries.get(alpha_2=self.country_code)
            except KeyError:
                invalid_fields['country_code'] = self.country_code

        if self.subdivision_code and 'subdivision_code' not in required_fields:
            # Check that the country code exists.
            try:
                subdivisions.get(code=self.subdivision_code)
            except KeyError:
                invalid_fields['subdivision_code'] = self.subdivision_code
        return invalid_fields
Example #25
0
 def __init__(self, code):
     try:
         sd = subdivisions.get(code=code)
     except LookupError as e:
         raise CountrySubdivisionNotFound(str(e)) from e
     if not sd:
         raise CountrySubdivisionNotFound(
             f"Subdivision {code} does not exist")
     self.code = code
     self.name = sd.name
     self.type = sd.type
     self.country_code = sd.country_code
     self.parent_code = sd.parent_code
Example #26
0
def add_states(event):
    hu3 = "BR"
    states_br = subdivisions.get(country_code=hu3)
    for state in states_br:
        new_code = state.code.split("-")[-1].lower()
        if State.query.filter_by(code=new_code).first():
            logging.info("{} ja adicionado".format(new_code))
        else:
            with transaction.manager:
                logging.info("Adicionando: {}".format(new_code))
                new_state = State(code=new_code)
                db.DBSession.add(new_state)
    return True
Example #27
0
    def check_invalid_fields(self, required_fields):
        """Check all fields for invalidity, only if not previously flagged as
        required.

        :param required_fields:
        :return:
        """
        invalid_fields = dict()
        if 'country_code' not in required_fields:
            # Check that the country code exists.
            try:
                countries.get(alpha_2=self.country_code)
            except KeyError:
                invalid_fields['country_code'] = self.country_code

        if self.subdivision_code and 'subdivision_code' not in required_fields:
            # Check that the country code exists.
            try:
                subdivisions.get(code=self.subdivision_code)
            except KeyError:
                invalid_fields['subdivision_code'] = self.subdivision_code
        return invalid_fields
Example #28
0
    def test_subdivision_derived_country(self):
        address = Address(line1='Senate House',
                          line2='Tyndall Avenue',
                          postal_code='BS8 1TH',
                          city_name='Bristol',
                          subdivision_code='GB-ENG')

        self.assertEquals(address.subdivision, subdivisions.get(code='GB-ENG'))
        self.assertEquals(address.subdivision_code, 'GB-ENG')
        self.assertEquals(address.subdivision_name, 'England')
        self.assertEquals(address.subdivision_type_name, 'Country')
        self.assertEquals(address.subdivision_type_id, 'country')

        self.assertEquals(address.country_code, 'GB')
Example #29
0
 def list_for_country(cls, country_code, search_term=None, ordering='name'):
     if ordering not in ['code', 'name', 'type']:
         ordering = 'name'
     if search_term:
         return cls.search(search_term=search_term,
                           country_code=country_code,
                           ordering=ordering)
     else:
         try:
             return sorted([
                 CountrySubdivision(code=r.code)
                 for r in subdivisions.get(country_code=country_code)
             ],
                           key=lambda x: getattr(x, ordering))
         except TypeError as e:
             raise CountrySubdivisionNotFound(str(e)) from e
Example #30
0
    def get(self, country_alpha2: str, subdivision_code: str):
        """
        Returns the specified subdivision record.
        :param country_alpha2: The unique two character identifier of the country record.
        :type country_alpha2: str
        :param subdivision_code: The unique two character identifier of the subdivision record.
        :type subdivision_code: str
        :return:
        """
        subdivivion_code = '{country_code}-{subdivision_code}'.format(
            country_code=country_alpha2, subdivision_code=subdivision_code)
        subdivision_record = subdivisions.get(code=subdivivion_code)

        if subdivision_record is not None:
            return subdivision_record
        else:
            abort(404, 'Subdivision not found')
Example #31
0
    def check_invalid_fields(self,
                             required_fields: Set[str]) -> Dict[str, str]:
        """Check all fields for invalidity, only if not previously flagged as required.

        :param required_fields:
        """
        invalid_fields: Dict[str, str] = {}
        if "country_code" not in required_fields and self.country_code:
            country = countries.get(alpha_2=self.country_code)
            if country is None:
                invalid_fields["country_code"] = self.country_code

        if self.subdivision_code and "subdivision_code" not in required_fields:
            subdiv = subdivisions.get(code=self.subdivision_code)
            if subdiv is None:
                invalid_fields["subdivision_code"] = self.subdivision_code
        return invalid_fields
Example #32
0
    def put(self, country_alpha2: str, subdivision_code: str, city_id: int):
        """
        Updates a city record.

        Use this method to change the values for a city record.

        * Send a JSON object with the new data in the request body.

        ```
        {
            "name": "Calgary",
            "subdivision": "CA-AB"
        }
        ```

        * Specify the ID of the city to modify in the request URL path.
        :param country_alpha2: The unique two character identifier of the country record.
        :type country_alpha2: str
        :param subdivision_code: The unique two character identifier of the subdivision record.
        :type subdivision_code: str
        :param city_id: The unique identifier of the city record.
        :type city_id: int
        """
        data = request.json

        # Validate the country_alpha2 and subdivision_code are valid
        code = '{country_alpha2}-{subdivision_code}'.format(
            country_alpha2=country_alpha2, subdivision_code=subdivision_code)

        try:
            if subdivisions.get(code=code) is None:
                abort(
                    400,
                    'Bad request: country_alpha2 and subdivision_code are invalid'
                )
        except KeyError:
            abort(
                400,
                'Bad request: country_alpha2 and subdivision_code are invalid')

        try:
            data = update_city(city_id, data)
        except LengthError:
            abort(400, 'Bad request: City name length error')
        return data, 204
Example #33
0
    def test_subdivision_derived_country(self,
                                         replace_city_name: bool) -> None:
        address = Address(
            line1="Senate House",
            line2="Tyndall Avenue",
            postal_code="BS8 1TH",
            city_name="Bristol",
            subdivision_code="GB-BST",
            replace_city_name=replace_city_name,
        )

        assert address.subdivision == subdivisions.get(code="GB-BST")
        assert address.subdivision_code == "GB-BST"
        assert address.subdivision_name == "Bristol, City of"
        assert address.subdivision_type_name == "Unitary authority"
        assert address.subdivision_type_id == "unitary_authority"

        assert address.country_code == "GB"
Example #34
0
 def test_subdivision_type_id_city_classification(self) -> None:
     city_like_subdivisions = [
         "TM-S",  # Aşgabat, Turkmenistan, City
         "TW-CYI",  # Chiay City, Taiwan, Municipality
         "TW-TPE",  # Taipei City, Taiwan, Special Municipality
         "ES-ML",  # Melilla, Spain, Autonomous city
         "GB-LND",  # City of London, United Kingdom, City corporation
         "KP-01",  # P’yŏngyang, North Korea, Capital city
         "KP-13",  # Nasŏn (Najin-Sŏnbong), North Korea, Special city
         "KR-11",  # Seoul Teugbyeolsi, South Korea, Capital Metropolitan
         # City
         "HU-HV",  # Hódmezővásárhely, Hungary, City with county rights
         "LV-RIX",  # Rīga, Latvia, Republican City
         "ME-15",  # Plužine, Montenegro, Municipality
         "NL-BQ1",  # Bonaire, Netherlands, Special municipality
         "KH-12",  # Phnom Penh, Cambodia, Autonomous municipality
     ]
     for subdiv_code in city_like_subdivisions:
         assert subdivision_type_id(subdivisions.get(code=subdiv_code)) == "city"
Example #35
0
    def test_subdivision_derived_country(self):
        address = Address(
            line1='Senate House',
            line2='Tyndall Avenue',
            postal_code='BS8 1TH',
            city_name='Bristol',
            subdivision_code='GB-ENG')

        self.assertEquals(
            address.subdivision, subdivisions.get(code='GB-ENG'))
        self.assertEquals(
            address.subdivision_code, 'GB-ENG')
        self.assertEquals(
            address.subdivision_name, 'England')
        self.assertEquals(
            address.subdivision_type_name, 'Country')
        self.assertEquals(
            address.subdivision_type_id, 'country')

        self.assertEquals(address.country_code, 'GB')
Example #36
0
def country_from_subdivision(subdivision_code: str) -> Optional[str]:
    """Return the normalized country code from a subdivision code.

    If no country is found, or the subdivision code is incorrect, ``None`` is
    returned.

    For subdivisions having their own ISO 3166-1 alpha-2 country code, returns
    the later instead of the parent ISO 3166-2 top entry.
    """
    # Resolve subdivision alias.
    code = SUBDIVISION_COUNTRIES.get(subdivision_code, subdivision_code)

    # We have a country code, return it right away.
    if code in supported_country_codes():
        return code

    subdiv = subdivisions.get(code=subdivision_code)
    if subdiv is None:
        return None
    return subdiv.country_code
Example #37
0
 def test_subdivision_type_id_city_classification(self):
     city_like_subdivisions = [
         'TM-S',  # Aşgabat, Turkmenistan, City
         'TW-CYI',  # Chiay City, Taiwan, Municipality
         'TW-TPE',  # Taipei City, Taiwan, Special Municipality
         'ES-ML',  # Melilla, Spain, Autonomous city
         'GB-LND',  # City of London, United Kingdom, City corporation
         'KP-01',  # P’yŏngyang, North Korea, Capital city
         'KP-13',  # Nasŏn (Najin-Sŏnbong), North Korea, Special city
         'KR-11',  # Seoul Teugbyeolsi, South Korea, Capital Metropolitan
         # City
         'HU-HV',  # Hódmezővásárhely, Hungary, City with county rights
         'LV-RIX',  # Rīga, Latvia, Republican City
         'ME-15',  # Plužine, Montenegro, Municipality
         'NL-BQ1',  # Bonaire, Netherlands, Special municipality
         'KH-12',  # Phnom Penh, Cambodia, Autonomous municipality
     ]
     for subdiv_code in city_like_subdivisions:
         self.assertEquals(
             subdivision_type_id(subdivisions.get(code=subdiv_code)),
             'city')
Example #38
0
 def test_subdivision_type_id_city_classification(self):
     city_like_subdivisions = [
         'TM-S',  # Aşgabat, Turkmenistan, City
         'TW-CYI',  # Chiay City, Taiwan, Municipality
         'TW-TPE',  # Taipei City, Taiwan, Special Municipality
         'ES-ML',  # Melilla, Spain, Autonomous city
         'GB-LND',  # City of London, United Kingdom, City corporation
         'KP-01',  # P’yŏngyang, North Korea, Capital city
         'KP-13',  # Nasŏn (Najin-Sŏnbong), North Korea, Special city
         'KR-11',  # Seoul Teugbyeolsi, South Korea, Capital Metropolitan
         # City
         'HU-HV',  # Hódmezővásárhely, Hungary, City with county rights
         'LV-RIX',  # Rīga, Latvia, Republican City
         'ME-15',  # Plužine, Montenegro, Municipality
         'NL-BQ1',  # Bonaire, Netherlands, Special municipality
         'KH-12',  # Phnom Penh, Cambodia, Autonomous municipality
     ]
     for subdiv_code in city_like_subdivisions:
         self.assertEquals(
             subdivision_type_id(subdivisions.get(code=subdiv_code)),
             'city')
Example #39
0
def country_from_subdivision(subdivision_code):
    """ Return the normalized country code from a subdivision code.

    If no country is found, or the subdivision code is incorrect, ``None`` is
    returned.

    For subdivisions having their own ISO 3166-1 alpha-2 country code, returns
    the later instead of the parent ISO 3166-2 top entry.
    """
    # Resolve subdivision alias.
    code = SUBDIVISION_ALIASES.get(subdivision_code, subdivision_code)

    # We have a country code, return it right away.
    if code in supported_country_codes():
        return code

    # Try to extract country code from subdivision.
    try:
        subdiv = subdivisions.get(code=code)
    except KeyError:
        return None
    return subdiv.country_code
Example #40
0
def country_from_subdivision(subdivision_code):
    """ Return the normalized country code from a subdivision code.

    If no country is found, or the subdivision code is incorrect, ``None`` is
    returned.

    For subdivisions having their own ISO 3166-1 alpha-2 country code, returns
    the later instead of the parent ISO 3166-2 top entry.
    """
    # Resolve subdivision alias.
    code = SUBDIVISION_ALIASES.get(subdivision_code, subdivision_code)

    # We have a country code, return it right away.
    if code in supported_country_codes():
        return code

    # Try to extract country code from subdivision.
    try:
        subdiv = subdivisions.get(code=code)
    except KeyError:
        return None
    return subdiv.country_code
Example #41
0
    def post(self, country_alpha2: str, subdivision_code: str):
        """
        Creates a new city record.
        :param country_alpha2: The unique two character identifier of the country record.
        :type country_alpha2: str
        :param subdivision_code: The unique two character identifier of the subdivision record.
        :type subdivision_code: str
        :return:
        """
        data = request.json

        # Validate the country_alpha2 and subdivision_code are valid
        code = '{country_alpha2}-{subdivision_code}'.format(
            country_alpha2=country_alpha2, subdivision_code=subdivision_code)

        try:
            if subdivisions.get(code=code) is None:
                abort(
                    400,
                    'Bad request: country_alpha2 and subdivision_code are invalid'
                )
        except KeyError:
            abort(
                400,
                'Bad request: country_alpha2 and subdivision_code are invalid')

        try:
            data = create_city(data)
        except LengthError:
            abort(400, 'Bad request: City name length')
        except IntegrityError:
            abort(400, 'Bad request: City already exists')
        except Exception:
            abort(400, 'Bad request: City already exists')

        return data, 201
Example #42
0
 def iso3166_2(self):
     code = self.short_address_components[
         'country'] + '-' + self.short_address_components[
             'administrative_area_level_1']
     return subdivisions.get(code=code)
Example #43
0
 def subdivision(self) -> Optional[pycountry.Subdivision]:
     """Return subdivision object."""
     if self.subdivision_code:
         return subdivisions.get(code=self.subdivision_code)
     return None
Example #44
0
    def normalize(self, strict=True):
        """ Normalize address fields.

        If values are unrecognized or invalid, they will be set to None.

        By default, the normalization is ``strict``: metadata derived from
        territory's parents are not allowed to overwrite valid address fields
        entered by the user. If set to ``False``, territory-derived values
        takes precedence over user's.

        You need to call back the ``validate()`` method afterwards to properly
        check that the fully-qualified address is ready for consumption.
        """
        # Clean-up all fields.
        empty_fields = []
        for field_id in self._fields:
            # Remove leading and trailing white spaces.
            if isinstance(self._fields[field_id], basestring):
                self._fields[field_id] = self._fields[field_id].strip()
            # Get rid of empty/blank strings.
            if not getattr(self, field_id):
                empty_fields.append(field_id)
        for field_id in empty_fields:
            del self[field_id]

        # Normalize territory codes. Unrecognized territory codes are reset
        # to None.
        for territory_id in ['country_code', 'subdivision_code']:
            territory_code = getattr(self, territory_id)
            if territory_code:
                try:
                    code = normalize_territory_code(
                        territory_code, resolve_aliases=False)
                except ValueError:
                    code = None
                setattr(self, territory_id, code)

        # Swap lines if the first is empty.
        if self.line2 and not self.line1:
            self.line1, self.line2 = self.line2, self.line1

        # Try to set default subdivision from country if not set.
        if self.country_code and not self.subdivision_code:
            self.subdivision_code = default_subdivision_code(self.country_code)
            # If the country set its own subdivision, reset it. It will be
            # properly re-guessed below.
            if self.subdivision_code:
                self.country_code = None

        # Automaticcaly populate address fields with metadata extracted from
        # all subdivision parents.
        if self.subdivision_code:
            parent_metadata = {
                # All subdivisions have a parent country.
                'country_code': country_from_subdivision(
                    self.subdivision_code)}

            # Add metadata of each subdivision parent.
            for parent_subdiv in territory_parents(
                    self.subdivision_code, include_country=False):
                parent_metadata.update(subdivision_metadata(parent_subdiv))

            # Parent metadata are not allowed to overwrite address fields
            # if not blank, unless strict mode is de-activated.
            if strict:
                for field_id, new_value in parent_metadata.items():
                    # New metadata are not allowed to be blank.
                    assert new_value
                    current_value = self._fields.get(field_id)
                    if current_value and field_id in self.BASE_FIELD_IDS:

                        # Build the list of substitute values that are
                        # equivalent to our new normalized target.
                        alias_values = set([new_value])
                        if field_id == 'country_code':
                            # Allow normalization if the current country code
                            # is the direct parent of a subdivision which also
                            # have its own country code.
                            alias_values.add(subdivisions.get(
                                code=self.subdivision_code).country_code)

                        # Change of current value is allowed if it is a direct
                        # substitute to our new normalized value.
                        if current_value not in alias_values:
                            raise InvalidAddress(
                                inconsistent_fields=set([
                                    tuple(sorted((
                                        field_id, 'subdivision_code')))]),
                                extra_msg="{} subdivision is trying to replace"
                                " {}={!r} field by {}={!r}".format(
                                    self.subdivision_code,
                                    field_id, current_value,
                                    field_id, new_value))

            self._fields.update(parent_metadata)
Example #45
0
 def subdivision(self):
     """ Return subdivision object. """
     if self.subdivision_code:
         return subdivisions.get(code=self.subdivision_code)
     return None
Example #46
0
    def normalize(self, strict=True):
        """ Normalize address fields.

        If values are unrecognized or invalid, they will be set to None.

        By default, the normalization is ``strict``: metadata derived from
        territory's parents are not allowed to overwrite valid address fields
        entered by the user. If set to ``False``, territory-derived values
        takes precedence over user's.

        You need to call back the ``validate()`` method afterwards to properly
        check that the fully-qualified address is ready for consumption.
        """
        # Strip postal codes of any characters but alphanumerics, spaces and
        # hyphens.
        if self.postal_code:
            self.postal_code = self.postal_code.upper()
            # Remove unrecognized characters.
            self.postal_code = re.compile(
                r'[^A-Z0-9 -]').sub('', self.postal_code)
            # Reduce sequences of mixed hyphens and spaces to single hyphen.
            self.postal_code = re.compile(
                r'[^A-Z0-9]*-+[^A-Z0-9]*').sub('-', self.postal_code)
            # Edge case: remove leading and trailing hyphens and spaces.
            self.postal_code = self.postal_code.strip('-')

        # Normalize spaces.
        for field_id, field_value in self.items():
            if isinstance(field_value, basestring):
                try:
                    self[field_id] = ' '.join(field_value.split())
                except KeyError:
                    # Invalid field_id, usually all the 'subdivision_metadata'
                    pass

        # Reset empty and blank strings.
        empty_fields = [f_id for f_id, f_value in self.items() if not f_value]
        for field_id in empty_fields:
            del self[field_id]

        # Swap lines if the first is empty.
        if self.line2 and not self.line1:
            self.line1, self.line2 = self.line2, self.line1

        # Normalize territory codes. Unrecognized territory codes are reset
        # to None.
        for territory_id in ['country_code', 'subdivision_code']:
            territory_code = getattr(self, territory_id)
            if territory_code:
                try:
                    code = normalize_territory_code(
                        territory_code, resolve_aliases=False)
                except ValueError:
                    code = None
                setattr(self, territory_id, code)

        # Try to set default subdivision from country if not set.
        if self.country_code and not self.subdivision_code:
            self.subdivision_code = default_subdivision_code(self.country_code)
            # If the country set its own subdivision, reset it. It will be
            # properly re-guessed below.
            if self.subdivision_code:
                self.country_code = None

        # Automatically populate address fields with metadata extracted from
        # all subdivision parents.
        if self.subdivision_code:
            parent_metadata = {
                # All subdivisions have a parent country.
                'country_code': country_from_subdivision(
                    self.subdivision_code)}

            # Add metadata of each subdivision parent.
            for parent_subdiv in territory_parents(
                    self.subdivision_code, include_country=False):
                parent_metadata.update(subdivision_metadata(parent_subdiv))

            # Parent metadata are not allowed to overwrite address fields
            # if not blank, unless strict mode is de-activated.
            if strict:
                for field_id, new_value in parent_metadata.items():
                    # New metadata are not allowed to be blank.
                    assert new_value
                    current_value = self._fields.get(field_id)
                    if current_value and field_id in self.BASE_FIELD_IDS:

                        # Build the list of substitute values that are
                        # equivalent to our new normalized target.
                        alias_values = {new_value}
                        if field_id == 'country_code':
                            # Allow normalization if the current country code
                            # is the direct parent of a subdivision which also
                            # have its own country code.
                            alias_values.add(subdivisions.get(
                                code=self.subdivision_code).country_code)

                        # Change of current value is allowed if it is a direct
                        # substitute to our new normalized value.
                        if current_value not in alias_values:
                            raise InvalidAddress(
                                inconsistent_fields={tuple(sorted((
                                    field_id, 'subdivision_code')))},
                                extra_msg="{} subdivision is trying to replace"
                                " {}={!r} field by {}={!r}".format(
                                    self.subdivision_code,
                                    field_id, current_value,
                                    field_id, new_value))

            self._fields.update(parent_metadata)
Example #47
0
 def test_subdivision_parent_code(self):
     # See https://bitbucket.org/flyingcircus/pycountry/issues/13389
     self.assertEqual("GB-ENG", subdivisions.get(code='GB-STS').parent_code)
     self.assertEqual("CZ-20", subdivisions.get(code='CZ-205').parent_code)