summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorScott Sanderson <ssanderson@quantopian.com>2018-06-01 20:36:23 (GMT)
committerBrett Cannon <brettcannon@users.noreply.github.com>2018-06-01 20:36:23 (GMT)
commit2e01b75884892d5aabdaab658fbd17f7a7ccebaa (patch)
tree2f518fe2d3d32e398d5ddbf3d10681f2396f4e3c
parent252f6abe0a9430f4ae7588c0cb50a6ff141bebe3 (diff)
downloadcpython-2e01b75884892d5aabdaab658fbd17f7a7ccebaa.zip
cpython-2e01b75884892d5aabdaab658fbd17f7a7ccebaa.tar.gz
cpython-2e01b75884892d5aabdaab658fbd17f7a7ccebaa.tar.bz2
bpo-29235: Make cProfile.Profile a context manager (GH-6808)
-rw-r--r--Doc/library/profile.rst10
-rwxr-xr-xLib/cProfile.py7
-rw-r--r--Lib/test/test_cprofile.py27
-rw-r--r--Misc/NEWS.d/next/Library/2018-05-14-15-01-55.bpo-29235.47Fzwt.rst8
4 files changed, 52 insertions, 0 deletions
diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst
index a6dc56f..5dc0b2f 100644
--- a/Doc/library/profile.rst
+++ b/Doc/library/profile.rst
@@ -262,6 +262,16 @@ functions:
ps.print_stats()
print(s.getvalue())
+ The :class:`Profile` class can also be used as a context manager (see
+ :ref:`typecontextmanager`)::
+
+ import cProfile
+
+ with cProfile.Profile() as pr:
+ # ... do something ...
+
+ pr.print_stats()
+
.. method:: enable()
Start collecting profiling data.
diff --git a/Lib/cProfile.py b/Lib/cProfile.py
index f166a1c..c804504 100755
--- a/Lib/cProfile.py
+++ b/Lib/cProfile.py
@@ -110,6 +110,13 @@ class Profile(_lsprof.Profiler):
finally:
self.disable()
+ def __enter__(self):
+ self.enable()
+ return self
+
+ def __exit__(self, *exc_info):
+ self.disable()
+
# ____________________________________________________________
def label(code):
diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py
index 1430d22..2fd67ee 100644
--- a/Lib/test/test_cprofile.py
+++ b/Lib/test/test_cprofile.py
@@ -49,6 +49,33 @@ class CProfileTest(ProfileTest):
# Test successful run
assert_python_ok('-m', 'cProfile', '-m', 'timeit', '-n', '1')
+ def test_profile_enable_disable(self):
+ prof = self.profilerclass()
+ # Make sure we clean ourselves up if the test fails for some reason.
+ self.addCleanup(prof.disable)
+
+ prof.enable()
+ self.assertIs(sys.getprofile(), prof)
+
+ prof.disable()
+ self.assertIs(sys.getprofile(), None)
+
+ def test_profile_as_context_manager(self):
+ prof = self.profilerclass()
+ # Make sure we clean ourselves up if the test fails for some reason.
+ self.addCleanup(prof.disable)
+
+ with prof as __enter__return_value:
+ # profile.__enter__ should return itself.
+ self.assertIs(prof, __enter__return_value)
+
+ # profile should be set as the global profiler inside the
+ # with-block
+ self.assertIs(sys.getprofile(), prof)
+
+ # profile shouldn't be set once we leave the with-block.
+ self.assertIs(sys.getprofile(), None)
+
def test_main():
run_unittest(CProfileTest)
diff --git a/Misc/NEWS.d/next/Library/2018-05-14-15-01-55.bpo-29235.47Fzwt.rst b/Misc/NEWS.d/next/Library/2018-05-14-15-01-55.bpo-29235.47Fzwt.rst
new file mode 100644
index 0000000..4618afc
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-05-14-15-01-55.bpo-29235.47Fzwt.rst
@@ -0,0 +1,8 @@
+The :class:`cProfile.Profile` class can now be used as a context manager.
+You can profile a block of code by running::
+
+ import cProfile
+ with cProfile.Profile() as profiler:
+ # ... code to be profiled ...
+
+Patch by Scott Sanderson.