206 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			206 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import re
 | |
| 
 | |
| def pascal_to_loudsnakes(text):
 | |
|     '''
 | |
|     NoSuchPhoto -> NO_SUCH_PHOTO
 | |
|     '''
 | |
|     match = re.findall(r'[A-Z][a-z]*', text)
 | |
|     text = '_'.join(match)
 | |
|     text = text.upper()
 | |
|     return text
 | |
| 
 | |
| class ErrorTypeAdder(type):
 | |
|     '''
 | |
|     During definition, the Exception class will automatically receive a class
 | |
|     attribute called `error_type` which is just the class's name as a string
 | |
|     in the loudsnake casing style. NoSuchPhoto -> NO_SUCH_PHOTO.
 | |
| 
 | |
|     This is used for serialization of the exception object and should
 | |
|     basically act as a status code when displaying the error to the user.
 | |
| 
 | |
|     Thanks Unutbu
 | |
|     http://stackoverflow.com/a/18126678
 | |
|     '''
 | |
|     def __init__(cls, name, bases, clsdict):
 | |
|         type.__init__(cls, name, bases, clsdict)
 | |
|         cls.error_type = pascal_to_loudsnakes(name)
 | |
| 
 | |
| class EtiquetteException(Exception, metaclass=ErrorTypeAdder):
 | |
|     '''
 | |
|     Base type for all of the Etiquette exceptions.
 | |
|     Subtypes should have a class attribute `error_message`. The error message
 | |
|     may contain {format} strings which will be formatted using the
 | |
|     Exception's constructor arguments.
 | |
|     '''
 | |
|     error_message = ''
 | |
| 
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         super().__init__()
 | |
|         self.given_args = args
 | |
|         self.given_kwargs = kwargs
 | |
|         self.error_message = self.error_message.format(*args, **kwargs)
 | |
|         self.args = (self.error_message, args, kwargs)
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.error_type + '\n' + self.error_message
 | |
| 
 | |
| # NO SUCH ##########################################################################################
 | |
| 
 | |
| class NoSuch(EtiquetteException):
 | |
|     pass
 | |
| 
 | |
| class NoSuchAlbum(NoSuch):
 | |
|     error_message = 'Album "{}" does not exist.'
 | |
| 
 | |
| class NoSuchBookmark(NoSuch):
 | |
|     error_message = 'Bookmark "{}" does not exist.'
 | |
| 
 | |
| class NoSuchGroup(NoSuch):
 | |
|     error_message = 'Group "{}" does not exist.'
 | |
| 
 | |
| class NoSuchPhoto(NoSuch):
 | |
|     error_message = 'Photo "{}" does not exist.'
 | |
| 
 | |
| class NoSuchSynonym(NoSuch):
 | |
|     error_message = 'Synonym "{}" does not exist.'
 | |
| 
 | |
| class NoSuchTag(NoSuch):
 | |
|     error_message = 'Tag "{}" does not exist.'
 | |
| 
 | |
| class NoSuchUser(NoSuch):
 | |
|     error_message = 'User "{}" does not exist.'
 | |
| 
 | |
| # EXISTS ###########################################################################################
 | |
| 
 | |
| class Exists(EtiquetteException):
 | |
|     pass
 | |
| 
 | |
| class AlbumExists(Exists):
 | |
|     error_message = 'Album "{}" already exists.'
 | |
| 
 | |
|     def __init__(self, album):
 | |
|         self.album = album
 | |
|         EtiquetteException.__init__(self, album)
 | |
| 
 | |
| class GroupExists(Exists):
 | |
|     error_message = '{member} already in group {group}.'
 | |
| 
 | |
| class PhotoExists(Exists):
 | |
|     error_message = 'Photo "{}" already exists.'
 | |
| 
 | |
|     def __init__(self, photo):
 | |
|         self.photo = photo
 | |
|         EtiquetteException.__init__(self, photo)
 | |
| 
 | |
| class TagExists(Exists):
 | |
|     error_message = 'Tag "{}" already exists.'
 | |
| 
 | |
|     def __init__(self, tag):
 | |
|         self.tag = tag
 | |
|         EtiquetteException.__init__(self, tag)
 | |
| 
 | |
| class UserExists(Exists):
 | |
|     error_message = 'User "{}" already exists.'
 | |
| 
 | |
|     def __init__(self, user):
 | |
|         self.user = user
 | |
|         EtiquetteException.__init__(self, user)
 | |
| 
 | |
| # TAG ERRORS #######################################################################################
 | |
| 
 | |
| class CantGroupSelf(EtiquetteException):
 | |
|     error_message = 'Cannot group {} into itself.'
 | |
| 
 | |
| class CantSynonymSelf(EtiquetteException):
 | |
|     error_message = 'Cannot make {} a synonym of itself.'
 | |
| 
 | |
| class EasyBakeError(EtiquetteException):
 | |
|     error_message = '{}'
 | |
| 
 | |
| class RecursiveGrouping(EtiquetteException):
 | |
|     error_message = '{group} is an ancestor of {member}.'
 | |
| 
 | |
| class TagTooLong(EtiquetteException):
 | |
|     error_message = 'Tag "{}" is too long.'
 | |
| 
 | |
| class TagTooShort(EtiquetteException):
 | |
|     error_message = 'Tag "{}" has too few valid characters.'
 | |
| 
 | |
| # USER ERRORS ######################################################################################
 | |
| 
 | |
| class AlreadySignedIn(EtiquetteException):
 | |
|     error_message = 'You\'re already signed in.'
 | |
| 
 | |
| class InvalidPassword(EtiquetteException):
 | |
|     error_message = 'Password is invalid.'
 | |
| 
 | |
| class InvalidUsername(EtiquetteException):
 | |
|     error_message = 'Username "{username}" is invalid.'
 | |
| 
 | |
| class InvalidUsernameChars(InvalidUsername):
 | |
|     error_message = 'Username "{username}" contains invalid characters: {badchars}.'
 | |
| 
 | |
| class PasswordTooShort(InvalidPassword):
 | |
|     error_message = 'Password is shorter than the minimum of {min_length}.'
 | |
| 
 | |
| class UsernameTooLong(InvalidUsername):
 | |
|     error_message = 'Username "{username}" is longer than maximum of {max_length}.'
 | |
| 
 | |
| class UsernameTooShort(InvalidUsername):
 | |
|     error_message = 'Username "{username}" is shorter than minimum of {min_length}.'
 | |
| 
 | |
| class DisplayNameTooLong(EtiquetteException):
 | |
|     error_message = 'Display name "{display_name}" is longer than maximum of {max_length}.'
 | |
| 
 | |
| class WrongLogin(EtiquetteException):
 | |
|     error_message = 'Wrong username-password combination.'
 | |
| 
 | |
| # SQL ERRORS #######################################################################################
 | |
| 
 | |
| class BadSQL(EtiquetteException):
 | |
|     pass
 | |
| 
 | |
| class BadTable(BadSQL):
 | |
|     error_message = 'Table "{}" does not exist.'
 | |
| 
 | |
| # GENERAL ERRORS ###################################################################################
 | |
| 
 | |
| class BadDataDirectory(EtiquetteException):
 | |
|     '''
 | |
|     Raised by PhotoDB __init__ if the requested data_directory is invalid.
 | |
|     '''
 | |
|     error_message = 'Bad data directory "{}"'
 | |
| 
 | |
| OUTOFDATE = '''
 | |
| Database is out of date. {existing} should be {new}.
 | |
| Please run utilities\\database_upgrader\\database_upgrader.py "{filepath.absolute_path}"
 | |
| '''.strip()
 | |
| class DatabaseOutOfDate(EtiquetteException):
 | |
|     '''
 | |
|     Raised by PhotoDB __init__ if the user's database is behind.
 | |
|     '''
 | |
|     error_message = OUTOFDATE
 | |
| 
 | |
| class DeletedObject(EtiquetteException):
 | |
|     '''
 | |
|     For when thing.deleted == True.
 | |
|     '''
 | |
|     error_message = '{} has already been deleted by another caller.'
 | |
| 
 | |
| class FeatureDisabled(EtiquetteException):
 | |
|     '''
 | |
|     For when features of the system have been disabled by the configuration.
 | |
|     '''
 | |
|     error_message = 'This feature has been disabled. Requires {}.'
 | |
| 
 | |
| class NotExclusive(EtiquetteException):
 | |
|     '''
 | |
|     For when two or more mutually exclusive actions have been requested.
 | |
|     '''
 | |
|     error_message = 'One and only one of {} must be passed.'
 | |
| 
 | |
| class OutOfOrder(EtiquetteException):
 | |
|     '''
 | |
|     For when a requested minmax range (a, b) has b > a
 | |
|     '''
 | |
|     error_message = 'Range "{range}": minimum "{min}" and maximum "{max}" are out of order.'
 |