summaryrefslogtreecommitdiff
path: root/fs/errors.py
blob: 372096a570db7995c5a501f0e2d31460cc26873f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
"""

  fs.errors:  error class definitions for FS

"""

import sys
import errno

try:
    from functools import wraps
except ImportError:
    def wraps(func):
        def decorator(wfunc):
            wfunc.__name__ == func.__name__
            wfunc.__doc__ == func.__doc__
            wfunc.__module__ == func.__module__
        return decorator


class FSError(Exception):
    """Base exception class for the FS module."""
    default_message = "Unspecified error"

    def __init__(self,msg=None,details=None):
        if msg is None:
            msg = self.default_message
        self.msg = msg
        self.details = details

    def __str__(self):
        keys = dict((k,str(v)) for k,v in self.__dict__.iteritems())
        return self.msg % keys

    def __unicode__(self):
        return unicode(str(self))


class PathError(FSError):
    """Exception for errors to do with a path string."""
    default_message = "Path is invalid: %(path)s"

    def __init__(self,path,**kwds):
        self.path = path
        super(PathError,self).__init__(**kwds)
 

class OperationFailedError(FSError):
    """Base exception class for errors associated with a specific operation."""
    default_message = "Unable to %(opname)s: unspecified error [%(errno)s - %(details)s]"

    def __init__(self,opname,path=None,**kwds):
        self.opname = opname
        self.path = path
        self.errno = getattr(kwds.get("details",None),"errno",None)
        super(OperationFailedError,self).__init__(**kwds)


class UnsupportedError(OperationFailedError):
    """Exception raised for operations that are not supported by the FS."""
    default_message = "Unable to %(opname)s: not supported by this filesystem"


class RemoteConnectionError(OperationFailedError):
    """Exception raised when operations encounter remote connection trouble."""
    default_message = "Unable to %(opname)s: remote connection errror"


class StorageSpaceError(OperationFailedError):
    """Exception raised when operations encounter storage space trouble."""
    default_message = "Unable to %(opname)s: insufficient storage space"


class PermissionDeniedError(OperationFailedError):
    default_message = "Unable to %(opname)s: permission denied"



class ResourceError(FSError):
    """Base exception class for error associated with a specific resource."""
    default_message = "Unspecified resource error: %(path)s"

    def __init__(self,path,**kwds):
        self.path = path
        self.opname = kwds.pop("opname",None)
        super(ResourceError,self).__init__(**kwds)


class NoSysPathError(ResourceError):
    """Exception raised when there is no syspath for a given path."""
    default_message = "No mapping to OS filesystem: %(path)s"


class ResourceNotFoundError(ResourceError):
    """Exception raised when a required resource is not found."""
    default_message = "Resource not found: %(path)s"


class ResourceInvalidError(ResourceError):
    """Exception raised when a resource is the wrong type."""
    default_message = "Resource is invalid: %(path)s"


class DestinationExistsError(ResourceError):
    """Exception raised when a target destination already exists."""
    default_message = "Destination exists: %(path)s"


class DirectoryNotEmptyError(ResourceError):
    """Exception raised when a directory to be removed is not empty."""
    default_message = "Directory is not empty: %(path)s"


class ParentDirectoryMissingError(ResourceError):
    """Exception raised when a parent directory is missing."""
    default_message = "Parent directory is missing: %(path)s"


class ResourceLockedError(ResourceError):
    """Exception raised when a resource can't be used because it is locked."""
    default_message = "Resource is locked: %(path)s"



def convert_fs_errors(func):
    """Function wrapper to convert FSError instances into OSErrors."""
    @wraps(func)
    def wrapper(*args,**kwds):
        try:
            return func(*args,**kwds)
        except ResourceNotFoundError, e:
            raise OSError(errno.ENOENT,str(e))
        except ResourceInvalidError, e:
            raise OSError(errno.EINVAL,str(e))
        except PermissionDeniedError, e:
            raise OSError(errno.EACCESS,str(e))
        except DirectoryNotEmptyError, e:
            raise OSError(errno.ENOTEMPTY,str(e))
        except DestinationExistsError, e:
            raise OSError(errno.EEXIST,str(e))
        except StorageSpaceError, e:
            raise OSError(errno.ENOSPC,str(e))
        except RemoteConnectionError, e:
            raise OSError(errno.ENONET,str(e))
        except UnsupportedError, e:
            raise OSError(errno.ENOSYS,str(e))
        except FSError, e:
            raise OSError(errno.EFAULT,str(e))
    return wrapper


def convert_os_errors(func):
    """Function wrapper to convert OSError/IOError instances into FSErrors."""
    opname = func.__name__
    @wraps(func)
    def wrapper(*args,**kwds):
        try:
            return func(*args,**kwds)
        except (OSError,IOError), e:
            if not hasattr(e,"errno") or not e.errno:
                raise OperationFailedError(opname,details=e)
            if e.errno == errno.ENOENT:
                raise ResourceNotFoundError(e.filename,opname=opname,details=e)
            if e.errno == errno.ENOTEMPTY:
                raise DirectoryNotEmptyError(e.filename,opname=opname,details=e)
            if e.errno == errno.EEXIST:
                raise DestinationExistsError(e.filename,opname=opname,details=e)
            if e.errno == 183: # some sort of win32 equivalent to EEXIST
                raise DestinationExistsError(e.filename,opname=opname,details=e)
            if e.errno == errno.ENOTDIR:
                raise ResourceInvalidError(e.filename,opname=opname,details=e)
            if e.errno == errno.EISDIR:
                raise ResourceInvalidError(e.filename,opname=opname,details=e)
            if e.errno == errno.EINVAL:
                raise ResourceInvalidError(e.filename,opname=opname,details=e)
            raise OperationFailedError(opname,details=e)
    return wrapper