11#!/usr/bin/env python
22# -*- coding: UTF-8 -*-
3+ from __future__ import with_statement
4+ try :
5+ import cPickle as pickle
6+ except ImportError :
7+ import pickle
8+
9+ try :
10+ from cStringIO import StringIO
11+ except ImportError :
12+ from io import StringIO
313
4- import cPickle
5- from cStringIO import StringIO
614import inspect
715import linecache
816import optparse
1119
1220from _line_profiler import LineProfiler as CLineProfiler
1321
22+ # Python 2/3 compatibility utils
23+ # ===========================================================
24+ PY3 = sys .version_info [0 ] == 3
25+
26+ # next:
27+ try :
28+ next_ = next
29+ except NameError :
30+ next_ = lambda obj : obj .next ()
31+
32+ # exec (from https://bitbucket.org/gutworth/six/):
33+ if PY3 :
34+ import builtins
35+ exec_ = getattr (builtins , "exec" )
36+ del builtins
37+ else :
38+ def exec_ (_code_ , _globs_ = None , _locs_ = None ):
39+ """Execute code in a namespace."""
40+ if _globs_ is None :
41+ frame = sys ._getframe (1 )
42+ _globs_ = frame .f_globals
43+ if _locs_ is None :
44+ _locs_ = frame .f_locals
45+ del frame
46+ elif _locs_ is None :
47+ _locs_ = _globs_
48+ exec ("""exec _code_ in _globs_, _locs_""" )
49+
50+ # ============================================================
1451
1552CO_GENERATOR = 0x0020
1653def is_generator (f ):
1754 """ Return True if a function is a generator.
1855 """
19- isgen = (f .func_code .co_flags & CO_GENERATOR ) != 0
56+ func_code = f .__code__ if PY3 else f .func_code
57+ isgen = (func_code .co_flags & CO_GENERATOR ) != 0
2058 return isgen
2159
2260# Code to exec inside of LineProfiler.__call__ to support PEP-342-style
@@ -30,7 +68,7 @@ def f(*args, **kwds):
3068 # The first iterate will not be a .send()
3169 self.enable_by_count()
3270 try:
33- item = g.next( )
71+ item = next_(g )
3472 finally:
3573 self.disable_by_count()
3674 input = (yield item)
@@ -67,7 +105,7 @@ def __call__(self, func):
67105 if sys .version_info [:2 ] >= (2 ,5 ):
68106 # Delay compilation because the syntax is not compatible with older
69107 # Python versions.
70- exec pep342_gen_wrapper
108+ exec_ ( pep342_gen_wrapper )
71109 else :
72110 def wrap_generator (self , func ):
73111 """ Wrap a generator to profile it.
@@ -77,7 +115,7 @@ def f(*args, **kwds):
77115 while True :
78116 self .enable_by_count ()
79117 try :
80- item = g . next ( )
118+ item = next_ ( g )
81119 finally :
82120 self .disable_by_count ()
83121 yield item
@@ -102,7 +140,7 @@ def dump_stats(self, filename):
102140 lstats = self .get_stats ()
103141 f = open (filename , 'wb' )
104142 try :
105- cPickle .dump (lstats , f , cPickle .HIGHEST_PROTOCOL )
143+ pickle .dump (lstats , f , pickle .HIGHEST_PROTOCOL )
106144 finally :
107145 f .close ()
108146
@@ -116,15 +154,15 @@ def run(self, cmd):
116154 """ Profile a single executable statment in the main namespace.
117155 """
118156 import __main__
119- dict = __main__ .__dict__
120- return self .runctx (cmd , dict , dict )
157+ main_dict = __main__ .__dict__
158+ return self .runctx (cmd , main_dict , main_dict )
121159
122160 def runctx (self , cmd , globals , locals ):
123161 """ Profile a single executable statement in the given namespaces.
124162 """
125163 self .enable_by_count ()
126164 try :
127- exec cmd in globals , locals
165+ exec_ ( cmd , globals , locals )
128166 finally :
129167 self .disable_by_count ()
130168 return self
@@ -144,22 +182,23 @@ def show_func(filename, start_lineno, func_name, timings, unit, stream=None):
144182 """
145183 if stream is None :
146184 stream = sys .stdout
147- print >> stream , "File: %s" % filename
148- print >> stream , "Function: %s at line %s" % (func_name , start_lineno )
185+
186+ stream .write ("File: %s\n " % filename )
187+ stream .write ("Function: %s at line %s\n " % (func_name , start_lineno ))
149188 template = '%6s %9s %12s %8s %8s %-s'
150189 d = {}
151190 total_time = 0.0
152191 linenos = []
153192 for lineno , nhits , time in timings :
154193 total_time += time
155194 linenos .append (lineno )
156- print >> stream , "Total time: %g s" % (total_time * unit )
195+ stream . write ( "Total time: %g s\n " % (total_time * unit ) )
157196 if not os .path .exists (filename ):
158- print >> stream , ""
159- print >> stream , "Could not find file %s" % filename
160- print >> stream , "Are you sure you are running this program from the same directory"
161- print >> stream , "that you ran the profiler from?"
162- print >> stream , "Continuing without the function's contents."
197+ stream . write ( " \n " )
198+ stream . write ( "Could not find file %s\n " % filename )
199+ stream . write ( "Are you sure you are running this program from the same directory\n " )
200+ stream . write ( "that you ran the profiler from?\n " )
201+ stream . write ( "Continuing without the function's contents.\n " )
163202 # Fake empty lines so we can see the timings, if not the code.
164203 nlines = max (linenos ) - min (min (linenos ), start_lineno ) + 1
165204 sublines = ['' ] * nlines
@@ -173,24 +212,28 @@ def show_func(filename, start_lineno, func_name, timings, unit, stream=None):
173212 '%5.1f' % (100 * time / total_time ))
174213 linenos = range (start_lineno , start_lineno + len (sublines ))
175214 empty = ('' , '' , '' , '' )
176- header = template % ('Line #' , 'Hits' , 'Time' , 'Per Hit' , '% Time' ,
215+ header = template % ('Line #' , 'Hits' , 'Time' , 'Per Hit' , '% Time' ,
177216 'Line Contents' )
178- print >> stream , ""
179- print >> stream , header
180- print >> stream , '=' * len (header )
217+ stream .write ("\n " )
218+ stream .write (header )
219+ stream .write ("\n " )
220+ stream .write ('=' * len (header ))
221+ stream .write ("\n " )
181222 for lineno , line in zip (linenos , sublines ):
182223 nhits , time , per_hit , percent = d .get (lineno , empty )
183- print >> stream , template % (lineno , nhits , time , per_hit , percent ,
184- line .rstrip ('\n ' ).rstrip ('\r ' ))
185- print >> stream , ""
224+ txt = template % (lineno , nhits , time , per_hit , percent ,
225+ line .rstrip ('\n ' ).rstrip ('\r ' ))
226+ stream .write (txt )
227+ stream .write ("\n " )
228+ stream .write ("\n " )
186229
187230def show_text (stats , unit , stream = None ):
188231 """ Show text for the given timings.
189232 """
190233 if stream is None :
191234 stream = sys .stdout
192- print >> stream , 'Timer unit: %g s' % unit
193- print >> stream , ''
235+
236+ stream . write ( 'Timer unit: %g s \n \n ' % unit )
194237 for (fn , lineno , name ), timings in sorted (stats .items ()):
195238 show_func (fn , lineno , name , stats [fn , lineno , name ], unit , stream = stream )
196239
@@ -208,7 +251,7 @@ def magic_lprun(self, parameter_s=''):
208251 pager once the statement has completed.
209252
210253 Options:
211-
254+
212255 -f <function>: LineProfiler only profiles functions and methods it is told
213256 to profile. This option tells the profiler about these functions. Multiple
214257 -f options may be used. The argument may be any expression that gives
@@ -243,7 +286,7 @@ def magic_lprun(self, parameter_s=''):
243286
244287 # Escape quote markers.
245288 opts_def = Struct (D = ['' ], T = ['' ], f = [])
246- parameter_s = parameter_s .replace ('"' ,r'\"' ).replace ("'" ,r"\'" )
289+ parameter_s = parameter_s .replace ('"' , r'\"' ).replace ("'" , r"\'" )
247290 opts , arg_str = self .parse_options (parameter_s , 'rf:D:T:' , list_all = True )
248291 opts .merge (opts_def )
249292
@@ -255,21 +298,28 @@ def magic_lprun(self, parameter_s=''):
255298 for name in opts .f :
256299 try :
257300 funcs .append (eval (name , global_ns , local_ns ))
258- except Exception , e :
259- raise UsageError ('Could not find function %r.\n %s: %s' % (name ,
301+ except Exception :
302+ # "except Exception as e" is not supported in Python 2.5
303+ # so we're using a hack to get the exception
304+ e = sys .exc_info ()[1 ]
305+ raise UsageError ('Could not find function %r.\n %s: %s' % (name ,
260306 e .__class__ .__name__ , e ))
261307
262308 profile = LineProfiler (* funcs )
263309
264310 # Add the profiler to the builtins for @profile.
265- import __builtin__
266- if 'profile' in __builtin__ .__dict__ :
311+ if PY3 :
312+ import builtins
313+ else :
314+ import __builtin__ as builtins
315+
316+ if 'profile' in builtins .__dict__ :
267317 had_profile = True
268- old_profile = __builtin__ .__dict__ ['profile' ]
318+ old_profile = builtins .__dict__ ['profile' ]
269319 else :
270320 had_profile = False
271321 old_profile = None
272- __builtin__ .__dict__ ['profile' ] = profile
322+ builtins .__dict__ ['profile' ] = profile
273323
274324 try :
275325 try :
@@ -282,7 +332,7 @@ def magic_lprun(self, parameter_s=''):
282332 "profiled." )
283333 finally :
284334 if had_profile :
285- __builtin__ .__dict__ ['profile' ] = old_profile
335+ builtins .__dict__ ['profile' ] = old_profile
286336
287337 # Trap text output.
288338 stdout_trap = StringIO ()
@@ -294,24 +344,24 @@ def magic_lprun(self, parameter_s=''):
294344 page (output , screen_lines = self .shell .rc .screen_length )
295345 else :
296346 page (output )
297- print message ,
347+ print ( message )
298348
299349 dump_file = opts .D [0 ]
300350 if dump_file :
301351 profile .dump_stats (dump_file )
302- print '\n *** Profile stats pickled to file' ,\
303- ` dump_file` + '.' , message
352+ print ( '\n *** Profile stats pickled to file %r. %s' % (
353+ dump_file , message ))
304354
305355 text_file = opts .T [0 ]
306356 if text_file :
307357 pfile = open (text_file , 'w' )
308358 pfile .write (output )
309359 pfile .close ()
310- print '\n *** Profile printout saved to text file' ,\
311- ` text_file` + '.' , message
360+ print ( '\n *** Profile printout saved to text file %r. %s' % (
361+ text_file , message ))
312362
313363 return_value = None
314- if opts . has_key ( 'r' ) :
364+ if 'r' in opts :
315365 return_value = profile
316366
317367 return return_value
@@ -327,12 +377,8 @@ def load_stats(filename):
327377 """ Utility function to load a pickled LineStats object from a given
328378 filename.
329379 """
330- f = open (filename , 'rb' )
331- try :
332- lstats = cPickle .load (f )
333- finally :
334- f .close ()
335- return lstats
380+ with open (filename , 'rb' ) as f :
381+ return pickle .load (f )
336382
337383
338384def main ():
0 commit comments