##// END OF EJS Templates
Various fixes to tests in IPython.utils.
Thomas Kluyver -
Show More
@@ -1,85 +1,87 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for working with stack frames.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2008-2009 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import sys
18 from IPython.utils import py3compat
18 19
19 20 #-----------------------------------------------------------------------------
20 21 # Code
21 22 #-----------------------------------------------------------------------------
22 23
24 @py3compat.doctest_refactor_print
23 25 def extract_vars(*names,**kw):
24 26 """Extract a set of variables by name from another frame.
25 27
26 28 :Parameters:
27 29 - `*names`: strings
28 30 One or more variable names which will be extracted from the caller's
29 31 frame.
30 32
31 33 :Keywords:
32 34 - `depth`: integer (0)
33 35 How many frames in the stack to walk when looking for your variables.
34 36
35 37
36 38 Examples:
37 39
38 40 In [2]: def func(x):
39 41 ...: y = 1
40 42 ...: print extract_vars('x','y')
41 43 ...:
42 44
43 45 In [3]: func('hello')
44 46 {'y': 1, 'x': 'hello'}
45 47 """
46 48
47 49 depth = kw.get('depth',0)
48 50
49 51 callerNS = sys._getframe(depth+1).f_locals
50 52 return dict((k,callerNS[k]) for k in names)
51 53
52 54
53 55 def extract_vars_above(*names):
54 56 """Extract a set of variables by name from another frame.
55 57
56 58 Similar to extractVars(), but with a specified depth of 1, so that names
57 59 are exctracted exactly from above the caller.
58 60
59 61 This is simply a convenience function so that the very common case (for us)
60 62 of skipping exactly 1 frame doesn't have to construct a special dict for
61 63 keyword passing."""
62 64
63 65 callerNS = sys._getframe(2).f_locals
64 66 return dict((k,callerNS[k]) for k in names)
65 67
66 68
67 69 def debugx(expr,pre_msg=''):
68 70 """Print the value of an expression from the caller's frame.
69 71
70 72 Takes an expression, evaluates it in the caller's frame and prints both
71 73 the given expression and the resulting value (as well as a debug mark
72 74 indicating the name of the calling function. The input must be of a form
73 75 suitable for eval().
74 76
75 77 An optional message can be passed, which will be prepended to the printed
76 78 expr->value pair."""
77 79
78 80 cf = sys._getframe(1)
79 81 print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr,
80 82 eval(expr,cf.f_globals,cf.f_locals))
81 83
82 84
83 85 # deactivate it by uncommenting the following line, which makes it a no-op
84 86 #def debugx(expr,pre_msg=''): pass
85 87
@@ -1,395 +1,395 b''
1 1 # encoding: utf-8
2 2 """A dict subclass that supports attribute style access.
3 3
4 4 Authors:
5 5
6 6 * Fernando Perez (original)
7 7 * Brian Granger (refactoring to a dict subclass)
8 8 """
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Copyright (C) 2008-2009 The IPython Development Team
12 12 #
13 13 # Distributed under the terms of the BSD License. The full license is in
14 14 # the file COPYING, distributed as part of this software.
15 15 #-----------------------------------------------------------------------------
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Imports
19 19 #-----------------------------------------------------------------------------
20 20
21 21 from IPython.utils.data import list2dict2
22 22
23 23 __all__ = ['Struct']
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Code
27 27 #-----------------------------------------------------------------------------
28 28
29 29
30 30 class Struct(dict):
31 31 """A dict subclass with attribute style access.
32 32
33 33 This dict subclass has a a few extra features:
34 34
35 35 * Attribute style access.
36 36 * Protection of class members (like keys, items) when using attribute
37 37 style access.
38 38 * The ability to restrict assignment to only existing keys.
39 39 * Intelligent merging.
40 40 * Overloaded operators.
41 41 """
42 42 _allownew = True
43 43 def __init__(self, *args, **kw):
44 44 """Initialize with a dictionary, another Struct, or data.
45 45
46 46 Parameters
47 47 ----------
48 48 args : dict, Struct
49 49 Initialize with one dict or Struct
50 50 kw : dict
51 51 Initialize with key, value pairs.
52 52
53 53 Examples
54 54 --------
55 55
56 56 >>> s = Struct(a=10,b=30)
57 57 >>> s.a
58 58 10
59 59 >>> s.b
60 60 30
61 61 >>> s2 = Struct(s,c=30)
62 62 >>> s2.keys()
63 63 ['a', 'c', 'b']
64 64 """
65 65 object.__setattr__(self, '_allownew', True)
66 66 dict.__init__(self, *args, **kw)
67 67
68 68 def __setitem__(self, key, value):
69 69 """Set an item with check for allownew.
70 70
71 71 Examples
72 72 --------
73 73
74 74 >>> s = Struct()
75 75 >>> s['a'] = 10
76 76 >>> s.allow_new_attr(False)
77 77 >>> s['a'] = 10
78 78 >>> s['a']
79 79 10
80 80 >>> try:
81 81 ... s['b'] = 20
82 82 ... except KeyError:
83 83 ... print 'this is not allowed'
84 84 ...
85 85 this is not allowed
86 86 """
87 87 if not self._allownew and not self.has_key(key):
88 88 raise KeyError(
89 89 "can't create new attribute %s when allow_new_attr(False)" % key)
90 90 dict.__setitem__(self, key, value)
91 91
92 92 def __setattr__(self, key, value):
93 93 """Set an attr with protection of class members.
94 94
95 95 This calls :meth:`self.__setitem__` but convert :exc:`KeyError` to
96 96 :exc:`AttributeError`.
97 97
98 98 Examples
99 99 --------
100 100
101 101 >>> s = Struct()
102 102 >>> s.a = 10
103 103 >>> s.a
104 104 10
105 105 >>> try:
106 106 ... s.get = 10
107 107 ... except AttributeError:
108 108 ... print "you can't set a class member"
109 109 ...
110 110 you can't set a class member
111 111 """
112 112 # If key is an str it might be a class member or instance var
113 113 if isinstance(key, str):
114 114 # I can't simply call hasattr here because it calls getattr, which
115 115 # calls self.__getattr__, which returns True for keys in
116 116 # self._data. But I only want keys in the class and in
117 117 # self.__dict__
118 118 if key in self.__dict__ or hasattr(Struct, key):
119 119 raise AttributeError(
120 120 'attr %s is a protected member of class Struct.' % key
121 121 )
122 122 try:
123 123 self.__setitem__(key, value)
124 124 except KeyError, e:
125 125 raise AttributeError(e)
126 126
127 127 def __getattr__(self, key):
128 128 """Get an attr by calling :meth:`dict.__getitem__`.
129 129
130 130 Like :meth:`__setattr__`, this method converts :exc:`KeyError` to
131 131 :exc:`AttributeError`.
132 132
133 133 Examples
134 134 --------
135 135
136 136 >>> s = Struct(a=10)
137 137 >>> s.a
138 138 10
139 139 >>> type(s.get)
140 <type 'builtin_function_or_method'>
140 <... 'builtin_function_or_method'>
141 141 >>> try:
142 142 ... s.b
143 143 ... except AttributeError:
144 144 ... print "I don't have that key"
145 145 ...
146 146 I don't have that key
147 147 """
148 148 try:
149 149 result = self[key]
150 150 except KeyError:
151 151 raise AttributeError(key)
152 152 else:
153 153 return result
154 154
155 155 def __iadd__(self, other):
156 156 """s += s2 is a shorthand for s.merge(s2).
157 157
158 158 Examples
159 159 --------
160 160
161 161 >>> s = Struct(a=10,b=30)
162 162 >>> s2 = Struct(a=20,c=40)
163 163 >>> s += s2
164 164 >>> s
165 165 {'a': 10, 'c': 40, 'b': 30}
166 166 """
167 167 self.merge(other)
168 168 return self
169 169
170 170 def __add__(self,other):
171 171 """s + s2 -> New Struct made from s.merge(s2).
172 172
173 173 Examples
174 174 --------
175 175
176 176 >>> s1 = Struct(a=10,b=30)
177 177 >>> s2 = Struct(a=20,c=40)
178 178 >>> s = s1 + s2
179 179 >>> s
180 180 {'a': 10, 'c': 40, 'b': 30}
181 181 """
182 182 sout = self.copy()
183 183 sout.merge(other)
184 184 return sout
185 185
186 186 def __sub__(self,other):
187 187 """s1 - s2 -> remove keys in s2 from s1.
188 188
189 189 Examples
190 190 --------
191 191
192 192 >>> s1 = Struct(a=10,b=30)
193 193 >>> s2 = Struct(a=40)
194 194 >>> s = s1 - s2
195 195 >>> s
196 196 {'b': 30}
197 197 """
198 198 sout = self.copy()
199 199 sout -= other
200 200 return sout
201 201
202 202 def __isub__(self,other):
203 203 """Inplace remove keys from self that are in other.
204 204
205 205 Examples
206 206 --------
207 207
208 208 >>> s1 = Struct(a=10,b=30)
209 209 >>> s2 = Struct(a=40)
210 210 >>> s1 -= s2
211 211 >>> s1
212 212 {'b': 30}
213 213 """
214 214 for k in other.keys():
215 215 if self.has_key(k):
216 216 del self[k]
217 217 return self
218 218
219 219 def __dict_invert(self, data):
220 220 """Helper function for merge.
221 221
222 222 Takes a dictionary whose values are lists and returns a dict with
223 223 the elements of each list as keys and the original keys as values.
224 224 """
225 225 outdict = {}
226 226 for k,lst in data.items():
227 227 if isinstance(lst, str):
228 228 lst = lst.split()
229 229 for entry in lst:
230 230 outdict[entry] = k
231 231 return outdict
232 232
233 233 def dict(self):
234 234 return self
235 235
236 236 def copy(self):
237 237 """Return a copy as a Struct.
238 238
239 239 Examples
240 240 --------
241 241
242 242 >>> s = Struct(a=10,b=30)
243 243 >>> s2 = s.copy()
244 244 >>> s2
245 245 {'a': 10, 'b': 30}
246 246 >>> type(s2).__name__
247 247 'Struct'
248 248 """
249 249 return Struct(dict.copy(self))
250 250
251 251 def hasattr(self, key):
252 252 """hasattr function available as a method.
253 253
254 254 Implemented like has_key.
255 255
256 256 Examples
257 257 --------
258 258
259 259 >>> s = Struct(a=10)
260 260 >>> s.hasattr('a')
261 261 True
262 262 >>> s.hasattr('b')
263 263 False
264 264 >>> s.hasattr('get')
265 265 False
266 266 """
267 267 return self.has_key(key)
268 268
269 269 def allow_new_attr(self, allow = True):
270 270 """Set whether new attributes can be created in this Struct.
271 271
272 272 This can be used to catch typos by verifying that the attribute user
273 273 tries to change already exists in this Struct.
274 274 """
275 275 object.__setattr__(self, '_allownew', allow)
276 276
277 277 def merge(self, __loc_data__=None, __conflict_solve=None, **kw):
278 278 """Merge two Structs with customizable conflict resolution.
279 279
280 280 This is similar to :meth:`update`, but much more flexible. First, a
281 281 dict is made from data+key=value pairs. When merging this dict with
282 282 the Struct S, the optional dictionary 'conflict' is used to decide
283 283 what to do.
284 284
285 285 If conflict is not given, the default behavior is to preserve any keys
286 286 with their current value (the opposite of the :meth:`update` method's
287 287 behavior).
288 288
289 289 Parameters
290 290 ----------
291 291 __loc_data : dict, Struct
292 292 The data to merge into self
293 293 __conflict_solve : dict
294 294 The conflict policy dict. The keys are binary functions used to
295 295 resolve the conflict and the values are lists of strings naming
296 296 the keys the conflict resolution function applies to. Instead of
297 297 a list of strings a space separated string can be used, like
298 298 'a b c'.
299 299 kw : dict
300 300 Additional key, value pairs to merge in
301 301
302 302 Notes
303 303 -----
304 304
305 305 The `__conflict_solve` dict is a dictionary of binary functions which will be used to
306 306 solve key conflicts. Here is an example::
307 307
308 308 __conflict_solve = dict(
309 309 func1=['a','b','c'],
310 310 func2=['d','e']
311 311 )
312 312
313 313 In this case, the function :func:`func1` will be used to resolve
314 314 keys 'a', 'b' and 'c' and the function :func:`func2` will be used for
315 315 keys 'd' and 'e'. This could also be written as::
316 316
317 317 __conflict_solve = dict(func1='a b c',func2='d e')
318 318
319 319 These functions will be called for each key they apply to with the
320 320 form::
321 321
322 322 func1(self['a'], other['a'])
323 323
324 324 The return value is used as the final merged value.
325 325
326 326 As a convenience, merge() provides five (the most commonly needed)
327 327 pre-defined policies: preserve, update, add, add_flip and add_s. The
328 328 easiest explanation is their implementation::
329 329
330 330 preserve = lambda old,new: old
331 331 update = lambda old,new: new
332 332 add = lambda old,new: old + new
333 333 add_flip = lambda old,new: new + old # note change of order!
334 334 add_s = lambda old,new: old + ' ' + new # only for str!
335 335
336 336 You can use those four words (as strings) as keys instead
337 337 of defining them as functions, and the merge method will substitute
338 338 the appropriate functions for you.
339 339
340 340 For more complicated conflict resolution policies, you still need to
341 341 construct your own functions.
342 342
343 343 Examples
344 344 --------
345 345
346 346 This show the default policy:
347 347
348 348 >>> s = Struct(a=10,b=30)
349 349 >>> s2 = Struct(a=20,c=40)
350 350 >>> s.merge(s2)
351 351 >>> s
352 352 {'a': 10, 'c': 40, 'b': 30}
353 353
354 354 Now, show how to specify a conflict dict:
355 355
356 356 >>> s = Struct(a=10,b=30)
357 357 >>> s2 = Struct(a=20,b=40)
358 358 >>> conflict = {'update':'a','add':'b'}
359 359 >>> s.merge(s2,conflict)
360 360 >>> s
361 361 {'a': 20, 'b': 70}
362 362 """
363 363
364 364 data_dict = dict(__loc_data__,**kw)
365 365
366 366 # policies for conflict resolution: two argument functions which return
367 367 # the value that will go in the new struct
368 368 preserve = lambda old,new: old
369 369 update = lambda old,new: new
370 370 add = lambda old,new: old + new
371 371 add_flip = lambda old,new: new + old # note change of order!
372 372 add_s = lambda old,new: old + ' ' + new
373 373
374 374 # default policy is to keep current keys when there's a conflict
375 375 conflict_solve = list2dict2(self.keys(), default = preserve)
376 376
377 377 # the conflict_solve dictionary is given by the user 'inverted': we
378 378 # need a name-function mapping, it comes as a function -> names
379 379 # dict. Make a local copy (b/c we'll make changes), replace user
380 380 # strings for the three builtin policies and invert it.
381 381 if __conflict_solve:
382 382 inv_conflict_solve_user = __conflict_solve.copy()
383 383 for name, func in [('preserve',preserve), ('update',update),
384 384 ('add',add), ('add_flip',add_flip),
385 385 ('add_s',add_s)]:
386 386 if name in inv_conflict_solve_user.keys():
387 387 inv_conflict_solve_user[func] = inv_conflict_solve_user[name]
388 388 del inv_conflict_solve_user[name]
389 389 conflict_solve.update(self.__dict_invert(inv_conflict_solve_user))
390 390 for key in data_dict:
391 391 if key not in self:
392 392 self[key] = data_dict[key]
393 393 else:
394 394 self[key] = conflict_solve[key](self[key],data_dict[key])
395 395
@@ -1,185 +1,187 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for getting information about IPython and the system it's running in.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2008-2009 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import os
18 18 import platform
19 19 import pprint
20 20 import sys
21 21 import subprocess
22 22
23 23 from ConfigParser import ConfigParser
24 24
25 25 from IPython.core import release
26 from IPython.utils import py3compat
26 27
27 28 #-----------------------------------------------------------------------------
28 29 # Globals
29 30 #-----------------------------------------------------------------------------
30 31 COMMIT_INFO_FNAME = '.git_commit_info.ini'
31 32
32 33 #-----------------------------------------------------------------------------
33 34 # Code
34 35 #-----------------------------------------------------------------------------
35 36
36 37 def pkg_commit_hash(pkg_path):
37 38 """Get short form of commit hash given directory `pkg_path`
38 39
39 40 There should be a file called 'COMMIT_INFO.txt' in `pkg_path`. This is a
40 41 file in INI file format, with at least one section: ``commit hash``, and two
41 42 variables ``archive_subst_hash`` and ``install_hash``. The first has a
42 43 substitution pattern in it which may have been filled by the execution of
43 44 ``git archive`` if this is an archive generated that way. The second is
44 45 filled in by the installation, if the installation is from a git archive.
45 46
46 47 We get the commit hash from (in order of preference):
47 48
48 49 * A substituted value in ``archive_subst_hash``
49 50 * A written commit hash value in ``install_hash`
50 51 * git output, if we are in a git repository
51 52
52 53 If all these fail, we return a not-found placeholder tuple
53 54
54 55 Parameters
55 56 ----------
56 57 pkg_path : str
57 58 directory containing package
58 59
59 60 Returns
60 61 -------
61 62 hash_from : str
62 63 Where we got the hash from - description
63 64 hash_str : str
64 65 short form of hash
65 66 """
66 67 # Try and get commit from written commit text file
67 68 pth = os.path.join(pkg_path, COMMIT_INFO_FNAME)
68 69 if not os.path.isfile(pth):
69 70 raise IOError('Missing commit info file %s' % pth)
70 71 cfg_parser = ConfigParser()
71 72 cfg_parser.read(pth)
72 73 archive_subst = cfg_parser.get('commit hash', 'archive_subst_hash')
73 74 if not archive_subst.startswith('$Format'): # it has been substituted
74 75 return 'archive substitution', archive_subst
75 76 install_subst = cfg_parser.get('commit hash', 'install_hash')
76 77 if install_subst != '':
77 78 return 'installation', install_subst
78 79 # maybe we are in a repository
79 80 proc = subprocess.Popen('git rev-parse --short HEAD',
80 81 stdout=subprocess.PIPE,
81 82 stderr=subprocess.PIPE,
82 83 cwd=pkg_path, shell=True)
83 84 repo_commit, _ = proc.communicate()
84 85 if repo_commit:
85 86 return 'repository', repo_commit.strip()
86 87 return '(none found)', '<not found>'
87 88
88 89
89 90 def pkg_info(pkg_path):
90 91 """Return dict describing the context of this package
91 92
92 93 Parameters
93 94 ----------
94 95 pkg_path : str
95 96 path containing __init__.py for package
96 97
97 98 Returns
98 99 -------
99 100 context : dict
100 101 with named parameters of interest
101 102 """
102 103 src, hsh = pkg_commit_hash(pkg_path)
103 104 return dict(
104 105 ipython_version=release.version,
105 106 ipython_path=pkg_path,
106 107 commit_source=src,
107 108 commit_hash=hsh,
108 109 sys_version=sys.version,
109 110 sys_executable=sys.executable,
110 111 sys_platform=sys.platform,
111 112 platform=platform.platform(),
112 113 os_name=os.name,
113 114 )
114 115
115 116
117 @py3compat.doctest_refactor_print
116 118 def sys_info():
117 119 """Return useful information about IPython and the system, as a string.
118 120
119 121 Example
120 122 -------
121 123 In [2]: print sys_info()
122 124 {'commit_hash': '144fdae', # random
123 125 'commit_source': 'repository',
124 126 'ipython_path': '/home/fperez/usr/lib/python2.6/site-packages/IPython',
125 127 'ipython_version': '0.11.dev',
126 128 'os_name': 'posix',
127 129 'platform': 'Linux-2.6.35-22-generic-i686-with-Ubuntu-10.10-maverick',
128 130 'sys_executable': '/usr/bin/python',
129 131 'sys_platform': 'linux2',
130 132 'sys_version': '2.6.6 (r266:84292, Sep 15 2010, 15:52:39) \\n[GCC 4.4.5]'}
131 133 """
132 134 p = os.path
133 135 path = p.dirname(p.abspath(p.join(__file__, '..')))
134 136 return pprint.pformat(pkg_info(path))
135 137
136 138
137 139 def _num_cpus_unix():
138 140 """Return the number of active CPUs on a Unix system."""
139 141 return os.sysconf("SC_NPROCESSORS_ONLN")
140 142
141 143
142 144 def _num_cpus_darwin():
143 145 """Return the number of active CPUs on a Darwin system."""
144 146 p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
145 147 return p.stdout.read()
146 148
147 149
148 150 def _num_cpus_windows():
149 151 """Return the number of active CPUs on a Windows system."""
150 152 return os.environ.get("NUMBER_OF_PROCESSORS")
151 153
152 154
153 155 def num_cpus():
154 156 """Return the effective number of CPUs in the system as an integer.
155 157
156 158 This cross-platform function makes an attempt at finding the total number of
157 159 available CPUs in the system, as returned by various underlying system and
158 160 python calls.
159 161
160 162 If it can't find a sensible answer, it returns 1 (though an error *may* make
161 163 it return a large positive number that's actually incorrect).
162 164 """
163 165
164 166 # Many thanks to the Parallel Python project (http://www.parallelpython.com)
165 167 # for the names of the keys we needed to look up for this function. This
166 168 # code was inspired by their equivalent function.
167 169
168 170 ncpufuncs = {'Linux':_num_cpus_unix,
169 171 'Darwin':_num_cpus_darwin,
170 172 'Windows':_num_cpus_windows,
171 173 # On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
172 174 # See http://bugs.python.org/issue1082 for details.
173 175 'Microsoft':_num_cpus_windows,
174 176 }
175 177
176 178 ncpufunc = ncpufuncs.get(platform.system(),
177 179 # default to unix version (Solaris, AIX, etc)
178 180 _num_cpus_unix)
179 181
180 182 try:
181 183 ncpus = max(1,int(ncpufunc()))
182 184 except:
183 185 ncpus = 1
184 186 return ncpus
185 187
@@ -1,71 +1,75 b''
1 1 # encoding: utf-8
2 2 """Tests for io.py"""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2008 The IPython Development Team
6 6 #
7 7 # Distributed under the terms of the BSD License. The full license is in
8 8 # the file COPYING, distributed as part of this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 import sys
16 16
17 17 from StringIO import StringIO
18 18 from subprocess import Popen, PIPE
19 19
20 20 import nose.tools as nt
21 21
22 22 from IPython.testing import decorators as dec
23 23 from IPython.utils.io import Tee
24 from IPython.utils.py3compat import doctest_refactor_print
24 25
25 26 #-----------------------------------------------------------------------------
26 27 # Tests
27 28 #-----------------------------------------------------------------------------
28 29
29 30
30 31 def test_tee_simple():
31 32 "Very simple check with stdout only"
32 33 chan = StringIO()
33 34 text = 'Hello'
34 35 tee = Tee(chan, channel='stdout')
35 print >> chan, text,
36 nt.assert_equal(chan.getvalue(), text)
36 print >> chan, text
37 nt.assert_equal(chan.getvalue(), text+"\n")
37 38
38 39
39 40 class TeeTestCase(dec.ParametricTestCase):
40 41
41 42 def tchan(self, channel, check='close'):
42 43 trap = StringIO()
43 44 chan = StringIO()
44 45 text = 'Hello'
45 46
46 47 std_ori = getattr(sys, channel)
47 48 setattr(sys, channel, trap)
48 49
49 50 tee = Tee(chan, channel=channel)
50 51 print >> chan, text,
51 52 setattr(sys, channel, std_ori)
52 53 trap_val = trap.getvalue()
53 54 nt.assert_equals(chan.getvalue(), text)
54 55 if check=='close':
55 56 tee.close()
56 57 else:
57 58 del tee
58 59
59 60 def test(self):
60 61 for chan in ['stdout', 'stderr']:
61 62 for check in ['close', 'del']:
62 63 yield self.tchan(chan, check)
63 64
64 65 def test_io_init():
65 66 """Test that io.stdin/out/err exist at startup"""
66 67 for name in ('stdin', 'stdout', 'stderr'):
67 p = Popen([sys.executable, '-c', "from IPython.utils import io;print io.%s.__class__"%name],
68 cmd = doctest_refactor_print("from IPython.utils import io;print io.%s.__class__"%name)
69 p = Popen([sys.executable, '-c', cmd],
68 70 stdout=PIPE)
69 71 p.wait()
70 classname = p.stdout.read().strip()
71 nt.assert_equals(classname, 'IPython.utils.io.IOStream')
72 classname = p.stdout.read().strip().decode('ascii')
73 # __class__ is a reference to the class object in Python 3, so we can't
74 # just test for string equality.
75 assert 'IPython.utils.io.IOStream' in classname, classname
@@ -1,450 +1,450 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.utils.path.py"""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2008 The IPython Development Team
6 6 #
7 7 # Distributed under the terms of the BSD License. The full license is in
8 8 # the file COPYING, distributed as part of this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 from __future__ import with_statement
16 16
17 17 import os
18 18 import shutil
19 19 import sys
20 20 import tempfile
21 import StringIO
21 from io import StringIO
22 22
23 23 from os.path import join, abspath, split
24 24
25 25 import nose.tools as nt
26 26
27 27 from nose import with_setup
28 28
29 29 import IPython
30 30 from IPython.testing import decorators as dec
31 31 from IPython.testing.decorators import skip_if_not_win32, skip_win32
32 32 from IPython.testing.tools import make_tempfile
33 33 from IPython.utils import path, io
34 34 from IPython.utils import py3compat
35 35
36 36 # Platform-dependent imports
37 37 try:
38 38 import _winreg as wreg
39 39 except ImportError:
40 40 #Fake _winreg module on none windows platforms
41 41 import types
42 42 wr_name = "winreg" if py3compat.PY3 else "_winreg"
43 43 sys.modules[wr_name] = types.ModuleType(wr_name)
44 44 import _winreg as wreg
45 45 #Add entries that needs to be stubbed by the testing code
46 46 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
47 47
48 48 try:
49 49 reload
50 50 except NameError: # Python 3
51 51 from imp import reload
52 52
53 53 #-----------------------------------------------------------------------------
54 54 # Globals
55 55 #-----------------------------------------------------------------------------
56 56 env = os.environ
57 57 TEST_FILE_PATH = split(abspath(__file__))[0]
58 58 TMP_TEST_DIR = tempfile.mkdtemp()
59 59 HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
60 60 XDG_TEST_DIR = join(HOME_TEST_DIR, "xdg_test_dir")
61 61 IP_TEST_DIR = join(HOME_TEST_DIR,'.ipython')
62 62 #
63 63 # Setup/teardown functions/decorators
64 64 #
65 65
66 66 def setup():
67 67 """Setup testenvironment for the module:
68 68
69 69 - Adds dummy home dir tree
70 70 """
71 71 # Do not mask exceptions here. In particular, catching WindowsError is a
72 72 # problem because that exception is only defined on Windows...
73 73 os.makedirs(IP_TEST_DIR)
74 74 os.makedirs(os.path.join(XDG_TEST_DIR, 'ipython'))
75 75
76 76
77 77 def teardown():
78 78 """Teardown testenvironment for the module:
79 79
80 80 - Remove dummy home dir tree
81 81 """
82 82 # Note: we remove the parent test dir, which is the root of all test
83 83 # subdirs we may have created. Use shutil instead of os.removedirs, so
84 84 # that non-empty directories are all recursively removed.
85 85 shutil.rmtree(TMP_TEST_DIR)
86 86
87 87
88 88 def setup_environment():
89 89 """Setup testenvironment for some functions that are tested
90 90 in this module. In particular this functions stores attributes
91 91 and other things that we need to stub in some test functions.
92 92 This needs to be done on a function level and not module level because
93 93 each testfunction needs a pristine environment.
94 94 """
95 95 global oldstuff, platformstuff
96 96 oldstuff = (env.copy(), os.name, path.get_home_dir, IPython.__file__, os.getcwd())
97 97
98 98 if os.name == 'nt':
99 99 platformstuff = (wreg.OpenKey, wreg.QueryValueEx,)
100 100
101 101
102 102 def teardown_environment():
103 103 """Restore things that were remebered by the setup_environment function
104 104 """
105 105 (oldenv, os.name, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
106 106 os.chdir(old_wd)
107 107 reload(path)
108 108
109 109 for key in env.keys():
110 110 if key not in oldenv:
111 111 del env[key]
112 112 env.update(oldenv)
113 113 if hasattr(sys, 'frozen'):
114 114 del sys.frozen
115 115 if os.name == 'nt':
116 116 (wreg.OpenKey, wreg.QueryValueEx,) = platformstuff
117 117
118 118 # Build decorator that uses the setup_environment/setup_environment
119 119 with_environment = with_setup(setup_environment, teardown_environment)
120 120
121 121
122 122 @skip_if_not_win32
123 123 @with_environment
124 124 def test_get_home_dir_1():
125 125 """Testcase for py2exe logic, un-compressed lib
126 126 """
127 127 sys.frozen = True
128 128
129 129 #fake filename for IPython.__init__
130 130 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
131 131
132 132 home_dir = path.get_home_dir()
133 133 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
134 134
135 135
136 136 @skip_if_not_win32
137 137 @with_environment
138 138 def test_get_home_dir_2():
139 139 """Testcase for py2exe logic, compressed lib
140 140 """
141 141 sys.frozen = True
142 142 #fake filename for IPython.__init__
143 143 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
144 144
145 145 home_dir = path.get_home_dir()
146 146 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR).lower())
147 147
148 148
149 149 @with_environment
150 150 @skip_win32
151 151 def test_get_home_dir_3():
152 152 """Testcase $HOME is set, then use its value as home directory."""
153 153 env["HOME"] = HOME_TEST_DIR
154 154 home_dir = path.get_home_dir()
155 155 nt.assert_equal(home_dir, env["HOME"])
156 156
157 157
158 158 @with_environment
159 159 @skip_win32
160 160 def test_get_home_dir_4():
161 161 """Testcase $HOME is not set, os=='posix'.
162 162 This should fail with HomeDirError"""
163 163
164 164 os.name = 'posix'
165 165 if 'HOME' in env: del env['HOME']
166 166 nt.assert_raises(path.HomeDirError, path.get_home_dir)
167 167
168 168
169 169 @skip_if_not_win32
170 170 @with_environment
171 171 def test_get_home_dir_5():
172 172 """Using HOMEDRIVE + HOMEPATH, os=='nt'.
173 173
174 174 HOMESHARE is missing.
175 175 """
176 176
177 177 os.name = 'nt'
178 178 env.pop('HOMESHARE', None)
179 179 env['HOMEDRIVE'], env['HOMEPATH'] = os.path.splitdrive(HOME_TEST_DIR)
180 180 home_dir = path.get_home_dir()
181 181 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
182 182
183 183
184 184 @skip_if_not_win32
185 185 @with_environment
186 186 def test_get_home_dir_6():
187 187 """Using USERPROFILE, os=='nt'.
188 188
189 189 HOMESHARE, HOMEDRIVE, HOMEPATH are missing.
190 190 """
191 191
192 192 os.name = 'nt'
193 193 env.pop('HOMESHARE', None)
194 194 env.pop('HOMEDRIVE', None)
195 195 env.pop('HOMEPATH', None)
196 196 env["USERPROFILE"] = abspath(HOME_TEST_DIR)
197 197 home_dir = path.get_home_dir()
198 198 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
199 199
200 200
201 201 @skip_if_not_win32
202 202 @with_environment
203 203 def test_get_home_dir_7():
204 204 """Using HOMESHARE, os=='nt'."""
205 205
206 206 os.name = 'nt'
207 207 env["HOMESHARE"] = abspath(HOME_TEST_DIR)
208 208 home_dir = path.get_home_dir()
209 209 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
210 210
211 211
212 212 # Should we stub wreg fully so we can run the test on all platforms?
213 213 @skip_if_not_win32
214 214 @with_environment
215 215 def test_get_home_dir_8():
216 216 """Using registry hack for 'My Documents', os=='nt'
217 217
218 218 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
219 219 """
220 220 os.name = 'nt'
221 221 # Remove from stub environment all keys that may be set
222 222 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
223 223 env.pop(key, None)
224 224
225 225 #Stub windows registry functions
226 226 def OpenKey(x, y):
227 227 class key:
228 228 def Close(self):
229 229 pass
230 230 return key()
231 231 def QueryValueEx(x, y):
232 232 return [abspath(HOME_TEST_DIR)]
233 233
234 234 wreg.OpenKey = OpenKey
235 235 wreg.QueryValueEx = QueryValueEx
236 236
237 237 home_dir = path.get_home_dir()
238 238 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
239 239
240 240
241 241 @with_environment
242 242 def test_get_ipython_dir_1():
243 243 """test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
244 244 env_ipdir = os.path.join("someplace", ".ipython")
245 245 path._writable_dir = lambda path: True
246 246 env['IPYTHON_DIR'] = env_ipdir
247 247 ipdir = path.get_ipython_dir()
248 248 nt.assert_equal(ipdir, env_ipdir)
249 249
250 250
251 251 @with_environment
252 252 def test_get_ipython_dir_2():
253 253 """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
254 254 path.get_home_dir = lambda : "someplace"
255 255 path.get_xdg_dir = lambda : None
256 256 path._writable_dir = lambda path: True
257 257 os.name = "posix"
258 258 env.pop('IPYTHON_DIR', None)
259 259 env.pop('IPYTHONDIR', None)
260 260 env.pop('XDG_CONFIG_HOME', None)
261 261 ipdir = path.get_ipython_dir()
262 262 nt.assert_equal(ipdir, os.path.join("someplace", ".ipython"))
263 263
264 264 @with_environment
265 265 def test_get_ipython_dir_3():
266 266 """test_get_ipython_dir_3, use XDG if defined, and .ipython doesn't exist."""
267 267 path.get_home_dir = lambda : "someplace"
268 268 path._writable_dir = lambda path: True
269 269 os.name = "posix"
270 270 env.pop('IPYTHON_DIR', None)
271 271 env.pop('IPYTHONDIR', None)
272 272 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
273 273 ipdir = path.get_ipython_dir()
274 274 nt.assert_equal(ipdir, os.path.join(XDG_TEST_DIR, "ipython"))
275 275
276 276 @with_environment
277 277 def test_get_ipython_dir_4():
278 278 """test_get_ipython_dir_4, use XDG if both exist."""
279 279 path.get_home_dir = lambda : HOME_TEST_DIR
280 280 os.name = "posix"
281 281 env.pop('IPYTHON_DIR', None)
282 282 env.pop('IPYTHONDIR', None)
283 283 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
284 284 xdg_ipdir = os.path.join(XDG_TEST_DIR, "ipython")
285 285 ipdir = path.get_ipython_dir()
286 286 nt.assert_equal(ipdir, xdg_ipdir)
287 287
288 288 @with_environment
289 289 def test_get_ipython_dir_5():
290 290 """test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
291 291 path.get_home_dir = lambda : HOME_TEST_DIR
292 292 os.name = "posix"
293 293 env.pop('IPYTHON_DIR', None)
294 294 env.pop('IPYTHONDIR', None)
295 295 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
296 296 os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
297 297 ipdir = path.get_ipython_dir()
298 298 nt.assert_equal(ipdir, IP_TEST_DIR)
299 299
300 300 @with_environment
301 301 def test_get_ipython_dir_6():
302 302 """test_get_ipython_dir_6, use XDG if defined and neither exist."""
303 303 xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
304 304 os.mkdir(xdg)
305 305 shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
306 306 path.get_home_dir = lambda : HOME_TEST_DIR
307 307 path.get_xdg_dir = lambda : xdg
308 308 os.name = "posix"
309 309 env.pop('IPYTHON_DIR', None)
310 310 env.pop('IPYTHONDIR', None)
311 311 env.pop('XDG_CONFIG_HOME', None)
312 312 xdg_ipdir = os.path.join(xdg, "ipython")
313 313 ipdir = path.get_ipython_dir()
314 314 nt.assert_equal(ipdir, xdg_ipdir)
315 315
316 316 @with_environment
317 317 def test_get_ipython_dir_7():
318 318 """test_get_ipython_dir_7, test home directory expansion on IPYTHON_DIR"""
319 319 path._writable_dir = lambda path: True
320 320 home_dir = os.path.expanduser('~')
321 321 env['IPYTHON_DIR'] = os.path.join('~', 'somewhere')
322 322 ipdir = path.get_ipython_dir()
323 323 nt.assert_equal(ipdir, os.path.join(home_dir, 'somewhere'))
324 324
325 325
326 326 @with_environment
327 327 def test_get_xdg_dir_1():
328 328 """test_get_xdg_dir_1, check xdg_dir"""
329 329 reload(path)
330 330 path._writable_dir = lambda path: True
331 331 path.get_home_dir = lambda : 'somewhere'
332 332 os.name = "posix"
333 333 env.pop('IPYTHON_DIR', None)
334 334 env.pop('IPYTHONDIR', None)
335 335 env.pop('XDG_CONFIG_HOME', None)
336 336
337 337 nt.assert_equal(path.get_xdg_dir(), os.path.join('somewhere', '.config'))
338 338
339 339
340 340 @with_environment
341 341 def test_get_xdg_dir_1():
342 342 """test_get_xdg_dir_1, check nonexistant xdg_dir"""
343 343 reload(path)
344 344 path.get_home_dir = lambda : HOME_TEST_DIR
345 345 os.name = "posix"
346 346 env.pop('IPYTHON_DIR', None)
347 347 env.pop('IPYTHONDIR', None)
348 348 env.pop('XDG_CONFIG_HOME', None)
349 349 nt.assert_equal(path.get_xdg_dir(), None)
350 350
351 351 @with_environment
352 352 def test_get_xdg_dir_2():
353 353 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
354 354 reload(path)
355 355 path.get_home_dir = lambda : HOME_TEST_DIR
356 356 os.name = "posix"
357 357 env.pop('IPYTHON_DIR', None)
358 358 env.pop('IPYTHONDIR', None)
359 359 env.pop('XDG_CONFIG_HOME', None)
360 360 cfgdir=os.path.join(path.get_home_dir(), '.config')
361 361 os.makedirs(cfgdir)
362 362
363 363 nt.assert_equal(path.get_xdg_dir(), cfgdir)
364 364
365 365 def test_filefind():
366 366 """Various tests for filefind"""
367 367 f = tempfile.NamedTemporaryFile()
368 368 # print 'fname:',f.name
369 369 alt_dirs = path.get_ipython_dir()
370 370 t = path.filefind(f.name, alt_dirs)
371 371 # print 'found:',t
372 372
373 373
374 374 def test_get_ipython_package_dir():
375 375 ipdir = path.get_ipython_package_dir()
376 376 nt.assert_true(os.path.isdir(ipdir))
377 377
378 378
379 379 def test_get_ipython_module_path():
380 380 ipapp_path = path.get_ipython_module_path('IPython.frontend.terminal.ipapp')
381 381 nt.assert_true(os.path.isfile(ipapp_path))
382 382
383 383
384 384 @dec.skip_if_not_win32
385 385 def test_get_long_path_name_win32():
386 386 p = path.get_long_path_name('c:\\docume~1')
387 387 nt.assert_equals(p,u'c:\\Documents and Settings')
388 388
389 389
390 390 @dec.skip_win32
391 391 def test_get_long_path_name():
392 392 p = path.get_long_path_name('/usr/local')
393 393 nt.assert_equals(p,'/usr/local')
394 394
395 395 @dec.skip_win32 # can't create not-user-writable dir on win
396 396 @with_environment
397 397 def test_not_writable_ipdir():
398 398 tmpdir = tempfile.mkdtemp()
399 399 os.name = "posix"
400 400 env.pop('IPYTHON_DIR', None)
401 401 env.pop('IPYTHONDIR', None)
402 402 env.pop('XDG_CONFIG_HOME', None)
403 403 env['HOME'] = tmpdir
404 404 ipdir = os.path.join(tmpdir, '.ipython')
405 405 os.mkdir(ipdir)
406 406 os.chmod(ipdir, 600)
407 407 stderr = io.stderr
408 pipe = StringIO.StringIO()
408 pipe = StringIO()
409 409 io.stderr = pipe
410 410 ipdir = path.get_ipython_dir()
411 411 io.stderr.flush()
412 412 io.stderr = stderr
413 413 nt.assert_true('WARNING' in pipe.getvalue())
414 414 env.pop('IPYTHON_DIR', None)
415 415
416 416 def test_unquote_filename():
417 417 for win32 in (True, False):
418 418 nt.assert_equals(path.unquote_filename('foo.py', win32=win32), 'foo.py')
419 419 nt.assert_equals(path.unquote_filename('foo bar.py', win32=win32), 'foo bar.py')
420 420 nt.assert_equals(path.unquote_filename('"foo.py"', win32=True), 'foo.py')
421 421 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=True), 'foo bar.py')
422 422 nt.assert_equals(path.unquote_filename("'foo.py'", win32=True), 'foo.py')
423 423 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=True), 'foo bar.py')
424 424 nt.assert_equals(path.unquote_filename('"foo.py"', win32=False), '"foo.py"')
425 425 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=False), '"foo bar.py"')
426 426 nt.assert_equals(path.unquote_filename("'foo.py'", win32=False), "'foo.py'")
427 427 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=False), "'foo bar.py'")
428 428
429 429 @with_environment
430 430 def test_get_py_filename():
431 431 os.chdir(TMP_TEST_DIR)
432 432 for win32 in (True, False):
433 433 with make_tempfile('foo.py'):
434 434 nt.assert_equals(path.get_py_filename('foo.py', force_win32=win32), 'foo.py')
435 435 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo.py')
436 436 with make_tempfile('foo'):
437 437 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo')
438 438 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
439 439 nt.assert_raises(IOError, path.get_py_filename, 'foo', force_win32=win32)
440 440 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
441 441 true_fn = 'foo with spaces.py'
442 442 with make_tempfile(true_fn):
443 443 nt.assert_equals(path.get_py_filename('foo with spaces', force_win32=win32), true_fn)
444 444 nt.assert_equals(path.get_py_filename('foo with spaces.py', force_win32=win32), true_fn)
445 445 if win32:
446 446 nt.assert_equals(path.get_py_filename('"foo with spaces.py"', force_win32=True), true_fn)
447 447 nt.assert_equals(path.get_py_filename("'foo with spaces.py'", force_win32=True), true_fn)
448 448 else:
449 449 nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"', force_win32=False)
450 450 nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'", force_win32=False)
@@ -1,87 +1,87 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.utils.text"""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2011 The IPython Development Team
6 6 #
7 7 # Distributed under the terms of the BSD License. The full license is in
8 8 # the file COPYING, distributed as part of this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 import os
16 16 import math
17 17
18 18 import nose.tools as nt
19 19
20 20 from nose import with_setup
21 21
22 22 from IPython.testing import decorators as dec
23 23 from IPython.utils import text
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Globals
27 27 #-----------------------------------------------------------------------------
28 28
29 29 def test_columnize():
30 30 """Basic columnize tests."""
31 31 size = 5
32 32 items = [l*size for l in 'abc']
33 33 out = text.columnize(items, displaywidth=80)
34 34 nt.assert_equals(out, 'aaaaa bbbbb ccccc\n')
35 35 out = text.columnize(items, displaywidth=10)
36 36 nt.assert_equals(out, 'aaaaa ccccc\nbbbbb\n')
37 37
38 38
39 39 def test_columnize_long():
40 40 """Test columnize with inputs longer than the display window"""
41 41 text.columnize(['a'*81, 'b'*81], displaywidth=80)
42 42 size = 11
43 43 items = [l*size for l in 'abc']
44 44 out = text.columnize(items, displaywidth=size-1)
45 45 nt.assert_equals(out, '\n'.join(items+['']))
46 46
47 47 def test_eval_formatter():
48 48 f = text.EvalFormatter()
49 49 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
50 s = f.format("{n} {n/4} {stuff.split()[0]}", **ns)
50 s = f.format("{n} {n//4} {stuff.split()[0]}", **ns)
51 51 nt.assert_equals(s, "12 3 hello")
52 52 s = f.format(' '.join(['{n//%i}'%i for i in range(1,8)]), **ns)
53 53 nt.assert_equals(s, "12 6 4 3 2 2 1")
54 54 s = f.format('{[n//i for i in range(1,8)]}', **ns)
55 55 nt.assert_equals(s, "[12, 6, 4, 3, 2, 2, 1]")
56 56 s = f.format("{stuff!s}", **ns)
57 57 nt.assert_equals(s, ns['stuff'])
58 58 s = f.format("{stuff!r}", **ns)
59 59 nt.assert_equals(s, repr(ns['stuff']))
60 60
61 61 nt.assert_raises(NameError, f.format, '{dne}', **ns)
62 62
63 63
64 64 def test_eval_formatter_slicing():
65 65 f = text.EvalFormatter()
66 66 f.allow_slicing = True
67 67 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
68 68 s = f.format(" {stuff.split()[:]} ", **ns)
69 69 nt.assert_equals(s, " ['hello', 'there'] ")
70 70 s = f.format(" {stuff.split()[::-1]} ", **ns)
71 71 nt.assert_equals(s, " ['there', 'hello'] ")
72 72 s = f.format("{stuff[::2]}", **ns)
73 73 nt.assert_equals(s, ns['stuff'][::2])
74 74
75 75 nt.assert_raises(SyntaxError, f.format, "{n:x}", **ns)
76 76
77 77
78 78 def test_eval_formatter_no_slicing():
79 79 f = text.EvalFormatter()
80 80 f.allow_slicing = False
81 81 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
82 82
83 83 s = f.format('{n:x} {pi**2:+f}', **ns)
84 84 nt.assert_equals(s, "c +9.869604")
85 85
86 86 nt.assert_raises(SyntaxError, f.format, "{a[:]}")
87 87
@@ -1,846 +1,855 b''
1 1 # encoding: utf-8
2 2 """
3 3 Tests for IPython.utils.traitlets.
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 * Enthought, Inc. Some of the code in this file comes from enthought.traits
9 9 and is licensed under the BSD license. Also, many of the ideas also come
10 10 from enthought.traits even though our implementation is very different.
11 11 """
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Copyright (C) 2008-2009 The IPython Development Team
15 15 #
16 16 # Distributed under the terms of the BSD License. The full license is in
17 17 # the file COPYING, distributed as part of this software.
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Imports
22 22 #-----------------------------------------------------------------------------
23 23
24 24 import sys
25 25 from unittest import TestCase
26 26
27 27 from IPython.utils.traitlets import (
28 28 HasTraits, MetaHasTraits, TraitType, Any, CBytes,
29 29 Int, Long, Float, Complex, Bytes, Unicode, TraitError,
30 30 Undefined, Type, This, Instance, TCPAddress, List, Tuple,
31 31 ObjectName, DottedObjectName
32 32 )
33
33 from IPython.utils import py3compat
34 34
35 35 #-----------------------------------------------------------------------------
36 36 # Helper classes for testing
37 37 #-----------------------------------------------------------------------------
38 38
39 39
40 40 class HasTraitsStub(HasTraits):
41 41
42 42 def _notify_trait(self, name, old, new):
43 43 self._notify_name = name
44 44 self._notify_old = old
45 45 self._notify_new = new
46 46
47 47
48 48 #-----------------------------------------------------------------------------
49 49 # Test classes
50 50 #-----------------------------------------------------------------------------
51 51
52 52
53 53 class TestTraitType(TestCase):
54 54
55 55 def test_get_undefined(self):
56 56 class A(HasTraits):
57 57 a = TraitType
58 58 a = A()
59 59 self.assertEquals(a.a, Undefined)
60 60
61 61 def test_set(self):
62 62 class A(HasTraitsStub):
63 63 a = TraitType
64 64
65 65 a = A()
66 66 a.a = 10
67 67 self.assertEquals(a.a, 10)
68 68 self.assertEquals(a._notify_name, 'a')
69 69 self.assertEquals(a._notify_old, Undefined)
70 70 self.assertEquals(a._notify_new, 10)
71 71
72 72 def test_validate(self):
73 73 class MyTT(TraitType):
74 74 def validate(self, inst, value):
75 75 return -1
76 76 class A(HasTraitsStub):
77 77 tt = MyTT
78 78
79 79 a = A()
80 80 a.tt = 10
81 81 self.assertEquals(a.tt, -1)
82 82
83 83 def test_default_validate(self):
84 84 class MyIntTT(TraitType):
85 85 def validate(self, obj, value):
86 86 if isinstance(value, int):
87 87 return value
88 88 self.error(obj, value)
89 89 class A(HasTraits):
90 90 tt = MyIntTT(10)
91 91 a = A()
92 92 self.assertEquals(a.tt, 10)
93 93
94 94 # Defaults are validated when the HasTraits is instantiated
95 95 class B(HasTraits):
96 96 tt = MyIntTT('bad default')
97 97 self.assertRaises(TraitError, B)
98 98
99 99 def test_is_valid_for(self):
100 100 class MyTT(TraitType):
101 101 def is_valid_for(self, value):
102 102 return True
103 103 class A(HasTraits):
104 104 tt = MyTT
105 105
106 106 a = A()
107 107 a.tt = 10
108 108 self.assertEquals(a.tt, 10)
109 109
110 110 def test_value_for(self):
111 111 class MyTT(TraitType):
112 112 def value_for(self, value):
113 113 return 20
114 114 class A(HasTraits):
115 115 tt = MyTT
116 116
117 117 a = A()
118 118 a.tt = 10
119 119 self.assertEquals(a.tt, 20)
120 120
121 121 def test_info(self):
122 122 class A(HasTraits):
123 123 tt = TraitType
124 124 a = A()
125 125 self.assertEquals(A.tt.info(), 'any value')
126 126
127 127 def test_error(self):
128 128 class A(HasTraits):
129 129 tt = TraitType
130 130 a = A()
131 131 self.assertRaises(TraitError, A.tt.error, a, 10)
132 132
133 133 def test_dynamic_initializer(self):
134 134 class A(HasTraits):
135 135 x = Int(10)
136 136 def _x_default(self):
137 137 return 11
138 138 class B(A):
139 139 x = Int(20)
140 140 class C(A):
141 141 def _x_default(self):
142 142 return 21
143 143
144 144 a = A()
145 145 self.assertEquals(a._trait_values, {})
146 146 self.assertEquals(a._trait_dyn_inits.keys(), ['x'])
147 147 self.assertEquals(a.x, 11)
148 148 self.assertEquals(a._trait_values, {'x': 11})
149 149 b = B()
150 150 self.assertEquals(b._trait_values, {'x': 20})
151 151 self.assertEquals(a._trait_dyn_inits.keys(), ['x'])
152 152 self.assertEquals(b.x, 20)
153 153 c = C()
154 154 self.assertEquals(c._trait_values, {})
155 155 self.assertEquals(a._trait_dyn_inits.keys(), ['x'])
156 156 self.assertEquals(c.x, 21)
157 157 self.assertEquals(c._trait_values, {'x': 21})
158 158 # Ensure that the base class remains unmolested when the _default
159 159 # initializer gets overridden in a subclass.
160 160 a = A()
161 161 c = C()
162 162 self.assertEquals(a._trait_values, {})
163 163 self.assertEquals(a._trait_dyn_inits.keys(), ['x'])
164 164 self.assertEquals(a.x, 11)
165 165 self.assertEquals(a._trait_values, {'x': 11})
166 166
167 167
168 168
169 169 class TestHasTraitsMeta(TestCase):
170 170
171 171 def test_metaclass(self):
172 172 self.assertEquals(type(HasTraits), MetaHasTraits)
173 173
174 174 class A(HasTraits):
175 175 a = Int
176 176
177 177 a = A()
178 178 self.assertEquals(type(a.__class__), MetaHasTraits)
179 179 self.assertEquals(a.a,0)
180 180 a.a = 10
181 181 self.assertEquals(a.a,10)
182 182
183 183 class B(HasTraits):
184 184 b = Int()
185 185
186 186 b = B()
187 187 self.assertEquals(b.b,0)
188 188 b.b = 10
189 189 self.assertEquals(b.b,10)
190 190
191 191 class C(HasTraits):
192 192 c = Int(30)
193 193
194 194 c = C()
195 195 self.assertEquals(c.c,30)
196 196 c.c = 10
197 197 self.assertEquals(c.c,10)
198 198
199 199 def test_this_class(self):
200 200 class A(HasTraits):
201 201 t = This()
202 202 tt = This()
203 203 class B(A):
204 204 tt = This()
205 205 ttt = This()
206 206 self.assertEquals(A.t.this_class, A)
207 207 self.assertEquals(B.t.this_class, A)
208 208 self.assertEquals(B.tt.this_class, B)
209 209 self.assertEquals(B.ttt.this_class, B)
210 210
211 211 class TestHasTraitsNotify(TestCase):
212 212
213 213 def setUp(self):
214 214 self._notify1 = []
215 215 self._notify2 = []
216 216
217 217 def notify1(self, name, old, new):
218 218 self._notify1.append((name, old, new))
219 219
220 220 def notify2(self, name, old, new):
221 221 self._notify2.append((name, old, new))
222 222
223 223 def test_notify_all(self):
224 224
225 225 class A(HasTraits):
226 226 a = Int
227 227 b = Float
228 228
229 229 a = A()
230 230 a.on_trait_change(self.notify1)
231 231 a.a = 0
232 232 self.assertEquals(len(self._notify1),0)
233 233 a.b = 0.0
234 234 self.assertEquals(len(self._notify1),0)
235 235 a.a = 10
236 236 self.assert_(('a',0,10) in self._notify1)
237 237 a.b = 10.0
238 238 self.assert_(('b',0.0,10.0) in self._notify1)
239 239 self.assertRaises(TraitError,setattr,a,'a','bad string')
240 240 self.assertRaises(TraitError,setattr,a,'b','bad string')
241 241 self._notify1 = []
242 242 a.on_trait_change(self.notify1,remove=True)
243 243 a.a = 20
244 244 a.b = 20.0
245 245 self.assertEquals(len(self._notify1),0)
246 246
247 247 def test_notify_one(self):
248 248
249 249 class A(HasTraits):
250 250 a = Int
251 251 b = Float
252 252
253 253 a = A()
254 254 a.on_trait_change(self.notify1, 'a')
255 255 a.a = 0
256 256 self.assertEquals(len(self._notify1),0)
257 257 a.a = 10
258 258 self.assert_(('a',0,10) in self._notify1)
259 259 self.assertRaises(TraitError,setattr,a,'a','bad string')
260 260
261 261 def test_subclass(self):
262 262
263 263 class A(HasTraits):
264 264 a = Int
265 265
266 266 class B(A):
267 267 b = Float
268 268
269 269 b = B()
270 270 self.assertEquals(b.a,0)
271 271 self.assertEquals(b.b,0.0)
272 272 b.a = 100
273 273 b.b = 100.0
274 274 self.assertEquals(b.a,100)
275 275 self.assertEquals(b.b,100.0)
276 276
277 277 def test_notify_subclass(self):
278 278
279 279 class A(HasTraits):
280 280 a = Int
281 281
282 282 class B(A):
283 283 b = Float
284 284
285 285 b = B()
286 286 b.on_trait_change(self.notify1, 'a')
287 287 b.on_trait_change(self.notify2, 'b')
288 288 b.a = 0
289 289 b.b = 0.0
290 290 self.assertEquals(len(self._notify1),0)
291 291 self.assertEquals(len(self._notify2),0)
292 292 b.a = 10
293 293 b.b = 10.0
294 294 self.assert_(('a',0,10) in self._notify1)
295 295 self.assert_(('b',0.0,10.0) in self._notify2)
296 296
297 297 def test_static_notify(self):
298 298
299 299 class A(HasTraits):
300 300 a = Int
301 301 _notify1 = []
302 302 def _a_changed(self, name, old, new):
303 303 self._notify1.append((name, old, new))
304 304
305 305 a = A()
306 306 a.a = 0
307 307 # This is broken!!!
308 308 self.assertEquals(len(a._notify1),0)
309 309 a.a = 10
310 310 self.assert_(('a',0,10) in a._notify1)
311 311
312 312 class B(A):
313 313 b = Float
314 314 _notify2 = []
315 315 def _b_changed(self, name, old, new):
316 316 self._notify2.append((name, old, new))
317 317
318 318 b = B()
319 319 b.a = 10
320 320 b.b = 10.0
321 321 self.assert_(('a',0,10) in b._notify1)
322 322 self.assert_(('b',0.0,10.0) in b._notify2)
323 323
324 324 def test_notify_args(self):
325 325
326 326 def callback0():
327 327 self.cb = ()
328 328 def callback1(name):
329 329 self.cb = (name,)
330 330 def callback2(name, new):
331 331 self.cb = (name, new)
332 332 def callback3(name, old, new):
333 333 self.cb = (name, old, new)
334 334
335 335 class A(HasTraits):
336 336 a = Int
337 337
338 338 a = A()
339 339 a.on_trait_change(callback0, 'a')
340 340 a.a = 10
341 341 self.assertEquals(self.cb,())
342 342 a.on_trait_change(callback0, 'a', remove=True)
343 343
344 344 a.on_trait_change(callback1, 'a')
345 345 a.a = 100
346 346 self.assertEquals(self.cb,('a',))
347 347 a.on_trait_change(callback1, 'a', remove=True)
348 348
349 349 a.on_trait_change(callback2, 'a')
350 350 a.a = 1000
351 351 self.assertEquals(self.cb,('a',1000))
352 352 a.on_trait_change(callback2, 'a', remove=True)
353 353
354 354 a.on_trait_change(callback3, 'a')
355 355 a.a = 10000
356 356 self.assertEquals(self.cb,('a',1000,10000))
357 357 a.on_trait_change(callback3, 'a', remove=True)
358 358
359 359 self.assertEquals(len(a._trait_notifiers['a']),0)
360 360
361 361
362 362 class TestHasTraits(TestCase):
363 363
364 364 def test_trait_names(self):
365 365 class A(HasTraits):
366 366 i = Int
367 367 f = Float
368 368 a = A()
369 369 self.assertEquals(a.trait_names(),['i','f'])
370 370 self.assertEquals(A.class_trait_names(),['i','f'])
371 371
372 372 def test_trait_metadata(self):
373 373 class A(HasTraits):
374 374 i = Int(config_key='MY_VALUE')
375 375 a = A()
376 376 self.assertEquals(a.trait_metadata('i','config_key'), 'MY_VALUE')
377 377
378 378 def test_traits(self):
379 379 class A(HasTraits):
380 380 i = Int
381 381 f = Float
382 382 a = A()
383 383 self.assertEquals(a.traits(), dict(i=A.i, f=A.f))
384 384 self.assertEquals(A.class_traits(), dict(i=A.i, f=A.f))
385 385
386 386 def test_traits_metadata(self):
387 387 class A(HasTraits):
388 388 i = Int(config_key='VALUE1', other_thing='VALUE2')
389 389 f = Float(config_key='VALUE3', other_thing='VALUE2')
390 390 j = Int(0)
391 391 a = A()
392 392 self.assertEquals(a.traits(), dict(i=A.i, f=A.f, j=A.j))
393 393 traits = a.traits(config_key='VALUE1', other_thing='VALUE2')
394 394 self.assertEquals(traits, dict(i=A.i))
395 395
396 396 # This passes, but it shouldn't because I am replicating a bug in
397 397 # traits.
398 398 traits = a.traits(config_key=lambda v: True)
399 399 self.assertEquals(traits, dict(i=A.i, f=A.f, j=A.j))
400 400
401 401 def test_init(self):
402 402 class A(HasTraits):
403 403 i = Int()
404 404 x = Float()
405 405 a = A(i=1, x=10.0)
406 406 self.assertEquals(a.i, 1)
407 407 self.assertEquals(a.x, 10.0)
408 408
409 409 #-----------------------------------------------------------------------------
410 410 # Tests for specific trait types
411 411 #-----------------------------------------------------------------------------
412 412
413 413
414 414 class TestType(TestCase):
415 415
416 416 def test_default(self):
417 417
418 418 class B(object): pass
419 419 class A(HasTraits):
420 420 klass = Type
421 421
422 422 a = A()
423 423 self.assertEquals(a.klass, None)
424 424
425 425 a.klass = B
426 426 self.assertEquals(a.klass, B)
427 427 self.assertRaises(TraitError, setattr, a, 'klass', 10)
428 428
429 429 def test_value(self):
430 430
431 431 class B(object): pass
432 432 class C(object): pass
433 433 class A(HasTraits):
434 434 klass = Type(B)
435 435
436 436 a = A()
437 437 self.assertEquals(a.klass, B)
438 438 self.assertRaises(TraitError, setattr, a, 'klass', C)
439 439 self.assertRaises(TraitError, setattr, a, 'klass', object)
440 440 a.klass = B
441 441
442 442 def test_allow_none(self):
443 443
444 444 class B(object): pass
445 445 class C(B): pass
446 446 class A(HasTraits):
447 447 klass = Type(B, allow_none=False)
448 448
449 449 a = A()
450 450 self.assertEquals(a.klass, B)
451 451 self.assertRaises(TraitError, setattr, a, 'klass', None)
452 452 a.klass = C
453 453 self.assertEquals(a.klass, C)
454 454
455 455 def test_validate_klass(self):
456 456
457 457 class A(HasTraits):
458 458 klass = Type('no strings allowed')
459 459
460 460 self.assertRaises(ImportError, A)
461 461
462 462 class A(HasTraits):
463 463 klass = Type('rub.adub.Duck')
464 464
465 465 self.assertRaises(ImportError, A)
466 466
467 467 def test_validate_default(self):
468 468
469 469 class B(object): pass
470 470 class A(HasTraits):
471 471 klass = Type('bad default', B)
472 472
473 473 self.assertRaises(ImportError, A)
474 474
475 475 class C(HasTraits):
476 476 klass = Type(None, B, allow_none=False)
477 477
478 478 self.assertRaises(TraitError, C)
479 479
480 480 def test_str_klass(self):
481 481
482 482 class A(HasTraits):
483 483 klass = Type('IPython.utils.ipstruct.Struct')
484 484
485 485 from IPython.utils.ipstruct import Struct
486 486 a = A()
487 487 a.klass = Struct
488 488 self.assertEquals(a.klass, Struct)
489 489
490 490 self.assertRaises(TraitError, setattr, a, 'klass', 10)
491 491
492 492 class TestInstance(TestCase):
493 493
494 494 def test_basic(self):
495 495 class Foo(object): pass
496 496 class Bar(Foo): pass
497 497 class Bah(object): pass
498 498
499 499 class A(HasTraits):
500 500 inst = Instance(Foo)
501 501
502 502 a = A()
503 503 self.assert_(a.inst is None)
504 504 a.inst = Foo()
505 505 self.assert_(isinstance(a.inst, Foo))
506 506 a.inst = Bar()
507 507 self.assert_(isinstance(a.inst, Foo))
508 508 self.assertRaises(TraitError, setattr, a, 'inst', Foo)
509 509 self.assertRaises(TraitError, setattr, a, 'inst', Bar)
510 510 self.assertRaises(TraitError, setattr, a, 'inst', Bah())
511 511
512 512 def test_unique_default_value(self):
513 513 class Foo(object): pass
514 514 class A(HasTraits):
515 515 inst = Instance(Foo,(),{})
516 516
517 517 a = A()
518 518 b = A()
519 519 self.assert_(a.inst is not b.inst)
520 520
521 521 def test_args_kw(self):
522 522 class Foo(object):
523 523 def __init__(self, c): self.c = c
524 524 class Bar(object): pass
525 525 class Bah(object):
526 526 def __init__(self, c, d):
527 527 self.c = c; self.d = d
528 528
529 529 class A(HasTraits):
530 530 inst = Instance(Foo, (10,))
531 531 a = A()
532 532 self.assertEquals(a.inst.c, 10)
533 533
534 534 class B(HasTraits):
535 535 inst = Instance(Bah, args=(10,), kw=dict(d=20))
536 536 b = B()
537 537 self.assertEquals(b.inst.c, 10)
538 538 self.assertEquals(b.inst.d, 20)
539 539
540 540 class C(HasTraits):
541 541 inst = Instance(Foo)
542 542 c = C()
543 543 self.assert_(c.inst is None)
544 544
545 545 def test_bad_default(self):
546 546 class Foo(object): pass
547 547
548 548 class A(HasTraits):
549 549 inst = Instance(Foo, allow_none=False)
550 550
551 551 self.assertRaises(TraitError, A)
552 552
553 553 def test_instance(self):
554 554 class Foo(object): pass
555 555
556 556 def inner():
557 557 class A(HasTraits):
558 558 inst = Instance(Foo())
559 559
560 560 self.assertRaises(TraitError, inner)
561 561
562 562
563 563 class TestThis(TestCase):
564 564
565 565 def test_this_class(self):
566 566 class Foo(HasTraits):
567 567 this = This
568 568
569 569 f = Foo()
570 570 self.assertEquals(f.this, None)
571 571 g = Foo()
572 572 f.this = g
573 573 self.assertEquals(f.this, g)
574 574 self.assertRaises(TraitError, setattr, f, 'this', 10)
575 575
576 576 def test_this_inst(self):
577 577 class Foo(HasTraits):
578 578 this = This()
579 579
580 580 f = Foo()
581 581 f.this = Foo()
582 582 self.assert_(isinstance(f.this, Foo))
583 583
584 584 def test_subclass(self):
585 585 class Foo(HasTraits):
586 586 t = This()
587 587 class Bar(Foo):
588 588 pass
589 589 f = Foo()
590 590 b = Bar()
591 591 f.t = b
592 592 b.t = f
593 593 self.assertEquals(f.t, b)
594 594 self.assertEquals(b.t, f)
595 595
596 596 def test_subclass_override(self):
597 597 class Foo(HasTraits):
598 598 t = This()
599 599 class Bar(Foo):
600 600 t = This()
601 601 f = Foo()
602 602 b = Bar()
603 603 f.t = b
604 604 self.assertEquals(f.t, b)
605 605 self.assertRaises(TraitError, setattr, b, 't', f)
606 606
607 607 class TraitTestBase(TestCase):
608 608 """A best testing class for basic trait types."""
609 609
610 610 def assign(self, value):
611 611 self.obj.value = value
612 612
613 613 def coerce(self, value):
614 614 return value
615 615
616 616 def test_good_values(self):
617 617 if hasattr(self, '_good_values'):
618 618 for value in self._good_values:
619 619 self.assign(value)
620 620 self.assertEquals(self.obj.value, self.coerce(value))
621 621
622 622 def test_bad_values(self):
623 623 if hasattr(self, '_bad_values'):
624 624 for value in self._bad_values:
625 self.assertRaises(TraitError, self.assign, value)
625 try:
626 self.assertRaises(TraitError, self.assign, value)
627 except AssertionError:
628 assert False, value
626 629
627 630 def test_default_value(self):
628 631 if hasattr(self, '_default_value'):
629 632 self.assertEquals(self._default_value, self.obj.value)
630 633
631 634
632 635 class AnyTrait(HasTraits):
633 636
634 637 value = Any
635 638
636 639 class AnyTraitTest(TraitTestBase):
637 640
638 641 obj = AnyTrait()
639 642
640 643 _default_value = None
641 644 _good_values = [10.0, 'ten', u'ten', [10], {'ten': 10},(10,), None, 1j]
642 645 _bad_values = []
643 646
644 647
645 648 class IntTrait(HasTraits):
646 649
647 650 value = Int(99)
648 651
649 652 class TestInt(TraitTestBase):
650 653
651 654 obj = IntTrait()
652 655 _default_value = 99
653 656 _good_values = [10, -10]
654 _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None, 1j, 10L,
655 -10L, 10.1, -10.1, '10L', '-10L', '10.1', '-10.1', u'10L',
657 _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None, 1j,
658 10.1, -10.1, '10L', '-10L', '10.1', '-10.1', u'10L',
656 659 u'-10L', u'10.1', u'-10.1', '10', '-10', u'10', u'-10']
660 if not py3compat.PY3:
661 _bad_values.extend([10L, -10L])
657 662
658 663
659 664 class LongTrait(HasTraits):
660 665
661 666 value = Long(99L)
662 667
663 668 class TestLong(TraitTestBase):
664 669
665 670 obj = LongTrait()
666 671
667 672 _default_value = 99L
668 673 _good_values = [10, -10, 10L, -10L]
669 674 _bad_values = ['ten', u'ten', [10], [10l], {'ten': 10},(10,),(10L,),
670 675 None, 1j, 10.1, -10.1, '10', '-10', '10L', '-10L', '10.1',
671 676 '-10.1', u'10', u'-10', u'10L', u'-10L', u'10.1',
672 677 u'-10.1']
673 678
674 679
675 680 class FloatTrait(HasTraits):
676 681
677 682 value = Float(99.0)
678 683
679 684 class TestFloat(TraitTestBase):
680 685
681 686 obj = FloatTrait()
682 687
683 688 _default_value = 99.0
684 689 _good_values = [10, -10, 10.1, -10.1]
685 _bad_values = [10L, -10L, 'ten', u'ten', [10], {'ten': 10},(10,), None,
690 _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None,
686 691 1j, '10', '-10', '10L', '-10L', '10.1', '-10.1', u'10',
687 692 u'-10', u'10L', u'-10L', u'10.1', u'-10.1']
693 if not py3compat.PY3:
694 _bad_values.extend([10L, -10L])
688 695
689 696
690 697 class ComplexTrait(HasTraits):
691 698
692 699 value = Complex(99.0-99.0j)
693 700
694 701 class TestComplex(TraitTestBase):
695 702
696 703 obj = ComplexTrait()
697 704
698 705 _default_value = 99.0-99.0j
699 706 _good_values = [10, -10, 10.1, -10.1, 10j, 10+10j, 10-10j,
700 707 10.1j, 10.1+10.1j, 10.1-10.1j]
701 _bad_values = [10L, -10L, u'10L', u'-10L', 'ten', [10], {'ten': 10},(10,), None]
708 _bad_values = [u'10L', u'-10L', 'ten', [10], {'ten': 10},(10,), None]
709 if not py3compat.PY3:
710 _bad_values.extend([10L, -10L])
702 711
703 712
704 713 class BytesTrait(HasTraits):
705 714
706 715 value = Bytes(b'string')
707 716
708 717 class TestBytes(TraitTestBase):
709 718
710 719 obj = BytesTrait()
711 720
712 721 _default_value = b'string'
713 722 _good_values = [b'10', b'-10', b'10L',
714 723 b'-10L', b'10.1', b'-10.1', b'string']
715 724 _bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j, [10],
716 725 ['ten'],{'ten': 10},(10,), None, u'string']
717 726
718 727
719 728 class UnicodeTrait(HasTraits):
720 729
721 730 value = Unicode(u'unicode')
722 731
723 732 class TestUnicode(TraitTestBase):
724 733
725 734 obj = UnicodeTrait()
726 735
727 736 _default_value = u'unicode'
728 737 _good_values = ['10', '-10', '10L', '-10L', '10.1',
729 738 '-10.1', '', u'', 'string', u'string', u"€"]
730 739 _bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j,
731 740 [10], ['ten'], [u'ten'], {'ten': 10},(10,), None]
732 741
733 742
734 743 class ObjectNameTrait(HasTraits):
735 744 value = ObjectName("abc")
736 745
737 746 class TestObjectName(TraitTestBase):
738 747 obj = ObjectNameTrait()
739 748
740 749 _default_value = "abc"
741 750 _good_values = ["a", "gh", "g9", "g_", "_G", u"a345_"]
742 751 _bad_values = [1, "", u"€", "9g", "!", "#abc", "aj@", "a.b", "a()", "a[0]",
743 752 object(), object]
744 753 if sys.version_info[0] < 3:
745 754 _bad_values.append(u"ΓΎ")
746 755 else:
747 756 _good_values.append(u"ΓΎ") # ΓΎ=1 is valid in Python 3 (PEP 3131).
748 757
749 758
750 759 class DottedObjectNameTrait(HasTraits):
751 760 value = DottedObjectName("a.b")
752 761
753 762 class TestDottedObjectName(TraitTestBase):
754 763 obj = DottedObjectNameTrait()
755 764
756 765 _default_value = "a.b"
757 766 _good_values = ["A", "y.t", "y765.__repr__", "os.path.join", u"os.path.join"]
758 767 _bad_values = [1, u"abc.€", "_.@", ".", ".abc", "abc.", ".abc."]
759 768 if sys.version_info[0] < 3:
760 769 _bad_values.append(u"t.ΓΎ")
761 770 else:
762 771 _good_values.append(u"t.ΓΎ")
763 772
764 773
765 774 class TCPAddressTrait(HasTraits):
766 775
767 776 value = TCPAddress()
768 777
769 778 class TestTCPAddress(TraitTestBase):
770 779
771 780 obj = TCPAddressTrait()
772 781
773 782 _default_value = ('127.0.0.1',0)
774 783 _good_values = [('localhost',0),('192.168.0.1',1000),('www.google.com',80)]
775 784 _bad_values = [(0,0),('localhost',10.0),('localhost',-1)]
776 785
777 786 class ListTrait(HasTraits):
778 787
779 788 value = List(Int)
780 789
781 790 class TestList(TraitTestBase):
782 791
783 792 obj = ListTrait()
784 793
785 794 _default_value = []
786 795 _good_values = [[], [1], range(10)]
787 796 _bad_values = [10, [1,'a'], 'a', (1,2)]
788 797
789 798 class LenListTrait(HasTraits):
790 799
791 800 value = List(Int, [0], minlen=1, maxlen=2)
792 801
793 802 class TestLenList(TraitTestBase):
794 803
795 804 obj = LenListTrait()
796 805
797 806 _default_value = [0]
798 807 _good_values = [[1], range(2)]
799 808 _bad_values = [10, [1,'a'], 'a', (1,2), [], range(3)]
800 809
801 810 class TupleTrait(HasTraits):
802 811
803 812 value = Tuple(Int)
804 813
805 814 class TestTupleTrait(TraitTestBase):
806 815
807 816 obj = TupleTrait()
808 817
809 818 _default_value = None
810 819 _good_values = [(1,), None,(0,)]
811 820 _bad_values = [10, (1,2), [1],('a'), ()]
812 821
813 822 def test_invalid_args(self):
814 823 self.assertRaises(TypeError, Tuple, 5)
815 824 self.assertRaises(TypeError, Tuple, default_value='hello')
816 825 t = Tuple(Int, CBytes, default_value=(1,5))
817 826
818 827 class LooseTupleTrait(HasTraits):
819 828
820 829 value = Tuple((1,2,3))
821 830
822 831 class TestLooseTupleTrait(TraitTestBase):
823 832
824 833 obj = LooseTupleTrait()
825 834
826 835 _default_value = (1,2,3)
827 836 _good_values = [(1,), None, (0,), tuple(range(5)), tuple('hello'), ('a',5), ()]
828 837 _bad_values = [10, 'hello', [1], []]
829 838
830 839 def test_invalid_args(self):
831 840 self.assertRaises(TypeError, Tuple, 5)
832 841 self.assertRaises(TypeError, Tuple, default_value='hello')
833 842 t = Tuple(Int, CBytes, default_value=(1,5))
834 843
835 844
836 845 class MultiTupleTrait(HasTraits):
837 846
838 value = Tuple(Int, Bytes, default_value=[99,'bottles'])
847 value = Tuple(Int, Bytes, default_value=[99,b'bottles'])
839 848
840 849 class TestMultiTuple(TraitTestBase):
841 850
842 851 obj = MultiTupleTrait()
843 852
844 _default_value = (99,'bottles')
845 _good_values = [(1,'a'), (2,'b')]
846 _bad_values = ((),10, 'a', (1,'a',3), ('a',1))
853 _default_value = (99,b'bottles')
854 _good_values = [(1,b'a'), (2,b'b')]
855 _bad_values = ((),10, b'a', (1,b'a',3), (b'a',1), (1, u'a'))
General Comments 0
You need to be logged in to leave comments. Login now