1"""
2create errno-specific classes for IO or os calls.
3
4"""
5import sys, os, errno
6
7class Error(EnvironmentError):
8    def __repr__(self):
9        return "%s.%s %r: %s " %(self.__class__.__module__,
10                               self.__class__.__name__,
11                               self.__class__.__doc__,
12                               " ".join(map(str, self.args)),
13                               #repr(self.args)
14                                )
15
16    def __str__(self):
17        s = "[%s]: %s" %(self.__class__.__doc__,
18                          " ".join(map(str, self.args)),
19                          )
20        return s
21
22_winerrnomap = {
23    2: errno.ENOENT,
24    3: errno.ENOENT,
25    17: errno.EEXIST,
26    13: errno.EBUSY, # empty cd drive, but ENOMEDIUM seems unavailiable
27    22: errno.ENOTDIR,
28    20: errno.ENOTDIR,
29    267: errno.ENOTDIR,
30    5: errno.EACCES,  # anything better?
31}
32
33class ErrorMaker(object):
34    """ lazily provides Exception classes for each possible POSIX errno
35        (as defined per the 'errno' module).  All such instances
36        subclass EnvironmentError.
37    """
38    Error = Error
39    _errno2class = {}
40
41    def __getattr__(self, name):
42        if name[0] == "_":
43            raise AttributeError(name)
44        eno = getattr(errno, name)
45        cls = self._geterrnoclass(eno)
46        setattr(self, name, cls)
47        return cls
48
49    def _geterrnoclass(self, eno):
50        try:
51            return self._errno2class[eno]
52        except KeyError:
53            clsname = errno.errorcode.get(eno, "UnknownErrno%d" %(eno,))
54            errorcls = type(Error)(clsname, (Error,),
55                    {'__module__':'py.error',
56                     '__doc__': os.strerror(eno)})
57            self._errno2class[eno] = errorcls
58            return errorcls
59
60    def checked_call(self, func, *args, **kwargs):
61        """ call a function and raise an errno-exception if applicable. """
62        __tracebackhide__ = True
63        try:
64            return func(*args, **kwargs)
65        except self.Error:
66            raise
67        except (OSError, EnvironmentError):
68            cls, value, tb = sys.exc_info()
69            if not hasattr(value, 'errno'):
70                raise
71            __tracebackhide__ = False
72            errno = value.errno
73            try:
74                if not isinstance(value, WindowsError):
75                    raise NameError
76            except NameError:
77                # we are not on Windows, or we got a proper OSError
78                cls = self._geterrnoclass(errno)
79            else:
80                try:
81                    cls = self._geterrnoclass(_winerrnomap[errno])
82                except KeyError:
83                    raise value
84            raise cls("%s%r" % (func.__name__, args))
85            __tracebackhide__ = True
86
87
88error = ErrorMaker()
89