Skip to content

Commit c4f6665

Browse files
fix either feature conditional compilation, again (#3834)
* fix `either` feature conditional compilation, again * test feature powerset in CI * install `rust-src` for feature powerset tests * review: adamreichold feedback * Fix one more case of redundant imports. * just check feature powerset for now --------- Co-authored-by: Adam Reichold <[email protected]>
1 parent 5ddcd46 commit c4f6665

File tree

6 files changed

+113
-15
lines changed

6 files changed

+113
-15
lines changed

.github/workflows/ci.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,22 @@ jobs:
480480
- run: python3 -m pip install --upgrade pip && pip install nox
481481
- run: python3 -m nox -s test-version-limits
482482

483+
check-feature-powerset:
484+
needs: [fmt]
485+
if: ${{ contains(github.event.pull_request.labels.*.name, 'CI-build-full') || (github.event_name != 'pull_request' && github.ref != 'refs/heads/main') }}
486+
runs-on: ubuntu-latest
487+
steps:
488+
- uses: actions/checkout@v4
489+
- uses: actions/setup-python@v5
490+
- uses: Swatinem/rust-cache@v2
491+
continue-on-error: true
492+
- uses: dtolnay/rust-toolchain@stable
493+
with:
494+
components: rust-src
495+
- uses: taiki-e/install-action@cargo-hack
496+
- run: python3 -m pip install --upgrade pip && pip install nox
497+
- run: python3 -m nox -s check-feature-powerset
498+
483499
conclusion:
484500
needs:
485501
- fmt
@@ -494,6 +510,7 @@ jobs:
494510
- emscripten
495511
- test-debug
496512
- test-version-limits
513+
- check-feature-powerset
497514
if: always()
498515
runs-on: ubuntu-latest
499516
steps:

Cargo.toml

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -107,20 +107,21 @@ nightly = []
107107
# This is mostly intended for testing purposes - activating *all* of these isn't particularly useful.
108108
full = [
109109
"macros",
110+
"gil-refs",
110111
# "multiple-pymethods", # TODO re-add this when MSRV is greater than 1.62
112+
"anyhow",
111113
"chrono",
112114
"chrono-tz",
113-
"num-bigint",
114-
"num-complex",
115-
"hashbrown",
116-
"smallvec",
117-
"serde",
118-
"indexmap",
119115
"either",
120-
"eyre",
121-
"anyhow",
122116
"experimental-inspect",
117+
"eyre",
118+
"hashbrown",
119+
"indexmap",
120+
"num-bigint",
121+
"num-complex",
123122
"rust_decimal",
123+
"serde",
124+
"smallvec",
124125
]
125126

126127
[workspace]

newsfragments/3834.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix compilation failure with `either` feature enabled without `experimental-inspect` enabled.

noxfile.py

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@
1313
import nox
1414
import nox.command
1515

16+
try:
17+
import tomllib as toml
18+
except ImportError:
19+
try:
20+
import toml
21+
except ImportError:
22+
toml = None
23+
1624
nox.options.sessions = ["test", "clippy", "rustfmt", "ruff", "docs"]
1725

1826

@@ -479,10 +487,8 @@ def check_changelog(session: nox.Session):
479487
def set_minimal_package_versions(session: nox.Session):
480488
from collections import defaultdict
481489

482-
try:
483-
import tomllib as toml
484-
except ImportError:
485-
import toml
490+
if toml is None:
491+
session.error("requires Python 3.11 or `toml` to be installed")
486492

487493
projects = (
488494
None,
@@ -593,6 +599,74 @@ def test_version_limits(session: nox.Session):
593599
_run_cargo(session, "check", env=env, expect_error=True)
594600

595601

602+
@nox.session(name="check-feature-powerset", venv_backend="none")
603+
def check_feature_powerset(session: nox.Session):
604+
if toml is None:
605+
session.error("requires Python 3.11 or `toml` to be installed")
606+
607+
with (PYO3_DIR / "Cargo.toml").open("rb") as cargo_toml_file:
608+
cargo_toml = toml.load(cargo_toml_file)
609+
610+
EXCLUDED_FROM_FULL = {
611+
"nightly",
612+
"extension-module",
613+
"full",
614+
"default",
615+
"auto-initialize",
616+
"generate-import-lib",
617+
"multiple-pymethods", # TODO add this after MSRV 1.62
618+
}
619+
620+
features = cargo_toml["features"]
621+
622+
full_feature = set(features["full"])
623+
abi3_features = {feature for feature in features if feature.startswith("abi3")}
624+
abi3_version_features = abi3_features - {"abi3"}
625+
626+
expected_full_feature = features.keys() - EXCLUDED_FROM_FULL - abi3_features
627+
628+
uncovered_features = expected_full_feature - full_feature
629+
if uncovered_features:
630+
session.error(
631+
f"some features missing from `full` meta feature: {uncovered_features}"
632+
)
633+
634+
experimental_features = {
635+
feature for feature in features if feature.startswith("experimental-")
636+
}
637+
full_without_experimental = full_feature - experimental_features
638+
639+
if len(experimental_features) >= 2:
640+
# justification: we always assume that feature within these groups are
641+
# mutually exclusive to simplify CI
642+
features_to_group = [
643+
full_without_experimental,
644+
experimental_features,
645+
]
646+
elif len(experimental_features) == 1:
647+
# no need to make an experimental features group
648+
features_to_group = [full_without_experimental]
649+
else:
650+
session.error("no experimental features exist; please simplify the noxfile")
651+
652+
features_to_skip = [
653+
*EXCLUDED_FROM_FULL,
654+
*abi3_version_features,
655+
]
656+
657+
comma_join = ",".join
658+
_run_cargo(
659+
session,
660+
"hack",
661+
"--feature-powerset",
662+
'--optional-deps=""',
663+
f'--skip="{comma_join(features_to_skip)}"',
664+
*(f"--group-features={comma_join(group)}" for group in features_to_group),
665+
"check",
666+
"--all-targets",
667+
)
668+
669+
596670
def _build_docs_for_ffi_check(session: nox.Session) -> None:
597671
# pyo3-ffi-check needs to scrape docs of pyo3-ffi
598672
_run_cargo(session, "doc", _FFI_CHECK, "-p", "pyo3-ffi", "--no-deps")

pytests/src/comparisons.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use pyo3::prelude::*;
2-
use pyo3::{types::PyModule, Python};
32

43
#[pyclass]
54
struct Eq(i64);

src/conversions/either.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,13 @@ where
9494
} else if let Ok(r) = obj.extract::<R>() {
9595
Ok(Either::Right(r))
9696
} else {
97-
let err_msg = format!("failed to convert the value to '{}'", Self::type_input());
97+
// TODO: it might be nice to use the `type_input()` name here once `type_input`
98+
// is not experimental, rather than the Rust type names.
99+
let err_msg = format!(
100+
"failed to convert the value to 'Union[{}, {}]'",
101+
std::any::type_name::<L>(),
102+
std::any::type_name::<R>()
103+
);
98104
Err(PyTypeError::new_err(err_msg))
99105
}
100106
}
@@ -134,7 +140,7 @@ mod tests {
134140
assert!(err.is_instance_of::<PyTypeError>(py));
135141
assert_eq!(
136142
err.to_string(),
137-
"TypeError: failed to convert the value to 'Union[int, float]'"
143+
"TypeError: failed to convert the value to 'Union[i32, f32]'"
138144
);
139145

140146
let obj_i = 42.to_object(py);

0 commit comments

Comments
 (0)