<commit_before>#!/usr/bin/env python

""" Tumblpy """

__author__ = '<NAME> <<EMAIL>>'
__version__ = '0.5.0'

import urllib
import inspect

try:
    from urlparse import parse_qsl
except ImportError:
    from cgi import parse_qsl

import oauth2 as oauth
import httplib2
import urllib2  # Need this for completing upload requests

try:
    import simplejson as json
except ImportError:
    try:
        import json
    except ImportError:
        try:
            from django.utils import simplejson as json
        except ImportError:
            raise ImportError('A json library is required to use this python library. Lol, yay for being verbose. ;)')


import mimetypes
import mimetools
import codecs
from io import BytesIO

writer = codecs.lookup('utf-8')[3]


def get_content_type(filename):
    return mimetypes.guess_type(filename)[0] or 'application/octet-stream'


def iter_fields(fields):
    """Iterate over fields.

    Supports list of (k, v) tuples and dicts.
    """
    if isinstance(fields, dict):
        return ((k, v) for k, v in fields.iteritems())
    return ((k, v) for k, v in fields)

# The following is grabbed from Twython
# Try and gauge the old OAuth2 library spec. Versions 1.5 and greater no longer have the callback
# url as part of the request object; older versions we need to patch for Python 2.5... ugh. ;P
OAUTH_CALLBACK_IN_URL = False
OAUTH_LIB_SUPPORTS_CALLBACK = False
if not hasattr(oauth, '_version') or float(oauth._version.manual_verstr) <= 1.4:
    OAUTH_CLIENT_INSPECTION = inspect.getargspec(oauth.Client.request)
    try:
        OAUTH_LIB_SUPPORTS_CALLBACK = 'callback_url' in OAUTH_CLIENT_INSPECTION.args
    except AttributeError:
        # Python 2.5 doesn't return named tuples, so don't look for an args section specifically.
        OAUTH_LIB_SUPPORTS_CALLBACK = 'callback_url' in OAUTH_CLIENT_INSPECTION
else:
    OAUTH_CALLBACK_IN_URL = True


class TumblpyError(Exception):
    """ Generic error class, catch-all for most Tumblpy issues.

        from Tumblpy import TumblpyError, TumblpyRateLimitError, TumblpyAuthError
    """
    def __init__(self, msg, error_code=None):
        self.msg = msg
        if error_code is not None:
            if error_code == 503:
                raise TumblpyRateLimitError(msg)
            elif error_code == 401:
                raise TumblpyAuthError(msg)

    def __str__(self):
        return repr(self.msg)


class TumblpyRateLimitError(TumblpyError):
    """ Raised when you've hit an API limit.
    """
    def __init__(self, msg):
        self.msg = msg

    def __str__(self):
        return repr(self.msg)


class TumblpyAuthError(TumblpyError):
    """ Raised when you try to access a protected resource and it fails due to some issue with your authentication. """
    def __init__(self, msg):
        self.msg = msg

    def __str__(self):
        return repr(self.msg)


class Tumblpy(object):
    def __init__(self, app_key=None, app_secret=None, oauth_token=None, oauth_token_secret=None, headers=None, client_args=None, callback_url=None):
        # Define some API URLs real quick
        self.base_api_url = 'http://api.tumblr.com'
        self.api_version = 'v2'
        self.api_url = '%s/%s/' % (self.base_api_url, self.api_version)

        # Authentication URLs
        self.request_token_url = 'http://www.tumblr.com/oauth/request_token'
        self.access_token_url = 'http://www.tumblr.com/oauth/access_token'
        self.authorize_url = 'http://www.tumblr.com/oauth/authorize'
        self.authenticate_url = 'http://www.tumblr.com/oauth/authorize'

        self.app_key = app_key
        self.app_secret = app_secret
        self.oauth_token = oauth_token
        self.oauth_token_secret = oauth_token_secret

        self.callback_url = callback_url

        self.default_params = {'api_key': self.app_key}

        # If there's headers, set them. If not, lets
        self.headers = headers or {'User-agent': 'Tumblpy %s' % __version__}

        self.consumer = None
        self.token = None

        client_args = client_args or {}

        # See if they're authenticating for the first or if they already have some tokens.
        # http://michaelhelmick.com/tokens.jpg
        if self.app_key is not None and self.app_secret is not None:
            self.consumer = oauth.Consumer(key=self.app_key, secret=self.app_secret)

        if self.oauth_token is not None and self.oauth_token_secret is not None:
            self.token = oauth.Token(key=self.oauth_token, secret=self.oauth_token_secret)

        if self.consumer is not None and self.token is not None:
            # Authenticated
            self.client = oauth.Client(self.consumer, self.token, **client_args)
        elif self.consumer is not None:
            # Authenticating
            self.client = oauth.Client(self.consumer, **client_args)
        else:
            # Unauthenticated requests (in case Tumblr decides to open up some API calls to public)
            self.client = httplib2.Http(**client_args)

    def get_authentication_tokens(self):
        """ So, you want to get an authentication url?

            t = Tumblpy(YOUR_CONFIG)
            auth_props = t.get_authentication_tokens()
            auth_url = auth_props['auth_url']
            print auth_url
        """
        callback_url = self.callback_url

        request_args = {}
        method = 'GET'

        if OAUTH_LIB_SUPPORTS_CALLBACK:
            request_args['oauth_callback'] = callback_url
        else:
            # Thanks @jbouvier for the following hack
            # This is a hack for versions of oauth that don't support the callback url
            request_args['body'] = urllib.urlencode({'oauth_callback': callback_url})
            method = 'POST'

        resp, content = self.client.request(self.request_token_url, method, **request_args)

        status = int(resp['status'])
        if status != 200:
            raise TumblpyAuthError('There was a problem authenticating you. Error: %s, Message: %s' % (status, content))

        request_tokens = dict(parse_qsl(content))

        auth_url_params = {<commit_msg>Added Tumblr API HTTP error code to exception classes<commit_after>#!/usr/bin/env python

""" Tumblpy """

__author__ = '<NAME> <<EMAIL>>'
__version__ = '0.5.0'

import urllib
import inspect

try:
    from urlparse import parse_qsl
except ImportError:
    from cgi import parse_qsl

import oauth2 as oauth
import httplib2
import urllib2  # Need this for completing upload requests

try:
    import simplejson as json
except ImportError:
    try:
        import json
    except ImportError:
        try:
            from django.utils import simplejson as json
        except ImportError:
            raise ImportError('A json library is required to use this python library. Lol, yay for being verbose. ;)')


import mimetypes
import mimetools
import codecs
from io import BytesIO

writer = codecs.lookup('utf-8')[3]


def get_content_type(filename):
    return mimetypes.guess_type(filename)[0] or 'application/octet-stream'


def iter_fields(fields):
    """Iterate over fields.

    Supports list of (k, v) tuples and dicts.
    """
    if isinstance(fields, dict):
        return ((k, v) for k, v in fields.iteritems())
    return ((k, v) for k, v in fields)

# The following is grabbed from Twython
# Try and gauge the old OAuth2 library spec. Versions 1.5 and greater no longer have the callback
# url as part of the request object; older versions we need to patch for Python 2.5... ugh. ;P
OAUTH_CALLBACK_IN_URL = False
OAUTH_LIB_SUPPORTS_CALLBACK = False
if not hasattr(oauth, '_version') or float(oauth._version.manual_verstr) <= 1.4:
    OAUTH_CLIENT_INSPECTION = inspect.getargspec(oauth.Client.request)
    try:
        OAUTH_LIB_SUPPORTS_CALLBACK = 'callback_url' in OAUTH_CLIENT_INSPECTION.args
    except AttributeError:
        # Python 2.5 doesn't return named tuples, so don't look for an args section specifically.
        OAUTH_LIB_SUPPORTS_CALLBACK = 'callback_url' in OAUTH_CLIENT_INSPECTION
else:
    OAUTH_CALLBACK_IN_URL = True


class TumblpyError(Exception):
    """ Generic error class, catch-all for most Tumblpy issues.

        from Tumblpy import TumblpyError, TumblpyRateLimitError, TumblpyAuthError
    """
    def __init__(self, msg, error_code=None):
        self.msg = msg
        self.error_code = error_code
        if error_code is not None:
            if error_code == 503:
                raise TumblpyRateLimitError(msg, error_code)
            elif error_code == 401:
                raise TumblpyAuthError(msg, error_code)

    def __str__(self):
        return repr(self.msg)


class TumblpyRateLimitError(TumblpyError):
    """ Raised when you've hit an API limit.
    """
    def __init__(self, msg, error_code=None):
        self.msg = msg
        self.error_code = error_code

    def __str__(self):
        return repr(self.msg)


class TumblpyAuthError(TumblpyError):
    """ Raised when you try to access a protected resource and it fails due to some issue with your authentication. """
    def __init__(self, msg, error_code=None):
        self.msg = msg
        self.error_code = error_code

    def __str__(self):
        return repr(self.msg)


class Tumblpy(object):
    def __init__(self, app_key=None, app_secret=None, oauth_token=None, oauth_token_secret=None, headers=None, client_args=None, callback_url=None):
        # Define some API URLs real quick
        self.base_api_url = 'http://api.tumblr.com'
        self.api_version = 'v2'
        self.api_url = '%s/%s/' % (self.base_api_url, self.api_version)

        # Authentication URLs
        self.request_token_url = 'http://www.tumblr.com/oauth/request_token'
        self.access_token_url = 'http://www.tumblr.com/oauth/access_token'
        self.authorize_url = 'http://www.tumblr.com/oauth/authorize'
        self.authenticate_url = 'http://www.tumblr.com/oauth/authorize'

        self.app_key = app_key
        self.app_secret = app_secret
        self.oauth_token = oauth_token
        self.oauth_token_secret = oauth_token_secret

        self.callback_url = callback_url

        self.default_params = {'api_key': self.app_key}

        # If there's headers, set them. If not, lets
        self.headers = headers or {'User-agent': 'Tumblpy %s' % __version__}

        self.consumer = None
        self.token = None

        client_args = client_args or {}

        # See if they're authenticating for the first or if they already have some tokens.
        # http://michaelhelmick.com/tokens.jpg
        if self.app_key is not None and self.app_secret is not None:
            self.consumer = oauth.Consumer(key=self.app_key, secret=self.app_secret)

        if self.oauth_token is not None and self.oauth_token_secret is not None:
            self.token = oauth.Token(key=self.oauth_token, secret=self.oauth_token_secret)

        if self.consumer is not None and self.token is not None:
            # Authenticated
            self.client = oauth.Client(self.consumer, self.token, **client_args)
        elif self.consumer is not None:
            # Authenticating
            self.client = oauth.Client(self.consumer, **client_args)
        else:
            # Unauthenticated requests (in case Tumblr decides to open up some API calls to public)
            self.client = httplib2.Http(**client_args)

    def get_authentication_tokens(self):
        """ So, you want to get an authentication url?

            t = Tumblpy(YOUR_CONFIG)
            auth_props = t.get_authentication_tokens()
            auth_url = auth_props['auth_url']
            print auth_url
        """
        callback_url = self.callback_url

        request_args = {}
        method = 'GET'

        if OAUTH_LIB_SUPPORTS_CALLBACK:
            request_args['oauth_callback'] = callback_url
        else:
            # Thanks @jbouvier for the following hack
            # This is a hack for versions of oauth that don't support the callback url
            request_args['body'] = urllib.urlencode({'oauth_callback': callback_url})
            method = 'POST'

        resp, content = self.client.request(self.request_token_url, method, **request_args)

        status = int(resp['status'])
        if status != 200:
            raise TumblpyAuthError('There was a problem authenticating you. Error: %s, Message: %s' % (status, content), error_code=status)

        request_tokens = dict(parse_qsl(content))

        auth_url_params = {
{'fraction_non_alphanumeric': 0.08848562710775655, 'fraction_numerical': 0.004657138268829292, 'mean_word_length': 2.7742424242424244, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 8, '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': '5119436', 'n_tokens_mistral': 3935, 'n_tokens_neox': 3758, 'n_words': 1071}