Source code for spinnerchief

# -*- coding: utf-8 -*-

import urllib
import urllib2
import base64
from sets import Set

from spinnerchief import exceptions as ex


[docs]class SpinnerChief(object): """A class representing the Spinner Chief API (http://developer.spinnerchief.com/API_Document.aspx). Articles must be in Unicode object type. """ URL = u'http://api.spinnerchief.com:9001/apikey={apikey}&username={username}&password={password}&' """URL for invoking the API""" TIMEOUT = 10 DEFAULT_PARAMS = { 'protecthtml': '0', 'usehurricane': '1', 'spinhtml': '0', 'percent': '0', 'phrasecount': '2', 'Chartype': '1', 'replacetype': '0', 'autospin': '1', 'convertbase': '0', 'thesaurus': 'English', 'pos': '0', 'Orderly': '0', 'Wordscount': '5', 'spinfreq': '4', 'tagprotect': '[]', 'spintype': '0', 'UseGrammarAI': '0', 'protectwords': None, 'rule': 'none', 'onecharforword': '0', 'wordquality': '0', 'original': '0', } def __init__(self, apikey, username, password): self._url = self.URL.format(apikey=apikey, username=username, password=password)
[docs] def _get_param_value(self, param_name, params): """ Returns parameter value or use default. """ if param_name in params: return params[param_name] elif param_name in self.DEFAULT_PARAMS: return self.DEFAULT_PARAMS[param_name] else: raise ex.WrongParameterName(param_name)
[docs] def _value_has(self, param, values, params): """ Raise WrongParameterVal if value of param is not in values. """ val = self._get_param_value(param, params) if val not in values: raise ex.WrongParameterVal(param, val)
[docs] def _value_is_int(self, param, params): """ Raise WrongParameterVal if value of param is not integer. """ val = self._get_param_value(param, params) try: int(val) except ValueError: raise ex.WrongParameterVal(param, val)
[docs] def _validate(self, params): """ Checks every single parameter and raise error on wrong key or value. """ # remove entries with None value for i, j in params.iteritems(): if j is None: del(i) self._value_has('protecthtml', ['0', '1'], params) self._value_has('usehurricane', ['0', '1'], params) self._value_has('spinhtml', ['0', '1'], params) self._value_has('percent', map(lambda x: str(x), range(0, 101)), params) self._value_has('phrasecount', ['2', '3', '4', 'X'], params) self._value_has('Chartype', ['1', '2', '3'], params) self._value_has('replacetype', map(lambda x: str(x), range(0, 6)), params) self._value_has('autospin', ['0', '1'], params) self._value_has('convertbase', ['0', '1'], params) self._value_has('pos', ['0', '1'], params) self._value_has('Orderly', ['0', '1'], params) self._value_is_int('Wordscount', params) self._value_is_int('spinfreq', params) # allow any combination of '[]','()','<-->' val = self._get_param_value('tagprotect', params) if Set(val.split(',')).difference(Set(['[]', '()', '<-->'])): raise ex.WrongParameterVal('tagprotect', val) self._value_has('spintype', ['0', '1'], params) self._value_has('UseGrammarAI', ['0', '1'], params) self._value_has('onecharforword', ['0', '1'], params) self._value_has('wordquality', ['0', '1', '2', '3', '9'], params) self._value_has('original', ['0', '1'], params) return True
[docs] def quota_used(self): """ The server returns today's used query times of this account. """ response = self._send_request(text='', params={'querytimes': 1}) return response
[docs] def quota_left(self): """ The server returns today's remaining query times of this account. """ response = self._send_request(text='', params={'querytimes': 2}) return response
[docs] def text_with_spintax(self, text, params=None): """ Return processed spun text with spintax. :param text: original text that needs to be changed :type text: string :param params: parameters to pass along with the request :type params: dictionary :return: processed text in spintax format :rtype: string """ if params is None: params = self.DEFAULT_PARAMS else: self._validate(params) params['spintype'] = '0' return self._send_request(text=text, params=params)
[docs] def unique_variation(self, text, params=None): """ Return a unique variation of the given text. :param text: original text that needs to be changed :type text: string :param params: parameters to pass along with the request :type params: dictionary :return: processed text :rtype: string """ if params is None: params = self.DEFAULT_PARAMS else: self._validate(params) params['spintype'] = '1' return self._send_request(text=text, params=params)
[docs] def _send_request(self, text='', params=DEFAULT_PARAMS): """ Invoke Spinner Chief API with given parameters and return its response. :param params: parameters to pass along with the request :type params: dictionary :return: API's response (article) :rtype: string """ urldata = self._url + urllib.urlencode(params) base64text = base64.b64encode(text.encode("utf-8")) req = urllib2.Request(urldata, data=base64text) try: response = urllib2.urlopen(req, timeout=self.TIMEOUT) except urllib2.URLError as e: raise ex.NetworkError(str(e)) result = base64.b64decode(response.read()).decode("utf-8") if result.lower().startswith('error='): self._raise_error(result[6:]) return result
def _raise_error(self, api_response): lower = api_response.lower() error = None if lower.startswith("login error"): error = ex.LoginError(api_response) raise error if error else ex.SpinnerChiefError(api_response)