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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 🎭 [Playwright](https://github.com/microsoft/playwright) for Python

[![PyPI version](https://badge.fury.io/py/playwright.svg)](https://pypi.python.org/pypi/playwright/) [![PyPI pyversions](https://img.shields.io/pypi/pyversions/playwright.svg)](https://pypi.python.org/pypi/playwright/) [![Join Slack](https://img.shields.io/badge/join-slack-infomational)](https://join.slack.com/t/playwright/shared_invite/enQtOTEyMTUxMzgxMjIwLThjMDUxZmIyNTRiMTJjNjIyMzdmZDA3MTQxZWUwZTFjZjQwNGYxZGM5MzRmNzZlMWI5ZWUyOTkzMjE5Njg1NDg) <!-- GEN:chromium-version-badge -->[![Chromium version](https://img.shields.io/badge/chromium-86.0.4217.0-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-79.0a1-blue.svg?logo=mozilla-firefox)](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> [![WebKit version](https://img.shields.io/badge/webkit-14.0-blue.svg?logo=safari)](https://webkit.org/)
[![PyPI version](https://badge.fury.io/py/playwright.svg)](https://pypi.python.org/pypi/playwright/) [![PyPI pyversions](https://img.shields.io/pypi/pyversions/playwright.svg)](https://pypi.python.org/pypi/playwright/) [![Join Slack](https://img.shields.io/badge/join-slack-infomational)](https://join.slack.com/t/playwright/shared_invite/enQtOTEyMTUxMzgxMjIwLThjMDUxZmIyNTRiMTJjNjIyMzdmZDA3MTQxZWUwZTFjZjQwNGYxZGM5MzRmNzZlMWI5ZWUyOTkzMjE5Njg1NDg) <!-- GEN:chromium-version-badge -->[![Chromium version](https://img.shields.io/badge/chromium-86.0.4217.0-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-80.0b8-blue.svg?logo=mozilla-firefox)](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> [![WebKit version](https://img.shields.io/badge/webkit-14.0-blue.svg?logo=safari)](https://webkit.org/)

##### [Docs](#documentation) | [API reference](https://playwright.dev/#?path=docs/api.md) | [Docstrings](https://github.com/microsoft/playwright-python/blob/master/playwright/sync_api.py)

Expand All @@ -10,7 +10,7 @@ Playwright is a Python library to automate [Chromium](https://www.chromium.org/H
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->86.0.4217.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| WebKit 14.0 | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->79.0a1<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->80.0b8<!-- GEN:stop --> | ✅ | ✅ | ✅ |

Headless execution is supported for all the browsers on all platforms.

Expand Down
2 changes: 1 addition & 1 deletion driver/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,5 @@ const util = require('util');
return;
}

require('playwright/lib/rpc/server');
require('playwright/lib/server');
})();
2 changes: 1 addition & 1 deletion driver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
},
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.3.0-next.1596843106133"
"playwright": "1.3.0-next.1598476714110"
},
"devDependencies": {
"pkg": "^4.4.9"
Expand Down
121 changes: 5 additions & 116 deletions playwright/async_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
from playwright.async_base import AsyncBase, AsyncEventContextManager, mapping
from playwright.browser import Browser as BrowserImpl
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 (
Expand Down Expand Up @@ -3070,6 +3069,11 @@ def workers(self) -> typing.List["Worker"]:
"""
return mapping.from_impl_list(self._impl_obj.workers)

def remove_listener(self, event: str, f: typing.Any) -> NoneType:
return mapping.from_maybe_impl(
self._impl_obj.remove_listener(event=event, f=mapping.to_impl(f))
)

async def opener(self) -> typing.Union["Page", NoneType]:
"""Page.opener

Expand Down Expand Up @@ -5518,45 +5522,6 @@ async def close(self) -> NoneType:
mapping.register(BrowserImpl, Browser)


class BrowserServer(AsyncBase):
def __init__(self, obj: BrowserServerImpl):
super().__init__(obj)

@property
def pid(self) -> str:
return mapping.from_maybe_impl(self._impl_obj.pid)

@property
def wsEndpoint(self) -> str:
"""BrowserServer.wsEndpoint

Browser websocket endpoint which can be used as an argument to browserType.connect(options) to establish connection to the browser.

Returns
-------
str
Browser websocket url.
"""
return mapping.from_maybe_impl(self._impl_obj.wsEndpoint)

async def kill(self) -> NoneType:
"""BrowserServer.kill

Kills the browser process and waits for the process to exit.
"""
return mapping.from_maybe_impl(await self._impl_obj.kill())

async def close(self) -> NoneType:
"""BrowserServer.close

Closes the browser gracefully and makes sure the process is terminated.
"""
return mapping.from_maybe_impl(await self._impl_obj.close())


mapping.register(BrowserServerImpl, BrowserServer)


class BrowserType(AsyncBase):
def __init__(self, obj: BrowserTypeImpl):
super().__init__(obj)
Expand Down Expand Up @@ -5665,82 +5630,6 @@ async def launch(
)
)

async def launchServer(
self,
executablePath: typing.Union[str, pathlib.Path] = None,
args: typing.List[str] = None,
ignoreDefaultArgs: typing.Union[bool, typing.List[str]] = None,
handleSIGINT: bool = None,
handleSIGTERM: bool = None,
handleSIGHUP: bool = None,
timeout: int = None,
env: typing.Union[typing.Dict[str, typing.Union[str, int, bool]]] = None,
headless: bool = None,
devtools: bool = None,
proxy: ProxyServer = None,
downloadsPath: typing.Union[str, pathlib.Path] = None,
port: int = None,
chromiumSandbox: bool = None,
) -> "BrowserServer":
"""BrowserType.launchServer

Launches browser server that client can connect to. An example of launching a browser executable and connecting to it later:

Parameters
----------
executablePath : Union[str, pathlib.Path, NoneType]
Path to a browser executable to run instead of the bundled one. If `executablePath` is a relative path, then it is resolved relative to current working directory. **BEWARE**: Playwright is only guaranteed to work with the bundled Chromium, Firefox or WebKit, use at your own risk.
args : Optional[List[str]]
Additional arguments to pass to the browser instance. The list of Chromium flags can be found here.
ignoreDefaultArgs : Union[bool, List[str], NoneType]
If `true`, then do not use any of the default arguments. If an array is given, then filter out the given default arguments. Dangerous option; use with care. Defaults to `false`.
handleSIGINT : Optional[bool]
Close the browser process on Ctrl-C. Defaults to `true`.
handleSIGTERM : Optional[bool]
Close the browser process on SIGTERM. Defaults to `true`.
handleSIGHUP : Optional[bool]
Close the browser process on SIGHUP. Defaults to `true`.
timeout : Optional[int]
Maximum time in milliseconds to wait for the browser instance to start. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
env : Optional[Dict[str, Union[str, int, bool]]]
Specify environment variables that will be visible to the browser. Defaults to `process.env`.
headless : Optional[bool]
Whether to run browser in headless mode. More details for Chromium and Firefox. Defaults to `true` unless the `devtools` option is `true`.
devtools : Optional[bool]
**Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is `true`, the `headless` option will be set `false`.
proxy : Optional[{"server": str, "bypass": Optional[str], "username": Optional[str], "password": Optional[str]}]
Network proxy settings.
downloadsPath : Union[str, pathlib.Path, NoneType]
If specified, accepted downloads are downloaded into this folder. Otherwise, temporary folder is created and is deleted when browser is closed.
port : Optional[int]
Port to use for the web socket. Defaults to 0 that picks any available port.
chromiumSandbox : Optional[bool]
Enable Chromium sandboxing. Defaults to `true`.

Returns
-------
BrowserServer
Promise which resolves to the browser app instance.
"""
return mapping.from_impl(
await self._impl_obj.launchServer(
executablePath=executablePath,
args=args,
ignoreDefaultArgs=ignoreDefaultArgs,
handleSIGINT=handleSIGINT,
handleSIGTERM=handleSIGTERM,
handleSIGHUP=handleSIGHUP,
timeout=timeout,
env=mapping.to_impl(env),
headless=headless,
devtools=devtools,
proxy=proxy,
downloadsPath=downloadsPath,
port=port,
chromiumSandbox=chromiumSandbox,
)
)

async def launchPersistentContext(
self,
userDataDir: typing.Union[str, pathlib.Path],
Expand Down
43 changes: 0 additions & 43 deletions playwright/browser_server.py

This file was deleted.

27 changes: 0 additions & 27 deletions playwright/browser_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

from playwright.browser import Browser
from playwright.browser_context import BrowserContext
from playwright.browser_server import BrowserServer
from playwright.connection import ChannelOwner, from_channel
from playwright.helper import (
ColorScheme,
Expand Down Expand Up @@ -72,32 +71,6 @@ async def launch(
raise not_installed_error(f'"{self.name}" browser was not found.')
raise e

async def launchServer(
self,
executablePath: Union[str, Path] = None,
args: List[str] = None,
ignoreDefaultArgs: Union[bool, List[str]] = None,
handleSIGINT: bool = None,
handleSIGTERM: bool = None,
handleSIGHUP: bool = None,
timeout: int = None,
env: Env = None,
headless: bool = None,
devtools: bool = None,
proxy: ProxyServer = None,
downloadsPath: Union[str, Path] = None,
port: int = None,
chromiumSandbox: bool = None,
) -> BrowserServer:
params = locals_to_params(locals())
normalize_launch_params(params)
try:
return from_channel(await self._channel.send("launchServer", params))
except Exception as e:
if f"{self.name}-" in str(e):
raise not_installed_error(f'"{self.name}" browser was not found.')
raise e

async def launchPersistentContext(
self,
userDataDir: Union[str, Path],
Expand Down
8 changes: 3 additions & 5 deletions playwright/cdp_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
from typing import Any, Dict

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


class CDPSession(ChannelOwner):
Expand All @@ -29,10 +30,7 @@ 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)
result = await self._channel.send("send", locals_to_params(locals()))
return parse_result(result)

async def detach(self) -> None:
Expand Down
4 changes: 2 additions & 2 deletions playwright/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def __init__(self, connection: "Connection", guid: str) -> None:
self._guid = guid
self._object: Optional[ChannelOwner] = None

async def send(self, method: str, params: dict = None) -> Any:
async def send(self, method: str, params: Dict = None) -> Any:
if params is None:
params = {}
callback = self._connection._send_message_to_server(self._guid, method, params)
Expand All @@ -48,7 +48,7 @@ async def send(self, method: str, params: dict = None) -> Any:
key = next(iter(result))
return result[key]

def send_no_reply(self, method: str, params: dict = None) -> None:
def send_no_reply(self, method: str, params: Dict = None) -> None:
if params is None:
params = {}
self._connection._send_message_to_server(self._guid, method, params)
Expand Down
4 changes: 2 additions & 2 deletions playwright/drivers/browsers.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
},
{
"name": "firefox",
"revision": "1154",
"revision": "1167",
"download": true
},
{
"name": "webkit",
"revision": "1322",
"revision": "1332",
"download": true
}
]
Expand Down
2 changes: 1 addition & 1 deletion playwright/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,4 @@ def serialize_headers(headers: Dict[str, str]) -> List[Header]:


def parse_headers(headers: List[Header]) -> Dict[str, str]:
return {header["name"]: header["value"] for header in headers}
return {header["name"].lower(): header["value"] for header in headers}
3 changes: 0 additions & 3 deletions playwright/object_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

from playwright.browser import Browser
from playwright.browser_context import BrowserContext
from playwright.browser_server import BrowserServer
from playwright.browser_type import BrowserType
from playwright.cdp_session import CDPSession
from playwright.chromium_browser_context import ChromiumBrowserContext
Expand Down Expand Up @@ -47,8 +46,6 @@ def create_remote_object(
return BindingCall(parent, type, guid, initializer)
if type == "Browser":
return Browser(cast(BrowserType, parent), type, guid, initializer)
if type == "BrowserServer":
return BrowserServer(parent, type, guid, initializer)
if type == "BrowserType":
return BrowserType(parent, type, guid, initializer)
if type == "BrowserContext":
Expand Down
14 changes: 14 additions & 0 deletions playwright/page.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,20 @@ def _reject_pending_operations(self, is_crash: bool) -> None:
for pending_event in self._pending_wait_for_events:
pending_event.reject(is_crash, "Page")

def _add_event_handler(self, event: str, k: Any, v: Any) -> None:
if event == Page.Events.FileChooser and len(self.listeners(event)) == 0:
self._channel.send_no_reply(
"setFileChooserInterceptedNoReply", {"intercepted": True}
)
super()._add_event_handler(event, k, v)

def remove_listener(self, event: str, f: Any) -> None:
super().remove_listener(event, f)
if event == Page.Events.FileChooser and len(self.listeners(event)) == 0:
self._channel.send_no_reply(
"setFileChooserInterceptedNoReply", {"intercepted": False}
)

@property
def context(self) -> "BrowserContext":
return self._browser_context
Expand Down
Loading