Align local monitoring events and final warning-format tests

Allow final exception-event masks locally and remove only the local event registration on DISABLE. Match final bytes unsupported-letter diagnostics. Copy the three affected canonical test definitions through update_lib from pinned final CPython.

Assisted-by: OpenAI Codex:model identifier unavailable
This commit is contained in:
dot committed 2026-10-13 10:47:47 +09:00
1 parent 7ecedcf187
commit ec206b1125
4 files changed
+50 -21

No files matched your search

+1 -1
View File
@@ -626,7 +626,7 @@ class FormatTest(unittest.TestCase):
with self.assertRaisesRegex(ValueError, error_msg):
f"{'x':zs}" # can't apply to string
error_msg = re.escape("unsupported format character 'z'")
error_msg = re.escape("unsupported format %z at position 0")
with self.assertRaisesRegex(ValueError, error_msg):
"%z.1f" % 0 # not allowed in old style string interpolation
with self.assertRaisesRegex(ValueError, error_msg):
+21 -10
View File
@@ -250,10 +250,23 @@ class FilterTests(BaseTest):
self.module.warn_explicit('msg', UserWarning, 'filename', 42,
module='package.module')
self.assertEqual(len(w), 1)
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module', 42)
self.assertEqual(len(w), 2)
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module.py', 42)
self.assertEqual(len(w), 3)
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module/__init__.py', 42)
self.assertEqual(len(w), 4)
with self.assertRaises(UserWarning):
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module', 42)
with self.assertRaises(UserWarning):
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module.py', 42)
self.module.warn_explicit('msg', UserWarning, '/path/to/package/module/__init__', 42)
if MS_WINDOWS:
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.PY', 42)
self.assertEqual(len(w), 5)
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module\__INIT__.PY', 42)
self.assertEqual(len(w), 6)
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.PYW', 42)
self.assertEqual(len(w), 7)
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module\__INIT__.PYW', 42)
self.assertEqual(len(w), 8)
with self.module.catch_warnings(record=True) as w:
self.module.simplefilter('error')
@@ -277,9 +290,8 @@ class FilterTests(BaseTest):
with self.assertRaises(UserWarning):
self.module.warn_explicit('msg', UserWarning, '/PATH/TO/PACKAGE/MODULE', 42)
if MS_WINDOWS:
if self.module is py_warnings:
self.module.warn_explicit('msg', UserWarning, r'/path/to/package/module.PY', 42)
self.assertEqual(len(w), 3)
self.module.warn_explicit('msg', UserWarning, r'/path/to/package/module.PY', 42)
self.assertEqual(len(w), 3)
with self.assertRaises(UserWarning):
self.module.warn_explicit('msg', UserWarning, r'/path/to/package/module/__init__.py', 42)
with self.assertRaises(UserWarning):
@@ -303,9 +315,8 @@ class FilterTests(BaseTest):
self.assertEqual(len(w), 1)
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.py', 42)
self.assertEqual(len(w), 2)
if self.module is py_warnings:
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.PY', 42)
self.assertEqual(len(w), 3)
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.PY', 42)
self.assertEqual(len(w), 3)
with self.assertRaises(UserWarning):
self.module.warn_explicit('msg', UserWarning, r'C:\path\to\package\module.pyw', 42)
with self.assertRaises(UserWarning):
@@ -400,7 +411,7 @@ class FilterTests(BaseTest):
def test_mutate_filter_list(self):
class X:
def match(self, a):
def match(self, a, start=0):
L[:] = []
L = [("default",X(),UserWarning,X(),0) for i in range(2)]
+11 -3
View File
@@ -73,8 +73,14 @@ fn spec_format_bytes(
spec: &CFormatSpec,
obj: PyObjectRef,
argument: FormatArgument<'_>,
format_start: usize,
) -> PyResult<Vec<u8>> {
match &spec.format_type {
CFormatType::Unsupported { ch, .. } if ch.to_char_lossy().is_ascii_alphabetic() => Err(vm
.new_value_error(format!(
"unsupported format %{} at position {format_start}",
ch.to_char_lossy(),
))),
CFormatType::Unsupported { ch, index } => Err(vm.new_value_error(format!(
"unsupported format character '{}' ({:#x}) at index {index}",
ch.to_char_lossy(),
@@ -407,7 +413,7 @@ pub(crate) fn cformat_bytes(
}
// dict
for (_, part) in format {
for (format_start, part) in format {
match part {
CFormatPart::Literal(literal) => result.extend(literal),
CFormatPart::Spec(CFormatSpecKeyed { mapping_key, spec }) => {
@@ -419,6 +425,7 @@ pub(crate) fn cformat_bytes(
&spec,
value,
FormatArgument::Mapping(key.as_object()),
format_start,
)?;
result.extend(part_result);
}
@@ -443,7 +450,7 @@ pub(crate) fn cformat_bytes(
let mut value_iter = value_iter.inspect(|_| argument_index.set(argument_index.get() + 1));
let is_tuple = values_obj.downcast_ref::<tuple::PyTuple>().is_some();
for (_, part) in format {
for (format_start, part) in format {
match part {
CFormatPart::Literal(literal) => result.extend(literal),
CFormatPart::Spec(CFormatSpecKeyed { mut spec, .. }) => {
@@ -464,7 +471,8 @@ pub(crate) fn cformat_bytes(
} else {
FormatArgument::Scalar
};
let part_result = spec_format_bytes(vm, &spec, value.to_owned(), argument)?;
let part_result =
spec_format_bytes(vm, &spec, value.to_owned(), argument, format_start)?;
result.extend(part_result);
}
}
+17 -7
View File
@@ -9,7 +9,8 @@ use std::collections::{HashMap, HashSet};
pub(crate) const TOOL_LIMIT: usize = 6;
const EVENTS_COUNT: usize = 19;
const LOCAL_EVENTS_COUNT: usize = 11;
const INSTRUMENTED_EVENTS_COUNT: usize = 11;
const LOCAL_EVENTS_COUNT: usize = 16;
const UNGROUPED_EVENTS_COUNT: usize = 18;
/// Event identifier (`PY_MONITORING_EVENT_*`), stored in `tstate->what_event`.
@@ -905,10 +906,21 @@ fn fire(
for (tool, cb) in callbacks {
let result = cb.call(args.clone(), vm)?;
if disable_sentinel.as_ref().is_some_and(|d| result.is(d)) {
// Only local events (event_id < LOCAL_EVENTS_COUNT) can be disabled.
// Non-local events (RAISE, EXCEPTION_HANDLED, PY_UNWIND, etc.)
// cannot be disabled per code object.
if event_id >= LOCAL_EVENTS_COUNT {
if event_id < INSTRUMENTED_EVENTS_COUNT {
let mut state = vm.state.monitoring.lock();
state.disabled.insert((code_id, offset as usize, tool));
} else if event_id < LOCAL_EVENTS_COUNT {
// Non-instrumented events disable their local registration
// for this code object, leaving global events active.
let mut state = vm.state.monitoring.lock();
if let Some(events) = state.local_events.get_mut(&(tool, code_id)) {
*events &= !event_mask;
if *events == 0 {
state.local_events.remove(&(tool, code_id));
}
}
update_events_mask(vm, &state);
} else {
// Remove the callback.
let mut state = vm.state.monitoring.lock();
state.callbacks.remove(&(tool, event_id));
@@ -917,8 +929,6 @@ fn fire(
EVENT_NAMES[event_id]
)));
}
let mut state = vm.state.monitoring.lock();
state.disabled.insert((code_id, offset as usize, tool));
}
}
Ok(())