diff --git a/src/python_factory/__main__.py b/src/python_factory/__main__.py index feafe1c..0f3f766 100644 --- a/src/python_factory/__main__.py +++ b/src/python_factory/__main__.py @@ -1,6 +1,4 @@ -""" -Re-Use the main function from the example module. -""" +"""Re-Use the main function from the example module.""" from python_factory.example import main diff --git a/src/python_factory/core/__init__.py b/src/python_factory/core/__init__.py index e69de29..466bd68 100644 --- a/src/python_factory/core/__init__.py +++ b/src/python_factory/core/__init__.py @@ -0,0 +1 @@ +"""Python Factory Core Module.""" diff --git a/src/python_factory/core/api/__init__.py b/src/python_factory/core/api/__init__.py index 7f3fdc1..37305ee 100644 --- a/src/python_factory/core/api/__init__.py +++ b/src/python_factory/core/api/__init__.py @@ -1,6 +1,4 @@ -""" -Define the API for the Python Factory. -""" +"""Define the API for the Python Factory.""" from fastapi import APIRouter diff --git a/src/python_factory/core/api/tags.py b/src/python_factory/core/api/tags.py index 7e6dd4f..a744097 100644 --- a/src/python_factory/core/api/tags.py +++ b/src/python_factory/core/api/tags.py @@ -1,9 +1,9 @@ -""" -Provides the Tag as Enum -""" +"""Provides the Tag as Enum.""" from enum import StrEnum, auto class TagEnum(StrEnum): + """Define Tag for OpenAPI Description.""" + SYS = auto() diff --git a/src/python_factory/core/api/v1/sys/__init__.py b/src/python_factory/core/api/v1/sys/__init__.py index 7b565d2..75b9f9f 100644 --- a/src/python_factory/core/api/v1/sys/__init__.py +++ b/src/python_factory/core/api/v1/sys/__init__.py @@ -1,6 +1,4 @@ -""" -Package for system related API endpoints. -""" +"""Package for system related API endpoints.""" from fastapi import APIRouter diff --git a/src/python_factory/core/api/v1/sys/health.py b/src/python_factory/core/api/v1/sys/health.py index cef8a30..f0e53bb 100644 --- a/src/python_factory/core/api/v1/sys/health.py +++ b/src/python_factory/core/api/v1/sys/health.py @@ -1,5 +1,4 @@ -""" -API v1 sys health module. +"""API v1 sys health module. Provide the Get health endpoint """ @@ -14,18 +13,14 @@ class HealthStatusEnum(StrEnum): - """ - Health status enum. - """ + """Health status enum.""" HEALTHY = "healthy" UNHEALTHY = "unhealthy" class HealthResponseModel(BaseModel): - """ - Health response schema. - """ + """Health response schema.""" status: HealthStatusEnum @@ -46,10 +41,11 @@ class HealthResponseModel(BaseModel): }, ) def get_api_v1_sys_health(response: Response) -> HealthResponseModel: - """ - Get the health of the system. + """Get the health of the system. + Args: response (Response): The response object. + Returns: HealthResponse: The health status. """ diff --git a/src/python_factory/core/api/v1/sys/readiness.py b/src/python_factory/core/api/v1/sys/readiness.py index 6c5c4ee..83c58f5 100644 --- a/src/python_factory/core/api/v1/sys/readiness.py +++ b/src/python_factory/core/api/v1/sys/readiness.py @@ -1,5 +1,4 @@ -""" -API v1 sys readiness module. +"""API v1 sys readiness module. Provide the Get readiness endpoint """ @@ -14,18 +13,14 @@ class ReadinessStatusEnum(StrEnum): - """ - Readiness status enum. - """ + """Readiness status enum.""" READY = "ready" NOT_READY = "not_ready" class ReadinessResponseModel(BaseModel): - """ - Readiness response schema. - """ + """Readiness response schema.""" status: ReadinessStatusEnum @@ -46,10 +41,11 @@ class ReadinessResponseModel(BaseModel): }, ) def get_api_v1_sys_readiness(response: Response) -> ReadinessResponseModel: - """ - Get the readiness of the system. + """Get the readiness of the system. + Args: response (Response): The response object. + Returns: ReadinessResponse: The readiness status. """ diff --git a/src/python_factory/core/app/__init__.py b/src/python_factory/core/app/__init__.py index 1fc62b9..03679c9 100644 --- a/src/python_factory/core/app/__init__.py +++ b/src/python_factory/core/app/__init__.py @@ -1,7 +1,4 @@ -""" -Package that contains the abstract classes -for the application and application configuration. -""" +"""Provides the core application module for the Python Factory.""" from .base import ( AppConfigAbstract, diff --git a/src/python_factory/core/app/base/__init__.py b/src/python_factory/core/app/base/__init__.py index 90c98f3..65d55a2 100644 --- a/src/python_factory/core/app/base/__init__.py +++ b/src/python_factory/core/app/base/__init__.py @@ -1,6 +1,4 @@ -""" -Package for the base application, abstract config classes and related exceptions. -""" +"""Package for the base application, abstract config classes and related exceptions.""" from .application import BaseApplication from .config_abstract import AppConfigAbstract diff --git a/src/python_factory/core/app/base/application.py b/src/python_factory/core/app/base/application.py index d0026c2..f584981 100644 --- a/src/python_factory/core/app/base/application.py +++ b/src/python_factory/core/app/base/application.py @@ -1,6 +1,4 @@ -""" -Provides the abstract class for the application. -""" +"""Provides the abstract class for the application.""" from typing import cast @@ -12,14 +10,22 @@ class BaseApplication(FastAPIAbstract, ApplicationPluginManagerAbstract): - """ - Application abstract class. - """ + """Application abstract class.""" PACKAGE_NAME: str = "" def __init__(self, config: AppConfigAbstract) -> None: + """Instanciate the application. + Args: + config (AppConfigAbstract): The application configuration. + + Returns: + None + + Raises: + ValueError: If the package name is not set. + """ if self.PACKAGE_NAME == "": raise ValueError( "The package name must be set in the concrete application class." @@ -34,7 +40,5 @@ def __init__(self, config: AppConfigAbstract) -> None: ) def get_config(self) -> AppConfigAbstract: - """ - Get the application configuration. - """ + """Get the application configuration.""" return self._config diff --git a/src/python_factory/core/app/base/config_abstract.py b/src/python_factory/core/app/base/config_abstract.py index 76ac3aa..f0f9a56 100644 --- a/src/python_factory/core/app/base/config_abstract.py +++ b/src/python_factory/core/app/base/config_abstract.py @@ -1,12 +1,12 @@ -""" -Provide the configuration for the app server. -""" +"""Provide the configuration for the app server.""" from ..enums import EnvironmentEnum from .fastapi_application_abstract import FastAPIConfigAbstract class AppConfigAbstract(FastAPIConfigAbstract): + """Application configuration abstract class.""" + environment: EnvironmentEnum service_name: str service_namespace: str diff --git a/src/python_factory/core/app/base/exceptions.py b/src/python_factory/core/app/base/exceptions.py index 7a8aabb..0c93e13 100644 --- a/src/python_factory/core/app/base/exceptions.py +++ b/src/python_factory/core/app/base/exceptions.py @@ -1,19 +1,25 @@ -""" -Provides the exceptions for the application factory. -""" +"""Provides the exceptions for the application factory.""" class BaseApplicationException(BaseException): + """Base application exception.""" + pass class ApplicationFactoryException(BaseApplicationException): + """Application factory exception.""" + pass class ApplicationConfigFactoryException(BaseApplicationException): + """Application configuration factory exception.""" + pass class ApplicationPluginManagerException(BaseApplicationException): + """Application plugin manager exception.""" + pass diff --git a/src/python_factory/core/app/base/fastapi_application_abstract.py b/src/python_factory/core/app/base/fastapi_application_abstract.py index 97a1c31..d2a57cf 100644 --- a/src/python_factory/core/app/base/fastapi_application_abstract.py +++ b/src/python_factory/core/app/base/fastapi_application_abstract.py @@ -1,6 +1,4 @@ -""" -Provide -""" +"""Provides an abstract class for FastAPI application integration.""" from abc import ABC from typing import Any @@ -10,9 +8,7 @@ class FastAPIConfigAbstract(ABC, BaseModel): - """ - Partial configuration for FastAPI. - """ + """Partial configuration for FastAPI.""" model_config = ConfigDict(strict=False) @@ -37,13 +33,22 @@ class FastAPIConfigAbstract(ABC, BaseModel): class FastAPIAbstract(ABC): - """ - Application integration with FastAPI. - """ + """Application integration with FastAPI.""" def __init__( self, config: FastAPIConfigAbstract, api_router: APIRouter | None = None ) -> None: + """Instanciate the FastAPI application. + + Args: + config (FastAPIConfigAbstract): The FastAPI configuration. + api_router (APIRouter, optional): The API router to include. + Defaults to None. + + Returns: + None + + """ self._fastapi_app: FastAPI = FastAPI( title=config.title, description=config.description, @@ -55,13 +60,9 @@ def __init__( self._fastapi_app.include_router(router=api_router) def get_asgi_app(self) -> FastAPI: - """ - Get the ASGI application. - """ + """Get the ASGI application.""" return self._fastapi_app async def __call__(self, scope: Any, receive: Any, send: Any) -> None: - """ - Forward the call to the FastAPI app. - """ + """Forward the call to the FastAPI app.""" return await self._fastapi_app.__call__(scope=scope, receive=receive, send=send) diff --git a/src/python_factory/core/app/base/module.py b/src/python_factory/core/app/base/module.py index f7745a4..83c54a0 100644 --- a/src/python_factory/core/app/base/module.py +++ b/src/python_factory/core/app/base/module.py @@ -1,6 +1,4 @@ -""" -Provide a generic module for injection bindings for the application. -""" +"""Provide a generic module for injection bindings for the application.""" from typing import Generic, TypeVar, get_args @@ -22,16 +20,18 @@ class GenericBaseApplicationModule(Generic[APP_T, CONFIG_T], injector.Module): - """ - Generic application module. - """ + """Generic application module.""" def configure(self, binder: injector.Binder) -> None: - """ - Configure injection bindings for the application - in a generic way. - """ + """Configure injection bindings for the application in a generic way. + + Args: + binder (injector.Binder): The injector binder. + + Returns: + None + """ # Retrieve the concrete application class and configuration class app_concrete_class, app_config_concrete_class = get_args( self.__orig_bases__[0] # type: ignore[attr-defined] @@ -54,7 +54,7 @@ def configure(self, binder: injector.Binder) -> None: # Like the application class, bind the concrete application configuration # and the application configuration abstract class to the same provider. application_config_callable_provider = injector.CallableProvider( - self._build_generic_application_config + callable=self._build_generic_application_config ) binder.bind( interface=app_config_concrete_class, @@ -70,8 +70,8 @@ def configure(self, binder: injector.Binder) -> None: binder.install(module=OpenTelemetryPluginModule) def _build_generic_application_config(self) -> CONFIG_T | None: - """ - Generic Builder for the application configuration. + """Generic Builder for the application configuration. + Use the concrete application class to build the concrete application configuration class. @@ -87,7 +87,6 @@ def _build_generic_application_config(self) -> CONFIG_T | None: The application configuration """ - # Retrieve the concrete application class # and the concrete application configuration class app_concrete_class, app_config_concrete_class = get_args( diff --git a/src/python_factory/core/app/base/plugins_manager_abstract.py b/src/python_factory/core/app/base/plugins_manager_abstract.py index 5ffd303..2d1c078 100644 --- a/src/python_factory/core/app/base/plugins_manager_abstract.py +++ b/src/python_factory/core/app/base/plugins_manager_abstract.py @@ -1,6 +1,4 @@ -""" -Plugins manager abstract module. -""" +"""Plugins manager abstract module.""" from abc import ABC from importlib import import_module @@ -20,9 +18,7 @@ class PluginsActivationList(BaseModel): - """ - Model for the plugins activation list. - """ + """Model for the plugins activation list.""" model_config = ConfigDict(extra="forbid") @@ -30,8 +26,7 @@ class PluginsActivationList(BaseModel): class ApplicationPluginManagerAbstract(ABC): - """ - Abstract class for the application plugin manager. + """Abstract class for the application plugin manager. Responsibilities: - Retrieve the plugins for the application. @@ -45,7 +40,7 @@ class ApplicationPluginManagerAbstract(ABC): PLUGIN_PACKAGE_NAME: str = "python_factory.core.plugins" def __init__(self) -> None: - + """Instanciate the application plugin manager.""" if self.PACKAGE_NAME == "": raise ValueError( "The package name must be set in the concrete plugin manager class." @@ -62,17 +57,14 @@ def __init__(self) -> None: rich.inspect(self._plugins) def _check_pre_conditions(self) -> None: - """ - Check the pre-conditions for the plugins. + """Check the pre-conditions for the plugins. Raises: ApplicationPluginManagerException: If a plugin is not activated. """ - for plugin in self._plugins_activation_list.activate: - try: plugin_module: ModuleType = import_module( name=f"{self.PLUGIN_PACKAGE_NAME}.{plugin.value}" @@ -95,8 +87,7 @@ def _check_pre_conditions(self) -> None: self._plugins.append(plugin_module) def _build_plugins_activation_list(self) -> PluginsActivationList: - """ - Build the plugins activation list. + """Build the plugins activation list. Returns: PluginsActivationList: The plugins activation list. @@ -108,7 +99,6 @@ def _build_plugins_activation_list(self) -> PluginsActivationList: creating the configuration model. """ - try: config: PluginsActivationList = build_config_from_file_in_package( package_name=self.PACKAGE_NAME, diff --git a/src/python_factory/core/app/base/protocols.py b/src/python_factory/core/app/base/protocols.py index 16ae73f..3f6b877 100644 --- a/src/python_factory/core/app/base/protocols.py +++ b/src/python_factory/core/app/base/protocols.py @@ -1,10 +1,9 @@ -""" -Protocols for the base application. -""" +"""Protocols for the base application.""" from typing import Protocol class BaseApplicationProtocol(Protocol): + """Protocol for the base application.""" PACKAGE_NAME: str diff --git a/src/python_factory/core/app/enums.py b/src/python_factory/core/app/enums.py index 1c98868..b16efd8 100644 --- a/src/python_factory/core/app/enums.py +++ b/src/python_factory/core/app/enums.py @@ -1,11 +1,11 @@ -""" -Provides enums for the app module. -""" +"""Provides enums for the app module.""" from enum import StrEnum class EnvironmentEnum(StrEnum): + """Represents the environment.""" + DEVELOPMENT = "development" STAGING = "staging" PRODUCTION = "production" diff --git a/src/python_factory/core/app/utils.py b/src/python_factory/core/app/utils.py index 5f3109c..3f927e4 100644 --- a/src/python_factory/core/app/utils.py +++ b/src/python_factory/core/app/utils.py @@ -1,6 +1,4 @@ -""" -Provides utilities for the application. -""" +"""Provides utilities for the application.""" import uvicorn import uvicorn.server @@ -9,17 +7,26 @@ class UvicornUtils: - """ - Provides utilities for Uvicorn. - """ + """Provides utilities for Uvicorn.""" def __init__(self, app: BaseApplication, config: AppConfigAbstract) -> None: + """Instanticate the factory. + + Args: + app (BaseApplication): The application. + config (AppConfigAbstract): The application configuration. + + Returns: + None + """ self._app: BaseApplication = app self._config: AppConfigAbstract = config def build_uvicorn_config(self) -> uvicorn.Config: - """ - Build the Uvicorn configuration. + """Build the Uvicorn configuration. + + Returns: + uvicorn.Config: The Uvicorn configuration. """ return uvicorn.Config( app=self._app.get_asgi_app(), @@ -30,9 +37,7 @@ def build_uvicorn_config(self) -> uvicorn.Config: ) def serve(self) -> None: - """ - Serve the application. - """ + """Serve the application.""" config: uvicorn.Config = self.build_uvicorn_config() server: uvicorn.Server = uvicorn.Server(config=config) server.run() diff --git a/src/python_factory/core/plugins/__init__.py b/src/python_factory/core/plugins/__init__.py index 4979c25..0b287e0 100644 --- a/src/python_factory/core/plugins/__init__.py +++ b/src/python_factory/core/plugins/__init__.py @@ -1,7 +1,4 @@ -""" -Package for plugins. - -""" +"""Package for plugins.""" from enum import StrEnum, auto @@ -9,6 +6,8 @@ class PluginsEnum(StrEnum): + """Enumeration for the plugins.""" + OPENTELEMETRY_PLUGIN = auto() diff --git a/src/python_factory/core/plugins/opentelemetry_plugin/__init__.py b/src/python_factory/core/plugins/opentelemetry_plugin/__init__.py index 70a526d..2082dad 100644 --- a/src/python_factory/core/plugins/opentelemetry_plugin/__init__.py +++ b/src/python_factory/core/plugins/opentelemetry_plugin/__init__.py @@ -1,6 +1,4 @@ -""" -OpenTelemetry Plugin Module -""" +"""OpenTelemetry Plugin Module.""" from injector import Module @@ -21,22 +19,37 @@ def pre_conditions_check(application: BaseApplicationProtocol) -> bool: - """ - Check the pre-conditions for the OpenTelemetry plugin. + """Check the pre-conditions for the OpenTelemetry plugin. + + Args: + application (BaseApplicationProtocol): The application. + + Returns: + bool: True if the pre-conditions are met, False otherwise. """ del application return True async def on_startup(application: BaseApplicationProtocol) -> None: - """ - Actions to perform on startup for the OpenTelemetry plugin. + """Actions to perform on startup for the OpenTelemetry plugin. + + Args: + application (BaseApplicationProtocol): The application. + + Returns: + None """ del application async def on_shutdown(application: BaseApplicationProtocol) -> None: - """ - Actions to perform on shutdown for the OpenTelemetry plugin. + """Actions to perform on shutdown for the OpenTelemetry plugin. + + Args: + application (BaseApplicationProtocol): The application. + + Returns: + None """ del application diff --git a/src/python_factory/core/plugins/opentelemetry_plugin/configs.py b/src/python_factory/core/plugins/opentelemetry_plugin/configs.py index 14a98e3..6271e64 100644 --- a/src/python_factory/core/plugins/opentelemetry_plugin/configs.py +++ b/src/python_factory/core/plugins/opentelemetry_plugin/configs.py @@ -1,6 +1,4 @@ -""" -Provides the configuration model for the OpenTelemetry plugin. -""" +"""Provides the configuration model for the OpenTelemetry plugin.""" from typing import Annotated @@ -9,9 +7,7 @@ class OpenTelemetryMeterConfig(BaseModel): - """ - Provides the configuration model for the OpenTelemetry meter as sub-model. - """ + """Provides the configuration model for the OpenTelemetry meter as sub-model.""" model_config = ConfigDict(frozen=True, extra="forbid") @@ -27,9 +23,7 @@ class OpenTelemetryMeterConfig(BaseModel): class OpenTelemetryTracerConfig(BaseModel): - """ - Provides the configuration model for the OpenTelemetry tracer as sub-model. - """ + """Provides the configuration model for the OpenTelemetry tracer as sub-model.""" model_config = ConfigDict(frozen=True, extra="forbid") @@ -52,9 +46,7 @@ class OpenTelemetryTracerConfig(BaseModel): class OpenTelemetryConfig(BaseModel): - """ - Provides the configuration model for the OpenTelemetry plugin. - """ + """Provides the configuration model for the OpenTelemetry plugin.""" COLLECTOR_ENDPOINT_DEFAULT: str = "http://localhost:4317" diff --git a/src/python_factory/core/plugins/opentelemetry_plugin/exceptions.py b/src/python_factory/core/plugins/opentelemetry_plugin/exceptions.py index 8494bf5..0370de2 100644 --- a/src/python_factory/core/plugins/opentelemetry_plugin/exceptions.py +++ b/src/python_factory/core/plugins/opentelemetry_plugin/exceptions.py @@ -1,11 +1,13 @@ -""" -Provides the exceptions for the OpenTelemetryPlugin. -""" +"""Provides the exceptions for the OpenTelemetryPlugin.""" class OpenTelemetryPluginBaseException(BaseException): + """Base exception for the OpenTelemetryPlugin.""" + pass class OpenTelemetryPluginConfigError(OpenTelemetryPluginBaseException): + """Exception for the OpenTelemetryPlugin configuration.""" + pass diff --git a/src/python_factory/core/plugins/opentelemetry_plugin/providers.py b/src/python_factory/core/plugins/opentelemetry_plugin/providers.py index d527fc1..14bec65 100644 --- a/src/python_factory/core/plugins/opentelemetry_plugin/providers.py +++ b/src/python_factory/core/plugins/opentelemetry_plugin/providers.py @@ -1,6 +1,4 @@ -""" -Provides a factory function to build a objets for OpenTelemetry. -""" +"""Provides a factory function to build a objets for OpenTelemetry.""" from typing import Any @@ -35,18 +33,14 @@ class OpenTelemetryPluginModule(injector.Module): - """ - Configure the injection bindings for OpenTelemetryPlugin. - """ + """Configure the injection bindings for OpenTelemetryPlugin.""" @injector.singleton @injector.provider def resource_factory( self, application: injector.Inject[BaseApplication] ) -> Resource: - """ - Build a resource object for OpenTelemetry - from the application and it's configuration. + """Build a resource object for OpenTelemetry from the application and configs. Args: application (BaseApplication): The application object. @@ -54,7 +48,6 @@ def resource_factory( Returns: Resource: The resource object for OpenTelemetry. """ - return Resource( attributes={ DEPLOYMENT_ENVIRONMENT: application.get_config().environment.value, @@ -71,8 +64,7 @@ def meter_provider_factory( resource: injector.Inject[Resource], opentelemetry_config: injector.Inject[OpenTelemetryConfig], ) -> MeterProvider: - """ - Build a meter provider object for OpenTelemetry + """Build a meter provider object for OpenTelemetry. Args: resource (Resource): The resource object for OpenTelemetry. @@ -82,7 +74,6 @@ def meter_provider_factory( Returns: MeterProvider: The meter provider object for OpenTelemetry. """ - # Exit with a void MeterProvider if the export is not activated if opentelemetry_config.activate is False: return MeterProvider( @@ -125,8 +116,7 @@ def tracer_provider_factory( resource: injector.Inject[Resource], opentelemetry_config: injector.Inject[OpenTelemetryConfig], ) -> TracerProvider: - """ - Provides a tracer provider for OpenTelemetry. + """Provides a tracer provider for OpenTelemetry. Args: resource (Resource): The resource object for OpenTelemetry. @@ -136,7 +126,6 @@ def tracer_provider_factory( Returns: TracerProvider: The tracer provider object for OpenTelemetry. """ - # Exit with a void TracerProvider if the export is not activated if opentelemetry_config.activate is False: return TracerProvider( @@ -189,7 +178,14 @@ def provider_open_telemetry_config( self, base_application: injector.Inject["BaseApplication"], ) -> OpenTelemetryConfig: + """Provide the OpenTelemetry configuration. + + Args: + base_application (BaseApplication): The base application object. + Returns: + OpenTelemetryConfig: The OpenTelemetry configuration object. + """ if base_application.PACKAGE_NAME == "": raise OpenTelemetryPluginConfigError( "The package name must be set in the concrete application class." diff --git a/src/python_factory/core/plugins/protocols.py b/src/python_factory/core/plugins/protocols.py index c4e3318..18d0c4b 100644 --- a/src/python_factory/core/plugins/protocols.py +++ b/src/python_factory/core/plugins/protocols.py @@ -1,6 +1,4 @@ -""" -Defines the protocols for the plugins. -""" +"""Defines the protocols for the plugins.""" from typing import Protocol, runtime_checkable @@ -11,26 +9,44 @@ @runtime_checkable class PluginProtocol(Protocol): - """ - Defines the protocol for the plugin. + """Defines the protocol for the plugin. + + Attributes: + INJECTOR_MODULE (type[Module]): The module for the plugin. + """ INJECTOR_MODULE: type[Module] def pre_conditions_check(self, application: BaseApplicationProtocol) -> bool: - """ - Check the pre-conditions for the plugin. + """Check the pre-conditions for the plugin. + + Args: + application (BaseApplicationProtocol): The application. + + Returns: + bool: True if the pre-conditions are met, False otherwise. """ raise NotImplementedError async def on_startup(self, application: BaseApplicationProtocol) -> None: - """ - The actions to perform on startup for the plugin. + """The actions to perform on startup for the plugin. + + Args: + application (BaseApplicationProtocol): The application. + + Returns: + None """ raise NotImplementedError async def on_shutdown(self, application: BaseApplicationProtocol) -> None: - """ - The actions to perform on shutdown for the plugin. + """The actions to perform on shutdown for the plugin. + + Args: + application (BaseApplicationProtocol): The application. + + Returns: + None """ raise NotImplementedError diff --git a/src/python_factory/core/utils/configs.py b/src/python_factory/core/utils/configs.py index 1c7caa6..c8a5bff 100644 --- a/src/python_factory/core/utils/configs.py +++ b/src/python_factory/core/utils/configs.py @@ -1,6 +1,4 @@ -""" -Provides utilities to handle configurations. -""" +"""Provides utilities to handle configurations.""" from typing import Any, TypeVar @@ -18,25 +16,19 @@ class ConfigBaseException(BaseException): - """ - Base exception for all the configuration exceptions. - """ + """Base exception for all the configuration exceptions.""" pass class UnableToReadConfigFileError(ConfigBaseException): - """ - Exception raised when the configuration file cannot be read. - """ + """Exception raised when the configuration file cannot be read.""" pass class ValueErrorConfigError(ConfigBaseException): - """ - Exception raised when the configuration file cannot be read. - """ + """Exception raised when the configuration file cannot be read.""" pass @@ -47,13 +39,13 @@ def build_config_from_file_in_package( config_class: type[GENERIC_CONFIG], yaml_base_key: str, ) -> GENERIC_CONFIG: - """ - Build a configuration object from a file in a package. + """Build a configuration object from a file in a package. Args: package_name (str): The package name. filename (str): The filename. config_class (type[GENERIC_CONFIG]): The configuration class. + yaml_base_key (str): The base key in the YAML file. Returns: GENERIC_CONFIG: The configuration object. @@ -62,7 +54,6 @@ def build_config_from_file_in_package( UnableToReadConfigFileError: If the configuration file cannot be read. ValueErrorConfigError: If the configuration file is invalid. """ - # Read the application configuration file try: yaml_file_content: dict[str, Any] = YamlFileReader( diff --git a/src/python_factory/core/utils/importlib.py b/src/python_factory/core/utils/importlib.py index 070ea0a..ee95291 100644 --- a/src/python_factory/core/utils/importlib.py +++ b/src/python_factory/core/utils/importlib.py @@ -1,12 +1,11 @@ -""" Provide importlib functions """ +"""Provide importlib functions.""" from importlib.resources import files from pathlib import Path def get_path_file_in_package(filename: str, package: str) -> Path: - """ - Return Absolute Path of file in package + """Return Absolute Path of file in package. Args: filename (str): Filename to search diff --git a/src/python_factory/core/utils/log.py b/src/python_factory/core/utils/log.py index 37d6d1e..077568d 100644 --- a/src/python_factory/core/utils/log.py +++ b/src/python_factory/core/utils/log.py @@ -1,6 +1,4 @@ -""" -Provides a function to setup the logging configuration. -""" +"""Provides a function to setup the logging configuration.""" from enum import StrEnum, auto @@ -10,17 +8,14 @@ class LogModeEnum(StrEnum): - """ - Defines the possible logging modes. - """ + """Defines the possible logging modes.""" CONSOLE = auto() JSON = auto() def setup_log(mode: LogModeEnum = LogModeEnum.CONSOLE) -> None: - """ - Prepares the logging configuration. + """Prepares the logging configuration. Args: mode (LogMode): The logging mode to use. @@ -28,7 +23,6 @@ def setup_log(mode: LogModeEnum = LogModeEnum.CONSOLE) -> None: Returns: None """ - processors: list[structlog.typing.Processor] = [ structlog.stdlib.add_log_level, structlog.processors.TimeStamper(fmt="iso"), diff --git a/src/python_factory/core/utils/yaml_reader.py b/src/python_factory/core/utils/yaml_reader.py index 0e9a07d..640ae51 100644 --- a/src/python_factory/core/utils/yaml_reader.py +++ b/src/python_factory/core/utils/yaml_reader.py @@ -1,6 +1,4 @@ -""" -Provides a class for reading YAML files and converting them to Pydantic models. -""" +"""Provides a class for reading YAML files and converting them to Pydantic models.""" # mypy: disable-error-code="unused-ignore" @@ -13,13 +11,10 @@ class UnableToReadYamlFileError(Exception): - """ - Raised when there is an error reading a YAML file. - """ + """Raised when there is an error reading a YAML file.""" def __init__(self, file_path: Path | None = None, message: str = "") -> None: - """ - Initializes the exception. + """Initializes the exception. Args: file_path (str): The path to the YAML file. @@ -29,9 +24,7 @@ def __init__(self, file_path: Path | None = None, message: str = "") -> None: class YamlFileReader: - """ - Handles reading YAML files and converting them to Pydantic models. - """ + """Handles reading YAML files and converting them to Pydantic models.""" re_pattern: re.Pattern[str] = re.compile( r"\${([A-Za-z0-9\-\_]+):?([A-Za-z0-9\-\_]*)?}" @@ -43,8 +36,7 @@ def __init__( yaml_base_key: str | None = None, use_environment_injection: bool = True, ) -> None: - """ - Initializes the YAML file reader. + """Initializes the YAML file reader. Args: file_path (str): The path to the YAML file. @@ -53,7 +45,6 @@ def __init__( use_environment_injection (bool, optional): Whether to use environment injection. Defaults to True. """ - # Store the file path and base key for YAML reading self._yaml_base_key: str | None = yaml_base_key self._file_path: Path = file_path @@ -62,12 +53,14 @@ def __init__( self._use_environment_injection: bool = use_environment_injection def _filter_data_with_base_key(self, yaml_data: dict[str, Any]) -> dict[str, Any]: - """ - Extracts the data from the YAML file with the base key. + """Extracts the data from the YAML file with the base key. + Args: yaml_data (dict): The data from the YAML file. + Returns: dict: The filtered data from the YAML file. + Raises: KeyError: If the base key is not found in the YAML file. """ @@ -85,8 +78,8 @@ def _filter_data_with_base_key(self, yaml_data: dict[str, Any]) -> dict[str, Any return yaml_data def _read_yaml_file(self, file_path: Path) -> dict[str, Any]: - """ - Reads the YAML file and returns the data as a dictionary. + """Reads the YAML file and returns the data as a dictionary. + Args: file_path (Path): The path to the YAML file. @@ -116,10 +109,11 @@ def _read_yaml_file(self, file_path: Path) -> dict[str, Any]: def _inject_environment_variables( self, yaml_data: dict[str, Any] | str | list[str] ) -> dict[str, Any] | str | list[str]: - """ - Injects environment variables into the YAML data recursively. + """Injects environment variables into the YAML data recursively. + Args: yaml_data (dict | str | list): The data from the YAML file. + Returns: dict: The data from the YAML file with environment variables injected. @@ -145,14 +139,11 @@ def _inject_environment_variables( return yaml_data def read(self) -> dict[str, Any]: - """ - Reads the YAML file and converts it to a Pydantic model - with or without environment injection. + """Reads the YAML file and converts it to a Pydantic model with env injected. Raises: UnableToReadYamlFileError: If there is an error reading the file. """ - # Read the YAML file and filter the data with the base key try: yaml_data: dict[str, Any] = self._filter_data_with_base_key( diff --git a/src/python_factory/example/__init__.py b/src/python_factory/example/__init__.py index 735eb1e..43ddd43 100644 --- a/src/python_factory/example/__init__.py +++ b/src/python_factory/example/__init__.py @@ -1,6 +1,4 @@ -""" -Python Factory Example -""" +"""Python Factory Example.""" from python_factory.core.app.utils import UvicornUtils from python_factory.core.utils.log import LogModeEnum, setup_log @@ -8,13 +6,12 @@ def application_factory() -> App: - """ - Provides the application factory. - """ + """Provides the application factory.""" return factory_for_app() def main() -> None: + """Main function.""" setup_log(mode=LogModeEnum.CONSOLE) application: App = application_factory() uvicorn_utils = UvicornUtils(app=application, config=application.get_config()) diff --git a/src/python_factory/example/__main__.py b/src/python_factory/example/__main__.py index e6c8884..5c53170 100644 --- a/src/python_factory/example/__main__.py +++ b/src/python_factory/example/__main__.py @@ -1,6 +1,4 @@ -""" -Main entry point for the application. -""" +"""Main entry point for the application.""" from python_factory.example import main diff --git a/src/python_factory/example/app/__init__.py b/src/python_factory/example/app/__init__.py index 68836b7..0996448 100644 --- a/src/python_factory/example/app/__init__.py +++ b/src/python_factory/example/app/__init__.py @@ -1,6 +1,4 @@ -""" -Provides the App and AppConfig classes. -""" +"""Provides the App and AppConfig classes.""" from .app import App, factory_for_app from .config import AppConfig diff --git a/src/python_factory/example/app/app.py b/src/python_factory/example/app/app.py index 2c4599a..1e1ff58 100644 --- a/src/python_factory/example/app/app.py +++ b/src/python_factory/example/app/app.py @@ -1,6 +1,4 @@ -""" -Provides the concrete application class. -""" +"""Provides the concrete application class.""" import injector @@ -10,23 +8,26 @@ class App(BaseApplication): - """ - Concrete application class. - """ + """Concrete application class.""" PACKAGE_NAME: str = "python_factory.example" def __init__(self, config: injector.Inject[AppConfig]) -> None: + """Instanciate the application. + + Args: + config (AppConfig): The application configuration. + """ super().__init__(config=config) class AppModule(GenericBaseApplicationModule[App, AppConfig]): + """Configure the injection bindings for the application.""" + pass def factory_for_app() -> App: - """ - Provides the application factory. - """ + """Provides the application factory.""" injector_instance = injector.Injector(modules=[AppModule]) return injector_instance.get(interface=App) diff --git a/src/python_factory/example/app/config.py b/src/python_factory/example/app/config.py index 5ca62e2..fec51a6 100644 --- a/src/python_factory/example/app/config.py +++ b/src/python_factory/example/app/config.py @@ -1,10 +1,10 @@ -""" -Provides the application configuration. -""" +"""Provides the application configuration.""" from python_factory.core.app import AppConfigAbstract class AppConfig(AppConfigAbstract): + """The application configuration.""" + title: str = "Python Factory Example" description: str = "An example application for Python Factory." diff --git a/tests/units/conf_test.py b/tests/units/conf_test.py index e69de29..a6cecf1 100644 --- a/tests/units/conf_test.py +++ b/tests/units/conf_test.py @@ -0,0 +1 @@ +"""Cong Test.""" diff --git a/tests/units/python_factory/core/app/base/test_plugins_manager_abstract.py b/tests/units/python_factory/core/app/base/test_plugins_manager_abstract.py index df281ce..829e8de 100644 --- a/tests/units/python_factory/core/app/base/test_plugins_manager_abstract.py +++ b/tests/units/python_factory/core/app/base/test_plugins_manager_abstract.py @@ -1,3 +1 @@ -""" -Provides unit tests for the `PluginsManagerAbstract` class. -""" +"""Provides unit tests for the `PluginsManagerAbstract` class.""" diff --git a/tests/units/python_factory/core/utils/test_configs.py b/tests/units/python_factory/core/utils/test_configs.py index a427b57..a1d8b16 100644 --- a/tests/units/python_factory/core/utils/test_configs.py +++ b/tests/units/python_factory/core/utils/test_configs.py @@ -1,6 +1,4 @@ -""" -Test for python_factory.core.utils.configs -""" +"""Test for python_factory.core.utils.configs.""" from collections.abc import Iterator from contextlib import contextmanager @@ -19,9 +17,7 @@ class TestBuildConfigFromFileInPackage: - """ - Provides test cases for the build_config_from_file_in_package function. - """ + """Provides test cases for the build_config_from_file_in_package function.""" @contextmanager def mock_method( @@ -31,7 +27,21 @@ def mock_method( base_key: str = "base_key", side_effects: type[Exception] | None = None, ) -> Iterator[tuple[MagicMock, MagicMock, MagicMock]]: + """Mock the methods used in the build_config_from_file_in_package function. + Args: + mock_value_file_path (str): The file path. + mock_value_file_content (dict[str, Any]): The file content. + base_key (str): The base key in the yaml file. + side_effects (type[Exception] | None): The side effects for the read method. + + Yields: + tuple[MagicMock, MagicMock, MagicMock]: The mocks for the methods. ( + mock_get_path_file_in_package, + mock_yamlfilereader_constructor, + mock_yaml_file_reader_object) + + """ # mock get_path_file_in_package with patch( "python_factory.core.utils.configs.get_path_file_in_package" @@ -60,14 +70,10 @@ def mock_method( ) def test_build_config_from_file_in_package(self) -> None: - """ - Test the case where the configuration file is read successfully. - """ + """Test the case where the configuration file is read successfully.""" class TestConfigModel(BaseModel): - """ - Test configuration model. - """ + """Test configuration model.""" key: str @@ -107,10 +113,7 @@ class TestConfigModel(BaseModel): def test_build_config_from_file_in_package_with_exception( self, side_effects: type[Exception], expected_raise: type[Exception] ) -> None: - """ - Test the case where an exception is raised while reading the configuration file. - """ - + """Test the case where an exception is raised.""" mock_value_file_path: str = "file_path" mock_value_package_name: str = "package_name" mock_value_file_content: dict[str, str] = { @@ -133,9 +136,7 @@ def test_build_config_from_file_in_package_with_exception( ) def test_build_config_from_file_in_package_with_invalid_config(self) -> None: - """ - Test the case where the configuration file is invalid. - """ + """Test the case where the configuration file is invalid.""" class TestConfigModel(BaseModel): key: str diff --git a/tests/units/python_factory/core/utils/test_importlib.py b/tests/units/python_factory/core/utils/test_importlib.py index 5aa6871..8a376b6 100644 --- a/tests/units/python_factory/core/utils/test_importlib.py +++ b/tests/units/python_factory/core/utils/test_importlib.py @@ -1,6 +1,4 @@ -""" -Testing the importlib module. -""" +"""Testing the importlib module.""" from pathlib import Path from unittest.mock import patch @@ -10,7 +8,8 @@ from python_factory.core.utils.importlib import get_path_file_in_package -def test_get_path_file_in_package_file_found(): +def test_get_path_file_in_package_file_found() -> None: + """Test the case where the file is found.""" # Mock the files function from importlib.resources with patch("python_factory.core.utils.importlib.files") as files_mock: # Mock the joinpath method of the files object @@ -18,7 +17,7 @@ def test_get_path_file_in_package_file_found(): joinpath_mock.return_value = Path("/path/to/file.txt") # Call the function - result = get_path_file_in_package("file.txt", "package") + result = get_path_file_in_package(filename="file.txt", package="package") # Assert that the joinpath method was called with the correct arguments joinpath_mock.assert_called_once_with("file.txt") @@ -27,7 +26,8 @@ def test_get_path_file_in_package_file_found(): assert result == Path("/path/to/file.txt") -def test_get_path_file_in_package_file_not_found(): +def test_get_path_file_in_package_file_not_found() -> None: + """Test the case where the file is not found.""" # Mock the files function from importlib.resources with patch("python_factory.core.utils.importlib.files") as files_mock: # Mock the joinpath method of the files object to raise FileNotFoundError @@ -39,7 +39,8 @@ def test_get_path_file_in_package_file_not_found(): get_path_file_in_package("file.txt", "package") -def test_get_path_file_in_package_package_not_found(): +def test_get_path_file_in_package_package_not_found() -> None: + """Test the case where the package is not found.""" # Mock the files function from importlib.resources to raise ImportError with patch("python_factory.core.utils.importlib.files", side_effect=ImportError): # Call the function and assert that it raises ImportError diff --git a/tests/units/python_factory/core/utils/test_log.py b/tests/units/python_factory/core/utils/test_log.py index 3be82b3..046f686 100644 --- a/tests/units/python_factory/core/utils/test_log.py +++ b/tests/units/python_factory/core/utils/test_log.py @@ -1,6 +1,4 @@ -""" -Test the setup.log module -""" +"""Test the setup.log module.""" from unittest.mock import MagicMock, patch @@ -8,18 +6,17 @@ class TestSetupLog: - """ - Various tests for the setup_log function - """ + """Various tests for the setup_log function.""" @patch("structlog.configure") def test_structlog_has_been_configured( self, structlog_configure_mock: MagicMock ) -> None: - """ - Test that structlog has been configured - """ + """Test that structlog has been configured. + Args: + structlog_configure_mock (MagicMock): The structlog.configure mock. + """ setup_log() # Called once and only once diff --git a/tests/units/python_factory/core/utils/test_yaml_reader.py b/tests/units/python_factory/core/utils/test_yaml_reader.py index 26ff876..cc93790 100644 --- a/tests/units/python_factory/core/utils/test_yaml_reader.py +++ b/tests/units/python_factory/core/utils/test_yaml_reader.py @@ -1,6 +1,4 @@ -""" -Provides unit tests for the YamlFileReader class. -""" +"""Provides unit tests for the YamlFileReader class.""" from pathlib import Path from typing import Any @@ -15,18 +13,13 @@ class TestYamlFileReader: - """ - Provides unit tests for the YamlFileReader class. - """ + """Provides unit tests for the YamlFileReader class.""" def test_simple_yaml_read(self) -> None: - """ - Tests reading a simple YAML file. - """ - + """Tests reading a simple YAML file.""" yaml_test_key = "key" yaml_test_value = "value" - data = f""" + data: str = f""" {yaml_test_key}: {yaml_test_value} """ with patch("os.path.exists", return_value=True) as mock_exists: @@ -48,10 +41,7 @@ def test_simple_yaml_read(self) -> None: assert read_data == {yaml_test_key: yaml_test_value} def test_yaml_read_with_base_key(self) -> None: - """ - Tests reading a YAML file with a base key. - """ - + """Tests reading a YAML file with a base key.""" yaml_test_key = "key" yaml_test_value = "value" yaml_base_key = "base_key" @@ -78,14 +68,11 @@ def test_yaml_read_with_base_key(self) -> None: assert read_data == {yaml_test_key: yaml_test_value} def test_yaml_read_with_base_key_multiple_levels(self) -> None: - """ - Tests reading a YAML file with a base key with multiple levels. - """ - + """Tests reading a YAML file with a base key with multiple levels.""" yaml_test_key = "key" yaml_test_value = "value" yaml_base_key = "base.key" - data = f""" + data: str = f""" base: key: {yaml_test_key}: {yaml_test_value} @@ -109,10 +96,7 @@ def test_yaml_read_with_base_key_multiple_levels(self) -> None: assert read_data == {yaml_test_key: yaml_test_value} def test_yaml_read_with_base_key_not_present(self) -> None: - """ - Tests reading a YAML file with a base key not present. - """ - + """Tests reading a YAML file with a base key not present.""" yaml_test_key = "key" yaml_test_value = "value" yaml_base_key = "base_key" @@ -136,10 +120,7 @@ def test_yaml_read_with_base_key_not_present(self) -> None: ) def test_yaml_read_with_simple_env_value_to_inject(self) -> None: - """ - Tests reading a YAML file with a simple environment value to inject. - """ - + """Tests reading a YAML file with a simple environment value to inject.""" yaml_test_key = "key" yaml_test_value = "value" data: str = f""" @@ -165,10 +146,7 @@ def test_yaml_read_with_simple_env_value_to_inject(self) -> None: assert read_data == {yaml_test_key: yaml_test_value} def test_yaml_read_with_list(self) -> None: - """ - Tests reading a YAML file with a list. - """ - + """Tests reading a YAML file with a list.""" yaml_test_key = "key" yaml_test_value: list[str] = ["value1", "value2"] data: str = f""" @@ -226,10 +204,13 @@ def test_yaml_read_with_list(self) -> None: def test_yaml_read_with_env_value_to_inject( self, data: str, env_mock: dict[str, str], expected_result: dict[str, str] ) -> None: - """ - Tests reading a YAML file with an environment value to inject. - """ + """Tests reading a YAML file with an environment value to inject. + Args: + data (str): The data to read. + env_mock (dict[str, str]): The environment key and value to be mocked. + expected_result (dict[str, str]): The expected result. + """ with patch("os.path.exists", return_value=True) as mock_exists: with patch( "builtins.open", new_callable=mock_open, read_data=data diff --git a/tests/units/python_factory/example/api/v1/sys/test_health.py b/tests/units/python_factory/example/api/v1/sys/test_health.py index b5c9edb..173a268 100644 --- a/tests/units/python_factory/example/api/v1/sys/test_health.py +++ b/tests/units/python_factory/example/api/v1/sys/test_health.py @@ -1,6 +1,6 @@ -""" -Test cases for the health endpoint. -""" +"""Test cases for the health endpoint.""" + +from http import HTTPStatus from fastapi.testclient import TestClient from httpx import Response @@ -9,17 +9,13 @@ class TestApiV1SysHealth: - """ - Test the health endpoint. - """ + """Test the health endpoint.""" def test_get_api_v1_sys_health(self) -> None: - """ - Test the get_api_v1_sys_health function. - """ - + """Test the get_api_v1_sys_health function.""" with TestClient(app=application_factory()) as client: response: Response = client.get(url="/api/v1/sys/health") - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK.value + assert response.json() == {"status": "healthy"} assert response.json() == {"status": "healthy"}