Skip to content

Commit 36d200b

Browse files
committed
init 1.54.1
1 parent 7b15b2a commit 36d200b

28 files changed

+2025
-25
lines changed

playwright_firefox/_impl/_browser.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,19 @@ def __init__(
6565
self, parent: "BrowserType", type: str, guid: str, initializer: Dict
6666
) -> None:
6767
super().__init__(parent, type, guid, initializer)
68-
self._browser_type: parent # Optional["BrowserType"] = None
68+
self._browser_type: Optional["BrowserType"] = None
6969
self._is_connected = True
7070
self._should_close_connection_on_close = False
7171
self._cr_tracing_path: Optional[str] = None
7272

73-
self._contexts: List[BrowserContext] = [] # Set[BrowserContext] = set()
73+
self._contexts: Set[BrowserContext] = set()
7474
self._traces_dir: Optional[str] = None
75-
# self._channel.on(
76-
# "context",
77-
# lambda params: self._did_create_context(
78-
# cast(BrowserContext, from_channel(params["context"]))
79-
# ),
80-
# )
75+
self._channel.on(
76+
"context",
77+
lambda params: self._did_create_context(
78+
cast(BrowserContext, from_channel(params["context"]))
79+
),
80+
)
8181
self._channel.on("close", lambda _: self._on_close())
8282
self._close_reason: Optional[str] = None
8383

@@ -115,11 +115,11 @@ def _on_close(self) -> None:
115115

116116
@property
117117
def contexts(self) -> List[BrowserContext]:
118-
return self._contexts.copy() # list(self._contexts)
118+
return list(self._contexts)
119119

120120
@property
121121
def browser_type(self) -> "BrowserType":
122-
# assert self._browser_type is not None
122+
assert self._browser_type is not None
123123
return self._browser_type
124124

125125
def is_connected(self) -> bool:

playwright_firefox/_impl/_browser_context.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,13 @@ def __init__(
110110
self._browser: Optional["Browser"] = None
111111
if parent.__class__.__name__ == "Browser":
112112
self._browser = cast("Browser", parent)
113-
self._browser._contexts.append(self)
114113
self._pages: List[Page] = []
115114
self._routes: List[RouteHandler] = []
116115
self._web_socket_routes: List[WebSocketRouteHandler] = []
117116
self._bindings: Dict[str, Any] = {}
118117
self._timeout_settings = TimeoutSettings(None)
119118
self._owner_page: Optional[Page] = None
120-
self._options: Dict[str, Any] = {'viewport': {'width': 1280, 'height': 720}, 'acceptDownloads': 'accept', 'serviceWorkers': 'block', 'selectorEngines': []} # initializer["options"]
119+
self._options: Dict[str, Any] = initializer["options"]
121120
self._background_pages: Set[Page] = set()
122121
self._service_workers: Set[Worker] = set()
123122
self._base_url: Optional[str] = self._options.get("baseURL")
@@ -455,20 +454,16 @@ async def _unroute_internal(
455454
behavior: Literal["default", "ignoreErrors", "wait"] = None,
456455
) -> None:
457456
self._routes = remaining
458-
# if behavior is not None and behavior != "default":
459-
# await asyncio.gather(*map(lambda router: router.stop(behavior), removed)) # type: ignore
457+
if behavior is not None and behavior != "default":
458+
await asyncio.gather(*map(lambda router: router.stop(behavior), removed)) # type: ignore
460459
await self._update_interception_patterns()
461-
if behavior is None or behavior == "default":
462-
return
463-
await asyncio.gather(*map(lambda router: router.stop(behavior), removed)) # type: ignore
464460

465461
async def route_web_socket(
466462
self, url: URLMatch, handler: WebSocketRouteHandlerCallback
467463
) -> None:
468464
self._web_socket_routes.insert(
469465
0,
470-
# WebSocketRouteHandler(self._base_url, url, handler),
471-
WebSocketRouteHandler(self._options.get("baseURL"), url, handler),
466+
WebSocketRouteHandler(self._base_url, url, handler),
472467
)
473468
await self._update_web_socket_interception_patterns()
474469

playwright_firefox/_impl/_driver.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from typing import Tuple
2020

2121
import playwright_firefox
22-
from playwright_firefox._repo_version import version
22+
# from playwright_firefox._repo_version import version
2323

2424

2525
def compute_driver_executable() -> Tuple[str, str]:
@@ -37,5 +37,5 @@ def get_driver_env() -> dict:
3737
env = os.environ.copy()
3838
env["PW_LANG_NAME"] = "python"
3939
env["PW_LANG_NAME_VERSION"] = f"{sys.version_info.major}.{sys.version_info.minor}"
40-
env["PW_CLI_DISPLAY_VERSION"] = version
40+
# env["PW_CLI_DISPLAY_VERSION"] = version
4141
return env

playwright_firefox/_impl/_network.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -501,8 +501,8 @@ async def continue_(
501501

502502
async def _inner() -> None:
503503
self.request._apply_fallback_overrides(overrides)
504-
# await self._inner_continue(False)
505-
await self._internal_continue()
504+
await self._inner_continue(False)
505+
# await self._internal_continue()
506506

507507
return await self._handle_route(_inner)
508508

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
from collections.abc import MutableMapping
2+
3+
4+
# straight from: https://github.com/kennethreitz/requests/blob/master/src/requests/structures.py
5+
class CaseInsensitiveDict(MutableMapping):
6+
"""A case-insensitive ``dict``-like object.
7+
8+
Implements all methods and operations of
9+
``MutableMapping`` as well as dict's ``copy``. Also
10+
provides ``lower_items``.
11+
12+
All keys are expected to be strings. The structure remembers the
13+
case of the last key to be set, and ``iter(instance)``,
14+
``keys()``, ``items()``, ``iterkeys()``, and ``iteritems()``
15+
will contain case-sensitive keys. However, querying and contains
16+
testing is case insensitive::
17+
18+
cid = CaseInsensitiveDict()
19+
cid['Accept'] = 'application/json'
20+
cid['aCCEPT'] == 'application/json' # True
21+
list(cid) == ['Accept'] # True
22+
23+
For example, ``headers['content-encoding']`` will return the
24+
value of a ``'Content-Encoding'`` response header, regardless
25+
of how the header name was originally stored.
26+
27+
If the constructor, ``.update``, or equality comparison
28+
operations are given keys that have equal ``.lower()``s, the
29+
behavior is undefined.
30+
"""
31+
32+
def __init__(self, data=None, **kwargs):
33+
self._store = {}
34+
if data is None:
35+
data = {}
36+
self.update(data, **kwargs)
37+
38+
def __setitem__(self, key, value):
39+
# Use the lowercased key for lookups, but store the actual
40+
# key alongside the value.
41+
self._store[key.lower()] = (key, value)
42+
43+
def __getitem__(self, key):
44+
return self._store[key.lower()][1]
45+
46+
def __delitem__(self, key):
47+
del self._store[key.lower()]
48+
49+
def __iter__(self):
50+
return (casedkey for casedkey, mappedvalue in self._store.values())
51+
52+
def __len__(self):
53+
return len(self._store)
54+
55+
def lower_items(self):
56+
"""Like iteritems(), but with all lowercase keys."""
57+
return ((lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items())
58+
59+
def __eq__(self, other):
60+
from collections.abc import Mapping
61+
62+
if isinstance(other, Mapping):
63+
other = CaseInsensitiveDict(other)
64+
else:
65+
return NotImplemented
66+
# Compare insensitively
67+
return dict(self.lower_items()) == dict(other.lower_items())
68+
69+
# Copy is required
70+
def copy(self):
71+
return CaseInsensitiveDict(self._store.values())
72+
73+
def __repr__(self):
74+
return str(dict(self.items()))
75+
76+
def items(self):
77+
pass
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# from . import async_api, sync_api
2+
3+
from .async_api import PlaywrightContextManager,Playwright
4+
from .sync_api import PlaywrightContextManager,Playwright
5+
6+
7+
class AsyncWrappingContextManager:
8+
def __init__(self, stealth: "Stealth", manager: PlaywrightContextManager):
9+
if isinstance(manager, PlaywrightContextManager):
10+
raise TypeError("You need to call 'use_sync' instead of 'use_async' for a sync Playwright context")
11+
self.stealth = stealth
12+
self.manager = manager
13+
14+
async def __aenter__(
15+
self,
16+
) -> Playwright:
17+
context = await self.manager.__aenter__()
18+
self.stealth.hook_playwright_context(context)
19+
return context
20+
21+
async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
22+
await self.manager.__aexit__(exc_type, exc_val, exc_tb)
23+
24+
25+
class SyncWrappingContextManager:
26+
def __init__(self, stealth: "Stealth", manager: PlaywrightContextManager):
27+
if isinstance(manager, PlaywrightContextManager):
28+
raise TypeError("You need to call 'use_async' instead of 'use_sync' for an async Playwright context")
29+
self.stealth = stealth
30+
self.manager = manager
31+
32+
def __enter__(
33+
self,
34+
) -> Playwright:
35+
context = self.manager.__enter__()
36+
self.stealth.hook_playwright_context(context)
37+
return context
38+
39+
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
40+
self.manager.__exit__(exc_type, exc_val, exc_tb)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
log("loading chrome.app.js");
2+
3+
if (!window.chrome) {
4+
// Use the exact property descriptor found in headful Chrome
5+
// fetch it via `Object.getOwnPropertyDescriptor(window, 'chrome')`
6+
Object.defineProperty(window, "chrome", {
7+
writable: true,
8+
enumerable: true,
9+
configurable: false, // note!
10+
value: {}, // We'll extend that later
11+
});
12+
}
13+
14+
// app in window.chrome means we're running headful and don't need to mock anything
15+
if (!("app" in window.chrome)) {
16+
const makeError = {
17+
ErrorInInvocation: (fn) => {
18+
const err = new TypeError(`Error in invocation of app.${fn}()`);
19+
return utils.stripErrorWithAnchor(err, `at ${fn} (eval at <anonymous>`);
20+
},
21+
};
22+
23+
const APP_STATIC_DATA = JSON.parse(
24+
`
25+
{
26+
"isInstalled": false,
27+
"InstallState": {
28+
"DISABLED": "disabled",
29+
"INSTALLED": "installed",
30+
"NOT_INSTALLED": "not_installed"
31+
},
32+
"RunningState": {
33+
"CANNOT_RUN": "cannot_run",
34+
"READY_TO_RUN": "ready_to_run",
35+
"RUNNING": "running"
36+
}
37+
}
38+
`.trim()
39+
);
40+
41+
window.chrome.app = {
42+
...APP_STATIC_DATA,
43+
44+
get isInstalled() {
45+
return false;
46+
},
47+
48+
getDetails: function getDetails() {
49+
if (arguments.length) {
50+
throw makeError.ErrorInInvocation(`getDetails`);
51+
}
52+
return null;
53+
},
54+
getIsInstalled: function getDetails() {
55+
if (arguments.length) {
56+
throw makeError.ErrorInInvocation(`getIsInstalled`);
57+
}
58+
return false;
59+
},
60+
runningState: function getDetails() {
61+
if (arguments.length) {
62+
throw makeError.ErrorInInvocation(`runningState`);
63+
}
64+
return "cannot_run";
65+
},
66+
};
67+
utils.patchToStringNested(window.chrome.app);
68+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
log("loading chrome.csi.js");
2+
3+
if (!window.chrome) {
4+
// Use the exact property descriptor found in headful Chrome
5+
// fetch it via `Object.getOwnPropertyDescriptor(window, 'chrome')`
6+
Object.defineProperty(window, "chrome", {
7+
writable: true,
8+
enumerable: true,
9+
configurable: false, // note!
10+
value: {}, // We'll extend that later
11+
});
12+
}
13+
14+
// Check if we're running headful and don't need to mock anything
15+
// Check that the Navigation Timing API v1 is available, we need that
16+
if (!("csi" in window.chrome) && window.performance?.timing) {
17+
const { csi_timing } = window.performance;
18+
19+
log("loading chrome.csi.js");
20+
window.chrome.csi = function () {
21+
return {
22+
onloadT: csi_timing?.domContentLoadedEventEnd,
23+
startE: csi_timing?.navigationStart,
24+
pageT: Date.now() - csi_timing?.navigationStart,
25+
tran: 15, // transition? seems constant
26+
};
27+
};
28+
utils.patchToString(window.chrome.csi);
29+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
log("loading chrome.hairline.js");
2+
// inspired by: https://intoli.com/blog/making-chrome-headless-undetectable/
3+
const elementDescriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetHeight");
4+
5+
utils.replaceProperty(HTMLDivElement.prototype, "offsetHeight", {
6+
get: function () {
7+
// hmmm not sure about this
8+
if (this.id === "modernizr") {
9+
return 1;
10+
}
11+
return elementDescriptor.get.apply(this);
12+
},
13+
});

0 commit comments

Comments
 (0)