1010 from cStringIO import StringIO
1111except ImportError :
1212 from io import StringIO
13-
1413import inspect
1514import linecache
1615import optparse
@@ -50,6 +49,7 @@ def is_generator(f):
5049 isgen = (f .__code__ .co_flags & CO_GENERATOR ) != 0
5150 return isgen
5251
52+
5353class LineProfiler (CLineProfiler ):
5454 """ A profiler that records the execution times of individual lines.
5555 """
@@ -111,11 +111,11 @@ def dump_stats(self, filename):
111111 with open (filename , 'wb' ) as f :
112112 pickle .dump (lstats , f , pickle .HIGHEST_PROTOCOL )
113113
114- def print_stats (self , stream = None ):
114+ def print_stats (self , stream = None , stripzeros = False ):
115115 """ Show the gathered statistics.
116116 """
117117 lstats = self .get_stats ()
118- show_text (lstats .timings , lstats .unit , stream = stream )
118+ show_text (lstats .timings , lstats .unit , stream = stream , stripzeros = stripzeros )
119119
120120 def run (self , cmd ):
121121 """ Profile a single executable statment in the main namespace.
@@ -143,24 +143,46 @@ def runcall(self, func, *args, **kw):
143143 finally :
144144 self .disable_by_count ()
145145
146+ def add_module (self , mod ):
147+ """ Add all the functions in a module and its classes.
148+ """
149+ from inspect import isclass , isfunction
150+
151+ nfuncsadded = 0
152+ for item in mod .__dict__ .values ():
153+ if isclass (item ):
154+ for k , v in item .__dict__ .items ():
155+ if isfunction (v ):
156+ self .add_function (v )
157+ nfuncsadded += 1
158+ elif isfunction (item ):
159+ self .add_function (item )
160+ nfuncsadded += 1
146161
147- def show_func (filename , start_lineno , func_name , timings , unit , stream = None ):
162+ return nfuncsadded
163+
164+
165+ def show_func (filename , start_lineno , func_name , timings , unit , stream = None , stripzeros = False ):
148166 """ Show results for a single function.
149167 """
150168 if stream is None :
151169 stream = sys .stdout
152170
153- stream .write ("File: %s\n " % filename )
154- stream .write ("Function: %s at line %s\n " % (func_name , start_lineno ))
155171 template = '%6s %9s %12s %8s %8s %-s'
156172 d = {}
157173 total_time = 0.0
158174 linenos = []
159175 for lineno , nhits , time in timings :
160176 total_time += time
161177 linenos .append (lineno )
178+
179+ if stripzeros and total_time == 0 :
180+ return
181+
162182 stream .write ("Total time: %g s\n " % (total_time * unit ))
163183 if os .path .exists (filename ) or filename .startswith ("<ipython-input-" ):
184+ stream .write ("File: %s\n " % filename )
185+ stream .write ("Function: %s at line %s\n " % (func_name , start_lineno ))
164186 if os .path .exists (filename ):
165187 # Clear the cache to ensure that we get up-to-date results.
166188 linecache .clearcache ()
@@ -195,15 +217,15 @@ def show_func(filename, start_lineno, func_name, timings, unit, stream=None):
195217 stream .write ("\n " )
196218 stream .write ("\n " )
197219
198- def show_text (stats , unit , stream = None ):
220+ def show_text (stats , unit , stream = None , stripzeros = False ):
199221 """ Show text for the given timings.
200222 """
201223 if stream is None :
202224 stream = sys .stdout
203225
204226 stream .write ('Timer unit: %g s\n \n ' % unit )
205227 for (fn , lineno , name ), timings in sorted (stats .items ()):
206- show_func (fn , lineno , name , stats [fn , lineno , name ], unit , stream = stream )
228+ show_func (fn , lineno , name , stats [fn , lineno , name ], unit , stream = stream , stripzeros = stripzeros )
207229
208230# A %lprun magic for IPython.
209231def magic_lprun (self , parameter_s = '' ):
@@ -228,7 +250,9 @@ def magic_lprun(self, parameter_s=''):
228250 in the interpreter at the In[] prompt or via %run currently cannot be
229251 displayed. Write these functions out to a separate file and import them.
230252
231- One or more -f options are required to get any useful results.
253+ -m <module>: Get all the functions/methods in a module
254+
255+ One or more -f or -m options are required to get any useful results.
232256
233257 -D <filename>: dump the raw statistics out to a pickle file on disk. The
234258 usual extension for this is ".lprof". These statistics may be viewed later
@@ -238,6 +262,8 @@ def magic_lprun(self, parameter_s=''):
238262 out to a text file.
239263
240264 -r: return the LineProfiler object after it has completed profiling.
265+
266+ -s: strip out all entries from the print-out that have zeros.
241267 """
242268 # Local imports to avoid hard dependency.
243269 from distutils .version import LooseVersion
@@ -253,9 +279,9 @@ def magic_lprun(self, parameter_s=''):
253279 from IPython .core .error import UsageError
254280
255281 # Escape quote markers.
256- opts_def = Struct (D = ['' ], T = ['' ], f = [])
282+ opts_def = Struct (D = ['' ], T = ['' ], f = [], m = [] )
257283 parameter_s = parameter_s .replace ('"' , r'\"' ).replace ("'" , r"\'" )
258- opts , arg_str = self .parse_options (parameter_s , 'rf :D:T:' , list_all = True )
284+ opts , arg_str = self .parse_options (parameter_s , 'rsf:m :D:T:' , list_all = True )
259285 opts .merge (opts_def )
260286
261287 global_ns = self .shell .user_global_ns
@@ -272,6 +298,15 @@ def magic_lprun(self, parameter_s=''):
272298
273299 profile = LineProfiler (* funcs )
274300
301+ # Get the modules, too
302+ for modname in opts .m :
303+ try :
304+ mod = __import__ (modname , fromlist = ['' ])
305+ profile .add_module (mod )
306+ except Exception as e :
307+ raise UsageError ('Could not find module %r.\n %s: %s' % (name ,
308+ e .__class__ .__name__ , e ))
309+
275310 # Add the profiler to the builtins for @profile.
276311 if PY3 :
277312 import builtins
@@ -301,7 +336,7 @@ def magic_lprun(self, parameter_s=''):
301336
302337 # Trap text output.
303338 stdout_trap = StringIO ()
304- profile .print_stats (stdout_trap )
339+ profile .print_stats (stdout_trap , stripzeros = 's' in opts )
305340 output = stdout_trap .getvalue ()
306341 output = output .rstrip ()
307342
0 commit comments