Skip to content

Commit ffabcd8

Browse files
committed
Fix duplicate get_action() call in mprof.main and add tests for #388 (Closes #388)
1 parent e3cbcf0 commit ffabcd8

2 files changed

Lines changed: 60 additions & 4 deletions

File tree

‎mprof.py‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -919,8 +919,10 @@ def get_profiles(args):
919919
return filenames
920920

921921
def main():
922-
# Workaround for optparse limitation: insert -- before first negative
923-
# number found.
922+
# Workaround for optparse/argparse limitation: insert -- before the first
923+
# negative number found so commands like `mprof plot -1` or `mprof rm -1`
924+
# can accept negative profile indices. Skip this for `run` so negative
925+
# numbers passed as arguments to the profiled script are not modified (#388).
924926
action = get_action()
925927
if action not in ["run"]:
926928
negint = re.compile("-[0-9]+")
@@ -935,7 +937,7 @@ def main():
935937
"attach": attach_action,
936938
"plot": plot_action,
937939
"peak": peak_action}
938-
actions[get_action()]()
940+
actions[action]()
939941

940942
if __name__ == "__main__":
941943
main()

‎test/test_mprof.py‎

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
import os
2+
import sys
3+
import tempfile
14
import unittest
25

36
import mprof
47

8+
59
class Test_function_labels(unittest.TestCase):
610
def test(self):
711
expected = {
@@ -14,7 +18,57 @@ def test(self):
1418
"b.c": "b.c",
1519
}
1620
result = mprof.function_labels(expected.keys())
17-
self.assertEqual(expected,result)
21+
self.assertEqual(expected, result)
22+
23+
24+
class TestMprofMainArgs(unittest.TestCase):
25+
"""Tests for CLI argument handling in mprof.main() (Issue #388 / PR #390).
26+
27+
Background (Issue #388):
28+
Subcommands like `mprof plot -1` or `mprof rm -1` allow selecting a profile
29+
file by negative index (-1 = most recent). To prevent argparse from treating
30+
`-1` as an unknown flag, `mprof.main()` inserts `"--"` before the first
31+
negative integer in `sys.argv`.
32+
33+
However, when running `mprof run script.py -1`, inserting `"--"` into
34+
`sys.argv` causes `"--"` to be forwarded as an extra argument to `script.py`
35+
(so the script receives `['--', '-1']` instead of `['-1']`).
36+
"""
37+
38+
def test_run_preserves_negative_int_args(self):
39+
# Verify that `mprof run` does NOT inject "--" before negative integer
40+
# arguments meant for the target program. The temporary script checks
41+
# that its sys.argv[1:] is exactly ['-1'] and exits non-zero otherwise.
42+
script = (
43+
"import sys\n"
44+
"assert sys.argv[1:] == ['-1'], 'Unexpected argv: %r' % (sys.argv[1:],)\n"
45+
)
46+
with tempfile.NamedTemporaryFile('w', suffix='.py') as tmp_script, \
47+
tempfile.NamedTemporaryFile('w', suffix='.dat') as tmp_dat:
48+
tmp_script.write(script)
49+
tmp_script.flush()
50+
sys.argv = [
51+
'mprof', 'run', '--exit-code', '-o', tmp_dat.name,
52+
tmp_script.name, '-1'
53+
]
54+
with self.assertRaises(SystemExit) as cm:
55+
mprof.main()
56+
self.assertEqual(cm.exception.code, 0)
57+
58+
def test_non_run_action_accepts_negative_index(self):
59+
# Verify that non-`run` subcommands (such as `mprof rm --dry-run -1`)
60+
# still have "--" inserted before `-1` so negative profile indices
61+
# are accepted by argparse without raising an unrecognized argument error.
62+
tmp_prof = "mprofile_20990101000000.dat"
63+
with open(tmp_prof, "w") as f:
64+
f.write("")
65+
try:
66+
sys.argv = ['mprof', 'rm', '--dry-run', '-1']
67+
mprof.main()
68+
finally:
69+
if os.path.exists(tmp_prof):
70+
os.remove(tmp_prof)
71+
1872

1973
if __name__ == "__main__":
2074
unittest.main()

0 commit comments

Comments
 (0)