1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

""" 

This module contains fixups for using nose under different versions of Python. 

""" 

import sys 

import os 

import traceback 

import types 

import inspect 

import nose.util 

 

__all__ = ['make_instancemethod', 'cmp_to_key', 'sort_list', 'ClassType', 

'TypeType', 'UNICODE_STRINGS', 'unbound_method', 'ismethod', 

'bytes_', 'is_base_exception', 'force_unicode', 'exc_to_unicode', 

'format_exception'] 

 

# In Python 3.x, all strings are unicode (the call to 'unicode()' in the 2.x 

# source will be replaced with 'str()' when running 2to3, so this test will 

# then become true) 

UNICODE_STRINGS = (type(str()) == type(str())) 

 

if sys.version_info[:2] < (3, 0): 

def force_unicode(s, encoding='UTF-8'): 

try: 

s = str(s) 

except UnicodeDecodeError: 

s = str(s).decode(encoding, 'replace') 

 

return s 

else: 

def force_unicode(s, encoding='UTF-8'): 

return str(s) 

 

# new.instancemethod() is obsolete for new-style classes (Python 3.x) 

# We need to use descriptor methods instead. 

try: 

import new 

def make_instancemethod(function, instance): 

return new.instancemethod(function.__func__, instance, 

instance.__class__) 

except ImportError: 

def make_instancemethod(function, instance): 

return function.__get__(instance, instance.__class__) 

 

# To be forward-compatible, we do all list sorts using keys instead of cmp 

# functions. However, part of the unittest.TestLoader API involves a 

# user-provideable cmp function, so we need some way to convert that. 

def cmp_to_key(mycmp): 

'Convert a cmp= function into a key= function' 

class Key(object): 

def __init__(self, obj): 

self.obj = obj 

def __lt__(self, other): 

return mycmp(self.obj, other.obj) < 0 

def __gt__(self, other): 

return mycmp(self.obj, other.obj) > 0 

def __eq__(self, other): 

return mycmp(self.obj, other.obj) == 0 

return Key 

 

# Python 2.3 also does not support list-sorting by key, so we need to convert 

# keys to cmp functions if we're running on old Python.. 

if sys.version_info < (2, 4): 

def sort_list(l, key, reverse=False): 

if reverse: 

return l.sort(lambda a, b: cmp(key(b), key(a))) 

else: 

return l.sort(lambda a, b: cmp(key(a), key(b))) 

else: 

def sort_list(l, key, reverse=False): 

return l.sort(key=key, reverse=reverse) 

 

# In Python 3.x, all objects are "new style" objects descended from 'type', and 

# thus types.ClassType and types.TypeType don't exist anymore. For 

# compatibility, we make sure they still work. 

if hasattr(types, 'ClassType'): 

ClassType = type 

TypeType = type 

else: 

ClassType = type 

TypeType = type 

 

# The following emulates the behavior (we need) of an 'unbound method' under 

# Python 3.x (namely, the ability to have a class associated with a function 

# definition so that things can do stuff based on its associated class) 

class UnboundMethod: 

def __init__(self, cls, func): 

# Make sure we have all the same attributes as the original function, 

# so that the AttributeSelector plugin will work correctly... 

self.__dict__ = func.__dict__.copy() 

self._func = func 

self.__self__ = UnboundSelf(cls) 

if sys.version_info < (3, 0): 

self.__self__.__class__ = cls 

self.__doc__ = getattr(func, '__doc__', None) 

 

def address(self): 

cls = self.__self__.cls 

modname = cls.__module__ 

module = sys.modules[modname] 

filename = getattr(module, '__file__', None) 

if filename is not None: 

filename = os.path.abspath(filename) 

return (nose.util.src(filename), modname, "%s.%s" % (cls.__name__, 

self._func.__name__)) 

 

def __call__(self, *args, **kwargs): 

return self._func(*args, **kwargs) 

 

def __getattr__(self, attr): 

return getattr(self._func, attr) 

 

def __repr__(self): 

return '<unbound method %s.%s>' % (self.__self__.cls.__name__, 

self._func.__name__) 

 

class UnboundSelf: 

def __init__(self, cls): 

self.cls = cls 

 

# We have to do this hackery because Python won't let us override the 

# __class__ attribute... 

def __getattribute__(self, attr): 

if attr == '__class__': 

return self.cls 

else: 

return object.__getattribute__(self, attr) 

 

def unbound_method(cls, func): 

if inspect.ismethod(func): 

return func 

if not inspect.isfunction(func): 

raise TypeError('%s is not a function' % (repr(func),)) 

return UnboundMethod(cls, func) 

 

def ismethod(obj): 

return inspect.ismethod(obj) or isinstance(obj, UnboundMethod) 

 

 

# Make a pseudo-bytes function that can be called without the encoding arg: 

if sys.version_info >= (3, 0): 

def bytes_(s, encoding='utf8'): 

if isinstance(s, bytes): 

return s 

return bytes(s, encoding) 

else: 

def bytes_(s, encoding=None): 

return str(s) 

 

 

if sys.version_info[:2] >= (2, 6): 

def isgenerator(o): 

if isinstance(o, UnboundMethod): 

o = o._func 

return inspect.isgeneratorfunction(o) or inspect.isgenerator(o) 

else: 

try: 

from compiler.consts import CO_GENERATOR 

except ImportError: 

# IronPython doesn't have a complier module 

CO_GENERATOR=0x20 

 

def isgenerator(func): 

try: 

return func.__code__.co_flags & CO_GENERATOR != 0 

except AttributeError: 

return False 

 

# Make a function to help check if an exception is derived from BaseException. 

# In Python 2.4, we just use Exception instead. 

if sys.version_info[:2] < (2, 5): 

def is_base_exception(exc): 

return isinstance(exc, Exception) 

else: 

def is_base_exception(exc): 

return isinstance(exc, BaseException) 

 

if sys.version_info[:2] < (3, 0): 

def exc_to_unicode(ev, encoding='utf-8'): 

if is_base_exception(ev): 

if not hasattr(ev, '__unicode__'): 

# 2.5- 

if not hasattr(ev, 'message'): 

# 2.4 

msg = len(ev.args) and ev.args[0] or '' 

else: 

msg = ev.message 

msg = force_unicode(msg, encoding=encoding) 

clsname = force_unicode(ev.__class__.__name__, 

encoding=encoding) 

ev = '%s: %s' % (clsname, msg) 

elif not isinstance(ev, str): 

ev = repr(ev) 

 

return force_unicode(ev, encoding=encoding) 

else: 

def exc_to_unicode(ev, encoding='utf-8'): 

return str(ev) 

 

def format_exception(exc_info, encoding='UTF-8'): 

ec, ev, tb = exc_info 

 

# Our exception object may have been turned into a string, and Python 3's 

# traceback.format_exception() doesn't take kindly to that (it expects an 

# actual exception object). So we work around it, by doing the work 

# ourselves if ev is not an exception object. 

if not is_base_exception(ev): 

tb_data = force_unicode( 

''.join(traceback.format_tb(tb)), 

encoding) 

ev = exc_to_unicode(ev) 

return tb_data + ev 

else: 

return force_unicode( 

''.join(traceback.format_exception(*exc_info)), 

encoding)