Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ jobs:
run: nox -s rustfmt
- name: Check markdown formatting (rumdl)
run: nox -s rumdl
- name: Check `required-features` in Cargo.toml
run: nox -s check-test-features

resolve:
runs-on: ubuntu-latest
Expand Down
176 changes: 176 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,179 @@ bare_urls = "warn"

[lints]
workspace = true

# Many tests are only relevant on certain feature combinations;
# CI is marginally more efficient if `required-feature` is specified to avoid
# building and launching empty test suites.

[[test]]
name = "test_anyhow"
required-features = ["anyhow"]

[[test]]
name = "test_append_to_inittab"
required-features = ["macros"]

[[test]]
name = "test_arithmetics"
required-features = ["macros"]

[[test]]
name = "test_buffer"
required-features = ["macros"]

[[test]]
name = "test_buffer_protocol"
required-features = ["macros"]

[[test]]
name = "test_bytes"
required-features = ["macros"]

[[test]]
name = "test_class_attributes"
required-features = ["macros"]

[[test]]
name = "test_class_basics"
required-features = ["macros"]

[[test]]
name = "test_class_comparisons"
required-features = ["macros"]

[[test]]
name = "test_class_conversion"
required-features = ["macros"]

[[test]]
name = "test_class_formatting"
required-features = ["macros"]

[[test]]
name = "test_class_init"
required-features = ["macros"]

[[test]]
name = "test_class_new"
required-features = ["macros"]

[[test]]
name = "test_compile_error"
required-features = ["macros"]

[[test]]
name = "test_coroutine"
required-features = ["experimental-async"]

[[test]]
name = "test_declarative_module"
required-features = ["macros"]

[[test]]
name = "test_default_impls"
required-features = ["macros"]

[[test]]
name = "test_enum"
required-features = ["macros"]

[[test]]
name = "test_exceptions"
required-features = ["macros"]

[[test]]
name = "test_field_cfg"
required-features = ["macros"]

[[test]]
name = "test_frompy_intopy_roundtrip"
required-features = ["macros"]

[[test]]
name = "test_frompyobject"
required-features = ["macros"]

[[test]]
name = "test_gc"
required-features = ["macros"]

[[test]]
name = "test_getter_setter"
required-features = ["macros"]

[[test]]
name = "test_inheritance"
required-features = ["macros"]

[[test]]
name = "test_intopyobject"
required-features = ["macros"]

[[test]]
name = "test_macro_docs"
required-features = ["macros"]

[[test]]
name = "test_macros"
required-features = ["macros"]

[[test]]
name = "test_mapping"
required-features = ["macros"]

[[test]]
name = "test_methods"
required-features = ["macros"]

[[test]]
name = "test_module"
required-features = ["macros"]

[[test]]
name = "test_multiple_pymethods"
required-features = ["multiple-pymethods"]

[[test]]
name = "test_proto_methods"
required-features = ["macros"]

[[test]]
name = "test_pyfunction"
required-features = ["macros"]

[[test]]
name = "test_pyself"
required-features = ["macros"]

[[test]]
name = "test_sequence"
required-features = ["macros"]

[[test]]
name = "test_serde"
required-features = ["serde"]

[[test]]
name = "test_static_slots"
required-features = ["macros"]

[[test]]
name = "test_string"
required-features = ["macros"]

[[test]]
name = "test_super"
required-features = ["macros"]

[[test]]
name = "test_text_signature"
required-features = ["macros"]

[[test]]
name = "test_variable_arguments"
required-features = ["macros"]

[[test]]
name = "test_various"
required-features = ["macros"]
76 changes: 76 additions & 0 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,82 @@ def format_ffi_extern(session: nox.Session):
_format_ffi_extern(session)


_INNER_CFG_RE = re.compile(r"^#!\[\s*cfg\s*\((.*)\)\s*\]\s*$")
_FEATURE_RE = re.compile(r'feature\s*=\s*"([^"]+)"')


def _read_inner_cfgs(path: Path) -> List[str]:
"""Return the bodies of leading `#![cfg(...)]` inner attributes."""
cfgs: List[str] = []
with path.open("r", encoding="utf-8") as f:
for line in f:
stripped = line.strip()
if stripped == "" or stripped.startswith("//"):
continue
if not stripped.startswith("#!["):
break
m = _INNER_CFG_RE.match(stripped)
if m:
cfgs.append(m.group(1).strip())
return cfgs


@nox.session(name="check-test-features", venv_backend="none")
def check_test_features(session: nox.Session) -> None:
if toml is None:
session.error("requires Python 3.11 or `toml` to be installed")

expected_tests = {}
errors = []
for path in sorted((PYO3_DIR / "tests").glob("test_*.rs")):
features = set()
for body in _read_inner_cfgs(path):
feature = _FEATURE_RE.search(body)
if not feature:
continue

if feature.group(0) != body:
# To keep the this check simple, expect a single simple `cfg` per required feature
errors.append(
f'{path}: please use simple `#![cfg(feature = "...")] for feature predicates, got `#![cfg({body})]`'
)

features.add(feature.group(1))

if features:
expected_tests[path.stem] = sorted(features)

declared_tests = {
test["name"]: test
for test in toml.loads((PYO3_DIR / "Cargo.toml").read_text()).get("test", [])
}
all_test_names = sorted(expected_tests.keys() | declared_tests.keys())

for test in all_test_names:
if (expected := expected_tests.get(test)) is None:
errors.append(f"Remove [[test]] entry for {test!r} from Cargo.toml")
continue

declared = declared_tests.get(test, {})
declared_features = declared.get("required-features", [])

if set(declared_features) != set(expected):
errors.append(
f"""- Update Cargo.toml for test {test}:

[[test]]
name = "{test}"
required-features = [{", ".join(f'"{f}"' for f in expected)}]
"""
)

if errors:
print("Errors found in test feature predicates:", file=sys.stderr)
for error in errors:
print(" " + error, file=sys.stderr)
session.error()


@nox.session(name="address-sanitizer", venv_backend="none")
def address_sanitizer(session: nox.Session):
_run_cargo(
Expand Down
3 changes: 2 additions & 1 deletion tests/test_append_to_inittab.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![cfg(all(feature = "macros", not(PyPy)))]
#![cfg(feature = "macros")]
#![cfg(not(PyPy))]

use pyo3::prelude::*;

Expand Down
Loading
Loading