Coverage for packages/pyswig/src/pyswig/maininterfacefile.py: 95%

86 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 

4from __future__ import annotations 

5 

6from pathlib import Path 

7from typing import TYPE_CHECKING, TextIO 

8 

9from pyswig.exceptions import PySwigError 

10from pyswig.types import normalize_source_entry 

11 

12if TYPE_CHECKING: 

13 from pyswig.pyswig import PySwig 

14 

15 

16class MainInterfaceFile: 

17 """Class generating the main interface file, input to Swig""" 

18 

19 def __init__(self, pyswig: PySwig | None = None) -> None: 

20 self.m_pyswig = pyswig 

21 self.m_fout: TextIO | None = None 

22 

23 def _get_pyswig(self) -> PySwig | None: 

24 """Get the PySwig instance to use to generate the main interface file""" 

25 return self.m_pyswig 

26 

27 def generate(self) -> None: 

28 """Generate the Swig interface file, the main input file for Swig""" 

29 output_path = self._output_path() 

30 pyswig = self._get_pyswig() 

31 assert pyswig is not None 

32 pyswig.set_output_file(output_path.name) 

33 with open(output_path, "w", encoding="utf-8") as fout: 

34 self.m_fout = fout 

35 self.write_header() 

36 self.write_cpp_includes() 

37 self.write_defines() 

38 self.main_file_write_interface_files() 

39 self.m_fout = None 

40 

41 def _output_path(self) -> Path: 

42 pyswig = self._get_pyswig() 

43 if pyswig is None: 

44 raise PySwigError("PySwig instance is required to generate the main interface file") 

45 

46 src_output_dir = pyswig.get_src_output_dir() 

47 module_name = pyswig.get_module_name() 

48 if src_output_dir is None or module_name is None: 

49 raise PySwigError("module name and source output directory must be configured") 

50 

51 return Path(src_output_dir) / f"{module_name}.hh" 

52 

53 def write_header(self) -> None: 

54 """Write header of the the main interface file""" 

55 pyswig = self._get_pyswig() 

56 assert pyswig is not None 

57 assert self.m_fout is not None 

58 

59 self.m_fout.write(f"// PySwig {pyswig.get_version()}\n\n") 

60 if pyswig.get_use_director(): 

61 self.m_fout.write(f'%module(directors="1") {pyswig.get_module_name()}\n') 

62 else: 

63 self.m_fout.write(f"%module {pyswig.get_module_name()}\n") 

64 

65 self.m_fout.write("%include typemaps.i\n") 

66 

67 for type_map in pyswig.get_typemaps(): 

68 self.m_fout.write(f"%include {type_map}\n") 

69 

70 self.m_fout.write("\n") 

71 imports = pyswig.get_imports() 

72 if imports is not None: 

73 for import_lib in imports: 

74 self.m_fout.write(f"%import {import_lib}\n") 

75 self.m_fout.write("\n") 

76 

77 def write_cpp_includes(self) -> None: 

78 """Write the C/C++ includes to the main file""" 

79 pyswig = self._get_pyswig() 

80 assert pyswig is not None 

81 assert self.m_fout is not None 

82 

83 self.m_fout.write("%{\n") 

84 self.m_fout.write("\n") 

85 for include in pyswig.get_includes(False): 

86 self.m_fout.write(f"#include <{include}>\n") 

87 self.m_fout.write("\n") 

88 for include in pyswig.get_includes(True): 

89 self.m_fout.write(f'#include "{include}"\n') 

90 self.m_fout.write("\n") 

91 self.m_fout.write("%}\n\n") 

92 

93 def write_defines(self) -> None: 

94 """Write the defines in the main file""" 

95 pyswig = self._get_pyswig() 

96 assert pyswig is not None 

97 assert self.m_fout is not None 

98 

99 for define in pyswig.get_defines(): 

100 if define.value: 

101 self.m_fout.write(f"#define {define.name} {define.value}\n") 

102 else: 

103 self.m_fout.write(f"#define {define.name}\n") 

104 self.m_fout.write("\n") 

105 

106 def main_file_write_interface_files(self) -> None: 

107 """Write the insterface in the main file""" 

108 pyswig = self._get_pyswig() 

109 assert pyswig is not None 

110 assert self.m_fout is not None 

111 

112 for file_config in pyswig.get_file_configs(): 

113 source_files = file_config.get_source_files() 

114 if source_files is None: 

115 continue 

116 for source_file in source_files: 

117 spec = normalize_source_entry(source_file) 

118 rel = Path(spec.name) 

119 if spec.wrap: 

120 rel = rel.with_name(rel.stem + "_wrap" + rel.suffix) 

121 out_interface = rel.with_suffix(".hh") 

122 self.m_fout.write(f"%include {out_interface.as_posix()}\n")