Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion playwright/_impl/_artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
from typing import Dict, Optional, Union, cast

from playwright._impl._connection import ChannelOwner, from_channel
from playwright._impl._helper import Error, make_dirs_for_file, patch_error_message
from playwright._impl._errors import Error, patch_error_message
from playwright._impl._helper import make_dirs_for_file
from playwright._impl._stream import Stream


Expand Down
4 changes: 2 additions & 2 deletions playwright/_impl/_assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@
from playwright._impl._connection import format_call_log
from playwright._impl._errors import Error
from playwright._impl._fetch import APIResponse
from playwright._impl._helper import is_textual_mime_type
from playwright._impl._internal_structures import (
AriaRole,
ExpectedTextValue,
FrameExpectOptions,
FrameExpectResult,
)
from playwright._impl._js_handle import parse_value
from playwright._impl._locator import Locator
from playwright._impl._mime_type import is_textual_mime_type
from playwright._impl._page import Page
from playwright._impl._serializers import parse_value
from playwright._impl._str_utils import escape_regex_flags

_soft_errors: Optional[List[AssertionError]] = None
Expand Down
7 changes: 3 additions & 4 deletions playwright/_impl/_browser_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,24 @@
from playwright._impl._debugger import Debugger
from playwright._impl._dialog import Dialog
from playwright._impl._disposable import Disposable, DisposableStub
from playwright._impl._errors import Error, TargetClosedError
from playwright._impl._errors import Error, TargetClosedError, parse_error
from playwright._impl._event_context_manager import EventContextManagerImpl
from playwright._impl._fetch import APIRequestContext
from playwright._impl._frame import Frame
from playwright._impl._har_router import HarRouter
from playwright._impl._headers import serialize_headers
from playwright._impl._helper import (
HarContentPolicy,
HarMode,
RouteFromHarNotFoundPolicy,
RouteHandler,
RouteHandlerCallback,
TimeoutSettings,
URLMatch,
WebSocketRouteHandlerCallback,
async_readfile,
async_writefile,
create_task_and_ignore_exception,
locals_to_params,
parse_error,
to_impl,
)
from playwright._impl._network import (
Expand All @@ -77,10 +76,10 @@
Route,
WebSocketRoute,
WebSocketRouteHandler,
serialize_headers,
to_clear_cookies_params,
)
from playwright._impl._page import BindingCall, Page, Worker
from playwright._impl._timeout_settings import TimeoutSettings
from playwright._impl._tracing import Tracing
from playwright._impl._waiter import Waiter
from playwright._impl._web_error import WebError
Expand Down
4 changes: 2 additions & 2 deletions playwright/_impl/_browser_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from playwright._impl._browser_context import BrowserContext
from playwright._impl._connection import ChannelOwner, Connection, from_channel
from playwright._impl._errors import Error
from playwright._impl._headers import serialize_headers
from playwright._impl._helper import (
PLAYWRIGHT_MAX_DEADLINE,
ColorScheme,
Expand All @@ -39,16 +40,15 @@
HarMode,
ReducedMotion,
ServiceWorkersPolicy,
TimeoutSettings,
async_readfile,
locals_to_params,
)
from playwright._impl._json_pipe import JsonPipeTransport
from playwright._impl._network import (
serialize_headers,
to_client_certificates_protocol,
to_http_credentials_protocol,
)
from playwright._impl._timeout_settings import TimeoutSettings
from playwright._impl._waiter import throw_on_timeout

if TYPE_CHECKING:
Expand Down
9 changes: 6 additions & 3 deletions playwright/_impl/_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,16 @@

import playwright
import playwright._impl._impl_to_api_mapping
from playwright._impl._errors import TargetClosedError, rewrite_error
from playwright._impl._errors import (
Error,
TargetClosedError,
parse_error,
rewrite_error,
)
from playwright._impl._greenlets import EventGreenlet
from playwright._impl._helper import (
Error,
ParsedMessagePayload,
create_task_and_ignore_exception,
parse_error,
)
from playwright._impl._protocol_check import check_message, is_enabled
from playwright._impl._transport import Transport
Expand Down
2 changes: 1 addition & 1 deletion playwright/_impl/_element_handle.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@

from playwright._impl._api_structures import FilePayload, FloatRect, Position
from playwright._impl._connection import ChannelOwner, from_nullable_channel
from playwright._impl._errors import Error
from playwright._impl._helper import (
Error,
KeyboardModifier,
MouseButton,
async_writefile,
Expand Down
53 changes: 52 additions & 1 deletion playwright/_impl/_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.

"""Port of packages/playwright-core/src/client/errors.ts."""

# These are types that we use in the API. They are public and are a part of the
# stable API.


from typing import Any, List, Optional
import re
import traceback
from types import TracebackType
from typing import Any, List, Optional, TypedDict


def is_target_closed_error(error: Exception) -> bool:
Expand Down Expand Up @@ -62,3 +67,49 @@ def rewrite_error(error: Exception, message: str) -> Exception:
rewritten_exc._details = error._details
rewritten_exc._log = error._log
return rewritten_exc


class ErrorPayload(TypedDict, total=False):
message: str
name: str
stack: str
value: Optional[Any]


def serialize_error(ex: Exception, tb: Optional[TracebackType]) -> ErrorPayload:
return ErrorPayload(
message=str(ex), name="Error", stack="".join(traceback.format_tb(tb))
)


def parse_error(error: ErrorPayload, log: Optional[str] = None) -> Error:
base_error_class = Error
if error.get("name") == "TimeoutError":
base_error_class = TimeoutError
if error.get("name") == "TargetClosedError":
base_error_class = TargetClosedError
if not log:
log = ""
exc = base_error_class(patch_error_message(error["message"]) + log)
exc._name = error["name"]
exc._stack = error["stack"]
return exc


def patch_error_message(message: str) -> str:
match = re.match(r"(\w+)(: expected .*)", message)
if match:
message = to_snake_case(match.group(1)) + match.group(2)
message = message.replace(
"Pass { acceptDownloads: true }", "Pass 'accept_downloads=True'"
)
return message


# Upstream: toSnakeCase() in packages/isomorphic/stringUtils.ts. It is here, not
# in _str_utils.py, because _str_utils.py imports this module.
to_snake_case_regex = re.compile("((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))")


def to_snake_case(name: str) -> str:
return to_snake_case_regex.sub(r"_\1", name).lower()
26 changes: 18 additions & 8 deletions playwright/_impl/_fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,28 @@
StorageState,
)
from playwright._impl._connection import ChannelOwner, from_channel
from playwright._impl._errors import is_target_closed_error
from playwright._impl._errors import Error, TargetClosedError, is_target_closed_error
from playwright._impl._form_data import FormData
from playwright._impl._headers import serialize_headers
from playwright._impl._helper import (
Error,
NameValue,
TargetClosedError,
TimeoutSettings,
async_readfile,
async_writefile,
is_file_payload,
locals_to_params,
object_to_array,
to_impl,
)
from playwright._impl._internal_structures import FormField, Headers, ServerFilePayload
from playwright._impl._internal_structures import (
FormField,
Headers,
NameValue,
ServerFilePayload,
)
from playwright._impl._network import (
serialize_headers,
to_clear_cookies_params,
to_client_certificates_protocol,
to_http_credentials_protocol,
)
from playwright._impl._timeout_settings import TimeoutSettings
from playwright._impl._tracing import Tracing

if typing.TYPE_CHECKING:
Expand Down Expand Up @@ -493,6 +494,15 @@ async def storage_state(
return result


def object_to_array(obj: Optional[Dict]) -> Optional[List[NameValue]]:
if not obj:
return None
result = []
for key, value in obj.items():
result.append(NameValue(name=key, value=str(value)))
return result


def file_payload_to_json(payload: FilePayload) -> ServerFilePayload:
return ServerFilePayload(
name=payload["name"],
Expand Down
10 changes: 6 additions & 4 deletions playwright/_impl/_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,9 @@
FrameNavigatedEvent,
KeyboardModifier,
MouseButton,
TimeoutSettings,
URLMatch,
async_readfile,
locals_to_params,
monotonic_time,
url_matches,
)
from playwright._impl._internal_structures import (
Expand All @@ -61,24 +59,28 @@
Serializable,
add_source_url_to_script,
parse_result,
parse_value,
serialize_argument,
)
from playwright._impl._locator import (
ANY_FRAME_SELECTOR,
FrameLocator,
Locator,
test_id_attribute_name,
)
from playwright._impl._locator_utils import (
get_by_alt_text_selector,
get_by_label_selector,
get_by_placeholder_selector,
get_by_role_selector,
get_by_test_id_selector,
get_by_text_selector,
get_by_title_selector,
test_id_attribute_name,
)
from playwright._impl._network import Response
from playwright._impl._serializers import parse_value
from playwright._impl._set_input_files_helpers import convert_input_files
from playwright._impl._time import monotonic_time
from playwright._impl._timeout_settings import TimeoutSettings
from playwright._impl._waiter import Waiter
from playwright._impl._web_mcp import WebMCP

Expand Down
28 changes: 28 additions & 0 deletions playwright/_impl/_headers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright (c) Microsoft Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Port of packages/isomorphic/headers.ts."""

from typing import Dict

from playwright._impl._internal_structures import HeadersArray


# Upstream: headersObjectToArray().
def serialize_headers(headers: Dict[str, str]) -> HeadersArray:
return [
{"name": name, "value": value}
for name, value in headers.items()
if value is not None
]
Loading
Loading