|
1 | 1 |
|
2 | | -def raise_type_error_with_signature(): |
| 2 | +def raise_type_error_with_signature(argument_name: str | list[str] | tuple[str, ...] | set[str] | None = None): |
3 | 3 | """Generate a standard type error message.""" |
4 | | - # TODO: f"arg must be of type 'argtype', but {inspect.stack()[0][3]} got {type(arg).__name__}" |
5 | | - message = "" |
| 4 | + message = f"TypeError with one or more of argument(s): {argument_name}" |
6 | 5 | try: |
7 | 6 | import inspect |
8 | | - caller_frame = inspect.stack()[1].frame |
9 | 7 | import types |
| 8 | + current_frame = inspect.currentframe() |
| 9 | + current_function_name = None |
| 10 | + caller_frame = None |
| 11 | + if isinstance(current_frame, types.FrameType): |
| 12 | + current_function_name = inspect.getframeinfo(current_frame).function |
| 13 | + # caller_frame = inspect.stack()[1].frame |
| 14 | + caller_frame = current_frame.f_back |
10 | 15 | if isinstance(caller_frame, types.FrameType): |
11 | | - function_name = inspect.getframeinfo(caller_frame).function |
12 | | - signature = inspect.signature(caller_frame.f_globals[function_name]) |
13 | | - message = f"TypeError in function '{function_name}'. Signature:\n{function_name}{signature}" |
| 16 | + caller_function_name = inspect.getframeinfo(caller_frame).function |
| 17 | + message = f"TypeError in function '{caller_function_name}'." |
| 18 | + signature = inspect.signature(caller_frame.f_globals[caller_function_name]) |
| 19 | + message += f"\nSignature: {caller_function_name}{signature}" |
| 20 | + arg_names = [] |
| 21 | + if argument_name is None: |
| 22 | + arg_names = list(signature.parameters.keys()) |
| 23 | + elif isinstance(argument_name, (list, tuple, set)): |
| 24 | + arg_names = list(argument_name) |
| 25 | + elif isinstance(argument_name, str): |
| 26 | + arg_names = [argument_name] |
| 27 | + else: |
| 28 | + current_function_name_msg_str = f"in '{current_function_name}'" if current_function_name else "" |
| 29 | + received_argument_name_type_str = type(argument_name).__name__ |
| 30 | + raise TypeError(f"Invalid argument name type {current_function_name_msg_str} for argument 'argument_name': {received_argument_name_type_str}") |
| 31 | + for arg_name in arg_names: |
| 32 | + received_arg_type = type(caller_frame.f_locals[arg_name]) |
| 33 | + received_arg_type_str = received_arg_type.__name__ if isinstance(received_arg_type, type) else received_arg_type |
| 34 | + received_arg = caller_frame.f_locals[arg_name] |
| 35 | + expected_arg_type = signature.parameters[arg_name].annotation |
| 36 | + expected_arg_type_str = expected_arg_type.__name__ if isinstance(expected_arg_type, type) else expected_arg_type |
| 37 | + if received_arg_type != expected_arg_type: |
| 38 | + message += f"\nArgument '{arg_name}' must be of type '{expected_arg_type_str}', but {caller_function_name} got {received_arg_type_str}: {received_arg}" |
14 | 39 | except Exception as e: |
15 | | - raise Exception(f"Failed to generate type error message: {e}") |
| 40 | + raise TypeError(message + f"\nAdditional error while generating error message:\n{e}") |
| 41 | + # raise Exception(f"Failed to generate type error message: {e}") |
16 | 42 | raise TypeError(message) |
0 commit comments