Skip to content

Commit 1daba38

Browse files
committed
Fix cron-ci failures: ctypes set_attr, missing features, __func__ AttributeError
- Use cls.set_attr() instead of cls.as_object().set_attr() in ctypes to ensure modified() is called and type cache stays valid - Add host_env feature to cron-ci.yaml for frozen_origname_matches test - Add stdio feature to cron-ci.yaml for encodings initialization - Fix __func__ AttributeError in custom_text_test_runner.py
1 parent add34a2 commit 1daba38

File tree

6 files changed

+42
-50
lines changed

6 files changed

+42
-50
lines changed

.github/workflows/cron-ci.yaml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ on:
1212
name: Periodic checks/tasks
1313

1414
env:
15-
CARGO_ARGS: --no-default-features --features stdlib,importlib,encodings,ssl-rustls,jit
15+
CARGO_ARGS: --no-default-features --features stdlib,importlib,stdio,encodings,ssl-rustls,jit,host_env
1616
PYTHON_VERSION: "3.14.3"
1717

1818
jobs:
@@ -35,7 +35,7 @@ jobs:
3535
python-version: ${{ env.PYTHON_VERSION }}
3636
- run: sudo apt-get update && sudo apt-get -y install lcov
3737
- name: Run cargo-llvm-cov with Rust tests.
38-
run: cargo llvm-cov --no-report --workspace --exclude rustpython_wasm --exclude rustpython-compiler-source --exclude rustpython-venvlauncher --verbose --no-default-features --features stdlib,importlib,encodings,ssl-rustls,jit
38+
run: cargo llvm-cov --no-report --workspace --exclude rustpython_wasm --exclude rustpython-compiler-source --exclude rustpython-venvlauncher --verbose --no-default-features --features stdlib,importlib,stdio,encodings,ssl-rustls,jit,host_env
3939
- name: Run cargo-llvm-cov with Python snippets.
4040
run: python scripts/cargo-llvm-cov.py
4141
continue-on-error: true
@@ -48,7 +48,7 @@ jobs:
4848
if: ${{ github.event_name != 'pull_request' }}
4949
uses: codecov/codecov-action@v5
5050
with:
51-
file: ./codecov.lcov
51+
files: ./codecov.lcov
5252

5353
testdata:
5454
name: Collect regression test data
@@ -170,12 +170,12 @@ jobs:
170170
- name: restructure generated files
171171
run: |
172172
cd ./target/criterion/reports
173-
find -type d -name cpython | xargs rm -rf
174-
find -type d -name rustpython | xargs rm -rf
175-
find -mindepth 2 -maxdepth 2 -name violin.svg | xargs rm -rf
176-
find -type f -not -name violin.svg | xargs rm -rf
177-
for file in $(find -type f -name violin.svg); do mv $file $(echo $file | sed -E "s_\./([^/]+)/([^/]+)/violin\.svg_./\1/\2.svg_"); done
178-
find -mindepth 2 -maxdepth 2 -type d | xargs rm -rf
173+
find . -type d -name cpython -print0 | xargs -0 rm -rf
174+
find . -type d -name rustpython -print0 | xargs -0 rm -rf
175+
find . -mindepth 2 -maxdepth 2 -name violin.svg -print0 | xargs -0 rm -rf
176+
find . -type f -not -name violin.svg -print0 | xargs -0 rm -rf
177+
find . -type f -name violin.svg -exec sh -c 'for file; do mv "$file" "$(echo "$file" | sed -E "s_\./([^/]+)/([^/]+)/violin\.svg_./\1/\2.svg_")"; done' _ {} +
178+
find . -mindepth 2 -maxdepth 2 -type d -print0 | xargs -0 rm -rf
179179
cd ..
180180
mv reports/* .
181181
rmdir reports

Lib/test/test_class.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,6 @@ def assertNotOrderable(self, a, b):
614614
with self.assertRaises(TypeError):
615615
a >= b
616616

617-
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON; AssertionError: 1543448294720 != 1543448295392")
618617
def testHashComparisonOfMethods(self):
619618
# Test comparison and hash of methods
620619
class A:

crates/vm/src/stdlib/_ctypes/base.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2554,11 +2554,10 @@ fn make_fields(
25542554
}
25552555

25562556
let new_descr = super::PyCField::new_from_field(fdescr, index, offset);
2557-
cls.as_object().set_attr(
2557+
cls.set_attr(
25582558
vm.ctx.intern_str(fname.as_wtf8()),
25592559
new_descr.to_pyobject(vm),
2560-
vm,
2561-
)?;
2560+
);
25622561
}
25632562

25642563
Ok(())
@@ -2597,11 +2596,10 @@ pub(super) fn make_anon_fields(cls: &Py<PyType>, vm: &VirtualMachine) -> PyResul
25972596

25982597
let mut new_descr = super::PyCField::new_from_field(descr, 0, 0);
25992598
new_descr.set_anonymous(true);
2600-
cls.as_object().set_attr(
2599+
cls.set_attr(
26012600
vm.ctx.intern_str(fname.as_wtf8()),
26022601
new_descr.to_pyobject(vm),
2603-
vm,
2604-
)?;
2602+
);
26052603

26062604
make_fields(cls, descr, descr.index, descr.offset, vm)?;
26072605
}

crates/vm/src/stdlib/_ctypes/structure.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -498,11 +498,7 @@ impl PyCStructType {
498498
};
499499

500500
// Set the CField as a class attribute
501-
cls.as_object().set_attr(
502-
vm.ctx.intern_str(name.clone()),
503-
c_field.to_pyobject(vm),
504-
vm,
505-
)?;
501+
cls.set_attr(vm.ctx.intern_str(name.clone()), c_field.to_pyobject(vm));
506502

507503
// Update tracking - don't advance offset for packed bitfields
508504
if field_advances_offset {

crates/vm/src/stdlib/_ctypes/union.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,7 @@ impl PyCUnionType {
312312
PyCField::new(name.clone(), field_type_ref, 0, size as isize, index)
313313
};
314314

315-
cls.as_object()
316-
.set_attr(vm.ctx.intern_str(name), c_field.to_pyobject(vm), vm)?;
315+
cls.set_attr(vm.ctx.intern_str(name), c_field.to_pyobject(vm));
317316
}
318317

319318
// Calculate total_align and aligned_size

extra_tests/custom_text_test_runner.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@
3838
from unittest.runner import registerResult, result
3939

4040

41+
def _get_method_dict(test):
42+
"""Get the __dict__ of the underlying function for a test method.
43+
44+
Works for both bound methods (__func__.__dict__) and plain functions.
45+
"""
46+
method = getattr(test, test._testMethodName)
47+
func = getattr(method, "__func__", method)
48+
return func.__dict__
49+
50+
4151
class TablePrinter(object):
4252
# Modified from https://github.com/agramian/table-printer, same license as above
4353
"Print a list of dicts as a table"
@@ -325,9 +335,7 @@ def startTest(self, test):
325335
self.stream.writeln("TEST SUITE: %s" % self.suite)
326336
self.stream.writeln("Description: %s" % self.getSuiteDescription(test))
327337
try:
328-
name_override = getattr(test, test._testMethodName).__func__.__dict__[
329-
"test_case_name"
330-
]
338+
name_override = _get_method_dict(test)["test_case_name"]
331339
except:
332340
name_override = None
333341
self.case = name_override if name_override else self.case
@@ -345,7 +353,11 @@ def startTest(self, test):
345353
self.results["suites"][self.suite_number] = {
346354
"name": self.suite,
347355
"class": test.__class__.__name__,
348-
"module": re.compile(".* \((.*)\)").match(str(test)).group(1),
356+
"module": (
357+
m.group(1)
358+
if (m := re.compile(r".* \((.*)\)").match(str(test)))
359+
else str(test)
360+
),
349361
"description": self.getSuiteDescription(test),
350362
"cases": {},
351363
"used_case_names": {},
@@ -380,34 +392,22 @@ def startTest(self, test):
380392
if "test_type" in getattr(
381393
test, test._testMethodName
382394
).__func__.__dict__ and set([s.lower() for s in self.test_types]) == set(
383-
[
384-
s.lower()
385-
for s in getattr(test, test._testMethodName).__func__.__dict__[
386-
"test_type"
387-
]
388-
]
395+
[s.lower() for s in _get_method_dict(test)["test_type"]]
389396
):
390397
pass
391398
else:
392-
getattr(test, test._testMethodName).__func__.__dict__[
393-
"__unittest_skip_why__"
394-
] = 'Test run specified to only run tests of type "%s"' % ",".join(
395-
self.test_types
399+
_get_method_dict(test)["__unittest_skip_why__"] = (
400+
'Test run specified to only run tests of type "%s"'
401+
% ",".join(self.test_types)
396402
)
397-
getattr(test, test._testMethodName).__func__.__dict__[
398-
"__unittest_skip__"
399-
] = True
400-
if "skip_device" in getattr(test, test._testMethodName).__func__.__dict__:
401-
for device in getattr(test, test._testMethodName).__func__.__dict__[
402-
"skip_device"
403-
]:
403+
_get_method_dict(test)["__unittest_skip__"] = True
404+
if "skip_device" in _get_method_dict(test):
405+
for device in _get_method_dict(test)["skip_device"]:
404406
if self.config and device.lower() in self.config["device_name"].lower():
405-
getattr(test, test._testMethodName).__func__.__dict__[
406-
"__unittest_skip_why__"
407-
] = "Test is marked to be skipped on %s" % device
408-
getattr(test, test._testMethodName).__func__.__dict__[
409-
"__unittest_skip__"
410-
] = True
407+
_get_method_dict(test)["__unittest_skip_why__"] = (
408+
"Test is marked to be skipped on %s" % device
409+
)
410+
_get_method_dict(test)["__unittest_skip__"] = True
411411
break
412412

413413
def stopTest(self, test):

0 commit comments

Comments
 (0)