Greetings
One small problem that anyone have to tackle with in Python is handling invalid argument types ( without an automatic static type checking tool like Mypy )
One of the best methods for handling the invalid argument is raising an exception which would easily inform the code client with the required steps to fix, ( I.E ):
"Expected argument type passed for the parameter ( im_a_parameter ): ( int ) | Not: ( str )"
in this case, raising a ValueError would get the job done.
While attending this method, as my project was growing larger, I found out that repeating this idiom would deny the DRY principle, so I rolled up my sleeves, and came up with a fixture:
unexpected_argument_type.py
"""
# The holder module for the UnexpectedArgumentTypeError exception class
"""
class UnexpectedArgumentTypeError(ValueError):
def __init__(self, parameter: str, expected_argument_types: object | list[object]) -> None:
"""
# Args:
1. ( parameter ): The expected parameter of the current function signature.
2. ( expected_argument_types ): The types that were expected to be passed to the function parameter.
"""
self.passed_argument = parameter
self.passed_argument_type = parameter
self.expected_argument_types = expected_argument_types
self._generate_error_message()
super().__init__(self._error_message)
def _generate_error_message(self):
if isinstance(self.expected_argument_type, object) and not self._arguments_are_list:
self._error_message = (
f"Expected argument type passed for the parameter \
( {self.passed_argument} ): ( {self.expected_argument_type} ) | Not ( {self.passed_argument_type} )."
)
return
if isinstance(self.expected_argument_type, list):
expected_argument_types_str = ', '.join(self.expected_argument_type)
self._error_message = (
f"Expected argument type passed for the parameter \
( {self.passed_argument} ): ( {expected_argument_types_str} ) | Not ( {self.passed_argument_type} )"
)
@property
def passed_argument_type(self):
return self._passed_argument_type
@passed_argument_type.setter
def passed_argument_type(self, argument_type):
self._passed_argument_type = type(argument_type).__name__
@property
def expected_argument_types(self):
return self._expected_argument_type
@expected_argument_types.setter
def expected_argument_type(self, arguments):
if not isinstance(arguments, (list, object)):
raise ValueError("The ( expected_argument_type ) argument must be object| e.x: ( str, tuple... )")
if isinstance(arguments, list):
self._arguments_are_list = True
arguments = [str(argument) for argument in arguments]
if isinstance(arguments, object) and not self._arguments_are_list:
arguments = arguments.__name__
self._expected_argument_type = arguments
After all of this, one question remains:
Does handling this problem worth the complexity that this piece of code adds? ( Writing unit tests, maintaining documentations ).
coding
,coding/database
, andcoding/database/exceptions
? How is this fixture used? This is currently incomplete, so off-topic until the additional code is added. \$\endgroup\$