tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 0a286614a007ed84773faf0806aaa6b15e7f9d2f
parent 069c2bb8fe5cb0d8819e84512a127c932a4bc2ee
Author: Maksim Sadym <69349599+sadym-chromium@users.noreply.github.com>
Date:   Fri, 10 Oct 2025 07:49:13 +0000

Bug 1992761 [wpt PR 54351] - [wdspec] introduce `Maybe` and `Nullable` types, a=testonly

Automatic update from web-platform-tests
[wdspec] introduce `Maybe` and `Nullable` types (#54351)

* In order to avoid confusion, add `Maybe` and `Nullable` types for WebDriver BiDi parameters.
* And do not use `None` for missing parameter in `Emulation` module.

Out of scope: updating of the other modules.

Context: https://github.com/w3c/webdriver-bidi/issues/642
--

wpt-commits: 06549edf764586a7d0b9557d48f7e4a586d29140
wpt-pr: 54351

Diffstat:
Mtesting/web-platform/tests/tools/webdriver/webdriver/bidi/modules/_module.py | 52++++++++++++++++++++++++++++++++++++++++++++++++++--
Mtesting/web-platform/tests/tools/webdriver/webdriver/bidi/modules/emulation.py | 138++++++++++++++++++++++++++++++++-----------------------------------------------
Mtesting/web-platform/tests/tools/webdriver/webdriver/bidi/undefined.py | 27+++++++++++++++++++++++----
Mtesting/web-platform/tests/tools/wptrunner/wptrunner/executors/asyncactions.py | 16++++++++--------
4 files changed, 136 insertions(+), 97 deletions(-)

diff --git a/testing/web-platform/tests/tools/webdriver/webdriver/bidi/modules/_module.py b/testing/web-platform/tests/tools/webdriver/webdriver/bidi/modules/_module.py @@ -102,5 +102,53 @@ def to_camelcase(name: str) -> str: return "".join(parts) -def remove_undefined(obj: Mapping[str, Any]) -> Mapping[str, Any]: - return {key: value for key, value in obj.items() if value != UNDEFINED} +def remove_undefined(obj: Any) -> Any: + """ + Removes entries from a dictionary where the value is UNDEFINED. Also removes + UNDEFINED values from lists. Recursively processes nested dictionaries and + lists. + + >>> from ..undefined import UNDEFINED + >>> remove_undefined({"a": 1, "b": UNDEFINED, "c": 3}) + {'a': 1, 'c': 3} + + >>> remove_undefined({"a": 1, "b": {"x": UNDEFINED, "y": 2}, "c": UNDEFINED}) + {'a': 1, 'b': {'y': 2}} + + >>> remove_undefined({"a": 1, "b": [1, UNDEFINED, 3], "c": UNDEFINED}) + {'a': 1, 'b': [1, 3]} + + >>> remove_undefined({"a": 1, "b": [{"x": UNDEFINED, "y": 2}], "c": UNDEFINED}) + {'a': 1, 'b': [{'y': 2}]} + + >>> remove_undefined({"a": UNDEFINED, "b": {"x": UNDEFINED}}) + {'b': {}} + + >>> remove_undefined({}) + {} + + >>> remove_undefined([]) + [] + + >>> remove_undefined(1) + 1 + + >>> remove_undefined("foo") + 'foo' + + >>> remove_undefined(None) + + """ + if isinstance(obj, Mapping): + new_obj = {} + for key, value in obj.items(): + if value is not UNDEFINED: + new_obj[key] = remove_undefined(value) + return new_obj + elif isinstance(obj, list): + new_list = [] + for item in obj: + if item is not UNDEFINED: + new_list.append(remove_undefined(item)) + return new_list + return obj diff --git a/testing/web-platform/tests/tools/webdriver/webdriver/bidi/modules/emulation.py b/testing/web-platform/tests/tools/webdriver/webdriver/bidi/modules/emulation.py @@ -1,82 +1,64 @@ -from typing import Any, Dict, List, Literal, Mapping, MutableMapping, Optional, \ - Union +from typing import Any, Dict, List, Literal, Mapping from ._module import BidiModule, command -from ..undefined import UNDEFINED, Undefined +from ..undefined import UNDEFINED, Maybe, Nullable class CoordinatesOptions(Dict[str, Any]): def __init__( - self, - latitude: float, - longitude: float, - accuracy: Optional[float] = None, - altitude: Optional[float] = None, - altitude_accuracy: Optional[float] = None, - heading: Optional[float] = None, - speed: Optional[float] = None, + self, + latitude: float, + longitude: float, + accuracy: Maybe[float] = UNDEFINED, + altitude: Maybe[Nullable[float]] = UNDEFINED, + altitude_accuracy: Maybe[Nullable[float]] = UNDEFINED, + heading: Maybe[Nullable[float]] = UNDEFINED, + speed: Maybe[Nullable[float]] = UNDEFINED, ): self["latitude"] = latitude self["longitude"] = longitude - - if accuracy is not None: - self["accuracy"] = accuracy - if altitude is not None: - self["altitude"] = altitude - if altitude_accuracy is not None: - self["altitudeAccuracy"] = altitude_accuracy - if heading is not None: - self["heading"] = heading - if speed is not None: - self["speed"] = speed + self["accuracy"] = accuracy + self["altitude"] = altitude + self["altitudeAccuracy"] = altitude_accuracy + self["heading"] = heading + self["speed"] = speed class Emulation(BidiModule): @command def set_geolocation_override( - self, - coordinates: Union[CoordinatesOptions, Undefined] = UNDEFINED, - error: Optional[Dict[str, Any]] = None, - contexts: Optional[List[str]] = None, - user_contexts: Optional[List[str]] = None, + self, + coordinates: Maybe[Nullable[CoordinatesOptions]] = UNDEFINED, + error: Maybe[Dict[str, Any]] = UNDEFINED, + contexts: Maybe[List[str]] = UNDEFINED, + user_contexts: Maybe[List[str]] = UNDEFINED, ) -> Mapping[str, Any]: - params: MutableMapping[str, Any] = {} - - if coordinates is not UNDEFINED: - params["coordinates"] = coordinates - if error is not None: - params["error"] = error - if contexts is not None: - params["contexts"] = contexts - if user_contexts is not None: - params["userContexts"] = user_contexts - - return params + return { + "coordinates": coordinates, + "error": error, + "contexts": contexts, + "userContexts": user_contexts + } @command def set_locale_override( - self, - locale: Union[str, None], - contexts: Optional[List[str]] = None, - user_contexts: Optional[List[str]] = None, + self, + locale: Nullable[str], + contexts: Maybe[List[str]] = UNDEFINED, + user_contexts: Maybe[List[str]] = UNDEFINED, ) -> Mapping[str, Any]: - params: MutableMapping[str, Any] = { - "locale": locale + return { + "locale": locale, + "contexts": contexts, + "userContexts": user_contexts } - if contexts is not None: - params["contexts"] = contexts - if user_contexts is not None: - params["userContexts"] = user_contexts - - return params - @command def set_scripting_enabled( self, - enabled: Literal[False, None], - contexts: Union[List[str], Undefined] = UNDEFINED, - user_contexts: Union[List[str], Undefined] = UNDEFINED, + enabled: Nullable[Literal[False]], + contexts: Maybe[List[str]] = UNDEFINED, + user_contexts: Maybe[List[str]] = UNDEFINED, ) -> Mapping[str, Any]: return { "enabled": enabled, @@ -86,46 +68,36 @@ class Emulation(BidiModule): @command def set_screen_orientation_override( - self, - screen_orientation:Dict[str, Any], - contexts: Optional[List[str]] = None, - user_contexts: Optional[List[str]] = None, + self, + screen_orientation: Nullable[Dict[str, Any]], + contexts: Maybe[List[str]] = UNDEFINED, + user_contexts: Maybe[List[str]] = UNDEFINED, ) -> Mapping[str, Any]: - params: MutableMapping[str, Any] = { - "screenOrientation": screen_orientation + return { + "screenOrientation": screen_orientation, + "contexts": contexts, + "userContexts": user_contexts } - if contexts is not None: - params["contexts"] = contexts - if user_contexts is not None: - params["userContexts"] = user_contexts - - return params - @command def set_timezone_override( self, - timezone: Union[str, None], - contexts: Optional[List[str]] = None, - user_contexts: Optional[List[str]] = None, + timezone: Nullable[str], + contexts: Maybe[List[str]] = UNDEFINED, + user_contexts: Maybe[List[str]] = UNDEFINED, ) -> Mapping[str, Any]: - params: MutableMapping[str, Any] = { - "timezone": timezone + return { + "timezone": timezone, + "contexts": contexts, + "userContexts": user_contexts } - if contexts is not None: - params["contexts"] = contexts - if user_contexts is not None: - params["userContexts"] = user_contexts - - return params - @command def set_user_agent_override( self, - user_agent: Union[str, None], - contexts: Union[List[str], Undefined] = UNDEFINED, - user_contexts: Union[List[str], Undefined] = UNDEFINED, + user_agent: Nullable[str], + contexts: Maybe[List[str]] = UNDEFINED, + user_contexts: Maybe[List[str]] = UNDEFINED, ) -> Mapping[str, Any]: return { "userAgent": user_agent, diff --git a/testing/web-platform/tests/tools/webdriver/webdriver/bidi/undefined.py b/testing/web-platform/tests/tools/webdriver/webdriver/bidi/undefined.py @@ -1,6 +1,25 @@ -class Undefined: - def __init__(self) -> None: - raise RuntimeError('Import UNDEFINED instead.') +import enum +from enum import Enum +from typing import TypeVar, Union -UNDEFINED = Undefined.__new__(Undefined) +class Undefined(Enum): + """ + Class representing special value that indicates that a property is not set. + """ + + UNDEFINED = enum.auto() + + +UNDEFINED = Undefined.UNDEFINED +"""A special value that indicates that a property is not set.""" + +T = TypeVar("T") + +#: A type hint for a value that can be of a specific type or UNDEFINED. +#: For example, ``Maybe[str]`` is equivalent to ``Union[str, Undefined]``. +Maybe = Union[T, Undefined] + +#: A type hint which can have protocol values `null`. Intended to be used +# instead of `Optional` to avoid confusion. +Nullable = Union[T, None] diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/asyncactions.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/executors/asyncactions.py @@ -176,14 +176,14 @@ class BidiEmulationSetGeolocationOverrideAction: raise ValueError( "Params `error` and `coordinates` are mutually exclusive") - # If `error` is present, set it. Otherwise, do not pass it (error: None). - # Note, unlike `coordinates`, `error` cannot be `UNDEFINED`. It's either - # `None` and it's not passed, or some dict value which is passed. - error = payload['error'] if 'error' in payload else None - # If `error` is present, do not pass `coordinates` (coordinates: UNDEFINED). - # Otherwise, remove emulation (coordinates: None). - coordinates = payload['coordinates'] if 'coordinates' in payload else ( - None if error is None else webdriver.bidi.undefined.UNDEFINED) + # If `error` is present, set it. Otherwise, use `UNDEFINED`. + error = payload['error'] if 'error' in payload else webdriver.bidi.undefined.UNDEFINED + coordinates = webdriver.bidi.undefined.UNDEFINED + if 'coordinates' in payload: + coordinates = payload['coordinates'] + elif error is webdriver.bidi.undefined.UNDEFINED: + # If `error` is not present, pass `coordinates` of null. + coordinates = None if "contexts" not in payload: raise ValueError("Missing required parameter: contexts")