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