Skip to content

Commit 062cc15

Browse files
authored
feat(api): api review nits (microsoft#381)
1 parent f347dd4 commit 062cc15

30 files changed

+441
-469
lines changed

playwright/__init__.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,8 @@
2828
FilePayload = api_types.FilePayload
2929
FloatRect = api_types.FloatRect
3030
Geolocation = api_types.Geolocation
31-
HttpCredentials = api_types.HttpCredentials
3231
PdfMargins = api_types.PdfMargins
3332
ProxySettings = api_types.ProxySettings
34-
RecordHarOptions = api_types.RecordHarOptions
35-
RecordVideoOptions = api_types.RecordVideoOptions
36-
RequestFailure = api_types.RequestFailure
37-
OptionSelector = api_types.OptionSelector
3833
SourceLocation = api_types.SourceLocation
3934
TimeoutError = api_types.TimeoutError
4035

@@ -55,19 +50,14 @@ def sync_playwright() -> SyncPlaywrightContextManager:
5550
"async_playwright",
5651
"sync_playwright",
5752
"Cookie",
58-
"HttpCredentials",
5953
"DeviceDescriptor",
6054
"Error",
6155
"FilePayload",
6256
"FloatRect",
6357
"Geolocation",
6458
"PdfMargins",
6559
"ProxySettings",
66-
"RecordHarOptions",
67-
"RecordVideoOptions",
68-
"RequestFailure",
6960
"ResourceTiming",
70-
"OptionSelector",
7161
"SourceLocation",
7262
"StorageState",
7363
"TimeoutError",

playwright/_api_types.py

Lines changed: 7 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from pathlib import Path
15+
import sys
1616
from typing import Any, Dict, Optional, Tuple, Union
1717

18+
if sys.version_info >= (3, 8): # pragma: no cover
19+
from typing import TypedDict
20+
else: # pragma: no cover
21+
from typing_extensions import TypedDict
22+
1823

1924
class Error(Exception):
2025
def __init__(self, message: str, stack: str = None) -> None:
@@ -68,37 +73,13 @@ def __init__(self, x: float, y: float, width: float, height: float):
6873
self.height = height
6974

7075

71-
class DeviceDescriptor(ApiType):
76+
class DeviceDescriptor(TypedDict):
7277
user_agent: Optional[str]
7378
viewport: Optional[Tuple[int, int]]
7479
device_scale_factor: Optional[int]
7580
is_mobile: Optional[bool]
7681
has_touch: Optional[bool]
7782

78-
@classmethod
79-
def _parse(cls, dict: Dict) -> "DeviceDescriptor":
80-
return DeviceDescriptor(
81-
dict["userAgent"],
82-
dict["viewport"],
83-
dict["deviceScaleFactor"],
84-
dict["isMobile"],
85-
dict["hasTouch"],
86-
)
87-
88-
def __init__(
89-
self,
90-
user_agent: str = None,
91-
viewport: Tuple[int, int] = None,
92-
device_scale_factor: int = None,
93-
is_mobile: bool = None,
94-
has_touch: bool = None,
95-
):
96-
self.user_agent = user_agent
97-
self.viewport = viewport
98-
self.device_scale_factor = device_scale_factor
99-
self.is_mobile = is_mobile
100-
self.has_touch = has_touch
101-
10283

10384
class Geolocation(ApiType):
10485
latitude: float
@@ -111,15 +92,6 @@ def __init__(self, latitude: float, longitude: float, accuracy: float = None):
11192
self.accuracy = accuracy
11293

11394

114-
class HttpCredentials(ApiType):
115-
username: str
116-
password: str
117-
118-
def __init__(self, username: str, password: str):
119-
self.username = username
120-
self.password = password
121-
122-
12395
class PdfMargins(ApiType):
12496
top: Optional[Union[str, int]]
12597
right: Optional[Union[str, int]]
@@ -158,52 +130,6 @@ def __init__(
158130
self.password = password
159131

160132

161-
class RequestFailure(ApiType):
162-
error_text: str
163-
164-
@classmethod
165-
def _parse(cls, dict: Optional[Dict]) -> Optional["RequestFailure"]:
166-
if not dict:
167-
return None
168-
return RequestFailure(dict["errorText"])
169-
170-
def __init__(self, error_text: str):
171-
self.error_text = error_text
172-
173-
174-
class RecordHarOptions(ApiType):
175-
omit_content: Optional[bool]
176-
path: Union[Path, str]
177-
178-
def __init__(self, path: Union[str, Path], omit_content: bool = None):
179-
self.path = path
180-
self.omit_content = omit_content
181-
182-
def _to_json(self) -> Dict:
183-
return filter_out_none(
184-
{"omitContent": self.omit_content, "path": str(self.path)}
185-
)
186-
187-
188-
class RecordVideoOptions(ApiType):
189-
dir: Union[Path, str]
190-
size: Optional[Tuple[int, int]]
191-
192-
def __init__(self, dir: Union[str, Path], size: Tuple[int, int] = None):
193-
self.dir = dir
194-
self.size = size
195-
196-
def _to_json(self) -> Dict:
197-
return filter_out_none(
198-
{
199-
"dir": str(self.dir),
200-
"size": {"width": self.size[0], "height": self.size[1]}
201-
if self.size
202-
else None,
203-
}
204-
)
205-
206-
207133
class SourceLocation(ApiType):
208134
url: str
209135
line: int
@@ -215,17 +141,6 @@ def __init__(self, url: str, line: int, column: int):
215141
self.column = column
216142

217143

218-
class OptionSelector(ApiType):
219-
value: Optional[str]
220-
label: Optional[str]
221-
index: Optional[int]
222-
223-
def __init__(self, value: str = None, label: str = None, index: int = None):
224-
self.value = value
225-
self.label = label
226-
self.index = index
227-
228-
229144
def filter_out_none(args: Dict) -> Any:
230145
copy = {}
231146
for key in args:

playwright/_browser.py

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,7 @@
1919
from typing import TYPE_CHECKING, Dict, List, Tuple, Union
2020

2121
from playwright._api_structures import StorageState
22-
from playwright._api_types import (
23-
Geolocation,
24-
HttpCredentials,
25-
ProxySettings,
26-
RecordHarOptions,
27-
RecordVideoOptions,
28-
)
22+
from playwright._api_types import Geolocation, ProxySettings
2923
from playwright._browser_context import BrowserContext
3024
from playwright._connection import ChannelOwner, from_channel
3125
from playwright._helper import ColorScheme, is_safe_close_error, locals_to_params
@@ -83,32 +77,22 @@ async def newContext(
8377
permissions: List[str] = None,
8478
extraHTTPHeaders: Dict[str, str] = None,
8579
offline: bool = None,
86-
httpCredentials: HttpCredentials = None,
80+
httpCredentials: Tuple[str, str] = None,
8781
deviceScaleFactor: int = None,
8882
isMobile: bool = None,
8983
hasTouch: bool = None,
9084
colorScheme: ColorScheme = None,
9185
acceptDownloads: bool = None,
9286
defaultBrowserType: str = None,
9387
proxy: ProxySettings = None,
94-
recordHar: RecordHarOptions = None,
95-
recordVideo: RecordVideoOptions = None,
88+
recordHarPath: Union[Path, str] = None,
89+
recordHarOmitContent: bool = None,
90+
recordVideoDir: Union[Path, str] = None,
91+
recordVideoSize: Tuple[int, int] = None,
9692
storageState: Union[StorageState, str, Path] = None,
9793
) -> BrowserContext:
9894
params = locals_to_params(locals())
99-
# Python is strict in which variables gets passed to methods. We get this
100-
# value from the device descriptors, thats why we have to strip it out.
101-
if defaultBrowserType in params:
102-
del params["defaultBrowserType"]
103-
if storageState:
104-
if not isinstance(storageState, dict):
105-
with open(storageState, "r") as f:
106-
params["storageState"] = json.load(f)
107-
if viewport == 0:
108-
del params["viewport"]
109-
params["noDefaultViewport"] = True
110-
if extraHTTPHeaders:
111-
params["extraHTTPHeaders"] = serialize_headers(extraHTTPHeaders)
95+
normalize_context_params(params)
11296

11397
channel = await self._channel.send("newContext", params)
11498
context = from_channel(channel)
@@ -130,27 +114,21 @@ async def newPage(
130114
permissions: List[str] = None,
131115
extraHTTPHeaders: Dict[str, str] = None,
132116
offline: bool = None,
133-
httpCredentials: HttpCredentials = None,
117+
httpCredentials: Tuple[str, str] = None,
134118
deviceScaleFactor: int = None,
135119
isMobile: bool = None,
136120
hasTouch: bool = None,
137121
colorScheme: ColorScheme = None,
138122
acceptDownloads: bool = None,
139123
defaultBrowserType: str = None,
140124
proxy: ProxySettings = None,
141-
recordHar: RecordHarOptions = None,
142-
recordVideo: RecordVideoOptions = None,
125+
recordHarPath: Union[Path, str] = None,
126+
recordHarOmitContent: bool = None,
127+
recordVideoDir: Union[Path, str] = None,
128+
recordVideoSize: Tuple[int, int] = None,
143129
storageState: Union[StorageState, str, Path] = None,
144130
) -> Page:
145131
params = locals_to_params(locals())
146-
# Python is strict in which variables gets passed to methods. We get this
147-
# value from the device descriptors, thats why we have to strip it out.
148-
if defaultBrowserType:
149-
del params["defaultBrowserType"]
150-
if storageState:
151-
if not isinstance(storageState, dict):
152-
with open(storageState, "r") as f:
153-
params["storageState"] = json.load(f)
154132
context = await self.newContext(**params)
155133
page = await context.newPage()
156134
page._owned_context = context
@@ -170,3 +148,33 @@ async def close(self) -> None:
170148
@property
171149
def version(self) -> str:
172150
return self._initializer["version"]
151+
152+
153+
def normalize_context_params(params: Dict) -> None:
154+
if "viewport" in params and params["viewport"] == 0:
155+
del params["viewport"]
156+
params["noDefaultViewport"] = True
157+
if "defaultBrowserType" in params:
158+
del params["defaultBrowserType"]
159+
if "extraHTTPHeaders" in params:
160+
params["extraHTTPHeaders"] = serialize_headers(params["extraHTTPHeaders"])
161+
if "recordHarPath" in params:
162+
params["recordHar"] = {"path": str(params["recordHarPath"])}
163+
if "recordHarOmitContent" in params:
164+
params["recordHar"]["omitContent"] = True
165+
del params["recordHarOmitContent"]
166+
del params["recordHarPath"]
167+
if "recordVideoDir" in params:
168+
params["recordVideo"] = {"dir": str(params["recordVideoDir"])}
169+
if "recordVideoSize" in params:
170+
params["recordVideo"]["size"] = {
171+
"width": params["recordVideoSize"][0],
172+
"height": params["recordVideoSize"][1],
173+
}
174+
del params["recordVideoSize"]
175+
del params["recordVideoDir"]
176+
if "storageState" in params:
177+
storageState = params["storageState"]
178+
if not isinstance(storageState, dict):
179+
with open(storageState, "r") as f:
180+
params["storageState"] = json.load(f)

playwright/_browser_context.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Union, cast
2121

2222
from playwright._api_structures import Cookie, StorageState
23-
from playwright._api_types import Error, Geolocation
23+
from playwright._api_types import Error
2424
from playwright._connection import ChannelOwner, from_channel
2525
from playwright._event_context_manager import EventContextManagerImpl
2626
from playwright._helper import (
@@ -141,8 +141,15 @@ async def grantPermissions(
141141
async def clearPermissions(self) -> None:
142142
await self._channel.send("clearPermissions")
143143

144-
async def setGeolocation(self, geolocation: Optional[Geolocation]) -> None:
145-
await self._channel.send("setGeolocation", locals_to_params(locals()))
144+
async def setGeolocation(
145+
self, latitude: float, longitude: float, accuracy: Optional[float]
146+
) -> None:
147+
await self._channel.send(
148+
"setGeolocation", {"geolocation": locals_to_params(locals())}
149+
)
150+
151+
async def resetGeolocation(self) -> None:
152+
await self._channel.send("setGeolocation", {})
146153

147154
async def setExtraHTTPHeaders(self, headers: Dict[str, str]) -> None:
148155
await self._channel.send(

playwright/_browser_type.py

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,11 @@
1616
from pathlib import Path
1717
from typing import Dict, List, Tuple, Union
1818

19-
from playwright._api_types import (
20-
Geolocation,
21-
HttpCredentials,
22-
ProxySettings,
23-
RecordHarOptions,
24-
RecordVideoOptions,
25-
)
26-
from playwright._browser import Browser
19+
from playwright._api_types import Geolocation, ProxySettings
20+
from playwright._browser import Browser, normalize_context_params
2721
from playwright._browser_context import BrowserContext
2822
from playwright._connection import ChannelOwner, from_channel
2923
from playwright._helper import ColorScheme, Env, locals_to_params, not_installed_error
30-
from playwright._network import serialize_headers
3124

3225
if sys.version_info >= (3, 8): # pragma: no cover
3326
from typing import Literal
@@ -103,23 +96,21 @@ async def launchPersistentContext(
10396
permissions: List[str] = None,
10497
extraHTTPHeaders: Dict[str, str] = None,
10598
offline: bool = None,
106-
httpCredentials: HttpCredentials = None,
99+
httpCredentials: Tuple[str, str] = None,
107100
deviceScaleFactor: int = None,
108101
isMobile: bool = None,
109102
hasTouch: bool = None,
110103
colorScheme: ColorScheme = None,
111104
acceptDownloads: bool = None,
112105
chromiumSandbox: bool = None,
113-
recordHar: RecordHarOptions = None,
114-
recordVideo: RecordVideoOptions = None,
106+
recordHarPath: Union[Path, str] = None,
107+
recordHarOmitContent: bool = None,
108+
recordVideoDir: Union[Path, str] = None,
109+
recordVideoSize: Tuple[int, int] = None,
115110
) -> BrowserContext:
116111
userDataDir = str(Path(userDataDir))
117112
params = locals_to_params(locals())
118-
if viewport == 0:
119-
del params["viewport"]
120-
params["noDefaultViewport"] = True
121-
if extraHTTPHeaders:
122-
params["extraHTTPHeaders"] = serialize_headers(extraHTTPHeaders)
113+
normalize_context_params(params)
123114
normalize_launch_params(params)
124115
try:
125116
context = from_channel(

playwright/_connection.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ def _replace_channels_with_guids(self, payload: Any, param_name: str) -> Any:
237237
return {"x": payload[0], "y": payload[1]}
238238
if param_name == "size" or param_name == "viewport":
239239
return {"width": payload[0], "height": payload[1]}
240+
if param_name == "httpCredentials":
241+
return {"username": payload[0], "password": payload[1]}
240242
if isinstance(payload, Path):
241243
return str(payload)
242244
if isinstance(payload, ApiType):

0 commit comments

Comments
 (0)