<commit_before>"""
.. module:: api
   :synopsis: This is the actual API client, along with a few helper classes.

.. moduleauthor:: <NAME> <<EMAIL>>
"""

from requests import Request

class DistrictApiError(Exception):
    """
    Parent class from which all other Districts API errors inherit.
    
    Used for any other generic exceptions.
    """
    pass

class ApiUnavailable(DistrictApiError):
    """
    Thrown when network or server errors are encountered.
    """
    pass
    
    
class LocationUnavailable(DistrictApiError):
    """
    As of this writing, the Times' Districts API only offers data for New York 
    City districts. This exception is thrown when the API returns a response
    indicating that the lat/long given are outside the area covered.       
    """
    pass
    
    
class AuthorizationError(DistrictApiError):
    """
    Receiving this error probably means your API key is invalid.
    """
    pass
    
    
class QuotaExceeded(DistrictApiError):
    """
    Currently unused (because we haven't hit our quota and thus haven't been 
    able to see what the API returns in this case!)
        
    When we do get this running, well, it'll mean you've exceeded your quota.
    """
    pass
    

class District(object):
    """
    Represents a district
    
    :ivar string district: The name or number of the district
    :ivar string level: Which political body this district elects to (e.g. 
       "City Council", "State Senate")
    :ivar string kml_url: URL to retrieve KML file representing the district's
       boundaries
    """

    def __init__(self, district, level, kml_url, *args, **kwargs):
        """
        :param string district: The name or number of the district
        :param string level: Which political body this district elects to (e.g. 
           "City Council", "State Senate")
        :param string kml_url: URL to retrieve KML file representing the district's
           boundaries
        """
        self.district = district
        self.level = level
        self.kml_url = kml_url
        
        super(District, self).__init__(*args, **kwargs)
    

class DistrictApi(object):
    """
    NY Times Districts API client.

    :ivar string api_key: NY Times Districts API key. Obtained from 
       `NY Times Developer Network <http://developer.nytimes.com/apps/register/>`_
    :ivar string url: Endpoint for NY Times Districts API.  Defaults to URL
        specified in `the docs <http://developer.nytimes.com/docs/districts_api>`_
    """
    def __init__(self, api_key, *args, **kwargs):
        """
        :param string api_key: NY Times Districts API key. Obtained from 
           `NY Times Developer Network <http://developer.nytimes.com/apps/register/>`_
        :param string url: Override API endpoint (used mostly for testing)
        """
        self.api_key = api_key
        self.url = kwargs.pop('url', 'http://api.nytimes.com/svc/politics/v2/districts.json')
        
        super(DistrictApi, self).__init__(*args, **kwargs)

    def construct_query_vars(self, lat_lng=None):
        """
        Constructs the query string for our particular API query.  Called by 
        ``send_request``.  This doesn't really need to be a separate method,
        but it makes for easier unit testing.
            
        :param lat_lng: 2-tuple of latitude and longitude floats representing 
           the location for which district data should be retrieved -- e.g. 
           (34.6405, -85.3)
        :type lat_lng: tuple of floats
        :returns: Dictionary of variables that should be included in the query 
           string when querying the API
        :rtype: dict
        """
        query_vars = {
            'api_key': self.api_key,
        }
        
        if lat_lng:
            query_vars['lat'] = lat_lng[0]
            query_vars['lng'] = lat_lng[1]
        
        return query_vars
        
    def send_request(self, lat_lng=None):
        """
        Construct query string; send HTTP request to API; return HTTP response.
        
        :param lat_lng: 2-tuple of latitude and longitude floats representing 
           the location for which district data should be retrieved -- e.g. 
           (34.6405, -85.3)
        :type lat_lng: tuple of floats
        :returns: raw HTTP response from API
        :rtype: requests.Response
        """
        query_vars = self.construct_query_vars(lat_lng)
        return Request('GET', self.url, data=query_vars).prepare()
    
    def get_all_districts(self):
        """
        Get information about all districts about which the API can provide data.<commit_msg>We don't need to return a Request object, just execute the request (we were previously creating the object with the idea that it'd be easier to unit test, but it's not -- separating out the query var prep function was more effective)<commit_after>"""
.. module:: api
   :synopsis: This is the actual API client, along with a few helper classes.

.. moduleauthor:: <NAME> <<EMAIL>>
"""

import requests

class DistrictApiError(Exception):
    """
    Parent class from which all other Districts API errors inherit.
    
    Used for any other generic exceptions.
    """
    pass

class ApiUnavailable(DistrictApiError):
    """
    Thrown when network or server errors are encountered.
    """
    pass
    
    
class LocationUnavailable(DistrictApiError):
    """
    As of this writing, the Times' Districts API only offers data for New York 
    City districts. This exception is thrown when the API returns a response
    indicating that the lat/long given are outside the area covered.       
    """
    pass
    
    
class AuthorizationError(DistrictApiError):
    """
    Receiving this error probably means your API key is invalid.
    """
    pass
    
    
class QuotaExceeded(DistrictApiError):
    """
    Currently unused (because we haven't hit our quota and thus haven't been 
    able to see what the API returns in this case!)
        
    When we do get this running, well, it'll mean you've exceeded your quota.
    """
    pass
    

class District(object):
    """
    Represents a district
    
    :ivar string district: The name or number of the district
    :ivar string level: Which political body this district elects to (e.g. 
       "City Council", "State Senate")
    :ivar string kml_url: URL to retrieve KML file representing the district's
       boundaries
    """

    def __init__(self, district, level, kml_url, *args, **kwargs):
        """
        :param string district: The name or number of the district
        :param string level: Which political body this district elects to (e.g. 
           "City Council", "State Senate")
        :param string kml_url: URL to retrieve KML file representing the district's
           boundaries
        """
        self.district = district
        self.level = level
        self.kml_url = kml_url
        
        super(District, self).__init__(*args, **kwargs)
    

class DistrictApi(object):
    """
    NY Times Districts API client.

    :ivar string api_key: NY Times Districts API key. Obtained from 
       `NY Times Developer Network <http://developer.nytimes.com/apps/register/>`_
    :ivar string url: Endpoint for NY Times Districts API.  Defaults to URL
        specified in `the docs <http://developer.nytimes.com/docs/districts_api>`_
    """
    def __init__(self, api_key, *args, **kwargs):
        """
        :param string api_key: NY Times Districts API key. Obtained from 
           `NY Times Developer Network <http://developer.nytimes.com/apps/register/>`_
        :param string url: Override API endpoint (used mostly for testing)
        """
        self.api_key = api_key
        self.url = kwargs.pop('url', 'http://api.nytimes.com/svc/politics/v2/districts.json')
        
        super(DistrictApi, self).__init__(*args, **kwargs)

    def construct_query_vars(self, lat_lng=None):
        """
        Constructs the query string for our particular API query.  Called by 
        ``send_request``.  This doesn't really need to be a separate method,
        but it makes for easier unit testing.
            
        :param lat_lng: 2-tuple of latitude and longitude floats representing 
           the location for which district data should be retrieved -- e.g. 
           (34.6405, -85.3)
        :type lat_lng: tuple of floats
        :returns: Dictionary of variables that should be included in the query 
           string when querying the API
        :rtype: dict
        """
        query_vars = {
            'api_key': self.api_key,
        }
        
        if lat_lng:
            query_vars['lat'] = lat_lng[0]
            query_vars['lng'] = lat_lng[1]
        
        return query_vars
        
    def send_request(self, lat_lng=None):
        """
        Construct query string; send HTTP request to API; return HTTP response.
        
        :param lat_lng: 2-tuple of latitude and longitude floats representing 
           the location for which district data should be retrieved -- e.g. 
           (34.6405, -85.3)
        :type lat_lng: tuple of floats
        :returns: raw HTTP response from API
        :rtype: requests.Response
        """
        query_vars = self.construct_query_vars(lat_lng)
        return requests.get(self.url, data=query_vars)
    
    def get_all_districts(self):
        """
        Get information about all districts about which the API can provide data.
{'fraction_non_alphanumeric': 0.08246114811290835, 'fraction_numerical': 0.00486309335024844, 'mean_word_length': 2.3463035019455254, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1313003', 'n_tokens_mistral': 2664, 'n_tokens_neox': 2546, 'n_words': 974}