Show More
@@ -0,0 +1,51 b'' | |||||
|
1 | """Base utilities support for IPython. | |||
|
2 | ||||
|
3 | Warning: this is a module that other utilities modules will import from, so it | |||
|
4 | can ONLY depend on the standard library, and NOTHING ELSE. In particular, this | |||
|
5 | module can NOT import anything from IPython, or circular dependencies will arise. | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Imports | |||
|
10 | #----------------------------------------------------------------------------- | |||
|
11 | ||||
|
12 | import subprocess | |||
|
13 | ||||
|
14 | #----------------------------------------------------------------------------- | |||
|
15 | # Functions | |||
|
16 | #----------------------------------------------------------------------------- | |||
|
17 | ||||
|
18 | def getoutputerror(cmd,verbose=0,debug=0,header='',split=0): | |||
|
19 | """Return (standard output,standard error) of executing cmd in a shell. | |||
|
20 | ||||
|
21 | Accepts the same arguments as system(), plus: | |||
|
22 | ||||
|
23 | - split(0): if true, each of stdout/err is returned as a list split on | |||
|
24 | newlines. | |||
|
25 | ||||
|
26 | Note: a stateful version of this function is available through the | |||
|
27 | SystemExec class.""" | |||
|
28 | ||||
|
29 | if verbose or debug: print header+cmd | |||
|
30 | if not cmd: | |||
|
31 | if split: | |||
|
32 | return [],[] | |||
|
33 | else: | |||
|
34 | return '','' | |||
|
35 | if not debug: | |||
|
36 | p = subprocess.Popen(cmd, shell=True, | |||
|
37 | stdin=subprocess.PIPE, | |||
|
38 | stdout=subprocess.PIPE, | |||
|
39 | stderr=subprocess.PIPE, | |||
|
40 | close_fds=True) | |||
|
41 | pin, pout, perr = (p.stdin, p.stdout, p.stderr) | |||
|
42 | ||||
|
43 | tout = pout.read().rstrip() | |||
|
44 | terr = perr.read().rstrip() | |||
|
45 | pin.close() | |||
|
46 | pout.close() | |||
|
47 | perr.close() | |||
|
48 | if split: | |||
|
49 | return tout.split('\n'),terr.split('\n') | |||
|
50 | else: | |||
|
51 | return tout,terr |
@@ -0,0 +1,26 b'' | |||||
|
1 | #!/usr/bin/env python | |||
|
2 | """Test script for IPython. | |||
|
3 | ||||
|
4 | The actual ipython test script to be installed with 'python setup.py install' | |||
|
5 | is in './scripts' directory, and will test IPython from an importable | |||
|
6 | location. | |||
|
7 | ||||
|
8 | This file is here (ipython source root directory) to facilitate non-root | |||
|
9 | 'zero-installation testing and development' (just copy the source tree | |||
|
10 | somewhere and run iptest.py). | |||
|
11 | ||||
|
12 | You can run this script directly, type -h to see all options.""" | |||
|
13 | ||||
|
14 | # Ensure that the imported IPython packages come from *THIS* IPython, not some | |||
|
15 | # other one that may exist system-wide | |||
|
16 | import os, sys | |||
|
17 | this_dir = os.path.dirname(os.path.abspath(__file__)) | |||
|
18 | sys.path.insert(0, this_dir) | |||
|
19 | ||||
|
20 | import IPython.testing.tools as t | |||
|
21 | import IPython.testing.iptest as ipt | |||
|
22 | t.INSTALLED = False | |||
|
23 | ipt.INSTALLED = False | |||
|
24 | ||||
|
25 | # Now proceed with execution | |||
|
26 | execfile(os.path.join(this_dir, 'IPython', 'scripts', 'iptest')) |
@@ -26,9 +26,12 b' from pprint import pformat' | |||||
26 | # Our own |
|
26 | # Our own | |
27 | from IPython.core import release |
|
27 | from IPython.core import release | |
28 | from IPython.core import ultratb |
|
28 | from IPython.core import ultratb | |
|
29 | from IPython.utils.genutils import sys_info | |||
|
30 | ||||
29 | from IPython.external.Itpl import itpl |
|
31 | from IPython.external.Itpl import itpl | |
30 |
|
32 | |||
31 | #**************************************************************************** |
|
33 | #**************************************************************************** | |
|
34 | ||||
32 | class CrashHandler(object): |
|
35 | class CrashHandler(object): | |
33 | """Customizable crash handlers for IPython-based systems. |
|
36 | """Customizable crash handlers for IPython-based systems. | |
34 |
|
37 | |||
@@ -166,21 +169,13 b' $self.bug_tracker' | |||||
166 |
|
169 | |||
167 | def make_report(self,traceback): |
|
170 | def make_report(self,traceback): | |
168 | """Return a string containing a crash report.""" |
|
171 | """Return a string containing a crash report.""" | |
169 | import platform |
|
|||
170 |
|
172 | |||
171 | sec_sep = self.section_sep |
|
173 | sec_sep = self.section_sep | |
172 |
|
174 | |||
173 | report = [] |
|
175 | report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n'] | |
174 | rpt_add = report.append |
|
176 | rpt_add = report.append | |
|
177 | rpt_add(sys_info()) | |||
175 |
|
178 | |||
176 | rpt_add('*'*75+'\n\n'+'IPython post-mortem report\n\n') |
|
|||
177 | rpt_add('IPython version: %s \n' % release.version) |
|
|||
178 | rpt_add('BZR revision : %s \n' % release.revision) |
|
|||
179 | rpt_add('Platform info : os.name -> %s, sys.platform -> %s\n' % |
|
|||
180 | (os.name,sys.platform) ) |
|
|||
181 | rpt_add(' : %s\n' % platform.platform()) |
|
|||
182 | rpt_add('Python info : %s\n' % sys.version) |
|
|||
183 |
|
||||
184 | try: |
|
179 | try: | |
185 | config = pformat(self.app.config) |
|
180 | config = pformat(self.app.config) | |
186 | rpt_add(sec_sep+'Current user configuration structure:\n\n') |
|
181 | rpt_add(sec_sep+'Current user configuration structure:\n\n') |
@@ -85,22 +85,22 b" def magic_history(self, parameter_s = ''):" | |||||
85 | if 'g' in opts: |
|
85 | if 'g' in opts: | |
86 | init = 1 |
|
86 | init = 1 | |
87 | final = len(input_hist) |
|
87 | final = len(input_hist) | |
88 | parts = parameter_s.split(None,1) |
|
88 | parts = parameter_s.split(None, 1) | |
89 | if len(parts) == 1: |
|
89 | if len(parts) == 1: | |
90 | parts += '*' |
|
90 | parts += '*' | |
91 | head, pattern = parts |
|
91 | head, pattern = parts | |
92 | pattern = "*" + pattern + "*" |
|
92 | pattern = "*" + pattern + "*" | |
93 | elif len(args) == 0: |
|
93 | elif len(args) == 0: | |
94 | final = len(input_hist) |
|
94 | final = len(input_hist)-1 | |
95 | init = max(1,final-default_length) |
|
95 | init = max(1,final-default_length) | |
96 | elif len(args) == 1: |
|
96 | elif len(args) == 1: | |
97 | final = len(input_hist) |
|
97 | final = len(input_hist) | |
98 | init = max(1,final-int(args[0])) |
|
98 | init = max(1, final-int(args[0])) | |
99 | elif len(args) == 2: |
|
99 | elif len(args) == 2: | |
100 | init,final = map(int,args) |
|
100 | init, final = map(int, args) | |
101 | else: |
|
101 | else: | |
102 | warn('%hist takes 0, 1 or 2 arguments separated by spaces.') |
|
102 | warn('%hist takes 0, 1 or 2 arguments separated by spaces.') | |
103 | print self.magic_hist.__doc__ |
|
103 | print >> Term.cout, self.magic_hist.__doc__ | |
104 | return |
|
104 | return | |
105 |
|
105 | |||
106 | width = len(str(final)) |
|
106 | width = len(str(final)) | |
@@ -114,13 +114,14 b" def magic_history(self, parameter_s = ''):" | |||||
114 | sh = self.shadowhist.all() |
|
114 | sh = self.shadowhist.all() | |
115 | for idx, s in sh: |
|
115 | for idx, s in sh: | |
116 | if fnmatch.fnmatch(s, pattern): |
|
116 | if fnmatch.fnmatch(s, pattern): | |
117 | print "0%d: %s" %(idx, s) |
|
117 | print >> outfile, "0%d: %s" %(idx, s) | |
118 | found = True |
|
118 | found = True | |
119 |
|
119 | |||
120 | if found: |
|
120 | if found: | |
121 | print "===" |
|
121 | print >> outfile, "===" | |
122 | print "shadow history ends, fetch by %rep <number> (must start with 0)" |
|
122 | print >> outfile, \ | |
123 | print "=== start of normal history ===" |
|
123 | "shadow history ends, fetch by %rep <number> (must start with 0)" | |
|
124 | print >> outfile, "=== start of normal history ===" | |||
124 |
|
125 | |||
125 | for in_num in range(init,final): |
|
126 | for in_num in range(init,final): | |
126 | inline = input_hist[in_num] |
|
127 | inline = input_hist[in_num] | |
@@ -130,7 +131,7 b" def magic_history(self, parameter_s = ''):" | |||||
130 | multiline = int(inline.count('\n') > 1) |
|
131 | multiline = int(inline.count('\n') > 1) | |
131 | if print_nums: |
|
132 | if print_nums: | |
132 | print >> outfile, \ |
|
133 | print >> outfile, \ | |
133 | '%s:%s' % (str(in_num).ljust(width),line_sep[multiline]), |
|
134 | '%s:%s' % (str(in_num).ljust(width), line_sep[multiline]), | |
134 | if pyprompts: |
|
135 | if pyprompts: | |
135 | print >> outfile, '>>>', |
|
136 | print >> outfile, '>>>', | |
136 | if multiline: |
|
137 | if multiline: | |
@@ -141,9 +142,10 b" def magic_history(self, parameter_s = ''):" | |||||
141 | print >> outfile, inline, |
|
142 | print >> outfile, inline, | |
142 | else: |
|
143 | else: | |
143 | print >> outfile, inline, |
|
144 | print >> outfile, inline, | |
144 | output = self.shell.user_ns['Out'].get(in_num) |
|
145 | if print_outputs: | |
145 | if output is not None: |
|
146 | output = self.shell.user_ns['Out'].get(in_num) | |
146 |
|
|
147 | if output is not None: | |
|
148 | print >> outfile, repr(output) | |||
147 |
|
149 | |||
148 | if close_at_end: |
|
150 | if close_at_end: | |
149 | outfile.close() |
|
151 | outfile.close() |
@@ -219,14 +219,21 b' def make_user_namespaces(user_ns=None, user_global_ns=None):' | |||||
219 | of the interpreter and a dict to be used as the global namespace. |
|
219 | of the interpreter and a dict to be used as the global namespace. | |
220 | """ |
|
220 | """ | |
221 |
|
221 | |||
|
222 | ||||
|
223 | # We must ensure that __builtin__ (without the final 's') is always | |||
|
224 | # available and pointing to the __builtin__ *module*. For more details: | |||
|
225 | # http://mail.python.org/pipermail/python-dev/2001-April/014068.html | |||
|
226 | ||||
222 | if user_ns is None: |
|
227 | if user_ns is None: | |
223 | # Set __name__ to __main__ to better match the behavior of the |
|
228 | # Set __name__ to __main__ to better match the behavior of the | |
224 | # normal interpreter. |
|
229 | # normal interpreter. | |
225 | user_ns = {'__name__' :'__main__', |
|
230 | user_ns = {'__name__' :'__main__', | |
|
231 | '__builtin__' : __builtin__, | |||
226 | '__builtins__' : __builtin__, |
|
232 | '__builtins__' : __builtin__, | |
227 | } |
|
233 | } | |
228 | else: |
|
234 | else: | |
229 | user_ns.setdefault('__name__','__main__') |
|
235 | user_ns.setdefault('__name__','__main__') | |
|
236 | user_ns.setdefault('__builtin__',__builtin__) | |||
230 | user_ns.setdefault('__builtins__',__builtin__) |
|
237 | user_ns.setdefault('__builtins__',__builtin__) | |
231 |
|
238 | |||
232 | if user_global_ns is None: |
|
239 | if user_global_ns is None: | |
@@ -970,8 +977,20 b' class InteractiveShell(Component, Magic):' | |||||
970 | # user_ns, and we sync that contents into user_config_ns so that these |
|
977 | # user_ns, and we sync that contents into user_config_ns so that these | |
971 | # initial variables aren't shown by %who. After the sync, we add the |
|
978 | # initial variables aren't shown by %who. After the sync, we add the | |
972 | # rest of what we *do* want the user to see with %who even on a new |
|
979 | # rest of what we *do* want the user to see with %who even on a new | |
973 | # session. |
|
980 | # session (probably nothing, so theye really only see their own stuff) | |
974 | ns = {} |
|
981 | ||
|
982 | # The user dict must *always* have a __builtin__ reference to the | |||
|
983 | # Python standard __builtin__ namespace, which must be imported. | |||
|
984 | # This is so that certain operations in prompt evaluation can be | |||
|
985 | # reliably executed with builtins. Note that we can NOT use | |||
|
986 | # __builtins__ (note the 's'), because that can either be a dict or a | |||
|
987 | # module, and can even mutate at runtime, depending on the context | |||
|
988 | # (Python makes no guarantees on it). In contrast, __builtin__ is | |||
|
989 | # always a module object, though it must be explicitly imported. | |||
|
990 | ||||
|
991 | # For more details: | |||
|
992 | # http://mail.python.org/pipermail/python-dev/2001-April/014068.html | |||
|
993 | ns = dict(__builtin__ = __builtin__) | |||
975 |
|
994 | |||
976 | # Put 'help' in the user namespace |
|
995 | # Put 'help' in the user namespace | |
977 | try: |
|
996 | try: | |
@@ -987,20 +1006,23 b' class InteractiveShell(Component, Magic):' | |||||
987 |
|
1006 | |||
988 | ns['_sh'] = shadowns |
|
1007 | ns['_sh'] = shadowns | |
989 |
|
1008 | |||
990 | # Sync what we've added so far to user_config_ns so these aren't seen |
|
1009 | # user aliases to input and output histories. These shouldn't show up | |
991 | # by %who |
|
1010 | # in %who, as they can have very large reprs. | |
992 | self.user_config_ns.update(ns) |
|
|||
993 |
|
||||
994 | # Now, continue adding more contents |
|
|||
995 |
|
||||
996 | # user aliases to input and output histories |
|
|||
997 | ns['In'] = self.input_hist |
|
1011 | ns['In'] = self.input_hist | |
998 | ns['Out'] = self.output_hist |
|
1012 | ns['Out'] = self.output_hist | |
999 |
|
1013 | |||
1000 | # Store myself as the public api!!! |
|
1014 | # Store myself as the public api!!! | |
1001 | ns['get_ipython'] = self.get_ipython |
|
1015 | ns['get_ipython'] = self.get_ipython | |
|
1016 | ||||
|
1017 | # Sync what we've added so far to user_config_ns so these aren't seen | |||
|
1018 | # by %who | |||
|
1019 | self.user_config_ns.update(ns) | |||
|
1020 | ||||
|
1021 | # Anything put into ns now would show up in %who. Think twice before | |||
|
1022 | # putting anything here, as we really want %who to show the user their | |||
|
1023 | # stuff, not our variables. | |||
1002 |
|
1024 | |||
1003 |
# |
|
1025 | # Finally, update the real user's namespace | |
1004 | self.user_ns.update(ns) |
|
1026 | self.user_ns.update(ns) | |
1005 |
|
1027 | |||
1006 |
|
1028 |
@@ -2537,6 +2537,9 b' Defaulting color scheme to \'NoColor\'"""' | |||||
2537 |
|
2537 | |||
2538 | self.shell.ask_exit() |
|
2538 | self.shell.ask_exit() | |
2539 |
|
2539 | |||
|
2540 | # Add aliases as magics so all common forms work: exit, quit, Exit, Quit. | |||
|
2541 | magic_exit = magic_quit = magic_Quit = magic_Exit | |||
|
2542 | ||||
2540 | #...................................................................... |
|
2543 | #...................................................................... | |
2541 | # Functions to implement unix shell-type things |
|
2544 | # Functions to implement unix shell-type things | |
2542 |
|
2545 |
@@ -131,8 +131,14 b' prompt_specials_color = {' | |||||
131 | # Prompt/history count, with the actual digits replaced by dots. Used |
|
131 | # Prompt/history count, with the actual digits replaced by dots. Used | |
132 | # mainly in continuation prompts (prompt_in2) |
|
132 | # mainly in continuation prompts (prompt_in2) | |
133 | #r'\D': '${"."*len(str(self.cache.prompt_count))}', |
|
133 | #r'\D': '${"."*len(str(self.cache.prompt_count))}', | |
134 | # More robust form of the above expression, that uses __builtins__ |
|
134 | ||
135 | r'\D': '${"."*__builtins__.len(__builtins__.str(self.cache.prompt_count))}', |
|
135 | # More robust form of the above expression, that uses the __builtin__ | |
|
136 | # module. Note that we can NOT use __builtins__ (note the 's'), because | |||
|
137 | # that can either be a dict or a module, and can even mutate at runtime, | |||
|
138 | # depending on the context (Python makes no guarantees on it). In | |||
|
139 | # contrast, __builtin__ is always a module object, though it must be | |||
|
140 | # explicitly imported. | |||
|
141 | r'\D': '${"."*__builtin__.len(__builtin__.str(self.cache.prompt_count))}', | |||
136 |
|
142 | |||
137 | # Current working directory |
|
143 | # Current working directory | |
138 | r'\w': '${os.getcwd()}', |
|
144 | r'\w': '${os.getcwd()}', | |
@@ -215,6 +221,7 b' def str_safe(arg):' | |||||
215 | out = '<ERROR: %s>' % msg |
|
221 | out = '<ERROR: %s>' % msg | |
216 | except Exception,msg: |
|
222 | except Exception,msg: | |
217 | out = '<ERROR: %s>' % msg |
|
223 | out = '<ERROR: %s>' % msg | |
|
224 | #raise # dbg | |||
218 | return out |
|
225 | return out | |
219 |
|
226 | |||
220 | class BasePrompt(object): |
|
227 | class BasePrompt(object): |
@@ -23,7 +23,7 b" name = 'ipython'" | |||||
23 | development = True # change this to False to do a release |
|
23 | development = True # change this to False to do a release | |
24 | version_base = '0.11' |
|
24 | version_base = '0.11' | |
25 | branch = 'ipython' |
|
25 | branch = 'ipython' | |
26 |
revision = '13 |
|
26 | revision = '1346' | |
27 |
|
27 | |||
28 | if development: |
|
28 | if development: | |
29 | if branch == 'ipython': |
|
29 | if branch == 'ipython': |
@@ -13,7 +13,7 b' class C(object):' | |||||
13 |
|
13 | |||
14 | def __del__(self): |
|
14 | def __del__(self): | |
15 | print 'tclass.py: deleting object:',self.name |
|
15 | print 'tclass.py: deleting object:',self.name | |
16 |
|
16 | sys.stdout.flush() | ||
17 |
|
17 | |||
18 | try: |
|
18 | try: | |
19 | name = sys.argv[1] |
|
19 | name = sys.argv[1] | |
@@ -28,3 +28,4 b' else:' | |||||
28 | # This next print statement is NOT debugging, we're making the check on a |
|
28 | # This next print statement is NOT debugging, we're making the check on a | |
29 | # completely separate process so we verify by capturing stdout: |
|
29 | # completely separate process so we verify by capturing stdout: | |
30 | print 'ARGV 1-:', sys.argv[1:] |
|
30 | print 'ARGV 1-:', sys.argv[1:] | |
|
31 | sys.stdout.flush() |
@@ -153,7 +153,6 b' def doctest_hist_op():' | |||||
153 | >>> ss |
|
153 | >>> ss | |
154 | <...s instance at ...> |
|
154 | <...s instance at ...> | |
155 | >>> |
|
155 | >>> | |
156 | >>> get_ipython().magic("hist -op") |
|
|||
157 | """ |
|
156 | """ | |
158 |
|
157 | |||
159 | def test_shist(): |
|
158 | def test_shist(): |
@@ -67,7 +67,7 b' def doctest_run_builtins():' | |||||
67 |
|
67 | |||
68 | In [6]: t1 = type(__builtins__) |
|
68 | In [6]: t1 = type(__builtins__) | |
69 |
|
69 | |||
70 |
In [7]: %run |
|
70 | In [7]: %run $fname | |
71 |
|
71 | |||
72 | In [7]: f.close() |
|
72 | In [7]: f.close() | |
73 |
|
73 | |||
@@ -101,7 +101,7 b' class TestMagicRunPass(tt.TempFileMixin):' | |||||
101 | _ip = get_ipython() |
|
101 | _ip = get_ipython() | |
102 | # This fails on Windows if self.tmpfile.name has spaces or "~" in it. |
|
102 | # This fails on Windows if self.tmpfile.name has spaces or "~" in it. | |
103 | # See below and ticket https://bugs.launchpad.net/bugs/366353 |
|
103 | # See below and ticket https://bugs.launchpad.net/bugs/366353 | |
104 |
_ip.magic('run |
|
104 | _ip.magic('run %s' % self.fname) | |
105 |
|
105 | |||
106 | def test_builtins_id(self): |
|
106 | def test_builtins_id(self): | |
107 | """Check that %run doesn't damage __builtins__ """ |
|
107 | """Check that %run doesn't damage __builtins__ """ |
@@ -20,7 +20,7 b' import sys' | |||||
20 | from nose.tools import assert_equal |
|
20 | from nose.tools import assert_equal | |
21 |
|
21 | |||
22 | from IPython.frontend.prefilterfrontend import PrefilterFrontEnd |
|
22 | from IPython.frontend.prefilterfrontend import PrefilterFrontEnd | |
23 |
from IPython. |
|
23 | from IPython.testing.globalipapp import get_ipython | |
24 | from IPython.testing.tools import default_argv |
|
24 | from IPython.testing.tools import default_argv | |
25 |
|
25 | |||
26 | #----------------------------------------------------------------------------- |
|
26 | #----------------------------------------------------------------------------- | |
@@ -60,7 +60,7 b' def isolate_ipython0(func):' | |||||
60 | with arguments. |
|
60 | with arguments. | |
61 | """ |
|
61 | """ | |
62 | def my_func(): |
|
62 | def my_func(): | |
63 |
ip0 = get_ipython |
|
63 | ip0 = get_ipython() | |
64 | if ip0 is None: |
|
64 | if ip0 is None: | |
65 | return func() |
|
65 | return func() | |
66 | # We have a real ipython running... |
|
66 | # We have a real ipython running... | |
@@ -169,7 +169,7 b' def test_magic():' | |||||
169 | f.input_buffer += '%who' |
|
169 | f.input_buffer += '%who' | |
170 | f._on_enter() |
|
170 | f._on_enter() | |
171 | out_value = f.out.getvalue() |
|
171 | out_value = f.out.getvalue() | |
172 |
assert_equal(out_value, 'In |
|
172 | assert_equal(out_value, 'Interactive namespace is empty.\n') | |
173 |
|
173 | |||
174 |
|
174 | |||
175 | @isolate_ipython0 |
|
175 | @isolate_ipython0 |
@@ -22,4 +22,4 b' __docformat__ = "restructuredtext en"' | |||||
22 | # the file COPYING, distributed as part of this software. |
|
22 | # the file COPYING, distributed as part of this software. | |
23 | #----------------------------------------------------------------------------- |
|
23 | #----------------------------------------------------------------------------- | |
24 |
|
24 | |||
25 | from IPython.kernel.error import TaskRejectError No newline at end of file |
|
25 | from IPython.kernel.error import TaskRejectError |
@@ -20,6 +20,7 b' from __future__ import with_statement' | |||||
20 | import os |
|
20 | import os | |
21 | import shutil |
|
21 | import shutil | |
22 | import sys |
|
22 | import sys | |
|
23 | import warnings | |||
23 |
|
24 | |||
24 | from twisted.python import log |
|
25 | from twisted.python import log | |
25 |
|
26 | |||
@@ -27,13 +28,25 b' from IPython.core import release' | |||||
27 | from IPython.config.loader import PyFileConfigLoader |
|
28 | from IPython.config.loader import PyFileConfigLoader | |
28 | from IPython.core.application import Application |
|
29 | from IPython.core.application import Application | |
29 | from IPython.core.component import Component |
|
30 | from IPython.core.component import Component | |
|
31 | from IPython.utils.genutils import get_ipython_dir, get_ipython_package_dir | |||
30 | from IPython.utils.traitlets import Unicode, Bool |
|
32 | from IPython.utils.traitlets import Unicode, Bool | |
31 | from IPython.utils import genutils |
|
33 | from IPython.utils import genutils | |
32 |
|
34 | |||
33 | #----------------------------------------------------------------------------- |
|
35 | #----------------------------------------------------------------------------- | |
34 | # Imports |
|
36 | # Warnings control | |
35 | #----------------------------------------------------------------------------- |
|
37 | #----------------------------------------------------------------------------- | |
|
38 | # Twisted generates annoying warnings with Python 2.6, as will do other code | |||
|
39 | # that imports 'sets' as of today | |||
|
40 | warnings.filterwarnings('ignore', 'the sets module is deprecated', | |||
|
41 | DeprecationWarning ) | |||
36 |
|
42 | |||
|
43 | # This one also comes from Twisted | |||
|
44 | warnings.filterwarnings('ignore', 'the sha module is deprecated', | |||
|
45 | DeprecationWarning) | |||
|
46 | ||||
|
47 | #----------------------------------------------------------------------------- | |||
|
48 | # Classes and functions | |||
|
49 | #----------------------------------------------------------------------------- | |||
37 |
|
50 | |||
38 | class ClusterDirError(Exception): |
|
51 | class ClusterDirError(Exception): | |
39 | pass |
|
52 | pass | |
@@ -352,9 +365,6 b' class ApplicationWithClusterDir(Application):' | |||||
352 | self.default_config.Global.cluster_dir = self.cluster_dir |
|
365 | self.default_config.Global.cluster_dir = self.cluster_dir | |
353 | self.command_line_config.Global.cluster_dir = self.cluster_dir |
|
366 | self.command_line_config.Global.cluster_dir = self.cluster_dir | |
354 |
|
367 | |||
355 | # Set the search path to the cluster directory |
|
|||
356 | self.config_file_paths = (self.cluster_dir,) |
|
|||
357 |
|
||||
358 | def find_config_file_name(self): |
|
368 | def find_config_file_name(self): | |
359 | """Find the config file name for this application.""" |
|
369 | """Find the config file name for this application.""" | |
360 | # For this type of Application it should be set as a class attribute. |
|
370 | # For this type of Application it should be set as a class attribute. | |
@@ -362,8 +372,11 b' class ApplicationWithClusterDir(Application):' | |||||
362 | self.log.critical("No config filename found") |
|
372 | self.log.critical("No config filename found") | |
363 |
|
373 | |||
364 | def find_config_file_paths(self): |
|
374 | def find_config_file_paths(self): | |
365 | # Set the search path to the cluster directory |
|
375 | # Include our own config directory last, so that users can still find | |
366 | self.config_file_paths = (self.cluster_dir,) |
|
376 | # our shipped copies of builtin config files even if they don't have | |
|
377 | # them in their ipython cluster directory. | |||
|
378 | conf_dir = os.path.join(get_ipython_package_dir(), 'config', 'default') | |||
|
379 | self.config_file_paths = (self.cluster_dir, conf_dir) | |||
367 |
|
380 | |||
368 | def pre_construct(self): |
|
381 | def pre_construct(self): | |
369 | # The log and security dirs were set earlier, but here we put them |
|
382 | # The log and security dirs were set earlier, but here we put them |
@@ -17,8 +17,6 b' __test__ = {}' | |||||
17 | #------------------------------------------------------------------------------- |
|
17 | #------------------------------------------------------------------------------- | |
18 | # Imports |
|
18 | # Imports | |
19 | #------------------------------------------------------------------------------- |
|
19 | #------------------------------------------------------------------------------- | |
20 | from twisted.python import failure |
|
|||
21 |
|
||||
22 | from IPython.kernel.core import error |
|
20 | from IPython.kernel.core import error | |
23 |
|
21 | |||
24 | #------------------------------------------------------------------------------- |
|
22 | #------------------------------------------------------------------------------- | |
@@ -179,6 +177,8 b' class CompositeError(KernelError):' | |||||
179 | raise et, ev, etb |
|
177 | raise et, ev, etb | |
180 |
|
178 | |||
181 | def collect_exceptions(rlist, method): |
|
179 | def collect_exceptions(rlist, method): | |
|
180 | from twisted.python import failure | |||
|
181 | ||||
182 | elist = [] |
|
182 | elist = [] | |
183 | for r in rlist: |
|
183 | for r in rlist: | |
184 | if isinstance(r, failure.Failure): |
|
184 | if isinstance(r, failure.Failure): |
@@ -3,6 +3,22 b'' | |||||
3 | """IPython Test Suite Runner. |
|
3 | """IPython Test Suite Runner. | |
4 | """ |
|
4 | """ | |
5 |
|
5 | |||
6 | from IPython.testing import iptest |
|
6 | # The tests can't even run if nose isn't available, so might as well give the | |
|
7 | # user a civilized error message in that case. | |||
7 |
|
8 | |||
8 | iptest.main() |
|
9 | try: | |
|
10 | import nose | |||
|
11 | except ImportError: | |||
|
12 | error = """\ | |||
|
13 | ERROR: The IPython test suite requires nose to run. | |||
|
14 | ||||
|
15 | Please install nose on your system first and try again. | |||
|
16 | For information on installing nose, see: | |||
|
17 | http://somethingaboutorange.com/mrl/projects/nose | |||
|
18 | ||||
|
19 | Exiting.""" | |||
|
20 | import sys | |||
|
21 | print >> sys.stderr, error | |||
|
22 | else: | |||
|
23 | from IPython.testing import iptest | |||
|
24 | iptest.main() |
@@ -16,8 +16,6 b' For now, this script requires that both nose and twisted are installed. This' | |||||
16 | will change in the future. |
|
16 | will change in the future. | |
17 | """ |
|
17 | """ | |
18 |
|
18 | |||
19 | from __future__ import absolute_import |
|
|||
20 |
|
||||
21 | #----------------------------------------------------------------------------- |
|
19 | #----------------------------------------------------------------------------- | |
22 | # Module imports |
|
20 | # Module imports | |
23 | #----------------------------------------------------------------------------- |
|
21 | #----------------------------------------------------------------------------- | |
@@ -25,6 +23,7 b' from __future__ import absolute_import' | |||||
25 | # Stdlib |
|
23 | # Stdlib | |
26 | import os |
|
24 | import os | |
27 | import os.path as path |
|
25 | import os.path as path | |
|
26 | import platform | |||
28 | import signal |
|
27 | import signal | |
29 | import sys |
|
28 | import sys | |
30 | import subprocess |
|
29 | import subprocess | |
@@ -32,24 +31,46 b' import tempfile' | |||||
32 | import time |
|
31 | import time | |
33 | import warnings |
|
32 | import warnings | |
34 |
|
33 | |||
|
34 | ||||
|
35 | # Ugly, but necessary hack to ensure the test suite finds our version of | |||
|
36 | # IPython and not a possibly different one that may exist system-wide. | |||
|
37 | # Note that this must be done here, so the imports that come next work | |||
|
38 | # correctly even if IPython isn't installed yet. | |||
|
39 | p = os.path | |||
|
40 | ippath = p.abspath(p.join(p.dirname(__file__),'..','..')) | |||
|
41 | sys.path.insert(0, ippath) | |||
|
42 | ||||
35 | # Note: monkeypatch! |
|
43 | # Note: monkeypatch! | |
36 | # We need to monkeypatch a small problem in nose itself first, before importing |
|
44 | # We need to monkeypatch a small problem in nose itself first, before importing | |
37 | # it for actual use. This should get into nose upstream, but its release cycle |
|
45 | # it for actual use. This should get into nose upstream, but its release cycle | |
38 | # is slow and we need it for our parametric tests to work correctly. |
|
46 | # is slow and we need it for our parametric tests to work correctly. | |
39 | from . import nosepatch |
|
47 | from IPython.testing import nosepatch | |
40 | # Now, proceed to import nose itself |
|
48 | # Now, proceed to import nose itself | |
41 | import nose.plugins.builtin |
|
49 | import nose.plugins.builtin | |
42 | from nose.core import TestProgram |
|
50 | from nose.core import TestProgram | |
43 |
|
51 | |||
44 | # Our own imports |
|
52 | # Our own imports | |
|
53 | from IPython.core import release | |||
45 | from IPython.utils import genutils |
|
54 | from IPython.utils import genutils | |
46 | from IPython.utils.platutils import find_cmd, FindCmdError |
|
55 | from IPython.utils.platutils import find_cmd, FindCmdError | |
47 | from . import globalipapp |
|
56 | from IPython.testing import globalipapp | |
48 | from . import tools |
|
57 | from IPython.testing import tools | |
49 | from .plugin.ipdoctest import IPythonDoctest |
|
58 | from IPython.testing.plugin.ipdoctest import IPythonDoctest | |
50 |
|
59 | |||
51 | pjoin = path.join |
|
60 | pjoin = path.join | |
52 |
|
61 | |||
|
62 | ||||
|
63 | #----------------------------------------------------------------------------- | |||
|
64 | # Globals | |||
|
65 | #----------------------------------------------------------------------------- | |||
|
66 | ||||
|
67 | # By default, we assume IPython has been installed. But if the test suite is | |||
|
68 | # being run from a source tree that has NOT been installed yet, this flag can | |||
|
69 | # be set to False by the entry point scripts, to let us know that we must call | |||
|
70 | # the source tree versions of the scripts which manipulate sys.path instead of | |||
|
71 | # assuming that things exist system-wide. | |||
|
72 | INSTALLED = True | |||
|
73 | ||||
53 | #----------------------------------------------------------------------------- |
|
74 | #----------------------------------------------------------------------------- | |
54 | # Warnings control |
|
75 | # Warnings control | |
55 | #----------------------------------------------------------------------------- |
|
76 | #----------------------------------------------------------------------------- | |
@@ -62,6 +83,10 b" warnings.filterwarnings('ignore', 'the sets module is deprecated'," | |||||
62 | warnings.filterwarnings('ignore', 'the sha module is deprecated', |
|
83 | warnings.filterwarnings('ignore', 'the sha module is deprecated', | |
63 | DeprecationWarning) |
|
84 | DeprecationWarning) | |
64 |
|
85 | |||
|
86 | # Wx on Fedora11 spits these out | |||
|
87 | warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch', | |||
|
88 | UserWarning) | |||
|
89 | ||||
65 | #----------------------------------------------------------------------------- |
|
90 | #----------------------------------------------------------------------------- | |
66 | # Logic for skipping doctests |
|
91 | # Logic for skipping doctests | |
67 | #----------------------------------------------------------------------------- |
|
92 | #----------------------------------------------------------------------------- | |
@@ -70,22 +95,59 b' def test_for(mod):' | |||||
70 | """Test to see if mod is importable.""" |
|
95 | """Test to see if mod is importable.""" | |
71 | try: |
|
96 | try: | |
72 | __import__(mod) |
|
97 | __import__(mod) | |
73 | except ImportError: |
|
98 | except (ImportError, RuntimeError): | |
|
99 | # GTK reports Runtime error if it can't be initialized even if it's | |||
|
100 | # importable. | |||
74 | return False |
|
101 | return False | |
75 | else: |
|
102 | else: | |
76 | return True |
|
103 | return True | |
77 |
|
104 | |||
|
105 | # Global dict where we can store information on what we have and what we don't | |||
|
106 | # have available at test run time | |||
|
107 | have = {} | |||
|
108 | ||||
|
109 | have['curses'] = test_for('_curses') | |||
|
110 | have['wx'] = test_for('wx') | |||
|
111 | have['wx.aui'] = test_for('wx.aui') | |||
|
112 | have['zope.interface'] = test_for('zope.interface') | |||
|
113 | have['twisted'] = test_for('twisted') | |||
|
114 | have['foolscap'] = test_for('foolscap') | |||
|
115 | have['objc'] = test_for('objc') | |||
|
116 | have['pexpect'] = test_for('pexpect') | |||
|
117 | have['gtk'] = test_for('gtk') | |||
|
118 | have['gobject'] = test_for('gobject') | |||
|
119 | ||||
|
120 | #----------------------------------------------------------------------------- | |||
|
121 | # Functions and classes | |||
|
122 | #----------------------------------------------------------------------------- | |||
|
123 | ||||
|
124 | def report(): | |||
|
125 | """Return a string with a summary report of test-related variables.""" | |||
|
126 | ||||
|
127 | out = [ genutils.sys_info() ] | |||
|
128 | ||||
|
129 | out.append('\nRunning from an installed IPython: %s\n' % INSTALLED) | |||
|
130 | ||||
|
131 | avail = [] | |||
|
132 | not_avail = [] | |||
78 |
|
133 | |||
79 | have_curses = test_for('_curses') |
|
134 | for k, is_avail in have.items(): | |
80 | have_wx = test_for('wx') |
|
135 | if is_avail: | |
81 | have_wx_aui = test_for('wx.aui') |
|
136 | avail.append(k) | |
82 | have_zi = test_for('zope.interface') |
|
137 | else: | |
83 | have_twisted = test_for('twisted') |
|
138 | not_avail.append(k) | |
84 | have_foolscap = test_for('foolscap') |
|
139 | ||
85 | have_objc = test_for('objc') |
|
140 | if avail: | |
86 | have_pexpect = test_for('pexpect') |
|
141 | out.append('\nTools and libraries available at test time:\n') | |
87 | have_gtk = test_for('gtk') |
|
142 | avail.sort() | |
88 | have_gobject = test_for('gobject') |
|
143 | out.append(' ' + ' '.join(avail)+'\n') | |
|
144 | ||||
|
145 | if not_avail: | |||
|
146 | out.append('\nTools and libraries NOT available at test time:\n') | |||
|
147 | not_avail.sort() | |||
|
148 | out.append(' ' + ' '.join(not_avail)+'\n') | |||
|
149 | ||||
|
150 | return ''.join(out) | |||
89 |
|
151 | |||
90 |
|
152 | |||
91 | def make_exclude(): |
|
153 | def make_exclude(): | |
@@ -103,6 +165,10 b' def make_exclude():' | |||||
103 |
|
165 | |||
104 | exclusions = [ipjoin('external'), |
|
166 | exclusions = [ipjoin('external'), | |
105 | ipjoin('frontend', 'process', 'winprocess.py'), |
|
167 | ipjoin('frontend', 'process', 'winprocess.py'), | |
|
168 | # Deprecated old Shell and iplib modules, skip to avoid | |||
|
169 | # warnings | |||
|
170 | ipjoin('Shell'), | |||
|
171 | ipjoin('iplib'), | |||
106 | pjoin('IPython_doctest_plugin'), |
|
172 | pjoin('IPython_doctest_plugin'), | |
107 | ipjoin('quarantine'), |
|
173 | ipjoin('quarantine'), | |
108 | ipjoin('deathrow'), |
|
174 | ipjoin('deathrow'), | |
@@ -118,18 +184,18 b' def make_exclude():' | |||||
118 | ipjoin('config', 'profile'), |
|
184 | ipjoin('config', 'profile'), | |
119 | ] |
|
185 | ] | |
120 |
|
186 | |||
121 |
if not have |
|
187 | if not have['wx']: | |
122 | exclusions.append(ipjoin('gui')) |
|
188 | exclusions.append(ipjoin('gui')) | |
123 | exclusions.append(ipjoin('frontend', 'wx')) |
|
189 | exclusions.append(ipjoin('frontend', 'wx')) | |
124 | exclusions.append(ipjoin('lib', 'inputhookwx')) |
|
190 | exclusions.append(ipjoin('lib', 'inputhookwx')) | |
125 |
|
191 | |||
126 |
if not have |
|
192 | if not have['gtk'] or not have['gobject']: | |
127 | exclusions.append(ipjoin('lib', 'inputhookgtk')) |
|
193 | exclusions.append(ipjoin('lib', 'inputhookgtk')) | |
128 |
|
194 | |||
129 |
if not have |
|
195 | if not have['wx.aui']: | |
130 | exclusions.append(ipjoin('gui', 'wx', 'wxIPython')) |
|
196 | exclusions.append(ipjoin('gui', 'wx', 'wxIPython')) | |
131 |
|
197 | |||
132 |
if not have |
|
198 | if not have['objc']: | |
133 | exclusions.append(ipjoin('frontend', 'cocoa')) |
|
199 | exclusions.append(ipjoin('frontend', 'cocoa')) | |
134 |
|
200 | |||
135 | if not sys.platform == 'win32': |
|
201 | if not sys.platform == 'win32': | |
@@ -144,14 +210,14 b' def make_exclude():' | |||||
144 | if not os.name == 'posix': |
|
210 | if not os.name == 'posix': | |
145 | exclusions.append(ipjoin('utils', 'platutils_posix')) |
|
211 | exclusions.append(ipjoin('utils', 'platutils_posix')) | |
146 |
|
212 | |||
147 |
if not have |
|
213 | if not have['pexpect']: | |
148 | exclusions.extend([ipjoin('scripts', 'irunner'), |
|
214 | exclusions.extend([ipjoin('scripts', 'irunner'), | |
149 | ipjoin('lib', 'irunner')]) |
|
215 | ipjoin('lib', 'irunner')]) | |
150 |
|
216 | |||
151 | # This is scary. We still have things in frontend and testing that |
|
217 | # This is scary. We still have things in frontend and testing that | |
152 | # are being tested by nose that use twisted. We need to rethink |
|
218 | # are being tested by nose that use twisted. We need to rethink | |
153 | # how we are isolating dependencies in testing. |
|
219 | # how we are isolating dependencies in testing. | |
154 |
if not (have |
|
220 | if not (have['twisted'] and have['zope.interface'] and have['foolscap']): | |
155 | exclusions.extend( |
|
221 | exclusions.extend( | |
156 | [ipjoin('frontend', 'asyncfrontendbase'), |
|
222 | [ipjoin('frontend', 'asyncfrontendbase'), | |
157 | ipjoin('frontend', 'prefilterfrontend'), |
|
223 | ipjoin('frontend', 'prefilterfrontend'), | |
@@ -173,10 +239,6 b' def make_exclude():' | |||||
173 | return exclusions |
|
239 | return exclusions | |
174 |
|
240 | |||
175 |
|
241 | |||
176 | #----------------------------------------------------------------------------- |
|
|||
177 | # Functions and classes |
|
|||
178 | #----------------------------------------------------------------------------- |
|
|||
179 |
|
||||
180 | class IPTester(object): |
|
242 | class IPTester(object): | |
181 | """Call that calls iptest or trial in a subprocess. |
|
243 | """Call that calls iptest or trial in a subprocess. | |
182 | """ |
|
244 | """ | |
@@ -189,24 +251,27 b' class IPTester(object):' | |||||
189 | #: list, process ids of subprocesses we start (for cleanup) |
|
251 | #: list, process ids of subprocesses we start (for cleanup) | |
190 | pids = None |
|
252 | pids = None | |
191 |
|
253 | |||
192 | def __init__(self,runner='iptest',params=None): |
|
254 | def __init__(self, runner='iptest', params=None): | |
193 | """Create new test runner.""" |
|
255 | """Create new test runner.""" | |
|
256 | p = os.path | |||
194 | if runner == 'iptest': |
|
257 | if runner == 'iptest': | |
195 | # Find our own 'iptest' script OS-level entry point |
|
258 | if INSTALLED: | |
196 | try: |
|
259 | self.runner = tools.cmd2argv( | |
197 |
|
|
260 | p.abspath(find_cmd('iptest'))) + sys.argv[1:] | |
198 |
e |
|
261 | else: | |
199 | # Script not installed (may be the case for testing situations |
|
262 | # Find our own 'iptest' script OS-level entry point. Don't | |
200 | # that are running from a source tree only), pull from internal |
|
263 | # look system-wide, so we are sure we pick up *this one*. And | |
201 | # path: |
|
264 | # pass through to subprocess call our own sys.argv | |
202 | pak_dir = os.path.abspath(genutils.get_ipython_package_dir()) |
|
265 | ippath = p.abspath(p.join(p.dirname(__file__),'..','..')) | |
203 | iptest_path = pjoin(pak_dir, 'scripts', 'iptest') |
|
266 | script = p.join(ippath, 'iptest.py') | |
204 |
self.runner = tools.cmd2argv(ipt |
|
267 | self.runner = tools.cmd2argv(script) + sys.argv[1:] | |
|
268 | ||||
205 | else: |
|
269 | else: | |
206 | self.runner = tools.cmd2argv(os.path.abspath(find_cmd('trial'))) |
|
270 | # For trial, it needs to be installed system-wide | |
|
271 | self.runner = tools.cmd2argv(p.abspath(find_cmd('trial'))) | |||
207 | if params is None: |
|
272 | if params is None: | |
208 | params = [] |
|
273 | params = [] | |
209 | if isinstance(params,str): |
|
274 | if isinstance(params, str): | |
210 | params = [params] |
|
275 | params = [params] | |
211 | self.params = params |
|
276 | self.params = params | |
212 |
|
277 | |||
@@ -228,6 +293,7 b' class IPTester(object):' | |||||
228 | return os.system(' '.join(self.call_args)) |
|
293 | return os.system(' '.join(self.call_args)) | |
229 | else: |
|
294 | else: | |
230 | def _run_cmd(self): |
|
295 | def _run_cmd(self): | |
|
296 | #print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg | |||
231 | subp = subprocess.Popen(self.call_args) |
|
297 | subp = subprocess.Popen(self.call_args) | |
232 | self.pids.append(subp.pid) |
|
298 | self.pids.append(subp.pid) | |
233 | # If this fails, the pid will be left in self.pids and cleaned up |
|
299 | # If this fails, the pid will be left in self.pids and cleaned up | |
@@ -266,31 +332,34 b' def make_runners():' | |||||
266 | """Define the top-level packages that need to be tested. |
|
332 | """Define the top-level packages that need to be tested. | |
267 | """ |
|
333 | """ | |
268 |
|
334 | |||
269 | nose_packages = ['config', 'core', 'extensions', 'frontend', 'lib', |
|
335 | # Packages to be tested via nose, that only depend on the stdlib | |
270 | 'scripts', 'testing', 'utils', |
|
336 | nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib', | |
271 | # Note that we list the kernel here, though the bulk of it |
|
337 | 'scripts', 'testing', 'utils' ] | |
272 | # is twisted-based, because nose picks up doctests that |
|
338 | # The machinery in kernel needs twisted for real testing | |
273 | # twisted doesn't. |
|
339 | trial_pkg_names = [] | |
274 | 'kernel'] |
|
|||
275 | trial_packages = ['kernel'] |
|
|||
276 |
|
||||
277 | if have_wx: |
|
|||
278 | nose_packages.append('gui') |
|
|||
279 |
|
||||
280 | #nose_packages = ['core'] # dbg |
|
|||
281 | #trial_packages = [] # dbg |
|
|||
282 |
|
340 | |||
283 | nose_packages = ['IPython.%s' % m for m in nose_packages ] |
|
341 | if have['wx']: | |
284 | trial_packages = ['IPython.%s' % m for m in trial_packages ] |
|
342 | nose_pkg_names.append('gui') | |
285 |
|
343 | |||
286 | # Make runners, most with nose |
|
|||
287 | nose_testers = [IPTester(params=v) for v in nose_packages] |
|
|||
288 | runners = dict(zip(nose_packages, nose_testers)) |
|
|||
289 | # And add twisted ones if conditions are met |
|
344 | # And add twisted ones if conditions are met | |
290 |
if have |
|
345 | if have['zope.interface'] and have['twisted'] and have['foolscap']: | |
291 | trial_testers = [IPTester('trial',params=v) for v in trial_packages] |
|
346 | # Note that we list the kernel here, though the bulk of it is | |
292 | runners.update(dict(zip(trial_packages,trial_testers))) |
|
347 | # twisted-based, because nose picks up doctests that twisted doesn't. | |
293 |
|
348 | nose_pkg_names.append('kernel') | ||
|
349 | trial_pkg_names.append('kernel') | |||
|
350 | ||||
|
351 | # For debugging this code, only load quick stuff | |||
|
352 | #nose_pkg_names = ['core', 'extensions'] # dbg | |||
|
353 | #trial_pkg_names = [] # dbg | |||
|
354 | ||||
|
355 | # Make fully qualified package names prepending 'IPython.' to our name lists | |||
|
356 | nose_packages = ['IPython.%s' % m for m in nose_pkg_names ] | |||
|
357 | trial_packages = ['IPython.%s' % m for m in trial_pkg_names ] | |||
|
358 | ||||
|
359 | # Make runners | |||
|
360 | runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ] | |||
|
361 | runners.extend([ (v, IPTester('trial', params=v)) for v in trial_packages ]) | |||
|
362 | ||||
294 | return runners |
|
363 | return runners | |
295 |
|
364 | |||
296 |
|
365 | |||
@@ -305,15 +374,14 b' def run_iptest():' | |||||
305 | warnings.filterwarnings('ignore', |
|
374 | warnings.filterwarnings('ignore', | |
306 | 'This will be removed soon. Use IPython.testing.util instead') |
|
375 | 'This will be removed soon. Use IPython.testing.util instead') | |
307 |
|
376 | |||
308 | argv = sys.argv + [ '--detailed-errors', |
|
377 | argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks | |
|
378 | ||||
309 | # Loading ipdoctest causes problems with Twisted, but |
|
379 | # Loading ipdoctest causes problems with Twisted, but | |
310 | # our test suite runner now separates things and runs |
|
380 | # our test suite runner now separates things and runs | |
311 | # all Twisted tests with trial. |
|
381 | # all Twisted tests with trial. | |
312 | '--with-ipdoctest', |
|
382 | '--with-ipdoctest', | |
313 | '--ipdoctest-tests','--ipdoctest-extension=txt', |
|
383 | '--ipdoctest-tests','--ipdoctest-extension=txt', | |
314 |
|
384 | |||
315 | #'-x','-s', # dbg |
|
|||
316 |
|
||||
317 | # We add --exe because of setuptools' imbecility (it |
|
385 | # We add --exe because of setuptools' imbecility (it | |
318 | # blindly does chmod +x on ALL files). Nose does the |
|
386 | # blindly does chmod +x on ALL files). Nose does the | |
319 | # right thing and it tries to avoid executables, |
|
387 | # right thing and it tries to avoid executables, | |
@@ -323,21 +391,19 b' def run_iptest():' | |||||
323 | '--exe', |
|
391 | '--exe', | |
324 | ] |
|
392 | ] | |
325 |
|
393 | |||
326 | # Detect if any tests were required by explicitly calling an IPython |
|
394 | if nose.__version__ >= '0.11': | |
327 | # submodule or giving a specific path |
|
395 | # I don't fully understand why we need this one, but depending on what | |
328 | has_tests = False |
|
396 | # directory the test suite is run from, if we don't give it, 0 tests | |
329 | for arg in sys.argv: |
|
397 | # get run. Specifically, if the test suite is run from the source dir | |
330 | if 'IPython' in arg or arg.endswith('.py') or \ |
|
398 | # with an argument (like 'iptest.py IPython.core', 0 tests are run, | |
331 | (':' in arg and '.py' in arg): |
|
399 | # even if the same call done in this directory works fine). It appears | |
332 | has_tests = True |
|
400 | # that if the requested package is in the current dir, nose bails early | |
333 | break |
|
401 | # by default. Since it's otherwise harmless, leave it in by default | |
334 |
|
402 | # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it. | ||
335 | # If nothing was specifically requested, test full IPython |
|
403 | argv.append('--traverse-namespace') | |
336 | if not has_tests: |
|
404 | ||
337 | argv.append('IPython') |
|
405 | # Construct list of plugins, omitting the existing doctest plugin, which | |
338 |
|
406 | # ours replaces (and extends). | ||
339 | ## # Construct list of plugins, omitting the existing doctest plugin, which |
|
|||
340 | ## # ours replaces (and extends). |
|
|||
341 | plugins = [IPythonDoctest(make_exclude())] |
|
407 | plugins = [IPythonDoctest(make_exclude())] | |
342 | for p in nose.plugins.builtin.plugins: |
|
408 | for p in nose.plugins.builtin.plugins: | |
343 | plug = p() |
|
409 | plug = p() | |
@@ -348,7 +414,7 b' def run_iptest():' | |||||
348 | # We need a global ipython running in this process |
|
414 | # We need a global ipython running in this process | |
349 | globalipapp.start_ipython() |
|
415 | globalipapp.start_ipython() | |
350 | # Now nose can run |
|
416 | # Now nose can run | |
351 | TestProgram(argv=argv,plugins=plugins) |
|
417 | TestProgram(argv=argv, plugins=plugins) | |
352 |
|
418 | |||
353 |
|
419 | |||
354 | def run_iptestall(): |
|
420 | def run_iptestall(): | |
@@ -371,15 +437,15 b' def run_iptestall():' | |||||
371 | os.chdir(testdir) |
|
437 | os.chdir(testdir) | |
372 |
|
438 | |||
373 | # Run all test runners, tracking execution time |
|
439 | # Run all test runners, tracking execution time | |
374 |
failed = |
|
440 | failed = [] | |
375 | t_start = time.time() |
|
441 | t_start = time.time() | |
376 | try: |
|
442 | try: | |
377 |
for name,runner in runners |
|
443 | for (name, runner) in runners: | |
378 |
print '*'*7 |
|
444 | print '*'*70 | |
379 | print 'IPython test group:',name |
|
445 | print 'IPython test group:',name | |
380 | res = runner.run() |
|
446 | res = runner.run() | |
381 | if res: |
|
447 | if res: | |
382 |
failed |
|
448 | failed.append( (name, runner) ) | |
383 | finally: |
|
449 | finally: | |
384 | os.chdir(curdir) |
|
450 | os.chdir(curdir) | |
385 | t_end = time.time() |
|
451 | t_end = time.time() | |
@@ -388,17 +454,19 b' def run_iptestall():' | |||||
388 | nfail = len(failed) |
|
454 | nfail = len(failed) | |
389 | # summarize results |
|
455 | # summarize results | |
390 |
|
456 | |||
391 |
print '*'*7 |
|
457 | print '*'*70 | |
|
458 | print 'Test suite completed for system with the following information:' | |||
|
459 | print report() | |||
392 | print 'Ran %s test groups in %.3fs' % (nrunners, t_tests) |
|
460 | print 'Ran %s test groups in %.3fs' % (nrunners, t_tests) | |
393 |
|
461 | |||
|
462 | print 'Status:' | |||
394 | if not failed: |
|
463 | if not failed: | |
395 | print 'OK' |
|
464 | print 'OK' | |
396 | else: |
|
465 | else: | |
397 | # If anything went wrong, point out what command to rerun manually to |
|
466 | # If anything went wrong, point out what command to rerun manually to | |
398 | # see the actual errors and individual summary |
|
467 | # see the actual errors and individual summary | |
399 | print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners) |
|
468 | print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners) | |
400 | for name in failed: |
|
469 | for name, failed_runner in failed: | |
401 | failed_runner = runners[name] |
|
|||
402 | print '-'*40 |
|
470 | print '-'*40 | |
403 | print 'Runner failed:',name |
|
471 | print 'Runner failed:',name | |
404 | print 'You may wish to rerun this one individually, with:' |
|
472 | print 'You may wish to rerun this one individually, with:' | |
@@ -407,13 +475,13 b' def run_iptestall():' | |||||
407 |
|
475 | |||
408 |
|
476 | |||
409 | def main(): |
|
477 | def main(): | |
410 | if len(sys.argv) == 1: |
|
478 | for arg in sys.argv[1:]: | |
411 | run_iptestall() |
|
479 | if arg.startswith('IPython'): | |
412 | else: |
|
480 | # This is in-process | |
413 | if sys.argv[1] == 'all': |
|
|||
414 | run_iptestall() |
|
|||
415 | else: |
|
|||
416 | run_iptest() |
|
481 | run_iptest() | |
|
482 | else: | |||
|
483 | # This starts subprocesses | |||
|
484 | run_iptestall() | |||
417 |
|
485 | |||
418 |
|
486 | |||
419 | if __name__ == '__main__': |
|
487 | if __name__ == '__main__': |
@@ -114,11 +114,12 b' def test_skip_dt_decorator():' | |||||
114 | # Fetch the docstring from doctest_bad after decoration. |
|
114 | # Fetch the docstring from doctest_bad after decoration. | |
115 | val = doctest_bad.__doc__ |
|
115 | val = doctest_bad.__doc__ | |
116 |
|
116 | |||
117 |
assert |
|
117 | nt.assert_equal(check,val,"doctest_bad docstrings don't match") | |
|
118 | ||||
118 |
|
119 | |||
119 | # Doctest skipping should work for class methods too |
|
120 | # Doctest skipping should work for class methods too | |
120 |
class |
|
121 | class FooClass(object): | |
121 | """Foo |
|
122 | """FooClass | |
122 |
|
123 | |||
123 | Example: |
|
124 | Example: | |
124 |
|
125 | |||
@@ -128,22 +129,22 b' class foo(object):' | |||||
128 |
|
129 | |||
129 | @dec.skip_doctest |
|
130 | @dec.skip_doctest | |
130 | def __init__(self,x): |
|
131 | def __init__(self,x): | |
131 |
"""Make a |
|
132 | """Make a FooClass. | |
132 |
|
133 | |||
133 | Example: |
|
134 | Example: | |
134 |
|
135 | |||
135 |
>>> f = |
|
136 | >>> f = FooClass(3) | |
136 | junk |
|
137 | junk | |
137 | """ |
|
138 | """ | |
138 |
print 'Making a |
|
139 | print 'Making a FooClass.' | |
139 | self.x = x |
|
140 | self.x = x | |
140 |
|
141 | |||
141 | @dec.skip_doctest |
|
142 | @dec.skip_doctest | |
142 | def bar(self,y): |
|
143 | def bar(self,y): | |
143 | """Example: |
|
144 | """Example: | |
144 |
|
145 | |||
145 |
>>> f |
|
146 | >>> ff = FooClass(3) | |
146 | >>> f.bar(0) |
|
147 | >>> ff.bar(0) | |
147 | boom! |
|
148 | boom! | |
148 | >>> 1/0 |
|
149 | >>> 1/0 | |
149 | bam! |
|
150 | bam! | |
@@ -153,15 +154,14 b' class foo(object):' | |||||
153 | def baz(self,y): |
|
154 | def baz(self,y): | |
154 | """Example: |
|
155 | """Example: | |
155 |
|
156 | |||
156 |
>>> f |
|
157 | >>> ff2 = FooClass(3) | |
157 |
Making a |
|
158 | Making a FooClass. | |
158 | >>> f.baz(3) |
|
159 | >>> ff2.baz(3) | |
159 | True |
|
160 | True | |
160 | """ |
|
161 | """ | |
161 | return self.x==y |
|
162 | return self.x==y | |
162 |
|
163 | |||
163 |
|
164 | |||
164 |
|
||||
165 | def test_skip_dt_decorator2(): |
|
165 | def test_skip_dt_decorator2(): | |
166 | """Doctest-skipping decorator should preserve function signature. |
|
166 | """Doctest-skipping decorator should preserve function signature. | |
167 | """ |
|
167 | """ |
@@ -49,6 +49,13 b' from . import decorators as dec' | |||||
49 | # Globals |
|
49 | # Globals | |
50 | #----------------------------------------------------------------------------- |
|
50 | #----------------------------------------------------------------------------- | |
51 |
|
51 | |||
|
52 | # By default, we assume IPython has been installed. But if the test suite is | |||
|
53 | # being run from a source tree that has NOT been installed yet, this flag can | |||
|
54 | # be set to False by the entry point scripts, to let us know that we must call | |||
|
55 | # the source tree versions of the scripts which manipulate sys.path instead of | |||
|
56 | # assuming that things exist system-wide. | |||
|
57 | INSTALLED = True | |||
|
58 | ||||
52 | # Make a bunch of nose.tools assert wrappers that can be used in test |
|
59 | # Make a bunch of nose.tools assert wrappers that can be used in test | |
53 | # generators. This will expose an assert* function for each one in nose.tools. |
|
60 | # generators. This will expose an assert* function for each one in nose.tools. | |
54 |
|
61 | |||
@@ -209,14 +216,10 b" def temp_pyfile(src, ext='.py'):" | |||||
209 | def default_argv(): |
|
216 | def default_argv(): | |
210 | """Return a valid default argv for creating testing instances of ipython""" |
|
217 | """Return a valid default argv for creating testing instances of ipython""" | |
211 |
|
218 | |||
212 | # Get the install directory for the user configuration and tell ipython to |
|
219 | return ['--quick', # so no config file is loaded | |
213 | # use the default profile from there. |
|
220 | # Other defaults to minimize side effects on stdout | |
214 | from IPython.config import default |
|
221 | '--colors=NoColor', '--no-term-title','--no-banner', | |
215 | ipcdir = os.path.dirname(default.__file__) |
|
222 | '--autocall=0'] | |
216 | ipconf = os.path.join(ipcdir,'ipython_config.py') |
|
|||
217 | return ['--colors=NoColor', '--no-term-title','--no-banner', |
|
|||
218 | '--config-file="%s"' % ipconf, '--autocall=0', |
|
|||
219 | '--prompt-out=""'] |
|
|||
220 |
|
223 | |||
221 |
|
224 | |||
222 | def ipexec(fname, options=None): |
|
225 | def ipexec(fname, options=None): | |
@@ -240,22 +243,32 b' def ipexec(fname, options=None):' | |||||
240 | (stdout, stderr) of ipython subprocess. |
|
243 | (stdout, stderr) of ipython subprocess. | |
241 | """ |
|
244 | """ | |
242 | if options is None: options = [] |
|
245 | if options is None: options = [] | |
243 | cmdargs = ' '.join(default_argv() + options) |
|
246 | ||
|
247 | # For these subprocess calls, eliminate all prompt printing so we only see | |||
|
248 | # output from script execution | |||
|
249 | prompt_opts = ['--prompt-in1=""', '--prompt-in2=""', '--prompt-out=""'] | |||
|
250 | cmdargs = ' '.join(default_argv() + prompt_opts + options) | |||
244 |
|
251 | |||
245 | _ip = get_ipython() |
|
252 | _ip = get_ipython() | |
246 | test_dir = os.path.dirname(__file__) |
|
253 | test_dir = os.path.dirname(__file__) | |
|
254 | ||||
247 | # Find the ipython script from the package we're using, so that the test |
|
255 | # Find the ipython script from the package we're using, so that the test | |
248 | # suite can be run from the source tree without an installed IPython |
|
256 | # suite can be run from the source tree without an installed IPython | |
249 | ipython_package_dir = genutils.get_ipython_package_dir() |
|
257 | p = os.path | |
250 | ipython_script = os.path.join(ipython_package_dir,'scripts','ipython') |
|
258 | if INSTALLED: | |
251 | ipython_cmd = 'python "%s"' % ipython_script |
|
259 | ipython_cmd = platutils.find_cmd('ipython') | |
|
260 | else: | |||
|
261 | ippath = p.abspath(p.join(p.dirname(__file__),'..','..')) | |||
|
262 | ipython_script = p.join(ippath, 'ipython.py') | |||
|
263 | ipython_cmd = 'python "%s"' % ipython_script | |||
252 | # Absolute path for filename |
|
264 | # Absolute path for filename | |
253 |
full_fname = |
|
265 | full_fname = p.join(test_dir, fname) | |
254 |
full_cmd = '%s %s |
|
266 | full_cmd = '%s %s %s' % (ipython_cmd, cmdargs, full_fname) | |
|
267 | #print >> sys.stderr, 'FULL CMD:', full_cmd # dbg | |||
255 | return genutils.getoutputerror(full_cmd) |
|
268 | return genutils.getoutputerror(full_cmd) | |
256 |
|
269 | |||
257 |
|
270 | |||
258 |
def ipexec_validate(fname, expected_out, expected_err= |
|
271 | def ipexec_validate(fname, expected_out, expected_err='', | |
259 | options=None): |
|
272 | options=None): | |
260 | """Utility to call 'ipython filename' and validate output/error. |
|
273 | """Utility to call 'ipython filename' and validate output/error. | |
261 |
|
274 | |||
@@ -285,9 +298,18 b' def ipexec_validate(fname, expected_out, expected_err=None,' | |||||
285 | import nose.tools as nt |
|
298 | import nose.tools as nt | |
286 |
|
299 | |||
287 | out, err = ipexec(fname) |
|
300 | out, err = ipexec(fname) | |
|
301 | #print 'OUT', out # dbg | |||
|
302 | #print 'ERR', err # dbg | |||
|
303 | # If there are any errors, we must check those befor stdout, as they may be | |||
|
304 | # more informative than simply having an empty stdout. | |||
|
305 | if err: | |||
|
306 | if expected_err: | |||
|
307 | nt.assert_equals(err.strip(), expected_err.strip()) | |||
|
308 | else: | |||
|
309 | raise ValueError('Running file %r produced error: %r' % | |||
|
310 | (fname, err)) | |||
|
311 | # If no errors or output on stderr was expected, match stdout | |||
288 | nt.assert_equals(out.strip(), expected_out.strip()) |
|
312 | nt.assert_equals(out.strip(), expected_out.strip()) | |
289 | if expected_err: |
|
|||
290 | nt.assert_equals(err.strip(), expected_err.strip()) |
|
|||
291 |
|
313 | |||
292 |
|
314 | |||
293 | class TempFileMixin(object): |
|
315 | class TempFileMixin(object): |
@@ -11,6 +11,7 b' these things are also convenient when working at the command line.' | |||||
11 | # Distributed under the terms of the BSD License. The full license is in |
|
11 | # Distributed under the terms of the BSD License. The full license is in | |
12 | # the file COPYING, distributed as part of this software. |
|
12 | # the file COPYING, distributed as part of this software. | |
13 | #***************************************************************************** |
|
13 | #***************************************************************************** | |
|
14 | from __future__ import absolute_import | |||
14 |
|
15 | |||
15 | #**************************************************************************** |
|
16 | #**************************************************************************** | |
16 | # required modules from the Python standard library |
|
17 | # required modules from the Python standard library | |
@@ -41,11 +42,12 b' else:' | |||||
41 |
|
42 | |||
42 | # Other IPython utilities |
|
43 | # Other IPython utilities | |
43 | import IPython |
|
44 | import IPython | |
|
45 | from IPython.core import release | |||
44 | from IPython.external.Itpl import itpl,printpl |
|
46 | from IPython.external.Itpl import itpl,printpl | |
45 | from IPython.utils import platutils |
|
47 | from IPython.utils import platutils | |
46 | from IPython.utils.generics import result_display |
|
48 | from IPython.utils.generics import result_display | |
47 | from IPython.external.path import path |
|
49 | from IPython.external.path import path | |
48 |
|
50 | from .baseutils import getoutputerror | ||
49 |
|
51 | |||
50 | #**************************************************************************** |
|
52 | #**************************************************************************** | |
51 | # Exceptions |
|
53 | # Exceptions | |
@@ -194,21 +196,49 b' def warn(msg,level=2,exit_val=1):' | |||||
194 | print >> Term.cerr,'Exiting.\n' |
|
196 | print >> Term.cerr,'Exiting.\n' | |
195 | sys.exit(exit_val) |
|
197 | sys.exit(exit_val) | |
196 |
|
198 | |||
|
199 | ||||
197 | def info(msg): |
|
200 | def info(msg): | |
198 | """Equivalent to warn(msg,level=1).""" |
|
201 | """Equivalent to warn(msg,level=1).""" | |
199 |
|
202 | |||
200 | warn(msg,level=1) |
|
203 | warn(msg,level=1) | |
201 |
|
204 | |||
|
205 | ||||
202 | def error(msg): |
|
206 | def error(msg): | |
203 | """Equivalent to warn(msg,level=3).""" |
|
207 | """Equivalent to warn(msg,level=3).""" | |
204 |
|
208 | |||
205 | warn(msg,level=3) |
|
209 | warn(msg,level=3) | |
206 |
|
210 | |||
|
211 | ||||
207 | def fatal(msg,exit_val=1): |
|
212 | def fatal(msg,exit_val=1): | |
208 | """Equivalent to warn(msg,exit_val=exit_val,level=4).""" |
|
213 | """Equivalent to warn(msg,exit_val=exit_val,level=4).""" | |
209 |
|
214 | |||
210 | warn(msg,exit_val=exit_val,level=4) |
|
215 | warn(msg,exit_val=exit_val,level=4) | |
211 |
|
216 | |||
|
217 | def sys_info(): | |||
|
218 | """Return useful information about IPython and the system, as a string. | |||
|
219 | ||||
|
220 | Examples | |||
|
221 | -------- | |||
|
222 | In [1]: print(sys_info()) | |||
|
223 | IPython version: 0.11.bzr.r1340 # random | |||
|
224 | BZR revision : 1340 | |||
|
225 | Platform info : os.name -> posix, sys.platform -> linux2 | |||
|
226 | : Linux-2.6.31-17-generic-i686-with-Ubuntu-9.10-karmic | |||
|
227 | Python info : 2.6.4 (r264:75706, Dec 7 2009, 18:45:15) | |||
|
228 | [GCC 4.4.1] | |||
|
229 | """ | |||
|
230 | import platform | |||
|
231 | out = [] | |||
|
232 | out.append('IPython version: %s' % release.version) | |||
|
233 | out.append('BZR revision : %s' % release.revision) | |||
|
234 | out.append('Platform info : os.name -> %s, sys.platform -> %s' % | |||
|
235 | (os.name,sys.platform) ) | |||
|
236 | out.append(' : %s' % platform.platform()) | |||
|
237 | out.append('Python info : %s' % sys.version) | |||
|
238 | out.append('') # ensure closing newline | |||
|
239 | return '\n'.join(out) | |||
|
240 | ||||
|
241 | ||||
212 | #--------------------------------------------------------------------------- |
|
242 | #--------------------------------------------------------------------------- | |
213 | # Debugging routines |
|
243 | # Debugging routines | |
214 | # |
|
244 | # | |
@@ -282,6 +312,7 b' except ImportError:' | |||||
282 | This just returns clock() and zero.""" |
|
312 | This just returns clock() and zero.""" | |
283 | return time.clock(),0.0 |
|
313 | return time.clock(),0.0 | |
284 |
|
314 | |||
|
315 | ||||
285 | def timings_out(reps,func,*args,**kw): |
|
316 | def timings_out(reps,func,*args,**kw): | |
286 | """timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output) |
|
317 | """timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output) | |
287 |
|
318 | |||
@@ -310,6 +341,7 b' def timings_out(reps,func,*args,**kw):' | |||||
310 | av_time = tot_time / reps |
|
341 | av_time = tot_time / reps | |
311 | return tot_time,av_time,out |
|
342 | return tot_time,av_time,out | |
312 |
|
343 | |||
|
344 | ||||
313 | def timings(reps,func,*args,**kw): |
|
345 | def timings(reps,func,*args,**kw): | |
314 | """timings(reps,func,*args,**kw) -> (t_total,t_per_call) |
|
346 | """timings(reps,func,*args,**kw) -> (t_total,t_per_call) | |
315 |
|
347 | |||
@@ -319,6 +351,7 b' def timings(reps,func,*args,**kw):' | |||||
319 |
|
351 | |||
320 | return timings_out(reps,func,*args,**kw)[0:2] |
|
352 | return timings_out(reps,func,*args,**kw)[0:2] | |
321 |
|
353 | |||
|
354 | ||||
322 | def timing(func,*args,**kw): |
|
355 | def timing(func,*args,**kw): | |
323 | """timing(func,*args,**kw) -> t_total |
|
356 | """timing(func,*args,**kw) -> t_total | |
324 |
|
357 | |||
@@ -348,6 +381,7 b' def arg_split(s,posix=False):' | |||||
348 | lex.whitespace_split = True |
|
381 | lex.whitespace_split = True | |
349 | return list(lex) |
|
382 | return list(lex) | |
350 |
|
383 | |||
|
384 | ||||
351 | def system(cmd,verbose=0,debug=0,header=''): |
|
385 | def system(cmd,verbose=0,debug=0,header=''): | |
352 | """Execute a system command, return its exit status. |
|
386 | """Execute a system command, return its exit status. | |
353 |
|
387 | |||
@@ -369,6 +403,7 b" def system(cmd,verbose=0,debug=0,header=''):" | |||||
369 | if not debug: stat = os.system(cmd) |
|
403 | if not debug: stat = os.system(cmd) | |
370 | return stat |
|
404 | return stat | |
371 |
|
405 | |||
|
406 | ||||
372 | def abbrev_cwd(): |
|
407 | def abbrev_cwd(): | |
373 | """ Return abbreviated version of cwd, e.g. d:mydir """ |
|
408 | """ Return abbreviated version of cwd, e.g. d:mydir """ | |
374 | cwd = os.getcwd().replace('\\','/') |
|
409 | cwd = os.getcwd().replace('\\','/') | |
@@ -439,6 +474,7 b" if os.name in ('nt','dos'):" | |||||
439 |
|
474 | |||
440 | shell.__doc__ = shell_ori.__doc__ |
|
475 | shell.__doc__ = shell_ori.__doc__ | |
441 |
|
476 | |||
|
477 | ||||
442 | def getoutput(cmd,verbose=0,debug=0,header='',split=0): |
|
478 | def getoutput(cmd,verbose=0,debug=0,header='',split=0): | |
443 | """Dummy substitute for perl's backquotes. |
|
479 | """Dummy substitute for perl's backquotes. | |
444 |
|
480 | |||
@@ -468,45 +504,11 b" def getoutput(cmd,verbose=0,debug=0,header='',split=0):" | |||||
468 | else: |
|
504 | else: | |
469 | return output |
|
505 | return output | |
470 |
|
506 | |||
471 | def getoutputerror(cmd,verbose=0,debug=0,header='',split=0): |
|
|||
472 | """Return (standard output,standard error) of executing cmd in a shell. |
|
|||
473 |
|
||||
474 | Accepts the same arguments as system(), plus: |
|
|||
475 |
|
||||
476 | - split(0): if true, each of stdout/err is returned as a list split on |
|
|||
477 | newlines. |
|
|||
478 |
|
||||
479 | Note: a stateful version of this function is available through the |
|
|||
480 | SystemExec class.""" |
|
|||
481 |
|
||||
482 | if verbose or debug: print header+cmd |
|
|||
483 | if not cmd: |
|
|||
484 | if split: |
|
|||
485 | return [],[] |
|
|||
486 | else: |
|
|||
487 | return '','' |
|
|||
488 | if not debug: |
|
|||
489 | p = subprocess.Popen(cmd, shell=True, |
|
|||
490 | stdin=subprocess.PIPE, |
|
|||
491 | stdout=subprocess.PIPE, |
|
|||
492 | stderr=subprocess.PIPE, |
|
|||
493 | close_fds=True) |
|
|||
494 | pin, pout, perr = (p.stdin, p.stdout, p.stderr) |
|
|||
495 |
|
||||
496 | tout = pout.read().rstrip() |
|
|||
497 | terr = perr.read().rstrip() |
|
|||
498 | pin.close() |
|
|||
499 | pout.close() |
|
|||
500 | perr.close() |
|
|||
501 | if split: |
|
|||
502 | return tout.split('\n'),terr.split('\n') |
|
|||
503 | else: |
|
|||
504 | return tout,terr |
|
|||
505 |
|
||||
506 | # for compatibility with older naming conventions |
|
507 | # for compatibility with older naming conventions | |
507 | xsys = system |
|
508 | xsys = system | |
508 | bq = getoutput |
|
509 | bq = getoutput | |
509 |
|
510 | |||
|
511 | ||||
510 | class SystemExec: |
|
512 | class SystemExec: | |
511 | """Access the system and getoutput functions through a stateful interface. |
|
513 | """Access the system and getoutput functions through a stateful interface. | |
512 |
|
514 | |||
@@ -635,9 +637,9 b' def filefind(filename, path_dirs=None):' | |||||
635 | testname = expand_path(os.path.join(path, filename)) |
|
637 | testname = expand_path(os.path.join(path, filename)) | |
636 | if os.path.isfile(testname): |
|
638 | if os.path.isfile(testname): | |
637 | return os.path.abspath(testname) |
|
639 | return os.path.abspath(testname) | |
638 | raise IOError("File does not exist in any " |
|
640 | ||
639 |
|
|
641 | raise IOError("File %r does not exist in any of the search paths: %r" % | |
640 | (filename, path_dirs)) |
|
642 | (filename, path_dirs) ) | |
641 |
|
643 | |||
642 |
|
644 | |||
643 | #---------------------------------------------------------------------------- |
|
645 | #---------------------------------------------------------------------------- |
@@ -11,12 +11,25 b' to use these functions in platform agnostic fashion.' | |||||
11 | # Distributed under the terms of the BSD License. The full license is in |
|
11 | # Distributed under the terms of the BSD License. The full license is in | |
12 | # the file COPYING, distributed as part of this software. |
|
12 | # the file COPYING, distributed as part of this software. | |
13 | #***************************************************************************** |
|
13 | #***************************************************************************** | |
|
14 | #----------------------------------------------------------------------------- | |||
|
15 | # Imports | |||
|
16 | #----------------------------------------------------------------------------- | |||
|
17 | from __future__ import absolute_import | |||
14 |
|
18 | |||
15 | import sys |
|
19 | import sys | |
16 | import os |
|
20 | import os | |
17 |
|
21 | |||
|
22 | from .baseutils import getoutputerror | |||
|
23 | ||||
|
24 | #----------------------------------------------------------------------------- | |||
|
25 | # Globals | |||
|
26 | #----------------------------------------------------------------------------- | |||
|
27 | ||||
18 | ignore_termtitle = True |
|
28 | ignore_termtitle = True | |
19 |
|
29 | |||
|
30 | #----------------------------------------------------------------------------- | |||
|
31 | # Functions | |||
|
32 | #----------------------------------------------------------------------------- | |||
20 |
|
33 | |||
21 | def _dummy_op(*a, **b): |
|
34 | def _dummy_op(*a, **b): | |
22 | """ A no-op function """ |
|
35 | """ A no-op function """ | |
@@ -36,7 +49,7 b' else:' | |||||
36 |
|
49 | |||
37 | def find_cmd(cmd): |
|
50 | def find_cmd(cmd): | |
38 | """Find the full path to a command using which.""" |
|
51 | """Find the full path to a command using which.""" | |
39 | return os.popen('which %s' % cmd).read().strip() |
|
52 | return getoutputerror('/usr/bin/env which %s' % cmd)[0] | |
40 |
|
53 | |||
41 |
|
54 | |||
42 | def get_long_path_name(path): |
|
55 | def get_long_path_name(path): |
@@ -1,4 +1,3 b'' | |||||
1 | #!/usr/bin/env python |
|
|||
2 |
|
|
1 | # encoding: utf-8 | |
3 |
|
2 | |||
4 | def test_import_coloransi(): |
|
3 | def test_import_coloransi(): |
@@ -1,4 +1,5 b'' | |||||
1 | include ipython.py |
|
1 | include ipython.py | |
|
2 | include iptest.py | |||
2 | include setupbase.py |
|
3 | include setupbase.py | |
3 | include setupegg.py |
|
4 | include setupegg.py | |
4 |
|
5 |
@@ -5,7 +5,25 b' IPython README' | |||||
5 | Overview |
|
5 | Overview | |
6 | ======== |
|
6 | ======== | |
7 |
|
7 | |||
8 |
Welcome to IPython. Our documentation can be found in the |
|
8 | Welcome to IPython. Our full documentation can be found in the ``docs/dist`` | |
9 |
subdirectory |
|
9 | subdirectory in ``.html`` and ``.pdf`` formats, also available online at our | |
10 | documentation available on the IPython `website <http://ipython.scipy.org>`_. |
|
10 | `website <http://ipython.scipy.org>`_. The ``docs/source`` directory contains | |
|
11 | the plaintext version of these manuals. | |||
11 |
|
12 | |||
|
13 | ||||
|
14 | Instant running and testing | |||
|
15 | =========================== | |||
|
16 | ||||
|
17 | You can run IPython from this directory without even installing it system-wide | |||
|
18 | by typing at the terminal: | |||
|
19 | ||||
|
20 | .. code-block:: bash | |||
|
21 | ||||
|
22 | python ipython.py | |||
|
23 | ||||
|
24 | and similarly, you can execute the built-in test suite with: | |||
|
25 | ||||
|
26 | .. code-block:: bash | |||
|
27 | ||||
|
28 | python iptest.py | |||
|
29 | No newline at end of file |
@@ -42,7 +42,25 b' manages the Twisted reactor correctly.' | |||||
42 | For the impatient: running the tests |
|
42 | For the impatient: running the tests | |
43 | ==================================== |
|
43 | ==================================== | |
44 |
|
44 | |||
45 | The simplest way to test IPython is to type at the command line: |
|
45 | You can run IPython from the source download directory without even installing | |
|
46 | it system-wide or having configure anything, by typing at the terminal: | |||
|
47 | ||||
|
48 | .. code-block:: bash | |||
|
49 | ||||
|
50 | python ipython.py | |||
|
51 | ||||
|
52 | and similarly, you can execute the built-in test suite with: | |||
|
53 | ||||
|
54 | .. code-block:: bash | |||
|
55 | ||||
|
56 | python iptest.py | |||
|
57 | ||||
|
58 | ||||
|
59 | This script manages intelligently both nose and trial, choosing the correct | |||
|
60 | test system for each of IPython's components. | |||
|
61 | ||||
|
62 | Once you have either installed it or at least configured your system to be | |||
|
63 | able to import IPython, you can run the tests with: | |||
46 |
|
64 | |||
47 | .. code-block:: bash |
|
65 | .. code-block:: bash | |
48 |
|
66 | |||
@@ -50,57 +68,72 b' The simplest way to test IPython is to type at the command line:' | |||||
50 |
|
68 | |||
51 | This should work as long as IPython can be imported, even if you haven't fully |
|
69 | This should work as long as IPython can be imported, even if you haven't fully | |
52 | installed the user-facing scripts yet (common in a development environment). |
|
70 | installed the user-facing scripts yet (common in a development environment). | |
53 | After a lot of output, you should see something like: |
|
71 | Once you have installed IPython, you will have available system-wide a script | |
|
72 | called :file:`iptest` that does the exact same as the :file:`iptest.py` script | |||
|
73 | in the source directory, so you can then test simply with: | |||
54 |
|
74 | |||
55 | .. code-block:: bash |
|
75 | .. code-block:: bash | |
56 |
|
||||
57 | ************************************************************************ |
|
|||
58 | Ran 10 test groups in 35.228s |
|
|||
59 |
|
76 | |||
60 | OK |
|
77 | iptest [args] | |
61 |
|
78 | |||
62 | If not, there will be a message indicating which test group failed and how to |
|
|||
63 | rerun that group individually. |
|
|||
64 |
|
79 | |||
65 | But IPython ships with an entry point script called :file:`iptest` that offers |
|
80 | Regardless of how you run things, you should eventually see something like: | |
66 | fine-grain control over the test process and is particularly useful for |
|
|||
67 | developers; this script also manages intelligently both nose and trial, |
|
|||
68 | choosing the correct test system for each of IPython's components. Running |
|
|||
69 | :file:`iptest` without arguments gives output identical to that above, but with |
|
|||
70 | it, you can also run specific tests with fine control. The :file:`iptest` |
|
|||
71 | script is installed with IPython, but if you are running from a source tree, |
|
|||
72 | you can find it in the :file:`IPython/scripts` directory and you can run |
|
|||
73 | directly from there. |
|
|||
74 |
|
81 | |||
75 | For example, this tests the :mod:`IPython.utils` subpackage, the :option:`-v` |
|
82 | .. code-block:: bash | |
76 | option shows progress indicators: |
|
83 | ||
|
84 | ********************************************************************** | |||
|
85 | Test suite completed for system with the following information: | |||
|
86 | IPython version: 0.11.bzr.r1340 | |||
|
87 | BZR revision : 1340 | |||
|
88 | Platform info : os.name -> posix, sys.platform -> linux2 | |||
|
89 | : Linux-2.6.31-17-generic-i686-with-Ubuntu-9.10-karmic | |||
|
90 | Python info : 2.6.4 (r264:75706, Dec 7 2009, 18:45:15) | |||
|
91 | [GCC 4.4.1] | |||
|
92 | ||||
|
93 | Running from an installed IPython: True | |||
|
94 | ||||
|
95 | Tools and libraries available at test time: | |||
|
96 | curses foolscap gobject gtk pexpect twisted wx wx.aui zope.interface | |||
|
97 | ||||
|
98 | Tools and libraries NOT available at test time: | |||
|
99 | objc | |||
|
100 | ||||
|
101 | Ran 11 test groups in 36.244s | |||
|
102 | ||||
|
103 | Status: | |||
|
104 | OK | |||
|
105 | ||||
|
106 | If not, there will be a message indicating which test group failed and how to | |||
|
107 | rerun that group individually. For example, this tests the | |||
|
108 | :mod:`IPython.utils` subpackage, the :option:`-v` option shows progress | |||
|
109 | indicators: | |||
77 |
|
110 | |||
78 | .. code-block:: bash |
|
111 | .. code-block:: bash | |
79 |
|
112 | |||
80 | maqroll[ipython]> cd IPython/scripts/ |
|
113 | $ python iptest.py -v IPython.utils | |
81 | maqroll[scripts]> ./iptest -v IPython.utils |
|
114 | ..........................SS..SSS............................S.S... | |
82 |
|
|
115 | ......................................................... | |
83 | ................................................... |
|
116 | ---------------------------------------------------------------------- | |
84 | ---------------------------------------------------------------------- |
|
117 | Ran 125 tests in 0.119s | |
85 | Ran 125 tests in 0.070s |
|
118 | ||
|
119 | OK (SKIP=7) | |||
86 |
|
120 | |||
87 | OK (SKIP=7) |
|
|||
88 |
|
121 | |||
89 |
Because |
|
122 | Because the IPython test machinery is based on nose, you can use all nose | |
90 |
syntax, typing ``iptest -h`` shows all available options. For |
|
123 | options and syntax, typing ``iptest -h`` shows all available options. For | |
91 | lets you run the specific test :func:`test_rehashx` inside the |
|
124 | example, this lets you run the specific test :func:`test_rehashx` inside the | |
92 | :mod:`test_magic` module: |
|
125 | :mod:`test_magic` module: | |
93 |
|
126 | |||
94 | .. code-block:: bash |
|
127 | .. code-block:: bash | |
95 |
|
128 | |||
96 |
|
|
129 | $ python iptest.py -vv IPython.core.tests.test_magic:test_rehashx | |
97 |
|
|
130 | IPython.core.tests.test_magic.test_rehashx(True,) ... ok | |
98 |
|
|
131 | IPython.core.tests.test_magic.test_rehashx(True,) ... ok | |
99 |
|
132 | |||
100 |
|
|
133 | ---------------------------------------------------------------------- | |
101 |
|
|
134 | Ran 2 tests in 0.100s | |
102 |
|
135 | |||
103 |
|
|
136 | OK | |
104 |
|
137 | |||
105 | When developing, the :option:`--pdb` and :option:`--pdb-failures` of nose are |
|
138 | When developing, the :option:`--pdb` and :option:`--pdb-failures` of nose are | |
106 | particularly useful, these drop you into an interactive pdb session at the |
|
139 | particularly useful, these drop you into an interactive pdb session at the |
@@ -7,6 +7,10 b" in './scripts' directory. This file is here (ipython source root directory)" | |||||
7 | to facilitate non-root 'zero-installation' (just copy the source tree |
|
7 | to facilitate non-root 'zero-installation' (just copy the source tree | |
8 | somewhere and run ipython.py) and development. """ |
|
8 | somewhere and run ipython.py) and development. """ | |
9 |
|
9 | |||
10 | from IPython.core.ipapp import launch_new_instance |
|
10 | # Ensure that the imported IPython is the local one, not a system-wide one | |
|
11 | import os, sys | |||
|
12 | this_dir = os.path.dirname(os.path.abspath(__file__)) | |||
|
13 | sys.path.insert(0, this_dir) | |||
11 |
|
14 | |||
12 | launch_new_instance() |
|
15 | # Now proceed with execution | |
|
16 | execfile(os.path.join(this_dir, 'IPython', 'scripts', 'ipython')) |
@@ -13,6 +13,23 b' requires utilities which are not available under Windows."""' | |||||
13 | # the file COPYING, distributed as part of this software. |
|
13 | # the file COPYING, distributed as part of this software. | |
14 | #------------------------------------------------------------------------------- |
|
14 | #------------------------------------------------------------------------------- | |
15 |
|
15 | |||
|
16 | #----------------------------------------------------------------------------- | |||
|
17 | # Minimal Python version sanity check | |||
|
18 | #----------------------------------------------------------------------------- | |||
|
19 | ||||
|
20 | import sys | |||
|
21 | ||||
|
22 | # This check is also made in IPython/__init__, don't forget to update both when | |||
|
23 | # changing Python version requirements. | |||
|
24 | if sys.version[0:3] < '2.5': | |||
|
25 | error = """\ | |||
|
26 | ERROR: 'IPython requires Python Version 2.5 or above.' | |||
|
27 | Exiting.""" | |||
|
28 | print >> sys.stderr, error | |||
|
29 | sys.exit(1) | |||
|
30 | ||||
|
31 | # At least we're on Python 2.5 or newer, move on. | |||
|
32 | ||||
16 | #------------------------------------------------------------------------------- |
|
33 | #------------------------------------------------------------------------------- | |
17 | # Imports |
|
34 | # Imports | |
18 | #------------------------------------------------------------------------------- |
|
35 | #------------------------------------------------------------------------------- | |
@@ -20,7 +37,6 b' requires utilities which are not available under Windows."""' | |||||
20 | # Stdlib imports |
|
37 | # Stdlib imports | |
21 | import os |
|
38 | import os | |
22 | import shutil |
|
39 | import shutil | |
23 | import sys |
|
|||
24 |
|
40 | |||
25 | from glob import glob |
|
41 | from glob import glob | |
26 |
|
42 | |||
@@ -30,6 +46,7 b" if os.path.exists('MANIFEST'): os.remove('MANIFEST')" | |||||
30 |
|
46 | |||
31 | from distutils.core import setup |
|
47 | from distutils.core import setup | |
32 |
|
48 | |||
|
49 | # Our own imports | |||
33 | from IPython.utils.genutils import target_update |
|
50 | from IPython.utils.genutils import target_update | |
34 |
|
51 | |||
35 | from setupbase import ( |
|
52 | from setupbase import ( |
General Comments 0
You need to be logged in to leave comments.
Login now