Source code for bingmaps.apiservices.locations

import json
import os
import requests
from collections import namedtuple
import xmltodict
from bingmaps.urls import (
    LocationByAddressUrl,
    LocationByQueryUrl,
    LocationByPointUrl
)


class LocationApi(object):
    """Parent class for LocationByAddress and LocationByPoint api classes"""
    def __init__(self, schema, filename, http_protocol='http'):
        self.http_protocol = http_protocol
        self.file_name = filename
        self.locationApiData = None
        self.schema = schema

    def build_url(self):
        """Builds the URL for location API services based on the data given
        by the user.

        Returns:
            url (str): URL for the location API services
        """
        url = '{protocol}/{url}/{rest}/{version}/{restapi}/{rscpath}/' \
              '{query}'.format(protocol=self.schema.protocol,
                               url=self.schema.main_url,
                               rest=self.schema.rest,
                               version=self.schema.version,
                               restapi=self.schema.restApi,
                               rscpath=self.schema.resourcePath,
                               query=self.schema.query)
        return url

    def get_resource(self):
        try:
            resourceSets = self.response_to_dict()['resourceSets']
            for resource in resourceSets:
                return [rsc for rsc in resource['resources']]
        except KeyError:
            try:
                response = self.response_to_dict()['Response']
                resourceSets = response['ResourceSets']
                location = resourceSets['ResourceSet']['Resources']['Location']
                return location
            except KeyError:
                print(KeyError)

    def response_to_dict(self):
        try:
            return json.loads(self.locationApiData.text)
        except Exception:
            return json.loads(json.dumps(xmltodict.parse(
                self.locationApiData.text)))

    @property
    def response(self):
        """Returns response form the URL"""
        return self.locationApiData.text

    @property
    def status_code(self):
        """Returns status code from the URL response"""
        return self.locationApiData.status_code

    @property
    def get_coordinates(self):
        """Retrieves coordinates (latitudes/longitudes) from the output
        JSON/XML response

        Returns:
            coordinates (namedtuple): List of named tuples of coordinates
            (latitudes and longitudes)
        """
        resource_list = self.get_resource()
        coordinates = namedtuple('coordinates', ['latitude', 'longitude'])
        try:
            return [coordinates(*resource['point']['coordinates'])
                    for resource in resource_list]
        except (KeyError, TypeError):
            try:
                if isinstance(resource_list, dict):
                    resource_list = [resource_list]
                return [coordinates(resource['Point']['Latitude'],
                                    resource['Point']['Longitude'])
                        for resource in resource_list]
            except (KeyError, ValueError) as exc:
                print(exc)

    @property
    def get_address(self):
        """Retrieves addresses from the output JSON/XML response

        Returns:
            address (namedtuple): List of named tuples of addresses
        """
        resource_list = self.get_resource()
        try:
            return [resource['address'] for resource in resource_list]
        except (KeyError, TypeError):
            try:
                if isinstance(resource_list, dict):
                    resource_list = [resource_list]
                return [resource['Address'] for resource in resource_list]
            except (KeyError, TypeError) as exc:
                print(exc)

    @property
    def get_bbox(self):
        """Retrieves the bounding box coordinates from the output JSON/XML
        response

        Returns:
            boundingbox (namedtuple): List of named tuples of bounding box
            coordinates
        """
        resource_list = self.get_resource()
        bounding_box = namedtuple('boundingbox', ['southlatitude',
                                                  'westlongitude',
                                                  'northlatitude',
                                                  'eastlongitude'])
        try:
            return [bounding_box(*resource['bbox'])
                    for resource in resource_list]
        except (KeyError, TypeError):
            try:
                if isinstance(resource_list, dict):
                    resource_list = [resource_list]
                return [bounding_box(resource['BoundingBox']['SouthLatitude'],
                                     resource['BoundingBox']['WestLongitude'],
                                     resource['BoundingBox']['NorthLatitude'],
                                     resource['BoundingBox']['EastLongitude'])
                        for resource in resource_list]
            except (KeyError, TypeError) as exc:
                print(exc)

    def to_json_file(self, path, file_name=None):
        """Method to write response to a JSON file with the given file name"""
        if bool(path) and os.path.isdir(path):
            self.write_to_json(path, file_name)
        else:
            self.write_to_json(os.getcwd(), file_name)

    def write_to_json(self, path, file_name):
        if file_name is None:
            file_name = self.file_name
        with open(os.path.join(path,
                               '{0}.{1}'.format(file_name,
                                                'json')), 'w') as fp:
            json.dump(self.response, fp)


[docs]class LocationByAddress(LocationApi): """Location by address API class This class is used to retrieve the output from the given data from the user. - First, the data is used to build a URL which is related to the Locations by Address API. - Second, this class helps in retrieving the response from the URL built - Third, based on the response, this class helps in retrieving all the corresponding output data from the response. Some of the output data which this class would be retrieving is: - Coordinates (latitude/longitude) - BoundingBox coordinates (south latitude, west longitude, north latitude, east longitude) - Address The output from the URL can be either JSON/XML based on the output parameter mentioned in the data. Even the output response is 'xml', this class helps in converting the xml response to JSON data first and then retrieve all the necessary output from it. :ivar data: The data that the user will send in to the Location by address to retrieve all the respective output from the response :ivar url: The url that gets built based on the user's given data :ivar http_protocol: Http protocol for the URL. Can be either of the following: - http - https :ivar schema: The schema that gets used to build the URL and the schema is LocationByAddressUrl for location by address API service. :ivar file_name: The filename that the class can write the JSON response to. - file_name - 'locationByAddress' :ivar locationApiData: Response from the URL Some of the examples are illustrated in Examples page """ def __init__(self, data, http_protocol='http'): if not bool(data): raise TypeError('No data given') schema = LocationByAddressUrl(data, httpprotocol=http_protocol) filename = 'locationByAddress' super().__init__(schema, filename, http_protocol) self.get_data()
[docs] def get_data(self): """Gets data from the built url""" url = self.build_url() self.locationApiData = requests.get(url) if not self.locationApiData.status_code == 200: raise self.locationApiData.raise_for_status()
[docs] def build_url(self): """Build the url and replaces /None/ with empty string""" url = super().build_url() if '/None/' in url: return url.replace('/None/', '') else: return url
[docs]class LocationByPoint(LocationApi): """Location by point API class This class is used to retrieve the output from the given data from the user. - First, the data is used to build a URL which is related to the Location by Point API. - Second, this class helps in retrieving the response from the URL built - Third, based on the response, this class helps in retrieving all the corresponding output data from the response. Some of the output data which this class would be retrieving is: - Coordinates (latitude/longitude) - BoundingBox coordinates (south latitude, west longitude, north latitude, east longitude) - Address The output from the URL can be either JSON/XML based on the output parameter mentioned in the data. Even the output response is 'xml', this class helps in converting the xml response to JSON data first and then retrieve all the necessary output from it. :ivar data: The data that the user will send in to the Location by point to retrieve all the respective output from the response :ivar url: The url that gets built based on the user's given data :ivar http_protocol: Http protocol for the URL. Can be either of the following: - http - https :ivar schema: The schema that gets used to build the URL and the schema is LocationByPointUrl for location by point API service. :ivar file_name: The filename that the class can write the JSON response to. - file_name - 'locationByPoint' :ivar locationApiData: Response from the URL Some of the examples are illustrated in Examples page """ def __init__(self, data, http_protocol='http'): if not bool(data): raise TypeError('No data given') schema = LocationByPointUrl(data, httpprotocol=http_protocol) filename = 'locationByPoint' super().__init__(schema, filename, http_protocol) self.get_data()
[docs] def get_data(self): """Gets data from the built url""" url = self.build_url() self.locationApiData = requests.get(url) if not self.locationApiData.status_code == 200: raise self.locationApiData.raise_for_status()
[docs] def build_url(self): """Build the url and replaces /None/ with '/'""" url = super().build_url() if '/None/' in url: return url.replace('/None/', '/') else: return url
[docs]class LocationByQuery(LocationApi): """Location by query API class This class is used to retrieve the output from the given data from the user. - First, the data is used to build a URL which is related to the Location by Query API. - Second, this class helps in retrieving the response from the URL built - Third, based on the response, this class helps in retrieving all the corresponding output data from the response. Some of the output data which this class would be retrieving is: - Coordinates (latitude/longitude) - BoundingBox coordinates (south latitude, west longitude, north latitude, east longitude) - Address The output from the URL can be either JSON/XML based on the output parameter mentioned in the data. Even the output response is 'xml', this class helps in converting the xml response to JSON data first and then retrieve all the necessary output from it. :ivar data: The data that the user will send in to the Location by query to retrieve all the respective output from the response :ivar url: The url that gets built based on the user's given data :ivar http_protocol: Http protocol for the URL. Can be either of the following: - http - https :ivar schema: The schema that gets used to build the URL and the schema is LocationByQueryUrl for location by query API service. :ivar file_name: The filename that the class can write the JSON response to. - file_name - 'locationByQuery' :ivar locationApiData: Response from the URL Some of the examples are illustrated in Examples page """ def __init__(self, data, http_protocol='http'): if not bool(data): raise TypeError('No data given') schema = LocationByQueryUrl(data, httpprotocol=http_protocol) filename = 'locationByQuery' super().__init__(schema, filename, http_protocol) self.get_data()
[docs] def get_data(self): """Gets data from the built url""" url = self.build_url() self.locationApiData = requests.get(url) if not self.locationApiData.status_code == 200: raise self.locationApiData.raise_for_status()
[docs] def build_url(self): """Build the url and replaces /None/ with empty string""" url = super().build_url() if '/None/' in url: return url.replace('/None/', '') else: return url