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
« 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# ///////////////////////////////////////////////////////////////
6"""
7Compiler factory - Factory for creating compiler instances.
9This module provides a centralized factory for creating compiler
10instances based on type and configuration.
11"""
13from __future__ import annotations
15# ///////////////////////////////////////////////////////////////
16# IMPORTS
17# ///////////////////////////////////////////////////////////////
18# Standard library imports
19import importlib.util
21# Local imports
22from ..shared import CompilerConfig
23from ..shared.exceptions import CompilationError
24from .base_compiler import BaseCompiler
26# ///////////////////////////////////////////////////////////////
27# CONSTANTS
28# ///////////////////////////////////////////////////////////////
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}
36# ///////////////////////////////////////////////////////////////
37# CLASSES
38# ///////////////////////////////////////////////////////////////
41class CompilerFactory:
42 """Factory class for creating compiler instances."""
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.
49 Args:
50 compiler_name: Canonical compiler name (Cx_Freeze, PyInstaller, Nuitka)
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 )
62 @staticmethod
63 def create_compiler(config: CompilerConfig, compiler_name: str) -> BaseCompiler:
64 """
65 Create a compiler instance from its name.
67 Args:
68 config: Compiler configuration to inject
69 compiler_name: Compiler name (Cx_Freeze, PyInstaller, Nuitka)
71 Returns:
72 BaseCompiler: Concrete compiler instance
74 Raises:
75 CompilationError: If compiler name is unsupported or package not installed
76 """
77 normalized_name = compiler_name.strip()
79 if normalized_name == "Cx_Freeze":
80 CompilerFactory._check_compiler_available("Cx_Freeze")
81 from ._cx_freeze_compiler import CxFreezeCompiler
83 return CxFreezeCompiler(config=config)
85 if normalized_name == "PyInstaller":
86 CompilerFactory._check_compiler_available("PyInstaller")
87 from ._pyinstaller_compiler import PyInstallerCompiler
89 return PyInstallerCompiler(config=config)
91 if normalized_name == "Nuitka":
92 CompilerFactory._check_compiler_available("Nuitka")
93 from ._nuitka_compiler import NuitkaCompiler
95 return NuitkaCompiler(config=config)
97 raise CompilationError(f"Unsupported compiler: {normalized_name}")
99 @staticmethod
100 def create_from_config(config: CompilerConfig) -> BaseCompiler:
101 """
102 Create a compiler instance using the config default compiler.
104 Args:
105 config: Compiler configuration
107 Returns:
108 BaseCompiler: Concrete compiler instance
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 )
118 @staticmethod
119 def get_supported_compilers() -> list[str]:
120 """Return the list of supported compiler names."""
121 return ["Cx_Freeze", "PyInstaller", "Nuitka"]