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

1# Copyright (c) 2015-2020 Michel Gillet 

2# SPDX-License-Identifier: MIT 

3 

4"""Helpers for project binding generator scripts invoked from CMake.""" 

5 

6from __future__ import annotations 

7 

8import argparse 

9import os 

10from collections.abc import Mapping 

11from dataclasses import dataclass 

12 

13 

14@dataclass(frozen=True) 

15class BindingLayout: 

16 """Resolved source/include output directories for a binding generator.""" 

17 

18 src_dir: str 

19 inc_dir: str 

20 

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) 

40 

41 

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 ) 

51 

52 

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 ) 

71 

72 

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('.', '_')}"