<commit_before>"""
The DigitalOcean API allows you to manage Droplets and resources within the
DigitalOcean cloud in a simple, programmatic way using conventional HTTP
requests. The endpoints are intuitive and powerful, allowing you to easily make
calls to retrieve information or to execute actions.

All of the functionality that you are familiar with in the DigitalOcean control
panel is also available through the API, allowing you to script the complex
actions that your situation requires.
"""

import os
import requests
try:
    import simplejson as json
except ImportError:
    import json

API_VERSION = 'v2'
API_URL = 'https://api.digitalocean.com'


"""
TODO: refactor for multipage results
TODO: unit tests for Images, ImageActions, and DomainRecords
"""

class APIError(Exception):
    """
    Error raised when API response status code is above 200s range
    """

    def __init__(self, message, status_code, **kwargs):
        super(APIError, self).__init__(message)
        self.status_code = status_code
        for k, v in kwargs.iteritems():
            setattr(self, k, v)



class RestAPI(object):
    """
    Abstract REST API
    """

    def send_request(self, kind, resource, url_components, **kwargs):
        """
        Send a request to the REST API

        Parameters
        ----------
        kind: str, {get, delete, put, post, head}
        resource: str
        url_components: list or tuple to be appended to the request URL

        Notes
        -----
        kwargs contain request parameters to be sent as request data
        """
        url = self.format_request_url(resource, *url_components)
        meth = getattr(requests, kind)
        headers = self.get_request_headers()
        req_data = self.format_parameters(**kwargs)
        response = meth(url, headers=headers, data=req_data)
        data = self.get_response(response)
        if response.status_code >= 300:
            msg = data.pop('message', 'API request returned error')
            raise APIError(msg, response.status_code, **data)
        return data

    def get_response(self, resp):
        """
        Retrieve response as json and deserialize as dict

        Parameters
        ----------
        resp: requests.models.Response
        """
        try:
            return resp.json()
        except json.JSONDecodeError:
            return {}

    def get_request_headers(self):
        raise NotImplementedError()<commit_msg>DEP: make simplejson an optional dependency<commit_after>"""
The DigitalOcean API allows you to manage Droplets and resources within the
DigitalOcean cloud in a simple, programmatic way using conventional HTTP
requests. The endpoints are intuitive and powerful, allowing you to easily make
calls to retrieve information or to execute actions.

All of the functionality that you are familiar with in the DigitalOcean control
panel is also available through the API, allowing you to script the complex
actions that your situation requires.
"""

import os
import requests
try:
    import simplejson as json
    JSON_ERROR = json.JSONDecodeError
except ImportError:
    JSON_ERROR = Exception

API_VERSION = 'v2'
API_URL = 'https://api.digitalocean.com'


"""
TODO: refactor for multipage results
TODO: unit tests for Images, ImageActions, and DomainRecords
"""

class APIError(Exception):
    """
    Error raised when API response status code is above 200s range
    """

    def __init__(self, message, status_code, **kwargs):
        super(APIError, self).__init__(message)
        self.status_code = status_code
        for k, v in kwargs.iteritems():
            setattr(self, k, v)



class RestAPI(object):
    """
    Abstract REST API
    """

    def send_request(self, kind, resource, url_components, **kwargs):
        """
        Send a request to the REST API

        Parameters
        ----------
        kind: str, {get, delete, put, post, head}
        resource: str
        url_components: list or tuple to be appended to the request URL

        Notes
        -----
        kwargs contain request parameters to be sent as request data
        """
        url = self.format_request_url(resource, *url_components)
        meth = getattr(requests, kind)
        headers = self.get_request_headers()
        req_data = self.format_parameters(**kwargs)
        response = meth(url, headers=headers, data=req_data)
        data = self.get_response(response)
        if response.status_code >= 300:
            msg = data.pop('message', 'API request returned error')
            raise APIError(msg, response.status_code, **data)
        return data

    def get_response(self, resp):
        """
        Retrieve response as json and deserialize as dict

        Parameters
        ----------
        resp: requests.models.Response
        """
        try:
            return resp.json()
        except JSON_ERROR:
            return {}

    def get_request_headers(self):
        raise NotImplementedError()
{'fraction_non_alphanumeric': 0.08435675458022951, 'fraction_numerical': 0.0028186027783370245, 'mean_word_length': 2.60522496371553, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1823559', 'n_tokens_mistral': 1311, 'n_tokens_neox': 1259, 'n_words': 484}