|
3 | 3 |
|
4 | 4 |
|
5 | 5 | from __future__ import absolute_import |
6 | | -import six |
| 6 | +from __future__ import print_function |
| 7 | +import errno |
7 | 8 | import numbers |
| 9 | +import os |
| 10 | +import six |
| 11 | +import sys |
8 | 12 |
|
9 | 13 |
|
10 | 14 | class PycommandsException(Exception): |
@@ -61,14 +65,72 @@ class MultipleResultsFound(QueryException): |
61 | 65 |
|
62 | 66 | class iRODSExceptionMeta(type): |
63 | 67 | codes = {} |
64 | | - |
| 68 | + positive_code_error_message = "For {name}, a positive code of {attrs[code]} was declared." |
65 | 69 | def __init__(self, name, bases, attrs): |
66 | 70 | if 'code' in attrs: |
| 71 | + if attrs['code'] > 0: |
| 72 | + print(self.positive_code_error_message.format(**locals()), file = sys.stderr) |
| 73 | + exit(1) |
67 | 74 | iRODSExceptionMeta.codes[attrs['code']] = self |
68 | 75 |
|
69 | 76 |
|
| 77 | +class Errno: |
| 78 | + """Encapsulates an integer error code from the operating system |
| 79 | + and provides a text representation. |
| 80 | + """ |
| 81 | + def __init__(self,arg0,*_): |
| 82 | + """Initializes an object with an integer error code arg0. |
| 83 | + Further arguments are optional and ignored. |
| 84 | + """ |
| 85 | + self.int_code = arg0 |
| 86 | + |
| 87 | + def __repr__(self): |
| 88 | + e = self.int_code |
| 89 | + try: |
| 90 | + return self.__class__.__name__ + repr(tuple([e, errno.errorcode[e], os.strerror(e)])) |
| 91 | + except: |
| 92 | + # The errno code is unrecognized, so fall through to default representation. |
| 93 | + pass |
| 94 | + return self.__class__.__name__ + repr(tuple([e,])) |
| 95 | + |
| 96 | + def __int__(self): |
| 97 | + return self.int_code |
| 98 | + |
| 99 | + |
70 | 100 | class iRODSException(six.with_metaclass(iRODSExceptionMeta, Exception)): |
71 | | - pass |
| 101 | + """An exception that originates from a server error. |
| 102 | + Exception classes that are derived from this base and represent a concrete error, should |
| 103 | + store a unique error code (X*1000) in their 'code' attribute, where X < 0. |
| 104 | + """ |
| 105 | + |
| 106 | + def __init__(self,*arg): |
| 107 | + explicit_errno = None |
| 108 | + argl = list(arg) |
| 109 | + |
| 110 | + # For consistency with the text representation, allow initialization with an Errno object |
| 111 | + # at the end of the argument list. |
| 112 | + # Example: err = UNIX_FILE_OPEN_ERR('message', Errno(13)) |
| 113 | + # err_copy = eval(repr(err)) |
| 114 | + if hasattr(self.__class__,'code'): |
| 115 | + if argl and isinstance (argl[-1],Errno): |
| 116 | + explicit_errno = argl.pop() |
| 117 | + |
| 118 | + super(iRODSException,self).__init__(*argl) |
| 119 | + |
| 120 | + # To properly represent the Errno instance, the "code" attribute should be (-errno) plus the thousands |
| 121 | + # attribute stored in the class's code attribute. Because Python honors the instance "code" attribute |
| 122 | + # over the class "code" attribute, the following does _not_ modify the class: |
| 123 | + if explicit_errno: |
| 124 | + self.code -= int(explicit_errno) |
| 125 | + |
| 126 | + def __repr__(self): |
| 127 | + args = tuple(self.args) |
| 128 | + code = getattr(self,'code',None) |
| 129 | + if code is not None: |
| 130 | + os_err = abs(code) % 1000 |
| 131 | + if os_err: args += (Errno(os_err),) |
| 132 | + return self.__class__.__name__ + repr(args) |
| 133 | + |
72 | 134 |
|
73 | 135 |
|
74 | 136 | def nominal_code( the_code, THRESHOLD = 1000 ): |
|
0 commit comments