##// END OF EJS Templates
Merge pull request #3066 from tkf/run-module...
Bradley M. Froehle -
r10554:9087bb96 merge
parent child Browse files
Show More
@@ -77,8 +77,7 b' python-profiler package from non-free.""")'
77
77
78 @skip_doctest
78 @skip_doctest
79 @line_cell_magic
79 @line_cell_magic
80 def prun(self, parameter_s='', cell=None, user_mode=True,
80 def prun(self, parameter_s='', cell=None):
81 opts=None,arg_lst=None,prog_ns=None):
82
81
83 """Run a statement through the python code profiler.
82 """Run a statement through the python code profiler.
84
83
@@ -178,38 +177,33 b' python-profiler package from non-free.""")'
178
177
179 In [1]: import profile; profile.help()
178 In [1]: import profile; profile.help()
180 """
179 """
180 opts, arg_str = self.parse_options(parameter_s, 'D:l:rs:T:q',
181 list_all=True, posix=False)
182 if cell is not None:
183 arg_str += '\n' + cell
184 return self._run_with_profiler(arg_str, opts, self.shell.user_ns)
181
185
182 opts_def = Struct(D=[''],l=[],s=['time'],T=[''])
186 def _run_with_profiler(self, code, opts, namespace):
187 """
188 Run `code` with profiler. Used by ``%prun`` and ``%run -p``.
183
189
184 if user_mode: # regular user call
190 Parameters
185 opts,arg_str = self.parse_options(parameter_s,'D:l:rs:T:q',
191 ----------
186 list_all=True, posix=False)
192 code : str
187 namespace = self.shell.user_ns
193 Code to be executed.
188 if cell is not None:
194 opts : Struct
189 arg_str += '\n' + cell
195 Options parsed by `self.parse_options`.
190 else: # called to run a program by %run -p
196 namespace : dict
191 try:
197 A dictionary for Python namespace (e.g., `self.shell.user_ns`).
192 filename = get_py_filename(arg_lst[0])
193 except IOError as e:
194 try:
195 msg = str(e)
196 except UnicodeError:
197 msg = e.message
198 error(msg)
199 return
200
198
201 arg_str = 'execfile(filename,prog_ns)'
199 """
202 namespace = {
203 'execfile': self.shell.safe_execfile,
204 'prog_ns': prog_ns,
205 'filename': filename
206 }
207
200
208 opts.merge(opts_def)
201 # Fill default values for unspecified options:
202 opts.merge(Struct(D=[''], l=[], s=['time'], T=['']))
209
203
210 prof = profile.Profile()
204 prof = profile.Profile()
211 try:
205 try:
212 prof = prof.runctx(arg_str,namespace,namespace)
206 prof = prof.runctx(code, namespace, namespace)
213 sys_exit = ''
207 sys_exit = ''
214 except SystemExit:
208 except SystemExit:
215 sys_exit = """*** SystemExit exception caught in code being profiled."""
209 sys_exit = """*** SystemExit exception caught in code being profiled."""
@@ -327,8 +321,10 b' python-profiler package from non-free.""")'
327 file_finder=get_py_filename):
321 file_finder=get_py_filename):
328 """Run the named file inside IPython as a program.
322 """Run the named file inside IPython as a program.
329
323
330 Usage:\\
324 Usage:
331 %run [-n -i -t [-N<N>] -d [-b<N>] -p [profile options] -G] file [args]
325 %run [-n -i -e -G]
326 [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
327 ( -m mod | file ) [args]
332
328
333 Parameters after the filename are passed as command-line arguments to
329 Parameters after the filename are passed as command-line arguments to
334 the program (put in sys.argv). Then, control returns to IPython's
330 the program (put in sys.argv). Then, control returns to IPython's
@@ -541,62 +537,45 b' python-profiler package from non-free.""")'
541 # every single object ever created.
537 # every single object ever created.
542 sys.modules[main_mod_name] = main_mod
538 sys.modules[main_mod_name] = main_mod
543
539
540 if 'p' in opts or 'd' in opts:
541 if 'm' in opts:
542 code = 'run_module(modulename, prog_ns)'
543 code_ns = {
544 'run_module': self.shell.safe_run_module,
545 'prog_ns': prog_ns,
546 'modulename': modulename,
547 }
548 else:
549 code = 'execfile(filename, prog_ns)'
550 code_ns = {
551 'execfile': self.shell.safe_execfile,
552 'prog_ns': prog_ns,
553 'filename': get_py_filename(filename),
554 }
555
544 try:
556 try:
545 stats = None
557 stats = None
546 with self.shell.readline_no_record:
558 with self.shell.readline_no_record:
547 if 'p' in opts:
559 if 'p' in opts:
548 stats = self.prun('', None, False, opts, arg_lst, prog_ns)
560 stats = self._run_with_profiler(code, opts, code_ns)
549 else:
561 else:
550 if 'd' in opts:
562 if 'd' in opts:
551 deb = debugger.Pdb(self.shell.colors)
563 self._run_with_debugger(
552 # reset Breakpoint state, which is moronically kept
564 code, code_ns, opts.get('b', ['1'])[0], filename)
553 # in a class
554 bdb.Breakpoint.next = 1
555 bdb.Breakpoint.bplist = {}
556 bdb.Breakpoint.bpbynumber = [None]
557 # Set an initial breakpoint to stop execution
558 maxtries = 10
559 bp_file, bp_line = parse_breakpoint(opts.get('b', ['1'])[0], filename)
560 checkline = deb.checkline(bp_file, bp_line)
561 if not checkline:
562 for bp in range(bp_line + 1, bp_line + maxtries + 1):
563 if deb.checkline(bp_file, bp):
564 break
565 else:
566 msg = ("\nI failed to find a valid line to set "
567 "a breakpoint\n"
568 "after trying up to line: %s.\n"
569 "Please set a valid breakpoint manually "
570 "with the -b option." % bp)
571 error(msg)
572 return
573 # if we find a good linenumber, set the breakpoint
574 deb.do_break('%s:%s' % (bp_file, bp_line))
575
576 # Mimic Pdb._runscript(...)
577 deb._wait_for_mainpyfile = True
578 deb.mainpyfile = deb.canonic(filename)
579
580 # Start file run
581 print "NOTE: Enter 'c' at the",
582 print "%s prompt to start your script." % deb.prompt
583 ns = {'execfile': py3compat.execfile, 'prog_ns': prog_ns}
584 try:
585 #save filename so it can be used by methods on the deb object
586 deb._exec_filename = filename
587 deb.run('execfile("%s", prog_ns)' % filename, ns)
588
589 except:
590 etype, value, tb = sys.exc_info()
591 # Skip three frames in the traceback: the %run one,
592 # one inside bdb.py, and the command-line typed by the
593 # user (run by exec in pdb itself).
594 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
595 else:
565 else:
596 if runner is None:
566 if 'm' in opts:
597 runner = self.default_runner
567 def run():
598 if runner is None:
568 self.shell.safe_run_module(modulename, prog_ns)
599 runner = self.shell.safe_execfile
569 else:
570 if runner is None:
571 runner = self.default_runner
572 if runner is None:
573 runner = self.shell.safe_execfile
574
575 def run():
576 runner(filename, prog_ns, prog_ns,
577 exit_ignore=exit_ignore)
578
600 if 't' in opts:
579 if 't' in opts:
601 # timed execution
580 # timed execution
602 try:
581 try:
@@ -606,37 +585,10 b' python-profiler package from non-free.""")'
606 return
585 return
607 except (KeyError):
586 except (KeyError):
608 nruns = 1
587 nruns = 1
609 twall0 = time.time()
588 self._run_with_timing(run, nruns)
610 if nruns == 1:
611 t0 = clock2()
612 runner(filename, prog_ns, prog_ns,
613 exit_ignore=exit_ignore)
614 t1 = clock2()
615 t_usr = t1[0] - t0[0]
616 t_sys = t1[1] - t0[1]
617 print "\nIPython CPU timings (estimated):"
618 print " User : %10.2f s." % t_usr
619 print " System : %10.2f s." % t_sys
620 else:
621 runs = range(nruns)
622 t0 = clock2()
623 for nr in runs:
624 runner(filename, prog_ns, prog_ns,
625 exit_ignore=exit_ignore)
626 t1 = clock2()
627 t_usr = t1[0] - t0[0]
628 t_sys = t1[1] - t0[1]
629 print "\nIPython CPU timings (estimated):"
630 print "Total runs performed:", nruns
631 print " Times : %10s %10s" % ('Total', 'Per run')
632 print " User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns)
633 print " System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns)
634 twall1 = time.time()
635 print "Wall time: %10.2f s." % (twall1 - twall0)
636
637 else:
589 else:
638 # regular execution
590 # regular execution
639 runner(filename, prog_ns, prog_ns, exit_ignore=exit_ignore)
591 run()
640
592
641 if 'i' in opts:
593 if 'i' in opts:
642 self.shell.user_ns['__name__'] = __name__save
594 self.shell.user_ns['__name__'] = __name__save
@@ -676,7 +628,114 b' python-profiler package from non-free.""")'
676 del sys.modules[main_mod_name]
628 del sys.modules[main_mod_name]
677
629
678 return stats
630 return stats
679
631
632 def _run_with_debugger(self, code, code_ns, break_point, filename):
633 """
634 Run `code` in debugger with a break point.
635
636 Parameters
637 ----------
638 code : str
639 Code to execute.
640 code_ns : dict
641 A namespace in which `code` is executed.
642 break_point : str
643 Line number in the file specified by `filename` argument
644 or a string in the format ``file:line``. In the latter
645 case, `filename` is ignored.
646 See also :func:`.parse_breakpoint`.
647 filename : str
648 Path to the file in which break point is specified.
649
650 Raises
651 ------
652 UsageError
653 If no meaningful break point is given by `break_point` and
654 `filename`.
655
656 """
657 deb = debugger.Pdb(self.shell.colors)
658 # reset Breakpoint state, which is moronically kept
659 # in a class
660 bdb.Breakpoint.next = 1
661 bdb.Breakpoint.bplist = {}
662 bdb.Breakpoint.bpbynumber = [None]
663 # Set an initial breakpoint to stop execution
664 maxtries = 10
665 bp_file, bp_line = parse_breakpoint(break_point, filename)
666 checkline = deb.checkline(bp_file, bp_line)
667 if not checkline:
668 for bp in range(bp_line + 1, bp_line + maxtries + 1):
669 if deb.checkline(bp_file, bp):
670 break
671 else:
672 msg = ("\nI failed to find a valid line to set "
673 "a breakpoint\n"
674 "after trying up to line: %s.\n"
675 "Please set a valid breakpoint manually "
676 "with the -b option." % bp)
677 raise UsageError(msg)
678 # if we find a good linenumber, set the breakpoint
679 deb.do_break('%s:%s' % (bp_file, bp_line))
680
681 # Mimic Pdb._runscript(...)
682 deb._wait_for_mainpyfile = True
683 deb.mainpyfile = deb.canonic(filename)
684
685 # Start file run
686 print "NOTE: Enter 'c' at the",
687 print "%s prompt to start your script." % deb.prompt
688 try:
689 #save filename so it can be used by methods on the deb object
690 deb._exec_filename = filename
691 deb.run(code, code_ns)
692
693 except:
694 etype, value, tb = sys.exc_info()
695 # Skip three frames in the traceback: the %run one,
696 # one inside bdb.py, and the command-line typed by the
697 # user (run by exec in pdb itself).
698 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
699
700 @staticmethod
701 def _run_with_timing(run, nruns):
702 """
703 Run function `run` and print timing information.
704
705 Parameters
706 ----------
707 run : callable
708 Any callable object which takes no argument.
709 nruns : int
710 Number of times to execute `run`.
711
712 """
713 twall0 = time.time()
714 if nruns == 1:
715 t0 = clock2()
716 run()
717 t1 = clock2()
718 t_usr = t1[0] - t0[0]
719 t_sys = t1[1] - t0[1]
720 print "\nIPython CPU timings (estimated):"
721 print " User : %10.2f s." % t_usr
722 print " System : %10.2f s." % t_sys
723 else:
724 runs = range(nruns)
725 t0 = clock2()
726 for nr in runs:
727 run()
728 t1 = clock2()
729 t_usr = t1[0] - t0[0]
730 t_sys = t1[1] - t0[1]
731 print "\nIPython CPU timings (estimated):"
732 print "Total runs performed:", nruns
733 print " Times : %10s %10s" % ('Total', 'Per run')
734 print " User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns)
735 print " System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns)
736 twall1 = time.time()
737 print "Wall time: %10.2f s." % (twall1 - twall0)
738
680 @skip_doctest
739 @skip_doctest
681 @line_cell_magic
740 @line_cell_magic
682 def timeit(self, line='', cell=None):
741 def timeit(self, line='', cell=None):
@@ -13,9 +13,13 b' from __future__ import absolute_import'
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 import functools
16 import os
17 import os
18 import random
17 import sys
19 import sys
18 import tempfile
20 import tempfile
21 import textwrap
22 import unittest
19
23
20 import nose.tools as nt
24 import nose.tools as nt
21 from nose import SkipTest
25 from nose import SkipTest
@@ -23,6 +27,8 b' from nose import SkipTest'
23 from IPython.testing import decorators as dec
27 from IPython.testing import decorators as dec
24 from IPython.testing import tools as tt
28 from IPython.testing import tools as tt
25 from IPython.utils import py3compat
29 from IPython.utils import py3compat
30 from IPython.utils.tempdir import TemporaryDirectory
31 from IPython.core import debugger
26
32
27 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
28 # Test functions begin
34 # Test functions begin
@@ -337,3 +343,74 b' tclass.py: deleting object: C-third'
337 self.mktmp(src)
343 self.mktmp(src)
338 _ip.magic('run -t -N 1 %s' % self.fname)
344 _ip.magic('run -t -N 1 %s' % self.fname)
339 _ip.magic('run -t -N 10 %s' % self.fname)
345 _ip.magic('run -t -N 10 %s' % self.fname)
346
347
348 class TestMagicRunWithPackage(unittest.TestCase):
349
350 def writefile(self, name, content):
351 path = os.path.join(self.tempdir.name, name)
352 d = os.path.dirname(path)
353 if not os.path.isdir(d):
354 os.makedirs(d)
355 with open(path, 'w') as f:
356 f.write(textwrap.dedent(content))
357
358 def setUp(self):
359 self.package = package = 'tmp{0}'.format(repr(random.random())[2:])
360 """Temporary valid python package name."""
361
362 self.value = int(random.random() * 10000)
363
364 self.tempdir = TemporaryDirectory()
365 self.__orig_cwd = os.getcwdu()
366 sys.path.insert(0, self.tempdir.name)
367
368 self.writefile(os.path.join(package, '__init__.py'), '')
369 self.writefile(os.path.join(package, 'sub.py'), """
370 x = {0!r}
371 """.format(self.value))
372 self.writefile(os.path.join(package, 'relative.py'), """
373 from .sub import x
374 """)
375 self.writefile(os.path.join(package, 'absolute.py'), """
376 from {0}.sub import x
377 """.format(package))
378
379 def tearDown(self):
380 os.chdir(self.__orig_cwd)
381 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
382 self.tempdir.cleanup()
383
384 def check_run_submodule(self, submodule, opts=''):
385 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
386 self.assertEqual(_ip.user_ns['x'], self.value,
387 'Variable `x` is not loaded from module `{0}`.'
388 .format(submodule))
389
390 def test_run_submodule_with_absolute_import(self):
391 self.check_run_submodule('absolute')
392
393 def test_run_submodule_with_relative_import(self):
394 """Run submodule that has a relative import statement (#2727)."""
395 self.check_run_submodule('relative')
396
397 def test_prun_submodule_with_absolute_import(self):
398 self.check_run_submodule('absolute', '-p')
399
400 def test_prun_submodule_with_relative_import(self):
401 self.check_run_submodule('relative', '-p')
402
403 def with_fake_debugger(func):
404 @functools.wraps(func)
405 def wrapper(*args, **kwds):
406 with tt.monkeypatch(debugger.Pdb, 'run', staticmethod(eval)):
407 return func(*args, **kwds)
408 return wrapper
409
410 @with_fake_debugger
411 def test_debug_run_submodule_with_absolute_import(self):
412 self.check_run_submodule('absolute', '-d')
413
414 @with_fake_debugger
415 def test_debug_run_submodule_with_relative_import(self):
416 self.check_run_submodule('relative', '-d')
General Comments 0
You need to be logged in to leave comments. Login now