Skip to content

Commit 7e37aec

Browse files
authored
Merge branch 'develop' into myrrc/duckdb-vortex-versoin
2 parents d83ecfc + 9fdaa38 commit 7e37aec

10 files changed

Lines changed: 119 additions & 38 deletions

File tree

‎scripts/tests/test_benchmark_reporting.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def load_compare_module() -> ModuleType:
2626
return module
2727

2828

29-
def load_random_access_split_module():
29+
def load_random_access_split_module() -> ModuleType:
3030
spec = importlib.util.spec_from_file_location("random_access_split", RANDOM_ACCESS_SPLIT_SCRIPT)
3131
assert spec is not None
3232
module = importlib.util.module_from_spec(spec)

‎scripts/tests/test_measurement_id.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def test_every_fact_table_is_covered() -> None:
6363
assert covered_tables == set(module.MEASUREMENT_ID_BY_TABLE)
6464

6565

66-
def test_random_access_open_mode_preserves_cached_ids_and_separates_reopen():
66+
def test_random_access_open_mode_preserves_cached_ids_and_separates_reopen() -> None:
6767
module = load_measurement_id_module()
6868
dimensions = {
6969
"commit_sha": "0123456789abcdef0123456789abcdef01234567",

‎vortex-cloud/src/opendal/cos.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use vortex_utils::aliases::hash_map::HashMap;
1313

1414
use crate::opendal::OpenDALStoreError;
1515
use crate::opendal::build_operator;
16+
use crate::opendal::property_as_bool;
1617
use crate::opendal::property_or_env;
1718
use crate::opendal::warn_on_unknown_properties;
1819

@@ -129,8 +130,7 @@ where
129130
&env_lookup,
130131
),
131132
root: properties.get("root").cloned(),
132-
disable_config_load: properties.get("disable_config_load").map(String::as_str)
133-
== Some("true"),
133+
disable_config_load: property_as_bool(properties, "disable_config_load"),
134134
})
135135
}
136136

‎vortex-cloud/src/opendal/mod.rs‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,26 @@ where
204204
properties.get(key).cloned().or_else(|| env_lookup(env_var))
205205
}
206206

207+
/// Take `key` from `properties` as a boolean, accepting the spellings `object_store` accepts in
208+
/// its own configuration: `1`/`true`/`on`/`yes`/`y` and their negatives, case-insensitively.
209+
///
210+
/// An absent key is `false`. A value that is not a boolean is warned about and read as `false`,
211+
/// which is how [`warn_on_unknown_properties`] already treats a key the service cannot use.
212+
#[cfg(any(feature = "cos", feature = "oss"))]
213+
pub(crate) fn property_as_bool(properties: &HashMap<String, String>, key: &str) -> bool {
214+
let Some(value) = properties.get(key) else {
215+
return false;
216+
};
217+
match value.trim().to_ascii_lowercase().as_str() {
218+
"1" | "true" | "on" | "yes" | "y" => true,
219+
"0" | "false" | "off" | "no" | "n" => false,
220+
_ => {
221+
warn!("ignoring OpenDAL store property {key}: `{value}` is not a boolean");
222+
false
223+
}
224+
}
225+
}
226+
207227
/// Log a warning for every property key the service does not recognize.
208228
#[cfg(any(feature = "cos", feature = "goosefs", feature = "oss"))]
209229
pub(crate) fn warn_on_unknown_properties(properties: &HashMap<String, String>, known: &[&str]) {
@@ -265,4 +285,38 @@ mod tests {
265285
);
266286
}
267287
}
288+
289+
/// The spellings `object_store` accepts for its own boolean configuration, so that the same
290+
/// property means the same thing whether a URL resolves to a native store or an OpenDAL one.
291+
/// Values reach us verbatim from the caller's property map, hence the case and whitespace
292+
/// cases; anything that is not a boolean stays `false` rather than becoming an error.
293+
#[cfg(any(feature = "cos", feature = "oss"))]
294+
#[rstest::rstest]
295+
#[case("true", true)]
296+
#[case("True", true)]
297+
#[case("TRUE", true)]
298+
#[case(" true ", true)]
299+
#[case("1", true)]
300+
#[case("on", true)]
301+
#[case("yes", true)]
302+
#[case("y", true)]
303+
#[case("false", false)]
304+
#[case("False", false)]
305+
#[case("0", false)]
306+
#[case("off", false)]
307+
#[case("no", false)]
308+
#[case("n", false)]
309+
#[case("maybe", false)]
310+
#[case("", false)]
311+
fn property_as_bool_matches_object_store(#[case] value: &str, #[case] expected: bool) {
312+
let mut props = HashMap::new();
313+
props.insert("skip_signature".to_string(), value.to_string());
314+
assert_eq!(property_as_bool(&props, "skip_signature"), expected);
315+
}
316+
317+
#[cfg(any(feature = "cos", feature = "oss"))]
318+
#[test]
319+
fn property_as_bool_is_false_when_absent() {
320+
assert!(!property_as_bool(&HashMap::new(), "skip_signature"));
321+
}
268322
}

‎vortex-cloud/src/opendal/oss.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use vortex_utils::aliases::hash_map::HashMap;
1313

1414
use crate::opendal::OpenDALStoreError;
1515
use crate::opendal::build_operator;
16+
use crate::opendal::property_as_bool;
1617
use crate::opendal::property_or_env;
1718
use crate::opendal::warn_on_unknown_properties;
1819

@@ -140,7 +141,7 @@ where
140141
&env_lookup,
141142
),
142143
root: properties.get("root").cloned(),
143-
skip_signature: properties.get("skip_signature").map(String::as_str) == Some("true"),
144+
skip_signature: property_as_bool(properties, "skip_signature"),
144145
})
145146
}
146147

‎vortex-ffi/cmake/tests/support.py‎

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,20 @@
1313
import textwrap
1414
import unittest
1515
from pathlib import Path
16+
from typing import Any, TypedDict, Unpack
1617

1718
REPO_ROOT = Path(__file__).resolve().parents[3]
1819
CMAKE_DIR = REPO_ROOT / "vortex-ffi/cmake"
1920

2021

21-
def rust_toolchain_environment():
22+
class CommandOptions(TypedDict, total=False):
23+
env: dict[str, str] | None
24+
cwd: str | Path | None
25+
success: bool
26+
timeout: int
27+
28+
29+
def rust_toolchain_environment() -> dict[str, str]:
2230
"""Keep the repository's Rust selection when fixtures run outside its tree."""
2331
env = os.environ.copy()
2432
if not env.get("RUSTUP_TOOLCHAIN") and shutil.which("rustup"):
@@ -36,25 +44,32 @@ def rust_toolchain_environment():
3644

3745

3846
class CMakeTest(unittest.TestCase):
39-
def setUp(self):
47+
def setUp(self) -> None:
4048
temporary = tempfile.TemporaryDirectory(prefix="vortex-cmake-")
4149
self.addCleanup(temporary.cleanup)
4250
self.work = Path(temporary.name).resolve()
4351
self.repo = REPO_ROOT
4452
self.env = os.environ.copy()
4553

46-
def write(self, path, contents):
54+
def write(self, path: str | Path, contents: str) -> Path:
4755
path = self.work / path
4856
path.parent.mkdir(parents=True, exist_ok=True)
4957
path.write_text(textwrap.dedent(contents), encoding="utf-8")
5058
return path
5159

52-
def executable(self, name, body):
60+
def executable(self, name: str, body: str) -> str:
5361
path = self.write(name, f"#!{sys.executable}\n" + textwrap.dedent(body))
5462
path.chmod(0o755)
5563
return str(path)
5664

57-
def command(self, *args, env=None, cwd=None, success=True, timeout=120):
65+
def command(
66+
self,
67+
*args: str | Path,
68+
env: dict[str, str] | None = None,
69+
cwd: str | Path | None = None,
70+
success: bool = True,
71+
timeout: int = 120,
72+
) -> subprocess.CompletedProcess[str]:
5873
result = subprocess.run(
5974
list(map(str, args)),
6075
cwd=self.work if cwd is None else cwd,
@@ -71,13 +86,17 @@ def command(self, *args, env=None, cwd=None, success=True, timeout=120):
7186
self.assertNotEqual(result.returncode, 0, output)
7287
return result
7388

74-
def cmake_configure(self, source, build, *options, generator="Ninja", **kwargs):
89+
def cmake_configure(
90+
self, source: Path, build: Path, *options: str, generator: str = "Ninja", **kwargs: Unpack[CommandOptions]
91+
) -> subprocess.CompletedProcess[str]:
7592
return self.command("cmake", "-G", generator, "-S", source, "-B", build, *options, **kwargs)
7693

77-
def cmake_build(self, build, *options, **kwargs):
94+
def cmake_build(
95+
self, build: Path, *options: str, **kwargs: Unpack[CommandOptions]
96+
) -> subprocess.CompletedProcess[str]:
7897
return self.command("cmake", "--build", build, *options, **kwargs)
7998

80-
def recording_cargo(self):
99+
def recording_cargo(self) -> str:
81100
"""Record the handoff and emit an archive without compiling Vortex."""
82101
return self.executable(
83102
"cargo",
@@ -96,7 +115,7 @@ def option(name):
96115
""",
97116
)
98117

99-
def fake_rustc(self, release="1.95.0", host=None):
118+
def fake_rustc(self, release: str = "1.95.0", host: str | None = None) -> str:
100119
arch = {"arm64": "aarch64", "AMD64": "x86_64"}.get(platform.machine(), platform.machine())
101120
host = host or f"{arch}-{'apple-darwin' if sys.platform == 'darwin' else 'unknown-linux-gnu'}"
102121
return self.executable(
@@ -109,5 +128,5 @@ def fake_rustc(self, release="1.95.0", host=None):
109128
""",
110129
)
111130

112-
def cargo_recording(self, target_dir):
131+
def cargo_recording(self, target_dir: Path) -> dict[str, Any]:
113132
return json.loads((target_dir / "environment.json").read_text(encoding="utf-8"))

‎vortex-ffi/cmake/tests/test_compiler_commands.py‎

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,20 @@
77
import json
88
import shlex
99
import shutil
10+
import subprocess
1011
import tomllib
1112
import unittest
1213
from pathlib import Path
1314

1415
from support import CMakeTest, rust_toolchain_environment
1516

1617

17-
def snapshot(*paths):
18+
def snapshot(*paths: Path) -> dict[Path, tuple[int, bytes]]:
1819
return {path: (path.stat().st_mtime_ns, hashlib.sha256(path.read_bytes()).digest()) for path in paths}
1920

2021

2122
class CompilerCommandTests(CMakeTest):
22-
def setUp(self):
23+
def setUp(self) -> None:
2324
super().setUp()
2425
packages = tomllib.loads((self.repo / "Cargo.lock").read_text())["package"]
2526
[cc] = [package for package in packages if package["name"] == "cc"]
@@ -50,7 +51,9 @@ def setUp(self):
5051
self.env.update(CARGO_NET_OFFLINE="true", CARGO_BUILD_JOBS="2")
5152
self.command("cargo", "generate-lockfile", "--offline", cwd=self.source)
5253

53-
def configure(self, value=7, argument=7, policy=True, instrumentation=False, generator="Ninja", build_name=None):
54+
def configure(
55+
self, value=7, argument=7, policy=True, instrumentation=False, generator="Ninja", build_name=None
56+
) -> None:
5457
self.build_dir = self.work / (build_name or f"{generator} build directory's")
5558
self.target_dir = self.build_dir / "ffi/cargo-target"
5659
options = []
@@ -70,15 +73,15 @@ def configure(self, value=7, argument=7, policy=True, instrumentation=False, gen
7073
]
7174
self.cmake_configure(self.source, self.build_dir, "-DCMAKE_BUILD_TYPE=Debug", *options, generator=generator)
7275

73-
def build(self, target="vortex_ffi_cargo_build", success=True):
76+
def build(self, target: str = "vortex_ffi_cargo_build", success: bool = True) -> subprocess.CompletedProcess[str]:
7477
return self.cmake_build(self.build_dir, "--target", target, success=success)
7578

76-
def archives(self):
79+
def archives(self) -> dict[Path, tuple[int, bytes]]:
7780
archives = sorted(self.target_dir.rglob("libnative_*.a"))
7881
self.assertEqual(len(archives), 4, archives)
7982
return snapshot(*archives)
8083

81-
def test_compiler_arguments_warning_policy_and_freshness(self):
84+
def test_compiler_arguments_warning_policy_and_freshness(self) -> None:
8285
self.configure()
8386
rejected = self.build("parent_native", success=False)
8487
self.assertIn("error: unused variable 'vendored_unused'", rejected.stdout + rejected.stderr)
@@ -103,7 +106,7 @@ def test_compiler_arguments_warning_policy_and_freshness(self):
103106
self.assertNotEqual(changed[path][1], original[path][1], path)
104107
original = changed
105108

106-
def test_header_lifecycle(self):
109+
def test_header_lifecycle(self) -> None:
107110
# Incremental rustc changes archive member names even when the object bytes are identical.
108111
self.env["CARGO_INCREMENTAL"] = "0"
109112
for generator in ("Ninja", "Unix Makefiles"):
@@ -135,7 +138,7 @@ def test_header_lifecycle(self):
135138
self.assertEqual(self.command(consumer).stdout.strip(), "2")
136139
self.assertEqual(staged.read_bytes(), source_header.read_bytes())
137140

138-
def test_host_target_instrumentation_and_cache_boundary(self):
141+
def test_host_target_instrumentation_and_cache_boundary(self) -> None:
139142
log = self.work / "cache calls.jsonl"
140143
# Record the cache boundary, not cache behavior; every call still runs the real compiler.
141144
self.env["RUSTC_WRAPPER"] = self.executable(

‎vortex-ffi/cmake/tests/test_configure.py‎

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@
55

66
import json
77
import os
8+
import subprocess
89
import tomllib
910
import unittest
11+
from pathlib import Path
1012

1113
from support import CMakeTest
1214

1315

1416
class ConfigureTests(CMakeTest):
15-
def setUp(self):
17+
def setUp(self) -> None:
1618
super().setUp()
1719
for name in ("CMAKE_BUILD_TYPE", "RUSTUP_TOOLCHAIN"):
1820
self.env.pop(name, None)
@@ -35,7 +37,9 @@ def setUp(self):
3537
""",
3638
)
3739

38-
def configure(self, name, *options, source=None, success=True):
40+
def configure(
41+
self, name: str, *options: str, source: Path | None = None, success: bool = True
42+
) -> subprocess.CompletedProcess[str]:
3943
return self.cmake_configure(
4044
source or self.repo / "vortex-ffi",
4145
self.work / name,
@@ -49,7 +53,7 @@ def configure(self, name, *options, source=None, success=True):
4953
success=success,
5054
)
5155

52-
def test_standalone_defaults_and_ffi_default_build(self):
56+
def test_standalone_defaults_and_ffi_default_build(self) -> None:
5357
for name, source, directories in (
5458
("root", ".", ("ffi", "cpp")),
5559
("ffi", "vortex-ffi", (".",)),
@@ -74,7 +78,7 @@ def test_standalone_defaults_and_ffi_default_build(self):
7478
expected = config["target"]['cfg(target_family="unix")']["rustflags"] + ["-C", "relocation-model=pic"]
7579
self.assertEqual(recorded["env"]["CARGO_ENCODED_RUSTFLAGS"].split("\x1f"), expected)
7680

77-
def test_embedded_root_preserves_parent_variables(self):
81+
def test_embedded_root_preserves_parent_variables(self) -> None:
7882
source = self.write(
7983
"parent/CMakeLists.txt",
8084
f"""\
@@ -98,7 +102,7 @@ def test_embedded_root_preserves_parent_variables(self):
98102
self.cmake_build(build)
99103
self.assertFalse(list(build.rglob("libvortex_ffi.a")))
100104

101-
def test_unused_embedded_ffi_keeps_cargo_lazy(self):
105+
def test_unused_embedded_ffi_keeps_cargo_lazy(self) -> None:
102106
source = self.write(
103107
"parent/CMakeLists.txt",
104108
f"""\
@@ -114,7 +118,7 @@ def test_unused_embedded_ffi_keeps_cargo_lazy(self):
114118
self.cmake_build(build, "--target", "vortex_ffi_cargo_build")
115119
self.assertEqual((build / "ffi/vortex-artifacts/libvortex_ffi.a").read_bytes(), b"recorded archive")
116120

117-
def test_profile_mapping_and_override(self):
121+
def test_profile_mapping_and_override(self) -> None:
118122
for config, override, expected in (
119123
("Release", "", "release"),
120124
("RelWithDebInfo", "", "release_debug"),
@@ -128,7 +132,7 @@ def test_profile_mapping_and_override(self):
128132
self.assertEqual(args[args.index("--profile") + 1], expected)
129133
self.assertEqual((build / "vortex-artifacts/libvortex_ffi.a").read_bytes(), b"recorded archive")
130134

131-
def test_sanitizer_rejections(self):
135+
def test_sanitizer_rejections(self) -> None:
132136
result = self.configure("unknown", "-DVORTEX_SANITIZER=typo", success=False)
133137
self.assertIn("got 'typo'", result.stdout + result.stderr)
134138
for compiler, message in (
@@ -149,11 +153,11 @@ def test_sanitizer_rejections(self):
149153
)
150154
self.assertIn(message, result.stdout + result.stderr)
151155

152-
def test_toolchain_selection_survives_reconfigure_and_explicit_updates(self):
156+
def test_toolchain_selection_survives_reconfigure_and_explicit_updates(self) -> None:
153157
rustc_log = self.work / "rustc.json"
154158
build = self.work / "toolchain"
155159

156-
def assert_selection(selected):
160+
def assert_selection(selected: str | None) -> None:
157161
self.assertEqual(json.loads(rustc_log.read_text()), [selected, str(self.repo)])
158162
recorded = self.cargo_recording(build / "cargo-target")
159163
self.assertEqual(recorded["env"].get("RUSTUP_TOOLCHAIN"), selected)

‎vortex-ffi/cmake/tests/test_cuda_architectures.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818

1919
class CudaArchitectureTests(CMakeTest):
20-
def test_policy_preserves_parent(self):
20+
def test_policy_preserves_parent(self) -> None:
2121
for architectures, expected in (
2222
(None, "-arch=native"),
2323
("native", "-arch=native"),
@@ -53,7 +53,7 @@ def test_policy_preserves_parent(self):
5353
else:
5454
self.assertEqual((self.work / "flags.txt").read_text(encoding="utf-8"), expected)
5555

56-
def test_configure_forwards_flags_and_cpu_ignores_policy(self):
56+
def test_configure_forwards_flags_and_cpu_ignores_policy(self) -> None:
5757
cuda_root = self.work / "fake CUDA toolkit's"
5858
nvcc = self.executable("fake CUDA toolkit's/bin/nvcc", "raise SystemExit('No native compilation expected')\n")
5959
# Stub discovery only; production Configure.cmake and its Cargo driver run unchanged.

0 commit comments

Comments
 (0)