| """ |
| create errno-specific classes for IO or os calls. |
| |
| """ |
| import sys, os, errno |
| |
| class Error(EnvironmentError): |
| def __repr__(self): |
| return "%s.%s %r: %s " %(self.__class__.__module__, |
| self.__class__.__name__, |
| self.__class__.__doc__, |
| " ".join(map(str, self.args)), |
| #repr(self.args) |
| ) |
| |
| def __str__(self): |
| s = "[%s]: %s" %(self.__class__.__doc__, |
| " ".join(map(str, self.args)), |
| ) |
| return s |
| |
| _winerrnomap = { |
| 2: errno.ENOENT, |
| 3: errno.ENOENT, |
| 17: errno.EEXIST, |
| 13: errno.EBUSY, # empty cd drive, but ENOMEDIUM seems unavailiable |
| 22: errno.ENOTDIR, |
| 20: errno.ENOTDIR, |
| 267: errno.ENOTDIR, |
| 5: errno.EACCES, # anything better? |
| } |
| |
| class ErrorMaker(object): |
| """ lazily provides Exception classes for each possible POSIX errno |
| (as defined per the 'errno' module). All such instances |
| subclass EnvironmentError. |
| """ |
| Error = Error |
| _errno2class = {} |
| |
| def __getattr__(self, name): |
| if name[0] == "_": |
| raise AttributeError(name) |
| eno = getattr(errno, name) |
| cls = self._geterrnoclass(eno) |
| setattr(self, name, cls) |
| return cls |
| |
| def _geterrnoclass(self, eno): |
| try: |
| return self._errno2class[eno] |
| except KeyError: |
| clsname = errno.errorcode.get(eno, "UnknownErrno%d" %(eno,)) |
| errorcls = type(Error)(clsname, (Error,), |
| {'__module__':'py.error', |
| '__doc__': os.strerror(eno)}) |
| self._errno2class[eno] = errorcls |
| return errorcls |
| |
| def checked_call(self, func, *args, **kwargs): |
| """ call a function and raise an errno-exception if applicable. """ |
| __tracebackhide__ = True |
| try: |
| return func(*args, **kwargs) |
| except self.Error: |
| raise |
| except (OSError, EnvironmentError): |
| cls, value, tb = sys.exc_info() |
| if not hasattr(value, 'errno'): |
| raise |
| __tracebackhide__ = False |
| errno = value.errno |
| try: |
| if not isinstance(value, WindowsError): |
| raise NameError |
| except NameError: |
| # we are not on Windows, or we got a proper OSError |
| cls = self._geterrnoclass(errno) |
| else: |
| try: |
| cls = self._geterrnoclass(_winerrnomap[errno]) |
| except KeyError: |
| raise value |
| raise cls("%s%r" % (func.__name__, args)) |
| __tracebackhide__ = True |
| |
| |
| error = ErrorMaker() |