Skip to content

Commit

Permalink
chore: roll to ToT
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman committed Dec 15, 2022
1 parent eaf3f15 commit ac7453e
Show file tree
Hide file tree
Showing 20 changed files with 1,189 additions and 550 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ Playwright is a Python library to automate [Chromium](https://www.chromium.org/H

| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->108.0.5359.48<!-- GEN:stop --> ||||
| Chromium <!-- GEN:chromium-version -->109.0.5414.36<!-- GEN:stop --> ||||
| WebKit <!-- GEN:webkit-version -->16.4<!-- GEN:stop --> ||||
| Firefox <!-- GEN:firefox-version -->106.0<!-- GEN:stop --> ||||
| Firefox <!-- GEN:firefox-version -->107.0<!-- GEN:stop --> ||||

## Documentation

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 @@ -392,7 +392,7 @@ def convert_select_option_values(
if value:
if not isinstance(value, list):
value = [value]
options = (options or []) + list(map(lambda e: dict(value=e), value))
options = (options or []) + list(map(lambda e: dict(valueOrLabel=e), value))
if index:
if not isinstance(index, list):
index = [index]
Expand Down
33 changes: 32 additions & 1 deletion playwright/_impl/_fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ async def fetch(
ignoreHTTPSErrors: bool = None,
maxRedirects: int = None,
) -> "APIResponse":
url = urlOrRequest if isinstance(urlOrRequest, str) else None
request = (
cast(network.Request, to_impl(urlOrRequest))
if isinstance(to_impl(urlOrRequest), network.Request)
Expand All @@ -281,13 +282,43 @@ async def fetch(
assert request or isinstance(
urlOrRequest, str
), "First argument must be either URL string or Request"
return await self._inner_fetch(
request,
url,
method,
headers,
data,
params,
form,
multipart,
timeout,
failOnStatusCode,
ignoreHTTPSErrors,
maxRedirects,
)

async def _inner_fetch(
self,
request: Optional[network.Request],
url: Optional[str],
method: str = None,
headers: Headers = None,
data: DataType = None,
params: ParamsType = None,
form: FormType = None,
multipart: Dict[str, Union[bytes, bool, float, str, FilePayload]] = None,
timeout: float = None,
failOnStatusCode: bool = None,
ignoreHTTPSErrors: bool = None,
maxRedirects: int = None,
) -> "APIResponse":
assert (
(1 if data else 0) + (1 if form else 0) + (1 if multipart else 0)
) <= 1, "Only one of 'data', 'form' or 'multipart' can be specified"
assert (
maxRedirects is None or maxRedirects >= 0
), "'max_redirects' must be greater than or equal to '0'"
url = request.url if request else urlOrRequest
url = url or (request.url if request else url)
method = method or (request.method if request else "GET")
# Cannot call allHeaders() here as the request may be paused inside route handler.
headers_obj = headers or (request.headers if request else None)
Expand Down
2 changes: 1 addition & 1 deletion playwright/_impl/_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ def get_by_role(
)
)

def get_by_test_id(self, testId: str) -> "Locator":
def get_by_test_id(self, testId: Union[str, Pattern[str]]) -> "Locator":
return self.locator(get_by_test_id_selector(test_id_attribute_name(), testId))

def get_by_text(
Expand Down
7 changes: 0 additions & 7 deletions playwright/_impl/_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,6 @@ class ErrorPayload(TypedDict, total=False):
value: Optional[Any]


class FallbackOverrideParameters(TypedDict, total=False):
url: Optional[str]
method: Optional[str]
headers: Optional[Dict[str, str]]
postData: Optional[Union[str, bytes]]


class HarRecordingMetadata(TypedDict, total=False):
path: str
content: Optional[HarContentPolicy]
Expand Down
10 changes: 7 additions & 3 deletions playwright/_impl/_locator.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ def get_by_role(
)
)

def get_by_test_id(self, testId: str) -> "Locator":
def get_by_test_id(self, testId: Union[str, Pattern[str]]) -> "Locator":
return self.locator(get_by_test_id_selector(test_id_attribute_name(), testId))

def get_by_text(
Expand Down Expand Up @@ -709,7 +709,7 @@ def get_by_role(
)
)

def get_by_test_id(self, testId: str) -> "Locator":
def get_by_test_id(self, testId: Union[str, Pattern[str]]) -> "Locator":
return self.locator(get_by_test_id_selector(test_id_attribute_name(), testId))

def get_by_text(
Expand Down Expand Up @@ -755,7 +755,11 @@ def set_test_id_attribute_name(attribute_name: str) -> None:
_test_id_attribute_name = attribute_name


def get_by_test_id_selector(test_id_attribute_name: str, test_id: str) -> str:
def get_by_test_id_selector(
test_id_attribute_name: str, test_id: Union[str, Pattern[str]]
) -> str:
if isinstance(test_id, Pattern):
return f"internal:testid=[{test_id_attribute_name}=/{test_id.pattern}/{escape_regex_flags(test_id)}]"
return f"internal:testid=[{test_id_attribute_name}={escape_for_attribute_selector(test_id, True)}]"


Expand Down
119 changes: 79 additions & 40 deletions playwright/_impl/_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import inspect
import json
import mimetypes
import sys
from collections import defaultdict
from pathlib import Path
from types import SimpleNamespace
Expand All @@ -31,6 +32,11 @@
Union,
cast,
)

if sys.version_info >= (3, 8): # pragma: no cover
from typing import TypedDict
else: # pragma: no cover
from typing_extensions import TypedDict
from urllib import parse

from playwright._impl._api_structures import (
Expand All @@ -48,7 +54,7 @@
from_nullable_channel,
)
from playwright._impl._event_context_manager import EventContextManagerImpl
from playwright._impl._helper import FallbackOverrideParameters, locals_to_params
from playwright._impl._helper import locals_to_params
from playwright._impl._wait_helper import WaitHelper

if TYPE_CHECKING: # pragma: no cover
Expand All @@ -57,6 +63,21 @@
from playwright._impl._page import Page


class FallbackOverrideParameters(TypedDict, total=False):
url: Optional[str]
method: Optional[str]
headers: Optional[Dict[str, str]]
postData: Optional[Union[str, bytes]]


class SerializedFallbackOverrides:
def __init__(self) -> None:
self.url: Optional[str] = None
self.method: Optional[str] = None
self.headers: Optional[Dict[str, str]] = None
self.post_data_buffer: Optional[bytes] = None


def serialize_headers(headers: Dict[str, str]) -> HeadersArray:
return [
{"name": name, "value": value}
Expand Down Expand Up @@ -90,31 +111,47 @@ def __init__(
}
self._provisional_headers = RawHeaders(self._initializer["headers"])
self._all_headers_future: Optional[asyncio.Future[RawHeaders]] = None
self._fallback_overrides: FallbackOverrideParameters = (
FallbackOverrideParameters()
self._fallback_overrides: SerializedFallbackOverrides = (
SerializedFallbackOverrides()
)
base64_post_data = initializer.get("postData")
if base64_post_data is not None:
self._fallback_overrides.post_data_buffer = base64.b64decode(
base64_post_data
)

def __repr__(self) -> str:
return f"<Request url={self.url!r} method={self.method!r}>"

def _apply_fallback_overrides(self, overrides: FallbackOverrideParameters) -> None:
self._fallback_overrides = cast(
FallbackOverrideParameters, {**self._fallback_overrides, **overrides}
self._fallback_overrides.url = overrides.get(
"url", self._fallback_overrides.url
)
self._fallback_overrides.method = overrides.get(
"method", self._fallback_overrides.method
)
self._fallback_overrides.headers = overrides.get(
"headers", self._fallback_overrides.headers
)
post_data = overrides.get("postData")
if isinstance(post_data, str):
self._fallback_overrides.post_data_buffer = post_data.encode()
elif isinstance(post_data, bytes):
self._fallback_overrides.post_data_buffer = post_data
elif post_data is not None:
self._fallback_overrides.post_data_buffer = json.dumps(post_data).encode()

@property
def url(self) -> str:
return cast(str, self._fallback_overrides.get("url", self._initializer["url"]))
return cast(str, self._fallback_overrides.url or self._initializer["url"])

@property
def resource_type(self) -> str:
return self._initializer["resourceType"]

@property
def method(self) -> str:
return cast(
str, self._fallback_overrides.get("method", self._initializer["method"])
)
return cast(str, self._fallback_overrides.method or self._initializer["method"])

async def sizes(self) -> RequestSizes:
response = await self.response()
Expand All @@ -124,7 +161,7 @@ async def sizes(self) -> RequestSizes:

@property
def post_data(self) -> Optional[str]:
data = self._fallback_overrides.get("postData", self.post_data_buffer)
data = self._fallback_overrides.post_data_buffer
if not data:
return None
return data.decode() if isinstance(data, bytes) else data
Expand All @@ -144,17 +181,7 @@ def post_data_json(self) -> Optional[Any]:

@property
def post_data_buffer(self) -> Optional[bytes]:
override = self._fallback_overrides.get("post_data")
if override:
return (
override.encode()
if isinstance(override, str)
else cast(bytes, override)
)
b64_content = self._initializer.get("postData")
if b64_content is None:
return None
return base64.b64decode(b64_content)
return self._fallback_overrides.post_data_buffer

async def response(self) -> Optional["Response"]:
return from_nullable_channel(await self._channel.send("response"))
Expand Down Expand Up @@ -189,7 +216,7 @@ def _set_response_end_timing(self, response_end_timing: float) -> None:

@property
def headers(self) -> Headers:
override = self._fallback_overrides.get("headers")
override = self._fallback_overrides.headers
if override:
return RawHeaders._from_headers_dict_lossy(override).headers()
return self._provisional_headers.headers()
Expand All @@ -204,7 +231,7 @@ async def header_value(self, name: str) -> Optional[str]:
return (await self._actual_headers()).get(name)

async def _actual_headers(self) -> "RawHeaders":
override = self._fallback_overrides.get("headers")
override = self._fallback_overrides.headers
if override:
return RawHeaders(serialize_headers(override))
if not self._all_headers_future:
Expand Down Expand Up @@ -254,6 +281,7 @@ async def fulfill(
status: int = None,
headers: Dict[str, str] = None,
body: Union[str, bytes] = None,
json: Any = None,
path: Union[str, Path] = None,
contentType: str = None,
response: "APIResponse" = None,
Expand All @@ -270,6 +298,8 @@ async def fulfill(
)
from playwright._impl._fetch import APIResponse

if json is not None:
body = json.dumps(json)
if body is None and path is None and isinstance(response, APIResponse):
if response._request._connection is self._connection:
params["fetchResponseUid"] = response._fetch_uid
Expand All @@ -295,6 +325,8 @@ async def fulfill(
headers = {k.lower(): str(v) for k, v in params.get("headers", {}).items()}
if params.get("contentType"):
headers["content-type"] = params["contentType"]
elif json:
headers["content-type"] = "application/json"
elif path:
headers["content-type"] = (
mimetypes.guess_type(str(Path(path)))[0] or "application/octet-stream"
Expand All @@ -305,12 +337,24 @@ async def fulfill(
await self._race_with_page_close(self._channel.send("fulfill", params))
self._report_handled(True)

async def fetch(
self,
url: str = None,
method: str = None,
headers: Dict[str, str] = None,
postData: Union[Any, str, bytes] = None,
) -> "APIResponse":
page = self.request.frame._page
return await page.context.request._inner_fetch(
self.request, url, method, headers, postData
)

async def fallback(
self,
url: str = None,
method: str = None,
headers: Dict[str, str] = None,
postData: Union[str, bytes] = None,
postData: Union[Any, str, bytes] = None,
) -> None:
overrides = cast(FallbackOverrideParameters, locals_to_params(locals()))
self._check_not_handled()
Expand All @@ -322,7 +366,7 @@ async def continue_(
url: str = None,
method: str = None,
headers: Dict[str, str] = None,
postData: Union[str, bytes] = None,
postData: Union[Any, str, bytes] = None,
) -> None:
overrides = cast(FallbackOverrideParameters, locals_to_params(locals()))
self._check_not_handled()
Expand All @@ -335,23 +379,18 @@ def _internal_continue(
) -> Coroutine[Any, Any, None]:
async def continue_route() -> None:
try:
post_data_for_wire: Optional[str] = None
post_data_from_overrides = self.request._fallback_overrides.get(
"postData"
)
if post_data_from_overrides is not None:
post_data_for_wire = (
base64.b64encode(post_data_from_overrides.encode()).decode()
if isinstance(post_data_from_overrides, str)
else base64.b64encode(post_data_from_overrides).decode()
)
params = locals_to_params(
cast(Dict[str, str], self.request._fallback_overrides)
)
params: Dict[str, Any] = {}
params["url"] = self.request._fallback_overrides.url
params["method"] = self.request._fallback_overrides.method
params["headers"] = self.request._fallback_overrides.headers
if self.request._fallback_overrides.post_data_buffer is not None:
params["postData"] = base64.b64encode(
self.request._fallback_overrides.post_data_buffer
).decode()
params = locals_to_params(params)

if "headers" in params:
params["headers"] = serialize_headers(params["headers"])
if post_data_for_wire is not None:
params["postData"] = post_data_for_wire
await self._connection.wrap_api_call(
lambda: self._race_with_page_close(
self._channel.send(
Expand Down
2 changes: 1 addition & 1 deletion playwright/_impl/_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -788,7 +788,7 @@ def get_by_role(
exact=exact,
)

def get_by_test_id(self, testId: str) -> "Locator":
def get_by_test_id(self, testId: Union[str, Pattern[str]]) -> "Locator":
return self._main_frame.get_by_test_id(testId)

def get_by_text(
Expand Down

0 comments on commit ac7453e

Please sign in to comment.