Coverage for src/ezcompiler/adapters/compiler_factory.py: 88.37%

35 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-06-03 15:46 +0000

1# /////////////////////////////////////////////////////////////// 

2# COMPILER_FACTORY - Compiler factory for creating compiler instances 

3# Project: ezcompiler 

4# /////////////////////////////////////////////////////////////// 

5 

6""" 

7Compiler factory - Factory for creating compiler instances. 

8 

9This module provides a centralized factory for creating compiler 

10instances based on type and configuration. 

11""" 

12 

13from __future__ import annotations 

14 

15# /////////////////////////////////////////////////////////////// 

16# IMPORTS 

17# /////////////////////////////////////////////////////////////// 

18# Standard library imports 

19import importlib.util 

20 

21# Local imports 

22from ..shared import CompilerConfig 

23from ..shared.exceptions import CompilationError 

24from .base_compiler import BaseCompiler 

25 

26# /////////////////////////////////////////////////////////////// 

27# CONSTANTS 

28# /////////////////////////////////////////////////////////////// 

29 

30_COMPILER_PACKAGES: dict[str, tuple[str, str]] = { 

31 "Cx_Freeze": ("cx_Freeze", "ezcompiler[cx-freeze]"), 

32 "PyInstaller": ("PyInstaller", "ezcompiler[pyinstaller]"), 

33 "Nuitka": ("nuitka", "ezcompiler[nuitka]"), 

34} 

35 

36# /////////////////////////////////////////////////////////////// 

37# CLASSES 

38# /////////////////////////////////////////////////////////////// 

39 

40 

41class CompilerFactory: 

42 """Factory class for creating compiler instances.""" 

43 

44 @staticmethod 

45 def _check_compiler_available(compiler_name: str) -> None: 

46 """ 

47 Verify the compiler package is installed, raise a clear error if not. 

48 

49 Args: 

50 compiler_name: Canonical compiler name (Cx_Freeze, PyInstaller, Nuitka) 

51 

52 Raises: 

53 CompilationError: If the package is not installed, with install hint 

54 """ 

55 package, extra = _COMPILER_PACKAGES[compiler_name] 

56 if importlib.util.find_spec(package) is None: 

57 raise CompilationError( 

58 f"{compiler_name} is not installed. " 

59 f"Install it with: pip install {extra}" 

60 ) 

61 

62 @staticmethod 

63 def create_compiler(config: CompilerConfig, compiler_name: str) -> BaseCompiler: 

64 """ 

65 Create a compiler instance from its name. 

66 

67 Args: 

68 config: Compiler configuration to inject 

69 compiler_name: Compiler name (Cx_Freeze, PyInstaller, Nuitka) 

70 

71 Returns: 

72 BaseCompiler: Concrete compiler instance 

73 

74 Raises: 

75 CompilationError: If compiler name is unsupported or package not installed 

76 """ 

77 normalized_name = compiler_name.strip() 

78 

79 if normalized_name == "Cx_Freeze": 

80 CompilerFactory._check_compiler_available("Cx_Freeze") 

81 from ._cx_freeze_compiler import CxFreezeCompiler 

82 

83 return CxFreezeCompiler(config=config) 

84 

85 if normalized_name == "PyInstaller": 

86 CompilerFactory._check_compiler_available("PyInstaller") 

87 from ._pyinstaller_compiler import PyInstallerCompiler 

88 

89 return PyInstallerCompiler(config=config) 

90 

91 if normalized_name == "Nuitka": 

92 CompilerFactory._check_compiler_available("Nuitka") 

93 from ._nuitka_compiler import NuitkaCompiler 

94 

95 return NuitkaCompiler(config=config) 

96 

97 raise CompilationError(f"Unsupported compiler: {normalized_name}") 

98 

99 @staticmethod 

100 def create_from_config(config: CompilerConfig) -> BaseCompiler: 

101 """ 

102 Create a compiler instance using the config default compiler. 

103 

104 Args: 

105 config: Compiler configuration 

106 

107 Returns: 

108 BaseCompiler: Concrete compiler instance 

109 

110 Raises: 

111 CompilationError: If config compiler is unsupported 

112 """ 

113 compiler_name = config.compiler if config.compiler != "auto" else "Cx_Freeze" 

114 return CompilerFactory.create_compiler( 

115 config=config, compiler_name=compiler_name 

116 ) 

117 

118 @staticmethod 

119 def get_supported_compilers() -> list[str]: 

120 """Return the list of supported compiler names.""" 

121 return ["Cx_Freeze", "PyInstaller", "Nuitka"]