Skip to content

Commit

Permalink
feat(cdp): expose cdp session (#133)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman authored Aug 3, 2020
1 parent 87dceff commit 359f8cc
Show file tree
Hide file tree
Showing 14 changed files with 471 additions and 92 deletions.
133 changes: 110 additions & 23 deletions playwright/async_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
from playwright.browser_context import BrowserContext as BrowserContextImpl
from playwright.browser_server import BrowserServer as BrowserServerImpl
from playwright.browser_type import BrowserType as BrowserTypeImpl
from playwright.cdp_session import CDPSession as CDPSessionImpl
from playwright.chromium_browser_context import (
ChromiumBrowserContext as ChromiumBrowserContextImpl,
)
from playwright.console_message import ConsoleMessage as ConsoleMessageImpl
from playwright.dialog import Dialog as DialogImpl
from playwright.download import Download as DownloadImpl
Expand Down Expand Up @@ -647,7 +651,7 @@ def __init__(self, obj: JSHandleImpl):
super().__init__(obj)

async def evaluate(
self, expression: str, arg: typing.Any = None, force_expr: bool = False
self, expression: str, arg: typing.Any = None, force_expr: bool = None
) -> typing.Any:
"""JSHandle.evaluate
Expand Down Expand Up @@ -676,7 +680,7 @@ async def evaluate(
)

async def evaluateHandle(
self, expression: str, arg: typing.Any = None, force_expr: bool = False
self, expression: str, arg: typing.Any = None, force_expr: bool = None
) -> "JSHandle":
"""JSHandle.evaluateHandle
Expand Down Expand Up @@ -1034,7 +1038,7 @@ async def selectOption(
typing.List[str],
typing.List["ElementHandle"],
typing.List[SelectOption],
],
] = None,
timeout: int = None,
noWaitAfter: bool = None,
) -> typing.List[str]:
Expand Down Expand Up @@ -1336,7 +1340,7 @@ async def evalOnSelector(
selector: str,
expression: str,
arg: typing.Any = None,
force_expr: bool = False,
force_expr: bool = None,
) -> typing.Any:
"""ElementHandle.evalOnSelector
Expand Down Expand Up @@ -1374,7 +1378,7 @@ async def evalOnSelectorAll(
selector: str,
expression: str,
arg: typing.Any = None,
force_expr: bool = False,
force_expr: bool = None,
) -> typing.Any:
"""ElementHandle.evalOnSelectorAll
Expand Down Expand Up @@ -1699,7 +1703,7 @@ async def frameElement(self) -> "ElementHandle":
return mapping.from_impl(await self._impl_obj.frameElement())

async def evaluate(
self, expression: str, arg: typing.Any = None, force_expr: bool = False
self, expression: str, arg: typing.Any = None, force_expr: bool = None
) -> typing.Any:
"""Frame.evaluate
Expand Down Expand Up @@ -1729,7 +1733,7 @@ async def evaluate(
)

async def evaluateHandle(
self, expression: str, arg: typing.Any = None, force_expr: bool = False
self, expression: str, arg: typing.Any = None, force_expr: bool = None
) -> "JSHandle":
"""Frame.evaluateHandle
Expand Down Expand Up @@ -1878,7 +1882,7 @@ async def evalOnSelector(
selector: str,
expression: str,
arg: typing.Any = None,
force_expr: bool = False,
force_expr: bool = None,
) -> typing.Any:
"""Frame.evalOnSelector
Expand Down Expand Up @@ -1916,7 +1920,7 @@ async def evalOnSelectorAll(
selector: str,
expression: str,
arg: typing.Any = None,
force_expr: bool = False,
force_expr: bool = None,
) -> typing.Any:
"""Frame.evalOnSelectorAll
Expand Down Expand Up @@ -2334,7 +2338,7 @@ async def selectOption(
typing.List[str],
typing.List["ElementHandle"],
typing.List[SelectOption],
],
] = None,
timeout: int = None,
noWaitAfter: bool = None,
) -> typing.List[str]:
Expand Down Expand Up @@ -2556,7 +2560,7 @@ async def waitForFunction(
self,
expression: str,
arg: typing.Any = None,
force_expr: bool = False,
force_expr: bool = None,
timeout: int = None,
polling: typing.Union[int, Literal["raf"]] = None,
) -> "JSHandle":
Expand Down Expand Up @@ -2640,7 +2644,7 @@ def url(self) -> str:
return mapping.from_maybe_impl(self._impl_obj.url)

async def evaluate(
self, expression: str, arg: typing.Any = None, force_expr: bool = False
self, expression: str, arg: typing.Any = None, force_expr: bool = None
) -> typing.Any:
"""Worker.evaluate
Expand Down Expand Up @@ -2668,7 +2672,7 @@ async def evaluate(
)

async def evaluateHandle(
self, expression: str, arg: typing.Any = None, force_expr: bool = False
self, expression: str, arg: typing.Any = None, force_expr: bool = None
) -> "JSHandle":
"""Worker.evaluateHandle
Expand Down Expand Up @@ -2704,7 +2708,11 @@ def __init__(self, obj: SelectorsImpl):
super().__init__(obj)

async def register(
self, name: str, source: str = "", path: str = None, contentScript: bool = False
self,
name: str,
source: str = None,
path: str = None,
contentScript: bool = None,
) -> NoneType:
"""Selectors.register
Expand All @@ -2714,9 +2722,9 @@ async def register(
----------
name : str
Name that is used in selectors as a prefix, e.g. `{name: 'foo'}` enables `foo=myselectorbody` selectors. May only contain `[a-zA-Z0-9_]` characters.
source : str
source : Optional[str]
Script that evaluates to a selector engine instance.
contentScript : bool
contentScript : Optional[bool]
Whether to run this selector engine in isolated JavaScript environment. This environment has access to the same DOM, but not any JavaScript objects from the frame's scripts. Defaults to `false`. Note that running as a content script is not guaranteed when this engine is used together with other registered engines.
"""
return mapping.from_maybe_impl(
Expand Down Expand Up @@ -3198,7 +3206,7 @@ async def dispatchEvent(
)

async def evaluate(
self, expression: str, arg: typing.Any = None, force_expr: bool = False
self, expression: str, arg: typing.Any = None, force_expr: bool = None
) -> typing.Any:
"""Page.evaluate
Expand Down Expand Up @@ -3230,7 +3238,7 @@ async def evaluate(
)

async def evaluateHandle(
self, expression: str, arg: typing.Any = None, force_expr: bool = False
self, expression: str, arg: typing.Any = None, force_expr: bool = None
) -> "JSHandle":
"""Page.evaluateHandle
Expand Down Expand Up @@ -3264,7 +3272,7 @@ async def evalOnSelector(
selector: str,
expression: str,
arg: typing.Any = None,
force_expr: bool = False,
force_expr: bool = None,
) -> typing.Any:
"""Page.evalOnSelector
Expand Down Expand Up @@ -3303,7 +3311,7 @@ async def evalOnSelectorAll(
selector: str,
expression: str,
arg: typing.Any = None,
force_expr: bool = False,
force_expr: bool = None,
) -> typing.Any:
"""Page.evalOnSelectorAll
Expand Down Expand Up @@ -4281,7 +4289,7 @@ async def selectOption(
typing.List[str],
typing.List["ElementHandle"],
typing.List[SelectOption],
],
] = None,
timeout: int = None,
noWaitAfter: bool = None,
) -> typing.List[str]:
Expand Down Expand Up @@ -4505,7 +4513,7 @@ async def waitForFunction(
self,
expression: str,
arg: typing.Any = None,
force_expr: bool = False,
force_expr: bool = None,
timeout: int = None,
polling: typing.Union[int, Literal["raf"]] = None,
) -> "JSHandle":
Expand Down Expand Up @@ -4913,7 +4921,7 @@ async def clearPermissions(self) -> NoneType:
"""
return mapping.from_maybe_impl(await self._impl_obj.clearPermissions())

async def setGeolocation(self, geolocation: typing.Dict) -> NoneType:
async def setGeolocation(self, geolocation: typing.Dict = None) -> NoneType:
"""BrowserContext.setGeolocation
Sets the context's geolocation. Passing `null` or `undefined` emulates position unavailable.
Expand Down Expand Up @@ -5133,6 +5141,85 @@ def expect_page(
mapping.register(BrowserContextImpl, BrowserContext)


class CDPSession(AsyncBase):
def __init__(self, obj: CDPSessionImpl):
super().__init__(obj)

async def send(self, method: str, params: typing.Dict = None) -> typing.Dict:
"""CDPSession.send
Parameters
----------
method : str
protocol method name
params : Optional[typing.Dict]
Optional method parameters
Returns
-------
typing.Dict
"""
return mapping.from_maybe_impl(
await self._impl_obj.send(method=method, params=params)
)

async def detach(self) -> NoneType:
"""CDPSession.detach
Detaches the CDPSession from the target. Once detached, the CDPSession object won't emit any events and can't be used
to send messages.
"""
return mapping.from_maybe_impl(await self._impl_obj.detach())


mapping.register(CDPSessionImpl, CDPSession)


class ChromiumBrowserContext(BrowserContext):
def __init__(self, obj: ChromiumBrowserContextImpl):
super().__init__(obj)

def backgroundPages(self) -> typing.List["Page"]:
"""ChromiumBrowserContext.backgroundPages
Returns
-------
typing.List[Page]
All existing background pages in the context.
"""
return mapping.from_impl_list(self._impl_obj.backgroundPages())

def serviceWorkers(self) -> typing.List["Worker"]:
"""ChromiumBrowserContext.serviceWorkers
Returns
-------
typing.List[Worker]
All existing service workers in the context.
"""
return mapping.from_impl_list(self._impl_obj.serviceWorkers())

async def newCDPSession(self, page: "Page") -> "CDPSession":
"""ChromiumBrowserContext.newCDPSession
Parameters
----------
page : Page
Page to create new session for.
Returns
-------
CDPSession
Promise that resolves to the newly created session.
"""
return mapping.from_impl(
await self._impl_obj.newCDPSession(page=page._impl_obj)
)


mapping.register(ChromiumBrowserContextImpl, ChromiumBrowserContext)


class Browser(AsyncBase):
def __init__(self, obj: BrowserImpl):
super().__init__(obj)
Expand Down
8 changes: 6 additions & 2 deletions playwright/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import sys
from types import SimpleNamespace
from typing import Dict, List, Union
from typing import TYPE_CHECKING, Dict, List, Union

from playwright.browser_context import BrowserContext
from playwright.connection import ChannelOwner, from_channel
Expand All @@ -27,15 +27,19 @@
else: # pragma: no cover
from typing_extensions import Literal

if TYPE_CHECKING: # pragma: no cover
from playwright.browser_type import BrowserType


class Browser(ChannelOwner):

Events = SimpleNamespace(Disconnected="disconnected",)

def __init__(
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
self, parent: "BrowserType", type: str, guid: str, initializer: Dict
) -> None:
super().__init__(parent, type, guid, initializer)
self._browser_type = parent
self._is_connected = True
self._is_closed_or_closing = False

Expand Down
39 changes: 39 additions & 0 deletions playwright/cdp_session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# 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.

from typing import Any, Dict

from playwright.connection import ChannelOwner
from playwright.js_handle import parse_result, serialize_argument


class CDPSession(ChannelOwner):
def __init__(
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
) -> None:
super().__init__(parent, type, guid, initializer)
self._channel.on("event", lambda params: self._on_event(params))

def _on_event(self, params: Any) -> None:
self.emit(params["method"], parse_result(params["params"]))

async def send(self, method: str, params: Dict = None) -> Dict:
payload = {"method": method}
if params:
payload["params"] = serialize_argument(params)["value"]
result = await self._channel.send("send", payload)
return parse_result(result)

async def detach(self) -> None:
await self._channel.send("detach")
Loading

0 comments on commit 359f8cc

Please sign in to comment.