Coverage for packages/pyswig/src/pyswig/binding_layout.py: 97%
32 statements
« prev ^ index » next coverage.py v7.14.3, created at 2026-06-26 21:05 +0000
« prev ^ index » next coverage.py v7.14.3, created at 2026-06-26 21:05 +0000
1# Copyright (c) 2015-2020 Michel Gillet
2# SPDX-License-Identifier: MIT
4"""Helpers for project binding generator scripts invoked from CMake."""
6from __future__ import annotations
8import argparse
9import os
10from collections.abc import Mapping
11from dataclasses import dataclass
14@dataclass(frozen=True)
15class BindingLayout:
16 """Resolved source/include output directories for a binding generator."""
18 src_dir: str
19 inc_dir: str
21 @classmethod
22 def resolve(
23 cls,
24 *,
25 binding_subdir: str,
26 gen_dir: str | None = None,
27 legacy_src: str | None = None,
28 legacy_inc: str | None = None,
29 ) -> BindingLayout:
30 """Map --gen-dir (CMake build tree) or legacy in-tree paths."""
31 if gen_dir:
32 root = os.path.abspath(gen_dir)
33 return cls(
34 src_dir=os.path.join(root, "src", binding_subdir),
35 inc_dir=os.path.join(root, "include", binding_subdir),
36 )
37 if legacy_src is None or legacy_inc is None:
38 raise ValueError("legacy_src and legacy_inc are required when gen_dir is not set")
39 return cls(src_dir=legacy_src, inc_dir=legacy_inc)
42def add_gen_dir_argument(parser: argparse.ArgumentParser) -> None:
43 """Register the --gen-dir option used by CMake custom commands."""
44 parser.add_argument(
45 "--gen-dir",
46 help=(
47 "Root directory for generated outputs. When set, writes under "
48 "src/<binding_subdir> and include/<binding_subdir> beneath this path."
49 ),
50 )
53def parse_binding_layout(
54 description: str,
55 *,
56 binding_subdir: str,
57 legacy_src: str,
58 legacy_inc: str,
59 argv: list[str] | None = None,
60) -> BindingLayout:
61 """Parse argv (default: sys.argv) and return resolved output directories."""
62 parser = argparse.ArgumentParser(description=description)
63 add_gen_dir_argument(parser)
64 args = parser.parse_args(argv)
65 return BindingLayout.resolve(
66 binding_subdir=binding_subdir,
67 gen_dir=args.gen_dir,
68 legacy_src=legacy_src,
69 legacy_inc=legacy_inc,
70 )
73def versioned_module_name(
74 base: str,
75 *,
76 env: Mapping[str, str] | None = None,
77 log: bool = True,
78) -> str:
79 """Append _py<tag> when SWIG_TARGET_PYTHON_VERSION is set (CMake builds)."""
80 mapping: Mapping[str, str] = os.environ if env is None else env
81 target_version = mapping.get("SWIG_TARGET_PYTHON_VERSION")
82 if not target_version:
83 return base
84 if log:
85 print(f"WARNING: SWIG_TARGET_PYTHON_VERSION = {target_version}")
86 return f"{base}_py{target_version.replace('.', '_')}"