blob: 1d156673eb31569e224cd17685af93719627beda [file] [log] [blame]
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001import _tracemalloc
2import contextlib
3import datetime
4import os
5import sys
6import tracemalloc
7import unittest
8from unittest.mock import patch
9from test.script_helper import assert_python_ok, assert_python_failure
10from test import support
11try:
12 import threading
13except ImportError:
14 threading = None
15
16EMPTY_STRING_SIZE = sys.getsizeof(b'')
17
18def get_frames(nframe, lineno_delta):
19 frames = []
20 frame = sys._getframe(1)
21 for index in range(nframe):
22 code = frame.f_code
23 lineno = frame.f_lineno + lineno_delta
24 frames.append((code.co_filename, lineno))
25 lineno_delta = 0
26 frame = frame.f_back
27 if frame is None:
28 break
29 return tuple(frames)
30
31def allocate_bytes(size):
32 nframe = tracemalloc.get_traceback_limit()
33 bytes_len = (size - EMPTY_STRING_SIZE)
34 frames = get_frames(nframe, 1)
35 data = b'x' * bytes_len
36 return data, tracemalloc.Traceback(frames)
37
38def create_snapshots():
39 traceback_limit = 2
40
41 raw_traces = [
42 (10, (('a.py', 2), ('b.py', 4))),
43 (10, (('a.py', 2), ('b.py', 4))),
44 (10, (('a.py', 2), ('b.py', 4))),
45
46 (2, (('a.py', 5), ('b.py', 4))),
47
48 (66, (('b.py', 1),)),
49
50 (7, (('<unknown>', 0),)),
51 ]
52 snapshot = tracemalloc.Snapshot(raw_traces, traceback_limit)
53
54 raw_traces2 = [
55 (10, (('a.py', 2), ('b.py', 4))),
56 (10, (('a.py', 2), ('b.py', 4))),
57 (10, (('a.py', 2), ('b.py', 4))),
58
59 (2, (('a.py', 5), ('b.py', 4))),
60 (5000, (('a.py', 5), ('b.py', 4))),
61
62 (400, (('c.py', 578),)),
63 ]
64 snapshot2 = tracemalloc.Snapshot(raw_traces2, traceback_limit)
65
66 return (snapshot, snapshot2)
67
68def frame(filename, lineno):
69 return tracemalloc._Frame((filename, lineno))
70
71def traceback(*frames):
72 return tracemalloc.Traceback(frames)
73
74def traceback_lineno(filename, lineno):
75 return traceback((filename, lineno))
76
77def traceback_filename(filename):
78 return traceback_lineno(filename, 0)
79
80
81class TestTracemallocEnabled(unittest.TestCase):
82 def setUp(self):
83 if tracemalloc.is_tracing():
84 self.skipTest("tracemalloc must be stopped before the test")
85
Victor Stinner3728d6c2013-11-23 12:37:20 +010086 tracemalloc.start(1)
Victor Stinnered3b0bc2013-11-23 12:27:24 +010087
88 def tearDown(self):
89 tracemalloc.stop()
90
91 def test_get_tracemalloc_memory(self):
92 data = [allocate_bytes(123) for count in range(1000)]
93 size = tracemalloc.get_tracemalloc_memory()
94 self.assertGreaterEqual(size, 0)
95
96 tracemalloc.clear_traces()
97 size2 = tracemalloc.get_tracemalloc_memory()
98 self.assertGreaterEqual(size2, 0)
99 self.assertLessEqual(size2, size)
100
101 def test_get_object_traceback(self):
102 tracemalloc.clear_traces()
103 obj_size = 12345
104 obj, obj_traceback = allocate_bytes(obj_size)
105 traceback = tracemalloc.get_object_traceback(obj)
106 self.assertEqual(traceback, obj_traceback)
107
108 def test_set_traceback_limit(self):
109 obj_size = 10
110
Victor Stinner3728d6c2013-11-23 12:37:20 +0100111 tracemalloc.stop()
112 self.assertRaises(ValueError, tracemalloc.start, -1)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100113
Victor Stinner3728d6c2013-11-23 12:37:20 +0100114 tracemalloc.stop()
115 tracemalloc.start(10)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100116 obj2, obj2_traceback = allocate_bytes(obj_size)
117 traceback = tracemalloc.get_object_traceback(obj2)
118 self.assertEqual(len(traceback), 10)
119 self.assertEqual(traceback, obj2_traceback)
120
Victor Stinner3728d6c2013-11-23 12:37:20 +0100121 tracemalloc.stop()
122 tracemalloc.start(1)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100123 obj, obj_traceback = allocate_bytes(obj_size)
124 traceback = tracemalloc.get_object_traceback(obj)
125 self.assertEqual(len(traceback), 1)
126 self.assertEqual(traceback, obj_traceback)
127
128
129 def find_trace(self, traces, traceback):
130 for trace in traces:
131 if trace[1] == traceback._frames:
132 return trace
133
134 self.fail("trace not found")
135
136 def test_get_traces(self):
137 tracemalloc.clear_traces()
138 obj_size = 12345
139 obj, obj_traceback = allocate_bytes(obj_size)
140
141 traces = tracemalloc._get_traces()
142 trace = self.find_trace(traces, obj_traceback)
143
144 self.assertIsInstance(trace, tuple)
145 size, traceback = trace
146 self.assertEqual(size, obj_size)
147 self.assertEqual(traceback, obj_traceback._frames)
148
149 tracemalloc.stop()
150 self.assertEqual(tracemalloc._get_traces(), [])
151
152
153 def test_get_traces_intern_traceback(self):
154 # dummy wrappers to get more useful and identical frames in the traceback
155 def allocate_bytes2(size):
156 return allocate_bytes(size)
157 def allocate_bytes3(size):
158 return allocate_bytes2(size)
159 def allocate_bytes4(size):
160 return allocate_bytes3(size)
161
162 # Ensure that two identical tracebacks are not duplicated
Victor Stinner3728d6c2013-11-23 12:37:20 +0100163 tracemalloc.stop()
164 tracemalloc.start(4)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100165 obj_size = 123
166 obj1, obj1_traceback = allocate_bytes4(obj_size)
167 obj2, obj2_traceback = allocate_bytes4(obj_size)
168
169 traces = tracemalloc._get_traces()
170
171 trace1 = self.find_trace(traces, obj1_traceback)
172 trace2 = self.find_trace(traces, obj2_traceback)
173 size1, traceback1 = trace1
174 size2, traceback2 = trace2
175 self.assertEqual(traceback2, traceback1)
176 self.assertIs(traceback2, traceback1)
177
178 def test_get_traced_memory(self):
179 # Python allocates some internals objects, so the test must tolerate
180 # a small difference between the expected size and the real usage
181 max_error = 2048
182
183 # allocate one object
184 obj_size = 1024 * 1024
185 tracemalloc.clear_traces()
186 obj, obj_traceback = allocate_bytes(obj_size)
187 size, max_size = tracemalloc.get_traced_memory()
188 self.assertGreaterEqual(size, obj_size)
189 self.assertGreaterEqual(max_size, size)
190
191 self.assertLessEqual(size - obj_size, max_error)
192 self.assertLessEqual(max_size - size, max_error)
193
194 # destroy the object
195 obj = None
196 size2, max_size2 = tracemalloc.get_traced_memory()
197 self.assertLess(size2, size)
198 self.assertGreaterEqual(size - size2, obj_size - max_error)
199 self.assertGreaterEqual(max_size2, max_size)
200
201 # clear_traces() must reset traced memory counters
202 tracemalloc.clear_traces()
203 self.assertEqual(tracemalloc.get_traced_memory(), (0, 0))
204
205 # allocate another object
206 obj, obj_traceback = allocate_bytes(obj_size)
207 size, max_size = tracemalloc.get_traced_memory()
208 self.assertGreater(size, 0)
209
210 # stop() rests also traced memory counters
211 tracemalloc.stop()
212 self.assertEqual(tracemalloc.get_traced_memory(), (0, 0))
213
214 def test_clear_traces(self):
215 obj, obj_traceback = allocate_bytes(123)
216 traceback = tracemalloc.get_object_traceback(obj)
217 self.assertIsNotNone(traceback)
218
219 tracemalloc.clear_traces()
220 traceback2 = tracemalloc.get_object_traceback(obj)
221 self.assertIsNone(traceback2)
222
223 def test_is_tracing(self):
224 tracemalloc.stop()
225 self.assertFalse(tracemalloc.is_tracing())
226
227 tracemalloc.start()
228 self.assertTrue(tracemalloc.is_tracing())
229
230 def test_snapshot(self):
231 obj, source = allocate_bytes(123)
232
233 # take a snapshot
234 snapshot = tracemalloc.take_snapshot()
235
236 # write on disk
237 snapshot.dump(support.TESTFN)
238 self.addCleanup(support.unlink, support.TESTFN)
239
240 # load from disk
241 snapshot2 = tracemalloc.Snapshot.load(support.TESTFN)
242 self.assertEqual(snapshot2.traces, snapshot.traces)
243
244 # tracemalloc must be tracing memory allocations to take a snapshot
245 tracemalloc.stop()
246 with self.assertRaises(RuntimeError) as cm:
247 tracemalloc.take_snapshot()
248 self.assertEqual(str(cm.exception),
249 "the tracemalloc module must be tracing memory "
250 "allocations to take a snapshot")
251
252 def test_snapshot_save_attr(self):
253 # take a snapshot with a new attribute
254 snapshot = tracemalloc.take_snapshot()
255 snapshot.test_attr = "new"
256 snapshot.dump(support.TESTFN)
257 self.addCleanup(support.unlink, support.TESTFN)
258
259 # load() should recreates the attribute
260 snapshot2 = tracemalloc.Snapshot.load(support.TESTFN)
261 self.assertEqual(snapshot2.test_attr, "new")
262
263 def fork_child(self):
264 if not tracemalloc.is_tracing():
265 return 2
266
267 obj_size = 12345
268 obj, obj_traceback = allocate_bytes(obj_size)
269 traceback = tracemalloc.get_object_traceback(obj)
270 if traceback is None:
271 return 3
272
273 # everything is fine
274 return 0
275
276 @unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork()')
277 def test_fork(self):
278 # check that tracemalloc is still working after fork
279 pid = os.fork()
280 if not pid:
281 # child
282 exitcode = 1
283 try:
284 exitcode = self.fork_child()
285 finally:
286 os._exit(exitcode)
287 else:
288 pid2, status = os.waitpid(pid, 0)
289 self.assertTrue(os.WIFEXITED(status))
290 exitcode = os.WEXITSTATUS(status)
291 self.assertEqual(exitcode, 0)
292
293
294class TestSnapshot(unittest.TestCase):
295 maxDiff = 4000
296
297 def test_create_snapshot(self):
298 raw_traces = [(5, (('a.py', 2),))]
299
300 with contextlib.ExitStack() as stack:
301 stack.enter_context(patch.object(tracemalloc, 'is_tracing',
302 return_value=True))
303 stack.enter_context(patch.object(tracemalloc, 'get_traceback_limit',
304 return_value=5))
305 stack.enter_context(patch.object(tracemalloc, '_get_traces',
306 return_value=raw_traces))
307
308 snapshot = tracemalloc.take_snapshot()
309 self.assertEqual(snapshot.traceback_limit, 5)
310 self.assertEqual(len(snapshot.traces), 1)
311 trace = snapshot.traces[0]
312 self.assertEqual(trace.size, 5)
313 self.assertEqual(len(trace.traceback), 1)
314 self.assertEqual(trace.traceback[0].filename, 'a.py')
315 self.assertEqual(trace.traceback[0].lineno, 2)
316
317 def test_filter_traces(self):
318 snapshot, snapshot2 = create_snapshots()
319 filter1 = tracemalloc.Filter(False, "b.py")
320 filter2 = tracemalloc.Filter(True, "a.py", 2)
321 filter3 = tracemalloc.Filter(True, "a.py", 5)
322
323 original_traces = list(snapshot.traces._traces)
324
325 # exclude b.py
326 snapshot3 = snapshot.filter_traces((filter1,))
327 self.assertEqual(snapshot3.traces._traces, [
328 (10, (('a.py', 2), ('b.py', 4))),
329 (10, (('a.py', 2), ('b.py', 4))),
330 (10, (('a.py', 2), ('b.py', 4))),
331 (2, (('a.py', 5), ('b.py', 4))),
332 (7, (('<unknown>', 0),)),
333 ])
334
335 # filter_traces() must not touch the original snapshot
336 self.assertEqual(snapshot.traces._traces, original_traces)
337
338 # only include two lines of a.py
339 snapshot4 = snapshot3.filter_traces((filter2, filter3))
340 self.assertEqual(snapshot4.traces._traces, [
341 (10, (('a.py', 2), ('b.py', 4))),
342 (10, (('a.py', 2), ('b.py', 4))),
343 (10, (('a.py', 2), ('b.py', 4))),
344 (2, (('a.py', 5), ('b.py', 4))),
345 ])
346
347 # No filter: just duplicate the snapshot
348 snapshot5 = snapshot.filter_traces(())
349 self.assertIsNot(snapshot5, snapshot)
350 self.assertIsNot(snapshot5.traces, snapshot.traces)
351 self.assertEqual(snapshot5.traces, snapshot.traces)
352
353 def test_snapshot_group_by_line(self):
354 snapshot, snapshot2 = create_snapshots()
355 tb_0 = traceback_lineno('<unknown>', 0)
356 tb_a_2 = traceback_lineno('a.py', 2)
357 tb_a_5 = traceback_lineno('a.py', 5)
358 tb_b_1 = traceback_lineno('b.py', 1)
359 tb_c_578 = traceback_lineno('c.py', 578)
360
361 # stats per file and line
362 stats1 = snapshot.statistics('lineno')
363 self.assertEqual(stats1, [
364 tracemalloc.Statistic(tb_b_1, 66, 1),
365 tracemalloc.Statistic(tb_a_2, 30, 3),
366 tracemalloc.Statistic(tb_0, 7, 1),
367 tracemalloc.Statistic(tb_a_5, 2, 1),
368 ])
369
370 # stats per file and line (2)
371 stats2 = snapshot2.statistics('lineno')
372 self.assertEqual(stats2, [
373 tracemalloc.Statistic(tb_a_5, 5002, 2),
374 tracemalloc.Statistic(tb_c_578, 400, 1),
375 tracemalloc.Statistic(tb_a_2, 30, 3),
376 ])
377
378 # stats diff per file and line
379 statistics = snapshot2.compare_to(snapshot, 'lineno')
380 self.assertEqual(statistics, [
381 tracemalloc.StatisticDiff(tb_a_5, 5002, 5000, 2, 1),
382 tracemalloc.StatisticDiff(tb_c_578, 400, 400, 1, 1),
383 tracemalloc.StatisticDiff(tb_b_1, 0, -66, 0, -1),
384 tracemalloc.StatisticDiff(tb_0, 0, -7, 0, -1),
385 tracemalloc.StatisticDiff(tb_a_2, 30, 0, 3, 0),
386 ])
387
388 def test_snapshot_group_by_file(self):
389 snapshot, snapshot2 = create_snapshots()
390 tb_0 = traceback_filename('<unknown>')
391 tb_a = traceback_filename('a.py')
392 tb_b = traceback_filename('b.py')
393 tb_c = traceback_filename('c.py')
394
395 # stats per file
396 stats1 = snapshot.statistics('filename')
397 self.assertEqual(stats1, [
398 tracemalloc.Statistic(tb_b, 66, 1),
399 tracemalloc.Statistic(tb_a, 32, 4),
400 tracemalloc.Statistic(tb_0, 7, 1),
401 ])
402
403 # stats per file (2)
404 stats2 = snapshot2.statistics('filename')
405 self.assertEqual(stats2, [
406 tracemalloc.Statistic(tb_a, 5032, 5),
407 tracemalloc.Statistic(tb_c, 400, 1),
408 ])
409
410 # stats diff per file
411 diff = snapshot2.compare_to(snapshot, 'filename')
412 self.assertEqual(diff, [
413 tracemalloc.StatisticDiff(tb_a, 5032, 5000, 5, 1),
414 tracemalloc.StatisticDiff(tb_c, 400, 400, 1, 1),
415 tracemalloc.StatisticDiff(tb_b, 0, -66, 0, -1),
416 tracemalloc.StatisticDiff(tb_0, 0, -7, 0, -1),
417 ])
418
419 def test_snapshot_group_by_traceback(self):
420 snapshot, snapshot2 = create_snapshots()
421
422 # stats per file
423 tb1 = traceback(('a.py', 2), ('b.py', 4))
424 tb2 = traceback(('a.py', 5), ('b.py', 4))
425 tb3 = traceback(('b.py', 1))
426 tb4 = traceback(('<unknown>', 0))
427 stats1 = snapshot.statistics('traceback')
428 self.assertEqual(stats1, [
429 tracemalloc.Statistic(tb3, 66, 1),
430 tracemalloc.Statistic(tb1, 30, 3),
431 tracemalloc.Statistic(tb4, 7, 1),
432 tracemalloc.Statistic(tb2, 2, 1),
433 ])
434
435 # stats per file (2)
436 tb5 = traceback(('c.py', 578))
437 stats2 = snapshot2.statistics('traceback')
438 self.assertEqual(stats2, [
439 tracemalloc.Statistic(tb2, 5002, 2),
440 tracemalloc.Statistic(tb5, 400, 1),
441 tracemalloc.Statistic(tb1, 30, 3),
442 ])
443
444 # stats diff per file
445 diff = snapshot2.compare_to(snapshot, 'traceback')
446 self.assertEqual(diff, [
447 tracemalloc.StatisticDiff(tb2, 5002, 5000, 2, 1),
448 tracemalloc.StatisticDiff(tb5, 400, 400, 1, 1),
449 tracemalloc.StatisticDiff(tb3, 0, -66, 0, -1),
450 tracemalloc.StatisticDiff(tb4, 0, -7, 0, -1),
451 tracemalloc.StatisticDiff(tb1, 30, 0, 3, 0),
452 ])
453
454 self.assertRaises(ValueError,
455 snapshot.statistics, 'traceback', cumulative=True)
456
457 def test_snapshot_group_by_cumulative(self):
458 snapshot, snapshot2 = create_snapshots()
459 tb_0 = traceback_filename('<unknown>')
460 tb_a = traceback_filename('a.py')
461 tb_b = traceback_filename('b.py')
462 tb_a_2 = traceback_lineno('a.py', 2)
463 tb_a_5 = traceback_lineno('a.py', 5)
464 tb_b_1 = traceback_lineno('b.py', 1)
465 tb_b_4 = traceback_lineno('b.py', 4)
466
467 # per file
468 stats = snapshot.statistics('filename', True)
469 self.assertEqual(stats, [
470 tracemalloc.Statistic(tb_b, 98, 5),
471 tracemalloc.Statistic(tb_a, 32, 4),
472 tracemalloc.Statistic(tb_0, 7, 1),
473 ])
474
475 # per line
476 stats = snapshot.statistics('lineno', True)
477 self.assertEqual(stats, [
478 tracemalloc.Statistic(tb_b_1, 66, 1),
479 tracemalloc.Statistic(tb_b_4, 32, 4),
480 tracemalloc.Statistic(tb_a_2, 30, 3),
481 tracemalloc.Statistic(tb_0, 7, 1),
482 tracemalloc.Statistic(tb_a_5, 2, 1),
483 ])
484
485 def test_trace_format(self):
486 snapshot, snapshot2 = create_snapshots()
487 trace = snapshot.traces[0]
488 self.assertEqual(str(trace), 'a.py:2: 10 B')
489 traceback = trace.traceback
490 self.assertEqual(str(traceback), 'a.py:2')
491 frame = traceback[0]
492 self.assertEqual(str(frame), 'a.py:2')
493
494 def test_statistic_format(self):
495 snapshot, snapshot2 = create_snapshots()
496 stats = snapshot.statistics('lineno')
497 stat = stats[0]
498 self.assertEqual(str(stat),
499 'b.py:1: size=66 B, count=1, average=66 B')
500
501 def test_statistic_diff_format(self):
502 snapshot, snapshot2 = create_snapshots()
503 stats = snapshot2.compare_to(snapshot, 'lineno')
504 stat = stats[0]
505 self.assertEqual(str(stat),
506 'a.py:5: size=5002 B (+5000 B), count=2 (+1), average=2501 B')
507
508
509
510class TestFilters(unittest.TestCase):
511 maxDiff = 2048
512
513 def test_filter_attributes(self):
514 # test default values
515 f = tracemalloc.Filter(True, "abc")
516 self.assertEqual(f.inclusive, True)
517 self.assertEqual(f.filename_pattern, "abc")
518 self.assertIsNone(f.lineno)
519 self.assertEqual(f.all_frames, False)
520
521 # test custom values
522 f = tracemalloc.Filter(False, "test.py", 123, True)
523 self.assertEqual(f.inclusive, False)
524 self.assertEqual(f.filename_pattern, "test.py")
525 self.assertEqual(f.lineno, 123)
526 self.assertEqual(f.all_frames, True)
527
528 # parameters passed by keyword
529 f = tracemalloc.Filter(inclusive=False, filename_pattern="test.py", lineno=123, all_frames=True)
530 self.assertEqual(f.inclusive, False)
531 self.assertEqual(f.filename_pattern, "test.py")
532 self.assertEqual(f.lineno, 123)
533 self.assertEqual(f.all_frames, True)
534
535 # read-only attribute
536 self.assertRaises(AttributeError, setattr, f, "filename_pattern", "abc")
537
538 def test_filter_match(self):
539 # filter without line number
540 f = tracemalloc.Filter(True, "abc")
541 self.assertTrue(f._match_frame("abc", 0))
542 self.assertTrue(f._match_frame("abc", 5))
543 self.assertTrue(f._match_frame("abc", 10))
544 self.assertFalse(f._match_frame("12356", 0))
545 self.assertFalse(f._match_frame("12356", 5))
546 self.assertFalse(f._match_frame("12356", 10))
547
548 f = tracemalloc.Filter(False, "abc")
549 self.assertFalse(f._match_frame("abc", 0))
550 self.assertFalse(f._match_frame("abc", 5))
551 self.assertFalse(f._match_frame("abc", 10))
552 self.assertTrue(f._match_frame("12356", 0))
553 self.assertTrue(f._match_frame("12356", 5))
554 self.assertTrue(f._match_frame("12356", 10))
555
556 # filter with line number > 0
557 f = tracemalloc.Filter(True, "abc", 5)
558 self.assertFalse(f._match_frame("abc", 0))
559 self.assertTrue(f._match_frame("abc", 5))
560 self.assertFalse(f._match_frame("abc", 10))
561 self.assertFalse(f._match_frame("12356", 0))
562 self.assertFalse(f._match_frame("12356", 5))
563 self.assertFalse(f._match_frame("12356", 10))
564
565 f = tracemalloc.Filter(False, "abc", 5)
566 self.assertTrue(f._match_frame("abc", 0))
567 self.assertFalse(f._match_frame("abc", 5))
568 self.assertTrue(f._match_frame("abc", 10))
569 self.assertTrue(f._match_frame("12356", 0))
570 self.assertTrue(f._match_frame("12356", 5))
571 self.assertTrue(f._match_frame("12356", 10))
572
573 # filter with line number 0
574 f = tracemalloc.Filter(True, "abc", 0)
575 self.assertTrue(f._match_frame("abc", 0))
576 self.assertFalse(f._match_frame("abc", 5))
577 self.assertFalse(f._match_frame("abc", 10))
578 self.assertFalse(f._match_frame("12356", 0))
579 self.assertFalse(f._match_frame("12356", 5))
580 self.assertFalse(f._match_frame("12356", 10))
581
582 f = tracemalloc.Filter(False, "abc", 0)
583 self.assertFalse(f._match_frame("abc", 0))
584 self.assertTrue(f._match_frame("abc", 5))
585 self.assertTrue(f._match_frame("abc", 10))
586 self.assertTrue(f._match_frame("12356", 0))
587 self.assertTrue(f._match_frame("12356", 5))
588 self.assertTrue(f._match_frame("12356", 10))
589
590 def test_filter_match_filename(self):
591 def fnmatch(inclusive, filename, pattern):
592 f = tracemalloc.Filter(inclusive, pattern)
593 return f._match_frame(filename, 0)
594
595 self.assertTrue(fnmatch(True, "abc", "abc"))
596 self.assertFalse(fnmatch(True, "12356", "abc"))
597 self.assertFalse(fnmatch(True, "<unknown>", "abc"))
598
599 self.assertFalse(fnmatch(False, "abc", "abc"))
600 self.assertTrue(fnmatch(False, "12356", "abc"))
601 self.assertTrue(fnmatch(False, "<unknown>", "abc"))
602
603 def test_filter_match_filename_joker(self):
604 def fnmatch(filename, pattern):
605 filter = tracemalloc.Filter(True, pattern)
606 return filter._match_frame(filename, 0)
607
608 # empty string
609 self.assertFalse(fnmatch('abc', ''))
610 self.assertFalse(fnmatch('', 'abc'))
611 self.assertTrue(fnmatch('', ''))
612 self.assertTrue(fnmatch('', '*'))
613
614 # no *
615 self.assertTrue(fnmatch('abc', 'abc'))
616 self.assertFalse(fnmatch('abc', 'abcd'))
617 self.assertFalse(fnmatch('abc', 'def'))
618
619 # a*
620 self.assertTrue(fnmatch('abc', 'a*'))
621 self.assertTrue(fnmatch('abc', 'abc*'))
622 self.assertFalse(fnmatch('abc', 'b*'))
623 self.assertFalse(fnmatch('abc', 'abcd*'))
624
625 # a*b
626 self.assertTrue(fnmatch('abc', 'a*c'))
627 self.assertTrue(fnmatch('abcdcx', 'a*cx'))
628 self.assertFalse(fnmatch('abb', 'a*c'))
629 self.assertFalse(fnmatch('abcdce', 'a*cx'))
630
631 # a*b*c
632 self.assertTrue(fnmatch('abcde', 'a*c*e'))
633 self.assertTrue(fnmatch('abcbdefeg', 'a*bd*eg'))
634 self.assertFalse(fnmatch('abcdd', 'a*c*e'))
635 self.assertFalse(fnmatch('abcbdefef', 'a*bd*eg'))
636
637 # replace .pyc and .pyo suffix with .py
638 self.assertTrue(fnmatch('a.pyc', 'a.py'))
639 self.assertTrue(fnmatch('a.pyo', 'a.py'))
640 self.assertTrue(fnmatch('a.py', 'a.pyc'))
641 self.assertTrue(fnmatch('a.py', 'a.pyo'))
642
643 if os.name == 'nt':
644 # case insensitive
645 self.assertTrue(fnmatch('aBC', 'ABc'))
646 self.assertTrue(fnmatch('aBcDe', 'Ab*dE'))
647
648 self.assertTrue(fnmatch('a.pyc', 'a.PY'))
649 self.assertTrue(fnmatch('a.PYO', 'a.py'))
650 self.assertTrue(fnmatch('a.py', 'a.PYC'))
651 self.assertTrue(fnmatch('a.PY', 'a.pyo'))
652 else:
653 # case sensitive
654 self.assertFalse(fnmatch('aBC', 'ABc'))
655 self.assertFalse(fnmatch('aBcDe', 'Ab*dE'))
656
657 self.assertFalse(fnmatch('a.pyc', 'a.PY'))
658 self.assertFalse(fnmatch('a.PYO', 'a.py'))
659 self.assertFalse(fnmatch('a.py', 'a.PYC'))
660 self.assertFalse(fnmatch('a.PY', 'a.pyo'))
661
662 if os.name == 'nt':
663 # normalize alternate separator "/" to the standard separator "\"
664 self.assertTrue(fnmatch(r'a/b', r'a\b'))
665 self.assertTrue(fnmatch(r'a\b', r'a/b'))
666 self.assertTrue(fnmatch(r'a/b\c', r'a\b/c'))
667 self.assertTrue(fnmatch(r'a/b/c', r'a\b\c'))
668 else:
669 # there is no alternate separator
670 self.assertFalse(fnmatch(r'a/b', r'a\b'))
671 self.assertFalse(fnmatch(r'a\b', r'a/b'))
672 self.assertFalse(fnmatch(r'a/b\c', r'a\b/c'))
673 self.assertFalse(fnmatch(r'a/b/c', r'a\b\c'))
674
675 def test_filter_match_trace(self):
676 t1 = (("a.py", 2), ("b.py", 3))
677 t2 = (("b.py", 4), ("b.py", 5))
678 t3 = (("c.py", 5), ('<unknown>', 0))
679 unknown = (('<unknown>', 0),)
680
681 f = tracemalloc.Filter(True, "b.py", all_frames=True)
682 self.assertTrue(f._match_traceback(t1))
683 self.assertTrue(f._match_traceback(t2))
684 self.assertFalse(f._match_traceback(t3))
685 self.assertFalse(f._match_traceback(unknown))
686
687 f = tracemalloc.Filter(True, "b.py", all_frames=False)
688 self.assertFalse(f._match_traceback(t1))
689 self.assertTrue(f._match_traceback(t2))
690 self.assertFalse(f._match_traceback(t3))
691 self.assertFalse(f._match_traceback(unknown))
692
693 f = tracemalloc.Filter(False, "b.py", all_frames=True)
694 self.assertFalse(f._match_traceback(t1))
695 self.assertFalse(f._match_traceback(t2))
696 self.assertTrue(f._match_traceback(t3))
697 self.assertTrue(f._match_traceback(unknown))
698
699 f = tracemalloc.Filter(False, "b.py", all_frames=False)
700 self.assertTrue(f._match_traceback(t1))
701 self.assertFalse(f._match_traceback(t2))
702 self.assertTrue(f._match_traceback(t3))
703 self.assertTrue(f._match_traceback(unknown))
704
705 f = tracemalloc.Filter(False, "<unknown>", all_frames=False)
706 self.assertTrue(f._match_traceback(t1))
707 self.assertTrue(f._match_traceback(t2))
708 self.assertTrue(f._match_traceback(t3))
709 self.assertFalse(f._match_traceback(unknown))
710
711 f = tracemalloc.Filter(True, "<unknown>", all_frames=True)
712 self.assertFalse(f._match_traceback(t1))
713 self.assertFalse(f._match_traceback(t2))
714 self.assertTrue(f._match_traceback(t3))
715 self.assertTrue(f._match_traceback(unknown))
716
717 f = tracemalloc.Filter(False, "<unknown>", all_frames=True)
718 self.assertTrue(f._match_traceback(t1))
719 self.assertTrue(f._match_traceback(t2))
720 self.assertFalse(f._match_traceback(t3))
721 self.assertFalse(f._match_traceback(unknown))
722
723
724class TestCommandLine(unittest.TestCase):
725 def test_env_var(self):
726 # not tracing by default
727 code = 'import tracemalloc; print(tracemalloc.is_tracing())'
728 ok, stdout, stderr = assert_python_ok('-c', code)
729 stdout = stdout.rstrip()
730 self.assertEqual(stdout, b'False')
731
732 # PYTHON* environment varibles must be ignored when -E option is
733 # present
734 code = 'import tracemalloc; print(tracemalloc.is_tracing())'
735 ok, stdout, stderr = assert_python_ok('-E', '-c', code, PYTHONTRACEMALLOC='1')
736 stdout = stdout.rstrip()
737 self.assertEqual(stdout, b'False')
738
739 # tracing at startup
740 code = 'import tracemalloc; print(tracemalloc.is_tracing())'
741 ok, stdout, stderr = assert_python_ok('-c', code, PYTHONTRACEMALLOC='1')
742 stdout = stdout.rstrip()
743 self.assertEqual(stdout, b'True')
744
745 # start and set the number of frames
746 code = 'import tracemalloc; print(tracemalloc.get_traceback_limit())'
747 ok, stdout, stderr = assert_python_ok('-c', code, PYTHONTRACEMALLOC='10')
748 stdout = stdout.rstrip()
749 self.assertEqual(stdout, b'10')
750
751 def test_env_var_invalid(self):
752 for nframe in (-1, 0, 5000):
753 with self.subTest(nframe=nframe):
754 with support.SuppressCrashReport():
755 ok, stdout, stderr = assert_python_failure(
756 '-c', 'pass',
757 PYTHONTRACEMALLOC=str(nframe))
758 self.assertIn(b'PYTHONTRACEMALLOC must be an integer '
759 b'in range [1; 100]',
760 stderr)
761
762 def test_sys_xoptions(self):
763 for xoptions, nframe in (
764 ('tracemalloc', 1),
765 ('tracemalloc=1', 1),
766 ('tracemalloc=15', 15),
767 ):
768 with self.subTest(xoptions=xoptions, nframe=nframe):
769 code = 'import tracemalloc; print(tracemalloc.get_traceback_limit())'
770 ok, stdout, stderr = assert_python_ok('-X', xoptions, '-c', code)
771 stdout = stdout.rstrip()
772 self.assertEqual(stdout, str(nframe).encode('ascii'))
773
774 def test_sys_xoptions_invalid(self):
775 for nframe in (-1, 0, 5000):
776 with self.subTest(nframe=nframe):
777 with support.SuppressCrashReport():
778 args = ('-X', 'tracemalloc=%s' % nframe, '-c', 'pass')
779 ok, stdout, stderr = assert_python_failure(*args)
780 self.assertIn(b'-X tracemalloc=NFRAME: number of frame must '
781 b'be an integer in range [1; 100]',
782 stderr)
783
784
785def test_main():
786 support.run_unittest(
787 TestTracemallocEnabled,
788 TestSnapshot,
789 TestFilters,
790 TestCommandLine,
791 )
792
793if __name__ == "__main__":
794 test_main()