aboutsummaryrefslogtreecommitdiff
path: root/tools/cru-py/cru/service
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2024-11-11 01:12:29 +0800
committerYuqian Yang <crupest@crupest.life>2025-01-16 21:14:14 +0800
commitc0ba4d9d8d19d3faa7b4d2b3509546e37dd32364 (patch)
tree4b3d969850981094ba33e18ac9ec49fbc409dc93 /tools/cru-py/cru/service
parent7f2e4107e7f469d6747350487e9441d9b987de47 (diff)
downloadcrupest-c0ba4d9d8d19d3faa7b4d2b3509546e37dd32364.tar.gz
crupest-c0ba4d9d8d19d3faa7b4d2b3509546e37dd32364.tar.bz2
crupest-c0ba4d9d8d19d3faa7b4d2b3509546e37dd32364.zip
HALF WORK: 2024.1.16
Diffstat (limited to 'tools/cru-py/cru/service')
-rw-r--r--tools/cru-py/cru/service/__main__.py12
-rw-r--r--tools/cru-py/cru/service/_base.py37
-rw-r--r--tools/cru-py/cru/service/_config.py51
3 files changed, 47 insertions, 53 deletions
diff --git a/tools/cru-py/cru/service/__main__.py b/tools/cru-py/cru/service/__main__.py
index c218bc6..1c10e82 100644
--- a/tools/cru-py/cru/service/__main__.py
+++ b/tools/cru-py/cru/service/__main__.py
@@ -1,4 +1,4 @@
-from cru import CruUserFriendlyException
+from cru import CruException
from ._app import create_app
@@ -11,6 +11,10 @@ def main():
if __name__ == "__main__":
try:
main()
- except CruUserFriendlyException as e:
- print(f"Error: {e.user_message}")
- exit(1)
+ except CruException as e:
+ user_message = e.get_user_message()
+ if user_message is not None:
+ print(f"Error: {user_message}")
+ exit(1)
+ else:
+ raise
diff --git a/tools/cru-py/cru/service/_base.py b/tools/cru-py/cru/service/_base.py
index 124acd5..4454c2c 100644
--- a/tools/cru-py/cru/service/_base.py
+++ b/tools/cru-py/cru/service/_base.py
@@ -7,17 +7,27 @@ import os
from pathlib import Path
from typing import TypeVar, overload
-from cru import CruException, CruInternalError, CruPath, CruUserFriendlyException
+from cru import CruException, CruLogicError, CruPath
_Feature = TypeVar("_Feature", bound="AppFeatureProvider")
OWNER_NAME = "crupest"
-class InternalAppException(CruInternalError):
+class AppError(CruException):
pass
+class AppFeatureError(AppError):
+ def __init__(self, message, feature: type | str, *args, **kwargs):
+ super().__init__(message, *args, **kwargs)
+ self._feature = feature
+
+ @property
+ def feature(self) -> type | str:
+ return self._feature
+
+
class AppPathError(CruException):
def __init__(self, message, _path: str | Path, *args, **kwargs):
super().__init__(message, *args, **kwargs)
@@ -152,12 +162,12 @@ class AppRootPath(AppPath):
@property
def full_path(self) -> CruPath:
if self._full_path is None:
- raise CruInternalError("App root path is not set yet.")
+ raise AppError("App root path is not set yet.")
return self._full_path
def setup(self, path: os.PathLike) -> None:
if self._full_path is not None:
- raise CruInternalError("App root path is already set.")
+ raise AppError("App root path is already set.")
self._full_path = CruPath(path)
@@ -270,7 +280,7 @@ class AppBase:
@staticmethod
def get_instance() -> AppBase:
if AppBase._instance is None:
- raise CruInternalError("App instance not initialized")
+ raise AppError("App instance not initialized")
return AppBase._instance
def __init__(self, name: str):
@@ -312,8 +322,9 @@ class AppBase:
def ensure_app_initialized(self) -> AppRootPath:
if not self.app_initialized:
- raise CruUserFriendlyException(
- "Root directory does not exist. Please run 'init' to create one."
+ raise AppError(
+ user_message="Root directory does not exist. "
+ "Please run 'init' to create one."
)
return self.root
@@ -328,7 +339,9 @@ class AppBase:
def add_feature(self, feature: _Feature) -> _Feature:
for f in self.features:
if f.name == feature.name:
- raise CruInternalError(f"Duplicate feature name: {feature.name}.")
+ raise AppFeatureError(
+ f"Duplicate feature name: {feature.name}.", feature.name
+ )
self._features.append(feature)
return feature
@@ -365,14 +378,12 @@ class AppBase:
if isinstance(f, feature):
return f
else:
- raise InternalAppException(
- "Argument must be the name of feature or its class."
- )
+ raise CruLogicError("Argument must be the name of feature or its class.")
- raise InternalAppException(f"Feature {feature} not found.")
+ raise AppFeatureError(f"Feature {feature} not found.", feature)
def get_path(self, name: str) -> AppFeaturePath:
for p in self._paths:
if p.id == name or p.name == name:
return p
- raise InternalAppException(f"Application path {name} not found.")
+ raise AppPathError(f"Application path {name} not found.", name)
diff --git a/tools/cru-py/cru/service/_config.py b/tools/cru-py/cru/service/_config.py
index f2beeb2..9c91c93 100644
--- a/tools/cru-py/cru/service/_config.py
+++ b/tools/cru-py/cru/service/_config.py
@@ -1,7 +1,7 @@
from collections.abc import Iterable
from typing import Any, NoReturn
-from cru import CruException, CruUserFriendlyException
+from cru import CruException
from cru.config import Configuration, ConfigItem
from cru.value import (
INTEGER_VALUE_TYPE,
@@ -26,16 +26,6 @@ class AppConfigError(CruException):
def configuration(self) -> Configuration:
return self._configuration
- @property
- def friendly_error_message(self) -> str:
- raise NotImplementedError("Subclasses must implement this method.")
-
- def to_friendly_error(self) -> CruUserFriendlyException:
- return CruUserFriendlyException(self.friendly_error_message)
-
- def raise_friendly_error(self) -> NoReturn:
- raise self.to_friendly_error() from self
-
class AppConfigFileError(AppConfigError):
def __init__(
@@ -64,8 +54,7 @@ class AppConfigFileNotFoundError(AppConfigFileError):
def file_path(self) -> str:
return self._file_path
- @property
- def friendly_error_message(self) -> str:
+ def get_user_message(self) -> str:
return f"Config file not found at {self.file_path}. You may need to create one."
@@ -76,22 +65,18 @@ class AppConfigFileParseError(AppConfigFileError):
configuration: Configuration,
file_content: str,
*args,
- cause: ParseError | None = None,
**kwargs,
) -> None:
super().__init__(message, configuration, *args, **kwargs)
self._file_content = file_content
- if cause is not None:
- self._cause = cause
- self._cause = self.__cause__ # type: ignore
+ self.__cause__: ParseError
@property
def file_content(self) -> str:
return self._file_content
- @property
- def friendly_error_message(self) -> str:
- return f"Error while parsing config file at line {self._cause.line_number}."
+ def get_user_message(self) -> str:
+ return f"Error while parsing config file at line {self.__cause__.line_number}."
class AppConfigFileEntryError(AppConfigFileError):
@@ -123,8 +108,7 @@ class AppConfigFileEntryError(AppConfigFileError):
def friendly_message_head(self) -> str:
return "Error entries found in config file"
- @property
- def friendly_error_message(self) -> str:
+ def get_user_message(self) -> str:
return (
f"{self.friendly_message_head}:\n"
f"{self.entries_to_friendly_message(self.error_entries)}"
@@ -316,24 +300,19 @@ class ConfigManager(AppCommandFeatureProvider):
) from ExceptionGroup("Multiple format errors occurred.", errors)
return value_dict
- def _read_config_file(self, friendly: bool = False) -> dict[str, Any]:
- try:
- parsed = self._parse_config_file()
- entry_groups = parsed.cru_iter().group_by(lambda e: e.key)
- entry_dict = self._check_duplicate(entry_groups)
- entry_dict = self._check_defined(entry_dict)
- value_dict = self._check_type(entry_dict)
- return value_dict
- except AppConfigError as e:
- if friendly:
- e.raise_friendly_error()
- raise
+ def _read_config_file(self) -> dict[str, Any]:
+ parsed = self._parse_config_file()
+ entry_groups = parsed.cru_iter().group_by(lambda e: e.key)
+ entry_dict = self._check_duplicate(entry_groups)
+ entry_dict = self._check_defined(entry_dict)
+ value_dict = self._check_type(entry_dict)
+ return value_dict
def reload_config_file(self) -> bool:
self.configuration.reset_all()
value_dict = self._read_config_file()
- # TODO: Continue here!
- for key, value in config_dict.items():
+ for key, value in value_dict.items():
+ # TODO: Continue here!
self.configuration.set(key, value)
return True