Skip to content

Commit ffb3312

Browse files
ErotemicTTsangSC
andauthored
Update ci for 314 (#369)
* Update xcookie * Actually turn on 314 wheels * Partial fix for 3.14 compat issues line_profiler/_line_profiler.pyx::_SysMonitoringState.register() Updated implementation because of side effects of `sys.monitoring.free_tool_id()` in Python 3.14.0a1+ * Fix by removing `sys.monitoring.free_tool_id()` line_profiler/_line_profiler.pyx _code_replace() Now copying the `sys.monitoring` events of the old code object over _SysMonitoringState register() - Rolled back changes since the last commit; no longer double-setting the callbacks - No longer calling `sys.monitoring.free_tool_id()` at all to avoid unsetting local events - No longer overwriting the tool name with `'line_profiler'` if an existing tool is already using `sys.monitoring.PROFILER_ID` deregister() Updated implementation to avoid calling `sys.monitoring.free_tool_id()` * Added test: presevation of code-local events * Update line_profiler/_line_profiler.pyx * Update line_profiler/_line_profiler.pyx * Add coverage core environ * Set `${COVERAGE_CORE}` when running `pytest` --------- Co-authored-by: Terence S.-C. Tsang <t.tsang.sci@gmail.com>
1 parent 608a663 commit ffb3312

8 files changed

Lines changed: 170 additions & 42 deletions

File tree

.github/workflows/tests.yml

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ jobs:
2121
runs-on: ubuntu-latest
2222
steps:
2323
- name: Checkout source
24-
uses: actions/checkout@v4.1.1
24+
uses: actions/checkout@v4.2.2
2525
- name: Set up Python 3.13 for linting
26-
uses: actions/setup-python@v5.1.1
26+
uses: actions/setup-python@v5.6.0
2727
with:
2828
python-version: '3.13'
2929
- name: Install dependencies
@@ -49,9 +49,9 @@ jobs:
4949
runs-on: ubuntu-latest
5050
steps:
5151
- name: Checkout source
52-
uses: actions/checkout@v4.1.1
52+
uses: actions/checkout@v4.2.2
5353
- name: Set up Python 3.13
54-
uses: actions/setup-python@v5.1.1
54+
uses: actions/setup-python@v5.6.0
5555
with:
5656
python-version: '3.13'
5757
- name: Upgrade pip
@@ -71,6 +71,11 @@ jobs:
7171
ls -al wheelhouse
7272
python -m uv pip install wheelhouse/line_profiler*.tar.gz -v
7373
- name: Test minimal loose sdist
74+
env:
75+
# So far not needed, but once we bump to 3.14 this needs to be
76+
# set whenever `pytest` is run with `coverage`
77+
# (see the `test_binpy_wheels` jobs)
78+
COVERAGE_CORE: ctrace
7479
run: |-
7580
pwd
7681
ls -al
@@ -85,6 +90,8 @@ jobs:
8590
python -m pytest --verbose --cov=line_profiler $MOD_DPATH ../tests
8691
cd ..
8792
- name: Test full loose sdist
93+
env:
94+
COVERAGE_CORE: ctrace
8895
run: |-
8996
pwd
9097
ls -al
@@ -130,7 +137,7 @@ jobs:
130137
- auto
131138
steps:
132139
- name: Checkout source
133-
uses: actions/checkout@v4.1.1
140+
uses: actions/checkout@v4.2.2
134141
- name: Enable MSVC 64bit
135142
uses: ilammy/msvc-dev-cmd@v1
136143
if: matrix.os == 'windows-latest' && ${{ contains(matrix.cibw_skip, '*-win32') }}
@@ -140,7 +147,7 @@ jobs:
140147
with:
141148
platforms: all
142149
- name: Build binary wheels
143-
uses: pypa/cibuildwheel@v2.21.0
150+
uses: pypa/cibuildwheel@v3.1.2
144151
with:
145152
output-dir: wheelhouse
146153
config-file: pyproject.toml
@@ -153,7 +160,7 @@ jobs:
153160
shell: bash
154161
run: ls -la wheelhouse
155162
- name: Set up Python 3.13 to combine coverage
156-
uses: actions/setup-python@v5.1.1
163+
uses: actions/setup-python@v5.6.0
157164
if: runner.os == 'Linux'
158165
with:
159166
python-version: '3.13'
@@ -172,7 +179,7 @@ jobs:
172179
echo '### The cwd should now have a coverage.xml'
173180
ls -altr
174181
pwd
175-
- uses: codecov/codecov-action@v4.5.0
182+
- uses: codecov/codecov-action@v5.4.3
176183
name: Codecov Upload
177184
env:
178185
HAVE_CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN != '' }}
@@ -181,7 +188,7 @@ jobs:
181188
with:
182189
file: ./coverage.xml
183190
token: ${{ secrets.CODECOV_TOKEN }}
184-
- uses: codecov/codecov-action@v4.5.0
191+
- uses: codecov/codecov-action@v5.4.3
185192
name: Codecov Upload
186193
with:
187194
file: ./coverage.xml
@@ -264,6 +271,10 @@ jobs:
264271
install-extras: tests,optional
265272
os: ubuntu-latest
266273
arch: auto
274+
- python-version: 3.14.0-rc.1
275+
install-extras: tests,optional
276+
os: ubuntu-latest
277+
arch: auto
267278
- python-version: '3.8'
268279
install-extras: tests,optional
269280
os: macOS-latest
@@ -288,6 +299,10 @@ jobs:
288299
install-extras: tests,optional
289300
os: macOS-latest
290301
arch: auto
302+
- python-version: 3.14.0-rc.1
303+
install-extras: tests,optional
304+
os: macOS-latest
305+
arch: auto
291306
- python-version: '3.8'
292307
install-extras: tests,optional
293308
os: windows-latest
@@ -312,9 +327,13 @@ jobs:
312327
install-extras: tests,optional
313328
os: windows-latest
314329
arch: auto
330+
- python-version: 3.14.0-rc.1
331+
install-extras: tests,optional
332+
os: windows-latest
333+
arch: auto
315334
steps:
316335
- name: Checkout source
317-
uses: actions/checkout@v4.1.1
336+
uses: actions/checkout@v4.2.2
318337
- name: Enable MSVC 64bit
319338
uses: ilammy/msvc-dev-cmd@v1
320339
if: matrix.os == 'windows-latest'
@@ -324,7 +343,7 @@ jobs:
324343
with:
325344
platforms: all
326345
- name: Setup Python
327-
uses: actions/setup-python@v5.1.1
346+
uses: actions/setup-python@v5.6.0
328347
with:
329348
python-version: ${{ matrix.python-version }}
330349
- uses: actions/download-artifact@v4.1.8
@@ -354,9 +373,11 @@ jobs:
354373
")
355374
export MOD_VERSION=$(python -c "if 1:
356375
from pkginfo import Wheel, SDist
376+
import pathlib
357377
fpath = '$WHEEL_FPATH'
358378
cls = Wheel if fpath.endswith('.whl') else SDist
359-
print(cls(fpath).version)
379+
item = cls(fpath)
380+
print(item.version)
360381
")
361382
echo "WHEEL_FPATH=$WHEEL_FPATH"
362383
echo "INSTALL_EXTRAS=$INSTALL_EXTRAS"
@@ -367,6 +388,7 @@ jobs:
367388
shell: bash
368389
env:
369390
CI_PYTHON_VERSION: py${{ matrix.python-version }}
391+
COVERAGE_CORE: ctrace
370392
run: |-
371393
echo "Creating test sandbox directory"
372394
export WORKSPACE_DNAME="testdir_${CI_PYTHON_VERSION}_${GITHUB_RUN_ID}_${RUNNER_OS}"
@@ -409,7 +431,7 @@ jobs:
409431
echo '### The cwd should now have a coverage.xml'
410432
ls -altr
411433
pwd
412-
- uses: codecov/codecov-action@v4.5.0
434+
- uses: codecov/codecov-action@v5.4.3
413435
name: Codecov Upload
414436
with:
415437
file: ./coverage.xml
@@ -423,7 +445,7 @@ jobs:
423445
- build_binpy_wheels
424446
steps:
425447
- name: Checkout source
426-
uses: actions/checkout@v4.1.1
448+
uses: actions/checkout@v4.2.2
427449
- uses: actions/download-artifact@v4.1.8
428450
name: Download wheels
429451
with:
@@ -499,7 +521,7 @@ jobs:
499521
- build_binpy_wheels
500522
steps:
501523
- name: Checkout source
502-
uses: actions/checkout@v4.1.1
524+
uses: actions/checkout@v4.2.2
503525
- uses: actions/download-artifact@v4.1.8
504526
name: Download wheels
505527
with:
@@ -576,7 +598,7 @@ jobs:
576598
- live_deploy
577599
steps:
578600
- name: Checkout source
579-
uses: actions/checkout@v4.1.1
601+
uses: actions/checkout@v4.2.2
580602
- uses: actions/download-artifact@v4.1.8
581603
name: Download artifacts
582604
with:

build_wheels.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ fi
2121

2222
#pip wheel -w wheelhouse .
2323
# python -m build --wheel -o wheelhouse # line_profiler: +COMMENT_IF(binpy)
24-
cibuildwheel --config-file pyproject.toml --platform linux --arch x86_64 # line_profiler: +UNCOMMENT_IF(binpy)
24+
cibuildwheel --config-file pyproject.toml --platform linux --archs x86_64 # line_profiler: +UNCOMMENT_IF(binpy)

docs/source/conf.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,16 @@
1616
1717
# need to edit the conf.py
1818
19+
# Remove any old auto docs folder and regenerate it.
20+
rm -rf ~/code/line_profiler/docs/source/auto
1921
cd ~/code/line_profiler/docs
2022
sphinx-apidoc --private --separate --force --output-dir ~/code/line_profiler/docs/source/auto ~/code/line_profiler/line_profiler
23+
git add source/auto/*.rst
2124
2225
# Note: the module should importable before running this
2326
# (e.g. install it in developer mode or munge the PYTHONPATH)
2427
make html
2528
26-
git add source/auto/*.rst
27-
2829
Also:
2930
To turn on PR checks
3031
@@ -83,6 +84,7 @@
8384
push events,
8485
tag push events,
8586
merge request events
87+
release events
8688
8789
Click the "Add webhook" button.
8890

line_profiler/_line_profiler.pyx

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ cpdef _code_replace(func, co_code):
261261
code = func.__func__.__code__
262262
if hasattr(code, 'replace'):
263263
# python 3.8+
264-
code = code.replace(co_code=co_code)
264+
code = _copy_local_sysmon_events(code, code.replace(co_code=co_code))
265265
else:
266266
# python <3.8
267267
co = code
@@ -274,6 +274,30 @@ cpdef _code_replace(func, co_code):
274274
return code
275275

276276

277+
cpdef _copy_local_sysmon_events(old_code, new_code):
278+
"""
279+
Copy the local events from ``old_code`` over to ``new_code`` where
280+
appropriate.
281+
282+
Returns:
283+
code: ``new_code``
284+
"""
285+
try:
286+
mon = sys.monitoring
287+
except AttributeError: # Python < 3.12
288+
return new_code
289+
# Tool ids are integers in the range 0 to 5 inclusive.
290+
# https://docs.python.org/3/library/sys.monitoring.html#tool-identifiers
291+
NUM_TOOLS = 6
292+
for tool_id in range(NUM_TOOLS):
293+
try:
294+
events = mon.get_local_events(tool_id, old_code)
295+
mon.set_local_events(tool_id, new_code, events)
296+
except ValueError: # Tool ID not in use
297+
pass
298+
return new_code
299+
300+
277301
cpdef int _patch_events(int events, int before, int after):
278302
"""
279303
Patch ``events`` based on the differences between ``before`` and
@@ -371,22 +395,26 @@ cdef class _SysMonitoringState:
371395
mon = sys.monitoring
372396

373397
# Set prior state
398+
# Note: in 3.14.0a1+, calling `sys.monitoring.free_tool_id()`
399+
# also calls `.clear_tool_id()`, causing existing callbacks and
400+
# code-object-local events to be wiped... so don't call free.
401+
# this does have the side effect of not overriding the active
402+
# profiling tool name if one is already in use, but it's
403+
# probably better this way
374404
self.name = mon.get_tool(self.tool_id)
375405
if self.name is None:
376406
self.events = mon.events.NO_EVENTS
407+
mon.use_tool_id(self.tool_id, 'line_profiler')
377408
else:
378409
self.events = mon.get_events(self.tool_id)
379-
mon.free_tool_id(self.tool_id)
380-
mon.use_tool_id(self.tool_id, 'line_profiler')
381410
mon.set_events(self.tool_id, self.events | self.line_tracing_events)
382411

383-
# Register tracebacks
384-
for event_id, callback in [
385-
(mon.events.LINE, handle_line),
386-
(mon.events.PY_RETURN, handle_return),
387-
(mon.events.PY_YIELD, handle_yield),
388-
(mon.events.RAISE, handle_raise),
389-
(mon.events.RERAISE, handle_reraise)]:
412+
# Register tracebacks and remember the existing ones
413+
for event_id, callback in [(mon.events.LINE, handle_line),
414+
(mon.events.PY_RETURN, handle_return),
415+
(mon.events.PY_YIELD, handle_yield),
416+
(mon.events.RAISE, handle_raise),
417+
(mon.events.RERAISE, handle_reraise)]:
390418
self.callbacks[event_id] = mon.register_callback(
391419
self.tool_id, event_id, callback)
392420

@@ -395,12 +423,11 @@ cdef class _SysMonitoringState:
395423
cdef dict wrapped_callbacks = self.callbacks
396424

397425
# Restore prior state
398-
mon.free_tool_id(self.tool_id)
399-
if self.name is not None:
400-
mon.use_tool_id(self.tool_id, self.name)
401-
mon.set_events(self.tool_id, self.events)
402-
self.name = None
403-
self.events = mon.events.NO_EVENTS
426+
mon.set_events(self.tool_id, self.events)
427+
if self.name is None:
428+
mon.free_tool_id(self.tool_id)
429+
self.name = None
430+
self.events = mon.events.NO_EVENTS
404431

405432
# Reset tracebacks
406433
while wrapped_callbacks:
@@ -1120,7 +1147,7 @@ datamodel.html#user-defined-functions
11201147
# function (on some instance);
11211148
# (re-)pad with no-op
11221149
co_code = base_co_code + NOP_BYTES * npad
1123-
code = _code_replace(func, co_code=co_code)
1150+
code = _code_replace(func, co_code)
11241151
try:
11251152
func.__code__ = code
11261153
except AttributeError as e:
@@ -1157,6 +1184,9 @@ datamodel.html#user-defined-functions
11571184
code_hashes.append(code_hash)
11581185
# We can't replace the code object on Cython functions, but
11591186
# we can *store* a copy with the correct metadata
1187+
# Note: we don't use `_copy_local_sysmon_events()` here
1188+
# because Cython shim code objects don't support local
1189+
# events
11601190
code = code.replace(co_filename=cython_source)
11611191
profilers_to_update = {self}
11621192
# Update `._c_code_map` and `.code_hash_map` with the new line

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ omit =[
3030
]
3131

3232
[tool.cibuildwheel]
33-
build = "cp38-* cp39-* cp310-* cp311-* cp312-* cp313-*"
33+
build = "cp38-* cp39-* cp310-* cp311-* cp312-* cp313-* cp314-*"
3434
skip = ["*-win32", "cp313-musllinux_i686"]
3535
build-frontend = "build"
3636
build-verbosity = 1

requirements/build.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ scikit-build>=0.11.1
77
cmake>=3.21.2
88
ninja>=1.10.2
99

10-
cibuildwheel>=2.11.2 ; python_version < '4.0' and python_version >= '3.11' # Python 3.11+
11-
cibuildwheel>=2.11.2 ; python_version < '3.11' and python_version >= '3.10' # Python 3.10
12-
cibuildwheel>=2.11.2 ; python_version < '3.10' and python_version >= '3.9' # Python 3.9
13-
cibuildwheel>=2.11.2 ; python_version < '3.9' and python_version >= '3.8' # Python 3.8
10+
cibuildwheel>=3.1.2 ; python_version < '4.0' and python_version >= '3.11' # Python 3.11+
11+
cibuildwheel>=3.1.2 ; python_version < '3.11' and python_version >= '3.10' # Python 3.10
12+
cibuildwheel>=3.1.2 ; python_version < '3.10' and python_version >= '3.9' # Python 3.9
13+
cibuildwheel>=3.1.2 ; python_version < '3.9' and python_version >= '3.8' # Python 3.8

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ def run_cythonize(force=False):
304304
'Programming Language :: Python :: 3.11',
305305
'Programming Language :: Python :: 3.12',
306306
'Programming Language :: Python :: 3.13',
307+
'Programming Language :: Python :: 3.14',
307308
'Programming Language :: Python :: Implementation :: CPython',
308309
'Topic :: Software Development',
309310
]

0 commit comments

Comments
 (0)