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