|
12 | 12 | # See the License for the specific language governing permissions and |
13 | 13 | # limitations under the License. |
14 | 14 |
|
| 15 | +"""Port of packages/playwright-core/src/client/errors.ts.""" |
| 16 | + |
15 | 17 | # These are types that we use in the API. They are public and are a part of the |
16 | 18 | # stable API. |
17 | 19 |
|
18 | 20 |
|
19 | | -from typing import Any, List, Optional |
| 21 | +import re |
| 22 | +import traceback |
| 23 | +from types import TracebackType |
| 24 | +from typing import Any, List, Optional, TypedDict |
20 | 25 |
|
21 | 26 |
|
22 | 27 | def is_target_closed_error(error: Exception) -> bool: |
@@ -62,3 +67,49 @@ def rewrite_error(error: Exception, message: str) -> Exception: |
62 | 67 | rewritten_exc._details = error._details |
63 | 68 | rewritten_exc._log = error._log |
64 | 69 | return rewritten_exc |
| 70 | + |
| 71 | + |
| 72 | +class ErrorPayload(TypedDict, total=False): |
| 73 | + message: str |
| 74 | + name: str |
| 75 | + stack: str |
| 76 | + value: Optional[Any] |
| 77 | + |
| 78 | + |
| 79 | +def serialize_error(ex: Exception, tb: Optional[TracebackType]) -> ErrorPayload: |
| 80 | + return ErrorPayload( |
| 81 | + message=str(ex), name="Error", stack="".join(traceback.format_tb(tb)) |
| 82 | + ) |
| 83 | + |
| 84 | + |
| 85 | +def parse_error(error: ErrorPayload, log: Optional[str] = None) -> Error: |
| 86 | + base_error_class = Error |
| 87 | + if error.get("name") == "TimeoutError": |
| 88 | + base_error_class = TimeoutError |
| 89 | + if error.get("name") == "TargetClosedError": |
| 90 | + base_error_class = TargetClosedError |
| 91 | + if not log: |
| 92 | + log = "" |
| 93 | + exc = base_error_class(patch_error_message(error["message"]) + log) |
| 94 | + exc._name = error["name"] |
| 95 | + exc._stack = error["stack"] |
| 96 | + return exc |
| 97 | + |
| 98 | + |
| 99 | +def patch_error_message(message: str) -> str: |
| 100 | + match = re.match(r"(\w+)(: expected .*)", message) |
| 101 | + if match: |
| 102 | + message = to_snake_case(match.group(1)) + match.group(2) |
| 103 | + message = message.replace( |
| 104 | + "Pass { acceptDownloads: true }", "Pass 'accept_downloads=True'" |
| 105 | + ) |
| 106 | + return message |
| 107 | + |
| 108 | + |
| 109 | +# Upstream: toSnakeCase() in packages/isomorphic/stringUtils.ts. It is here, not |
| 110 | +# in _str_utils.py, because _str_utils.py imports this module. |
| 111 | +to_snake_case_regex = re.compile("((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))") |
| 112 | + |
| 113 | + |
| 114 | +def to_snake_case(name: str) -> str: |
| 115 | + return to_snake_case_regex.sub(r"_\1", name).lower() |
0 commit comments