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
2 changes: 1 addition & 1 deletion .azure-pipelines/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ extends:
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.9'
versionSpec: '3.10'
displayName: 'Use Python'
- task: NodeTool@0
inputs:
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/playwright-roll/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ There is sometimes no `vX.Y.0` tag for the latest release (the bots cut release

`CONTRIBUTING.md` covers this. Notes from past rolls:

- The repo says Python 3.9 is required, but 3.9+ works. If `python3.9` isn't available, use `python3` (3.12 is fine).
- The repo requires Python 3.10+. If `python3.10` isn't available, use `python3` (3.12 is fine).
- If `python3-venv` is missing system-wide, use `uv venv env` instead, then `uv pip install --python env/bin/python --upgrade pip`. Don't try to `apt install` — sudo is denied in the harness.
- Always activate the venv before any `pip`, `pytest`, `mypy`, or `pre-commit` invocation.

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.9', '3.10']
python-version: ['3.10', '3.14']
browser: [chromium, firefox, webkit]
exclude:
# WebKit on standard macOS-latest (currently macos-15-arm64) is unstable;
Expand All @@ -86,10 +86,10 @@ jobs:
browser: webkit
include:
- os: macos-15-xlarge
python-version: '3.9'
python-version: '3.10'
browser: webkit
- os: macos-15-xlarge
python-version: '3.10'
python-version: '3.14'
browser: webkit
- os: windows-latest
python-version: '3.11'
Expand Down
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

### Configuring python environment

The project development requires Python version 3.9+. To set it as default in the environment run the following commands:
The project development requires Python version 3.10+. To set it as default in the environment run the following commands:

```sh
# You may need to install python 3.9 venv if it's missing, on Ubuntu just run `sudo apt-get install python3.9-venv`
python3.9 -m venv env
# You may need to install python 3.10 venv if it's missing, on Ubuntu just run `sudo apt-get install python3.10-venv`
python3.10 -m venv env
source ./env/bin/activate
```

Expand Down
2 changes: 1 addition & 1 deletion ROLLING.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Rolling Playwright-Python to the latest Playwright driver

* checkout repo: `git clone https://github.com/microsoft/playwright-python`
* make sure local python is 3.9
* make sure local python is 3.10 or newer
* create virtual environment, if don't have one: `python -m venv env`
* activate venv: `source env/bin/activate`
* install all deps:
Expand Down
5 changes: 0 additions & 5 deletions playwright/_impl/_browser_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import asyncio
import json
import pathlib
import sys
from pathlib import Path
from typing import TYPE_CHECKING, Dict, List, Optional, Pattern, Sequence, Union, cast

Expand Down Expand Up @@ -187,10 +186,6 @@ def _user_data_dir(self, userDataDir: Optional[Union[str, Path]]) -> str:
if not userDataDir:
return ""
if not Path(userDataDir).is_absolute():
# Can be dropped once we drop Python 3.9 support (10/2025):
# https://github.com/python/cpython/issues/82852
if sys.platform == "win32" and sys.version_info[:2] < (3, 10):
return str(pathlib.Path.cwd() / userDataDir)
return str(Path(userDataDir).resolve())
return str(Path(userDataDir))

Expand Down
8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ authors = [
readme = "README.md"
license = "Apache-2.0"
dynamic = ["version"]
requires-python = ">=3.9"
requires-python = ">=3.10"
# Please when changing dependencies run the following commands to update requirements.txt:
# - pip install uv==0.5.4
# - uv pip compile pyproject.toml -o requirements.txt
Expand All @@ -24,11 +24,11 @@ classifiers = [
"Topic :: Internet :: WWW/HTTP :: Browsers",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Operating System :: OS Independent",
]

Expand Down Expand Up @@ -70,7 +70,7 @@ asyncio_default_test_loop_scope = "session"

[tool.mypy]
ignore_missing_imports = true
python_version = "3.9"
python_version = "3.10"
warn_unused_ignores = false
warn_redundant_casts = true
warn_unused_configs = true
Expand All @@ -88,7 +88,7 @@ profile = "black"
[tool.pyright]
include = ["playwright", "tests", "scripts"]
exclude = ["**/node_modules", "**/__pycache__", "**/.*", "./build"]
pythonVersion = "3.9"
pythonVersion = "3.10"
reportMissingImports = false
reportTypedDictNotRequiredAccess = false
reportCallInDefaultInitializer = true
Expand Down
15 changes: 13 additions & 2 deletions tests/test_reference_count_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
from playwright.async_api import async_playwright
from tests.server import Server

_NETWORK_RESPONSE_RECEIVED_MARKER = "__pw__is_last_network_response_received_event"
_NETWORK_RESPONSE_RECEIVED_MARKER_VALUE = object()


@pytest.mark.asyncio
async def test_memory_objects(server: Server, browser_name: str) -> None:
Expand All @@ -39,7 +42,9 @@ async def test_memory_objects(server: Server, browser_name: str) -> None:
await page.route("**/*", lambda route, _: route.fulfill(body="OK"))

def handle_network_response_received(event: Any) -> None:
event["__pw__is_last_network_response_received_event"] = True
event[_NETWORK_RESPONSE_RECEIVED_MARKER] = (
_NETWORK_RESPONSE_RECEIVED_MARKER_VALUE
)

if browser_name == "chromium":
# https://github.com/microsoft/playwright-python/issues/1602
Expand All @@ -64,7 +69,13 @@ def handle_network_response_received(event: Any) -> None:
assert isinstance(o, dict)
name = o.get("_type")
# https://github.com/microsoft/playwright-python/issues/1602
if o.get("__pw__is_last_network_response_received_event", False):
# Python 3.14 can expose CPython's interned-strings dict here, where
# a string can appear as both key and value. Check the sentinel by
# identity to avoid confusing that internal dict with a leaked event.
if (
o.get(_NETWORK_RESPONSE_RECEIVED_MARKER)
is _NETWORK_RESPONSE_RECEIVED_MARKER_VALUE
):
assert False
if not name:
continue
Expand Down
Loading