<commit_before># -*- coding: utf-8 -*-
#
# pylast - Python bindings for the Last.fm webservices.
# Copyright (C) 2008-2009  <NAME>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
#
# For help regarding using this library, please visit the official
# documentation at http://code.google.com/p/pylast/wiki/Documentation

LIB_NAME = 'pyLast'
LIB_VERSION = '0.2b2'

API_SERVER = 'ws.audioscrobbler.com'
API_SUBDIR = '/2.0/'

import md5
import httplib
import urllib
import threading
from xml.dom import minidom

USE_SILENT_EXCEPTIONS = True

STATUS_OK = 'ok'
STATUS_FAILED = 'failed'
STATUS_INVALID_SERVICE = 2
STATUS_INVALID_METHOD = 3
STATUS_AUTH_FAILED = 4
STATUS_INVALID_FORMAT = 5
STATUS_INVALID_PARAMS = 6
STATUS_INVALID_RESOURCE = 7
STATUS_TOKEN_ERROR = 8
STATUS_INVALID_SK = 9
STATUS_INVALID_API_KEY = 10
STATUS_OFFLINE = 11
STATUS_SUBSCRIBERS_ONLY = 12
STATUS_TOKEN_UNAUTHORIZED = 14
STATUS_TOKEN_EXPIRED = 15

EVENT_ATTENDING = '0'
EVENT_MAYBE_ATTENDING = '1'
EVENT_NOT_ATTENDING = '2'

PERIOD_OVERALL = 'overall'
PERIOD_3MONTHS = '3month'
PERIOD_6MONTHS = '6month'
PERIOD_12MONTHS = '12month'

IMAGE_SMALL = 0
IMAGE_MEDIUM = 1
IMAGE_LARGE = 2

DOMAIN_ENGLISH = 'www.last.fm'
DOMAIN_GERMAN = 'www.lastfm.de'
DOMAIN_SPANISH = 'www.lastfm.es'
DOMAIN_FRENCH = 'www.lastfm.fr'
DOMAIN_ITALIAN = 'www.lastfm.it'
DOMAIN_POLISH = 'www.lastfm.pl'
DOMAIN_PORTUGUESE = 'www.lastfm.com.br'
DOMAIN_SWEDISH = 'www.lastfm.se'
DOMAIN_TURKISH = 'www.lastfm.com.tr'
DOMAIN_RUSSIAN = 'www.lastfm.ru'
DOMAIN_JAPANESE = 'www.lastfm.jp'
DOMAIN_CHINESE = 'cn.last.fm'

def _status2str(lastfm_status):
	
	statuses = {
		STATUS_OK: 'OK',
		STATUS_FAILED: 'Failed',
		STATUS_INVALID_METHOD: 'Invalid Method - No method with that name in this package',
		STATUS_TOKEN_ERROR: 'Token Error - There was an error granting the request token',
		STATUS_INVALID_SERVICE: 'Invalid Service - This service does not exist',
		STATUS_AUTH_FAILED: 'Authentication Failed - You do not have permissions to access the service',
		STATUS_INVALID_FORMAT: "Invalid Format - This service doesn't exist in that format",
		STATUS_INVALID_PARAMS: 'Invalid Parameters - Your request is missing a required parameter',
		STATUS_INVALID_RESOURCE: 'Invalid Resource Specified',
		STATUS_INVALID_SK: 'Invalid Session Key - Please re-authenticate',
		STATUS_INVALID_API_KEY: 'Invalid API Key - You must be granted a valid key by last.fm',
		STATUS_OFFLINE: 'Service Offline - This service is temporarily offline. Try again later.',
		STATUS_SUBSCRIBERS_ONLY: 'Subscribers Only - This service is only available to paid last.fm subscribers',
		STATUS_TOKEN_UNAUTHORIZED: 'Unauthorized Token - This token has not been authorized',
		STATUS_TOKEN_EXPIRED: 'Token Expired -This token has expired'
	}
	
	return statuses[int(lastfm_status)]

class ServiceException(Exception):
	"""Exception related to the Last.fm web service"""
	
	def __init__(self, lastfm_status, details):
		self._lastfm_status = lastfm_status
		self._details = details
	
	def __str__(self):
		return "%s: %s." %(_status2str(self._lastfm_status), self._details)

class Asynchronizer(threading.Thread):
	"""Hopingly, this class would help perform asynchronous operations less painfully.
	For inherited use only. And you must call Asynchronizer.__init__(descendant) before usage.
	"""
	
	def __init__(self):
		threading.Thread.__init__(self)
		
		self._calls = {}		#calls is structured like this: {call_pointer: (arg1, arg2, ...)}
		self._callbacks = {} 	#callbacks is structred like this: {call_pointer: callback_pointer}
	
	def run(self):
		"""Avoid running this function. Use start() to begin the thread's work."""
		for call in self._calls.keys():
			output = call(*(self._calls[call]))
			callback = self._callbacks[call]
			callback(self, output)
			
			del self._calls[call]
			del self._callbacks[call]
	
	def async_call(self, callback, call, *call_args):
		"""This is the function for setting up an asynchronous operation.
		* callback: the function to callback afterwards, accepting two argument, one being the sender and the other is the return of the target call.
		* call: the target call.
		* *call_args: any number of arguments to pass to the target call function.
		"""
		
		self._calls[call] = call_args
		self._callbacks[call] = callback

class Exceptionable(object):
	"""An abstract class that adds support for error reporting."""
	
	def __init__(self, parent = None):
		self.__errors = []
		self.__raising_exceptions = not USE_SILENT_EXCEPTIONS
		<commit_msg>* Added a little work-around on python's threading.Thread to make Asynchronizer objects able to restart more than once.<commit_after># -*- coding: utf-8 -*-
#
# pylast - Python bindings for the Last.fm webservices.
# Copyright (C) 2008-2009  <NAME>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
#
# For help regarding using this library, please visit the official
# documentation at http://code.google.com/p/pylast/wiki/Documentation

LIB_NAME = 'pyLast'
LIB_VERSION = '0.2b3'

API_SERVER = 'ws.audioscrobbler.com'
API_SUBDIR = '/2.0/'

import md5
import httplib
import urllib
import threading
from xml.dom import minidom

USE_SILENT_EXCEPTIONS = True

STATUS_OK = 'ok'
STATUS_FAILED = 'failed'
STATUS_INVALID_SERVICE = 2
STATUS_INVALID_METHOD = 3
STATUS_AUTH_FAILED = 4
STATUS_INVALID_FORMAT = 5
STATUS_INVALID_PARAMS = 6
STATUS_INVALID_RESOURCE = 7
STATUS_TOKEN_ERROR = 8
STATUS_INVALID_SK = 9
STATUS_INVALID_API_KEY = 10
STATUS_OFFLINE = 11
STATUS_SUBSCRIBERS_ONLY = 12
STATUS_TOKEN_UNAUTHORIZED = 14
STATUS_TOKEN_EXPIRED = 15

EVENT_ATTENDING = '0'
EVENT_MAYBE_ATTENDING = '1'
EVENT_NOT_ATTENDING = '2'

PERIOD_OVERALL = 'overall'
PERIOD_3MONTHS = '3month'
PERIOD_6MONTHS = '6month'
PERIOD_12MONTHS = '12month'

IMAGE_SMALL = 0
IMAGE_MEDIUM = 1
IMAGE_LARGE = 2

DOMAIN_ENGLISH = 'www.last.fm'
DOMAIN_GERMAN = 'www.lastfm.de'
DOMAIN_SPANISH = 'www.lastfm.es'
DOMAIN_FRENCH = 'www.lastfm.fr'
DOMAIN_ITALIAN = 'www.lastfm.it'
DOMAIN_POLISH = 'www.lastfm.pl'
DOMAIN_PORTUGUESE = 'www.lastfm.com.br'
DOMAIN_SWEDISH = 'www.lastfm.se'
DOMAIN_TURKISH = 'www.lastfm.com.tr'
DOMAIN_RUSSIAN = 'www.lastfm.ru'
DOMAIN_JAPANESE = 'www.lastfm.jp'
DOMAIN_CHINESE = 'cn.last.fm'

def _status2str(lastfm_status):
	
	statuses = {
		STATUS_OK: 'OK',
		STATUS_FAILED: 'Failed',
		STATUS_INVALID_METHOD: 'Invalid Method - No method with that name in this package',
		STATUS_TOKEN_ERROR: 'Token Error - There was an error granting the request token',
		STATUS_INVALID_SERVICE: 'Invalid Service - This service does not exist',
		STATUS_AUTH_FAILED: 'Authentication Failed - You do not have permissions to access the service',
		STATUS_INVALID_FORMAT: "Invalid Format - This service doesn't exist in that format",
		STATUS_INVALID_PARAMS: 'Invalid Parameters - Your request is missing a required parameter',
		STATUS_INVALID_RESOURCE: 'Invalid Resource Specified',
		STATUS_INVALID_SK: 'Invalid Session Key - Please re-authenticate',
		STATUS_INVALID_API_KEY: 'Invalid API Key - You must be granted a valid key by last.fm',
		STATUS_OFFLINE: 'Service Offline - This service is temporarily offline. Try again later.',
		STATUS_SUBSCRIBERS_ONLY: 'Subscribers Only - This service is only available to paid last.fm subscribers',
		STATUS_TOKEN_UNAUTHORIZED: 'Unauthorized Token - This token has not been authorized',
		STATUS_TOKEN_EXPIRED: 'Token Expired -This token has expired'
	}
	
	return statuses[int(lastfm_status)]

class ServiceException(Exception):
	"""Exception related to the Last.fm web service"""
	
	def __init__(self, lastfm_status, details):
		self._lastfm_status = lastfm_status
		self._details = details
	
	def __str__(self):
		return "%s: %s." %(_status2str(self._lastfm_status), self._details)

class Asynchronizer(threading.Thread):
	"""Hopingly, this class would help perform asynchronous operations less painfully.
	For inherited use only. And you must call Asynchronizer.__init__(descendant) before usage.
	"""
	
	def __init__(self):
		threading.Thread.__init__(self)
		
		self._calls = {}		#calls is structured like this: {call_pointer: (arg1, arg2, ...)}
		self._callbacks = {} 	#callbacks is structred like this: {call_pointer: callback_pointer}
	
	def run(self):
		"""Avoid running this function. Use start() to begin the thread's work."""
		for call in self._calls.keys():
			output = call(*(self._calls[call]))
			callback = self._callbacks[call]
			callback(self, output)
			
			del self._calls[call]
			del self._callbacks[call]
	
	def async_call(self, callback, call, *call_args):
		"""This is the function for setting up an asynchronous operation.
		* callback: the function to callback afterwards, accepting two argument, one being the sender and the other is the return of the target call.
		* call: the target call.
		* *call_args: any number of arguments to pass to the target call function.
		"""
		
		self._calls[call] = call_args
		self._callbacks[call] = callback
	
	def start(self):
		"""Since that Python thread objects can only be started once. This is my little work-around."""
		
		threading.Thread.__init__(self)
		super(Asynchronizer, self).start()

class Exceptionable(object):
	"""An abstract class that adds support for error reporting."""
	
	def __init__(self, parent = None):
		self.__errors = []
		self.__raising_exceptions = not USE_SILENT_EXCEPTIONS
		
{'fraction_non_alphanumeric': 0.09024759024759024, 'fraction_numerical': 0.012474012474012475, 'mean_word_length': 4.779901693063899, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 22, 'xml': 2}, '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': '848935', 'n_tokens_mistral': 3574, 'n_tokens_neox': 3328, 'n_words': 1117}