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

31 statements  

« prev     ^ index     » next       coverage.py v7.14.3, created at 2026-07-04 11:22 +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 

21from .._types import CompilerPort 

22 

23# Local imports 

24from ..shared import CompilerConfig 

25from ..shared.exceptions import CompilationError 

26 

27# /////////////////////////////////////////////////////////////// 

28# CONSTANTS 

29# /////////////////////////////////////////////////////////////// 

30 

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

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

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

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

35} 

36 

37# /////////////////////////////////////////////////////////////// 

38# CLASSES 

39# /////////////////////////////////////////////////////////////// 

40 

41 

42class CompilerFactory: 

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

44 

45 @staticmethod 

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

47 """ 

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

49 

50 Args: 

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

52 

53 Raises: 

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

55 """ 

56 package, extra = _COMPILER_PACKAGES[compiler_name] 

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

58 raise CompilationError( 

59 f"{compiler_name} is not installed. " 

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

61 ) 

62 

63 @staticmethod 

64 def create_compiler(config: CompilerConfig, compiler_name: str) -> CompilerPort: 

65 """ 

66 Create a compiler instance from its name. 

67 

68 Args: 

69 config: Compiler configuration to inject 

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

71 

72 Returns: 

73 CompilerPort: Concrete compiler instance (satisfies the Port) 

74 

75 Raises: 

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

77 """ 

78 normalized_name = compiler_name.strip() 

79 

80 if normalized_name == "Cx_Freeze": 

81 CompilerFactory._check_compiler_available("Cx_Freeze") 

82 from ._cx_freeze_compiler import CxFreezeCompiler 

83 

84 return CxFreezeCompiler(config=config) 

85 

86 if normalized_name == "PyInstaller": 

87 CompilerFactory._check_compiler_available("PyInstaller") 

88 from ._pyinstaller_compiler import PyInstallerCompiler 

89 

90 return PyInstallerCompiler(config=config) 

91 

92 if normalized_name == "Nuitka": 

93 CompilerFactory._check_compiler_available("Nuitka") 

94 from ._nuitka_compiler import NuitkaCompiler 

95 

96 return NuitkaCompiler(config=config) 

97 

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

99 

100 @staticmethod 

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

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

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