Skip to content

Commit b6bf152

Browse files
committed
Refactoring in kernprof.py
kernprof.py __doc__ Updated with the latest `kernprof --help` output, and with a narrower window so that the lines aren't too long __doc__ RepeatedTimer.__doc__ Added linter-friendly `noqa` comment for long lines in docstrings meant for `sphinx` consumption RepeatedTimer.start() main() Wrapped certain long lines of code main() - Removed note on boolean options in parser description - Removed parenthetical remark "boolean option" in option help texts - Removed redundant instantiation of `RepeatedTimer` - Refactored chained if-elif-else when executing code in non-autoprofiling mode
1 parent f014e69 commit b6bf152

File tree

1 file changed

+82
-47
lines changed

1 file changed

+82
-47
lines changed

kernprof.py

Lines changed: 82 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,20 @@ def main():
6363
6464
.. code::
6565
66-
usage: kernprof [-h] [-V] [--config CONFIG] [-l] [-b] [-s SETUP] [-p PROF_MOD] [--prof-imports] [-o OUTFILE] [-v] [-r] [-u UNIT] [-z] [-i [OUTPUT_INTERVAL]]
67-
{path/to/script | -m path.to.module | -c "literal code"} ...
68-
69-
Run and profile a python script or module.Boolean options can be negated by passing the corresponding flag (e.g. `--no-view` for `--view`).
66+
usage: kernprof [-h] [-V] [--config CONFIG] [--no-config]
67+
[--line-by-line [Y[es] | N[o] | T[rue] | F[alse] | on | off | 1 | 0]]
68+
[--builtin [Y[es] | N[o] | T[rue] | F[alse] | on | off | 1 | 0]]
69+
[-s SETUP] [-p PROF_MOD]
70+
[--prof-imports [Y[es] | N[o] | T[rue] | F[alse] | on | off | 1 | 0]]
71+
[-o OUTFILE]
72+
[--view [Y[es] | N[o] | T[rue] | F[alse] | on | off | 1 | 0]]
73+
[--rich [Y[es] | N[o] | T[rue] | F[alse] | on | off | 1 | 0]]
74+
[-u UNIT]
75+
[--skip-zero [Y[es] | N[o] | T[rue] | F[alse] | on | off | 1 | 0]]
76+
[-i [OUTPUT_INTERVAL]]
77+
{script | -m module} ...
78+
79+
Run and profile a python script or module.
7080
7181
positional arguments:
7282
{path/to/script | -m path.to.module | -c "literal code"}
@@ -76,33 +86,58 @@ def main():
7686
options:
7787
-h, --help show this help message and exit
7888
-V, --version show program's version number and exit
79-
--config CONFIG Path to the TOML file, from the `tool.line_profiler.kernprof` table of which to load defaults for the options. (Default: 'pyproject.toml')
80-
--no-config Disable the loading of configuration files other than the default one
89+
--config CONFIG Path to the TOML file, from the `tool.line_profiler.kernprof`
90+
table of which to load defaults for the options. (Default:
91+
'pyproject.toml')
92+
--no-config Disable the loading of configuration files other than the
93+
default one
8194
8295
profiling options:
83-
-l, --line-by-line Use the line-by-line profiler instead of cProfile. Implies `--builtin`. (Boolean option; default: False)
84-
-b, --builtin Put `profile` in the builtins. Use `profile.enable()`/`.disable()` to toggle profiling, `@profile` to decorate functions, or `with profile:` to profile
85-
a section of code. (Boolean option; default: False)
86-
-s, --setup SETUP Path to the Python source file containing setup code to execute before the code to profile. (Default: N/A)
96+
--line-by-line [Y[es] | N[o] | T[rue] | F[alse] | on | off | 1 | 0]
97+
Use the line-by-line profiler instead of cProfile. Implies
98+
`--builtin`. (Default: False; short form: -l)
99+
--builtin [Y[es] | N[o] | T[rue] | F[alse] | on | off | 1 | 0]
100+
Put `profile` in the builtins. Use
101+
`profile.enable()`/`.disable()` to toggle profiling,
102+
`@profile` to decorate functions, or `with profile:` to
103+
profile a section of code. (Default: False; short form: -b)
104+
-s, --setup SETUP Path to the Python source file containing setup code to
105+
execute before the code to profile. (Default: N/A)
87106
-p, --prof-mod PROF_MOD
88-
List of modules, functions and/or classes to profile specified by their name or path. List is comma separated, adding the current script path profiles
89-
the full script. Multiple copies of this flag can be supplied and the list is extended (e.g. `-p this.module,another.module -p some.func`). Only works
90-
with line profiling (`-l`/`--line-by-line`). (Default: N/A)
91-
--prof-imports If the script/module profiled is in `--prof-mod`, autoprofile all its imports. Only works with line profiling (`-l`/`--line-by-line`). (Boolean option;
92-
default: False)
107+
List of modules, functions and/or classes to profile specified
108+
by their name or path. List is comma separated, adding the
109+
current script path profiles the full script. Multiple copies
110+
of this flag can be supplied and the list is extended (e.g.
111+
`-p this.module,another.module -p some.func`). Only works with
112+
line profiling (`-l`/`--line-by-line`). (Default: N/A)
113+
--prof-imports [Y[es] | N[o] | T[rue] | F[alse] | on | off | 1 | 0]
114+
If the script/module profiled is in `--prof-mod`, autoprofile
115+
all its imports. Only works with line profiling (`-l`/`--line-
116+
by-line`). (Default: False)
93117
94118
output options:
95119
-o, --outfile OUTFILE
96-
Save stats to OUTFILE. (Default: '<script_or_module_name>.lprof' in line-profiling mode (`-l`/`--line-by-line`); '<script_or_module_name>.prof'
120+
Save stats to OUTFILE. (Default:
121+
'<script_or_module_name>.lprof' in line-profiling mode
122+
(`-l`/`--line-by-line`); '<script_or_module_name>.prof'
97123
otherwise)
98-
-v, --view View the results of the profile in addition to saving it. (Boolean option; default: False)
99-
-r, --rich Use rich formatting if viewing output. (Boolean option; default: False)
100-
-u, --unit UNIT Output unit (in seconds) in which the timing info is displayed. (Default: 1e-06 s)
101-
-z, --skip-zero Hide functions which have not been called. (Boolean option; default: False)
124+
--view [Y[es] | N[o] | T[rue] | F[alse] | on | off | 1 | 0]
125+
View the results of the profile in addition to saving it.
126+
(Default: False; short form: -v)
127+
--rich [Y[es] | N[o] | T[rue] | F[alse] | on | off | 1 | 0]
128+
Use rich formatting if viewing output. (Default: False; short
129+
form: -r)
130+
-u, --unit UNIT Output unit (in seconds) in which the timing info is
131+
displayed. (Default: 1e-06 s)
132+
--skip-zero [Y[es] | N[o] | T[rue] | F[alse] | on | off | 1 | 0]
133+
Hide functions which have not been called. (Default: False;
134+
short form: -z)
102135
-i, --output-interval [OUTPUT_INTERVAL]
103-
Enables outputting of cumulative profiling results to OUTFILE every OUTPUT_INTERVAL seconds. Uses the threading module. Minimum value (and the value
104-
implied if the bare option is given) is 1 s. (Default: 0 s (disabled))
105-
"""
136+
Enables outputting of cumulative profiling results to OUTFILE
137+
every OUTPUT_INTERVAL seconds. Uses the threading module.
138+
Minimum value (and the value implied if the bare option is
139+
given) is 1 s. (Default: 0 s (disabled))
140+
""" # noqa: E501
106141
import argparse
107142
import builtins
108143
import functools
@@ -181,7 +216,7 @@ class RepeatedTimer:
181216
182217
References:
183218
.. [SO474528] https://stackoverflow.com/questions/474528/execute-function-every-x-seconds/40965385#40965385
184-
"""
219+
""" # noqa: E501
185220
def __init__(self, interval, dump_func, outfile):
186221
self._timer = None
187222
self.interval = interval
@@ -199,7 +234,8 @@ def _run(self):
199234
def start(self):
200235
if not self.is_running:
201236
self.next_call += self.interval
202-
self._timer = threading.Timer(self.next_call - time.time(), self._run)
237+
self._timer = threading.Timer(self.next_call - time.time(),
238+
self._run)
203239
self._timer.start()
204240
self.is_running = True
205241

@@ -359,9 +395,7 @@ def main(args=None, exit_on_error=True):
359395
"""
360396
create_parser = functools.partial(
361397
argparse.ArgumentParser,
362-
description='Run and profile a python script or module.'
363-
'Boolean options can be negated by passing the corresponding flag '
364-
'(e.g. `--no-view` for `--view`).')
398+
description='Run and profile a python script or module.')
365399
get_kernprof_config = functools.partial(get_cli_config, 'kernprof')
366400
defaults, default_source = get_kernprof_config()
367401

@@ -412,13 +446,14 @@ def main(args=None, exit_on_error=True):
412446
add_argument(prof_opts, '-l', '--line-by-line', action='store_true',
413447
help='Use the line-by-line profiler instead of cProfile. '
414448
'Implies `--builtin`. '
415-
f'(Boolean option; default: {defaults["line_by_line"]})')
449+
f'(Default: {defaults["line_by_line"]})')
416450
add_argument(prof_opts, '-b', '--builtin', action='store_true',
417451
help="Put `profile` in the builtins. "
418-
"Use `profile.enable()`/`.disable()` to toggle profiling, "
452+
"Use `profile.enable()`/`.disable()` to "
453+
"toggle profiling, "
419454
"`@profile` to decorate functions, "
420455
"or `with profile:` to profile a section of code. "
421-
f"(Boolean option; default: {defaults['builtin']})")
456+
f"(Default: {defaults['builtin']})")
422457
if defaults['setup']:
423458
def_setupfile = repr(defaults['setup'])
424459
else:
@@ -445,7 +480,7 @@ def main(args=None, exit_on_error=True):
445480
help="If the script/module profiled is in `--prof-mod`, "
446481
"autoprofile all its imports. "
447482
"Only works with line profiling (`-l`/`--line-by-line`). "
448-
f"(Boolean option; default: {defaults['prof_imports']})")
483+
f"(Default: {defaults['prof_imports']})")
449484
out_opts = parser.add_argument_group('output options')
450485
if defaults['outfile']:
451486
def_outfile = repr(defaults['outfile'])
@@ -459,17 +494,17 @@ def main(args=None, exit_on_error=True):
459494
add_argument(out_opts, '-v', '--view', action='store_true',
460495
help='View the results of the profile '
461496
'in addition to saving it. '
462-
f'(Boolean option; default: {defaults["view"]})')
497+
f'(Default: {defaults["view"]})')
463498
add_argument(out_opts, '-r', '--rich', action='store_true',
464499
help='Use rich formatting if viewing output. '
465-
f'(Boolean option; default: {defaults["rich"]})')
500+
f'(Default: {defaults["rich"]})')
466501
add_argument(out_opts, '-u', '--unit', type=positive_float,
467502
help='Output unit (in seconds) in which '
468503
'the timing info is displayed. '
469504
f'(Default: {defaults["unit"]} s)')
470505
add_argument(out_opts, '-z', '--skip-zero', action='store_true',
471506
help="Hide functions which have not been called. "
472-
f"(Boolean option; default: {defaults['skip_zero']})")
507+
f"(Default: {defaults['skip_zero']})")
473508
if defaults['output_interval']:
474509
def_out_int = f'{defaults["output_interval"]} s'
475510
else:
@@ -582,7 +617,7 @@ def _main(options, module=False, exit_on_error=True):
582617
"""
583618
if not options.outfile:
584619
extension = 'lprof' if options.line_by_line else 'prof'
585-
options.outfile = '%s.%s' % (os.path.basename(options.script), extension)
620+
options.outfile = f'{os.path.basename(options.script)}.{extension}'
586621

587622
sys.argv = [options.script] + options.args
588623
if module:
@@ -631,12 +666,10 @@ def _main(options, module=False, exit_on_error=True):
631666
__file__ = script_file
632667
__name__ = '__main__'
633668

634-
if options.output_interval:
635-
# XXX: why are we doing this here (5a38626) and again below?
636-
rt = RepeatedTimer(max(options.output_interval, 1), prof.dump_stats, options.outfile)
637669
original_stdout = sys.stdout
638670
if options.output_interval:
639-
rt = RepeatedTimer(max(options.output_interval, 1), prof.dump_stats, options.outfile)
671+
rt = RepeatedTimer(max(options.output_interval, 1), prof.dump_stats,
672+
options.outfile)
640673
try:
641674
try:
642675
execfile_ = execfile
@@ -657,14 +690,16 @@ def _main(options, module=False, exit_on_error=True):
657690
prof_mod=prof_mod,
658691
profile_imports=options.prof_imports,
659692
as_module=module is not None)
660-
elif module and options.builtin:
661-
rmod_(options.script, ns)
662-
elif options.builtin:
663-
execfile(script_file, ns, ns)
664-
elif module:
665-
prof.runctx(f'rmod_({options.script!r}, globals())', ns, ns)
666693
else:
667-
prof.runctx('execfile_(%r, globals())' % (script_file,), ns, ns)
694+
if module:
695+
runner, target = 'rmod_', options.script
696+
else:
697+
runner, target = 'execfile_', script_file
698+
assert runner in ns
699+
if options.builtin:
700+
ns[runner](target, ns)
701+
else:
702+
prof.runctx(f'{runner}({target!r}, globals())', ns, ns)
668703
except (KeyboardInterrupt, SystemExit):
669704
pass
670705
finally:

0 commit comments

Comments
 (0)