Skip to content

chore: roll to v1.49.0 #2660

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 22, 2024
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
6 changes: 3 additions & 3 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 -->130.0.6723.31<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| WebKit <!-- GEN:webkit-version -->18.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->131.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Chromium <!-- GEN:chromium-version -->131.0.6778.33<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| WebKit <!-- GEN:webkit-version -->18.2<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->132.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |

## Documentation

Expand Down
6 changes: 6 additions & 0 deletions playwright/_impl/_api_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,3 +291,9 @@ class FrameExpectResult(TypedDict):
"treegrid",
"treeitem",
]


class TracingGroupLocation(TypedDict):
file: str
line: Optional[int]
column: Optional[int]
17 changes: 17 additions & 0 deletions playwright/_impl/_assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,23 @@ async def not_to_have_role(self, role: AriaRole, timeout: float = None) -> None:
__tracebackhide__ = True
await self._not.to_have_role(role, timeout)

async def to_match_aria_snapshot(
self, expected: str, timeout: float = None
) -> None:
__tracebackhide__ = True
await self._expect_impl(
"to.match.aria",
FrameExpectOptions(expectedValue=expected, timeout=timeout),
expected,
"Locator expected to match Aria snapshot",
)

async def not_to_match_aria_snapshot(
self, expected: str, timeout: float = None
) -> None:
__tracebackhide__ = True
await self._not.to_match_aria_snapshot(expected, timeout)


class APIResponseAssertions:
def __init__(
Expand Down
10 changes: 4 additions & 6 deletions playwright/_impl/_browser_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
RouteHandlerCallback,
TimeoutSettings,
URLMatch,
URLMatcher,
WebSocketRouteHandlerCallback,
async_readfile,
async_writefile,
Expand Down Expand Up @@ -416,7 +415,8 @@ async def route(
self._routes.insert(
0,
RouteHandler(
URLMatcher(self._options.get("baseURL"), url),
self._options.get("baseURL"),
url,
handler,
True if self._dispatcher_fiber else False,
times,
Expand All @@ -430,7 +430,7 @@ async def unroute(
removed = []
remaining = []
for route in self._routes:
if route.matcher.match != url or (handler and route.handler != handler):
if route.url != url or (handler and route.handler != handler):
remaining.append(route)
else:
removed.append(route)
Expand All @@ -453,9 +453,7 @@ async def route_web_socket(
) -> None:
self._web_socket_routes.insert(
0,
WebSocketRouteHandler(
URLMatcher(self._options.get("baseURL"), url), handler
),
WebSocketRouteHandler(self._options.get("baseURL"), url, handler),
)
await self._update_web_socket_interception_patterns()

Expand Down
18 changes: 9 additions & 9 deletions playwright/_impl/_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@
Literal,
MouseButton,
URLMatch,
URLMatcher,
async_readfile,
locals_to_params,
monotonic_time,
url_matches,
)
from playwright._impl._js_handle import (
JSHandle,
Expand Down Expand Up @@ -185,18 +185,17 @@ def expect_navigation(

to_url = f' to "{url}"' if url else ""
waiter.log(f"waiting for navigation{to_url} until '{waitUntil}'")
matcher = (
URLMatcher(self._page._browser_context._options.get("baseURL"), url)
if url
else None
)

def predicate(event: Any) -> bool:
# Any failed navigation results in a rejection.
if event.get("error"):
return True
waiter.log(f' navigated to "{event["url"]}"')
return not matcher or matcher.matches(event["url"])
return url_matches(
cast("Page", self._page)._browser_context._options.get("baseURL"),
event["url"],
url,
)

waiter.wait_for_event(
self._event_emitter,
Expand Down Expand Up @@ -226,8 +225,9 @@ async def wait_for_url(
timeout: float = None,
) -> None:
assert self._page
matcher = URLMatcher(self._page._browser_context._options.get("baseURL"), url)
if matcher.matches(self.url):
if url_matches(
self._page._browser_context._options.get("baseURL"), self.url, url
):
await self._wait_for_load_state_impl(state=waitUntil, timeout=timeout)
return
async with self.expect_navigation(
Expand Down
59 changes: 30 additions & 29 deletions playwright/_impl/_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,27 +142,26 @@ class FrameNavigatedEvent(TypedDict):
Env = Dict[str, Union[str, float, bool]]


class URLMatcher:
def __init__(self, base_url: Union[str, None], match: URLMatch) -> None:
self._callback: Optional[Callable[[str], bool]] = None
self._regex_obj: Optional[Pattern[str]] = None
if isinstance(match, str):
if base_url and not match.startswith("*"):
match = urljoin(base_url, match)
regex = glob_to_regex(match)
self._regex_obj = re.compile(regex)
elif isinstance(match, Pattern):
self._regex_obj = match
else:
self._callback = match
self.match = match

def matches(self, url: str) -> bool:
if self._callback:
return self._callback(url)
if self._regex_obj:
return cast(bool, self._regex_obj.search(url))
return False
def url_matches(
base_url: Optional[str], url_string: str, match: Optional[URLMatch]
) -> bool:
if not match:
return True
if isinstance(match, str) and match[0] != "*":
# Allow http(s) baseURL to match ws(s) urls.
if (
base_url
and re.match(r"^https?://", base_url)
and re.match(r"^wss?://", url_string)
):
base_url = re.sub(r"^http", "ws", base_url)
if base_url:
match = urljoin(base_url, match)
if isinstance(match, str):
match = glob_to_regex(match)
if isinstance(match, Pattern):
return bool(match.search(url_string))
return match(url_string)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason Python does not have this code:

https://github.com/microsoft/playwright/blob/f43b86fea43aeb99cfea4a0773c577dd9801b35d/packages/playwright-core/src/utils/isomorphic/urlMatch.ts#L110-L118

The "past path" seems an optimisation while the 'parseURL path matching' seems not implemented at all?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like js has some dead code. match cannot be a string there because we do match = globToRegex(match); before.



class HarLookupResult(TypedDict, total=False):
Expand Down Expand Up @@ -271,12 +270,14 @@ def __init__(self, complete: "asyncio.Future", route: "Route") -> None:
class RouteHandler:
def __init__(
self,
matcher: URLMatcher,
base_url: Optional[str],
url: URLMatch,
handler: RouteHandlerCallback,
is_sync: bool,
times: Optional[int] = None,
):
self.matcher = matcher
self._base_url = base_url
self.url = url
self.handler = handler
self._times = times if times else math.inf
self._handled_count = 0
Expand All @@ -285,7 +286,7 @@ def __init__(
self._active_invocations: Set[RouteHandlerInvocation] = set()

def matches(self, request_url: str) -> bool:
return self.matcher.matches(request_url)
return url_matches(self._base_url, request_url, self.url)

async def handle(self, route: "Route") -> bool:
handler_invocation = RouteHandlerInvocation(
Expand Down Expand Up @@ -362,13 +363,13 @@ def prepare_interception_patterns(
patterns = []
all = False
for handler in handlers:
if isinstance(handler.matcher.match, str):
patterns.append({"glob": handler.matcher.match})
elif isinstance(handler.matcher._regex_obj, re.Pattern):
if isinstance(handler.url, str):
patterns.append({"glob": handler.url})
elif isinstance(handler.url, re.Pattern):
patterns.append(
{
"regexSource": handler.matcher._regex_obj.pattern,
"regexFlags": escape_regex_flags(handler.matcher._regex_obj),
"regexSource": handler.url.pattern,
"regexFlags": escape_regex_flags(handler.url),
}
)
else:
Expand Down
9 changes: 9 additions & 0 deletions playwright/_impl/_locator.py
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,15 @@ async def screenshot(
),
)

async def aria_snapshot(self, timeout: float = None) -> str:
return await self._frame._channel.send(
"ariaSnapshot",
{
"selector": self._selector,
**locals_to_params(locals()),
},
)

async def scroll_into_view_if_needed(
self,
timeout: float = None,
Expand Down
25 changes: 16 additions & 9 deletions playwright/_impl/_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@
from playwright._impl._errors import Error
from playwright._impl._event_context_manager import EventContextManagerImpl
from playwright._impl._helper import (
URLMatcher,
URLMatch,
WebSocketRouteHandlerCallback,
async_readfile,
locals_to_params,
url_matches,
)
from playwright._impl._str_utils import escape_regex_flags
from playwright._impl._waiter import Waiter
Expand Down Expand Up @@ -718,8 +719,14 @@ async def _after_handle(self) -> None:


class WebSocketRouteHandler:
def __init__(self, matcher: URLMatcher, handler: WebSocketRouteHandlerCallback):
self.matcher = matcher
def __init__(
self,
base_url: Optional[str],
url: URLMatch,
handler: WebSocketRouteHandlerCallback,
):
self._base_url = base_url
self.url = url
self.handler = handler

@staticmethod
Expand All @@ -729,13 +736,13 @@ def prepare_interception_patterns(
patterns = []
all_urls = False
for handler in handlers:
if isinstance(handler.matcher.match, str):
patterns.append({"glob": handler.matcher.match})
elif isinstance(handler.matcher._regex_obj, re.Pattern):
if isinstance(handler.url, str):
patterns.append({"glob": handler.url})
elif isinstance(handler.url, re.Pattern):
patterns.append(
{
"regexSource": handler.matcher._regex_obj.pattern,
"regexFlags": escape_regex_flags(handler.matcher._regex_obj),
"regexSource": handler.url.pattern,
"regexFlags": escape_regex_flags(handler.url),
}
)
else:
Expand All @@ -746,7 +753,7 @@ def prepare_interception_patterns(
return patterns

def matches(self, ws_url: str) -> bool:
return self.matcher.matches(ws_url)
return url_matches(self._base_url, ws_url, self.url)

async def handle(self, websocket_route: "WebSocketRoute") -> None:
coro_or_future = self.handler(websocket_route)
Expand Down
Loading
Loading