1
0
Fork 0
mirror of https://github.com/yavook/kiwi-scp.git synced 2024-11-24 13:43:01 +00:00

Custom Exception classes

This commit is contained in:
Jörn-Michael Miehe 2022-02-22 13:18:35 +01:00
parent 33cb62bc3a
commit a54d66b9e7
4 changed files with 127 additions and 44 deletions

View file

@ -6,6 +6,27 @@ from typing import List, Optional
import click import click
class MissingCMDObjectError(ValueError):
"""raised if command object can't be found in its module"""
pass
class CMDObjectSubclassError(TypeError):
"""raised if a command object is not inheriting click.Command"""
pass
class CMDUnregisteredError(ValueError):
"""raised if commands have not been assigned to a command group"""
unregistered: List[str]
def __init__(self, unregistered):
self.unregistered = unregistered
super().__init__(f"Some commands were not registered in a group above: {unregistered!r}")
class KiwiCLI(click.MultiCommand): class KiwiCLI(click.MultiCommand):
"""Command Line Interface spread over multiple files in this directory""" """Command Line Interface spread over multiple files in this directory"""
@ -27,19 +48,19 @@ class KiwiCLI(click.MultiCommand):
except ImportError: except ImportError:
return return
member_name = f"{cmd_name.capitalize()}Command" cmd_object_name = f"{cmd_name.capitalize()}Command"
if member_name in dir(cmd_module): if cmd_object_name in dir(cmd_module):
member = getattr(cmd_module, member_name) cmd_object = getattr(cmd_module, cmd_object_name)
if isinstance(member, click.Command): if isinstance(cmd_object, click.Command):
return member return cmd_object
else: else:
raise Exception("Fail class") raise CMDObjectSubclassError()
else: else:
raise Exception("Fail member name") raise MissingCMDObjectError()
def format_commands(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: def format_commands(self, ctx: click.Context, formatter: click.HelpFormatter) -> None:
commands = { commands = {
@ -71,4 +92,4 @@ class KiwiCLI(click.MultiCommand):
cmd_names -= set(cmd_list) cmd_names -= set(cmd_list)
if len(cmd_names) > 0: if len(cmd_names) > 0:
raise Exception(f"Some commands were not registered in a group above: {cmd_names}") raise CMDUnregisteredError(cmd_names)

View file

@ -23,6 +23,10 @@ class KiwiCommandType(Enum):
T = TypeVar("T") T = TypeVar("T")
class KiwiCommandNotImplementedError(Exception):
pass
class KiwiCommand: class KiwiCommand:
type: KiwiCommandType = KiwiCommandType.SERVICES type: KiwiCommandType = KiwiCommandType.SERVICES
enabled_only: bool = False enabled_only: bool = False
@ -177,4 +181,4 @@ class KiwiCommand:
@classmethod @classmethod
def run_for_filtered_services(cls, instance: Instance, project: Project, services: Services, def run_for_filtered_services(cls, instance: Instance, project: Project, services: Services,
new_service_names: List[str], **kwargs) -> None: new_service_names: List[str], **kwargs) -> None:
raise Exception raise KiwiCommandNotImplementedError()

View file

@ -9,6 +9,25 @@ from ._constants import RE_SEMVER, RE_VARNAME, KIWI_CONF_NAME, RESERVED_PROJECT_
from .yaml import YAML from .yaml import YAML
class InvalidFormatError(ValueError):
"""raised if format recognition unsuccessful"""
cls: type
member: Optional[str]
data: str
def __init__(self, cls, data, member = None):
self.cls = cls
self.data = data
if member is not None:
self.member = member
super().__init__(f"Invalid {self.cls.__name__!r}.{self.member!r} Format: {self.data!r}")
else:
super().__init__(f"Invalid {self.cls.__name__!r} Format: {self.data!r}")
class StorageConfig(BaseModel): class StorageConfig(BaseModel):
"""a storage subsection""" """a storage subsection"""
@ -31,7 +50,17 @@ class StorageConfig(BaseModel):
else: else:
# undefined format # undefined format
raise ValueError("Invalid Storage Format") raise InvalidFormatError(cls, str(values))
class ProjectNameReservedError(ValueError):
"""raised if trying to create a project with a reserved name"""
name: str
def __init__(self, name):
self.name = name
super().__init__(f"Project name {self.name!r} is reserved!")
class ProjectConfig(BaseModel): class ProjectConfig(BaseModel):
@ -58,7 +87,7 @@ class ProjectConfig(BaseModel):
"""check if project name is allowed""" """check if project name is allowed"""
if value in RESERVED_PROJECT_NAMES: if value in RESERVED_PROJECT_NAMES:
raise ValueError(f"Project name '{value}' is reserved!") raise ProjectNameReservedError(value)
return value return value
@ -101,7 +130,7 @@ class ProjectConfig(BaseModel):
else: else:
# undefined format # undefined format
raise ValueError("Invalid Project Format") raise InvalidFormatError(ProjectConfig, values)
class NetworkConfig(BaseModel): class NetworkConfig(BaseModel):
@ -120,6 +149,18 @@ class NetworkConfig(BaseModel):
} }
class MissingMemberError(ValueError):
"""raised if class member is missing a definition"""
cls: type
member: str
def __init__(self, cls, member):
self.cls = cls
self.member = member
super().__init__(f"Member {self.cls.__name__!r}.{self.member!r} is required!")
class KiwiConfig(BaseModel): class KiwiConfig(BaseModel):
"""represents a kiwi.yml""" """represents a kiwi.yml"""
@ -225,7 +266,7 @@ class KiwiConfig(BaseModel):
except Exception: except Exception:
# undefined format # undefined format
raise ValueError("Invalid Shells Format") raise InvalidFormatError(KiwiConfig, value, "shells")
@validator("projects", pre=True) @validator("projects", pre=True)
@classmethod @classmethod
@ -254,7 +295,7 @@ class KiwiConfig(BaseModel):
except Exception: except Exception:
# undefined format # undefined format
raise ValueError("Invalid Projects Format") raise InvalidFormatError(KiwiConfig, value, "projects")
return result return result
@ -270,7 +311,7 @@ class KiwiConfig(BaseModel):
except Exception: except Exception:
# undefined format # undefined format
raise ValueError("Invalid Projects Format") raise InvalidFormatError(KiwiConfig, value, "projects")
@validator("environment", pre=True) @validator("environment", pre=True)
@classmethod @classmethod
@ -284,7 +325,7 @@ class KiwiConfig(BaseModel):
idx = str(var_val).find("=") idx = str(var_val).find("=")
except Exception: except Exception:
# undefined format # undefined format
raise ValueError("Invalid Environment Format") raise InvalidFormatError(KiwiConfig, value, "environment")
if idx == -1: if idx == -1:
# don't split, just define the variable # don't split, just define the variable
@ -325,7 +366,7 @@ class KiwiConfig(BaseModel):
if value is None: if value is None:
# empty storage # empty storage
raise ValueError("No Storage Given") raise MissingMemberError(KiwiConfig, "storage")
elif isinstance(value, dict): elif isinstance(value, dict):
# native dict format # native dict format
@ -350,7 +391,7 @@ class KiwiConfig(BaseModel):
if value is None: if value is None:
# empty network # empty network
raise ValueError("No Network Given") raise MissingMemberError(KiwiConfig, "network")
elif isinstance(value, dict): elif isinstance(value, dict):
# native dict format # native dict format
@ -358,4 +399,4 @@ class KiwiConfig(BaseModel):
else: else:
# undefined format # undefined format
raise ValueError("Invalid Network Format") raise InvalidFormatError(KiwiConfig, value, "network")

View file

@ -8,11 +8,18 @@ from kiwi_scp.config import KiwiConfig
from kiwi_scp.yaml import YAML from kiwi_scp.yaml import YAML
class UnCoercibleError(ValueError):
pass
class UnCoercible: class UnCoercible:
"""A class that doesn't have a string representation""" """A class that doesn't have a string representation"""
def __str__(self): def __str__(self):
raise ValueError raise UnCoercibleError()
def __repr__(self) -> str:
return "UnCoercible()"
class TestDefault: class TestDefault:
@ -130,8 +137,8 @@ class TestShells:
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
assert error["msg"] == "Invalid Shells Format" assert error["msg"] == "Invalid 'KiwiConfig'.'shells' Format: UnCoercible()"
assert error["type"] == "value_error" assert error["type"] == "value_error.invalidformat"
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
KiwiConfig(shells=["/bin/bash", UnCoercible()]) KiwiConfig(shells=["/bin/bash", UnCoercible()])
@ -207,8 +214,8 @@ class TestProject:
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
assert error["msg"] == "Invalid Storage Format" assert error["msg"] == "Invalid 'StorageConfig' Format: '{}'"
assert error["type"] == "value_error" assert error["type"] == "value_error.invalidformat"
def test_short(self): def test_short(self):
kiwi_dict = { kiwi_dict = {
@ -239,6 +246,15 @@ class TestProject:
assert p.enabled assert p.enabled
assert p.override_storage is None assert p.override_storage is None
def test_reserved_name(self):
with pytest.raises(ValidationError) as exc_info:
KiwiConfig(projects={"name": "config"})
assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0]
assert error["msg"] == "Project name 'config' is reserved!"
assert error["type"] == "value_error.projectnamereserved"
def test_invalid_dict(self): def test_invalid_dict(self):
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
KiwiConfig(projects={ KiwiConfig(projects={
@ -248,8 +264,9 @@ class TestProject:
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
assert error["msg"] == "Invalid Project Format" assert error["msg"] == "Invalid 'ProjectConfig' Format: " \
assert error["type"] == "value_error" "{'random key 1': 'random value 1', 'random key 2': 'random value 2'}"
assert error["type"] == "value_error.invalidformat"
def test_coercible(self): def test_coercible(self):
c = KiwiConfig(projects="project") c = KiwiConfig(projects="project")
@ -268,16 +285,16 @@ class TestProject:
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
assert error["msg"] == "Invalid Projects Format" assert error["msg"] == "Invalid 'KiwiConfig'.'projects' Format: ['valid', UnCoercible()]"
assert error["type"] == "value_error" assert error["type"] == "value_error.invalidformat"
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
KiwiConfig(projects=UnCoercible()) KiwiConfig(projects=UnCoercible())
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
assert error["msg"] == "Invalid Projects Format" assert error["msg"] == "Invalid 'KiwiConfig'.'projects' Format: UnCoercible()"
assert error["type"] == "value_error" assert error["type"] == "value_error.invalidformat"
class TestEnvironment: class TestEnvironment:
@ -360,16 +377,16 @@ class TestEnvironment:
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
assert error["msg"] == "Invalid Environment Format" assert error["msg"] == "Invalid 'KiwiConfig'.'environment' Format: UnCoercible()"
assert error["type"] == "value_error" assert error["type"] == "value_error.invalidformat"
with pytest.raises(ValidationError) as exc_info: with pytest.raises(ValidationError) as exc_info:
KiwiConfig(environment=["valid", UnCoercible()]) KiwiConfig(environment=["valid", UnCoercible()])
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
assert error["msg"] == "Invalid Environment Format" assert error["msg"] == "Invalid 'KiwiConfig'.'environment' Format: None"
assert error["type"] == "value_error" assert error["type"] == "value_error.invalidformat"
class TestStorage: class TestStorage:
@ -379,8 +396,8 @@ class TestStorage:
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
assert error["msg"] == "No Storage Given" assert error["msg"] == "Member 'KiwiConfig'.'storage' is required!"
assert error["type"] == "value_error" assert error["type"] == "value_error.missingmember"
def test_dict(self): def test_dict(self):
kiwi_dict = {"directory": "/test/directory"} kiwi_dict = {"directory": "/test/directory"}
@ -395,8 +412,8 @@ class TestStorage:
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
assert error["msg"] == "Invalid Storage Format" assert error["msg"] == "Invalid 'StorageConfig' Format: \"{'random key': 'random value'}\""
assert error["type"] == "value_error" assert error["type"] == "value_error.invalidformat"
def test_str(self): def test_str(self):
c = KiwiConfig(storage="/test/directory") c = KiwiConfig(storage="/test/directory")
@ -414,8 +431,8 @@ class TestStorage:
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
assert error["msg"] == "Invalid Storage Format" assert error["msg"] == "Invalid 'StorageConfig' Format: '{}'"
assert error["type"] == "value_error" assert error["type"] == "value_error.invalidformat"
class TestNetwork: class TestNetwork:
@ -425,8 +442,8 @@ class TestNetwork:
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
assert error["msg"] == "No Network Given" assert error["msg"] == "Member 'KiwiConfig'.'network' is required!"
assert error["type"] == "value_error" assert error["type"] == "value_error.missingmember"
def test_dict(self): def test_dict(self):
kiwi_dict = { kiwi_dict = {
@ -470,5 +487,5 @@ class TestNetwork:
assert len(exc_info.value.errors()) == 1 assert len(exc_info.value.errors()) == 1
error = exc_info.value.errors()[0] error = exc_info.value.errors()[0]
assert error["msg"] == "Invalid Network Format" assert error["msg"] == "Invalid 'KiwiConfig'.'network' Format: True"
assert error["type"] == "value_error" assert error["type"] == "value_error.invalidformat"