Services Layer¶
Business logic services and orchestration for EzCompiler.
The services layer implements the core business logic, handling compilation, configuration, template processing, and upload operations.
CompilerService¶
Service for managing compiler selection and orchestrating the compilation process.
CompilerService
¶
CompilerService(config: CompilerConfig)
Compilation orchestration service.
Orchestrates project compilation using different compiler backends. Handles compiler selection, validation, and execution.
Attributes:
| Name | Type | Description |
|---|---|---|
_config |
CompilerConfig instance with project settings |
Example
config = CompilerConfig(...) service = CompilerService(config) result = service.compile(console=True, compiler="PyInstaller") print(result.zip_needed) False
Initialize the compiler service.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
CompilerConfig
|
CompilerConfig instance with project settings |
required |
Raises:
| Type | Description |
|---|---|
ConfigurationError
|
If config is None or invalid |
compiler_instance
property
¶
compiler_instance: BaseCompiler | None
Get the current compiler instance.
Returns:
| Type | Description |
|---|---|
BaseCompiler | None
|
BaseCompiler | None: Current compiler instance or None if not compiled yet |
compile
¶
Compile the project using specified or auto-selected compiler.
Validates configuration, selects compiler if not specified, and executes compilation. Returns result with zip_needed flag.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
console
|
bool
|
Whether to show console window (default: True) |
True
|
compiler
|
_CompilerName | None
|
Compiler to use or None for auto-selection - "Cx_Freeze": Creates directory with dependencies - "PyInstaller": Creates single executable - "Nuitka": Creates standalone folder or single executable - "auto" or None: Prompt user for choice or use config default |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
CompilationResult |
CompilationResult
|
Result with zip_needed flag and compiler instance |
Raises:
| Type | Description |
|---|---|
ConfigurationError
|
If project not initialized |
CompilationError
|
If compilation fails |
Example
service = CompilerService(config) result = service.compile(console=False, compiler="PyInstaller") if result.zip_needed: ... # Create ZIP archive
ConfigService¶
Service for loading, validating, and managing configuration.
ConfigService
¶
Configuration orchestration service.
Orchestrates configuration loading from multiple sources with a cascade merge system. Sources are merged in priority order (later wins):
- pyproject.toml [project] + [tool.ezcompiler] (base)
- ezcompiler.yaml or ezcompiler.json (override)
- CLI arguments (final override)
Example
config = ConfigService.build_compiler_config() config = ConfigService.build_compiler_config( ... config_path=Path("ezcompiler.yaml"), ... cli_overrides={"compiler": "PyInstaller"}, ... )
load_config
staticmethod
¶
load_config(config_path: Path | None = None, pyproject_path: Path | None = None, cli_overrides: dict[str, Any] | None = None, search_dir: Path | None = None) -> dict[str, Any]
Load configuration with full cascade.
Merges configuration from multiple sources in priority order: 1. pyproject.toml [project] + [tool.ezcompiler] (base layer) 2. ezcompiler.yaml or .json - explicit or auto-discovered (override) 3. CLI overrides (final override)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config_path
|
Path | None
|
Explicit config file path for YAML/JSON (skips auto-discovery) |
None
|
pyproject_path
|
Path | None
|
Explicit pyproject.toml path (default: search_dir/pyproject.toml) |
None
|
cli_overrides
|
dict[str, Any] | None
|
Dict of CLI-provided overrides (only non-default values) |
None
|
search_dir
|
Path | None
|
Directory to search for config files (default: cwd) |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Merged configuration dictionary |
Raises:
| Type | Description |
|---|---|
ConfigurationError
|
If no configuration source found or loading fails |
build_compiler_config
staticmethod
¶
build_compiler_config(config_path: Path | None = None, pyproject_path: Path | None = None, cli_overrides: dict[str, Any] | None = None, search_dir: Path | None = None) -> CompilerConfig
Load configuration and create a CompilerConfig instance.
Convenience method that combines load_config() with CompilerConfig.from_dict().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config_path
|
Path | None
|
Explicit config file path for YAML/JSON |
None
|
pyproject_path
|
Path | None
|
Explicit pyproject.toml path |
None
|
cli_overrides
|
dict[str, Any] | None
|
Dict of CLI-provided overrides |
None
|
search_dir
|
Path | None
|
Directory to search for config files (default: cwd) |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
CompilerConfig |
CompilerConfig
|
Validated configuration instance |
Raises:
| Type | Description |
|---|---|
ConfigurationError
|
If configuration is invalid or not found |
load_pyproject_as_dict
staticmethod
¶
Load and extract configuration from a pyproject.toml file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pyproject_path
|
Path
|
Path to the pyproject.toml file |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Extracted configuration dictionary |
Raises:
| Type | Description |
|---|---|
ConfigurationError
|
If the file cannot be loaded or parsed |
merge_configs
staticmethod
¶
Deep-merge two configuration dictionaries (override wins on conflicts).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base
|
dict[str, Any]
|
Base configuration dictionary |
required |
override
|
dict[str, Any]
|
Override dictionary (values win over base) |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Merged configuration dictionary |
TemplateService¶
Service for processing templates and generating dynamic files.
TemplateService
¶
TemplateService(file_writer: BaseFileWriter | None = None)
Template processing and file generation service.
Orchestrates template loading, processing, and file generation for configuration files, setup.py, and version information files.
Attributes:
| Name | Type | Description |
|---|---|---|
_template_loader |
TemplateLoader instance for template operations |
|
_processor |
TemplateProcessor instance for variable substitution |
Example
service = TemplateService() config = {"version": "1.0.0", "project_name": "MyApp"} service.generate_setup_file(config, Path("setup.py")) service.generate_version_file(config, Path("version_info.txt"))
Initialize the template service.
Creates TemplateLoader and TemplateProcessor instances for template operations.
generate_config_file
¶
Generate a configuration file (YAML or JSON) from template.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
dict[str, Any]
|
Project configuration dictionary |
required |
output_path
|
Path
|
Path where to save the config file |
required |
format_type
|
str
|
Format type ("yaml" or "json") |
'yaml'
|
Raises:
| Type | Description |
|---|---|
TemplateError
|
If generation fails |
Example
config = {"version": "1.0.0", "project_name": "MyApp"} service.generate_config_file(config, Path("ezcompiler.yaml"), "yaml")
generate_setup_file
¶
generate_setup_file(config: dict[str, Any], output_path: Path | None = None, output_dir: Path | None = None) -> Path
Generate a setup.py file from template.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
dict[str, Any]
|
Project configuration dictionary |
required |
output_path
|
Path | None
|
Direct path to setup.py file (optional) |
None
|
output_dir
|
Path | None
|
Directory where to save setup.py (optional, defaults to current dir) |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Path |
Path
|
Path to the generated setup.py file |
Raises:
| Type | Description |
|---|---|
TemplateError
|
If generation fails |
Example
config = {"version": "1.0.0", "project_name": "MyApp"} setup_path = service.generate_setup_file(config, output_dir=Path("build"))
generate_version_file
¶
generate_version_file(config: dict[str, Any], output_path: Path | None = None, format_type: str = 'txt') -> Path
Generate a version information file from template.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
dict[str, Any]
|
Project configuration dictionary |
required |
output_path
|
Path | None
|
Path where to save the version file (optional) |
None
|
format_type
|
str
|
Template format type (default: "txt") |
'txt'
|
Returns:
| Name | Type | Description |
|---|---|---|
Path |
Path
|
Path to the generated version file |
Raises:
| Type | Description |
|---|---|
VersionError
|
If generation fails |
Note
If output_path is None, uses version_filename and output_folder from config.
Example
config = { ... "version": "1.0.0", ... "project_name": "MyApp", ... "version_filename": "version_info.txt", ... "output_folder": "dist" ... } version_path = service.generate_version_file(config)
process_config_template
¶
Process a configuration template with values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
format_type
|
str
|
Format type ("yaml" or "json") |
required |
config
|
dict[str, Any]
|
Configuration dictionary |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Processed template content |
Example
config = {"version": "1.0.0", "project_name": "MyApp"} content = service.process_config_template("yaml", config)
process_setup_template
¶
Process a setup template with values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
dict[str, Any]
|
Configuration dictionary |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Processed template content |
Example
config = {"version": "1.0.0", "project_name": "MyApp"} content = service.process_setup_template(config)
process_version_template
¶
process_version_template(version: str, company_name: str, project_description: str, project_name: str, format_type: str = 'txt') -> str
Process a version template with values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
version
|
str
|
Project version |
required |
company_name
|
str
|
Company name |
required |
project_description
|
str
|
Project description |
required |
project_name
|
str
|
Project name |
required |
format_type
|
str
|
Format type (default: "txt") |
'txt'
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Processed template content |
Example
content = service.process_version_template( ... "1.0.0", "MyCompany", "Description", "MyApp" ... )
list_available_templates
¶
List all available templates.
Returns:
| Type | Description |
|---|---|
dict[str, list[str]]
|
dict[str, list[str]]: Dictionary mapping template types to available formats |
Example
templates = service.list_available_templates() print(templates)
validate_template
¶
Validate a template file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
template_type
|
str
|
Type of template (config, version, setup) |
required |
format_type
|
str
|
Format of the template |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if template is valid, False otherwise |
Example
is_valid = service.validate_template("config", "yaml")
generate_mockup_template
¶
Generate a template file with mockup values instead of placeholders.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
template_type
|
str
|
Type of template (config, version, setup) |
required |
format_type
|
str
|
Format of the template (yaml, json, py, txt) |
required |
output_path
|
Path
|
Path where to save the generated file |
required |
Raises:
| Type | Description |
|---|---|
TemplateError
|
If generation fails |
Example
service.generate_mockup_template("config", "yaml", Path("ezcompiler.yaml"))
generate_raw_template
¶
Generate a raw template file with placeholders.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
template_type
|
str
|
Type of template (config, version, setup) |
required |
format_type
|
str
|
Format of the template (yaml, json, py, txt) |
required |
output_path
|
Path
|
Path where to save the template file |
required |
Raises:
| Type | Description |
|---|---|
TemplateError
|
If generation fails |
Example
service.generate_raw_template("config", "yaml", Path("template.yaml"))
PipelineService¶
Service for orchestrating the full compile → zip → upload pipeline with injectable factory.
PipelineService
¶
PipelineService(compiler_service_factory: Callable[[CompilerConfig], CompilerService] | None = None)
Service that coordinates compile, zip and upload stages.
Initialise the pipeline service.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
compiler_service_factory
|
Callable[[CompilerConfig], CompilerService] | None
|
Optional factory to create a CompilerService
from a CompilerConfig. Defaults to |
None
|
compile_project
¶
compile_project(config: CompilerConfig, console: bool = True, compiler: str | None = None) -> tuple[CompilerService, CompilationResult]
Compile a project and return service + result.
zip_artifact
¶
zip_artifact(config: CompilerConfig, compiler_service: CompilerService, compilation_result: CompilationResult | None, progress_callback: Callable[[str, int], None] | None = None) -> bool
Create ZIP artifact when required and return True when created.
build_stages
staticmethod
¶
build_stages(config: CompilerConfig, should_zip: bool = False, should_upload: bool = False) -> list[dict[str, Any]]
Build the stage list for dynamic_layered_progress.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
CompilerConfig
|
Compiler configuration (used for display labels) |
required |
should_zip
|
bool
|
Whether a ZIP stage should be included |
False
|
should_upload
|
bool
|
Whether an upload stage should be included |
False
|
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
list[dict]: Stage configuration list ready for dynamic_layered_progress |
upload_artifact
¶
upload_artifact(config: CompilerConfig, structure: str, destination: str, compilation_result: CompilationResult | None, upload_config: dict[str, Any] | None = None) -> None
Upload project artifact to a destination.
UploaderService¶
Service for orchestrating upload operations to various backends.
UploaderService
¶
Upload orchestration service.
Orchestrates file and directory uploads using different upload backends. Handles upload type selection, validation, and execution.
Example
service = UploaderService() service.upload( ... source_path=Path("dist.zip"), ... upload_type="disk", ... destination="releases/", ... upload_config={"overwrite": True} ... )
upload
staticmethod
¶
upload(source_path: Path, upload_type: UploadType, destination: str, upload_config: dict[str, Any] | None = None) -> None
Upload a file or directory to the specified destination.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_path
|
Path
|
Path to the source file or directory |
required |
upload_type
|
UploadType
|
Type of upload ("disk" or "server") |
required |
destination
|
str
|
Destination path or URL |
required |
upload_config
|
dict[str, Any] | None
|
Additional uploader configuration options |
None
|
Raises:
| Type | Description |
|---|---|
UploadError
|
If upload fails or upload type is invalid |
Example
UploaderService.upload( ... Path("dist.zip"), ... "disk", ... "releases/", ... {"overwrite": True} ... )
get_supported_types
staticmethod
¶
Get list of supported upload types.
Returns:
| Type | Description |
|---|---|
list[str]
|
list[str]: List of supported upload type names |
Example
types = UploaderService.get_supported_types() print(types) ['disk', 'server']
validate_upload_config
staticmethod
¶
Validate configuration for a specific upload type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
upload_type
|
UploadType
|
Type of uploader to validate |
required |
config
|
dict[str, Any] | None
|
Configuration to validate (default: None) |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if configuration is valid, False otherwise |
Example
is_valid = UploaderService.validate_upload_config( ... "disk", {"overwrite": True} ... )