We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Typing validations should be ignored for tests
## Description of the issue
https://github.com/frappe/frappe/blob/010aa4636ace30a9df4c09f0ca991169f34274b9/frappe/utils/typing_validations.py#L164

If you're writing Frappe tests using the `unittest.mock` module, there might be cases where the argument object is replaced with a `Mock` or `MagicMock` object. This breaks typing validations when running CI tests using the `develop` branch.

I think a reasonable approach could be to either ignore all validations during tests, and/or allow configuring this behaviour per-test (with the default being "ignore").

## Context

**Output of `bench version`**
```
frappe 14.14.2
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `frappe/utils/typing_validations.py`
Content:
```
1 from collections.abc import Callable
2 from functools import lru_cache, wraps
3 from inspect import _empty, isclass, signature
4 from types import EllipsisType
5 from typing import ForwardRef, TypeVar, Union
6 
7 from pydantic import ConfigDict
8 
9 from frappe.exceptions import FrappeTypeError
10 
11 SLACK_DICT = {
12 	bool: (int, bool, float),
13 }
14 T = TypeVar("T")
15 
16 
17 FrappePydanticConfig = ConfigDict(arbitrary_types_allowed=True)
18 
19 
20 def validate_argument_types(func: Callable, apply_condition: Callable = lambda: True):
21 	@wraps(func)
22 	def wrapper(*args, **kwargs):
23 		"""Validate argument types of whitelisted functions.
24 
25 		:param args: Function arguments.
26 		:param kwargs: Function keyword arguments."""
27 
28 		if apply_condition():
29 			args, kwargs = transform_parameter_types(func, args, kwargs)
30 
31 		return func(*args, **kwargs)
32 
33 	return wrapper
34 
35 
36 def qualified_name(obj) -> str:
37 	"""
38 	Return the qualified name (e.g. package.module.Type) for the given object.
39 
40 	Builtins and types from the :mod:typing package get special treatment by having the module
41 	name stripped from the generated name.
42 
43 	"""
44 	discovered_type = obj if isclass(obj) else type(obj)
45 	module, qualname = discovered_type.__module__, discovered_type.__qualname__
46 
47 	if module in {"typing", "types"}:
48 		return obj
49 	elif module in {"builtins"}:
50 		return qualname
51 	else:
52 		return f"{module}.{qualname}"
53 
54 
55 def raise_type_error(
56 	arg_name: str, arg_type: type, arg_value: object, current_exception: Exception | None = None
57 ):
58 	"""
59 	Raise a TypeError with a message that includes the name of the argument, the expected type
60 	and the actual type of the value passed.
61 
62 	"""
63 	raise FrappeTypeError(
64 		f"Argument '{arg_name}' should be of type '{qualified_name(arg_type)}' but got "
65 		f"'{qualified_name(arg_value)}' instead."
66 	) from current_exception
67 
68 
69 @lru_cache(maxsize=2048)
70 def TypeAdapter(type_):
71 	from pydantic import TypeAdapter as PyTypeAdapter
72 
73 	return PyTypeAdapter(type_, config=FrappePydanticConfig)
74 
75 
76 def transform_parameter_types(func: Callable, args: tuple, kwargs: dict):
77 	"""
78 	Validate the types of the arguments passed to a function with the type annotations
79 	defined on the function.
80 
81 	"""
82 	if not (args or kwargs) or not func.__annotations__:
83 		return args, kwargs
84 
85 	from pydantic import ValidationError as PyValidationError
86 
87 	annotations = func.__annotations__
88 	new_args, new_kwargs = list(args), kwargs
89 
90 	# generate kwargs dict from args
91 	arg_names = func.__code__.co_varnames[: func.__code__.co_argcount]
92 
93 	if not args:
94 		prepared_args = kwargs
95 
96 	elif kwargs:
97 		arg_values = args or func.__defaults__ or []
98 		prepared_args = dict(zip(arg_names, arg_values, strict=False))
99 		prepared_args.update(kwargs)
100 
101 	else:
102 		prepared_args = dict(zip(arg_names, args, strict=False))
103 
104 	# check if type hints dont match the default values
105 	func_signature = signature(func)
106 	func_params = dict(func_signature.parameters)
107 
108 	# check if the argument types are correct
109 	for current_arg, current_arg_type in annotations.items():
110 		if current_arg not in prepared_args:
111 			continue
112 
113 		current_arg_value = prepared_args[current_arg]
114 
115 		# if the type is a ForwardRef or str, ignore it
116 		if isinstance(current_arg_type, ForwardRef | str):
117 			continue
118 		elif any(isinstance(x, ForwardRef | str) for x in getattr(current_arg_type, "__args__", [])):
119 			continue
120 
121 		# allow slack for Frappe types
122 		if current_arg_type in SLACK_DICT:
123 			current_arg_type = SLACK_DICT[current_arg_type]
124 
125 		param_def = func_params.get(current_arg)
126 
127 		# add default value's type in acceptable types
128 		if param_def.default is not _empty:
129 			if isinstance(current_arg_type, tuple):
130 				if type(param_def.default) not in current_arg_type:
131 					current_arg_type += (type(param_def.default),)
132 				current_arg_type = Union[current_arg_type]  # noqa: UP007
133 
134 			elif param_def.default != current_arg_type:
135 				current_arg_type = Union[current_arg_type, type(param_def.default)]  # noqa: UP007
136 		elif isinstance(current_arg_type, tuple):
137 			current_arg_type = Union[current_arg_type]  # noqa: UP007
138 
139 		# validate the type set using pydantic - raise a TypeError if Validation is raised or Ellipsis is returned
140 		try:
141 			current_arg_value_after = TypeAdapter(current_arg_type).validate_python(current_arg_value)
142 		except (TypeError, PyValidationError) as e:
143 			raise_type_error(current_arg, current_arg_type, current_arg_value, current_exception=e)
144 
145 		if isinstance(current_arg_value_after, EllipsisType):
146 			raise_type_error(current_arg, current_arg_type, current_arg_value)
147 
148 		# update the args and kwargs with possibly casted value
149 		if current_arg in kwargs:
150 			new_kwargs[current_arg] = current_arg_value_after
151 		else:
152 			new_args[arg_names.index(current_arg)] = current_arg_value_after
153 
154 	return new_args, new_kwargs
155
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/frappe/utils/typing_validations.py b/frappe/utils/typing_validations.py
--- a/frappe/utils/typing_validations.py
+++ b/frappe/utils/typing_validations.py
@@ -3,6 +3,7 @@
 from inspect import _empty, isclass, signature
 from types import EllipsisType
 from typing import ForwardRef, TypeVar, Union
+from unittest import mock
 
 from pydantic import ConfigDict
 
@@ -77,8 +78,8 @@
 	"""
 	Validate the types of the arguments passed to a function with the type annotations
 	defined on the function.
-
 	"""
+
 	if not (args or kwargs) or not func.__annotations__:
 		return args, kwargs
 
@@ -117,6 +118,9 @@
 			continue
 		elif any(isinstance(x, ForwardRef | str) for x in getattr(current_arg_type, "__args__", [])):
 			continue
+		# ignore unittest.mock objects
+		elif isinstance(current_arg_value, mock.Mock):
+			continue
 
 		# allow slack for Frappe types
 		if current_arg_type in SLACK_DICT:

{"golden_diff": "diff --git a/frappe/utils/typing_validations.py b/frappe/utils/typing_validations.py\n--- a/frappe/utils/typing_validations.py\n+++ b/frappe/utils/typing_validations.py\n@@ -3,6 +3,7 @@\n from inspect import _empty, isclass, signature\n from types import EllipsisType\n from typing import ForwardRef, TypeVar, Union\n+from unittest import mock\n \n from pydantic import ConfigDict\n \n@@ -77,8 +78,8 @@\n \t\"\"\"\n \tValidate the types of the arguments passed to a function with the type annotations\n \tdefined on the function.\n-\n \t\"\"\"\n+\n \tif not (args or kwargs) or not func.__annotations__:\n \t\treturn args, kwargs\n \n@@ -117,6 +118,9 @@\n \t\t\tcontinue\n \t\telif any(isinstance(x, ForwardRef | str) for x in getattr(current_arg_type, \"__args__\", [])):\n \t\t\tcontinue\n+\t\t# ignore unittest.mock objects\n+\t\telif isinstance(current_arg_value, mock.Mock):\n+\t\t\tcontinue\n \n \t\t# allow slack for Frappe types\n \t\tif current_arg_type in SLACK_DICT:\n", "issue": "Typing validations should be ignored for tests\n## Description of the issue\r\nhttps://github.com/frappe/frappe/blob/010aa4636ace30a9df4c09f0ca991169f34274b9/frappe/utils/typing_validations.py#L164\r\n\r\nIf you're writing Frappe tests using the `unittest.mock` module, there might be cases where the argument object is replaced with a `Mock` or `MagicMock` object. This breaks typing validations when running CI tests using the `develop` branch.\r\n\r\nI think a reasonable approach could be to either ignore all validations during tests, and/or allow configuring this behaviour per-test (with the default being \"ignore\").\r\n\r\n## Context\r\n\r\n**Output of `bench version`**\r\n```\r\nfrappe 14.14.2\r\n```\r\n\n", "before_files": [{"content": "from collections.abc import Callable\nfrom functools import lru_cache, wraps\nfrom inspect import _empty, isclass, signature\nfrom types import EllipsisType\nfrom typing import ForwardRef, TypeVar, Union\n\nfrom pydantic import ConfigDict\n\nfrom frappe.exceptions import FrappeTypeError\n\nSLACK_DICT = {\n\tbool: (int, bool, float),\n}\nT = TypeVar(\"T\")\n\n\nFrappePydanticConfig = ConfigDict(arbitrary_types_allowed=True)\n\n\ndef validate_argument_types(func: Callable, apply_condition: Callable = lambda: True):\n\t@wraps(func)\n\tdef wrapper(*args, **kwargs):\n\t\t\"\"\"Validate argument types of whitelisted functions.\n\n\t\t:param args: Function arguments.\n\t\t:param kwargs: Function keyword arguments.\"\"\"\n\n\t\tif apply_condition():\n\t\t\targs, kwargs = transform_parameter_types(func, args, kwargs)\n\n\t\treturn func(*args, **kwargs)\n\n\treturn wrapper\n\n\ndef qualified_name(obj) -> str:\n\t\"\"\"\n\tReturn the qualified name (e.g. package.module.Type) for the given object.\n\n\tBuiltins and types from the :mod:typing package get special treatment by having the module\n\tname stripped from the generated name.\n\n\t\"\"\"\n\tdiscovered_type = obj if isclass(obj) else type(obj)\n\tmodule, qualname = discovered_type.__module__, discovered_type.__qualname__\n\n\tif module in {\"typing\", \"types\"}:\n\t\treturn obj\n\telif module in {\"builtins\"}:\n\t\treturn qualname\n\telse:\n\t\treturn f\"{module}.{qualname}\"\n\n\ndef raise_type_error(\n\targ_name: str, arg_type: type, arg_value: object, current_exception: Exception | None = None\n):\n\t\"\"\"\n\tRaise a TypeError with a message that includes the name of the argument, the expected type\n\tand the actual type of the value passed.\n\n\t\"\"\"\n\traise FrappeTypeError(\n\t\tf\"Argument '{arg_name}' should be of type '{qualified_name(arg_type)}' but got \"\n\t\tf\"'{qualified_name(arg_value)}' instead.\"\n\t) from current_exception\n\n\n@lru_cache(maxsize=2048)\ndef TypeAdapter(type_):\n\tfrom pydantic import TypeAdapter as PyTypeAdapter\n\n\treturn PyTypeAdapter(type_, config=FrappePydanticConfig)\n\n\ndef transform_parameter_types(func: Callable, args: tuple, kwargs: dict):\n\t\"\"\"\n\tValidate the types of the arguments passed to a function with the type annotations\n\tdefined on the function.\n\n\t\"\"\"\n\tif not (args or kwargs) or not func.__annotations__:\n\t\treturn args, kwargs\n\n\tfrom pydantic import ValidationError as PyValidationError\n\n\tannotations = func.__annotations__\n\tnew_args, new_kwargs = list(args), kwargs\n\n\t# generate kwargs dict from args\n\targ_names = func.__code__.co_varnames[: func.__code__.co_argcount]\n\n\tif not args:\n\t\tprepared_args = kwargs\n\n\telif kwargs:\n\t\targ_values = args or func.__defaults__ or []\n\t\tprepared_args = dict(zip(arg_names, arg_values, strict=False))\n\t\tprepared_args.update(kwargs)\n\n\telse:\n\t\tprepared_args = dict(zip(arg_names, args, strict=False))\n\n\t# check if type hints dont match the default values\n\tfunc_signature = signature(func)\n\tfunc_params = dict(func_signature.parameters)\n\n\t# check if the argument types are correct\n\tfor current_arg, current_arg_type in annotations.items():\n\t\tif current_arg not in prepared_args:\n\t\t\tcontinue\n\n\t\tcurrent_arg_value = prepared_args[current_arg]\n\n\t\t# if the type is a ForwardRef or str, ignore it\n\t\tif isinstance(current_arg_type, ForwardRef | str):\n\t\t\tcontinue\n\t\telif any(isinstance(x, ForwardRef | str) for x in getattr(current_arg_type, \"__args__\", [])):\n\t\t\tcontinue\n\n\t\t# allow slack for Frappe types\n\t\tif current_arg_type in SLACK_DICT:\n\t\t\tcurrent_arg_type = SLACK_DICT[current_arg_type]\n\n\t\tparam_def = func_params.get(current_arg)\n\n\t\t# add default value's type in acceptable types\n\t\tif param_def.default is not _empty:\n\t\t\tif isinstance(current_arg_type, tuple):\n\t\t\t\tif type(param_def.default) not in current_arg_type:\n\t\t\t\t\tcurrent_arg_type += (type(param_def.default),)\n\t\t\t\tcurrent_arg_type = Union[current_arg_type]  # noqa: UP007\n\n\t\t\telif param_def.default != current_arg_type:\n\t\t\t\tcurrent_arg_type = Union[current_arg_type, type(param_def.default)]  # noqa: UP007\n\t\telif isinstance(current_arg_type, tuple):\n\t\t\tcurrent_arg_type = Union[current_arg_type]  # noqa: UP007\n\n\t\t# validate the type set using pydantic - raise a TypeError if Validation is raised or Ellipsis is returned\n\t\ttry:\n\t\t\tcurrent_arg_value_after = TypeAdapter(current_arg_type).validate_python(current_arg_value)\n\t\texcept (TypeError, PyValidationError) as e:\n\t\t\traise_type_error(current_arg, current_arg_type, current_arg_value, current_exception=e)\n\n\t\tif isinstance(current_arg_value_after, EllipsisType):\n\t\t\traise_type_error(current_arg, current_arg_type, current_arg_value)\n\n\t\t# update the args and kwargs with possibly casted value\n\t\tif current_arg in kwargs:\n\t\t\tnew_kwargs[current_arg] = current_arg_value_after\n\t\telse:\n\t\t\tnew_args[arg_names.index(current_arg)] = current_arg_value_after\n\n\treturn new_args, new_kwargs\n", "path": "frappe/utils/typing_validations.py"}], "after_files": [{"content": "from collections.abc import Callable\nfrom functools import lru_cache, wraps\nfrom inspect import _empty, isclass, signature\nfrom types import EllipsisType\nfrom typing import ForwardRef, TypeVar, Union\nfrom unittest import mock\n\nfrom pydantic import ConfigDict\n\nfrom frappe.exceptions import FrappeTypeError\n\nSLACK_DICT = {\n\tbool: (int, bool, float),\n}\nT = TypeVar(\"T\")\n\n\nFrappePydanticConfig = ConfigDict(arbitrary_types_allowed=True)\n\n\ndef validate_argument_types(func: Callable, apply_condition: Callable = lambda: True):\n\t@wraps(func)\n\tdef wrapper(*args, **kwargs):\n\t\t\"\"\"Validate argument types of whitelisted functions.\n\n\t\t:param args: Function arguments.\n\t\t:param kwargs: Function keyword arguments.\"\"\"\n\n\t\tif apply_condition():\n\t\t\targs, kwargs = transform_parameter_types(func, args, kwargs)\n\n\t\treturn func(*args, **kwargs)\n\n\treturn wrapper\n\n\ndef qualified_name(obj) -> str:\n\t\"\"\"\n\tReturn the qualified name (e.g. package.module.Type) for the given object.\n\n\tBuiltins and types from the :mod:typing package get special treatment by having the module\n\tname stripped from the generated name.\n\n\t\"\"\"\n\tdiscovered_type = obj if isclass(obj) else type(obj)\n\tmodule, qualname = discovered_type.__module__, discovered_type.__qualname__\n\n\tif module in {\"typing\", \"types\"}:\n\t\treturn obj\n\telif module in {\"builtins\"}:\n\t\treturn qualname\n\telse:\n\t\treturn f\"{module}.{qualname}\"\n\n\ndef raise_type_error(\n\targ_name: str, arg_type: type, arg_value: object, current_exception: Exception | None = None\n):\n\t\"\"\"\n\tRaise a TypeError with a message that includes the name of the argument, the expected type\n\tand the actual type of the value passed.\n\n\t\"\"\"\n\traise FrappeTypeError(\n\t\tf\"Argument '{arg_name}' should be of type '{qualified_name(arg_type)}' but got \"\n\t\tf\"'{qualified_name(arg_value)}' instead.\"\n\t) from current_exception\n\n\n@lru_cache(maxsize=2048)\ndef TypeAdapter(type_):\n\tfrom pydantic import TypeAdapter as PyTypeAdapter\n\n\treturn PyTypeAdapter(type_, config=FrappePydanticConfig)\n\n\ndef transform_parameter_types(func: Callable, args: tuple, kwargs: dict):\n\t\"\"\"\n\tValidate the types of the arguments passed to a function with the type annotations\n\tdefined on the function.\n\t\"\"\"\n\n\tif not (args or kwargs) or not func.__annotations__:\n\t\treturn args, kwargs\n\n\tfrom pydantic import ValidationError as PyValidationError\n\n\tannotations = func.__annotations__\n\tnew_args, new_kwargs = list(args), kwargs\n\n\t# generate kwargs dict from args\n\targ_names = func.__code__.co_varnames[: func.__code__.co_argcount]\n\n\tif not args:\n\t\tprepared_args = kwargs\n\n\telif kwargs:\n\t\targ_values = args or func.__defaults__ or []\n\t\tprepared_args = dict(zip(arg_names, arg_values, strict=False))\n\t\tprepared_args.update(kwargs)\n\n\telse:\n\t\tprepared_args = dict(zip(arg_names, args, strict=False))\n\n\t# check if type hints dont match the default values\n\tfunc_signature = signature(func)\n\tfunc_params = dict(func_signature.parameters)\n\n\t# check if the argument types are correct\n\tfor current_arg, current_arg_type in annotations.items():\n\t\tif current_arg not in prepared_args:\n\t\t\tcontinue\n\n\t\tcurrent_arg_value = prepared_args[current_arg]\n\n\t\t# if the type is a ForwardRef or str, ignore it\n\t\tif isinstance(current_arg_type, ForwardRef | str):\n\t\t\tcontinue\n\t\telif any(isinstance(x, ForwardRef | str) for x in getattr(current_arg_type, \"__args__\", [])):\n\t\t\tcontinue\n\t\t# ignore unittest.mock objects\n\t\telif isinstance(current_arg_value, mock.Mock):\n\t\t\tcontinue\n\n\t\t# allow slack for Frappe types\n\t\tif current_arg_type in SLACK_DICT:\n\t\t\tcurrent_arg_type = SLACK_DICT[current_arg_type]\n\n\t\tparam_def = func_params.get(current_arg)\n\n\t\t# add default value's type in acceptable types\n\t\tif param_def.default is not _empty:\n\t\t\tif isinstance(current_arg_type, tuple):\n\t\t\t\tif type(param_def.default) not in current_arg_type:\n\t\t\t\t\tcurrent_arg_type += (type(param_def.default),)\n\t\t\t\tcurrent_arg_type = Union[current_arg_type]  # noqa: UP007\n\n\t\t\telif param_def.default != current_arg_type:\n\t\t\t\tcurrent_arg_type = Union[current_arg_type, type(param_def.default)]  # noqa: UP007\n\t\telif isinstance(current_arg_type, tuple):\n\t\t\tcurrent_arg_type = Union[current_arg_type]  # noqa: UP007\n\n\t\t# validate the type set using pydantic - raise a TypeError if Validation is raised or Ellipsis is returned\n\t\ttry:\n\t\t\tcurrent_arg_value_after = TypeAdapter(current_arg_type).validate_python(current_arg_value)\n\t\texcept (TypeError, PyValidationError) as e:\n\t\t\traise_type_error(current_arg, current_arg_type, current_arg_value, current_exception=e)\n\n\t\tif isinstance(current_arg_value_after, EllipsisType):\n\t\t\traise_type_error(current_arg, current_arg_type, current_arg_value)\n\n\t\t# update the args and kwargs with possibly casted value\n\t\tif current_arg in kwargs:\n\t\t\tnew_kwargs[current_arg] = current_arg_value_after\n\t\telse:\n\t\t\tnew_args[arg_names.index(current_arg)] = current_arg_value_after\n\n\treturn new_args, new_kwargs\n", "path": "frappe/utils/typing_validations.py"}]}