forked from pool/python-line_profiler
Compare commits
6 Commits
| Author | SHA256 | Date | |
|---|---|---|---|
| a313476683 | |||
| 83c7a1f81c | |||
| 441279412b | |||
| a4e2851fc6 | |||
| 1222d07288 | |||
| d4e46ccda1 |
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:aa56578b0ff5a756fe180b3fda7bd67c27bbd478b3d0124612d8cf00e4a21df2
|
|
||||||
size 78149
|
|
||||||
3
line_profiler-5.0.0.tar.gz
Normal file
3
line_profiler-5.0.0.tar.gz
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:a80f0afb05ba0d275d9dddc5ff97eab637471167ff3e66dcc7d135755059398c
|
||||||
|
size 376919
|
||||||
46
no-python-in-path.patch
Normal file
46
no-python-in-path.patch
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
Index: line_profiler-5.0.0/line_profiler/cli_utils.py
|
||||||
|
===================================================================
|
||||||
|
--- line_profiler-5.0.0.orig/line_profiler/cli_utils.py
|
||||||
|
+++ line_profiler-5.0.0/line_profiler/cli_utils.py
|
||||||
|
@@ -188,9 +188,7 @@ def get_python_executable():
|
||||||
|
Command or path thereto corresponding to
|
||||||
|
:py:data:`sys.executable`.
|
||||||
|
"""
|
||||||
|
- if os.path.samefile(shutil.which('python'), sys.executable):
|
||||||
|
- return 'python'
|
||||||
|
- elif os.path.samefile(shutil.which('python3'), sys.executable):
|
||||||
|
+ if os.path.samefile(shutil.which('python3'), sys.executable):
|
||||||
|
return 'python3'
|
||||||
|
else:
|
||||||
|
return short_string_path(sys.executable)
|
||||||
|
Index: line_profiler-5.0.0/tests/test_kernprof.py
|
||||||
|
===================================================================
|
||||||
|
--- line_profiler-5.0.0.orig/tests/test_kernprof.py
|
||||||
|
+++ line_profiler-5.0.0/tests/test_kernprof.py
|
||||||
|
@@ -184,7 +184,7 @@ def test_kernprof_sys_restoration(capsys
|
||||||
|
{'^Output to stdout': True,
|
||||||
|
r"^Wrote .* '.*script\.py\.lprof'": True,
|
||||||
|
r'^Inspect results with:''\n'
|
||||||
|
- r'python -m line_profiler .*script\.py\.lprof': True,
|
||||||
|
+ r'.*python.* -m line_profiler .*script\.py\.lprof': True,
|
||||||
|
r'line_profiler\.autoprofile\.autoprofile'
|
||||||
|
r'\.run\(\n(?:.+,\n)*.*\)': False,
|
||||||
|
r'^\[kernprof .*\]': False,
|
||||||
|
@@ -194,7 +194,7 @@ def test_kernprof_sys_restoration(capsys
|
||||||
|
{'^Output to stdout': True,
|
||||||
|
r"^Wrote .* '.*script\.py\.lprof'": True,
|
||||||
|
r'^Inspect results with:''\n'
|
||||||
|
- r'python -m line_profiler .*script\.py\.lprof': False,
|
||||||
|
+ r'.*python.* -m line_profiler .*script\.py\.lprof': False,
|
||||||
|
r'line_profiler\.autoprofile\.autoprofile'
|
||||||
|
r'\.run\(\n(?:.+,\n)*.*\)': False,
|
||||||
|
r'^\[kernprof .*\]': False,
|
||||||
|
@@ -204,7 +204,7 @@ def test_kernprof_sys_restoration(capsys
|
||||||
|
{'^Output to stdout': True,
|
||||||
|
r"^\[kernprof .*\] Wrote .* '.*script\.py\.lprof'": True,
|
||||||
|
r'Inspect results with:''\n'
|
||||||
|
- r'python -m line_profiler .*script\.py\.lprof': False,
|
||||||
|
+ r'.*python.* -m line_profiler .*script\.py\.lprof': False,
|
||||||
|
r'line_profiler\.autoprofile\.autoprofile'
|
||||||
|
r'\.run\(\n(?:.+,\n)*.*\)': True,
|
||||||
|
r'^Function: main': True},
|
||||||
@@ -1,3 +1,60 @@
|
|||||||
|
-------------------------------------------------------------------
|
||||||
|
Wed Nov 5 03:33:11 UTC 2025 - Steve Kowalik <steven.kowalik@suse.com>
|
||||||
|
|
||||||
|
- Update to 5.0.0:
|
||||||
|
* ENH: Add support for sys.monitoring (Python >= 3.12)
|
||||||
|
* FIX: Fixed issue when calling kernprof with neither the -l nor -b flag
|
||||||
|
* FIX: Fixed auto-profiling of async function definitions
|
||||||
|
* ENH: Added CLI argument -m to kernprof for running a library module as
|
||||||
|
a script
|
||||||
|
* FIX: Fixed explicit profiling of class methods; added handling for
|
||||||
|
profiling static, bound, and partial methods, functools.partial objects,
|
||||||
|
(cached) properties, and async generator functions
|
||||||
|
* FIX: Fixed namespace bug when running kernprof -m on certain modules.
|
||||||
|
* FIX: Fixed @contextlib.contextmanager bug where the cleanup code (e.g.
|
||||||
|
restoration of sys attributes) is not run if exceptions occurred inside
|
||||||
|
the context
|
||||||
|
* ENH: Added CLI arguments -c to kernprof for (auto-)profiling
|
||||||
|
module/package/inline-script execution instead of that of script files;
|
||||||
|
passing '-' as the script-file name now also reads from and profiles
|
||||||
|
stdin
|
||||||
|
* ENH: In Python >=3.11, profiled objects are reported using their
|
||||||
|
qualified name.
|
||||||
|
* ENH: Highlight final summary using rich if enabled
|
||||||
|
* ENH: Made it possible to use multiple profiler instances simultaneously
|
||||||
|
* ENH: various improvements related to auto-profiling:
|
||||||
|
* FIX: Fixed line tracing for Cython code; superseded use of the legacy
|
||||||
|
tracing system with sys.monitoring
|
||||||
|
* FIX: Tracing-system-related fixes
|
||||||
|
* ENH: Added capability to parse TOML config files for defaults
|
||||||
|
- Add patch no-python-in-path.patch:
|
||||||
|
* Do not search the path for python.
|
||||||
|
- Add patch support-python314.patch:
|
||||||
|
* Support Python 3.14 sys.monitoring changes.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Sun May 4 08:46:41 UTC 2025 - Dirk Müller <dmueller@suse.com>
|
||||||
|
|
||||||
|
- update to 4.2.0:
|
||||||
|
* FIX: Fix issue with auto-profile of editable installs #279
|
||||||
|
* FIX: Lookup OP-codes instead of hard coding them #284
|
||||||
|
* CHANGE: Drop support for Python 3.6 and Python 3.7
|
||||||
|
* ENH: Add support for Python 3.13
|
||||||
|
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Tue Nov 26 23:59:21 UTC 2024 - Steve Kowalik <steven.kowalik@suse.com>
|
||||||
|
|
||||||
|
- Update to 4.1.3:
|
||||||
|
* FIX: duration summary now respects the stripzeros argument.
|
||||||
|
* FIX: minor test fixes.
|
||||||
|
* ENH: building osx wheels for x86 and arm64.
|
||||||
|
* ENH: documentation improvements.
|
||||||
|
* Invoke subshell with the current python interpreter
|
||||||
|
* Respect stripzeros in summary report
|
||||||
|
* Normalize path before comparison
|
||||||
|
- Switch to pyproject macros.
|
||||||
|
- Drop patch use-sys-executable-python.patch, included upstream.
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
Wed Mar 13 15:29:56 UTC 2024 - Dirk Müller <dmueller@suse.com>
|
Wed Mar 13 15:29:56 UTC 2024 - Dirk Müller <dmueller@suse.com>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# spec file for package python-line_profiler
|
# spec file for package python-line_profiler
|
||||||
#
|
#
|
||||||
# Copyright (c) 2024 SUSE LLC
|
# Copyright (c) 2025 SUSE LLC and contributors
|
||||||
#
|
#
|
||||||
# All modifications and additions to the file contributed by third parties
|
# All modifications and additions to the file contributed by third parties
|
||||||
# remain the property of their copyright owners, unless otherwise agreed
|
# remain the property of their copyright owners, unless otherwise agreed
|
||||||
@@ -16,24 +16,27 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
# missing ipython
|
%{?sle15_python_module_pythons}
|
||||||
%global skip_python39 1
|
|
||||||
Name: python-line_profiler
|
Name: python-line_profiler
|
||||||
Version: 4.1.2
|
Version: 5.0.0
|
||||||
Release: 0
|
Release: 0
|
||||||
Summary: Line-by-line profiler
|
Summary: Line-by-line profiler
|
||||||
License: BSD-3-Clause
|
License: BSD-3-Clause
|
||||||
URL: https://github.com/pyutils/line_profiler
|
URL: https://github.com/pyutils/line_profiler
|
||||||
Source: https://files.pythonhosted.org/packages/source/l/line_profiler/line_profiler-%{version}.tar.gz
|
Source: https://files.pythonhosted.org/packages/source/l/line_profiler/line_profiler-%{version}.tar.gz
|
||||||
# submitted upstream as https://github.com/pyutils/line_profiler/pull/252
|
# PATCH-FIX-OPENSUSE We do not ship bare python, so don't look for it
|
||||||
Patch1: use-sys-executable-python.patch
|
Patch0: no-python-in-path.patch
|
||||||
|
# PATCH-FIX-UPSTREAM gh#pyutils/line_profiler#369
|
||||||
|
Patch1: support-python314.patch
|
||||||
BuildRequires: %{python_module Cython}
|
BuildRequires: %{python_module Cython}
|
||||||
BuildRequires: %{python_module devel}
|
BuildRequires: %{python_module devel}
|
||||||
BuildRequires: %{python_module ipython}
|
BuildRequires: %{python_module ipython}
|
||||||
|
BuildRequires: %{python_module pip}
|
||||||
BuildRequires: %{python_module pytest}
|
BuildRequires: %{python_module pytest}
|
||||||
BuildRequires: %{python_module scikit-build}
|
BuildRequires: %{python_module scikit-build}
|
||||||
BuildRequires: %{python_module setuptools}
|
BuildRequires: %{python_module setuptools}
|
||||||
BuildRequires: %{python_module ubelt}
|
BuildRequires: %{python_module ubelt}
|
||||||
|
BuildRequires: %{python_module wheel}
|
||||||
BuildRequires: cmake
|
BuildRequires: cmake
|
||||||
BuildRequires: fdupes
|
BuildRequires: fdupes
|
||||||
BuildRequires: gcc-c++
|
BuildRequires: gcc-c++
|
||||||
@@ -60,10 +63,10 @@ function-level profiling tools in the Python standard library.
|
|||||||
export CFLAGS="%{optflags} -fno-strict-aliasing"
|
export CFLAGS="%{optflags} -fno-strict-aliasing"
|
||||||
# remove shebangs
|
# remove shebangs
|
||||||
sed -i '1{/env python/d}' line_profiler/line_profiler.py kernprof.py
|
sed -i '1{/env python/d}' line_profiler/line_profiler.py kernprof.py
|
||||||
%python_build
|
%pyproject_wheel
|
||||||
|
|
||||||
%install
|
%install
|
||||||
%python_install
|
%pyproject_install
|
||||||
%python_clone -a %{buildroot}%{_bindir}/kernprof
|
%python_clone -a %{buildroot}%{_bindir}/kernprof
|
||||||
%python_compileall
|
%python_compileall
|
||||||
%python_expand %fdupes %{buildroot}%{$python_sitearch}
|
%python_expand %fdupes %{buildroot}%{$python_sitearch}
|
||||||
@@ -75,16 +78,19 @@ sed -i '1{/env python/d}' line_profiler/line_profiler.py kernprof.py
|
|||||||
%python_uninstall_alternative kernprof
|
%python_uninstall_alternative kernprof
|
||||||
|
|
||||||
%check
|
%check
|
||||||
# test_cli needs ubelt, which we don't have and which is needed just for tests
|
export PATH=%{buildroot}%{_bindir}:$PATH
|
||||||
%pytest_arch -k "not test_cli" tests
|
mv line_profiler line_profiler-do-not-import
|
||||||
|
# cython_examples not shipped
|
||||||
|
%pytest_arch -k 'not cython_source'
|
||||||
|
mv line_profiler-do-not-import line_profiler
|
||||||
|
|
||||||
%files %{python_files}
|
%files %{python_files}
|
||||||
%doc README.rst
|
%doc README.rst
|
||||||
%license LICENSE.txt LICENSE_Python.txt
|
%license LICENSE.txt LICENSE_Python.txt
|
||||||
%python_alternative %{_bindir}/kernprof
|
%python_alternative %{_bindir}/kernprof
|
||||||
%{python_sitearch}/line_profiler
|
%{python_sitearch}/line_profiler
|
||||||
%{python_sitearch}/line_profiler-%{version}*-info
|
%{python_sitearch}/line_profiler-%{version}.dist-info
|
||||||
%{python_sitearch}/kernprof.py*
|
%{python_sitearch}/kernprof.py
|
||||||
%pycache_only %{python_sitearch}/__pycache__/kernprof*
|
%pycache_only %{python_sitearch}/__pycache__/kernprof.*.pyc
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
|||||||
258
support-python314.patch
Normal file
258
support-python314.patch
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
From 0b32904897bff5d91886cf2476e3bb98638cb31e Mon Sep 17 00:00:00 2001
|
||||||
|
From: joncrall <erotemic@gmail.com>
|
||||||
|
Date: Tue, 29 Jul 2025 18:35:33 -0400
|
||||||
|
Subject: [PATCH 1/9] Update xcookie
|
||||||
|
|
||||||
|
---
|
||||||
|
.github/workflows/tests.yml | 46 ++++++++++++++++++++++++-------------
|
||||||
|
docs/source/conf.py | 6 +++--
|
||||||
|
2 files changed, 34 insertions(+), 18 deletions(-)
|
||||||
|
|
||||||
|
Index: line_profiler-5.0.0/pyproject.toml
|
||||||
|
===================================================================
|
||||||
|
--- line_profiler-5.0.0.orig/pyproject.toml
|
||||||
|
+++ line_profiler-5.0.0/pyproject.toml
|
||||||
|
@@ -30,7 +30,7 @@ omit =[
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.cibuildwheel]
|
||||||
|
-build = "cp38-* cp39-* cp310-* cp311-* cp312-* cp313-*"
|
||||||
|
+build = "cp38-* cp39-* cp310-* cp311-* cp312-* cp313-* cp314-*"
|
||||||
|
skip = ["*-win32", "cp313-musllinux_i686"]
|
||||||
|
build-frontend = "build"
|
||||||
|
build-verbosity = 1
|
||||||
|
Index: line_profiler-5.0.0/requirements/build.txt
|
||||||
|
===================================================================
|
||||||
|
--- line_profiler-5.0.0.orig/requirements/build.txt
|
||||||
|
+++ line_profiler-5.0.0/requirements/build.txt
|
||||||
|
@@ -7,7 +7,7 @@ scikit-build>=0.11.1
|
||||||
|
cmake>=3.21.2
|
||||||
|
ninja>=1.10.2
|
||||||
|
|
||||||
|
-cibuildwheel>=2.11.2 ; python_version < '4.0' and python_version >= '3.11' # Python 3.11+
|
||||||
|
-cibuildwheel>=2.11.2 ; python_version < '3.11' and python_version >= '3.10' # Python 3.10
|
||||||
|
-cibuildwheel>=2.11.2 ; python_version < '3.10' and python_version >= '3.9' # Python 3.9
|
||||||
|
-cibuildwheel>=2.11.2 ; python_version < '3.9' and python_version >= '3.8' # Python 3.8
|
||||||
|
+cibuildwheel>=3.1.2 ; python_version < '4.0' and python_version >= '3.11' # Python 3.11+
|
||||||
|
+cibuildwheel>=3.1.2 ; python_version < '3.11' and python_version >= '3.10' # Python 3.10
|
||||||
|
+cibuildwheel>=3.1.2 ; python_version < '3.10' and python_version >= '3.9' # Python 3.9
|
||||||
|
+cibuildwheel>=3.1.2 ; python_version < '3.9' and python_version >= '3.8' # Python 3.8
|
||||||
|
Index: line_profiler-5.0.0/setup.py
|
||||||
|
===================================================================
|
||||||
|
--- line_profiler-5.0.0.orig/setup.py
|
||||||
|
+++ line_profiler-5.0.0/setup.py
|
||||||
|
@@ -304,6 +304,7 @@ if __name__ == '__main__':
|
||||||
|
'Programming Language :: Python :: 3.11',
|
||||||
|
'Programming Language :: Python :: 3.12',
|
||||||
|
'Programming Language :: Python :: 3.13',
|
||||||
|
+ 'Programming Language :: Python :: 3.14',
|
||||||
|
'Programming Language :: Python :: Implementation :: CPython',
|
||||||
|
'Topic :: Software Development',
|
||||||
|
]
|
||||||
|
Index: line_profiler-5.0.0/line_profiler/_line_profiler.pyx
|
||||||
|
===================================================================
|
||||||
|
--- line_profiler-5.0.0.orig/line_profiler/_line_profiler.pyx
|
||||||
|
+++ line_profiler-5.0.0/line_profiler/_line_profiler.pyx
|
||||||
|
@@ -260,7 +260,7 @@ cpdef _code_replace(func, co_code):
|
||||||
|
code = func.__func__.__code__
|
||||||
|
if hasattr(code, 'replace'):
|
||||||
|
# python 3.8+
|
||||||
|
- code = code.replace(co_code=co_code)
|
||||||
|
+ code = _copy_local_sysmon_events(code, code.replace(co_code=co_code))
|
||||||
|
else:
|
||||||
|
# python <3.8
|
||||||
|
co = code
|
||||||
|
@@ -273,6 +273,30 @@ cpdef _code_replace(func, co_code):
|
||||||
|
return code
|
||||||
|
|
||||||
|
|
||||||
|
+cpdef _copy_local_sysmon_events(old_code, new_code):
|
||||||
|
+ """
|
||||||
|
+ Copy the local events from ``old_code`` over to ``new_code`` where
|
||||||
|
+ appropriate.
|
||||||
|
+
|
||||||
|
+ Returns:
|
||||||
|
+ code: ``new_code``
|
||||||
|
+ """
|
||||||
|
+ try:
|
||||||
|
+ mon = sys.monitoring
|
||||||
|
+ except AttributeError: # Python < 3.12
|
||||||
|
+ return new_code
|
||||||
|
+ # Tool ids are integers in the range 0 to 5 inclusive.
|
||||||
|
+ # https://docs.python.org/3/library/sys.monitoring.html#tool-identifiers
|
||||||
|
+ NUM_TOOLS = 6
|
||||||
|
+ for tool_id in range(NUM_TOOLS):
|
||||||
|
+ try:
|
||||||
|
+ events = mon.get_local_events(tool_id, old_code)
|
||||||
|
+ mon.set_local_events(tool_id, new_code, events)
|
||||||
|
+ except ValueError: # Tool ID not in use
|
||||||
|
+ pass
|
||||||
|
+ return new_code
|
||||||
|
+
|
||||||
|
+
|
||||||
|
cpdef int _patch_events(int events, int before, int after):
|
||||||
|
"""
|
||||||
|
Patch ``events`` based on the differences between ``before`` and
|
||||||
|
@@ -370,22 +394,26 @@ cdef class _SysMonitoringState:
|
||||||
|
mon = sys.monitoring
|
||||||
|
|
||||||
|
# Set prior state
|
||||||
|
+ # Note: in 3.14.0a1+, calling `sys.monitoring.free_tool_id()`
|
||||||
|
+ # also calls `.clear_tool_id()`, causing existing callbacks and
|
||||||
|
+ # code-object-local events to be wiped... so don't call free.
|
||||||
|
+ # this does have the side effect of not overriding the active
|
||||||
|
+ # profiling tool name if one is already in use, but it's
|
||||||
|
+ # probably better this way
|
||||||
|
self.name = mon.get_tool(self.tool_id)
|
||||||
|
if self.name is None:
|
||||||
|
self.events = mon.events.NO_EVENTS
|
||||||
|
+ mon.use_tool_id(self.tool_id, 'line_profiler')
|
||||||
|
else:
|
||||||
|
self.events = mon.get_events(self.tool_id)
|
||||||
|
- mon.free_tool_id(self.tool_id)
|
||||||
|
- mon.use_tool_id(self.tool_id, 'line_profiler')
|
||||||
|
mon.set_events(self.tool_id, self.events | self.line_tracing_events)
|
||||||
|
|
||||||
|
- # Register tracebacks
|
||||||
|
- for event_id, callback in [
|
||||||
|
- (mon.events.LINE, handle_line),
|
||||||
|
- (mon.events.PY_RETURN, handle_return),
|
||||||
|
- (mon.events.PY_YIELD, handle_yield),
|
||||||
|
- (mon.events.RAISE, handle_raise),
|
||||||
|
- (mon.events.RERAISE, handle_reraise)]:
|
||||||
|
+ # Register tracebacks and remember the existing ones
|
||||||
|
+ for event_id, callback in [(mon.events.LINE, handle_line),
|
||||||
|
+ (mon.events.PY_RETURN, handle_return),
|
||||||
|
+ (mon.events.PY_YIELD, handle_yield),
|
||||||
|
+ (mon.events.RAISE, handle_raise),
|
||||||
|
+ (mon.events.RERAISE, handle_reraise)]:
|
||||||
|
self.callbacks[event_id] = mon.register_callback(
|
||||||
|
self.tool_id, event_id, callback)
|
||||||
|
|
||||||
|
@@ -394,12 +422,11 @@ cdef class _SysMonitoringState:
|
||||||
|
cdef dict wrapped_callbacks = self.callbacks
|
||||||
|
|
||||||
|
# Restore prior state
|
||||||
|
- mon.free_tool_id(self.tool_id)
|
||||||
|
- if self.name is not None:
|
||||||
|
- mon.use_tool_id(self.tool_id, self.name)
|
||||||
|
- mon.set_events(self.tool_id, self.events)
|
||||||
|
- self.name = None
|
||||||
|
- self.events = mon.events.NO_EVENTS
|
||||||
|
+ mon.set_events(self.tool_id, self.events)
|
||||||
|
+ if self.name is None:
|
||||||
|
+ mon.free_tool_id(self.tool_id)
|
||||||
|
+ self.name = None
|
||||||
|
+ self.events = mon.events.NO_EVENTS
|
||||||
|
|
||||||
|
# Reset tracebacks
|
||||||
|
while wrapped_callbacks:
|
||||||
|
@@ -1118,7 +1145,7 @@ datamodel.html#user-defined-functions
|
||||||
|
# function (on some instance);
|
||||||
|
# (re-)pad with no-op
|
||||||
|
co_code = base_co_code + NOP_BYTES * npad
|
||||||
|
- code = _code_replace(func, co_code=co_code)
|
||||||
|
+ code = _code_replace(func, co_code)
|
||||||
|
try:
|
||||||
|
func.__code__ = code
|
||||||
|
except AttributeError as e:
|
||||||
|
@@ -1155,6 +1182,9 @@ datamodel.html#user-defined-functions
|
||||||
|
code_hashes.append(code_hash)
|
||||||
|
# We can't replace the code object on Cython functions, but
|
||||||
|
# we can *store* a copy with the correct metadata
|
||||||
|
+ # Note: we don't use `_copy_local_sysmon_events()` here
|
||||||
|
+ # because Cython shim code objects don't support local
|
||||||
|
+ # events
|
||||||
|
code = code.replace(co_filename=cython_source)
|
||||||
|
profilers_to_update = {self}
|
||||||
|
# Update `._c_code_map` and `.code_hash_map` with the new line
|
||||||
|
Index: line_profiler-5.0.0/tests/test_sys_monitoring.py
|
||||||
|
===================================================================
|
||||||
|
--- line_profiler-5.0.0.orig/tests/test_sys_monitoring.py
|
||||||
|
+++ line_profiler-5.0.0/tests/test_sys_monitoring.py
|
||||||
|
@@ -6,7 +6,7 @@ from functools import partial
|
||||||
|
from io import StringIO
|
||||||
|
from itertools import count
|
||||||
|
from types import CodeType, ModuleType
|
||||||
|
-from typing import (Any, Optional, Union,
|
||||||
|
+from typing import (Any, Optional, Union, Literal,
|
||||||
|
Callable, Generator,
|
||||||
|
Dict, FrozenSet, Tuple,
|
||||||
|
ClassVar)
|
||||||
|
@@ -754,3 +754,76 @@ def _test_callback_toggle_local_events_h
|
||||||
|
assert get_loop_hits() == nloop_before_disabling + nloop_after_reenabling
|
||||||
|
|
||||||
|
return n
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+@pytest.mark.parametrize('profile_when', ['before', 'after'])
|
||||||
|
+def test_local_event_preservation(
|
||||||
|
+ profile_when: Literal['before', 'after']) -> None:
|
||||||
|
+ """
|
||||||
|
+ Check that existing :py:mod:`sys.monitoring` code-local events are
|
||||||
|
+ preserved when a profiler swaps out the callable's code object.
|
||||||
|
+ """
|
||||||
|
+ prof = LineProfiler(wrap_trace=True)
|
||||||
|
+
|
||||||
|
+ @prof
|
||||||
|
+ def func0(n: int) -> int:
|
||||||
|
+ """
|
||||||
|
+ This function compiles down to the same bytecode as `func()` and
|
||||||
|
+ ensure that `prof` does bytecode padding with the latter later.
|
||||||
|
+ """
|
||||||
|
+ x = 0
|
||||||
|
+ for n in range(1, n + 1):
|
||||||
|
+ x += n
|
||||||
|
+ return x
|
||||||
|
+
|
||||||
|
+ def func(n: int) -> int:
|
||||||
|
+ x = 0
|
||||||
|
+ for n in range(1, n + 1):
|
||||||
|
+ x += n # Loop body
|
||||||
|
+ return x
|
||||||
|
+
|
||||||
|
+ def profile() -> None:
|
||||||
|
+ nonlocal code
|
||||||
|
+ nonlocal func
|
||||||
|
+ orig_code = func.__code__
|
||||||
|
+ orig_func, func = func, prof(func)
|
||||||
|
+ code = orig_func.__code__
|
||||||
|
+ assert code is not orig_code, (
|
||||||
|
+ '`line_profiler` didn\'t overwrite the function\'s code object')
|
||||||
|
+
|
||||||
|
+ lines, first_lineno = inspect.getsourcelines(func)
|
||||||
|
+ lineno_loop = first_lineno + next(
|
||||||
|
+ offset for offset, line in enumerate(lines)
|
||||||
|
+ if line.rstrip().endswith('# Loop body'))
|
||||||
|
+ names = {func.__name__, func.__qualname__}
|
||||||
|
+ code = func.__code__
|
||||||
|
+ callback = LineCallback(lambda code, _: code.co_name in names)
|
||||||
|
+
|
||||||
|
+ n = 17
|
||||||
|
+ try:
|
||||||
|
+ with ExitStack() as stack:
|
||||||
|
+ stack.enter_context(restore_events())
|
||||||
|
+ stack.enter_context(restore_events(code=code))
|
||||||
|
+ # Disable global line events, and enable local line events
|
||||||
|
+ disable_line_events()
|
||||||
|
+ if profile_when == 'before':
|
||||||
|
+ profile()
|
||||||
|
+ enable_line_events(code)
|
||||||
|
+ if profile_when != 'before':
|
||||||
|
+ # If we're here, the code object of `func()` is swapped
|
||||||
|
+ # out after code-local events have been registered to it
|
||||||
|
+ profile()
|
||||||
|
+ assert MON.get_current_callback() is callback
|
||||||
|
+ assert func(n) == n * (n + 1) // 2
|
||||||
|
+ assert MON.get_current_callback() is callback
|
||||||
|
+ print(callback.nhits)
|
||||||
|
+ assert callback.nhits[_line_profiler.label(code)][lineno_loop] == n
|
||||||
|
+ finally:
|
||||||
|
+ with StringIO() as sio:
|
||||||
|
+ prof.print_stats(sio)
|
||||||
|
+ output = sio.getvalue()
|
||||||
|
+ print(output)
|
||||||
|
+ line = next(line for line in output.splitlines()
|
||||||
|
+ if line.endswith('# Loop body'))
|
||||||
|
+ nhits = int(line.split()[1])
|
||||||
|
+ assert nhits == n
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
--- line_profiler-4.1.2/tests/test_complex_case.py
|
|
||||||
+++ line_profiler-4.1.2/tests/test_complex_case.py
|
|
||||||
@@ -20,7 +20,7 @@
|
|
||||||
Make sure the complex example script works without any profiling
|
|
||||||
"""
|
|
||||||
complex_fpath = get_complex_example_fpath()
|
|
||||||
- info = ub.cmd(f'python {complex_fpath}', shell=True, verbose=3, env=ub.udict(os.environ) | {'PROFILE_TYPE': 'none'})
|
|
||||||
+ info = ub.cmd(f'{sys.executable} {complex_fpath}', shell=True, verbose=3, env=ub.udict(os.environ) | {'PROFILE_TYPE': 'none'})
|
|
||||||
assert info.stdout == ''
|
|
||||||
info.check_returncode()
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user