Skip to content

feat(roll): roll to 1617212285000 aka video #609

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 1 commit into from
Apr 3, 2021
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Playwright is a Python library to automate [Chromium](https://www.chromium.org/H

| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->90.0.4430.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Chromium <!-- GEN:chromium-version -->91.0.4455.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| WebKit <!-- GEN:webkit-version -->14.2<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->87.0b10<!-- GEN:stop --> | ✅ | ✅ | ✅ |

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

import pathlib
from pathlib import Path
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._stream import Stream


class Artifact(ChannelOwner):
def __init__(
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
) -> None:
super().__init__(parent, type, guid, initializer)
self._is_remote = False
self.absolute_path = initializer["absolutePath"]

async def path_after_finished(self) -> Optional[pathlib.Path]:
if self._is_remote:
raise Error(
"Path is not available when using browser_type.connect(). Use save_as() to save a local copy."
)
return pathlib.Path(await self._channel.send("pathAfterFinished"))

async def save_as(self, path: Union[str, Path]) -> None:
stream = cast(Stream, from_channel(await self._channel.send("saveAsStream")))
make_dirs_for_file(path)
await stream.save_as(path)

async def failure(self) -> Optional[str]:
return patch_error_message(await self._channel.send("failure"))

async def delete(self) -> None:
await self._channel.send("delete")
1 change: 1 addition & 0 deletions playwright/_impl/_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def __init__(
self._browser_type = parent
self._is_connected = True
self._is_closed_or_closing = False
self._is_remote = False

self._contexts: List[BrowserContext] = []
self._channel.on("close", lambda _: self._on_close())
Expand Down
1 change: 1 addition & 0 deletions playwright/_impl/_browser_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ def __repr__(self) -> str:
return f"<BrowserContext browser={self.browser}>"

def _on_page(self, page: Page) -> None:
print("ON PAGE ARRIVED")
Copy link
Member

Choose a reason for hiding this comment

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

page._set_browser_context(self)
self._pages.append(page)
self.emit(BrowserContext.Events.Page, page)
Expand Down
31 changes: 18 additions & 13 deletions playwright/_impl/_download.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,43 @@

import pathlib
from pathlib import Path
from typing import Dict, Optional, Union
from typing import TYPE_CHECKING, Optional, Union

from playwright._impl._connection import ChannelOwner
from playwright._impl._helper import patch_error_message
from playwright._impl._artifact import Artifact

if TYPE_CHECKING: # pragma: no cover
from playwright._impl._page import Page

class Download(ChannelOwner):

class Download:
def __init__(
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
self, page: "Page", url: str, suggested_filename: str, artifact: Artifact
) -> None:
super().__init__(parent, type, guid, initializer)
self._loop = page._loop
self._dispatcher_fiber = page._dispatcher_fiber
self._url = url
self._suggested_filename = suggested_filename
self._artifact = artifact

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

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

@property
def suggested_filename(self) -> str:
return self._initializer["suggestedFilename"]
return self._suggested_filename

async def delete(self) -> None:
await self._channel.send("delete")
await self._artifact.delete()

async def failure(self) -> Optional[str]:
return patch_error_message(await self._channel.send("failure"))
return await self._artifact.failure()

async def path(self) -> Optional[pathlib.Path]:
return pathlib.Path(await self._channel.send("path"))
return await self._artifact.path_after_finished()

async def save_as(self, path: Union[str, Path]) -> None:
path = str(Path(path))
return await self._channel.send("saveAs", dict(path=path))
await self._artifact.save_as(path)
8 changes: 7 additions & 1 deletion playwright/_impl/_element_handle.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@
from playwright._impl._api_structures import FilePayload, FloatRect, Position
from playwright._impl._connection import ChannelOwner, from_nullable_channel
from playwright._impl._file_chooser import normalize_file_payloads
from playwright._impl._helper import KeyboardModifier, MouseButton, locals_to_params
from playwright._impl._helper import (
KeyboardModifier,
MouseButton,
locals_to_params,
make_dirs_for_file,
)
from playwright._impl._js_handle import (
JSHandle,
Serializable,
Expand Down Expand Up @@ -221,6 +226,7 @@ async def screenshot(
encoded_binary = await self._channel.send("screenshot", params)
decoded_binary = base64.b64decode(encoded_binary)
if path:
make_dirs_for_file(path)
with open(path, "wb") as fd:
fd.write(decoded_binary)
return decoded_binary
Expand Down
8 changes: 8 additions & 0 deletions playwright/_impl/_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@

import fnmatch
import math
import os
import re
import sys
import time
import traceback
from pathlib import Path
from types import TracebackType
from typing import (
TYPE_CHECKING,
Expand Down Expand Up @@ -232,3 +234,9 @@ def not_installed_error(message: str) -> Exception:

def to_snake_case(name: str) -> str:
return to_snake_case_regex.sub(r"_\1", name).lower()


def make_dirs_for_file(path: Union[Path, str]) -> None:
if not os.path.isabs(path):
path = Path.cwd() / path
os.makedirs(os.path.dirname(path), exist_ok=True)
9 changes: 6 additions & 3 deletions playwright/_impl/_object_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from typing import Any, Dict, cast

from playwright._impl._artifact import Artifact
from playwright._impl._browser import Browser
from playwright._impl._browser_context import BrowserContext
from playwright._impl._browser_type import BrowserType
Expand All @@ -22,14 +23,14 @@
from playwright._impl._connection import ChannelOwner
from playwright._impl._console_message import ConsoleMessage
from playwright._impl._dialog import Dialog
from playwright._impl._download import Download
from playwright._impl._element_handle import ElementHandle
from playwright._impl._frame import Frame
from playwright._impl._js_handle import JSHandle
from playwright._impl._network import Request, Response, Route, WebSocket
from playwright._impl._page import BindingCall, Page, Worker
from playwright._impl._playwright import Playwright
from playwright._impl._selectors import Selectors
from playwright._impl._stream import Stream


class DummyObject(ChannelOwner):
Expand All @@ -42,6 +43,8 @@ def __init__(
def create_remote_object(
parent: ChannelOwner, type: str, guid: str, initializer: Dict
) -> Any:
if type == "Artifact":
return Artifact(parent, type, guid, initializer)
if type == "BindingCall":
return BindingCall(parent, type, guid, initializer)
if type == "Browser":
Expand All @@ -63,8 +66,6 @@ def create_remote_object(
return ConsoleMessage(parent, type, guid, initializer)
if type == "Dialog":
return Dialog(parent, type, guid, initializer)
if type == "Download":
return Download(parent, type, guid, initializer)
if type == "ElementHandle":
return ElementHandle(parent, type, guid, initializer)
if type == "Frame":
Expand All @@ -81,6 +82,8 @@ def create_remote_object(
return Response(parent, type, guid, initializer)
if type == "Route":
return Route(parent, type, guid, initializer)
if type == "Stream":
return Stream(parent, type, guid, initializer)
if type == "WebSocket":
return WebSocket(parent, type, guid, initializer)
if type == "Worker":
Expand Down
34 changes: 18 additions & 16 deletions playwright/_impl/_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
URLMatchResponse,
is_safe_close_error,
locals_to_params,
make_dirs_for_file,
parse_error,
serialize_error,
)
Expand Down Expand Up @@ -142,12 +143,7 @@ def __init__(
self._channel.on(
"domcontentloaded", lambda _: self.emit(Page.Events.DOMContentLoaded)
)
self._channel.on(
"download",
lambda params: self.emit(
Page.Events.Download, from_channel(params["download"])
),
)
self._channel.on("download", lambda params: self._on_download(params))
self._channel.on(
"fileChooser",
lambda params: self.emit(
Expand Down Expand Up @@ -208,12 +204,7 @@ def __init__(
from_channel(params["route"]), from_channel(params["request"])
),
)
self._channel.on(
"video",
lambda params: cast(Video, self.video)._set_relative_path(
params["relativePath"]
),
)
self._channel.on("video", lambda params: self._on_video(params))
self._channel.on(
"webSocket",
lambda params: self.emit(
Expand Down Expand Up @@ -294,6 +285,18 @@ def _on_dialog(self, params: Any) -> None:
else:
asyncio.create_task(dialog.dismiss())

def _on_download(self, params: Any) -> None:
url = params["url"]
suggested_filename = params["suggestedFilename"]
artifact = from_channel(params["artifact"])
self.emit(
Page.Events.Download, Download(self, url, suggested_filename, artifact)
)

def _on_video(self, params: Any) -> None:
artifact = from_channel(params["artifact"])
cast(Video, self.video)._artifact_ready(artifact)

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(
Expand Down Expand Up @@ -575,6 +578,7 @@ async def screenshot(
encoded_binary = await self._channel.send("screenshot", params)
decoded_binary = base64.b64decode(encoded_binary)
if path:
make_dirs_for_file(path)
with open(path, "wb") as fd:
fd.write(decoded_binary)
return decoded_binary
Expand Down Expand Up @@ -765,6 +769,7 @@ async def pdf(
encoded_binary = await self._channel.send("pdf", params)
decoded_binary = base64.b64decode(encoded_binary)
if path:
make_dirs_for_file(path)
with open(path, "wb") as fd:
fd.write(decoded_binary)
return decoded_binary
Expand All @@ -773,13 +778,10 @@ async def pdf(
def video(
self,
) -> Optional[Video]:
context_options = self._browser_context._options
if "recordVideo" not in context_options:
if "recordVideo" not in self._browser_context._options:
return None
if not self._video:
self._video = Video(self)
if "videoRelativePath" in self._initializer:
self._video._set_relative_path(self._initializer["videoRelativePath"])
return self._video

def expect_event(
Expand Down
34 changes: 34 additions & 0 deletions playwright/_impl/_stream.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# 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.

import base64
from pathlib import Path
from typing import Dict

from playwright._impl._connection import ChannelOwner


class Stream(ChannelOwner):
def __init__(
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
) -> None:
super().__init__(parent, type, guid, initializer)

async def save_as(self, path: Path) -> None:
with open(path, mode="wb") as file:
while True:
binary = await self._channel.send("read")
if not binary:
break
file.write(base64.b64decode(binary))
Loading